1. boot目录中的代码流程
1.1 boot编译完成后是mbr在磁盘的第[1]扇区
boot扇区代码是bootsect.s
a. 将自己从0x7c00-->0x9000,512=0x200, [0x90000,0x90200]
b. 加载setup,即将磁盘第2个扇区的setup加载到0x90200,共4个扇区[0x90200-0x90A00]
c. 加载system到0x10000(64K)处,从0x1000(64K)-0x90000(576K)都是system的代码
d. 跳到0x90200处的setup运行
1.2 setup.s的流程,编译完成后是setup在磁盘的第[2-6]扇区
a.获取mem的容量,显卡模式,硬盘信息
b.把[0x10000-0x90000]的内存移动到[0x0000-0x80000],即把system移动到了0x0处
c. 加载gdt idt,开启保护模式
d. 跳到0x0处,即system处
1.3 head.s的流程
a. 运行地址是0x0,重新设置idt gdt check_x87
b. 在0x00地址处设置页目录表1个[0x0-0x1000]
页表4个[0x1000-0x2000] [0x2000-0x3000] [0x3000-0x4000] [0x4000-0x5000]
c. 跳到main
1.4 linux0.12在磁盘上的分布
注: 上图出自《Linux内核完全注释(修正版v3.0).pdf》赵炯
1.5 boot完成后
内存地址分布如下所示:
[0x67d8] -->main 0x000067d8
[0x5cc0-0x64c0] -->gdt 2k
[0x54c0-0x5cc0] -->idt 2k
[0x54ac-0x54b4] -->gdt_desc [8b]
[0x54ac-0x54b4] -->idt_desc [8b]
[0x5450-0x54a8] -->setup_paging
[0x5428-0x5450] -->ignore_init
[0x5412-0x5428] -->字符串 Unknown interrupt\n\r
[0x5400-0x5412] -->after_page_tables -->函数占字节0x10
[0x5000-0x5400] -->软盘缓冲区 [1k]
[0x4000-0x5000] -->页表3 [4k]
[0x3000-0x4000] -->页表2 [4k]
[0x2000-0x3000] -->页表1 [4k]
[0x1000-0x2000] -->页表0 [4k]
[0x0000-0x1000] -->页目录表 [4k]
注: 页目录表-->setup_paging的内容没错,后面的idt_desc的具体地址可能会有几个字节的错误,
错了没关系,知道这儿有什么就行了。
2. 几个问题
问题1.为什么head.s在system的最开始处
a. 将main.o与head.o调换一下,然后重新编译
-
tools/system: boot/head.o init/main.o \
-
$(ARCHIVES) $(DRIVERS) $(MATH) $(LIBS)
-
$(LD) $(LDFLAGS) init/main.o boot/head.o \ -->将head.o与main.o调换一下
-
$(ARCHIVES) \
-
$(DRIVERS) \
-
$(MATH) \
-
$(LIBS) \
-
-o tools/system > System.map
b.调试一下
-
Next at t=0
-
(0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
-
<bochs:1> b 0x00
-
<bochs:2> c
-
(0) Breakpoint 1, 0x00000000 in ?? ()
-
Next at t=425316395
-
(0) [0x000000000000] 0008:00000000 (unk. ctxt): sub esp, 0x00000010 ; 83ec10
-
<bochs:3> n
-
Next at t=425316396
-
(0) [0x000000000003] 0008:00000003 (unk. ctxt): mov eax, 0x00000002 ; b802000000
-
<bochs:4> n
-
Next at t=425316397
-
(0) [0x000000000008] 0008:00000008 (unk. ctxt): int 0x80 ; cd80
-
<bochs:5> n
-
(0).[425316397] [0x000000000008] 0008:00000008 (unk. ctxt): int 0x80 ; cd80
-
Next at t=425316398
-
(0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
c. 调换后,发现0x0的代码来于main.o
-
cong@msi:/work/os/linux12$ objdump -S init/main.o
-
init/main.o: file format elf32-i386
-
Disassembly of section .text:
-
00000000 <fork>:
-
inline _syscall0(int,fork)
-
0: 83 ec 10 sub $0x10,%esp
-
3: b8 02 00 00 00 mov $0x2,%eax
-
8: cd 80 int $0x80
-
a: 89 44 24 0c mov %eax,0xc(%esp)
-
e: 83 7c 24 0c 00 cmpl $0x0,0xc(%esp)
d.总结
这个是由链接器决定的,ld在链接时把head.o放在前面,就把head.o链接到了目标的最前面
问题2.在0x0处既有head.s的代码也有页表,这两个是不是冲突?
a. 下面是bochs的调试结果:
-
Next at t=0
-
(0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
-
<bochs:1> b 0x0 -->在0x00处设断点
-
<bochs:2> c
-
(0) Breakpoint 1, 0x00000000 in ?? ()
-
Next at t=606666395
-
(0) [0x000000000000] 0008:00000000 (unk. ctxt): mov eax, 0x00000010 ; b810000000
-
<bochs:3> n
-
Next at t=606666396
-
(0) [0x000000000005] 0008:00000005 (unk. ctxt): mov ds, ax ; 8ed8
-
<bochs:4> n
-
Next at t=606666397
-
(0) [0x000000000007] 0008:00000007 (unk. ctxt): mov es, ax ; 8ec0
-
<bochs:5>
-
Next at t=606666398
-
(0) [0x000000000009] 0008:00000009 (unk. ctxt): mov fs, ax ; 8ee0
-
<bochs:6>
-
Next at t=606666399
-
(0) [0x00000000000b] 0008:0000000b (unk. ctxt): mov gs, ax ; 8ee8
-
<bochs:7>
-
Next at t=606666400
-
(0) [0x00000000000d] 0008:0000000d (unk. ctxt): lss esp, ds:0x0002ab80 ; 0fb22580ab0200
-
<bochs:8>
-
Next at t=606666401
-
(0) [0x000000000014] 0008:00000014 (unk. ctxt): call .+90 (0x00000073) ; e85a000000 -->call setup_idt
-
<bochs:9> n
-
Next at t=606667690
-
(0) [0x000000000019] 0008:00000019 (unk. ctxt): call .+133 (0x000000a3) ; e885000000 -->call setup_gdt
-
<bochs:10> n
-
Next at t=606667693
-
(0) [0x00000000001e] 0008:0000001e (unk. ctxt): mov eax, 0x00000010 ; b810000000
-
<bochs:11>
-
Next at t=606667694
-
(0) [0x000000000023] 0008:00000023 (unk. ctxt): mov ds, ax ; 8ed8
-
<bochs:12>
-
Next at t=606667695
-
(0) [0x000000000025] 0008:00000025 (unk. ctxt): mov es, ax ; 8ec0
-
<bochs:13>
-
Next at t=606667696
-
(0) [0x000000000027] 0008:00000027 (unk. ctxt): mov fs, ax ; 8ee0
-
<bochs:14>
-
Next at t=606667697
-
(0) [0x000000000029] 0008:00000029 (unk. ctxt): mov gs, ax ; 8ee8
-
<bochs:15>
-
Next at t=606667698
-
(0) [0x00000000002b] 0008:0000002b (unk. ctxt): lss esp, ds:0x0002ab80 ; 0fb22580ab0200
-
<bochs:16>
-
Next at t=606667699
-
(0) [0x000000000032] 0008:00000032 (unk. ctxt): xor eax, eax ; 31c0
-
<bochs:17> n
-
Next at t=606667700
-
(0) [0x000000000034] 0008:00000034 (unk. ctxt): inc eax ; 40
-
<bochs:18>
-
Next at t=606667701
-
(0) [0x000000000035] 0008:00000035 (unk. ctxt): mov dword ptr ds:0x00000000, eax ; a300000000
-
<bochs:19>
-
Next at t=606667702
-
(0) [0x00000000003a] 0008:0000003a (unk. ctxt): cmp dword ptr ds:0x00100000, eax ; 390500001000
-
<bochs:20>
-
Next at t=606667703
-
(0) [0x000000000040] 0008:00000040 (unk. ctxt): jz .-14 (0x00000034) ; 74f2
-
<bochs:21>
-
Next at t=606667704
-
(0) [0x000000000042] 0008:00000042 (unk. ctxt): mov eax, cr0 ; 0f20c0
-
<bochs:22> n
-
Next at t=606667705
-
(0) [0x000000000045] 0008:00000045 (unk. ctxt): and eax, 0x80000011 ; 2511000080
-
<bochs:23>
-
Next at t=606667706
-
(0) [0x00000000004a] 0008:0000004a (unk. ctxt): or eax, 0x00000002 ; 83c802
-
<bochs:24>
-
Next at t=606667707
-
(0) [0x00000000004d] 0008:0000004d (unk. ctxt): mov cr0, eax ; 0f22c0
-
<bochs:25>
-
Next at t=606667708
-
(0) [0x000000000050] 0008:00000050 (unk. ctxt): call .+5 (0x0000005a) ; e805000000 -->call check_x87
-
<bochs:26>
-
Next at t=606667716
-
(0) [0x000000000055] 0008:00000055 (unk. ctxt): jmp .+21414 (0x00005400) ; e9a6530000 --> jmp after_page_tables
-
<bochs:27> n
-
Next at t=606667717
-
(0) [0x000000005400] 0008:00005400 (unk. ctxt): push 0x00000000 ; 6a00 -->一下子跳到了0x5400处
-
<bochs:28> n
Next at t=606667718
(0) [0x000000005402] 0008:00005402 (unk. ctxt): push 0x00000000 ; 6a00
<bochs:29> n
Next at t=606667719
(0) [0x000000005404] 0008:00005404 (unk. ctxt): push 0x00000000 ; 6a00
<bochs:30> n
Next at t=606667720
(0) [0x000000005406] 0008:00005406 (unk. ctxt): push 0x00005412 ; 6812540000
<bochs:31> n
Next at t=606667721
(0) [0x00000000540b] 0008:0000540b (unk. ctxt): push 0x000067d8 ; 68d8670000
<bochs:32> n
Next at t=606667722
(0) [0x000000005410] 0008:00005410 (unk. ctxt): jmp .+62 (0x00005450) ; eb3e --> jmp setup_paging
b.从上面的调试可以看出:
在0x00地址处设置页目录表1个[0x0-0x1000] 页表4个[0x1000-0x5000]
call setup_idt
-->setup_idt函数本身的地址是0x73,但中断处理函数的ignore_int与idt_descr都在0x50000以后
call setup_gdt
-->setup_gdt函数本身的地址是0xa3,但gdt_descr在0x50000以后
call check_x87
-->check_x87函数本身的地址是0x5a
setup_idt setup_gdt check_x87的地址虽然会被页表所覆盖,但是它们只需要执行一次,执行完再被覆盖也没有关系
-
setup_idt:
-
lea ignore_int,%edx
-
(0) [0x000000000073] 0008:00000073 (unk. ctxt): lea edx, dword ptr ds:0x00005428 ; 8d1528540000
-
-
lidt idt_descr
-
Next at t=931567493
-
(0) [0x00000000009b] 0008:0000009b (unk. ctxt): lidt ds:0x000054ae ; 0f011dae540000
-
-
lgdt gdt_descr
-
Next at t=931567496
-
(0) [0x0000000000a3] 0008:000000a3 (unk. ctxt): lgdt ds:0x000054b6 ; 0f0115b6540000
阅读(1602) | 评论(0) | 转发(0) |