《操作系统真相还原》 与 《Orange'S:一个操作系统的实现》都参考了
在上一篇文章中mbr读取了硬盘上的一个sector到0x9000,然后跳到了0x9000运行
1. 第一次写的loader.S
1.2 看需不需要改mbr
才86个字节,mbr是读了512个字节,这儿不到512字节,所以不需要修改mbr.S
下面开始分析问题
2.
2.1.a 第一次调试
2.2.b第二次修改
2.2.c 对比一下两次生成的二进制代码
xxd ./loader.bin
2.3 运行结果就对了
2.4 虽然结果上是对了,但还有点小问题
2.5 代码打包
3pm.rar
(下载后改名为3pm.tar.gz)
2.6 下面分析一下代码
在上一篇文章中mbr读取了硬盘上的一个sector到0x9000,然后跳到了0x9000运行
1. 第一次写的loader.S
- org 0x9000
- jmp begin
-
- TYPE_0 equ 0x0
-
- 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)
-
- %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>>8)&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)
- gdt_video: DESC 0xFFFF, 0xB8000, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1)
-
- 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:
- ;----------------- 打开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
- protect_mode:
- mov ax,select_video
- mov gs,ax
- mov byte [gs:160], 'P'
- jmp $
- cong@msi:/work/os/code/3pm$ ls -l loader.bin
- -rw-rw-r-- 1 cong cong 86 Aug 17 14:24 loader.bin
下面开始分析问题
2.
2.1.a 第一次调试
- (0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
- <bochs:1> b 0x9000 -->因为把代码加载到了0x9000,所以这儿直接到0x9000执行
- <bochs:2> c
- (0) Breakpoint 1, 0x00009000 in ?? ()
- Next at t=156817505
- .....
- <bochs:11>
- Next at t=156817513
- (0) [0x000000009035] 0000:00009035 (unk. ctxt): jmpf 0x0008:903a ; ea3a900800 -->向保护模式跳转
- <bochs:12>
- (0).[156817513] [0x000000009035] 0000:00009035 (unk. ctxt): jmpf 0x0008:903a ; ea3a900800
- Next at t=156817514
- (0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0 -->这儿发现不对了,这儿是复位了
2.1.b 第一次修改
2.2.a 第二次调试
- cong@msi:/work/os/code/3pm$ diff ./loader.S loader.S_bad
- 4,5c4
- < TYPE_8 equ 0x8 ;code -->exec
- < TYPE_2 equ 0x2 ;data -->r/w
- ---
- > TYPE_0 equ 0x0
- 38,39c37,38
- < gdt_code: DESC 0xFFFF, 0x0, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_8) -->code段加上可执行权限
- < gdt_video: DESC 0xFFFF, 0xB8000, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1|TYPE_2)
- ---
- > gdt_code: DESC 0xFFFF, 0x0, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1) -->原先code段没有可执行权限
- > gdt_video: DESC 0xFFFF, 0xB8000, (G_0|DB_1|AVL_0|P_1|DPL_0|S_1)
- (0) [0x000000009039] 0000:00009039 (unk. ctxt): jmpf 0x0008:903e ; ea3e900800
- <bochs:15>
- Next at t=313385561
- (0) [0x00000000903e] 0008:0000903e (unk. ctxt): mov eax, 0xe88e0010 ; b810008ee8 -->这儿的确是跳到903e上面来了,但是还是乱的
- <bochs:16>
- Next at t=313385562
- (0) [0x000000009043] 0008:00009043 (unk. ctxt): mov byte ptr gs:[esi], 0xa0 ; 65c606a0
- <bochs:17>
- Next at t=313385563
- (0) [0x000000009047] 0008:00009047 (unk. ctxt): add byte ptr ds:[eax+101], dl ; 005065
- <bochs:18>
- (0).[313385563] [0x000000009047] 0008:00009047 (unk. ctxt): add byte ptr ds:[eax+101], dl ; 005065
- Next at t=313385564
- (0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
- <bochs:19>
- Next at t=313385565
- (0) [0x0000000fe05b] f000:e05b (unk. ctxt): xor ax, ax ; 31c0
- 63 [bits 32] -->加入这个标签,使得这儿编出来的是32位的代码
- 64 protect_mode:
xxd ./loader.bin
- 0000000: eb1e 0000 0000 0000 0000 ffff 0000 0098 ................
- 0000010: 4f00 ffff 0080 0b92 4f00 1800 0290 0000 O.......O.......
- 0000020: e492 0c02 e692 0f01 161a 900f 20c0 6683 ............ .f. -->没有加[bits 32]标签
- 0000030: c801 0f22 c0ea 3a90 0800 b810 008e e865 ..."..:........e
- 0000040: c606 a000 50eb fe ....P..
-
-
- 0000000: eb1e 0000 0000 0000 0000 ffff 0000 0098 ................
- 0000010: 4f00 ffff 0080 0b92 4f00 1800 0290 0000 O.......O.......
- 0000020: e492 0c02 e692 0f01 161a 900f 20c0 6683 ............ .f. -->加了[bits 32]标签
- 0000030: c801 0f22 c0ea 3a90 0800 66b8 1000 8ee8 ..."..:...f.....
- 0000040: 65c6 05a0 0000 0050 ebfe e......P..

2.4 虽然结果上是对了,但还有点小问题
- cong@msi:/work/os/code/3pm$ diff ./loader.S loader.S_ok
- 34c34
- < db (((%1>>8)&0xF) | (%3>>4)&0xF0) ;limit[16-19]prop[8-11] -->arg1的前16位己填序,现在要填16-19位
- ---
- > db (((%1>>16)&0xF) | (%3>>4)&0xF0) ;limit[16-19]prop[8-11] -->所以要右称16位

2.6 下面分析一下代码
- cong@msi:/work/os/code/3pm$ cat loader.S
- org 0x9000 --> org是条伪指令不会生成二进制的代码
- jmp begin --> jmp下面是数据,cpu区分不了数据与代码,防止cpu把数据当成代码就加上jmp,人为的控制cpu去执行代码段中的代码
-->下面定义了一堆段属性
- 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)
- -->宏中arg1=段界限,arg2=段基址, arg3=段属性
- %macro DESC 3 -->这儿采用了《Orange'S:一个操作系统的实现》中的宏,用宏之后就比较直观
- 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=24, 只预留了3个gdt描述符的段界限
- dd gdt_base ;gdt_base gdt的基地址就是gdt_base这个标签的地址
-
- select_code equ (0x01<<3)|TI_0|RPL_0
- select_video equ (0x02<<3)|TI_0|RPL_0
-
- begin:
- ;----------------- 打开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
- jmp $