Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2112737
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2016-08-19 18:52:21

1. 实现分页机制的代码
  1. org 0x9000
  2. jmp begin
  3. ;segment discript
  4. TYPE_8 equ 0x8 ;code -->exec
  5. TYPE_2 equ 0x2 ;data -->r/w

  6. S_0 equ (0x0<<4) ;s=0-->gate
  7. S_1 equ (0x1<<4) ;s=1-->data/code

  8. DPL_0 equ (0x0<<5) ;privilege level
  9. DPL_3 equ (0x3<<5)

  10. P_0 equ (0x00<<7) ;not in memory
  11. P_1 equ (0x01<<7) ;in memory

  12. AVL_0 equ (0x00<<8)

  13. DB_0 equ (0x00<<10) ;16bit data&code
  14. DB_1 equ (0x01<<10) ;32bit data&code

  15. G_0 equ (0x00<<11) ;g=0,byte
  16. G_1 equ (0x01<<11) ;g=1,4K

  17. TI_0 equ (0x0<<2) ;TI=0,gdt
  18. TI_1 equ (0x1<<2) ;TI=1,ldt

  19. RPL_0 equ (0x0)

  20. ;PAGE
  21. PAGE_POS equ 0xF0000       ;0xF0000-->0xFFFFF-->64K
  22. PG_P_0 equ (0x0)           ;not in memory
  23. PG_P_1 equ (0x1)           ;in memory

  24. PG_RW_0 equ (0x0<<1) ;read,not write
  25. PG_RW_1 equ (0x1<<1) ;read,write

  26. PG_US_0 equ (0x0<<2) ;supervisor
  27. PG_US_1 equ (0x1<<2) ;user

  28. PG_PWT_0 equ (0x0<<3) ;memory
  29. PG_PWT_1 equ (0x1<<3) ;memory and cache

  30. PG_PCD_0 equ (0x0<<4) ;disable page level cache
  31. PG_PCD_1 equ (0x1<<4) ;enable page level cache

  32. PG_A_0 equ (0x0<<5) ;not accessed
  33. PG_A_1 equ (0x1<<5) ;accessed

  34. PG_D_0 equ (0x0<<6) ;not dirty
  35. PG_D_1 equ (0x1<<6) ;dirty

  36. PG_PAT_0 equ (0x0<<7) ;page attribute tabel
  37. PG_PAT_1 equ (0x1<<7) ;

  38. PG_G_0 equ (0x0<<8) ;global-->TLB
  39. PG_G_1 equ (0x1<<8) ;

  40. PG_AVL_0 equ (0x0<<9) ;available
  41. PG_AVL_1 equ (0x1<<9) ;
  42. %macro DESC 3
  43.     dw %1 & 0xFFFF ;limit[0-15]
  44.     dw %2 & 0xFFFF ;base[0-15]
  45.     db (%2>>16)&0xFF ;base[16-23]
  46.     db (%3&0xFF) ;prop[0-7]
  47.     db (((%1>>16)&0xF) | (%3>>4)&0xF0) ;limit[16-19]prop[8-11]
  48.     db (%2>>24) & 0xFF
  49. %endmacro
  50. gdt_base: DESC 0, 0, 0
  51. gdt_code: DESC 0xFFFF, 0x0, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_8)
  52. gdt_video: DESC 0xFFFF, 0xB8000, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_2)

  53. gdt_ptr:
  54.     dw 24 ;gdt_limit: 8*3=16, only 3 gdt item
  55.     dd gdt_base ;gdt_base

  56. select_code equ (0x01<<3)|TI_0|RPL_0
  57. select_video equ (0x02<<3)|TI_0|RPL_0
  58. begin:
  59.     mov ah, 0x88
  60.     int 0x15
  61.     mov cx, ax
  62.     ;----------------- 打开A20 ----------------
  63.     in al,0x92
  64.     or al,0000_0010B
  65.     out 0x92,al

  66.     ;----------------- 加载GDT ----------------
  67.     lgdt [gdt_ptr]

  68.     ;----------------- cr0第0位置1 ----------------
  69.     mov eax, cr0
  70.     or eax, 0x00000001
  71.     mov cr0, eax

  72.     ;----------------- 跳到保护模式 ----------------
  73.     jmp select_code:protect_mode
  74. [bits 32]
  75. protect_mode:
  76.     mov ax,select_video
  77.     mov gs,ax
  78.     mov byte [gs:160], 'P'
  79.     mov byte [gs:161], 0xA4

  80.     call setup_page_table    

  81.     sgdt [gdt_ptr]
  82.     
  83.     or dword [gdt_ptr+2], 0xC0000000 ; gdt_ptr
  84.     or byte [gdt_base+7], 0xC0 ;change gdt base addr
  85.     or byte [gdt_base+16+7], 0xC0 ;select_video: byte8

  86.     or esp, 0xC0000000

  87.     mov eax, PAGE_POS
  88.     mov cr3, eax
  89.         
  90.     ;打开cr0的pg位
  91.     mov eax, cr0
  92.     or eax, 0x80000000
  93.     mov cr0, eax

  94.     lgdt [gdt_ptr]

  95.     mov byte [gs:162], 'G'
  96.     mov byte [gs:163], 0xA4
  97.     jmp $

  98. setup_page_table:
  99.     mov ecx, 0x1000 ;1PTE:4K=0x1000      -->清空4k个字节每次清4个字节,这儿应为0x1000/4=0x400
  100.     xor esi, esi
  101.     mov eax, (PG_US_1|PG_RW_1|PG_P_1)    -->如果一开始就把PTE设为可用的话,bochs里面info tab会打印出上万条映射
  102. _init_page_table:
  103.     mov [PAGE_POS+esi], eax
  104.     add esi,0x04
  105.     loop _init_page_table

  106.     ;PDE0, PDE768 use the same PTE0
  107.     or eax,(0x01<<12)
  108.     mov [PAGE_POS+0x0], eax
  109.     mov [PAGE_POS+0xc00], eax

  110.     ;PTE for PDE0 and PDE768
  111.     mov ecx,256
  112.     xor esi,esi
  113.     mov eax, (PG_US_1|PG_RW_1|PG_P_1)
  114. _create_pte:
  115.     mov [PAGE_POS+0x1000+esi],eax
  116.     add esi,0x04
  117.     add eax,0x1000
  118.     loop _create_pte

  119.     ;create other PDE for kernel

  120.     ret

1.1 由于loader.bin没有超过512,所以不需要改mbr.S
  1. cong@msi:/work/os/code/4page$ ls -l loader.bin
  2. -rw-rw-r-- 1 cong cong 263 Aug 19 18:18 loader.bin
1.2.a 关于段界限的修改
在没有修改阶界限之前是不能访问1M以上字节的,因为刚开始code段的范围是0-0xFFFF
  1. <bochs:1> b 0x904e
  2. <bochs:2> c
  3. (0) Breakpoint 1, 0x0000904e in ?? ()
  4. Next at t=156817618
  5. (0) [0x00000000904e] 0008:0000904e (unk. ctxt): mov byte ptr gs:0x000000a1, 0xa4 ; 65c605a1000000a4
  6. <bochs:3> s
  7. Next at t=156817619
  8. (0) [0x000000009056] 0008:00009056 (unk. ctxt): call .+81 (0x000090ac) ; e851000000
  9. <bochs:4>
  10. Next at t=156817620
  11. (0) [0x0000000090ac] 0008:000090ac (unk. ctxt): mov ecx, 0x00001000 ; b900100000
  12. <bochs:5>
  13. Next at t=156817621
  14. (0) [0x0000000090b1] 0008:000090b1 (unk. ctxt): xor esi, esi ; 31f6
  15. <bochs:6>
  16. Next at t=156817622
  17. (0) [0x0000000090b3] 0008:000090b3 (unk. ctxt): mov eax, 0x00000007 ; b807000000
  18. <bochs:7>
  19. Next at t=156817623
  20. (0) [0x0000000090b8] 0008:000090b8 (unk. ctxt): mov dword ptr ds:[esi+983040], eax ; 898600000f00
  21. <bochs:8>
  22. (0).[156817623] [0x0000000090b8] 0008:000090b8 (unk. ctxt): mov dword ptr ds:[esi+983040], eax ; 898600000f00
  23. Next at t=156817624
  24. (0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0   -->重启了
983040=0xF0000,info gdt后发现没有一个段可以到地址0xF0000
  1. <bochs:3> info gdt
  2. Global Descriptor Table (base=0x00009002, limit=24):
  3. GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
  4. GDT[0x01]=Code segment, base=0x00000000, limit=0x0000ffff, Execute-Only, Non-Conforming, Accessed, 32-bit   -->code段的范轩是0-0xffff
  5. GDT[0x02]=Data segment, base=0x000b8000, limit=0x0000ffff, Read/Write, Accessed                             -->视频段的范围是0xb8000-(0xb8000+0xffff)
  6. You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'
这儿需要添加一个数据段,放分页的数据
1.2.b
添加数据段之后忘改段界限了,info gdt 后还是只有3个段
    1.  73 gdt_ptr:
    2.  74 dw 24 ;gdt_limit: 3*8=32, only 3 gdt item
    3.  75 dd gdt_base ;gdt_base
  1. <bochs:14> info gdt
  2. Global Descriptor Table (base=0x00009002, limit=24):
  3. GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
  4. GDT[0x01]=Code segment, base=0x00000000, limit=0x000fffff, Execute-Only, Non-Conforming, Accessed, 32-bit
  5. GDT[0x02]=Data segment, base=0x00000000, limit=0x0000ffff, Read/Write
  6. You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'

1.2.c
有了数据段之后,就重新设置一个各个段寄存器
  1.  96 protect_mode:
  2.  97 mov ax, select_code   --->这儿需要修改
  3.  98 mov ds, ax
  4.  99 mov es, ax

  5. <bochs:13>
  6. Next at t=156817514
  7. (0) [0x000000009040] 0008:00009040 (unk. ctxt): mov ds, ax ; 8ed8
  8. <bochs:14>
  9. (0).[156817514] [0x000000009040] 0008:00009040 (unk. ctxt): mov ds, ax ; 8ed8
  10. Next at t=156817515
  11. (0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0

1.2.d 
出现下面这个情况说明页表没有正确的设置好,PDE没有设置正确
  1. Next at t=1252900596
  2. (0) [0x0000000090a1] 0008:000090a1 (unk. ctxt): mov cr0, eax ; 0f22c0
  3. <bochs:38>
  4. Next at t=1252900597
  5. (0).[1252900597] ??? (physical address not available)


  6. <bochs:34> xp /31 0x1F0000
  7. [bochs]:
  8. 0x001f0000 <bogus+ 0>: 0x00001007 0x00000007 0x00000007 0x00000007
  9. 0x001f0010 <bogus+ 16>: 0x00000007 0x00000007 0x00000007 0x00000007
  10. 0x001f0020 <bogus+ 32>: 0x00000007 0x00000007 0x00000007 0x00000007
  11. 0x001f0030 <bogus+ 48>: 0x00000007 0x00000007 0x00000007 0x00000007
  12. 0x001f0040 <bogus+ 64>: 0x00000007 0x00000007 0x00000007 0x00000007
  13. 0x001f0050 <bogus+ 80>: 0x00000007 0x00000007 0x00000007 0x00000007
  14. 0x001f0060 <bogus+ 96>: 0x00000007 0x00000007 0x00000007 0x00000007
  15. 0x001f0070 <bogus+ 112>: 0x00000007 0x00000007 0x00000007
1.2.e
info gdt 出现上万个,说明PDE的属性都设置成可用了,想少打印只需把用得着的属性设为可用即可
  1. cr3: 0x000000100000
  2. 0x00000000-0x000fffff -> 0x000000000000-0x0000000fffff
  3. 0x00400000-0x00400fff -> 0x0000f000f000-0x0000f000ffff
  4. ...
  5. 0xffffe000-0xffffefff -> 0x000000000000-0x000000000fff
    0xfffff000-0xffffffff -> 0x000000100000-0x000000100fff  106190个
改完之后
  1. <bochs:37> info tab
  2. cr3: 0x000000100000
  3. 0x00000000-0x000fffff -> 0x000000000000-0x0000000fffff
  4. 0xc0000000-0xc00fffff -> 0x000000000000-0x0000000fffff
  5. 0xffc00000-0xffc00fff -> 0x000000101000-0x000000101fff
  6. 0xfff00000-0xfff00fff -> 0x000000101000-0x000000101fff
  7. 0xfffff000-0xffffffff -> 0x000000100000-0x000000100fff
1.3 正确代码分析
  1. org 0x9000
  2. jmp begin
  3. ;segment discript
  4. TYPE_8 equ 0x8 ;code -->exec
  5. TYPE_2 equ 0x2 ;data -->r/w

  6. S_0 equ (0x0<<4) ;s=0-->gate
  7. S_1 equ (0x1<<4) ;s=1-->data/code

  8. DPL_0 equ (0x0<<5) ;privilege level
  9. DPL_3 equ (0x3<<5)

  10. P_0 equ (0x00<<7) ;not in memory
  11. P_1 equ (0x01<<7) ;in memory

  12. AVL_0 equ (0x00<<8)

  13. DB_0 equ (0x00<<10) ;16bit data&code
  14. DB_1 equ (0x01<<10) ;32bit data&code

  15. G_0 equ (0x00<<11) ;g=0,byte
  16. G_1 equ (0x01<<11) ;g=1,4K

  17. TI_0 equ (0x0<<2) ;TI=0,gdt
  18. TI_1 equ (0x1<<2) ;TI=1,ldt

  19. RPL_0 equ (0x0)

  20. ;PAGE
  21. PAGE_POS equ 0x1F0000    ;0xF0000-->0xFFFFF-->64K
  22. ;PAGE_POS equ 0x1F0100   ;这儿测试PTE是否可以在 4K不对齐的地址上,答案是不可以,必须4K对齐
  23. PG_P_0 equ (0x0) ;not in memory
  24. PG_P_1 equ (0x1) ;in memory

  25. PG_RW_0 equ (0x0<<1) ;read,not write
  26. PG_RW_1 equ (0x1<<1) ;read,write

  27. PG_US_0 equ (0x0<<2) ;supervisor
  28. PG_US_1 equ (0x1<<2) ;user

  29. PG_PWT_0 equ (0x0<<3) ;memory
  30. PG_PWT_1 equ (0x1<<3) ;memory and cache

  31. PG_PCD_0 equ (0x0<<4) ;disable page level cache
  32. PG_PCD_1 equ (0x1<<4) ;enable page level cache

  33. PG_A_0 equ (0x0<<5) ;not accessed
  34. PG_A_1 equ (0x1<<5) ;accessed

  35. PG_D_0 equ (0x0<<6) ;not dirty
  36. PG_D_1 equ (0x1<<6) ;dirty

  37. PG_PAT_0 equ (0x0<<7) ;page attribute tabel
  38. PG_PAT_1 equ (0x1<<7) ;

  39. PG_G_0 equ (0x0<<8) ;global-->TLB
  40. PG_G_1 equ (0x1<<8) ;

  41. PG_AVL_0 equ (0x0<<9) ;available
  42. PG_AVL_1 equ (0x1<<9) ;
  43. %macro DESC 3
  44.     dw %1 & 0xFFFF ;limit[0-15]
  45.     dw %2 & 0xFFFF ;base[0-15]
  46.     db (%2>>16)&0xFF ;base[16-23]
  47.     db (%3&0xFF) ;prop[0-7]
  48.     db (((%1>>16)&0xF) | (%3>>4)&0xF0) ;limit[16-19]prop[8-11]
  49.     db (%2>>24) & 0xFF
  50. %endmacro
  51. gdt_base: DESC 0, 0, 0 ;desc_dummy
  52. gdt_code: DESC 0xFFFFFF, 0x0, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_8)
  53. gdt_data: DESC 0xFFFFF, 0x0, (G_1|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_2)          ;这儿加了一个data段且段界限是0xFFFFF×4K=4G
  54. gdt_video: DESC 0xFFFF, 0xB8000, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_2)

  55. gdt_ptr:
  56.     dw 32       ;gdt_limit: 4*8=32, only 4 gdt item         ;加gdt_data后这儿还是24,死活调不出来
  57.     dd gdt_base ;gdt_base

  58. select_code equ (0x01<<3)|TI_0|RPL_0
  59. select_data equ (0x02<<3)|TI_0|RPL_0
  60. select_video equ (0x03<<3)|TI_0|RPL_0
  61. begin:
  62.     mov cx, ax
  63.     ;----------------- 打开A20 ----------------
  64.     in al,0x92
  65.     or al,0000_0010B
  66.     out 0x92,al

  67.     ;----------------- 加载GDT ----------------
  68.     lgdt [gdt_ptr]

  69.     ;----------------- cr0第0位置1 ----------------
  70.     mov eax, cr0
  71.     or eax, 0x00000001
  72.     mov cr0, eax

  73.     ;----------------- 跳到保护模式 ----------------
  74.     jmp select_code:protect_mode
  75. [bits 32]
  76. protect_mode:
  77.     mov ax, select_data
  78.     mov ds, ax
  79.     mov es, ax
  80.     mov ax, select_video
  81.     mov gs, ax
  82.     mov byte [gs:160], 'P'
  83.     mov byte [gs:161], 0xA4

  84.     call setup_page_table    

  85.     sgdt [gdt_ptr]
  86.     
  87.     or dword [gdt_ptr+2], 0xC0000000     ; gdt_ptr
  88.     or byte [gdt_base+7], 0xC0           ;change gdt base addr
  89.     or byte [gdt_base+8+7], 0xC0         ;change gdt base addr
  90.     or byte [gdt_base+16+7], 0xC0        ;select_video: byte8

  91.     or esp, 0xC0000000

  92.     mov eax, PAGE_POS
  93.     mov cr3, eax
  94.         
  95.     ;打开cr0的pg位
  96.     mov eax, cr0
  97.     or eax, 0x80000000
  98.     mov cr0, eax

  99.     lgdt [gdt_ptr]

  100.     mov byte [gs:162], 'G'
  101.     mov byte [gs:163], 0xA4
  102.     jmp $

  103. setup_page_table:
  104.     mov ecx, 0x400 ;1PTE:4K=0x1000
  105.     xor esi, esi
  106.     xor eax, eax
  107. _init_page_table:
  108.     mov [PAGE_POS+esi], eax
  109.     add esi,0x04
  110.     loop _init_page_table

  111.     ;PDE0, PDE768 use the same PTE0
  112.     mov eax, (PG_US_1|PG_RW_1|PG_P_1)
  113.     or eax, ((PAGE_POS+0x1000)&0xFFF000)     
  114.     mov [PAGE_POS+0x0], eax
  115.     mov [PAGE_POS+0xc00], eax
  116.     sub eax, 0x1000
  117.     mov [PAGE_POS+0xFFC], eax

  118.     ;PTE for PDE0 and PDE768
  119.     mov ecx,256
  120.     xor esi,esi
  121.     mov eax, (PG_US_1|PG_RW_1|PG_P_1)
  122. _create_pte:
  123.     mov [PAGE_POS+0x1000+esi],eax
  124.     add esi,0x04
  125.     add eax,0x1000
  126.     loop _create_pte

  127.     ;create other PDE for kernel

  128.     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对齐
阅读(1040) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~