diff options
author | hpa <hpa> | 2002-06-02 05:12:25 +0000 |
---|---|---|
committer | hpa <hpa> | 2002-06-02 05:12:25 +0000 |
commit | f3d5f4fd208cc58d58e0a000595848bde49b2dbb (patch) | |
tree | af98774e9c4d27c37c0d2b6eefa570679140ad67 | |
parent | 5823e4914a21a2aecb58345716f851407612d63e (diff) | |
download | syslinux-elf-f3d5f4fd208cc58d58e0a000595848bde49b2dbb.tar.gz syslinux-elf-f3d5f4fd208cc58d58e0a000595848bde49b2dbb.tar.xz syslinux-elf-f3d5f4fd208cc58d58e0a000595848bde49b2dbb.zip |
Major rewrite of the very early SYSLINUX code. Generate the "stupid"
version in a different manner. Require NASM 0.98.32 or higher --
thus we don't need the jmpcc macros anymore.
-rw-r--r-- | Makefile | 32 | ||||
-rw-r--r-- | NEWS | 16 | ||||
-rwxr-xr-x | findpatch.pl | 25 | ||||
-rw-r--r-- | genstupid.pl | 77 | ||||
-rw-r--r-- | ldlinux.asm | 623 | ||||
-rw-r--r-- | macros.inc | 51 | ||||
-rw-r--r-- | runkernel.inc | 21 | ||||
-rw-r--r-- | syslinux.asm | 10 | ||||
-rw-r--r-- | syslinux.c | 24 | ||||
-rw-r--r-- | version | 2 |
10 files changed, 411 insertions, 470 deletions
@@ -20,7 +20,7 @@ INCLUDE = CFLAGS = -Wall -O2 -fomit-frame-pointer LDFLAGS = -O2 -s -NASM = nasm +NASM = nasm -O99 NINCLUDE = BINDIR = /usr/bin LIBDIR = /usr/lib/syslinux @@ -41,11 +41,11 @@ CSRC = syslinux.c gethostip.c NASMSRC = ldlinux.asm syslinux.asm copybs.asm \ pxelinux.asm mbr.asm isolinux.asm isolinux-debug.asm SOURCES = $(CSRC) $(NASMSRC) *.inc -BTARGET = kwdhash.gen ldlinux.bss ldlinux.sys ldlinux.bin ldlinux.lst \ +BTARGET = kwdhash.gen ldlinux.bss ldlinux.sys ldlinux.bin \ pxelinux.0 mbr.bin isolinux.bin isolinux-debug.bin ITARGET = syslinux.com syslinux copybs.com gethostip DOCS = COPYING NEWS README TODO *.doc sample -OTHER = Makefile bin2c.pl now.pl genhash.pl keywords genstupid.pl \ +OTHER = Makefile bin2c.pl now.pl genhash.pl keywords findpatch.pl \ keytab-lilo.pl version sys2ansi.pl ppmtolss16 lss16toppm memdisk OBSOLETE = pxelinux.bin @@ -113,11 +113,15 @@ ldlinux.bss: ldlinux.bin ldlinux.sys: ldlinux.bin dd if=ldlinux.bin of=ldlinux.sys bs=512 skip=1 +patch.offset: ldlinux.sys findpatch.pl + $(PERL) findpatch.pl > patch.offset + mbr.bin: mbr.asm $(NASM) -f bin -l mbr.lst -o mbr.bin mbr.asm -syslinux.com: syslinux.asm ldlinux.bss ldlinux.sys stupid.gen - $(NASM) -f bin -l syslinux.lst -o syslinux.com syslinux.asm +syslinux.com: syslinux.asm ldlinux.bss ldlinux.sys patch.offset + $(NASM) -f bin -DPATCH_OFFSET=`cat patch.offset` \ + -l syslinux.lst -o syslinux.com syslinux.asm copybs.com: copybs.asm $(NASM) -f bin -l copybs.lst -o copybs.com copybs.asm @@ -128,20 +132,12 @@ bootsect_bin.c: ldlinux.bss bin2c.pl ldlinux_bin.c: ldlinux.sys bin2c.pl $(PERL) bin2c.pl ldlinux < ldlinux.sys > ldlinux_bin.c -syslinux: syslinux.o bootsect_bin.o ldlinux_bin.o stupid.o +syslinux: syslinux.o bootsect_bin.o ldlinux_bin.o $(CC) $(LDFLAGS) -o syslinux \ - syslinux.o bootsect_bin.o ldlinux_bin.o stupid.o - -ldlinux.lst: ldlinux.bin - : Generated by side effect - -stupid.c: ldlinux.lst genstupid.pl - $(PERL) genstupid.pl < ldlinux.lst - -stupid.gen: stupid.c - : Generated by side effect + syslinux.o bootsect_bin.o ldlinux_bin.o -stupid.o: stupid.c +syslinux.o: syslinux.c patch.offset + $(CC) $(INCLUDE) $(CFLAGS) -DPATCH_OFFSET=`cat patch.offset` -c -o $@ $< gethostip.o: gethostip.c @@ -153,7 +149,7 @@ install: installer install -m 644 -c $(INSTALL_LIB) $(INSTALLROOT)$(LIBDIR) local-tidy: - rm -f *.o *_bin.c stupid.* + rm -f *.o *_bin.c stupid.* patch.offset rm -f syslinux.lst copybs.lst pxelinux.lst isolinux*.lst rm -f $(OBSOLETE) @@ -1,6 +1,22 @@ Starting with 1.47, changes marked with SYSLINUX/PXELINUX/ISOLINUX apply to that specific program only; other changes apply to both. +Changes in 1.75: + * ALL: NASM 0.98.32 or later is now required to build NASM + from sources. + * SYSLINUX: put back in the workaround for the BIOS floppy + table. This seems to be a requirement for "extended" floppy + formats to work correctly. + * SYSLINUX: No longer warn if one is trying to boot on a 286 + or older. The above BIOS workaround no longer fits if the + requirement to use only 8086-compatible code in the early + boot is maintained. It made sense in 1994, but in 2002 a + 286 or older is a museum object. + * SYSLINUX: Use a downright bizarre, stateful algorithm to try + to guess the maximum transfer size. I am *hoping* this will + cut down on the number of systems for which -s is required + to work at any acceptable speed. + Changes in 1.74: * SYSLINUX: fix bug that would cause valid kernel images to be labelled "invalid". diff --git a/findpatch.pl b/findpatch.pl new file mode 100755 index 00000000..ac8ee5c8 --- /dev/null +++ b/findpatch.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl +# +# Script to find the "patch area" of ldlinux.sys +# + +open(SYS, "< ldlinux.sys") or die "$0: Cannot open ldlinux.sys\n"; +if ( read(SYS,$sec1,512) != 512 ) { + die "$0: ldlinux.sys: short read\n"; +} +close(SYS); + +for ( $i = 0 ; $i < 512; $i++ ) { + $scan = substr($sec1,$i,12); + + if ( $scan eq "\032LDLINUX SYS" && + substr($sec1,$i+16,2) eq "\x55\xAA" ) { + last; + } +} + + +die "$0: Did not find patch area signature\n" unless ( $i < 512 ); + +# Past signature, plus align to the subsequent dword. +print ((($i+18)+3) & ~3); print "\n"; diff --git a/genstupid.pl b/genstupid.pl deleted file mode 100644 index 9adf8ef4..00000000 --- a/genstupid.pl +++ /dev/null @@ -1,77 +0,0 @@ -#ident "$Id$" -## ----------------------------------------------------------------------- -## -## Copyright 1998-2002 H. Peter Anvin - All Rights Reserved -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, -## USA; either version 2 of the License, or (at your option) any later -## version; incorporated herein by reference. -## -## ----------------------------------------------------------------------- - -# -# This file is part of the SYSLINUX compilation sequence. -# - -undef $addr, $begin, $end; -$isbegin = 0; $isend = 0; - -while ( $line = <STDIN> ) { - if ( $line =~ /^\s*([0-9]+) ([0-9A-F]{8}) / ) { - $addr = hex $2; - if ( $isbegin ) { - $begin = $addr; - $isbegin = 0; - } - if ( $isend ) { - $end = $addr; - $isend = 0; - } - } - if ( $line =~ /^[0-9A-F\s]+__BEGIN_STUPID_PATCH_AREA\:/ ) { - $isbegin = 1; - } elsif ( $line =~ /^[0-9A-F\s]+__END_STUPID_PATCH_AREA\:/ ) { - $isend = 1; - } -} - -if ( !defined($begin) || !defined($end) || $end > 512 || ($end-$begin) < 3 ) { - print STDERR "$0: error locating STUPID_PATCH_AREA\n"; - exit 1; -} - -open(CFILE, "> stupid.c") || die "$0: cannot create stupid.c: $!\n"; - -$addr = $begin; -printf CFILE "extern unsigned char bootsect[];\n"; -printf CFILE "void make_stupid(void)\n"; -printf CFILE "{\n"; -printf CFILE "\tbootsect[0x%x] = 0xbd;\n", $addr++; -printf CFILE "\tbootsect[0x%x] = 0x01;\n", $addr++; -printf CFILE "\tbootsect[0x%x] = 0x00;\n", $addr++; -while ( $addr < $end ) { - printf CFILE "\tbootsect[0x%x] = 0x90;\n", $addr++; -} -print CFILE "}\n"; - -close(CFILE); - -open(ASMFILE, "> stupid.gen") || die "$0: cannot open stupid.inc: $!\n"; - -printf ASMFILE "\tsection .text\n"; -printf ASMFILE "make_stupid:\n"; -printf ASMFILE "\tmov si, .stupid_patch\n"; -printf ASMFILE "\tmov di, BootSector+0%Xh\n", $begin; -printf ASMFILE "\tmov cx, %d\n", $end-$begin; -printf ASMFILE "\trep movsb\n"; -printf ASMFILE "\tret\n"; -printf ASMFILE "\tsection .data\n"; -printf ASMFILE ".stupid_patch:\n"; -printf ASMFILE "\tmov bp,1\n"; -for ( $addr = $begin + 3 ; $addr < $end ; $addr++ ) { - printf ASMFILE "\tnop\n"; -} - -close(ASMFILE); diff --git a/ldlinux.asm b/ldlinux.asm index ad82045b..9107334f 100644 --- a/ldlinux.asm +++ b/ldlinux.asm @@ -118,8 +118,21 @@ KbdMap resb 256 ; Keyboard map FKeyName resb 10*16 ; File names for F-key help NumBuf resb 15 ; Buffer to load number NumBufEnd resb 1 ; Last byte in NumBuf + alignb 8 + + ; Expanded superblock +SuperInfo equ $ + resq 16 ; The first 16 bytes expanded 8 times + ; + ; These need to follow SuperInfo + ; +RootDir resd 1 ; Location of root directory +DataArea resd 1 ; Location of data area +RootDirSize resw 1 ; Root dir size in sectors +DirScanCtr resw 1 ; Used while searching directory +EndofDirSec resw 1 ; = trackbuf+bsBytesPerSec-31 + alignb 4 -PartInfo resb 16 ; Partition table entry E820Buf resd 5 ; INT 15:E820 data buffer HiLoadAddr resd 1 ; Address pointer for high load loop HighMemSize resd 1 ; End of memory pointer (bytes) @@ -130,22 +143,11 @@ ClustPerMoby resd 1 ; Clusters per 64K ClustSize resd 1 ; Bytes/cluster KernelName resb 12 ; Mangled name for kernel ; (note the spare byte after!) -RootDir equ $ ; Location of root directory -RootDir1 resw 1 -RootDir2 resw 1 -DataArea equ $ ; Location of data area -DataArea1 resw 1 -DataArea2 resw 1 FBytes equ $ ; Used by open/getc FBytes1 resw 1 FBytes2 resw 1 -RootDirSize resw 1 ; Root dir size in sectors -DirScanCtr resw 1 ; Used while searching directory DirBlocksLeft resw 1 ; Ditto -EndofDirSec resw 1 ; = trackbuf+bsBytesPerSec-31 RunLinClust resw 1 ; Cluster # for LDLINUX.SYS -SecPerClust resw 1 ; Same as bsSecPerClust, but a word -NextCluster resw 1 ; Pointer to "nextcluster" routine BufSafe resw 1 ; Clusters we can load into trackbuf BufSafeSec resw 1 ; = how many sectors? BufSafeBytes resw 1 ; = how many bytes? @@ -196,7 +198,15 @@ VGAFileMBuf resb 11 ; Mangled VGA image name section .text org 7C00h -StackBuf equ $ ; Start the stack here (grow down - 4K) +; +; Some of the things that have to be saved very early are saved +; "close" to the initial stack pointer offset, in order to +; reduce the code size... +; +StackBuf equ $-32 ; Start the stack here (grow down - 4K) +PartInfo equ StackBuf ; Saved partition table entry +FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo) +OrigFDCTabPtr equ StackBuf-4 ; The high dword on the stack ; ; Primary entry point. Tempting as though it may be, we can't put the @@ -211,30 +221,49 @@ bootsec equ $ ; loaded and ready for us ; bsOemName db 'SYSLINUX' ; The SYS command sets this, so... +; +; These are the fields we actually care about. We end up expanding them +; all to dword size early in the code, so generate labels for both +; the expanded and unexpanded versions. +;; +%macro superb 1 +bx %+ %1 equ SuperInfo+($-superblock)*8+4 +bs %+ %1 equ $ + zb 1 +%endmacro +%macro superw 1 +bx %+ %1 equ SuperInfo+($-superblock)*8 +bs %+ %1 equ $ + zw 1 +%endmacro +%macro superd 1 +bx %+ %1 equ $ ; no expansion for dwords +bs %+ %1 equ $ + zd 1 +%endmacro superblock equ $ -bsBytesPerSec zw 1 -bsSecPerClust zb 1 -bsResSectors zw 1 -bsFATs zb 1 -bsRootDirEnts zw 1 -bsSectors zw 1 -bsMedia zb 1 -bsFATsecs zw 1 -bsSecPerTrack zw 1 -bsHeads zw 1 -bsHiddenSecs equ $ -bsHidden1 zw 1 -bsHidden2 zw 1 -bsHugeSectors equ $ -bsHugeSec1 zw 1 -bsHugeSec2 zw 1 -bsDriveNumber zb 1 -bsReserved1 zb 1 -bsBootSignature zb 1 ; 29h if the following fields exist -bsVolumeID zd 1 + superw BytesPerSec + superb SecPerClust + superw ResSectors + superb FATs + superw RootDirEnts + superw Sectors + superb Media + superw FATsecs + superw SecPerTrack + superw Heads +superinfo_size equ ($-superblock)-1 ; How much to expand + superd Hidden + superd HugeSectors + superb DriveNumber + superb Reserved1 + superb BootSignature ; 29h if the following fields exist + superd VolumeID bsVolumeLabel zb 11 -bsFileSysType zb 8 ; Must be FAT12 for this version +bsFileSysType zb 8 ; Must be FAT12 or FAT16 for this version superblock_len equ $-superblock + +SecPerClust equ bxSecPerClust ; ; Note we don't check the constraints above now; we did that at install ; time (we hope!) @@ -248,52 +277,46 @@ start: ; ; Set up the stack ; - xor cx,cx - mov ss,cx + xor ax,ax + mov ss,ax mov sp,StackBuf ; Just below BSS - mov es,cx + mov es,ax ; ; DS:SI may contain a partition table entry. Preserve it for us. ; - mov cl,8 ; Save partition info (CH == 0) - mov di,PartInfo + mov cx,8 ; Save partition info + mov di,sp rep movsw + + mov ds,ax ; Now we can initialize DS... + + mov [di+bsDriveNumber-FloppyTable],dl + and dl,dl ; If floppy disk (00-7F), assume no + js harddisk ; partition table ; ; Now sautee the BIOS floppy info block to that it will support decent- ; size transfers; the floppy block is 11 bytes and is stored in the ; INT 1Eh vector (brilliant waste of resources, eh?) ; ; Of course, if BIOSes had been properly programmed, we wouldn't have -; had to waste precious boot sector space with this code. -; -; This code no longer fits. Hope that noone really needs it anymore. -; (If so, it needs serious updating.) In fact, some indications is that -; this code does more harm than good with all the new kinds of drives and -; media. +; had to waste precious space with this code. ; -%ifdef SUPPORT_REALLY_BROKEN_BIOSES - lds si,[ss:fdctab] ; DS:SI -> original - push ds ; Save on stack in case - push si ; we have to bail - push bx - mov cx,6 ; 12 bytes - mov di,floppy_table - push di - cld - rep movsw ; Faster to move words - pop di - mov ds,ax ; Now we can point DS to here, too + mov bx,fdctab + lfs si,[bx] ; FS:SI -> original fdctab + push fs ; Save on stack in case we need to bail + push si + mov cl,6 ; 12 bytes (CX == 0) + ; es:di -> FloppyTable already + ; This should be safe to do now, interrupts are off... + mov [bx],di ; FloppyTable + mov [bx+2],ax ; Segment 0 + fs rep movsw ; Faster to move words mov cl,[bsSecPerTrack] ; Patch the sector count - mov [di+4],cl - mov [fdctab+2],ax ; Segment 0 - mov [fdctab],di ; offset floppy_block -%else - mov ds,cx ; CX == 0 -%endif -; -; Ready to enable interrupts, captain -; - sti + mov [di-8],cl + ; AX == 0 here + int 13h ; Some BIOSes need this + + jmp short not_harddisk ; ; The drive number and possibly partition information was passed to us ; by the BIOS or previous boot loader (MBR). Current "best practice" is to @@ -303,15 +326,12 @@ start: ; ; Note: di points to beyond the end of PartInfo ; - mov [bsDriveNumber],dl - test dl,80h ; If floppy disk (00-7F), assume no - jz not_harddisk ; partition table - test byte [di-16],7Fh ; Sanity check: "active flag" should - jnz no_partition ; be 00 or 80 - lea si,[di-8] ; Partition offset (dword) - mov di,bsHidden1 - mov cl,2 ; CH == 0 - rep movsw +harddisk: +; This sanity check doesn't fit anymore... +; test byte [di-16],7Fh ; Sanity check: "active flag" should +; jnz no_partition ; be 00 or 80 + mov eax,[di-8] ; Partition offset (dword) + mov [bsHidden],eax no_partition: ; ; Get disk drive parameters (don't trust the superblock.) Don't do this for @@ -325,69 +345,86 @@ no_partition: jc no_driveparm and ah,ah jnz no_driveparm - inc dh ; Contains # of heads - 1 - mov [bsHeads],dh + shr dx,8 + inc dx ; Contains # of heads - 1 + mov [bsHeads],dx and cx,3fh mov [bsSecPerTrack],cx no_driveparm: not_harddisk: ; +; Ready to enable interrupts, captain +; + sti +; +; Insane hack to expand the superblock to dwords +; +expand_super: + xor eax,eax + mov es,ax ; INT 13:08 destroys ES + mov si,superblock + mov di,SuperInfo + mov cl,superinfo_size ; CH == 0 +.loop: + lodsw + dec si + stosd ; Store expanded word + xor ah,ah + stosd ; Store expanded byte + loop .loop + +; ; Now we have to do some arithmetric to figure out where things are located. ; If Micro$oft had had brains they would already have done this for us, ; and stored it in the superblock at format time, but here we go, ; wasting precious boot sector space again... ; +%define Z di-superinfo_size*8-SuperInfo debugentrypt: - xor ax,ax ; INT 13:08 destroys ES - mov es,ax - mov al,[bsFATs] ; Number of FATs (AH == 0) - mul word [bsFATsecs] ; Get the size of the FAT area - add ax,[bsHidden1] ; Add hidden sectors - adc dx,[bsHidden2] - add ax,[bsResSectors] ; And reserved sectors - adc dx,byte 0 - - mov [RootDir1],ax ; Location of root directory - mov [RootDir2],dx - mov [DataArea1],ax - mov [DataArea2],dx - push ax - push dx - - mov ax,32 ; Size of a directory entry - mul word [bsRootDirEnts] - mov bx,[bsBytesPerSec] + mov ax,[bxFATs] ; Number of FATs (eax<31:16> == 0) + mov edx,[Z+bxFATsecs] ; Sectors/FAT + mul edx ; Get the size of the FAT area + ; edx <- 0 + add eax,[bxHidden] ; Add hidden sectors + add eax,[Z+bxResSectors] ; And reserved sectors + + mov [RootDir],eax ; Location of root directory + mov [DataArea],eax ; First data sector + push eax + + mov eax,[Z+bxRootDirEnts] + shl ax,5 ; Size of a directory entry + mov bx,[Z+bxBytesPerSec] add ax,bx ; Round up, not down dec ax div bx ; Now we have the size of the root dir mov [RootDirSize],ax mov [DirScanCtr],ax add bx,trackbuf-31 - mov [EndofDirSec],bx ; End of a single directory sector - - add [DataArea1],ax - adc word [DataArea2],byte 0 + mov [Z+EndofDirSec],bx ; End of a single directory sector + add [Z+DataArea],eax + pop eax ; Reload root directory starting point - pop dx ; Reload root directory starting point - pop ax ; ; Now the fun begins. We have to search the root directory for ; LDLINUX.SYS and load the first sector, so we have a little more ; space to have fun with. Then we can go chasing through the FAT. ; Joy!! ; -sd_nextsec: push ax - push dx +sd_nextsec: push eax mov bx,trackbuf push bx call getonesec pop si -sd_nextentry: cmp byte [si],0 ; Directory high water mark +sd_nextentry: mov cx,11 + cmp [si],ch ; Directory high water mark je kaboom - test byte [si+11],18h ; Must be a file - jnz sd_not_file +; This no longer fits... since we'd be dead anyway if there +; was a nonfile named LDLINUX.SYS on the disk, it shouldn't +; matter... +; test byte [si+11],18h ; Must be a file +; jnz sd_not_file mov di,ldlinux_name - mov cx,11 push si repe cmpsb pop si @@ -395,10 +432,8 @@ sd_nextentry: cmp byte [si],0 ; Directory high water mark sd_not_file: add si,byte 32 ; Distance to next cmp si,[EndofDirSec] jb sd_nextentry - pop dx - pop ax - add ax,byte 1 - adc dx,byte 0 + pop eax + inc eax dec word [DirScanCtr] jnz sd_nextsec ; @@ -407,8 +442,9 @@ sd_not_file: add si,byte 32 ; Distance to next kaboom: xor si,si mov ss,si - mov sp,StackBuf ; Reset stack + mov sp,StackBuf-4 ; Reset stack mov ds,si ; Reset data segment + pop dword [fdctab] ; Restore FDC table .patch: mov si,bailmsg call writestr ; Returns with AL = 0 cbw ; AH <- 0 @@ -422,16 +458,14 @@ kaboom: ; found_it: ; Note: we actually leave two words on the stack here ; (who cares?) - xor ax,ax - mov al,[bsSecPerClust] + mov eax,[bxSecPerClust] mov bp,ax ; Load an entire cluster - mov bx,[si+26] ; First cluster + movzx ebx,word [si+26] ; First cluster mov [RunLinClust],bx ; Save for later use dec bx ; First cluster is "cluster 2" dec bx - mul bx - add ax,[DataArea1] - adc dx,[DataArea2] + mul ebx + add eax,[DataArea] mov bx,ldlinux_sys call getlinsec mov si,bs_magic @@ -441,41 +475,32 @@ found_it: ; Note: we actually leave two words on the stack here jne kaboom ; matches LDLINUX.SYS ; ; Done! Jump to the entry point! -; -; Note that some BIOSes are buggy and run the boot sector at 07C0:0000 -; instead of 0000:7C00 and the like. We don't want to add anything -; more to the boot sector, so it is written to not assume a fixed -; value in CS, but we don't want to deal with that anymore from now -; on. ; - jmp 0:ldlinux_ent - + jmp ldlinux_ent ; ; ; writestr: write a null-terminated string to the console ; writestr: -wstr_1: lodsb +.loop: lodsb and al,al - jz return + jz .return mov ah,0Eh ; Write to screen as TTY mov bx,0007h ; White on black, current page int 10h - jmp short wstr_1 + jmp short .loop +.return: ret + ; -; disk_error: decrement the retry count and bail if zero +; disk_error: decrement the retry count and bail if zero. +; This gets patched once we have more space to try to +; optimize transfer sizes on broken machines. ; disk_error: dec si ; SI holds the disk retry counter jz kaboom - pop bx ; <I> - pop cx ; <H> - pop dx ; <G> - pop ax ; <F> (AH = 0) - mov al,1 ; Once we fail, only transfer 1 sector + ; End of patched "call" instruction! jmp short disk_try_again -return: ret - ; ; getonesec: like getlinsec, but pre-sets the count to 1 ; @@ -485,7 +510,7 @@ getonesec: ; ; getlinsec: load a sequence of BP floppy sector given by the linear sector -; number in DX:AX into the buffer at ES:BX. We try to optimize +; number in EAX into the buffer at ES:BX. We try to optimize ; by loading up to a whole track at a time, but the user ; is responsible for not crossing a 64K boundary. ; (Yes, BP is weird for a count, but it was available...) @@ -497,28 +522,25 @@ getonesec: ; mov bp,1 ; nop ... (BD 01 00 90 90...) when installing with ; the -s option. ; +; This routine assumes CS == DS. +; ; Stylistic note: use "xchg" instead of "mov" when the source is a register ; that is dead from that point; this saves space. However, please keep ; the order to dst,src to keep things sane. ; getlinsec: - mov si,[bsSecPerTrack] + mov esi,[bxSecPerTrack] ; ; Dividing by sectors to get (track,sector): we may have - ; up to 2^18 tracks, so we need to do this in two steps - ; to produce a 32-bit quotient. + ; up to 2^18 tracks, so we need to use 32-bit arithmetric. ; - xchg cx,ax ; CX <- LSW of LBA - xchg ax,dx - xor dx,dx ; DX:AX now == MSW of LBA - div si ; Obtain MSW of track # - xchg ax,cx ; Remainder -> MSW of new dividend - ; LSW of LBA -> LSW of new dividend - ; Quotient -> MSW of track # - div si ; Obtain LSW of track #, remainder - xchg cx,dx ; CX <- Sector index (0-based) - ; DX <- MSW of track # - div word [bsHeads] ; Convert track to head/cyl + xor edx,edx ; Zero-extend LBA to 64 bits + div esi + xor cx,cx + xchg cx,dx ; CX <- sector index (0-based) + ; EDX <- 0 + ; eax = track # + div dword [bxHeads] ; Convert track to head/cyl ; ; Now we have AX = cyl, DX = head, CX = sector (0-based), ; BP = sectors to transfer, SI = bsSecPerTrack, @@ -527,23 +549,25 @@ getlinsec: gls_nextchunk: push si ; <A> bsSecPerTrack push bp ; <B> Sectors to transfer + ; Important - this gets patched with a call. The call + ; assumes cx, si and bp are set up, and can modify bp + ; and destroy si. Until we have the space to do so, + ; transfer one sector at a time. +gls_set_size: __BEGIN_STUPID_PATCH_AREA: - sub si,cx ; Sectors left on track - cmp bp,si - jna gls_lastchunk - mov bp,si ; No more than a trackful, please! + mov bp,1 ; 3 bytes, same as a call insn __END_STUPID_PATCH_AREA: -gls_lastchunk: + push ax ; <C> Cylinder # push dx ; <D> Head # push cx ; <E> Sector # - mov cl,6 ; Because IBM was STOOPID - shl ah,cl ; and thought 8 bits were enough + shl ah,6 ; Because IBM was STOOPID + ; and thought 8 bits were enough ; then thought 10 bits were enough... pop cx ; <E> Sector # push cx ; <E> Sector # - inc cx ; Sector numbers are 1-based + inc cx ; Sector numbers are 1-based, sigh or cl,ah mov ch,al mov dh,dl @@ -555,24 +579,16 @@ gls_lastchunk: ; Do the disk transfer... save the registers in case we fail :( ; disk_try_again: - push ax ; <F> Number of sectors we're transferring + pusha ; <F> mov ah,02h ; READ DISK - push dx ; <G> - push cx ; <H> - push bx ; <I> - push si ; <J> int 13h - pop si ; <J> + popa ; <F> jc disk_error ; ; Disk access successful ; - pop bx ; <I> Buffer location - pop ax ; <H> No longer needed - pop ax ; <G> No longer needed - pop di ; <F> Sector transferred count pop cx ; <E> Sector # - mov ax,di ; Reduce sector left count + mov di,ax ; Reduce sector left count mul word [bsBytesPerSec] ; Figure out how much to advance ptr add bx,ax ; Update buffer location pop dx ; <D> Head # @@ -580,7 +596,7 @@ disk_try_again: pop bp ; <B> Sectors left to transfer pop si ; <A> Number of sectors/track sub bp,di ; Reduce with # of sectors just read - jz return ; Done! + jz writestr.return ; Done! add cx,di cmp cx,si jb gls_nextchunk @@ -596,6 +612,7 @@ bailmsg: db 'Boot failed', 0Dh, 0Ah, 0 bs_checkpt equ $ ; Must be <= 7DEFh +%if 1 bs_checkpt_off equ ($-$$) %ifndef DEPEND %if bs_checkpt_off > 1EFh @@ -604,6 +621,7 @@ bs_checkpt_off equ ($-$$) %endif zb 1EFh-($-$$) +%endif bs_magic equ $ ; From here to the magic_len equ ; must match ldlinux_magic ldlinux_name: db 'LDLINUX SYS' ; Looks like this in the root dir @@ -628,9 +646,26 @@ ldlinux_magic db 'LDLINUX SYS' dd HEXDATE dw 0AA55h - align 4 +; +; This area is possibly patched by the installer. It is located +; immediately after the EOF + LDLINUX SYS + 4 bytes + 55 AA + alignment, +; so we can find it algorithmically. +; + alignb 4 +MaxTransfer dw 00FFh ; Absolutely maximum transfer size + align 4 ldlinux_ent: +; +; Note that some BIOSes are buggy and run the boot sector at 07C0:0000 +; instead of 0000:7C00 and the like. We don't want to add anything +; more to the boot sector, so it is written to not assume a fixed +; value in CS, but we don't want to deal with that anymore from now +; on. +; + jmp 0:.next +.next: + ; ; Tell the user we got this far ; @@ -641,22 +676,22 @@ ldlinux_ent: ; We can really only rely on a single sector having been loaded. Hence ; we should load the FAT into RAM and start chasing pointers... ; - mov dx,1 ; 64K xor ax,ax - div word [bsBytesPerSec] ; sectors/64K + cwd + inc dx ; DX:AX <- 64K + div word [bxBytesPerSec] ; sectors/64K mov si,ax push es mov bx,fat_seg ; Load into fat_seg:0000 mov es,bx - mov ax,[bsHidden1] ; Hidden sectors - mov dx,[bsHidden2] - add ax,[bsResSectors] ; plus reserved sectors = FAT - adc dx,byte 0 - mov cx,[bsFATsecs] ; Sectors/FAT + mov eax,[bsHidden] ; Hidden sectors + add edx,[bxResSectors] + add eax,edx + mov ecx,[bxFATsecs] ; Sectors/FAT fat_load_loop: - mov bp,cx + mov ebp,ecx ; Make sure high EBP = 0 cmp bp,si jna fat_load mov bp,si ; A full 64K moby @@ -665,8 +700,7 @@ fat_load: call getlinsecsr sub cx,bp jz fat_load_done ; Last moby? - add ax,bp ; Advance sector count - adc dx,byte 0 + add eax,ebp ; Advance sector count mov bx,es ; Next 64K moby add bx,1000h mov es,bx @@ -678,20 +712,17 @@ fat_load_done: ; Also figure out how many clusters will fit in an 8K buffer, and how ; many sectors and bytes that is ; - mov di,[bsBytesPerSec] ; Used a lot below - - movzx eax,byte [bsSecPerClust] ; We do this in the boot - ; sector, too, but there - mov [SecPerClust],ax ; wasn't space to save it - mov si,ax ; Also used a lot... + mov edi,[bxBytesPerSec] ; Used a lot below + mov eax,[SecPerClust] + mov si,ax ; Also used a lot mul di mov [ClustSize],eax ; Bytes/cluster mov bx,ax - mov ax,trackbufsize - xor dx,dx + mov ax,trackbufsize ; High bit 0 + cwd div bx mov [BufSafe],ax ; # of cluster in trackbuf - mul word [SecPerClust] + mul si mov [BufSafeSec],ax mul di mov [BufSafeBytes],ax @@ -700,40 +731,29 @@ fat_load_done: ; ; FAT12 or FAT16? This computation is fscking ridiculous... ; - xor dx,dx - xor cx,cx - mov ax,[bsSectors] + mov eax,[bxSectors] and ax,ax jnz have_secs - mov ax,[bsHugeSectors] - mov dx,[bsHugeSectors+2] -have_secs: sub ax,[bsResSectors] - sbb dx,byte 0 - mov cl,[bsFATs] -sec_fat_loop: sub ax,[bsFATsecs] - sbb dx,byte 0 - loop sec_fat_loop - push ax - push dx - mov ax,[bsRootDirEnts] - mov bx,32 ; Smaller than shift since we - mul bx ; need the doubleword product - add ax,di - adc dx,byte 0 - sub ax,byte 1 - sbb dx,byte 0 - div di - mov bx,ax - pop dx - pop ax - sub ax,bx - sbb dx,byte 0 - div si - cmp ax,4086 ; Right value? - mov ax,nextcluster_fat16 - ja have_fat_type -have_fat12: mov ax,nextcluster_fat12 -have_fat_type: mov word [NextCluster],ax + mov eax,[bsHugeSectors] +have_secs: add eax,[bsHidden] ; These are not included + sub eax,[RootDir] ; Start of root directory + movzx ebx,word [RootDirSize] + sub eax,ebx ; Subtract root directory size + xor edx,edx + div esi ; Convert to clusters + cmp ax,4086 ; FAT12 limit + jna is_fat12 + ; Patch the jump + mov byte [nextcluster+1],nextcluster_fat16-(nextcluster+2) +is_fat12: + +; +; Patch gls_set_size so we can transfer more than one sector at a time. +; + mov byte [gls_set_size],0xe8 ; E8 = CALL NEAR + mov word [gls_set_size+1],do_gls_set_size-(gls_set_size+3) + mov byte [disk_error],0xe8 + mov word [disk_error+1],do_disk_error-(disk_error+3) ; ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first @@ -744,7 +764,7 @@ load_rest: mov bx,ldlinux_sys add bx,cx mov si,[RunLinClust] - call [NextCluster] + call nextcluster xor dx,dx mov ax,ldlinux_len-1 ; To be on the safe side add ax,cx @@ -775,19 +795,18 @@ all_read_jmp: ; ; 386 check getfssec: -getfragment: xor bp,bp ; Fragment sector count - mov ax,si ; Get sector address +getfragment: xor ebp,ebp ; Fragment sector count + movzx eax,si ; Get sector address dec ax ; Convert to 0-based dec ax - mul word [SecPerClust] - add ax,[DataArea1] - adc dx,[DataArea2] + mul dword [SecPerClust] + add eax,[DataArea] getseccnt: ; See if we can read > 1 clust add bp,[SecPerClust] dec cx ; Reduce clusters left to find - mov di,si ; Predict next cluster - inc di - call [NextCluster] + lea di,[si+1] + call nextcluster + cmc jc gfs_eof ; At EOF? jcxz endfragment ; Or was it the last we wanted? cmp si,di ; Is file continuous? @@ -797,31 +816,24 @@ gfs_eof: pushf ; Remember EOF or not push si push cx gfs_getchunk: - push ax - push dx + push eax mov ax,es ; Check for 64K boundaries. - mov cl,4 - shl ax,cl + shl ax,4 add ax,bx xor dx,dx neg ax - jnz gfs_partseg - inc dx ; Full 64K segment -gfs_partseg: + setz dl ; DX <- 1 if full 64K segment div word [bsBytesPerSec] ; How many sectors fit? mov si,bp sub si,ax ; Compute remaining sectors jbe gfs_lastchunk mov bp,ax - pop dx - pop ax + pop eax call getlinsecsr - add ax,bp - adc dx,byte 0 + add eax,ebp ; EBP<31:16> == 0 mov bp,si ; Remaining sector count jmp short gfs_getchunk -gfs_lastchunk: pop dx - pop ax +gfs_lastchunk: pop eax call getlinsec pop cx pop si @@ -833,51 +845,33 @@ gfs_return: ret ; ; getlinsecsr: save registers, call getlinsec, restore registers ; -getlinsecsr: push ax - push dx - push cx - push bp - push si - push di +getlinsecsr: pushad call getlinsec - pop di - pop si - pop bp - pop cx - pop dx - pop ax + popad ret ; ; nextcluster: Advance a cluster pointer in SI to the next cluster -; pointed at in the FAT tables (note: FAT12 assumed) -; Sets CF on return if end of file. -; -; The variable NextCluster gets set to the appropriate -; value here. +; pointed at in the FAT tables. CF=0 on return if end of file. ; +nextcluster: + jmp short nextcluster_fat12 ; This gets patched + nextcluster_fat12: - push ax + push bx push ds - mov ax,fat_seg - mov ds,ax - mov ax,si ; Multiply by 3/2 - shr ax,1 - pushf ; CF now set if odd - add si,ax - mov si,[si] - popf + mov bx,fat_seg + mov ds,bx + mov bx,si ; Multiply by 3/2 + shr bx,1 ; CF now set if odd + mov si,[si+bx] jnc nc_even - shr si,1 ; Needed for odd only - shr si,1 - shr si,1 - shr si,1 + shr si,4 ; Needed for odd only nc_even: and si,0FFFh cmp si,0FF0h ; Clears CF if at end of file - cmc ; But we want it SET... pop ds - pop ax + pop bx nc_return: ret ; @@ -894,10 +888,47 @@ nextcluster_fat16: .seg0: mov ds,ax mov si,[si] cmp si,0FFF0h - cmc pop ds pop ax ret + +; +; Routine that controls how much we can transfer in one chunk. Called +; from gls_set_size in getlinsec. +; +do_gls_set_size: + sub si,cx ; Sectors left on track + cmp bp,si + jna .lastchunk + mov bp,si ; No more than a trackful, please! +.lastchunk: + cmp bp,[MaxTransfer] ; Absolute maximum transfer size + jna .oktransfer + mov bp,[MaxTransfer] +.oktransfer: + ret + +; +; This routine captures disk errors, and tries to decide if it is +; time to reduce the transfer size. +; +do_disk_error: + dec si ; Decrement the retry counter + jz kaboom ; If expired, croak + cmp si,2 ; If only 2 attempts left + ja .nodanger + mov al,1 ; Drop transfer size to 1 + jmp short .setsize +.nodanger: + cmp si,retry_count-2 + ja .again ; First time, just try again + shr al,1 ; Otherwise, try to reduce + adc al,0 ; the max transfer size, but not to 0 +.setsize: + mov [MaxTransfer],al +.again: + ret + ; ; Debug routine ; @@ -951,8 +982,8 @@ all_read: ; Now, everything is "up and running"... patch kaboom for more ; verbosity and using the full screen system ; - mov byte [kaboom.patch],0e9h ; JMP NEAR - mov word [kaboom.patch+1],kaboom2-(kaboom.patch+3) + ; E9 = JMP NEAR + mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8) ; ; Compute some parameters that depend on cluster size @@ -983,7 +1014,7 @@ all_read: mov di,KbdMap ; Default keymap 1:1 xor al,al - mov cx,256 + inc ch ; CX <- 256 mkkeymap: stosb inc al loop mkkeymap @@ -1396,10 +1427,9 @@ searchdir: mov [DirScanCtr],ax mov ax,[RootDirSize] mov [DirBlocksLeft],ax - mov ax,[RootDir1] - mov dx,[RootDir2] + mov eax,[RootDir] scan_group: - mov bp,[DirBlocksLeft] + movzx ebp,word [DirBlocksLeft] and bp,bp jz dir_return cmp bp,[BufSafeSec] @@ -1407,24 +1437,14 @@ scan_group: mov bp,[BufSafeSec] load_last: sub [DirBlocksLeft],bp - push ax - push dx + push eax mov ax,[bsBytesPerSec] mul bp add ax,trackbuf-31 mov [EndofDirSec],ax ; End of loaded - pop dx - pop ax - push bp ; Save number of sectors - push ax ; Save present location - push dx - push di ; Save name + pop eax mov bx,trackbuf - call getlinsec - pop di - pop dx - pop ax - pop bp + call getlinsecsr mov si,trackbuf dir_test_name: cmp byte [si],0 ; Directory high water mark je dir_return ; Failed @@ -1442,8 +1462,7 @@ dir_not_this: add si,byte 32 jz dir_return ; Out of it... cmp si,[EndofDirSec] jb dir_test_name - add ax,bp ; Increment linear sector number - adc dx,byte 0 + add eax,ebp ; Increment linear sector number jmp short scan_group dir_success: mov ax,[si+28] ; Length of file @@ -35,57 +35,6 @@ %endif ; -; For our convenience: define macros for jump-over-unconditinal jumps -; -%macro jmpz 1 - jnz %%skip - jmp %1 -%%skip: -%endmacro - -%macro jmpnz 1 - jz %%skip - jmp %1 -%%skip: -%endmacro - -%macro jmpe 1 - jne %%skip - jmp %1 -%%skip: -%endmacro - -%macro jmpne 1 - je %%skip - jmp %1 -%%skip: -%endmacro - -%macro jmpc 1 - jnc %%skip - jmp %1 -%%skip: -%endmacro - -%macro jmpnc 1 - jc %%skip - jmp %1 -%%skip: -%endmacro - -%macro jmpb 1 - jnb %%skip - jmp %1 -%%skip: -%endmacro - -%macro jmpnb 1 - jb %%skip - jmp %1 -%%skip: -%endmacro - -; ; Macros similar to res[bwd], but which works in the code segment (after ; section .text) ; diff --git a/runkernel.inc b/runkernel.inc index 25e128c9..b87c9210 100644 --- a/runkernel.inc +++ b/runkernel.inc @@ -510,25 +510,18 @@ in_proper_place: jne root_not_floppy mov word [es:bs_rootdev],0200h root_not_floppy: + ; ; Copy the disk table to high memory, then re-initialize the floppy ; controller ; -; This needs to be moved before the copy -; -%if 0 - push ds - push bx - lds si,[fdctab] +%if IS_SYSLINUX + lgs si,[cs:fdctab] mov di,linux_fdctab - mov cx,3 ; 12 bytes - push di - rep movsd - pop di - mov [fdctab1],di ; Save new floppy tab pos - mov [fdctab2],es - pop bx - pop ds + mov cx,6 ; 12 bytes + gs rep movsw + mov [cs:fdctab],word linux_fdctab ; Save new floppy tab pos + mov [cs:fdctab+2],es %endif ; ; Linux wants the floppy motor shut off before starting the kernel, diff --git a/syslinux.asm b/syslinux.asm index ba23d20d..e104236a 100644 --- a/syslinux.asm +++ b/syslinux.asm @@ -440,12 +440,12 @@ die_common: int 21h ; -; This includes a small subroutine make_stupid to patch up the boot sector -; in case we give the -s (stupid) option +; Patch the code to make it "stupid" ; -%ifndef DEPEND ; Generated file -%include "stupid.gen" -%endif +make_stupid: + ; Only access one sector at a time + mov word [LDLinuxSYS+PATCH_OFFSET],1 + ret section .data msg_error_sp: db 'ERROR $' @@ -52,8 +52,6 @@ extern unsigned int bootsect_len; extern unsigned char ldlinux[]; extern unsigned int ldlinux_len; -extern void make_stupid(void); /* Patching routine for stupid mode */ - char *program; /* Name of program */ char *device; /* Device to install to */ uid_t euid; /* Our current euid */ @@ -100,6 +98,28 @@ static u_int32_t get_32(unsigned char *p) ((u_int32_t)p[2] << 16) + ((u_int32_t)p[3] << 24); } +static void set_16(unsigned char *p, u_int16_t v) +{ + p[0] = (v & 0xff); + p[1] = ((v >> 8) & 0xff); +} + +#if 0 /* Not needed */ +static void set_32(unsigned char *p, u_int32_t v) +{ + p[0] = (v & 0xff); + p[1] = ((v >> 8) & 0xff); + p[2] = ((v >> 16) & 0xff); + p[3] = ((v >> 24) & 0xff); +} +#endif + +/* Patch the code so that we're running in stupid mode */ +static void make_stupid(void) +{ + set_16(ldlinux+PATCH_OFFSET, 1); /* Access only one sector at a time */ +} + void usage(void) { fprintf(stderr, "Usage: %s [-sf] [-o offset] device\n", program); @@ -1 +1 @@ -1.74 +1.75 |