开启PAE分页

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为打开后才进入。