从这一节开始,分析代码,我会分析的比较细,适合像我这种水平比较低的同学看。
代码大家可以从http://download.csdn.net/tag/linux0.11%E5%86%85%E6%A0%B8下载
.equ SETUPLEN, 4 # nr of setup-sectors
.equ BOOTSEG, 0x07c0 # original address of boot-sector
.equ INITSEG, 0x9000 # we move boot here - out of the way
.equ SETUPSEG, 0x9020 # setup starts here
.equ SYSSEG, 0x1000 # system loaded at 0x10000 (65536).
.equ ENDSEG, SYSSEG + SYSSIZE # where to stop loading
设定了从软盘读取 SETUPPLEN=4 个扇区,BOOTSEG是bios复制的第一个扇区的起始位置,INITSEG是复制到
内存的第一个扇区代码自己复制自己后的起始位置,SETUPSEG是第二到第五扇区(即setup.s)代码复制到内存
的起始位置,SYSSEG是内核(后面的240个扇区)加载的位置,ENDSEG内核的末尾位置。
.equ ROOT_DEV, 0x301
ljmp $BOOTSEG, $_start
_start:
mov $BOOTSEG, %ax
mov %ax, %ds
mov $INITSEG, %ax
mov %ax, %es
mov $256, %cx
sub %si, %si
sub %di, %di
rep
movsw
这部分代码实现了 “挪代码”也就是 被bios拷贝进内存的代码,被这些代码自己放到新的位置上。
解释两个指令:
(1)ljmp $BOOTSEG, $_start
实现将cs置为BOOTSEG的段基址,ip置为_start的偏移地址,实现跳转
(2)rep
movsw
搬移字串指令,rep(repeat),movsw(moving string word),实现将把 DS:SI 所指地址的一个字搬移到
ES:DI 所指的地址上,搬移后原来的内容不变,但是原来 ES:DI 所指的内容会被覆盖而且在搬移之后 SI 和 DI
会自动地址向下一个要搬移的地址。
ljmp $INITSEG, $go
go: mov %cs, %ax
这两句实现了从原先的代码段执行到复制完成后的代码段执行的转变。
load_setup:
mov $0x0000, %dx # drive 0, head 0
mov $0x0002, %cx # sector 2, track 0
mov $0x0200, %bx # address = 512, in INITSEG
.equ AX, 0x0200+SETUPLEN
mov $AX, %ax # service 2, nr of sectors
int $0x13 # read it
jnc ok_load_setup # ok - continue
mov $0x0000, %dx
mov $0x0000, %ax # reset the diskette
int $0x13
jmp load_setup
解释一下,0x13中断。
ah: 功能号 0x02--读磁盘数据到内存
al: 需要读出的扇区的数量
ch: 磁道(柱面)号的低8位
cl: 开始扇区(0-5bit),磁道号的高两位(6-7bit)
dh: 磁头号, dl: 驱动器号(if it's hard-disk, set the 7th bit)
es:bx: 目的地址。指向数据缓冲区;如果出错则CF标志置位。
这样上面的代码就实现了从软盘将四个扇区的代码拷贝到制定内存的功能。