加载setup.s
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
第1行代码执行时,会修订CS寄存器为0x9000。所以第2~6行语句执行后的效果为当前代码段(CS),数据段(DS, ES),堆栈段的(CS)都是0x9000对应的段内存,即0x90000~0x9FFFF所在的段。第7行将sp指针指向0xff00的位置。由于代码和数据从0x90000往地址增加方向增长,而堆栈从0x9ff00往地址减小方向增长。这个空间对bootsect.s程序来说足够了(其代码和数据区只占用512字节内存)。
说明:sp指针可以调整成更小的值,但调得太小的话,担心堆栈溢出,覆盖代码和数据区。它的最大可能值为0xffff(如果考虑4字节对齐,则为0xfffc)。
! 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:
各种段寄存器设置成合适的值以后,就开始加载setup.s程序了,setup.s占4个扇区(SETUPLEN),其在磁盘中的位置为bootsect.s扇区之后(bootsect.s占1个扇区,512字节)。
需要说明的是,操作系统映像(image)在磁盘中是连续存储的(包含bootsect.s,setup.s,以及剩余部分),从(0驱动器,0磁头,0磁道,1扇区)开始,即磁盘的第1个扇区开始。但是setupsect.s, setup.s以及剩下的程序在内存中是分散的。内存中的分布是由bootsect.s和setup.s程序逻辑控制的。
从第7行代码可知,setup.s被加载到了0x9000:0200的位置,即0x90200的位置(偏移512字节),刚好在移动后的bootsect.s后面。实际上这样做也不是必须的,可以加载到0x9000:0400或者0x9000:0600等,只要不覆盖已有的bootsect.s以及不影响未来的剩余映像加载即可。
本程序通过0x13中断将磁盘中的内容读入内存(直接读入4个扇区),此中断程序为BIOS初始化,中断向量在0地址附近。
如果读取失败,则复位磁盘重试。没有查询相关资料,什么情况下读取会失败,复位磁盘重试就能成功吗:)