Messages in this thread Patch in this message | | | Date | Wed, 8 Dec 1999 22:30:32 -0500 (EST) | From | Chris Noe <> | Subject | [patch][rft] 360k/720k diskette boot support + bootsect optimizations (2.3.30) |
| |
Small diskette boot support courtesy of Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>, with a few added cleanups/comments by myself.
This hopefully final diff fixes a silly stack frob which Yann Dronaud made me aware of.
I'd like to hear somebody complain that this breaks their compile, kills their boot, or something exciting like that. :) A spare moment to apply this and check if 'make zdisk' or 'make bzdisk' breaks would be much obliged.
I wonder... Does this qualify as a 'new feature' (aka not for 2.3 anymore) or is it a bugfix? You decide, I suppose, based on how much testing it gets. :)
Thanks.
Chris Noe (stiker@northlink.com)
diff -u --recursive linux-2.3.30/README linux/README --- linux-2.3.30/README Mon Dec 6 20:22:19 1999 +++ linux/README Wed Nov 24 23:31:56 1999 @@ -197,10 +197,7 @@ For some, this is on a floppy disk, in which case you can "cp /usr/src/linux/arch/i386/boot/zImage /dev/fd0" to make a bootable - floppy. Please note that you can not boot a kernel by - directly dumping it to a 720k double-density 3.5" floppy. In this - case, it is highly recommended that you install LILO on your - double-density boot floppy or switch to high-density floppies. + floppy. If you boot Linux from the hard drive, chances are you use LILO which uses the kernel image as specified in the file /etc/lilo.conf. The diff -u --recursive linux-2.3.30/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S --- linux-2.3.30/arch/i386/boot/bootsect.S Mon Dec 6 20:22:19 1999 +++ linux/arch/i386/boot/bootsect.S Mon Dec 6 20:23:43 1999 @@ -5,8 +5,10 @@ * modified by Bruce Evans (bde) * modified by Chris Noe (May 1999) (as86 -> gas) * - * bootsect is loaded at 0x7c00 by the bios-startup routines, and moves - * itself out of the way to address 0x90000, and jumps there. + * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment + * addresses must be multiplied by 16 to obtain their respective linear + * addresses. To avoid confusion, linear addresses are written using leading + * hex while segment addresses are written as segment:offset. * * bde - should not jump blindly, there may be systems with only 512K low * memory. Use int 0x12 to get the top of memory, etc. @@ -56,14 +58,12 @@ .global _start _start: -#if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */ - int $0x3 -#endif +# First things first. Move ourselves from 0x7C00 -> 0x90000 and jump there. movw $BOOTSEG, %ax - movw %ax, %ds + movw %ax, %ds # %ds = BOOTSEG movw $INITSEG, %ax - movw %ax, %es + movw %ax, %es # %ax = %es = INITSEG movw $256, %cx subw %si, %si subw %di, %di @@ -82,7 +82,7 @@ # 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, %ds # %ax and %es already contain INITSEG movw %ax, %ss movw %di, %sp # put stack at INITSEG:0x4000-12. @@ -98,66 +98,29 @@ # # High doesn't hurt. Low does. # -# Segments are as follows: ds = es = ss = cs - INITSEG, fs = 0, -# and gs is unused. +# Segments are as follows: %cs = %ds = %es = %ss = INITSEG, %fs = 0, +# and %gs is unused. - movw %cx, %fs # set fs to 0 - movw $0x78, %bx # fs:bx is parameter table address + movw %cx, %fs # %fs = 0 + movw $0x78, %bx # %fs:%bx is parameter table address pushw %ds - ldsw %fs:(%bx), %si # ds:si is source + ldsw %fs:(%bx), %si # %ds:%si is source movb $6, %cl # copy 12 bytes - cld - pushw %di # di = 0x4000-12. - rep - movsw + pushw %di # %di = 0x4000-12. + rep # don't worry about cld + movsw # already done above popw %di popw %ds 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. - -load_setup: - xorb %ah, %ah # reset FDC - xorb %dl, %dl - int $0x13 - 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 nr of sectors/track. -#if 0 - -# bde - the Phoenix BIOS manual says function 0x08 only works for fixed -# disks. It doesn't work for one of my BIOS's (1987 Award). It was -# fatal not to check the error code. - - xorb %dl, %dl - movb $0x08, %ah # AH=8 is get drive parameters - int $0x13 - xorb %ch, %ch - -#else - # 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. +# Note that %cx = 0 from rep movsw above. movw $disksizes, %si # table of sizes to try probe_loop: @@ -166,31 +129,56 @@ movw %ax, sectors cmpw $disksizes+4, %si jae got_sectors # if all else fails, try 9 - - xchgw %cx, %ax # cx = track and sector + + 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) + movw $0x0200, %bx # address = 512, in INITSEG (%es = %cs) movw $0x0201, %ax # service 2, 1 sector int $0x13 jc probe_loop # try next value -#endif got_sectors: - movw $INITSEG, %ax - movw %ax, %es # set up es movb $0x03, %ah # read cursor pos xorb %bh, %bh int $0x10 movw $9, %cx - movw $0x0007, %bx # page 0, attribute 7 (normal) - movw $msg1, %bp - movw $0x1301, %ax # write string, move cursor + movb $0x07, %bl # page 0, attribute 7 (normal) + # %bh is set above; int10 doesn't + # modify it + movw $msg1, %bp + movw $0x1301, %ax # write string, move cursor int $0x10 # tell the user we're loading.. - movw $SYSSEG, %ax # ok, we've written the message, now - movw %ax, %es # we want to load system (at 0x10000) + +# Load the setup-sectors directly after the moved bootblock (at 0x90200). +# We should know the drive geometry to do it, as setup may exceed first +# cylinder (for 9-sector 360K and 720K floppies). + + movw $0x0001, %ax # set sread (sector-to-read) to 1 as + movw $sread, %si # the boot sector has already been read) + movw %ax, (%si) + + xorw %ax, %ax # reset FDC + xorb %dl, %dl + int $0x13 + movw $0x0200, %bx # address = 512, in INITSEG +next_step: + movb setup_sects, %al + movw sectors, %cx + subw (%si), %cx # (%si) = sread + cmpb %cl, %al + jbe no_cyl_crossing + movw sectors, %ax + subw (%si), %ax # (%si) = sread +no_cyl_crossing: + call read_track + pushw %ax # save it + call set_next # set %bx properly; it uses ax,cx,dx + popw %ax # restore + subb %al, setup_sects # rest - for next step + jnz next_step + + pushw $SYSSEG + popw %es # %es = SYSSEG call read_it call kill_motor call print_nl @@ -200,72 +188,74 @@ # 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. - movw %cs:root_dev, %ax +# Segments are as follows: %cs = %ds = %ss = INITSEG, +# %es = SYSSEG, %fs = 0, %gs is unused. + + movw root_dev, %ax orw %ax, %ax jne root_defined - - movw %cs:sectors, %bx + + 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, %cs:root_dev + movw %ax, root_dev # After that (everything 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. - -# es = starting address segment (normally 0x1000) +# These variables are addressed via %si register as it gives shorter code. sread: .word 0 # sectors read of current track head: .word 0 # current head track: .word 0 # current track +# This routine loads the system at address SYSSEG, making sure +# no 64kB boundaries are crossed. We try to load it as fast as +# possible, loading whole tracks whenever we can. + read_it: - movb setup_sects, %al - incb %al - movb %al, sread - movw %es, %ax + movw %es, %ax # %es = SYSSEG when called testw $0x0fff, %ax -die: jne die # es must be at 64kB boundary - - xorw %bx, %bx # bx is starting address within segment +die: jne die # %es must be at 64kB boundary + xorw %bx, %bx # %bx is starting address within segment rp_read: -#ifdef __BIG_KERNEL__ - bootsect_kludge = 0x220 # 0x200 (size of bootsector) + 0x20 (offset - lcall bootsect_kludge # of bootsect_kludge in setup.S) +#ifdef __BIG_KERNEL__ # look in setup.S for bootsect_kludge + bootsect_kludge = 0x220 # 0x200 + 0x20 which is the size of the + lcall bootsect_kludge # bootsector + bootsect_kludge offset #else - movw %es, %ax + movw %es, %ax subw $SYSSEG, %ax + movw %bx, %cx + shr $4, %cx + add %cx, %ax # check offset #endif - cmpw syssize, %ax # have we loaded all yet? + cmpw syssize, %ax # have we loaded everything yet? jbe ok1_read ret ok1_read: movw sectors, %ax - subw sread, %ax + subw (%si), %ax # (%si) = sread movw %ax, %cx shlw $9, %cx addw %bx, %cx jnc ok2_read - + je ok2_read xorw %ax, %ax @@ -273,60 +263,64 @@ shrw $9, %ax ok2_read: call read_track - movw %ax, %cx - addw sread, %ax - cmpw sectors, %ax - jne ok3_read - - movw $1, %ax - subw head, %ax - jne ok4_read - - incw track -ok4_read: - movw %ax, head - xorw %ax, %ax -ok3_read: - movw %ax, sread - shlw $9, %cx - addw %cx, %bx - jnc rp_read - - movw %es, %ax - addb $0x10, %ah - movw %ax, %es - xorw %bx, %bx + call set_next jmp rp_read read_track: pusha pusha - movw $0xe2e, %ax # loading... message 2e = . + movw $0xe2e, %ax # print "." (0x2e) for each track read movw $7, %bx int $0x10 popa - movw track, %dx - movw sread, %cx + +# Accessing head, track, sread via %si gives shorter code. + + movw 4(%si), %dx # 4(%si) = track + movw (%si), %cx # (%si) = sread incw %cx movb %dl, %ch - movw head, %dx + movw 2(%si), %dx # 2(%si) = head movb %dl, %dh andw $0x0100, %dx movb $2, %ah - pushw %dx # save for error dump + pushw %dx # save for error dump pushw %cx pushw %bx pushw %ax int $0x13 jc bad_rt - + addw $8, %sp popa ret +set_next: + movw %ax, %cx + addw (%si), %ax # (%si) = sread + cmp sectors, %ax + jne ok3_set + movw $0x0001, %ax + xorw %ax, 2(%si) # change head + jne ok4_set + incw 4(%si) # next track +ok4_set: + xorw %ax, %ax +ok3_set: + movw %ax, (%si) # set sread + shlw $9, %cx + addw %cx, %bx + jnc set_next_fin + movw %es, %ax + addb $0x10, %ah + movw %ax, %es + xorw %bx, %bx +set_next_fin: + ret + bad_rt: pushw %ax # save error code - call print_all # ah = error, al = read + call print_all # %ah = error, %al = read xorb %ah, %ah xorb %dl, %dl int $0x13 @@ -350,8 +344,8 @@ movw $5, %cx # error code + 4 registers movw %sp, %bp print_loop: - pushw %cx # save count left - call print_nl # nl for readability + pushw %cx # save count remaining + call print_nl # <-- for readability cmpb $5, %cl jae no_reg # see if register name is needed @@ -381,12 +375,12 @@ print_hex: movw $4, %cx # 4 hex digits - movw (%bp), %dx # load word into dx + movw (%bp), %dx # load word into %dx print_digit: rolw $4, %dx # rotate to use low 4 bits - movw $0xe0f, %ax # ah = request - andb %dl, %al # al = mask for nybble - addb $0x90, %al # convert al to ascii hex + movw $0xe0f, %ax # %ah = request + andb %dl, %al # %al = mask for nybble + addb $0x90, %al # convert %al to ascii hex daa # in only four instructions! adc $0x40, %al daa @@ -409,7 +403,7 @@ msg1: .byte 13, 10 .ascii "Loading" -# XXX: This is a *very* snug fit. +# XXX: This is a fairly snug fit. .org 497 setup_sects: .byte SETUPSECS
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |