这里我们将重写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

完整的代码可以在这里下载

存在的问题

  1. 这里在读取完setup section(4个sectors),并不是像很多书上说的读240个扇区,而是读了0x30000个字节,也就是384个扇区?


blog comments powered by Disqus

Published

10 March 2014

Tags