x86-64: canonical addresses and actual available range

梦想的初衷 提交于 2019-12-04 08:08:24

Yes, you can use CPUID.80000008H:EAX[7:0] if supported.

The algorithm is as follow:

  1. Check the maximum extended E value for cpuid with CPUID.80000000h.EAX.
  2. If E >= 80000008h, use CPUID.80000008H:EAX[7:0] for the number of physical address bits.
    CPUID.80000008H:EAX[15:8] for the number of linear address bits.
  3. Else if CPUID.1:EDX.PAE (bit 6) then the CPU has 36 physical address bits and 32 linear address bits.
  4. Else the CPU has 32 physical and logical address bits.

The notation, from Intel, CPUID.X:R B means

  • X The value to put into eax before cpuid.
  • R The output register of interest.
  • B A bitfield in the form [upper:lower] inclusive, or a named bit in the form .bitname.

AMD set the maximum limits for virtual:physical addresses at 63:52.
The current implementation is typically 48:40, though the size of the physical address space can be different.


An example code that can be compiled with 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

And used with a C program such as

#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;
}

And I've just discovered that my Haswell is a 48:39!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!