关于linux v0.01 bootsect.S

时间:2011-10-02 14:12:49

标签: linux assembly bootloader

最近我正在查看linux 0.01源代码,因为2.6.11和更高版本的bootsect.S是无用的,它是一个开始学习linux代码的好地方,因此我选择跟踪第一个版本的Linux操作系统。 :P

我在bootsect.S中有一些问题。以下是bootsect.S linux v 0.01中的一些代码。

P.S第一个版本汇编代码使用的是intel语法而不是& t。

mov   ax,#0x0001  | protected mode (PE) bit
lmsw  ax          | This is it!
jmpi  0,8  | jmp offset 0 of segment 8 (cs) which is the second entry of the gdt.

gdt:

.word    0,0,0,0        | dummy
.word    0x07FF        | 8Mb - limit=2047 (2048*4096=8Mb)
.word    0x0000        | base address=0
.word    0x9A00        | code read/exec
.word    0x00C0        | granularity=4096, 386

.word    0x07FF        | 8Mb - limit=2047 (2048*4096=8Mb)
.word    0x0000        | base address=0
.word    0x9200        | data read/write
.word    0x00C0        | granularity=4096, 386

启动过程似乎如下:

  • 将引导加载程序代码从0x7c00移动到0x9000

  • 跳转到0x9000

  • 设置段寄存器。

  • 将系统代码加载到0x10000 (根据Makefile,系统代码包含boot / head.S和init / main.c)

  • 使用lgdt和lidt加载临时gdt和idt

  • 启用A20以访问16mb物理内存。

  • 将cr0 PE位设置为保护模式

  • 跳转到0x000000

以下是系统的Makefile:

tools/system:   
boot/head.o init/main.o \
$(ARCHIVES) $(LIBS)
$(LD) $(LDFLAGS) boot/head.o init/main.o \
$(ARCHIVES) \
$(LIBS) \

-o tools/system > System.map

似乎head.S和main.c链接在一起作为bootsect加载到内存中的系统二进制文件。

我的问题是系统代码(哪个条目是head.S / startup_32)是否加载到0x10000而不是为什么不跳转到0x10000而不是跳转到0x000000? 跳转到0x0是不是很奇怪,因为里面没有加载代码?

以下是下载源代码的链接: https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=0B1F0m2rUn8BYMjQ4ZDQxZTUtODI5My00MGZiLTgwZDQtM2ZiZWQ2ZWQxYzIx

1 个答案:

答案 0 :(得分:1)

以下是答案:

| It then loads the system at 0x10000, using BIOS interrupts. Thereafter
| it disables all interrupts, moves the system down to 0x0000, ...

以下是与之相关的代码:

        cli                     | no interrupts allowed !

| first we move the system to it's rightful place

        mov     ax,#0x0000
        cld                     | 'direction'=0, movs moves forward
do_move:
        mov     es,ax           | destination segment
        add     ax,#0x1000
        cmp     ax,#0x9000
        jz      end_move
        mov     ds,ax           | source segment
        sub     di,di
        sub     si,si
        mov     cx,#0x8000
        rep
        movsw
        j       do_move

如果仔细观察代码,你会注意到它确实开始执行REP MOVSW,ES = 0,DI = 0(目标),DS = 0x1000,SI = 0(源),也就是说,它移动从0x10000(= DS * 0x10 + SI)到0(= ES * 0x10 + DI)的东西。