Linux0.11内核--引导程序分析

来源:互联网 发布:sopcast网络电视 apk 编辑:程序博客网 时间:2024/05/16 20:29

1.简介

本文主要介绍三个文件bootsect.s、setup.s、head.s,主要是做了些从软盘加载内核和设置32位保护模式的操作。

2.程序分析

当PC电源打开后,BIOS自检后将bootsect读入内存绝对地址0x7c00处,因为bootsect.s的结尾是:

1
.word 0xAA55

然后跳转到0x7c00处并把执行权交给此处的代码,从start:处开始执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
BOOTSEG  = 0x07c0  
INITSEG  = 0x9000
 
start:
    mov ax,#BOOTSEG
    mov ds,ax
    mov ax,#INITSEG
    mov es,ax
    mov cx,#256
    sub si,si
    sub di,di
    rep
    movw
    jmpi    go,INITSEG

BOOTSEG是当前程序的起始内存地址的段地址,INITSEG表示是bootsect将要移动要的内存地址的段地址,这段代码的意思是重复执行movw指令256次,每次从BOOTSEG(0x7c0段地址)+si的地址处移动一个字(2个字节)的数据到INITSEG(0x9000段地址)+di地址处,挨个移动256次,所以总共就是256字(512字节),bootsect.s编译出来也就是512字节的大小。所以这段代码执行完之后就是把自己拷贝到0x90000地址处,然后jmpi跳转到0x9000的偏移地址为go的地方执行。

所以接下来程序执行到go:处,但是整个程序的起始段地址变成了0x9000,go处的代码设置了下堆栈,接着是load_setup:

1
2
3
4
5
6
7
8
9
10
11
12
13
SETUPLEN = 4   
 
load_setup:
    mov dx,#0x0000      ! drive 0, head 0
    mov cx,#0x0002      ! sector 2, track 0
    mov bx,#0x0200      ! address = 512, in INITSEG
    mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors
    int0x13            ! read it
    jnc ok_load_setup       ! ok -continue
    mov dx,#0x0000
    mov ax,#0x0000      ! reset the diskette
    int0x13
    j   load_setup

利用BIOS中断int 0x13将setup从磁盘第2个扇区开始读到0x90200开始处,共SETUPLEN(setup 程序的扇区数)读4个扇区。成功后跳转到ok_load_setup。

1
2
3
4
5
6
7
8
9
10
11
SETUPSEG = 0x9020
 
ok_load_setup:
...
    mov ax,#SYSSEG
    mov es,ax       ! segment of 0x010000
    call    read_it
    call    kill_motor
 
...
    jmpi    0,SETUPSEG

省略的代码都是一些读硬盘和驱动器的数据。这里比较关键的是call read_it,调用read_it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
SYSSIZE = 0x3000
SYSSEG   = 0x1000
ENDSEG   = SYSSEG + SYSSIZE
 
read_it:
    mov ax,es
    test ax,#0x0fff
die:    jne die         ! es must be at 64kB boundary
    xor bx,bx       ! bx is starting address within segment
rp_read:
    mov ax,es
    cmp ax,#ENDSEG      ! have we loaded all yet?
    jb ok1_read
    ret
ok1_read:
    ...

SYSSIZE是编译后system模块的大小,SYSSEG是system模块将加载到的内存段地址处,所以ENDSEG的值就是system模块停止加载的段地址。那么read_it的作用就是先判断一下es是不是到了system模块停止加载的段地址处,如果没有则跳转去读取system模块到这个地址。加载完成后就ret返回。然后关闭马达后读一些驱动器的信息,最后jmpi 0,SETUPSEG跳转到0x9020:0000也就是setup.s程序的开始处。

bootsect.s就此结束,到现在为止内核各个模块在内存中的位置如下图的第3步:

接下来进入setup.s。

未完待续

1 0
原创粉丝点击