Yes, you can use CPUID.80000008H:EAX[7:0]
if supported.
The algorithm is as follow:
- Check the maximum extended E value for
cpuid
with CPUID.80000000h.EAX
.
- 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.
- Else if
CPUID.1:EDX.PAE
(bit 6) then the CPU has 36 physical address bits and 32 linear address bits.
- 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!