1. 实现分页机制的代码
-
org 0x9000
-
jmp begin
-
;segment discript
-
TYPE_8 equ 0x8 ;code -->exec
-
TYPE_2 equ 0x2 ;data -->r/w
-
-
S_0 equ (0x0<<4) ;s=0-->gate
-
S_1 equ (0x1<<4) ;s=1-->data/code
-
-
DPL_0 equ (0x0<<5) ;privilege level
-
DPL_3 equ (0x3<<5)
-
-
P_0 equ (0x00<<7) ;not in memory
-
P_1 equ (0x01<<7) ;in memory
-
-
AVL_0 equ (0x00<<8)
-
-
DB_0 equ (0x00<<10) ;16bit data&code
-
DB_1 equ (0x01<<10) ;32bit data&code
-
-
G_0 equ (0x00<<11) ;g=0,byte
-
G_1 equ (0x01<<11) ;g=1,4K
-
-
TI_0 equ (0x0<<2) ;TI=0,gdt
-
TI_1 equ (0x1<<2) ;TI=1,ldt
-
-
RPL_0 equ (0x0)
-
-
;PAGE
-
PAGE_POS equ 0xF0000 ;0xF0000-->0xFFFFF-->64K
-
PG_P_0 equ (0x0) ;not in memory
-
PG_P_1 equ (0x1) ;in memory
-
-
PG_RW_0 equ (0x0<<1) ;read,not write
-
PG_RW_1 equ (0x1<<1) ;read,write
-
-
PG_US_0 equ (0x0<<2) ;supervisor
-
PG_US_1 equ (0x1<<2) ;user
-
-
PG_PWT_0 equ (0x0<<3) ;memory
-
PG_PWT_1 equ (0x1<<3) ;memory and cache
-
-
PG_PCD_0 equ (0x0<<4) ;disable page level cache
-
PG_PCD_1 equ (0x1<<4) ;enable page level cache
-
-
PG_A_0 equ (0x0<<5) ;not accessed
-
PG_A_1 equ (0x1<<5) ;accessed
-
-
PG_D_0 equ (0x0<<6) ;not dirty
-
PG_D_1 equ (0x1<<6) ;dirty
-
-
PG_PAT_0 equ (0x0<<7) ;page attribute tabel
-
PG_PAT_1 equ (0x1<<7) ;
-
-
PG_G_0 equ (0x0<<8) ;global-->TLB
-
PG_G_1 equ (0x1<<8) ;
-
-
PG_AVL_0 equ (0x0<<9) ;available
-
PG_AVL_1 equ (0x1<<9) ;
-
%macro DESC 3
-
dw %1 & 0xFFFF ;limit[0-15]
-
dw %2 & 0xFFFF ;base[0-15]
-
db (%2>>16)&0xFF ;base[16-23]
-
db (%3&0xFF) ;prop[0-7]
-
db (((%1>>16)&0xF) | (%3>>4)&0xF0) ;limit[16-19]prop[8-11]
-
db (%2>>24) & 0xFF
-
%endmacro
-
gdt_base: DESC 0, 0, 0
-
gdt_code: DESC 0xFFFF, 0x0, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_8)
-
gdt_video: DESC 0xFFFF, 0xB8000, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_2)
-
-
gdt_ptr:
-
dw 24 ;gdt_limit: 8*3=16, only 3 gdt item
-
dd gdt_base ;gdt_base
-
-
select_code equ (0x01<<3)|TI_0|RPL_0
-
select_video equ (0x02<<3)|TI_0|RPL_0
-
begin:
-
mov ah, 0x88
-
int 0x15
-
mov cx, ax
-
;----------------- 打开A20 ----------------
-
in al,0x92
-
or al,0000_0010B
-
out 0x92,al
-
-
;----------------- 加载GDT ----------------
-
lgdt [gdt_ptr]
-
-
;----------------- cr0第0位置1 ----------------
-
mov eax, cr0
-
or eax, 0x00000001
-
mov cr0, eax
-
-
;----------------- 跳到保护模式 ----------------
-
jmp select_code:protect_mode
-
[bits 32]
-
protect_mode:
-
mov ax,select_video
-
mov gs,ax
-
mov byte [gs:160], 'P'
-
mov byte [gs:161], 0xA4
-
-
call setup_page_table
-
-
sgdt [gdt_ptr]
-
-
or dword [gdt_ptr+2], 0xC0000000 ; gdt_ptr
-
or byte [gdt_base+7], 0xC0 ;change gdt base addr
-
or byte [gdt_base+16+7], 0xC0 ;select_video: byte8
-
-
or esp, 0xC0000000
-
-
mov eax, PAGE_POS
-
mov cr3, eax
-
-
;打开cr0的pg位
-
mov eax, cr0
-
or eax, 0x80000000
-
mov cr0, eax
-
-
lgdt [gdt_ptr]
-
-
mov byte [gs:162], 'G'
-
mov byte [gs:163], 0xA4
-
jmp $
-
-
setup_page_table:
-
mov ecx, 0x1000 ;1PTE:4K=0x1000 -->清空4k个字节每次清4个字节,这儿应为0x1000/4=0x400
-
xor esi, esi
-
mov eax, (PG_US_1|PG_RW_1|PG_P_1) -->如果一开始就把PTE设为可用的话,bochs里面info tab会打印出上万条映射
-
_init_page_table:
-
mov [PAGE_POS+esi], eax
-
add esi,0x04
-
loop _init_page_table
-
-
;PDE0, PDE768 use the same PTE0
-
or eax,(0x01<<12)
-
mov [PAGE_POS+0x0], eax
-
mov [PAGE_POS+0xc00], eax
-
-
;PTE for PDE0 and PDE768
-
mov ecx,256
-
xor esi,esi
-
mov eax, (PG_US_1|PG_RW_1|PG_P_1)
-
_create_pte:
-
mov [PAGE_POS+0x1000+esi],eax
-
add esi,0x04
-
add eax,0x1000
-
loop _create_pte
-
-
;create other PDE for kernel
-
-
ret
1.1 由于loader.bin没有超过512,所以不需要改mbr.S
-
cong@msi:/work/os/code/4page$ ls -l loader.bin
-
-rw-rw-r-- 1 cong cong 263 Aug 19 18:18 loader.bin
1.2.a 关于段界限的修改
在没有修改阶界限之前是不能访问1M以上字节的,因为刚开始code段的范围是0-0xFFFF
-
<bochs:1> b 0x904e
-
<bochs:2> c
-
(0) Breakpoint 1, 0x0000904e in ?? ()
-
Next at t=156817618
-
(0) [0x00000000904e] 0008:0000904e (unk. ctxt): mov byte ptr gs:0x000000a1, 0xa4 ; 65c605a1000000a4
-
<bochs:3> s
-
Next at t=156817619
-
(0) [0x000000009056] 0008:00009056 (unk. ctxt): call .+81 (0x000090ac) ; e851000000
-
<bochs:4>
-
Next at t=156817620
-
(0) [0x0000000090ac] 0008:000090ac (unk. ctxt): mov ecx, 0x00001000 ; b900100000
-
<bochs:5>
-
Next at t=156817621
-
(0) [0x0000000090b1] 0008:000090b1 (unk. ctxt): xor esi, esi ; 31f6
-
<bochs:6>
-
Next at t=156817622
-
(0) [0x0000000090b3] 0008:000090b3 (unk. ctxt): mov eax, 0x00000007 ; b807000000
-
<bochs:7>
-
Next at t=156817623
-
(0) [0x0000000090b8] 0008:000090b8 (unk. ctxt): mov dword ptr ds:[esi+983040], eax ; 898600000f00
-
<bochs:8>
-
(0).[156817623] [0x0000000090b8] 0008:000090b8 (unk. ctxt): mov dword ptr ds:[esi+983040], eax ; 898600000f00
-
Next at t=156817624
-
(0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0 -->重启了
983040=0xF0000,info gdt后发现没有一个段可以到地址0xF0000
-
<bochs:3> info gdt
-
Global Descriptor Table (base=0x00009002, limit=24):
-
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
-
GDT[0x01]=Code segment, base=0x00000000, limit=0x0000ffff, Execute-Only, Non-Conforming, Accessed, 32-bit -->code段的范轩是0-0xffff
-
GDT[0x02]=Data segment, base=0x000b8000, limit=0x0000ffff, Read/Write, Accessed -->视频段的范围是0xb8000-(0xb8000+0xffff)
-
You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'
这儿需要添加一个数据段,放分页的数据
1.2.b
添加数据段之后忘改段界限了,info gdt 后还是只有3个段
-
-
73 gdt_ptr:
-
74 dw 24 ;gdt_limit: 3*8=32, only 3 gdt item
-
75 dd gdt_base ;gdt_base
-
<bochs:14> info gdt
-
Global Descriptor Table (base=0x00009002, limit=24):
-
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
-
GDT[0x01]=Code segment, base=0x00000000, limit=0x000fffff, Execute-Only, Non-Conforming, Accessed, 32-bit
-
GDT[0x02]=Data segment, base=0x00000000, limit=0x0000ffff, Read/Write
-
You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'
1.2.c
有了数据段之后,就重新设置一个各个段寄存器
-
96 protect_mode:
-
97 mov ax, select_code --->这儿需要修改
-
98 mov ds, ax
-
99 mov es, ax
-
-
<bochs:13>
-
Next at t=156817514
-
(0) [0x000000009040] 0008:00009040 (unk. ctxt): mov ds, ax ; 8ed8
-
<bochs:14>
-
(0).[156817514] [0x000000009040] 0008:00009040 (unk. ctxt): mov ds, ax ; 8ed8
-
Next at t=156817515
-
(0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
1.2.d
出现下面这个情况说明页表没有正确的设置好,PDE没有设置正确
-
Next at t=1252900596
-
(0) [0x0000000090a1] 0008:000090a1 (unk. ctxt): mov cr0, eax ; 0f22c0
-
<bochs:38>
-
Next at t=1252900597
-
(0).[1252900597] ??? (physical address not available)
-
-
-
<bochs:34> xp /31 0x1F0000
-
[bochs]:
-
0x001f0000 <bogus+ 0>: 0x00001007 0x00000007 0x00000007 0x00000007
-
0x001f0010 <bogus+ 16>: 0x00000007 0x00000007 0x00000007 0x00000007
-
0x001f0020 <bogus+ 32>: 0x00000007 0x00000007 0x00000007 0x00000007
-
0x001f0030 <bogus+ 48>: 0x00000007 0x00000007 0x00000007 0x00000007
-
0x001f0040 <bogus+ 64>: 0x00000007 0x00000007 0x00000007 0x00000007
-
0x001f0050 <bogus+ 80>: 0x00000007 0x00000007 0x00000007 0x00000007
-
0x001f0060 <bogus+ 96>: 0x00000007 0x00000007 0x00000007 0x00000007
-
0x001f0070 <bogus+ 112>: 0x00000007 0x00000007 0x00000007
1.2.e
info gdt 出现上万个,说明PDE的属性都设置成可用了,想少打印只需把用得着的属性设为可用即可
-
cr3: 0x000000100000
-
0x00000000-0x000fffff -> 0x000000000000-0x0000000fffff
-
0x00400000-0x00400fff -> 0x0000f000f000-0x0000f000ffff
-
...
-
0xffffe000-0xffffefff -> 0x000000000000-0x000000000fff
0xfffff000-0xffffffff -> 0x000000100000-0x000000100fff 106190个
改完之后
-
<bochs:37> info tab
-
cr3: 0x000000100000
-
0x00000000-0x000fffff -> 0x000000000000-0x0000000fffff
-
0xc0000000-0xc00fffff -> 0x000000000000-0x0000000fffff
-
0xffc00000-0xffc00fff -> 0x000000101000-0x000000101fff
-
0xfff00000-0xfff00fff -> 0x000000101000-0x000000101fff
-
0xfffff000-0xffffffff -> 0x000000100000-0x000000100fff
1.3 正确代码分析
-
org 0x9000
-
jmp begin
-
;segment discript
-
TYPE_8 equ 0x8 ;code -->exec
-
TYPE_2 equ 0x2 ;data -->r/w
-
-
S_0 equ (0x0<<4) ;s=0-->gate
-
S_1 equ (0x1<<4) ;s=1-->data/code
-
-
DPL_0 equ (0x0<<5) ;privilege level
-
DPL_3 equ (0x3<<5)
-
-
P_0 equ (0x00<<7) ;not in memory
-
P_1 equ (0x01<<7) ;in memory
-
-
AVL_0 equ (0x00<<8)
-
-
DB_0 equ (0x00<<10) ;16bit data&code
-
DB_1 equ (0x01<<10) ;32bit data&code
-
-
G_0 equ (0x00<<11) ;g=0,byte
-
G_1 equ (0x01<<11) ;g=1,4K
-
-
TI_0 equ (0x0<<2) ;TI=0,gdt
-
TI_1 equ (0x1<<2) ;TI=1,ldt
-
-
RPL_0 equ (0x0)
-
-
;PAGE
-
PAGE_POS equ 0x1F0000 ;0xF0000-->0xFFFFF-->64K
-
;PAGE_POS equ 0x1F0100 ;这儿测试PTE是否可以在 4K不对齐的地址上,答案是不可以,必须4K对齐
-
PG_P_0 equ (0x0) ;not in memory
-
PG_P_1 equ (0x1) ;in memory
-
-
PG_RW_0 equ (0x0<<1) ;read,not write
-
PG_RW_1 equ (0x1<<1) ;read,write
-
-
PG_US_0 equ (0x0<<2) ;supervisor
-
PG_US_1 equ (0x1<<2) ;user
-
-
PG_PWT_0 equ (0x0<<3) ;memory
-
PG_PWT_1 equ (0x1<<3) ;memory and cache
-
-
PG_PCD_0 equ (0x0<<4) ;disable page level cache
-
PG_PCD_1 equ (0x1<<4) ;enable page level cache
-
-
PG_A_0 equ (0x0<<5) ;not accessed
-
PG_A_1 equ (0x1<<5) ;accessed
-
-
PG_D_0 equ (0x0<<6) ;not dirty
-
PG_D_1 equ (0x1<<6) ;dirty
-
-
PG_PAT_0 equ (0x0<<7) ;page attribute tabel
-
PG_PAT_1 equ (0x1<<7) ;
-
-
PG_G_0 equ (0x0<<8) ;global-->TLB
-
PG_G_1 equ (0x1<<8) ;
-
-
PG_AVL_0 equ (0x0<<9) ;available
-
PG_AVL_1 equ (0x1<<9) ;
-
%macro DESC 3
-
dw %1 & 0xFFFF ;limit[0-15]
-
dw %2 & 0xFFFF ;base[0-15]
-
db (%2>>16)&0xFF ;base[16-23]
-
db (%3&0xFF) ;prop[0-7]
-
db (((%1>>16)&0xF) | (%3>>4)&0xF0) ;limit[16-19]prop[8-11]
-
db (%2>>24) & 0xFF
-
%endmacro
-
gdt_base: DESC 0, 0, 0 ;desc_dummy
-
gdt_code: DESC 0xFFFFFF, 0x0, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_8)
-
gdt_data: DESC 0xFFFFF, 0x0, (G_1|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_2) ;这儿加了一个data段且段界限是0xFFFFF×4K=4G
-
gdt_video: DESC 0xFFFF, 0xB8000, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_2)
-
-
gdt_ptr:
-
dw 32 ;gdt_limit: 4*8=32, only 4 gdt item ;加gdt_data后这儿还是24,死活调不出来
-
dd gdt_base ;gdt_base
-
-
select_code equ (0x01<<3)|TI_0|RPL_0
-
select_data equ (0x02<<3)|TI_0|RPL_0
-
select_video equ (0x03<<3)|TI_0|RPL_0
-
begin:
-
mov cx, ax
-
;----------------- 打开A20 ----------------
-
in al,0x92
-
or al,0000_0010B
-
out 0x92,al
-
-
;----------------- 加载GDT ----------------
-
lgdt [gdt_ptr]
-
-
;----------------- cr0第0位置1 ----------------
-
mov eax, cr0
-
or eax, 0x00000001
-
mov cr0, eax
-
-
;----------------- 跳到保护模式 ----------------
-
jmp select_code:protect_mode
-
[bits 32]
-
protect_mode:
-
mov ax, select_data
-
mov ds, ax
-
mov es, ax
-
mov ax, select_video
-
mov gs, ax
-
mov byte [gs:160], 'P'
-
mov byte [gs:161], 0xA4
-
-
call setup_page_table
-
-
sgdt [gdt_ptr]
-
-
or dword [gdt_ptr+2], 0xC0000000 ; gdt_ptr
-
or byte [gdt_base+7], 0xC0 ;change gdt base addr
-
or byte [gdt_base+8+7], 0xC0 ;change gdt base addr
-
or byte [gdt_base+16+7], 0xC0 ;select_video: byte8
-
-
or esp, 0xC0000000
-
-
mov eax, PAGE_POS
-
mov cr3, eax
-
-
;打开cr0的pg位
-
mov eax, cr0
-
or eax, 0x80000000
-
mov cr0, eax
-
-
lgdt [gdt_ptr]
-
-
mov byte [gs:162], 'G'
-
mov byte [gs:163], 0xA4
-
jmp $
-
-
setup_page_table:
-
mov ecx, 0x400 ;1PTE:4K=0x1000
-
xor esi, esi
-
xor eax, eax
-
_init_page_table:
-
mov [PAGE_POS+esi], eax
-
add esi,0x04
-
loop _init_page_table
-
-
;PDE0, PDE768 use the same PTE0
-
mov eax, (PG_US_1|PG_RW_1|PG_P_1)
-
or eax, ((PAGE_POS+0x1000)&0xFFF000)
-
mov [PAGE_POS+0x0], eax
-
mov [PAGE_POS+0xc00], eax
-
sub eax, 0x1000
-
mov [PAGE_POS+0xFFC], eax
-
-
;PTE for PDE0 and PDE768
-
mov ecx,256
-
xor esi,esi
-
mov eax, (PG_US_1|PG_RW_1|PG_P_1)
-
_create_pte:
-
mov [PAGE_POS+0x1000+esi],eax
-
add esi,0x04
-
add eax,0x1000
-
loop _create_pte
-
-
;create other PDE for kernel
-
-
ret
1.4 代码打包
4page.rar (下载后改名为4page.tar.gz)
1.5 注意
a. PDE[12-31]位存的是 PTE的[12-31]位,而PDE与PTE中存的是物理地址,但是后12位是不存的。
换句话话PDE与PTE只存物理地址的[12-31]位,低12位用来放属性,cpu在查找时直接把PDE与PTE的低12位设为0。
PDE的基地址是4K对齐的,PTE的基地址也是4K对齐的。
b. 这也就是为什么PAGE_POS不能在4K不对齐的地址上的原因
PAGE_POS equ 0x1F0000 ;0xF0000-->0xFFFFF-->64K
;PAGE_POS equ 0x1F0100 ;这儿测试PTE是否可以在 4K不对齐的地址上,答案是不可以,必须4K对齐
阅读(1104) | 评论(0) | 转发(0) |