《操作系统真相还原》 与 《Orange'S:一个操作系统的实现》都参考了
在上一篇文章中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 $
1.2 看需不需要改mbr
-
cong@msi:/work/os/code/3pm$ ls -l loader.bin
-
-rw-rw-r-- 1 cong cong 86 Aug 17 14:24 loader.bin
才86个字节,mbr是读了512个字节,这儿不到512字节,所以不需要修改mbr.S
下面开始分析问题
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 第一次修改
-
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)
2.2.a 第二次调试
-
(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
2.2.b第二次修改
-
63 [bits 32] -->加入这个标签,使得这儿编出来的是32位的代码
-
64 protect_mode:
2.2.c 对比一下两次生成的二进制代码
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.3 运行结果就对了
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.5 代码打包
3pm.rar (下载后改名为3pm.tar.gz)
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 $
阅读(1961) | 评论(0) | 转发(0) |