x86-64:规范地址和实际可用范围
x86-64: canonical addresses and actual available range
Intel 和 AMD 文档说,对于 64 位模式,实际上只有 48 位可用于虚拟地址,并且从 48 到 63 的位必须复制位 47(符号扩展)。据我所知,所有当前的 CPU 都是以这种方式实现的,但是(理论上)没有禁止在未来的实现中扩展可用的 space (这不会破坏二进制兼容性)。
有没有一种标准的方法来以编程方式确定有意义的位数? (即一些特定的 CPUID,就像物理地址一样)。
我知道实际上 48 位对于任何合理的应用来说都绰绰有余 OS;我的问题是理论上的。
是的,如果支持,您可以使用 CPUID.80000008H:EAX[7:0]
。
算法如下:
- 检查
cpuid
和 CPUID.80000000h.EAX
的最大扩展 E 值。
- 如果E >= 80000008h,使用
CPUID.80000008H:EAX[7:0]
为物理地址位数。
CPUID.80000008H:EAX[15:8]
为线性地址位数。
- 否则如果
CPUID.1:EDX.PAE
(位6)那么CPU有36个物理地址位和32个线性地址位。
- 否则 CPU 有 32 个物理和逻辑地址位。
表示法,来自Intel,CPUID.X:R B
表示
- X 在
cpuid
. 之前放入 eax
的值
- R 感兴趣的输出寄存器。
- B 形式为 [upper:lower] 的位域,或形式为 的命名位.bitname.
AMD 将 虚拟:物理 地址的最大限制设置为 63:52。
当前的实现通常是 48:40,尽管物理地址的大小 space 可能不同。
可以用NASM
编译的示例代码
BITS 64
GLOBAL max_phy_addr
GLOBAL max_lin_addr
SECTION .text
max_phy_addr:
push rbx
mov eax, 80000000h
cpuid
cmp eax, 80000008h
jae .fromCpuid
mov eax, 1
cpuid
mov eax, 32
shr edx, 4
and edx, 4
add eax, edx
pop rbx
ret
.fromCpuid:
mov eax, 80000008h
cpuid
movzx eax, al
pop rbx
ret
max_lin_addr:
push rbx
mov eax, 80000000h
cpuid
cmp eax, 80000008h
jae .fromCpuid
mov eax, 1
cpuid
mov eax, 32
pop rbx
ret
.fromCpuid:
mov eax, 80000008h
cpuid
movzx eax, ah
pop rbx
ret
并与 C 程序一起使用,例如
#include <stdio.h>
long max_phy_addr();
long max_lin_addr();
int main()
{
printf("Phy: %llu\nLin: %llu\n", max_phy_addr(), max_lin_addr());
return 0;
}
我刚刚发现我的 Haswell 是 48:39!
Intel 和 AMD 文档说,对于 64 位模式,实际上只有 48 位可用于虚拟地址,并且从 48 到 63 的位必须复制位 47(符号扩展)。据我所知,所有当前的 CPU 都是以这种方式实现的,但是(理论上)没有禁止在未来的实现中扩展可用的 space (这不会破坏二进制兼容性)。
有没有一种标准的方法来以编程方式确定有意义的位数? (即一些特定的 CPUID,就像物理地址一样)。
我知道实际上 48 位对于任何合理的应用来说都绰绰有余 OS;我的问题是理论上的。
是的,如果支持,您可以使用 CPUID.80000008H:EAX[7:0]
。
算法如下:
- 检查
cpuid
和CPUID.80000000h.EAX
的最大扩展 E 值。 - 如果E >= 80000008h,使用
CPUID.80000008H:EAX[7:0]
为物理地址位数。
CPUID.80000008H:EAX[15:8]
为线性地址位数。 - 否则如果
CPUID.1:EDX.PAE
(位6)那么CPU有36个物理地址位和32个线性地址位。 - 否则 CPU 有 32 个物理和逻辑地址位。
表示法,来自Intel,CPUID.X:R B
表示
- X 在
cpuid
. 之前放入 - R 感兴趣的输出寄存器。
- B 形式为 [upper:lower] 的位域,或形式为 的命名位.bitname.
eax
的值
AMD 将 虚拟:物理 地址的最大限制设置为 63:52。
当前的实现通常是 48:40,尽管物理地址的大小 space 可能不同。
可以用NASM
编译的示例代码BITS 64
GLOBAL max_phy_addr
GLOBAL max_lin_addr
SECTION .text
max_phy_addr:
push rbx
mov eax, 80000000h
cpuid
cmp eax, 80000008h
jae .fromCpuid
mov eax, 1
cpuid
mov eax, 32
shr edx, 4
and edx, 4
add eax, edx
pop rbx
ret
.fromCpuid:
mov eax, 80000008h
cpuid
movzx eax, al
pop rbx
ret
max_lin_addr:
push rbx
mov eax, 80000000h
cpuid
cmp eax, 80000008h
jae .fromCpuid
mov eax, 1
cpuid
mov eax, 32
pop rbx
ret
.fromCpuid:
mov eax, 80000008h
cpuid
movzx eax, ah
pop rbx
ret
并与 C 程序一起使用,例如
#include <stdio.h>
long max_phy_addr();
long max_lin_addr();
int main()
{
printf("Phy: %llu\nLin: %llu\n", max_phy_addr(), max_lin_addr());
return 0;
}
我刚刚发现我的 Haswell 是 48:39!