5

Intel 和 AMD 文档说,对于 64 位模式,实际上只有 48 位可用于虚拟地址,并且从 48 到 63 的位必须复制第 47 位(符号扩展)。据我所知,目前所有的 CPU 都是以这种方式实现的,但没有(理论上)禁止在未来的实现中扩展可用空间(这不会破坏二进制兼容性)。

是否有一种标准方法来以编程方式确定有意义的位数?(即一些特定的 CPUID,就像物理地址一样)。

我知道实际上 48 位对于任何合理的应用程序和操作系统来说都绰绰有余。我的问题是理论上的。

4

1 回答 1

7

CPUID.80000008H:EAX[7:0]是的,如果支持,您可以使用。

算法如下:

  1. 检查with的最大扩展E值。cpuidCPUID.80000000h.EAX
  2. 如果E >= 80000008h, CPUID.80000008H:EAX[7:0]则用于物理地址位数。
    CPUID.80000008H:EAX[15:8]为线性地址位数。
  3. else if CPUID.1:EDX.PAE(bit 6) 那么 CPU 有 36 个物理地址位和 32 个线性地址位。
  4. 否则 CPU 有 32 个物理和逻辑地址位。

来自英特尔的符号CPUID.X:R B意味着

  • X要放入eax之前的值cpuid
  • R感兴趣的输出寄存器。
  • B格式为[upper:lower]的位域,或格式为.bitname的命名位。

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!

于 2016-09-09T16:59:14.680 回答