bootsect.s 可以在屏幕上输出提示信息
输出语句“BDSOS is booting…”
检查bootsect.s,以下代码用于打印信息
ljmp $BOOTSEG, $_start
_start:
mov $0x03,%ah
xor %bh,%bh
int $0x10
mov $24, %cx
mov $0x0007, %bx # page 0, attribute 7 (normal)
#lea msg1, %bp
mov $msg1, %bp
mov $0x1301, %ax # write string, move cursor
int $0x10
msg1:
.byte 13,10
.ascii "Loading system ..."
.byte 13,10,13,10
.org 510
boot_flag:
.word 0xAA55
因此,对bootsect.s的内容进行修改,使其输出所需的信息,然后删除其余代码,最终,bootsect.s的完整内容如下:
.code16
.global _start
.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 ROOT_DEV, 0x301
ljmp $BOOTSEG, $_start
_start:
mov $0x03,%ah
xor %bh,%bh
int $0x10
mov $31,%cx
mov $0x0007,%bx
mov $msg1,%bp
mov $0x07c0,%ax
mov %ax,%es
mov $0x1301,%ax
int $0x10
msg1:
.byte 13,10
.ascii "BDSOS is booting..."
.byte 13,10,13,10
.org 510
boot_flag:
.word 0xAA55
最后,编译文件并执行,结果如下图,显示bootsect.s的修改是正确的,成功输出语句“BDSOS is booting…”
首先,确保setup.s能够向屏幕输出信息,这个功能已经在前一个问题中在bootsect.s中完成,因此,将相应代码复制到setup.s中,然后删除多余代码,完整的setup.s代码如下:
.code16
.equ SETUPSEG, 0x9020
.global _start
ljmp $SETUPSEG, $_start
_start:
mov $0x03,%ah
xor %bh,%bh
int $0x10
mov $25,%cx
mov $0x0007,%bx
mov $msg2,%bp
mov $0x07c0,%ax
mov %cs,%ax
mov %ax,%es
mov $0x1301,%ax
int $0x10
inf_loop:
jmp inf_loop
msg2:
.byte 13,10
.ascii "Now we are in SETUP"
.byte 13,10,13,10
.org 510
boot_flag:
.word 0xAA55
接下来,对bootsect.s进行修改,以使其能够加载并跳转到setup.s的起始地址执行。检查原bootsect.s的内容,找到以下代码实现了这个功能:
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
ok_load_setup:
ljmp $SETUPSEG, $0
因此,对bootsect.s的代码进行修改,首先加载setup.s,然后显示语句“BDSOS is booting…”,最后跳转至setup.s。完成这些功能并删除多余代码后,bootsect.s的完整代码如下:
.code16
.equ SETUPLEN, 2 # 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 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
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
ok_load_setup:
mov $0x03, %ah # read cursor pos
xor %bh, %bh
int $0x10
mov $31, %cx
mov $0x0007, %bx # page 0, attribute 7 (normal)
mov $msg1, %bp
mov $0x1301, %ax # write string, move cursor
int $0x10
ljmp $SETUPSEG, $0
msg1:
.byte 13,10
.ascii "BDSOS is booting..."
.byte 13,10,13,10
.org 508
root_dev:
.word ROOT_DEV
boot_flag:
.word 0xAA55
最后,编译文件并执行,结果如下图,bootsect.s和setup.s的修改是正确的,成功显示语句“Now we are in SETUP”
setup.s 可以获取至少一个基本的硬件参数(如内存参数、显卡参数、硬盘参数等),将其存储在内存的特定地址,并在屏幕上输出。
在保持setup.s原有功能不变的同时,使其能够读取硬件参数。首先,在原setup.s文件中,有以下代码可以读取各项硬件信息:
mov $INITSEG, %ax # get Cursor Poser
mov %ax, %ds
mov $0x03, %ah
xor %bh, %bh
int $0x10
mov %dx, %ds:0 # get Memory Size
mov $0x88, %ah
int $0x15
mov %ax, %ds:2
mov $0x0000, %ax # get hd0 data
mov %ax, %ds
lds %ds:4*0x41, %si
mov $INITSEG, %ax
mov %ax, %es
mov $0x0004, %di
mov $0x10, %cx
rep
movsb
但是,读取出的数以无符号整数形式存在,需要对这些数进行处理,以十六进制形式显示。可以通过以下函数完成这个操作:
print_hex:
mov $4,%cx
print_digit:
rol $4,%dx
mov $0xe0f,%ax
and %dl,%al
add $0x30,%al
cmp $0x3a,%al
jl outp
add $0x07,%al
outp:
int $0x10
loop print_digit
ret
print_nl:
mov $0xe0d,%ax
int $0x10
mov $0xa,%al
int $0x10
ret
然后,结合以上两点信息,使setup.s在显示"Now we are in SETUP"之后,进一步打印"Memory Size:"、内存大小、“KB”、"Cursor Poser:"等信息,以满足要求。完整的setup.s代码如下:
.code16
.equ SETUPSEG, 0x9020 # this is the current segment
.equ INITSEG, 0x9000 # we move boot here - out of the way
.global _start
ljmp $SETUPSEG, $_start
_start:
mov $0x03,%ah # print "Now we are in SETUP"
xor %bh,%bh
int $0x10
mov $25,%cx
mov $0x0007,%bx
mov $msg2,%bp
mov $0x07c0,%ax
mov %cs,%ax
mov %ax,%es
mov $0x1301,%ax
int $0x10
mov $INITSEG, %ax # get Cursor Poser
mov %ax, %ds
mov $0x03, %ah
xor %bh, %bh
int $0x10
mov %dx, %ds:0
mov $0x88, %ah # get memory size
int $0x15
mov %ax, %ds:2
mov $0x03,%ah # print "Memory Size:"
xor %bh,%bh
int $0x10
mov $12,%cx
mov $0x0007,%bx
mov $msg3,%bp
mov $0x1301,%ax
int $0x10
mov %ds:2 , %dx # print memory size
call print_hex
mov $0x03,%ah # print "KB"
xor %bh,%bh
int $0x10
mov $2,%cx
mov $0x0007,%bx
mov $msg4,%bp
mov $0x1301,%ax
int $0x10
call print_nl
mov $0x03,%ah # print "Memory Size:"
xor %bh,%bh
int $0x10
mov $12,%cx
mov $0x0007,%bx
mov $msg8,%bp
mov $0x1301,%ax
int $0x10
mov %ds:0 , %dx # print memory size
call print_hex
call print_nl
mov $0x03,%ah # print "Cylinders:"
xor %bh,%bh
int $0x10
mov $10,%cx
mov $0x0007,%bx
mov $msg5,%bp
mov $0x1301,%ax
int $0x10
mov $0x0000, %ax # get hd0 data
mov %ax, %ds
lds %ds:4*0x41, %si
mov $INITSEG, %ax
mov %ax, %es
mov $0x0004, %di
mov $0x10, %cx
rep
movsb
mov $INITSEG, %ax # print Cylinders
mov %ax, %ds
mov %ds:4 , %dx
call print_hex
call print_nl
mov $0x03,%ah # print "Headers:"
xor %bh,%bh
int $0x10
mov $8,%cx
mov $0x0007,%bx
mov $msg6,%bp
mov $0x07c0,%ax
mov %cs,%ax
mov %ax,%es
mov $0x1301,%ax
int $0x10
mov $INITSEG, %ax # print Headers
mov %ax, %ds
mov %ds:6 , %dx
call print_hex
call print_nl
mov $0x03,%ah # print "Sectors Per Track:"
xor %bh,%bh
int $0x10
mov $18,%cx
mov $0x0007,%bx
mov $msg7,%bp
mov $0x1301,%ax
int $0x10
mov $INITSEG, %ax # print Sectors Per Track
mov %ax, %ds
mov %ds:18 , %dx
call print_hex
call print_nl
inf_loop:
jmp inf_loop
print_hex:
mov $4,%cx
print_digit:
rol $4,%dx
mov $0xe0f,%ax
and %dl,%al
add $0x30,%al
cmp $0x3a,%al
jl outp
add $0x07,%al
outp:
int $0x10
loop print_digit
ret
print_nl:
mov $0xe0d,%ax
int $0x10
mov $0xa,%al
int $0x10
ret
msg2:
.byte 13,10
.ascii "Now we are in SETUP"
.byte 13,10,13,10
msg3:
.ascii "Memory Size:"
msg4:
.ascii "KB"
msg5:
.ascii "Cylinders:"
msg6:
.ascii "Headers:"
msg7:
.ascii "Sectors Per Track:"
msg8:
.ascii "Cursor Pose:"
.org 510
boot_flag:
.word 0xAA55
有时,继承传统意味着别手蹩脚。 x86 计算机为了向下兼容,导致启动过程比较复杂。 请找出 x86 计算机启动过程中,被硬件强制,软件必须遵守的两个“多此一举”的步骤(多找几个也无妨),说说它们为什么多此一举,并设计更简洁的替代方案。
实模式和保护模式切换:
BIOS中断调用: