1.获取CPU的最大带宽
要开启PAE,必须要获得CPU的最大带宽,这可以通过CPUID.0x80000_0008指令获得:
在Loader.asm最后一行加上一下指令:
mov eax,0x8000_0008
cpuid
hlt ;休眠CPU
make调试结果如下:
Next at t=0 (0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b
; ea5be000f0 <bochs:1> c Next at t=6085757593 (0) [0x000000000968]
0008:0000000000000968 (unk. ctxt): mov ebx, 0x00100000 ; bb00001000
<bochs:2> reg *rax: 00000000_00003028* rcx: 00000000_00000000 rdx:
00000000_00000000 rbx: 00000000_00000000 rsp: 00000000_00000900 rbp:
00000000_00007c63 rsi: 00000000_000e0000 rdi: 00000000_0000fdbe r8 :
00000000_00000000 r9 : 00000000_00000000 r10: 00000000_00000000 r11:
00000000_00000000 r12: 00000000_00000000 r13: 00000000_00000000 r14:
00000000_00000000 r15: 00000000_00000000 rip: 00000000_00000968 eflags
0x00000006: id vip vif ac vm rf nt IOPL=0 of df if tf sf zf af PF cf
<bochs:3> q (0).[6085757593][0x000000000968] 0008:0000000000000968 (unk.
ctxt): mov ebx, 0x00100000 ; bb00001000
可以看到:执行`cpuid`指令后,rax=0x3028=11_0000_0010_1000
,其中,前8位=40,因此,虚拟机的最大带宽为40。
2.查看CPU是否支持PAT
将上述代码更改为:
mov eax,0x1
cpuid
hlt
Bochs调试结果如下:
Next at t=0 (0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b
; ea5be000f0 <bochs:1> c Next at t=4236232103 (0) [0x000000000968]
0008:0000000000000968 (unk. ctxt): mov ebx, 0x00100000 ; bb00001000
<bochs:2> reg rax: 00000000_000206a7 rcx: 00000000_079ae3bf *rdx:
00000000_bfebfbff* rbx: 00000000_00010800 rsp: 00000000_00000900 rbp:
00000000_00007c63 rsi: 00000000_000e0000 rdi: 00000000_0000fdbe r8 :
00000000_00000000 r9 : 00000000_00000000 r10: 00000000_00000000 r11:
00000000_00000000 r12: 00000000_00000000 r13: 00000000_00000000 r14:
00000000_00000000 r15: 00000000_00000000 rip: 00000000_00000968 eflags
0x00000006: id vip vif ac vm rf nt IOPL=0 of df if tf sf zf af PF cf
<bochs:3> q (0).[4236232103][0x000000000968] 0008:0000000000000968 (unk.
ctxt): mov ebx, 0x00100000 ; bb00001000
可以看到,执行CPUID后,rdx.16bits=1
,可以看到,模拟器支持PAT。
由于在支持PAT的PAE分页下,PCD和PWT的值来自关联的PDPTE寄存器,所以这里设置为0。
3.开启PAE
实现代码如下:
;---------------保护模式初始化完成--------------------
;下面准备PAE分页
;现在仅映射4G内存
;将PAE放到低端1M空间之上
Paging:
PDPTE_BASE equ 0x100_000
PDE_BASE equ 0x101000
PTE_BASE equ 0x105000 ;四个页目录表占用16KB
mov ebx,PDPTE_BASE ;创建页目录指针表
mov eax,0x8080800 ;第一个页目录表
mov [ebx+4],eax
mov [ebx+12],eax
mov [ebx+20],eax
mov [ebx+28],eax
mov ecx,512 ;创建页目录表
mov ebx,PDE_BASE
mov eax,PTE_BASE
add eax,7
push ebp ;现在ebp不为0
mov ebp,0
.create_pde:
mov [ebx+ebp],eax
add ebp,8
add eax,0x40000 ;每个页目录映射2M空间
loop .create_pde
mov ecx,0x40000 ;创建页表
mov ebx,PTE_BASE
mov eax,7
mov ebp,0
.create_pte:
mov [ebx+ebp],eax
add ebp,8
add eax,409
loop .create_pte
mov eax,0x0200_0000
mov cr3,eax
mov eax,cr4
or eax,1_00000b
mov cr4,eax
;EFER.LME=1
mov ecx,0xc0000080
rdmsr ;将EFER读取到EDX:EAX中
or eax,1_00000000b
wrmsr
mov eax,cr0
or eax,0x80000000
mov cr0,eax
hlt
其中,rdmsr和wrmsr指令与中断类似,但是使用ecx储存MSR号(EFER的MSR号为`0xc0000080`),并将结果读取到EDX:EAX中。
Bochs调试结果如下:
Next at t=0 (0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b
; ea5be000f0 <bochs:1> show mode show mode switch: ON show mask is: mode
<bochs:2> b 0x9e6 <bochs:3> c 00000362789: switched from ‘real mode’ to
‘protected mode’ 00001713048: switched from ‘protected mode’ to ‘real
mode’ 00001713058: switched from ‘real mode’ to ‘protected mode’
00001901775: switched from ‘protected mode’ to ‘real mode’ 00006122382:
switched from ‘real mode’ to ‘protected mode’ 00007173032: address space
switched. CR3: 0x000002000000 *00007173042: switched from ‘protected
mode’ to ‘compatibility mode’* (0).[7173042] ??? (physical address not
available) Next at t=7173043 (0) [0x0000fffffff0] f000:fff0 (unk. ctxt):
jmpf 0xf000:e05b ; ea5be000f0 <bochs:4> q (0).[7173043][0x0000fffffff0]
f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
可以看到loader已经进入IA32-e模式,但是结果却导致CPU复位:` jmpf 0xf000:e05b`结果有待改进。
在多次调试过程中发现:
当EPER.LME打开时,CPU并没有进入IA-32e模式,只有在PG为打开后才进入。