/*
* 跳转到移动后的INITSEG:go处执行
*/
ljmp $INITSEG, $go
# bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
# would not have to worry about this if we checked the top of memory. Also
# my BIOS can be configured to put the wini drive tables in high memory
# instead of in the vector table. The old stack might have clobbered(击倒,使惨败) the
# drive table.
/*
* 12Byte用来存放磁盘参数表(disk para-meter table)
*/
go: movw $0x4000 - 12, %di # 0x4000 is an arbitrary value(任意值) >=
# length of bootsect + length of
# setup + room for stack;
# 12 is disk parm size.
movw %ax, %ds # ax and es already contain INITSEG
movw %ax, %ss
movw %di, %sp # put stack at INITSEG:0x4000-12.
# Many BIOSs default disk parameter tables will not recognize(认可,公认)
# multi-sector reads beyond the maximum sector number specified
# in the default diskette parameter tables - this may mean ?
# sectors in some cases.
#
# Since single sector reads are slow and out of question,
# we must take care of this by creating new parameter tables
# (for the first disk) in RAM. We will set the maximum sector
# count to 36 - the most we will encounter(遇到,相遇) on an ED 2.88
#
# High does not hurt(伤害,受伤). Low does.
#
# Segments are as follows: ds = es = ss = cs -[= ??] INITSEG, fs = 0,
# and gs is unused.
/*
* BIOS中断向量表中断1Eh的地址0:78h处,放置的是指向软盘参数表的指针.现在需要更改
* 软盘参数表中"每磁道的扇区数",而软盘参数表放在BIOS ROM中,我们无法修改. 所以将
* 其复制到指定的RAM参数表中,再进行修改.然后将BIOS的中断向量表中0:78h处的远指针
* 修改为指向RAM中新复制的软盘参数表.
*/
movw %cx,%fs # set fs to 0
movw $0x78, %bx # fs:bx is parameter table address
pushw %ds
/*
* LDS OPS, OPD - 传送偏移地址及数据段首址
* (OPS) ->OPD, (OPS + 2) ->DS
*/
ldsw %fs:(%bx), %si # ds:si is source
movb $6, %cl # copy 12 bytes
pushw %di # di = 0x4000-12.
rep # do not need cld -> done on line 66
movsw
popw %di
popw %ds
/*
* 指定"每磁道的扇区数"为36
*/
movb $36, 0x4(%di) # patch(修补) sector count
movw %di, %fs:(%bx)
movw %es, %fs:2(%bx)
# Load the setup-sectors directly after the bootblock.
# Note that 'es' is already set up.
# Also, cx = 0 from rep movsw above.
/* 从磁盘上读入紧邻着bootsect的setup程序 */
load_setup:
/* 重置磁盘驱动器,使得刚才对"每磁道的扇区数"的设定发挥功能 */
/*
* INT 13H: 直接磁盘服务(Direct Disk Service).
* 功能00H: 磁盘系统复位.AH=00H,DL=驱动器,00H~7FH:软盘; 80H~0FFH:硬盘.
*/
xorb %ah, %ah # reset FDC
xorb %dl, %dl
int $0x13
/*
* 功能02H: 读扇区.
* AH=02H,AL=扇区数,CH=柱面,CL=扇区,DH=磁头,DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘
* ES:BX=缓冲区地址.
* 出口参数:CF=0——操作成功,AH=00H,AL=传输的扇区数,否则AH=状态代码.
*/
xorw %dx, %dx # drive 0, head 0
movb $0x02, %cl # sector 2, track 0
movw $0x0200, %bx # address = 512, in INITSEG
movb $0x02, %ah # service 2, "read sector(s)"
movb setup_sects, %al # (assume all on head 0, track 0)
int $0x13 # read it
jnc ok_load_setup # ok - continue
/* 读盘错误处理 */
pushw %ax # dump error code
call print_nl
movw %sp, %bp
call print_hex
popw %ax
jmp load_setup
ok_load_setup:
# Get disk drive parameters, specifically number of sectors/track.
# It seems that there is no BIOS call to get the number of sectors.
# Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18
# can be read, 15 if sector 15 can be read. Otherwise guess 9.
/*
* 猜测软盘"每磁道的扇区数",试着从大到小读36,18,15,0扇区,如果读取成功,说明磁盘上的每
* 磁道扇区数足以达到试读的数
*/
movw $disksizes, %si # table of sizes to try
probe_loop:
lodsb
cbtw # extend to word
movw %ax, sectors
cmpw $disksizes + 4, %si
jae got_sectors # if all else fails, try 9
xchgw %cx, %ax # cx = track and sector
xorw %dx, %dx # drive 0, head 0
xorb %bl, %bl
movb setup_sects, %bh
incb %bh
shlb %bh # address after setup (es = cs) [逻辑左移 ??]
int $0x13
jc probe_loop # try next value
/* 接下来要真正读入linux的kernel了,也就是在linux根目录下看到的"vmlinux". */
got_sectors:
/*
* INT 10H: 显示服务.AH=03H: 在文本坐标下,读取光标各种信息.BH=显示页码.
* 出口参数: CH=光标的起始行,CL=光标的终止行,DH=行(Y坐标),DL=列(X坐标).
*/
movw $INITSEG, %ax
movw %ax, %es # set up es
movb $0x03, %ah # read cursor pos
xorb %bh, %bh
int $0x10
/* 在屏幕上输出字符串"Loading". */
/*
* BH=页码,BL=属性(若AL=00H或01H),CX=显示字符串长度,(DH,DL)=坐标(行,列).
* ES:BP=显示字符串的地址,AL=显示输出方式.
* 0——字符串中只含显示字符,其显示属性在BL中.显示后,光标位置不变.
* 1——字符串中只含显示字符,其显示属性在BL中.显示后,光标位置改变.
* 2——字符串中含显示字符和显示属性.显示后,光标位置不变.
* 3——字符串中含显示字符和显示属性.显示后,光标位置改变.
*/
movw $9, %cx
movw $0x0007, %bx # page 0, attribute 7 (normal)
movw $msg1, %bp
movw $0x1301, %ax # write string, move cursor [写字符串并移动光标]
int $0x10 # tell the user we are loading...
movw $SYSSEG, %ax # ok, we have written the message, now
movw %ax, %es # we want to load system (at 0x10000)
call read_it /* 读磁盘上system模块,es为输入参数. */
call kill_motor /* 关闭驱动器马达,这样就可以知道驱动器的状态了. */
call print_nl
/* 此后,我们检查要使用哪个根文件系统设备(简称根设备).解说见0.11版本的P46. */
# 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, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2, 8)
# depending on the number of sectors we pretend(假装) to know we have.
/*
* 上面后两个设备文件的含义[0.11版本]:
* 在Linux中软驱的主设备号是2,次设备号 = type * 4 + nr, 其中nr为0-3分别对应软驱A,B,C或D;
* type是软驱的类型(2->1.2M或7->1.44M等).因为7 * 4 + 0 = 28,所以/dev/PS0(2,28)指的是1.44M
* A驱动器,其设备号是021c,同理/dev/at0(2,8)指的是1.2M A驱动器,设备号是0x0208.
*/
movw root_dev, %ax
orw %ax, %ax
jne root_defined
/* 每磁道扇区数.如sectors=15则是1.2Mb的驱动器.如sectors=18,则为1.44Mb软驱... */
movw sectors, %bx
movw $0x0208, %ax # /dev/ps0 - 1.2Mb
cmpw $15, %bx
je root_defined
movb $0x1c, %al # /dev/PS0 - 1.44Mb
cmpw $18, %bx
je root_defined
movb $0x20, %al # /dev/fd0H2880 - 2.88Mb
cmpw $36, %bx
je root_defined
movb $0, %al # /dev/fd0 - autodetect[自动侦查??]
root_defined:
movw %ax, root_dev /* 保存设备号. */
# After that (everything loaded), we jump to the setup-routine
# loaded directly after the bootblock:
/*
* 所有程序加载完毕,跳转到被加载在bootsect后面的setup程序去.
*/
ljmp $SETUPSEG, $0
# 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.
# es = starting address segment (normally 0x1000)
sread: .word 0 # sectors read of current track [当前磁道中已读的扇区数]
head: .word 0 # current head [当前磁头号]
track: .word 0 # current track [当前磁道号]
read_it:
movb setup_sects, %al
incb %al
movb %al, sread /* 1个是引导扇区,4个是setup所在扇区 */
