英特尔和AMD的文档称,对于64位模式,虚拟地址实际上只有48位可用,而48到63位必须复制第47位(符号扩展)。据我所知,所有当前的CPU都以这种方式实现,但没有(理论上)禁止在未来的实现中扩展可用空间(这不会破坏二进制兼容性)。
是否有一种标准方式以编程方式确定有意义的位数? (即某些特定的CPUID,如物理地址所发生的那样)。
我知道实际上48位对于任何合理的应用程序和操作系统都是足够的;我的问题是理论上的。
答案 0 :(得分:5)
是的,如果支持,您可以使用CPUID.80000008H:EAX[7:0]
。
算法如下:
cpuid
检查CPUID.80000000h.EAX
的最大扩展 E 值。CPUID.80000008H:EAX[7:0]
表示物理地址位数
CPUID.80000008H:EAX[15:8]
表示线性地址位的数量。 CPUID.1:EDX.PAE
(第6位),那么CPU有36个物理地址位和32个线性地址位。来自英特尔的符号,CPUID.X:R B
表示
eax
之前输入cpuid
的值。AMD在63:52设置了虚拟:物理地址的最大限制 目前的实现通常是48:40,但物理地址空间的大小可能不同。
可以使用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!