首先,BIOS有一段自检程序,其作用还不明确。总之,与我们有关的地方是内存中0x07c00
CPU到了0x07c00从这里开始进入bootsect.s
_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
而bootsect.s 一开始先是将自己拷贝到0x90000处
bootsect 本身只有512字节,因此才有了上述程序rep那里的内容.
256word= 512 byte
也就是从内存中0x07c00拷贝512字节到0x90000.
0x90000-0x9001ff 这里便是bootsect的新的位置.
这时候,如果你反汇编一下0x07c00 与 0x90000。你会发现二者相同,并且就是bootsect.S中的内容,因此验证猜想正确。
go: mov ax,cs ! 此时cs=9000,IP = 0018
mov ds,ax
mov es,ax
! put stack at 0x9ff00.
mov ss,ax
mov sp,#0xFF00
执行完jmpi go,INITSEG后,CPU 便跳到了0x90018处,设置堆栈大小.并将ds,es设置为9000H.此时,cs=ds=es=ss=9000H.
接下来到了ok_load_setup
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
这里的重点就是bios 13号中断.
功能描述:读扇区
入口参数:AH=02H
AL=扇区数
CH=柱面
CL=扇区
DH=磁头
DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘
ES:BX=缓冲区的地址
出口参数:CF=0——操作成功,AH=00H,AL=传输的扇区数,否则,AH=状态代码
bios13号中断为基本的磁盘操作,根据ah不同选择不同功能。
上述ah = 02,al=SETUPLEN=2.
因此,其含义为“从0柱面第二个扇区第0个磁头读4个扇区(2048B)到内存的0x90200处”
执行完第一个int 13后,我们查看0x90200内容。
会发现0x90200-0x90337共312字节
<bochs:29> u 0x90200 0x902ff
00090200: ( ): mov ah, 0x03 ; b403
00090202: ( ): xor bh, bh ; 30ff
00090204: ( ): int 0x10 ; cd10
00090206: ( ): mov cx, 0x0017 ; b91700
00090209: ( ): mov bx, 0x0007 ; bb0700
0009020c: ( ): mov bp, 0x014c ; bd4c01
0009020f: ( ): mov ax, 0x1301 ; b80113
00090212: ( ): int 0x10 ; cd10
00090214: ( ): mov ax, 0x9000 ; b80090
00090217: ( ): mov ds, ax ; 8ed8
00090219: ( ): mov ah, 0x03 ; b403
0009021b: ( ): xor bh, bh ; 30ff
0009021d: ( ): int 0x10 ; cd10
0009021f: ( ): mov word ptr ds:0x0, dx ; 89160000
正是后面setup.S中的内容。
如果成功,CF=0,跳转至ok_load_setup
若不成功得想办法补救,即重新读:
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
又是int 13.这次AH=08:
入口参数:AH=08H
DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘
出口参数:CF=1——操作失败,AH=状态代码,参见功能号01H中的说明,否则, BL=01H — 360K
=02H — 1.2M
=03H — 720K
=04H — 1.44M
CH=柱面数的低8位
CL的位7-6=柱面数的该2位
CL的位5-0=扇区数
DH=磁头数
DL=驱动器数
ES:DI=磁盘驱动器参数表地址
执行完int 13后,发现BL= 4
代表读取软盘 大小为1.44M,CL =00010010B
代表18个扇区 ,将CH置零后,cx = 0012H
mov ch,#0x00
seg cs
mov sectors,cx
mov ax,#INITSEG
mov es,ax
接下来第2,3句为段超越,意思把cx内容移动到cs:[sectors],此时sectors相当于一个变量,用于保存一个值,测试时发现sectors=0x13d。意味着将读取到的数据保存在内存cs:sectors处。
同时,int 13 改变了ES,将es再设回9000。然后,准备在屏幕上显示一些文字。
! Print some inane message
mov ah,#0x03 ! read cursor pos
xor bh,bh
int 0x10
AH = 3
读光标位置
输入参数:BH = 页号
输出参数:
CH = 光标开始行
CL = 光标结束行
DH = 行
DL = 列
先读0页光标位置,ch=6,cl=7,dh=10,dl=0
。
mov cx,#24 ! cs:ip=0x00090056
mov bx,#0x0007 ! page 0, attribute 7 (normal)
mov bp,#msg1
mov ax,#0x1301 ! write string, move cursor
int 0x10
显示24个字符串。
接着将系统加载到内存起始0x10000处,代码如下
! 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
将段设置好后调用了读取函数:
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:...
ok2_read:...
.....
将一些东西准备就绪后,就要进入setup
jmpi 0,SETUPSEG
跳转至0x90200。