summaryrefslogtreecommitdiffstats
path: root/bootsect.S
diff options
context:
space:
mode:
Diffstat (limited to 'bootsect.S')
-rw-r--r--bootsect.S750
1 files changed, 375 insertions, 375 deletions
diff --git a/bootsect.S b/bootsect.S
index ee3bd90..982775d 100644
--- a/bootsect.S
+++ b/bootsect.S
@@ -1,375 +1,375 @@
-/*
- * bootsect.s Copyright (C) 1991, 1992 Linus Torvalds
- *
- * bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
- * itself out of the way to address 0x90000, and jumps there.
- *
- * It then loads 'setup' directly after itself (0x90200), and the system
- * at 0x10000, using BIOS interrupts.
- *
- * The loader has been made as simple as possible, and continuos
- * read errors will result in a unbreakable loop. Reboot by hand. It
- * loads pretty fast by getting whole tracks at a time whenever possible.
- *
- * 1-Jan-96 Modified by Chris Brady for use as a boot loader for MemTest-86.
- */
-
-#include "defs.h"
-
-ROOT_DEV = 0
-
-.code16
-.section ".bootsect", "ax", @progbits
-_boot:
-
-
-# ld86 requires an entry symbol. This may as well be the usual one.
-.globl _main
-_main:
- movw $BOOTSEG, %ax
- movw %ax, %ds
- movw $INITSEG, %ax
- movw %ax, %es
- movw $256, %cx
- subw %si, %si
- subw %di, %di
- cld
- rep
- movsw
- ljmp $INITSEG, $go - _boot
-
-go:
- movw %cs, %ax
- movw $(0x4000-12), %dx # 0x4000 is arbitrary value >= length of
- # bootsect + length of setup + room for stack
- # 12 is disk parm size
-
-# bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
-# wouldn't 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.
-
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss # put stack at INITSEG:0x4000-12.
- movw %dx, %sp
-
-/*
- * Many BIOS's 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 7 sectors in some cases.
- *
- * Since single sector reads are slow and out of the 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 18 - the most we will encounter on an HD 1.44.
- *
- * High doesn't hurt. Low does.
- *
- * Segments are as follows: ds=es=ss=cs - INITSEG,
- * fs = 0, gs = parameter table segment
- */
- pushw $0
- popw %fs
- movw $0x78, %bx # fs:bx is parameter table address
- lgs %fs:(%bx),%si # gs:si is source
-
- movw %dx, %di # es:di is destination
- movw $6, %cx # copy 12 bytes
- cld
-
- rep movsw %gs:(%si), (%di)
-
- movw %dx, %di
- movb $18, 4(%di) # patch sector count
-
- movw %di, %fs:(%bx)
- movw %es, %fs:2(%bx)
-
- movw %cs, %ax
- movw %ax, %fs
- movw %ax, %gs
-
- xorb %ah, %ah # reset FDC
- xorb %dl, %dl
- int $0x13
-
-# load the setup-sectors directly after the bootblock.
-# Note that 'es' is already set up.
-
-load_setup:
- xorw %dx, %dx # drive 0, head 0
- movw $0x0002, %cx # sector 2, track 0
- movw $0x0200, %bx # address = 512, in INITSEG
- movw $(0x0200 + SETUPSECS), %ax # service 2, nr of sectors
- # (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
-
- xorb %dl, %dl # reset FDC
- xorb %ah, %ah
- int $0x13
- jmp load_setup
-
-ok_load_setup:
-
-# Get disk drive parameters, specifically nr of sectors/track
-
-
-/* It seems that there is no BIOS call to get the number of sectors. Guess
- * 18 sectors if sector 18 can be read, 15 if sector 15 can be read.
- * Otherwise guess 9
- */
-
- xorw %dx, %dx # drive 0, head 0
- movw $0x0012, %cx # sector 18, track 0
- movw $(0x200+(SETUPSECS*0x200)), %bx # address after setup (es = cs)
- movw $0x0201, %ax # service 2, 1 sector
- int $0x13
- jnc got_sectors
- movb $0x0f, %cl # sector 15
- movw $0x0201, %ax # service 2, 1 sector
- int $0x13
- jnc got_sectors
- movb $0x09, %cl
-
-got_sectors:
- movw %cx, %cs:sectors - _boot
- movw $INITSEG, %ax
- movw %ax, %es
-
-# Print some inane message
-
- movb $0x03, %ah # read cursor pos
- xorb %bh, %bh
- int $0x10
-
- movw $9, %cx
- movw $0x0007, %bx # page 0, attribute 7 (normal)
- movw $msg1 - _boot, %bp
- movw $0x1301, %ax # write string, move cursor
- int $0x10
-
-# ok, we've written the message, now
-# we want to load the system (at 0x10000)
-
- movw $TSTLOAD, %ax
- movw %ax, %es # segment of 0x010000
- call read_it
- call kill_motor
- call print_nl
-
-# after that (everyting loaded), we jump to
-# the setup-routine loaded directly after
-# the bootblock:
-
- 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.
-#
-# in: es - starting address segment (normally 0x1000)
-#
-sread: .word 1+SETUPSECS # sectors read of current track
-head: .word 0 # current head
-track: .word 0 # current track
-
-read_it:
- movw %es, %ax
- testw $0x0fff, %ax
-die:
- jne die # es must be at 64kB boundary
- xorw %bx,%bx # bx is starting address within segment
-rp_read:
- movw %es, %ax
- subw $TSTLOAD, %ax # have we loaded all yet?
- cmpw syssize - _boot, %ax
- jbe ok1_read
- ret
-ok1_read:
- movw %cs:sectors - _boot, %ax
- subw sread - _boot, %ax
- movw %ax, %cx
- shlw $9, %cx
- addw %bx, %cx
- jnc ok2_read
- je ok2_read
- xorw %ax, %ax
- subw %bx, %ax
- shrw $9, %ax
-ok2_read:
- call read_track
- movw %ax, %cx
- add sread - _boot, %ax
- cmpw %cs:sectors - _boot, %ax
- jne ok3_read
- movw $1, %ax
- subw head - _boot, %ax
- jne ok4_read
- incw track - _boot
-ok4_read:
- movw %ax, head - _boot
- xorw %ax, %ax
-ok3_read:
- movw %ax, sread - _boot
- shlw $9, %cx
- addw %cx, %bx
- jnc rp_read
- movw %es, %ax
- addb $0x10, %ah
- movw %ax, %es
- xorw %bx, %bx
- jmp rp_read
-
-read_track:
- pusha
- pusha
- movw $0xe2e, %ax # loading... message 2e = .
- movw $7, %bx
- int $0x10
- popa
-
- movw track - _boot, %dx
- movw sread - _boot, %cx
- incw %cx
- movb %dl, %ch
- movw head - _boot, %dx
- movb %dl, %dh
- andw $0x0100, %dx
- movb $2, %ah
-
- pushw %dx # save for error dump
- pushw %cx
- pushw %bx
- pushw %ax
-
- int $0x13
- jc bad_rt
- addw $8, %sp
- popa
- ret
-
-bad_rt:
- pushw %ax # save error code
- call print_all # ah = error, al = read
-
- xorb %ah, %ah
- xorb %dl, %dl
- int $0x13
-
- addw $10, %sp
- popa
- jmp read_track
-
-/*
- * print_all is for debugging purposes.
- * It will print out all of the registers. The assumption is that this is
- * called from a routine, with a stack frame like
- * dx
- * cx
- * bx
- * ax
- * error
- * ret <- sp
- *
-*/
-
-print_all:
- movw $5, %cx # error code + 4 registers
- movw %sp, %bp
-
-print_loop:
- pushw %cx # save count left
- call print_nl # nl for readability
-
- cmpb 5, %cl # see if register name is needed
- jae no_reg
-
- movw $(0xe05 + 'A' - 1), %ax
- subb %cl, %al
- int $0x10
- movb $'X', %al
- int $0x10
- movb $':', %al
- int $0x10
-
-no_reg:
- addw $2, %bp # next register
- call print_hex # print it
- popw %cx
- loop print_loop
- ret
-
-print_nl:
- movw $0xe0d, %ax # CR
- int $0x10
- movb $0x0a, %al # LF
- int $0x10
- ret
-
-/*
- * print_hex is for debugging purposes, and prints the word
- * pointed to by ss:bp in hexadecmial.
-*/
-
-print_hex:
- movw $4, %cx # 4 hex digits
- movw (%bp), %dx # load word into dx
-
-print_digit:
- rolw $4, %dx # rotate so that lowest 4 bits are used
- movb $0xe, %ah
- movb %dl, %al # mask off so we have only next nibble
- andb $0xf, %al
- addb $'0', %al # convert to 0-based digit
- cmpb $'9', %al # check for overflow
- jbe good_digit
- addb $('A' - '0' - 10), %al
-
-good_digit:
- int $0x10
- loop print_digit
- ret
-
-
-/*
- * This procedure turns off the floppy drive motor, so
- * that we enter the kernel in a known state, and
- * don't have to worry about it later.
- */
-kill_motor:
- pushw %dx
- movw $0x3f2, %dx
- xorb %al, %al
- outb %al, %dx
- popw %dx
- ret
-
-sectors:
- .word 0
-
-msg1:
- .byte 13,10
- .ascii "Loading"
-
-.org 497
-setup_sects:
- .byte SETUPSECS
-.org 500
-syssize:
- .word _syssize
-.org 508
-root_dev:
- .word ROOT_DEV
-boot_flag:
- .word 0xAA55
-_eboot:
+/*
+ * bootsect.s Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
+ * itself out of the way to address 0x90000, and jumps there.
+ *
+ * It then loads 'setup' directly after itself (0x90200), and the system
+ * at 0x10000, using BIOS interrupts.
+ *
+ * The loader has been made as simple as possible, and continuos
+ * read errors will result in a unbreakable loop. Reboot by hand. It
+ * loads pretty fast by getting whole tracks at a time whenever possible.
+ *
+ * 1-Jan-96 Modified by Chris Brady for use as a boot loader for MemTest-86.
+ */
+
+#include "defs.h"
+
+ROOT_DEV = 0
+
+.code16
+.section ".bootsect", "ax", @progbits
+_boot:
+
+
+# ld86 requires an entry symbol. This may as well be the usual one.
+.globl _main
+_main:
+ movw $BOOTSEG, %ax
+ movw %ax, %ds
+ movw $INITSEG, %ax
+ movw %ax, %es
+ movw $256, %cx
+ subw %si, %si
+ subw %di, %di
+ cld
+ rep
+ movsw
+ ljmp $INITSEG, $go - _boot
+
+go:
+ movw %cs, %ax
+ movw $(0x4000-12), %dx # 0x4000 is arbitrary value >= length of
+ # bootsect + length of setup + room for stack
+ # 12 is disk parm size
+
+# bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
+# wouldn't 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.
+
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss # put stack at INITSEG:0x4000-12.
+ movw %dx, %sp
+
+/*
+ * Many BIOS's 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 7 sectors in some cases.
+ *
+ * Since single sector reads are slow and out of the 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 18 - the most we will encounter on an HD 1.44.
+ *
+ * High doesn't hurt. Low does.
+ *
+ * Segments are as follows: ds=es=ss=cs - INITSEG,
+ * fs = 0, gs = parameter table segment
+ */
+ pushw $0
+ popw %fs
+ movw $0x78, %bx # fs:bx is parameter table address
+ lgs %fs:(%bx),%si # gs:si is source
+
+ movw %dx, %di # es:di is destination
+ movw $6, %cx # copy 12 bytes
+ cld
+
+ rep movsw %gs:(%si), (%di)
+
+ movw %dx, %di
+ movb $18, 4(%di) # patch sector count
+
+ movw %di, %fs:(%bx)
+ movw %es, %fs:2(%bx)
+
+ movw %cs, %ax
+ movw %ax, %fs
+ movw %ax, %gs
+
+ xorb %ah, %ah # reset FDC
+ xorb %dl, %dl
+ int $0x13
+
+# load the setup-sectors directly after the bootblock.
+# Note that 'es' is already set up.
+
+load_setup:
+ xorw %dx, %dx # drive 0, head 0
+ movw $0x0002, %cx # sector 2, track 0
+ movw $0x0200, %bx # address = 512, in INITSEG
+ movw $(0x0200 + SETUPSECS), %ax # service 2, nr of sectors
+ # (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
+
+ xorb %dl, %dl # reset FDC
+ xorb %ah, %ah
+ int $0x13
+ jmp load_setup
+
+ok_load_setup:
+
+# Get disk drive parameters, specifically nr of sectors/track
+
+
+/* It seems that there is no BIOS call to get the number of sectors. Guess
+ * 18 sectors if sector 18 can be read, 15 if sector 15 can be read.
+ * Otherwise guess 9
+ */
+
+ xorw %dx, %dx # drive 0, head 0
+ movw $0x0012, %cx # sector 18, track 0
+ movw $(0x200+(SETUPSECS*0x200)), %bx # address after setup (es = cs)
+ movw $0x0201, %ax # service 2, 1 sector
+ int $0x13
+ jnc got_sectors
+ movb $0x0f, %cl # sector 15
+ movw $0x0201, %ax # service 2, 1 sector
+ int $0x13
+ jnc got_sectors
+ movb $0x09, %cl
+
+got_sectors:
+ movw %cx, %cs:sectors - _boot
+ movw $INITSEG, %ax
+ movw %ax, %es
+
+# Print some inane message
+
+ movb $0x03, %ah # read cursor pos
+ xorb %bh, %bh
+ int $0x10
+
+ movw $9, %cx
+ movw $0x0007, %bx # page 0, attribute 7 (normal)
+ movw $msg1 - _boot, %bp
+ movw $0x1301, %ax # write string, move cursor
+ int $0x10
+
+# ok, we've written the message, now
+# we want to load the system (at 0x10000)
+
+ movw $TSTLOAD, %ax
+ movw %ax, %es # segment of 0x010000
+ call read_it
+ call kill_motor
+ call print_nl
+
+# after that (everyting loaded), we jump to
+# the setup-routine loaded directly after
+# the bootblock:
+
+ 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.
+#
+# in: es - starting address segment (normally 0x1000)
+#
+sread: .word 1+SETUPSECS # sectors read of current track
+head: .word 0 # current head
+track: .word 0 # current track
+
+read_it:
+ movw %es, %ax
+ testw $0x0fff, %ax
+die:
+ jne die # es must be at 64kB boundary
+ xorw %bx,%bx # bx is starting address within segment
+rp_read:
+ movw %es, %ax
+ subw $TSTLOAD, %ax # have we loaded all yet?
+ cmpw syssize - _boot, %ax
+ jbe ok1_read
+ ret
+ok1_read:
+ movw %cs:sectors - _boot, %ax
+ subw sread - _boot, %ax
+ movw %ax, %cx
+ shlw $9, %cx
+ addw %bx, %cx
+ jnc ok2_read
+ je ok2_read
+ xorw %ax, %ax
+ subw %bx, %ax
+ shrw $9, %ax
+ok2_read:
+ call read_track
+ movw %ax, %cx
+ add sread - _boot, %ax
+ cmpw %cs:sectors - _boot, %ax
+ jne ok3_read
+ movw $1, %ax
+ subw head - _boot, %ax
+ jne ok4_read
+ incw track - _boot
+ok4_read:
+ movw %ax, head - _boot
+ xorw %ax, %ax
+ok3_read:
+ movw %ax, sread - _boot
+ shlw $9, %cx
+ addw %cx, %bx
+ jnc rp_read
+ movw %es, %ax
+ addb $0x10, %ah
+ movw %ax, %es
+ xorw %bx, %bx
+ jmp rp_read
+
+read_track:
+ pusha
+ pusha
+ movw $0xe2e, %ax # loading... message 2e = .
+ movw $7, %bx
+ int $0x10
+ popa
+
+ movw track - _boot, %dx
+ movw sread - _boot, %cx
+ incw %cx
+ movb %dl, %ch
+ movw head - _boot, %dx
+ movb %dl, %dh
+ andw $0x0100, %dx
+ movb $2, %ah
+
+ pushw %dx # save for error dump
+ pushw %cx
+ pushw %bx
+ pushw %ax
+
+ int $0x13
+ jc bad_rt
+ addw $8, %sp
+ popa
+ ret
+
+bad_rt:
+ pushw %ax # save error code
+ call print_all # ah = error, al = read
+
+ xorb %ah, %ah
+ xorb %dl, %dl
+ int $0x13
+
+ addw $10, %sp
+ popa
+ jmp read_track
+
+/*
+ * print_all is for debugging purposes.
+ * It will print out all of the registers. The assumption is that this is
+ * called from a routine, with a stack frame like
+ * dx
+ * cx
+ * bx
+ * ax
+ * error
+ * ret <- sp
+ *
+*/
+
+print_all:
+ movw $5, %cx # error code + 4 registers
+ movw %sp, %bp
+
+print_loop:
+ pushw %cx # save count left
+ call print_nl # nl for readability
+
+ cmpb 5, %cl # see if register name is needed
+ jae no_reg
+
+ movw $(0xe05 + 'A' - 1), %ax
+ subb %cl, %al
+ int $0x10
+ movb $'X', %al
+ int $0x10
+ movb $':', %al
+ int $0x10
+
+no_reg:
+ addw $2, %bp # next register
+ call print_hex # print it
+ popw %cx
+ loop print_loop
+ ret
+
+print_nl:
+ movw $0xe0d, %ax # CR
+ int $0x10
+ movb $0x0a, %al # LF
+ int $0x10
+ ret
+
+/*
+ * print_hex is for debugging purposes, and prints the word
+ * pointed to by ss:bp in hexadecmial.
+*/
+
+print_hex:
+ movw $4, %cx # 4 hex digits
+ movw (%bp), %dx # load word into dx
+
+print_digit:
+ rolw $4, %dx # rotate so that lowest 4 bits are used
+ movb $0xe, %ah
+ movb %dl, %al # mask off so we have only next nibble
+ andb $0xf, %al
+ addb $'0', %al # convert to 0-based digit
+ cmpb $'9', %al # check for overflow
+ jbe good_digit
+ addb $('A' - '0' - 10), %al
+
+good_digit:
+ int $0x10
+ loop print_digit
+ ret
+
+
+/*
+ * This procedure turns off the floppy drive motor, so
+ * that we enter the kernel in a known state, and
+ * don't have to worry about it later.
+ */
+kill_motor:
+ pushw %dx
+ movw $0x3f2, %dx
+ xorb %al, %al
+ outb %al, %dx
+ popw %dx
+ ret
+
+sectors:
+ .word 0
+
+msg1:
+ .byte 13,10
+ .ascii "Loading"
+
+.org 497
+setup_sects:
+ .byte SETUPSECS
+.org 500
+syssize:
+ .word _syssize
+.org 508
+root_dev:
+ .word ROOT_DEV
+boot_flag:
+ .word 0xAA55
+_eboot: