Trace Linux Kernel With Bochs(3)
这里我们将重写bootsect.s完成其真正的功能,重写使用AT&T汇编。
bootsect.s
内存规划
.code16 #use 16bit
.text #code segment start
SYSSIZE = 0x3000
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
bootsect将自己复制到0x90000处
movw %cs, %ax #cs:ip was initialized by BOIS instruction 'jmpi 0, 0x07c0'
movw %ax, %ds #initialize ds, es and ss with cs
movw %ax, %es
movw $BOOTSEG, %ax
movw %ax, %ds
movw $INITSEG, %ax
movw %ax, %es
movw $256, %cx
xor %si, %si
xor %di, %di
rep
movsw
跳到复制后的地方继续执行
ljmp $INITSEG, $go
go:
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
# put stack at 0x9ff00
movw %ax, %ss
movw $0xFF00, %sp # arbitrary value >> 512
将setup section加载至内存
load_setup:
movw $0x0000, %dx # DL = drive 0, DH = head 0
movw $0x0002, %cx # CL = sector 2, CH = track 0
movw $0x0200, %bx # address = 512, in INITSEG
movw $0x0200+SETUPLEN, %ax # servie 2, nr of sectors
int $0x13 # read it
jnc ok_load_setup # ok - continue
movw $0x0000, %dx
movw $0x0000, %ax #reset the diskette
int $0x13
jmp load_setup
获得每磁道的扇区数
ok_load_setup:
# Get disk drive parameters, specificlly nr of sectors/track
movb $0x00, %dl # DL = drive index
movw $0x0800, %ax # AH = service number
int $0x13 # return CX[0:5] = nr of sectors per track
# CX[6:7][8:15] = nr of cylinders
# es has changed
movb $0x00, %ch # clear CH because only nr of sectors per stack
# will be needed. CX[6:7] is zero in floppy.
movw %cx, %cs:sectors # save nr of sectors per stack
movw $INITSEG, %ax
movw %ax, %es
打印提示信息
# Print some inane message
movb $0x03, %ah # read cursor pos (AH = function number)
xor %bh, %bh # BH = page number
int $0x10 # return (DH = row, DL = column
# CH = cursor start line CL = cursor bottom line)
movw $24, %cx # number of characters in string
movw $0x0007, %bx # BH = page number BL = attribute if string
# contains only characters (bit 1 of AL = 0)
movw $msg1, %bp # ES:BP points to string to be printed
movw $0x1301, %ax # AH = function number
# AL = write mode:
# bit 0:update cursor after writing
# bit 1:string contains attribute
int $0x10
将system section加载至内存
# ok, we have written the message, now
# we want to load the system (at 0x10000)
movw $SYSSEG, %ax
movw %ax, %es # segment of 0x10000
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.
movw %cs:root_dev, %ax
cmp $0, %ax
jne root_defined
movw %cs:sectors, %bx
movw $0x0208, %ax # /dev/ps0 - 1.2Mb
cmp $15, %bx
je root_defined
movw $0x021c, %ax # /dev/PS0 - 1.44Mb
cmp $18, %bx
je root_defined
undef_root:
jmp undef_root
root_defined:
movw %ax, %cs:root_dev
开始执行setup.s
# after that (everything loaded), we jump to
# the setup-routine loaded directly after
# the bootblock:
ljmp $SETUPSEG, $0x0
读取system section子程序
# 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:
movw %es, %ax
test $0x0fff, %ax
die :
jne die # es must be at 64kB boundary
xor %bx, %bx # bx is starting addresss within segment
rp_read:
movw %es, %ax
cmp $ENDSEG, %ax # have we loaded all yet?
jb ok1_read
ret
ok1_read:
movw %cs:sectors, %ax
subw sread, %ax # nr of sectors in the track have not been read.
movw %ax, %cx
shlw $9, %cx # nr of Bytes = nr of sectors * 512
addw %bx, %cx # end address
jnc ok2_read # is out of 64kB boundary
je ok2_read
xor %ax, %ax # 0 = 64kB mod 2^16
subw %bx, %ax # free memory size in current segment
shrw $9, %ax # nr of sectors can be read in current segment
ok2_read:
call read_track
movw %ax, %cx
add sread, %ax # nr of sectors which have been read in the track
cmp %cs:sectors, %ax
jne ok3_read # have we read all sectors in the track?
movw $1, %ax
subw head, %ax
jne ok4_read # Is current head zero?
incw track # current head = 1, so increase track
ok4_read:
movw %ax, head # set current head = 1 if current head = 0
# set current head = 0 if current head = 1
xor %ax, %ax # reset sectors have been read in the track
ok3_read: # continue reading sectors in the track
movw %ax, sread # update sread after read_track
shlw $9, %cx
addw %cx, %bx # update offset(BX) in the segment
jnc rp_read # is out of 64kB boundary
movw %es, %ax
addw $0x1000, %ax
movw %ax, %es # increase segment base address(ES) by 64kB
xor %bx, %bx # reset the offset(BX)
jmp rp_read
read_track:
push %ax
push %bx
push %cx
push %dx
movw track, %dx
movw sread, %cx
inc %cx
movb %dl, %ch # CH = track, CL = sector
movw head, %dx
movb %dl, %dh
movb $0, %dl
and $0x0100, %dx # DH = head, DL = drive
# make sure only drive 0, head 0/1 will be read
movb $2, %ah # AH = service nr, AL = nr of sectors to be read
int $0x13
jc bad_rt
pop %dx
pop %cx
pop %bx
pop %ax
ret
bad_rt:
xor %ax, %ax
xor %dx, %dx
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 not have to worry about it later.
关闭马达
kill_motor:
push %dx
movw $0x3f2, %dx
movb $0, %al
outb %al, %dx
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
完整的代码可以在这里下载
存在的问题
- 这里在读取完setup section(4个sectors),并不是像很多书上说的读240个扇区,而是读了0x30000个字节,也就是384个扇区?
blog comments powered by Disqus