entry start
start:
mov ax,#BOOTSEG ;#1
mov ds,ax ;#2
mov ax,#INITSEG ;#3
mov es,ax ;#4
mov cx,#256 ;#5
sub si,si ;#6
sub di,di ;#7
rep movw ;#8
jmpi go,INITSEG ;#9
go: mov ax,cs
mov ds,ax
mov es,ax
; put stack at 0x9ff00.
mov ss,ax
mov sp,#0xFF00 ; arbitrary value >>512
在bootsect.s中,最开始需要运行上面的一段代码,下面详细讲一下这段代码。
entry_start
是一个汇编伪指令。伪指令不是是一种在汇编语言中使用的特殊指令,它们不是真正的机器指令。而是在汇编过程中被转换为一个或多个真正的机器指令。 这个伪指令的作用作用是将start
标签作为作为入口标签。标签是用于标识程序中位置的符号,它们可以用于标识指令、数据、子程序和其他程序元素的位置。start
标记的这段代码一共有9行,第一行的BOOTSEG
是一个符号常量,在bootsect.s中的前部分已经定义过该符号常量 BOOTSEG = 0x07c0
。那么前两行的意思就是将0x07c0
这个常量加载到AX寄存器中,再将AX寄存器中的值复制给DS寄存器。那为什么不直接把常量加载到DS寄存器中,而是将AX寄存器作为中间寄存器进行缓存呢?原因是将常量值先加载到中间寄存器中,再复制到数据段寄存器DS中,可以确保程序各个寄存器中的值同步,避免出现错误。第三行和第四行的作用相似。第五行是将立即数256
加载到CX寄存器中,CX寄存器叫做计数寄存器,通常用来放置循环数,而且该行使用十进制而不是十六进制,是为了更好的可读性。第六行和第七行是固定用法,用来将寄存器进行清零。第八行中rep
表示一个重复指令,通常和其他指令搭配使用,这这一句中,rep movw
表示对movw
指令进行重复,那重复多少次呢?这就要根据CX
中的值来定。在第五行中,CX已经寄存器中已经变成256,这表示需要将movw
指令循环执行256遍。而movw
指令表示将DS:SI
处的两个字节数据复制到ES:DI
处,要注意在重复过程成会对SI和DI进行自增,对CX进行自减。简单来说第八行指令的意思就是将内存0x7c00开始往后512个字节复制到0x90000开始的后512个字节处。那为何又要将引导程序挪窝呢?因为0x0000开始的后面一段内存是属于内核和系统预留空间,用来防止中断向量表和一些其他的数据。如果不把引导程序挪窝,就会被后续加载系统给覆盖。之所以先加载到0x7c00而不是直接加载到0x90000是因为历史包袱,这个要追溯到IBM的bios中。第九行的意思是进行跳转,跳转到go
标签处,INITSEG
则是基地址,此时为0x9000
。
go标签处的代码主要作用是在把bootsect.s程序进行挪窝后为各个寄存器重新加载值。但是这里需要注意的是,前面的代码中并没有显式的给CS寄存器加载值,那这个值又是从哪里来的呢?原来在上面执行jmpi go,INITSEG
指令的时候,CS寄存器也参与了过程,在执行该指令过程中CS被加载的值为0x9000
。
look_set_up
和ok_load_setup
标签处的代码的作用是加载
以下是linux 0.11 中bootsec.s的代码
;
; SYS_SIZE is the number of clicks (16 bytes) to be loaded.
; 0x3000 is 0x30000 bytes = 196kB, more than enough for current
; versions of linux
;
SYSSIZE = 0x3000
;
; bootsect.s (C) 1991 Linus Torvalds
;
; bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
; iself out of the way to address 0x90000, and jumps there.
;
; It then loads 'setup' directly after itself (0x90200), and the system
; at 0x10000, using BIOS interrupts.
;
; NOTE; currently system is at most 8*65536 bytes long. This should be no
; problem, even in the future. I want to keep it simple. This 512 kB
; kernel size should be enough, especially as this doesn't contain the
; buffer cache as in minix
;
; The loader has been made as simple as possible, and continuos
; read errors will result in a unbreakable loop. Reboot by hand. It
; loads pretty fast by getting whole sectors at a time whenever possible.
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text
SETUPLEN = 4 ; nr of setup-sectors
BOOTSEG = 0x07c0 ; original address of boot-sector
INITSEG = 0x9000 ; we move boot here - out of the way
SETUPSEG = 0x9020 ; setup starts here
SYSSEG = 0x1000 ; system loaded at 0x10000 (65536).
ENDSEG = SYSSEG + SYSSIZE ; where to stop loading
; ROOT_DEV: 0x000 - same type of floppy as boot.
; 0x301 - first partition on first drive etc
ROOT_DEV = 0x306
entry start
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
go: mov ax,cs
mov ds,ax
mov es,ax
; put stack at 0x9ff00.
mov ss,ax
mov sp,#0xFF00 ; arbitrary value >>512
; load the setup-sectors directly after the bootblock.
; Note that 'es' is already set up.
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
int 0x13 ; read it
jnc ok_load_setup ; ok - continue
mov dx,#0x0000
mov ax,#0x0000 ; reset the diskette
int 0x13
j load_setup
ok_load_setup:
; Get disk drive parameters, specifically nr of sectors/track
mov dl,#0x00
mov ax,#0x0800 ; AH=8 is get drive parameters
int 0x13
mov ch,#0x00
seg cs
mov sectors,cx
mov ax,#INITSEG
mov es,ax
; Print some inane message
mov ah,#0x03 ; read cursor pos
xor bh,bh
int 0x10
mov cx,#24
mov bx,#0x0007 ; page 0, attribute 7 (normal)
mov bp,#msg1
mov ax,#0x1301 ; write string, move cursor
int 0x10
; ok, we've written the message, now
; we want to load the system (at 0x10000)
mov ax,#SYSSEG
mov es,ax ; segment of 0x010000
call read_it
call kill_motor
; After that we check which root-device to use. If the device is
; defined (!= 0), nothing is done and the given device is used.
; Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
; on the number of sectors that the BIOS reports currently.
seg cs
mov ax,root_dev
cmp ax,#0
jne root_defined
seg cs
mov bx,sectors
mov ax,#0x0208 ; /dev/ps0 - 1.2Mb
cmp bx,#15
je root_defined
mov ax,#0x021c ; /dev/PS0 - 1.44Mb
cmp bx,#18
je root_defined
undef_root:
jmp undef_root
root_defined:
seg cs
mov root_dev,ax
; after that (everyting loaded), we jump to
; the setup-routine loaded directly after
; the bootblock:
jmpi 0,SETUPSEG
; This routine loads the system at address 0x10000, making sure
; no 64kB boundaries are crossed. We try to load it as fast as
; possible, loading whole tracks whenever we can.
;
; in: es - starting address segment (normally 0x1000)
;
sread: .word 1+SETUPLEN ; sectors read of current track
head: .word 0 ; current head
track: .word 0 ; current track
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:
seg cs
mov ax,sectors
sub ax,sread
mov cx,ax
shl cx,#9
add cx,bx
jnc ok2_read
je ok2_read
xor ax,ax
sub ax,bx
shr ax,#9
ok2_read:
call read_track
mov cx,ax
add ax,sread
seg cs
cmp ax,sectors
jne ok3_read
mov ax,#1
sub ax,head
jne ok4_read
inc track
ok4_read:
mov head,ax
xor ax,ax
ok3_read:
mov sread,ax
shl cx,#9
add bx,cx
jnc rp_read
mov ax,es
add ax,#0x1000
mov es,ax
xor bx,bx
jmp rp_read
read_track:
push ax
push bx
push cx
push dx
mov dx,track
mov cx,sread
inc cx
mov ch,dl
mov dx,head
mov dh,dl
mov dl,#0
and dx,#0x0100
mov ah,#2
int 0x13
jc bad_rt
pop dx
pop cx
pop bx
pop ax
ret
bad_rt: mov ax,#0
mov dx,#0
int 0x13
pop dx
pop cx
pop bx
pop ax
jmp read_track
/*
* This procedure turns off the floppy drive motor, so
* that we enter the kernel in a known state, and
* don't have to worry about it later.
*/
kill_motor:
push dx
mov dx,#0x3f2
mov al,#0
outb
pop dx
ret
sectors:
.word 0
msg1:
.byte 13,10
.ascii "Loading system ..."
.byte 13,10,13,10
.org 508
root_dev:
.word ROOT_DEV
boot_flag:
.word 0xAA55
.text
endtext:
.data
enddata:
.bss
endbss: