diff options
40 files changed, 865 insertions, 290 deletions
@@ -1,6 +1,6 @@ ## ----------------------------------------------------------------------- ## -## Copyright 1998-2006 H. Peter Anvin - All Rights Reserved +## Copyright 1998-2007 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 @@ -17,12 +17,18 @@ # No builtin rules MAKEFLAGS = -r +gcc_ok = $(shell if gcc $(1) dummy.c -o /dev/null 2>/dev/null; \ + then echo '$(1)'; else echo '$(2)'; fi) + +comma := , +LDHASH := $(call gcc_ok,-Wl$(comma)--hash-style=both,) + OSTYPE = $(shell uname -msr) CC = gcc INCLUDE = CFLAGS = -W -Wall -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64 PIC = -fPIC -LDFLAGS = -O2 -s +LDFLAGS = -O2 -s $(LDHASH) AR = ar RANLIB = ranlib @@ -63,12 +69,16 @@ BINFILES = bootsect_bin.c ldlinux_bin.c mbr_bin.c \ # mingw suite installed BTARGET = kwdhash.gen version.gen version.h \ ldlinux.bss ldlinux.sys ldlinux.bin \ - pxelinux.0 mbr.bin isolinux.bin isolinux-debug.bin \ + pxelinux.0 isolinux.bin isolinux-debug.bin \ extlinux.bin extlinux.bss extlinux.sys -BOBJECTS = $(BTARGET) dos/syslinux.com win32/syslinux.exe memdisk/memdisk +BOBJECTS = $(BTARGET) mbr/mbr.bin dos/syslinux.com win32/syslinux.exe memdisk/memdisk +# BESUBDIRS and IESUBDIRS are "early", i.e. before the root; BSUBDIRS +# and ISUBDIRS are "late", after the root. +BESUBDIRS = mbr BSUBDIRS = memdisk dos win32 ITARGET = copybs.com gethostip mkdiskimage IOBJECTS = $(ITARGET) mtools/syslinux unix/syslinux extlinux/extlinux +IESUBDIRS = ISUBDIRS = mtools unix extlinux sample com32 DOCS = COPYING NEWS README TODO BUGS *.doc sample menu com32 OTHER = Makefile bin2c.pl now.pl genhash.pl keywords findpatch.pl \ @@ -82,7 +92,7 @@ INSTALL_BIN = mtools/syslinux gethostip ppmtolss16 lss16toppm INSTALL_SBIN = extlinux/extlinux # Things to install in /usr/lib/syslinux INSTALL_AUX = pxelinux.0 isolinux.bin isolinux-debug.bin \ - dos/syslinux.com copybs.com memdisk/memdisk mbr.bin + dos/syslinux.com copybs.com memdisk/memdisk mbr/mbr.bin INSTALL_AUX_OPT = win32/syslinux.exe # The DATE is set on the make command line when building binaries for @@ -102,9 +112,10 @@ MAKE += DATE=$(DATE) HEXDATE=$(HEXDATE) # error every time you try to build. # -all: all-local - set -e ; for i in $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done +all: + set -e ; for i in $(BESUBDIRS) $(IESUBDIRS) ; do $(MAKE) -C $$i $@ ; done $(MAKE) all-local + set -e ; for i in $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done -ls -l $(BOBJECTS) $(IOBJECTS) all-local: $(BTARGET) $(ITARGET) $(BINFILES) @@ -167,10 +178,7 @@ extlinux.bss: extlinux.bin extlinux.sys: extlinux.bin dd if=$< of=$@ bs=512 skip=1 -mbr.bin: mbr.asm - $(NASM) -f bin -l mbr.lst -o mbr.bin mbr.asm - -mbr_bin.c: mbr.bin bin2c.pl +mbr_bin.c: mbr/mbr.bin bin2c.pl $(PERL) bin2c.pl syslinux_mbr < $< > $@ copybs.com: copybs.asm @@ -199,8 +207,8 @@ $(LIB_SO): bootsect_bin.o ldlinux_bin.o syslxmod.o gethostip: gethostip.o $(CC) $(LDFLAGS) -o $@ $^ -mkdiskimage: mkdiskimage.in mbr.bin bin2hex.pl - $(PERL) bin2hex.pl < mbr.bin | cat mkdiskimage.in - > $@ +mkdiskimage: mkdiskimage.in mbr/mbr.bin bin2hex.pl + $(PERL) bin2hex.pl < mbr/mbr.bin | cat mkdiskimage.in - > $@ chmod a+x $@ install: installer diff --git a/Makefile.private b/Makefile.private index 63a3bbdf..8573aa44 100644 --- a/Makefile.private +++ b/Makefile.private @@ -35,8 +35,8 @@ burn: isolinux.iso cdrecord -v blank=fast isolinux.iso official: - $(MAKE) spotless CC='$(CC) -m32' - $(MAKE) depend CC='$(CC) -m32' + $(MAKE) spotless CC='$(CC) -m32' + $(MAKE) depend CC='$(CC) -m32' $(MAKE) all CC='$(CC) -m32' $(MAKE) dist CC='$(CC) -m32' @@ -8,6 +8,17 @@ Changes in 3.40: * It is now supported to load a different configuration file with the CONFIG keyword. +Changes in 3.36: + * MEMDISK: Disable EDD by default on floppy disks. EDD can be + enabled with the "edd" option and disabled with "noedd". + This (hopefully) should make Ghost work again. + * SYSLINUX: "unix" installer now uses Linux ioctls instead of + using libfat. + * New MBR which can boot from logical partitions. + * SYSLINUX: Fix bug in detecting special extensions which was + introduced in 3.35 :( + * PXELINUX: Unbreak chainbooting FreeBSD (and possibly others.) + Changes in 3.35: * MEMDISK: New "safeint" mode. * MEMDISK: Be more compliant with the PnP BIOS spec. diff --git a/README.menu b/README.menu index 6f0fd83c..fe4f9091 100644 --- a/README.menu +++ b/README.menu @@ -186,13 +186,13 @@ MENU COLOR element ansi foreground background shadow represents fully transparent, and #ffffffff represents opaque white. - + "shadow" controls the handling of the graphical console text shadow. Permitted values are "none" (no shadowing), "std" or "standard" (standard shadowing - foreground pixels are raised), "all" (both background and foreground raised), and "rev" or "reverse" (background pixels are raised.) - + If any field is set to "*" or omitted (at the end of the line) then that field is left unchanged. @@ -31,4 +31,3 @@ - COM32-based CLI. - Rewrite the filesystems to run in protected mode C code. - @@ -62,4 +62,4 @@ error_or_command: mov cx,[OnerrorLen] and cx,cx jnz on_error - jmp enter_command
\ No newline at end of file + jmp enter_command diff --git a/bootsect.inc b/bootsect.inc index 16c5f5e9..7c288daf 100644 --- a/bootsect.inc +++ b/bootsect.inc @@ -136,6 +136,11 @@ replace_bootstrap: mov [es:di+12],esi ; New ESI mov [es:di+6],bx ; New DS +%if IS_PXELINUX == 0 + ; DON'T DO THIS FOR PXELINUX... + ; For PXE, ES:BX -> PXENV+, and this would corrupt + ; that use. + ; Hunt for $PnP header if one exists mov ax,0F000h mov fs,ax @@ -163,6 +168,7 @@ replace_bootstrap: ; Found a valid $PnP header, point ES:DI to it mov [es:di+8], bx ; New DI mov [es:di+4], fs ; New ES +%endif .donepnp: pop ax ; Copy list count @@ -1,6 +1,6 @@ ; -*- fundamental -*- --------------------------------------------------- ; -; Copyright 2004 H. Peter Anvin - All Rights Reserved +; Copyright 2004-2007 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 @@ -11,17 +11,33 @@ ; ----------------------------------------------------------------------- section .text + + struc cptr +.sector: resd 1 ; Sector number +.prev: resw 1 ; LRU pointer to previous (less recent) +.next: resw 1 ; LRU pointer to next (more recent) + endstruc +cptr_size_lg2 equ 3 + +NCacheEntries equ 65536/SECTOR_SIZE + ; ; initcache: Initialize the cache data structures ; initcache: xor eax,eax ; We don't care about sector 0 mov di,CachePtrs - mov cx,65536/SECTOR_SIZE - rep stosd + mov cx,NCacheEntries+1 + mov bx,CachePtrs+NCacheEntries*cptr_size ; "prev" pointer +.loop: + mov [di+cptr.sector],eax ; Zero sector number + mov [di+cptr.prev],bx ; Previous pointer + mov [bx+cptr.next],di ; Previous entry's next pointer + mov bx,di + add di,cptr_size + loop .loop ret - ; ; getcachesector: Check for a particular sector (EAX) in the sector cache, ; and if it is already there, return a pointer in GS:SI @@ -31,32 +47,29 @@ initcache: ; getcachesector: push cx + push bx + push di mov si,cache_seg mov gs,si - mov si,CachePtrs ; Sector cache pointers - mov cx,65536/SECTOR_SIZE + mov si,CachePtrs+cptr_size ; Real sector cache pointers + mov cx,NCacheEntries .search: cmp eax,[si] jz .hit - add si,4 + add si,cptr_size loop .search .miss: TRACER 'M' - ; Need to load it. Highly inefficient cache replacement - ; algorithm: Least Recently Written (LRW) - push bx + ; Need to load it. push es push gs pop es - mov bx,[NextCacheSlot] - inc bx - and bx,(1 << (16-SECTOR_SHIFT))-1 - mov [NextCacheSlot],bx - shl bx,2 - mov [CachePtrs+bx],eax - shl bx,SECTOR_SHIFT-2 + mov bx,[CachePtrs+cptr.next] ; "Next most recent than head node" + mov [bx+cptr.sector],eax mov si,bx + sub bx,CachePtrs+cptr_size + shl bx,SECTOR_SHIFT-cptr_size_lg2 ; Buffer address pushad %if IS_EXTLINUX call getonesec_ext @@ -65,18 +78,38 @@ getcachesector: %endif popad pop es - pop bx - pop cx - ret - -.hit: ; We have it; get the pointer +.hit: + ; Update LRU, then compute buffer address TRACER 'H' - sub si,CachePtrs - shl si,SECTOR_SHIFT-2 + + ; Remove from current position in the list + mov bx,[si+cptr.prev] + mov di,[si+cptr.next] + mov [bx+cptr.next],di + mov [di+cptr.prev],bx + + ; Add to just before head node + mov bx,[CachePtrs+cptr.prev] + mov [si+cptr.prev],bx + mov [bx+cptr.next],si + mov [CachePtrs+cptr.prev],si + mov word [si+cptr.next],CachePtrs + + sub si,CachePtrs+cptr_size + shl si,SECTOR_SHIFT-cptr_size_lg2 ; Buffer address + + pop di + pop bx pop cx ret section .latebss + + ; Each CachePtr contains: + ; - Block pointer + ; - LRU previous pointer + ; - LRU next pointer + ; The first entry is the head node of the list alignb 4 -CachePtrs resd 65536/SECTOR_SIZE ; Cached sector pointers -NextCacheSlot resw 1 ; Next cache slot to occupy +CachePtrs resb (NCacheEntries+1)*cptr_size + diff --git a/com32/lib/MCONFIG b/com32/lib/MCONFIG index 39b62db1..461ada44 100644 --- a/com32/lib/MCONFIG +++ b/com32/lib/MCONFIG @@ -1,5 +1,10 @@ # -*- makefile -*- +gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ + then echo $(1); else echo $(2); fi) + +GCCOPT := $(call gcc_ok,-m32,) $(call gcc_ok,-fno-stack-protector,) + CC = gcc LD = ld INCLUDE = -I. @@ -21,7 +26,7 @@ LIBFLAGS = -DDYNAMIC_CRC_TABLE -DPNG_NO_CONSOLE_IO \ # fallback anyway, just use that on old machines... # LIBFLAGS += -DPNG_NO_FLOATING_POINT_SUPPORTED -REQFLAGS = -g -m32 -mregparm=3 -DREGPARM=3 -D__COM32__ -I. -I./sys -I../include +REQFLAGS = $(GCCOPT) -g -mregparm=3 -DREGPARM=3 -D__COM32__ -I. -I./sys -I../include OPTFLAGS = -Os -march=i386 -falign-functions=0 -falign-jumps=0 \ -falign-labels=0 -ffast-math -fomit-frame-pointer WARNFLAGS = -W -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline diff --git a/com32/lib/sys/fileread.c b/com32/lib/sys/fileread.c index e184fc35..8fdd9167 100644 --- a/com32/lib/sys/fileread.c +++ b/com32/lib/sys/fileread.c @@ -46,7 +46,7 @@ ssize_t __file_read(struct file_info *fp, void *buf, size_t count) memset(&ireg, 0, sizeof ireg); ireg.eax.w[0] = 0x0007; /* Read file */ - ireg.esi.w[0] = OFFS(__com32.cs_bounce); + ireg.ebx.w[0] = OFFS(__com32.cs_bounce); ireg.es = SEG(__com32.cs_bounce); while ( count ) { @@ -64,7 +64,7 @@ ssize_t __file_read(struct file_info *fp, void *buf, size_t count) return -1; } - fp->i.filedes = ireg.esi.w[0]; + fp->i.filedes = oreg.esi.w[0]; fp->i.nbytes = min(fp->i.length-fp->i.offset, (unsigned)MAXBLOCK); fp->i.datap = fp->i.buf; memcpy(fp->i.buf, __com32.cs_bounce, fp->i.nbytes); diff --git a/com32/libutil/Makefile b/com32/libutil/Makefile index 9adeec66..3656fb3f 100644 --- a/com32/libutil/Makefile +++ b/com32/libutil/Makefile @@ -32,7 +32,7 @@ gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ then echo $(1); else echo $(2); fi) -M32 := $(call gcc_ok,-m32,) +M32 := $(call gcc_ok,-m32,) $(call gcc_ok,-fno-stack-protector,) CC = gcc LD = ld -m elf_i386 diff --git a/com32/modules/Makefile b/com32/modules/Makefile index 3c272f26..877ce399 100644 --- a/com32/modules/Makefile +++ b/com32/modules/Makefile @@ -17,7 +17,7 @@ gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ then echo $(1); else echo $(2); fi) -M32 := $(call gcc_ok,-m32,) +M32 := $(call gcc_ok,-m32,) $(call gcc_ok,-fno-stack-protector,) CC = gcc LD = ld -m elf_i386 diff --git a/com32/samples/Makefile b/com32/samples/Makefile index 213ae1a3..291413a6 100644 --- a/com32/samples/Makefile +++ b/com32/samples/Makefile @@ -17,7 +17,7 @@ gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ then echo $(1); else echo $(2); fi) -M32 := $(call gcc_ok,-m32,) +M32 := $(call gcc_ok,-m32,) $(call gcc_ok,-fno-stack-protector,) CC = gcc LD = ld -m elf_i386 diff --git a/comboot.doc b/comboot.doc index 00743835..0d7af174 100644 --- a/comboot.doc +++ b/comboot.doc @@ -699,7 +699,7 @@ AX=0017h [3.30] Report video mode change which are undefined in the current version of SYSLINUX. The following bits in BX are currently defined: - + Bit 0: graphics mode Indicates that the mode is a graphics mode, as opposed diff --git a/comboot.inc b/comboot.inc index fac5753e..304accaa 100644 --- a/comboot.inc +++ b/comboot.inc @@ -776,7 +776,7 @@ comapi_userfont: .done: ; CF=0 here mov P_AL,al ret - + ; ; INT 22h AX=0019h Read disk ; diff --git a/dos/Makefile b/dos/Makefile index 61423cec..5fd52d1b 100644 --- a/dos/Makefile +++ b/dos/Makefile @@ -1,9 +1,14 @@ +gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ + then echo $(1); else echo $(2); fi) + +M32 := $(call gcc_ok,-m32,) $(call gcc_ok,-ffreestanding,) $(call gcc_ok,-fno-stack-protector,) + CC = gcc LD = ld -m elf_i386 OBJCOPY = objcopy OPTFLAGS = -g -Os -march=i386 -falign-functions=0 -falign-jumps=0 -falign-loops=0 -fomit-frame-pointer INCLUDES = -include code16.h -I. -I.. -I../libfat -CFLAGS = -m32 -mregparm=3 -DREGPARM=3 -W -Wall -ffreestanding -msoft-float $(OPTFLAGS) $(INCLUDES) +CFLAGS = $(M32) -mregparm=3 -DREGPARM=3 -W -Wall -msoft-float $(OPTFLAGS) $(INCLUDES) LDFLAGS = -T com16.ld AR = ar RANLIB = ranlib diff --git a/dummy.c b/dummy.c new file mode 100644 index 00000000..81f2586c --- /dev/null +++ b/dummy.c @@ -0,0 +1,8 @@ +/* + * Trivial C program to test the compiler + */ + +int main(int argc, char *argv[]) +{ + return 0; +} diff --git a/extlinux.asm b/extlinux.asm index ddc0cc6b..e4628478 100644 --- a/extlinux.asm +++ b/extlinux.asm @@ -5,7 +5,7 @@ ; ; A program to boot Linux kernels off an ext2/ext3 filesystem. ; -; Copyright (C) 1994-2006 H. Peter Anvin +; Copyright (C) 1994-2007 H. Peter Anvin ; ; 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 @@ -112,7 +112,7 @@ trackbuf resb trackbufsize ; Track buffer goes here getcbuf resb trackbufsize ; ends at 4800h - section .latebss + section .bss SuperBlock resb 1024 ; ext2 superblock SuperInfo resq 16 ; DOS superblock expanded ClustSize resd 1 ; Bytes/cluster ("block") @@ -1024,7 +1024,7 @@ open_inode: pop di ret - section .latebss + section .bss alignb 4 ThisInode resb EXT2_GOOD_OLD_INODE_SIZE ; The most recently opened inode diff --git a/extlinux/Makefile b/extlinux/Makefile index a450a3dc..8d347a98 100644 --- a/extlinux/Makefile +++ b/extlinux/Makefile @@ -1,8 +1,14 @@ +gcc_ok = $(shell if gcc $(1) ../dummy.c -o /dev/null 2>/dev/null; \ + then echo '$(1)'; else echo '$(2)'; fi) + +comma := , +LDHASH := $(call gcc_ok,-Wl$(comma)--hash-style=both,) + CC = gcc OPTFLAGS = -g -Os INCLUDES = -I. -I.. -I../libfat CFLAGS = -W -Wall -Wno-sign-compare -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES) -LDFLAGS = -s +LDFLAGS = $(LDHASH) -s SRCS = extlinux.c ../extlinux_bss_bin.c ../extlinux_sys_bin.c OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) @@ -75,7 +75,7 @@ use_font: test byte [UsingVGA], 01h ; Are we in graphics mode? jz .text - + .graphics: xor cx,cx mov cl,bh ; CX = bytes/character @@ -1,6 +1,6 @@ ; -*- fundamental -*- (asm-mode sucks) ; ----------------------------------------------------------------------- -; +; ; Copyright 2006 H. Peter Anvin - All Rights Reserved ; ; This program is free software; you can redistribute it and/or modify @@ -1,6 +1,6 @@ ; ----------------------------------------------------------------------- ; -; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved +; Copyright 1994-2007 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 @@ -26,7 +26,7 @@ TEXT_START equ 7C00h ; The secondary BSS section, above the text; we really wish we could ; just make it follow .bcopy32 or hang off the end, ; but it doesn't seem to work that way. -LATEBSS_START equ 0B400h +LATEBSS_START equ 0B200h ; Reserve memory for the stack. This causes checkov to abort the ; compile if we violate this space. diff --git a/ldlinux.asm b/ldlinux.asm index d1c0c65a..69259247 100644 --- a/ldlinux.asm +++ b/ldlinux.asm @@ -123,7 +123,6 @@ RootDir resd 1 ; Location of root directory proper DataArea resd 1 ; Location of data area RootDirSize resd 1 ; Root dir size in sectors TotalSectors resd 1 ; Total number of sectors -EndSector resd 1 ; Location of filesystem end ClustSize resd 1 ; Bytes/cluster ClustMask resd 1 ; Sectors/cluster - 1 CopySuper resb 1 ; Distinguish .bs versus .bss @@ -795,9 +794,6 @@ genfatinfo: .have_secs: mov [TotalSectors],edx - add edx,eax - mov [EndSector],edx - mov eax,[bxResSectors] mov [FAT],eax ; Beginning of FAT mov edx,[bxFATsecs] @@ -835,7 +831,7 @@ genfatinfo: ; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous. ; getfattype: - mov eax,[EndSector] + mov eax,[TotalSectors] sub eax,[DataArea] shr eax,cl ; cl == ClustShift mov cl,nextcluster_fat12-(nextcluster+2) @@ -1605,11 +1601,11 @@ initrd_cmd_len equ 7 ; ; Extensions to search for (in *forward* order). ; -exten_table: db 'CBT',0 ; COMBOOT (specific) - db 'BSS',0 ; Boot Sector (add superblock) - db 'BS ',0 ; Boot Sector - db 'COM',0 ; COMBOOT (same as DOS) - db 'C32',0 ; COM32 +exten_table: db '.cbt' ; COMBOOT (specific) + db '.bss' ; Boot Sector (add superblock) + db '.bs', 0 ; Boot Sector + db '.com' ; COMBOOT (same as DOS) + db '.c32' ; COM32 exten_table_end: dd 0, 0 ; Need 8 null bytes here diff --git a/loadhigh.inc b/loadhigh.inc index 7d9f57a4..283778f6 100644 --- a/loadhigh.inc +++ b/loadhigh.inc @@ -88,7 +88,7 @@ load_high: sub eax,ecx pop bx ; <AA> Pausebird function jnz .read_loop ; More to read... - + .eof: pop es ; <AAA> ES diff --git a/mbr/Makefile b/mbr/Makefile new file mode 100644 index 00000000..d61f7f1c --- /dev/null +++ b/mbr/Makefile @@ -0,0 +1,47 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2007 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., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +# +# Makefile for MBR +# + +gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ + then echo $(1); else echo $(2); fi) + +M32 := $(call gcc_ok,-m32,) $(call gcc_ok,-ffreestanding,) $(call gcc_ok,-fno-stack-protector) + +CC = gcc +LD = ld -m elf_i386 +SFLAGS = $(M32) -march=i386 +OBJCOPY = objcopy +PERL = perl + +.SUFFIXES: .S .s .o .elf + +all: mbr.bin + +.PRECIOUS: %.o +%.o: %.S + $(CC) $(SFLAGS) -Wa,-a=$*.lst -c -o $@ $< + +mbr.elf: mbr.o mbr.ld + $(LD) -T mbr.ld -e _start -o $@ $< + +mbr.bin: mbr.elf checksize.pl + $(OBJCOPY) -O binary $< $@ + $(PERL) checksize.pl mbr.bin 440 + +tidy: + rm -f *.o *.elf *.lst + +clean: tidy + rm -f *.bin diff --git a/mbr/checksize.pl b/mbr/checksize.pl new file mode 100755 index 00000000..b7d560a0 --- /dev/null +++ b/mbr/checksize.pl @@ -0,0 +1,31 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2007 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., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## checksize.pl +## +## Check the size of a binary file +## + +($file, $maxsize) = @ARGV; + +@st = stat($file); +if (!defined($size = $st[7])) { + die "$0: $file: $!\n"; +} +if ($size > $maxsize) { + print STDERR "$file: too big ($size > $maxsize)\n"; + exit 1; +} else { + exit 0; +} + diff --git a/mbr/mbr.S b/mbr/mbr.S new file mode 100644 index 00000000..81e5dd00 --- /dev/null +++ b/mbr/mbr.S @@ -0,0 +1,299 @@ +/* ----------------------------------------------------------------------- + * + * Copyright 2007 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + + .code16 + .text + + .globl bootsec +stack = 0x7c00 +driveno = (stack-6) +heads = (stack-8) +sectors = (stack-10) + +BIOS_page = 0x462 + + /* gas/ld has issues with doing this as absolute addresses... */ + .section ".bootsec", "a", @nobits + .globl bootsec +bootsec: + .space 512 + + .text + .globl _start +_start: + cli + xorw %ax, %ax + movw %ax, %ds + movw %ax, %ss + movw $stack, %sp + movw %sp, %si + pushw %es /* es:di -> $PnP header */ + pushw %di + pushw %dx /* dl -> drive number */ + movw %ax, %es + sti + cld + + /* Copy down to 0:0x600 */ + movw $_start, %di + movw $(512/2), %cx + rep; movsw + + ljmpw $0, $next + +next: + /* Check to see if we have EBIOS */ + pushw %dx /* drive number */ + movw $0x4100, %ax + movw $0x55aa, %bx + xorw %cx, %cx + xorb %dh, %dh + stc + int $0x13 + jc 1f + cmpw $0xaa55, %bx + jne 1f + testb $0x01, %cl + jz 1f + + /* We have EBIOS; patch in a jump to read_sector_ebios */ + movw $0xeb+((read_sector_ebios-read_sector_cbios-2)<< 8), (read_sector_cbios) + +1: + popw %dx + + /* Get (C)HS geometry */ + movb $0x08, %ah + int $0x13 + xorw %ax, %ax + movb %dh, %al /* dh = number of heads */ + incw %ax /* From 0-based to count */ + pushw %ax /* Save heads on the stack */ + andw $0x3f, %cx /* Sector count */ + pushw %cx /* Save sectors on the stack */ + + xorl %eax, %eax + pushl %eax /* Base */ + pushl %eax /* Root */ + call scan_partition_table + + /* If we get here, we have no OS */ + jmp missing_os + +/* + * read_sector: read a single sector pointed to by %eax to 0x7c00. + * CF is set on error. All registers clobbered. + */ +read_sector: +read_sector_cbios: + movl %eax, %edx + shrl $16, %edx + divw (sectors) + incw %dx + movw %dx, %cx + xorw %dx, %dx + divw (heads) + /* dx = head, ax = cylinder */ + movb %al, %ch + shrw $2, %ax + shrw %ax + andb $0xc0, %al + orb %al, %cl + movb %dl, %dh + movw $bootsec, %bx + movw $0x0201, %ax + jmp read_common +read_sector_ebios: + movw $dapa, %si + movl %eax, 8(%si) + movb $0x42, %ah +read_common: + movb (driveno), %dl + int $0x13 + ret + +/* + * read_partition_table: + * Read a partition table (pointed to by %eax), and copy + * the partition table into the ptab buffer. + * Preserve registers. + */ +ptab = _start+446 + +read_partition_table: + pushal + call read_sector + jc 20f + movw $bootsec+446, %si + movw $ptab, %di + movw $(16*4/2), %cx + rep ; movsw +20: + popal + ret + +/* + * scan_partition_table: + * Scan a partition table currently loaded in the partition table + * area. Preserve 16-bit registers. + * + * On stack: + * 18(%bp) - root (offset from MBR, or 0 for MBR) + * 22(%bp) - base (location of this partition table) + */ + +scan_partition_table: + pusha + movw %sp, %bp + + /* Search for active partitions */ + movw $ptab, %di + movw $4, %cx + xorw %ax, %ax +5: + testb $0x80, (%di) + jz 6f + incw %ax + movw %di, %si +6: + addw $16, %di + loopw 5b + + cmpw $1, %ax /* Number of active partitions found */ + je boot + ja too_many_active + + /* No active partitions found, look for extended partitions */ + movw $ptab, %di + movb $4, %cl /* cx == 0 here */ +7: + movb 4(%di), %al + cmpb $0x05, %al /* MS-DOS extended */ + je 8f + cmpb $0x0f, %al /* Win9x extended */ + je 8f + cmpb $0x85, %al /* Linux extended */ + jne 9f + + /* It is an extended partition. Read the extended partition and + try to scan it. If the scan returns, re-load the current + partition table and resume scan. */ +8: + movl 8(%di), %eax /* Partition table offset */ + movl 18(%bp), %edx /* "Root" */ + addl %edx, %eax /* Compute location of new ptab */ + andl %edx, %edx /* Is this the MBR? */ + jnz 10f + movl %eax, %edx /* Offset -> root if this was MBR */ +10: + pushl %eax /* Push new base */ + pushl %edx /* Push new root */ + call read_partition_table + jc 11f + call scan_partition_table +11: + addw $8, %sp + /* This returned, so we need to reload the current partition table */ + movl 22(%bp), %eax + call read_partition_table + + /* fall through */ +9: + /* Not an extended partition */ + addw $16, %di + loopw 7b + + /* Nothing found, return */ + popa + ret + +/* + * boot: invoke the actual bootstrap. (%si) points to the partition + * table entry, and 22(%bp) has the partition table base. + */ +boot: + movl 8(%si), %eax + addl 22(%bp), %eax + movl %eax, 8(%si) + pushw %si + call read_sector + popw %si + jc disk_error + cmpw $0xaa55, (bootsec+510) + jne missing_os /* Not a valid boot sector */ + movw $driveno, %sp + popw %dx /* dl -> drive number */ + popw %di /* es:di -> $PnP vector */ + popw %es + cli + jmp bootsec + +/* + * error messages + */ +missing_os: + movw $missing_os_msg, %si + jmp error +disk_error: + movw $disk_error_msg, %si + jmp error +too_many_active: + movw $too_many_active_msg, %si + /* jmp error */ + +error: +2: + lodsb + andb %al, %al + jz 3f + movb $0x0e, %ah + movb (BIOS_page), %bh + movb $0x07, %bl + int $0x10 + jmp 2b +3: + int $0x18 /* Boot failure */ + jmp . /* Die */ + +missing_os_msg: + .ascii "Missing operating system." + .byte 0 +disk_error_msg: + .ascii "Operating system load error." + .byte 0 +too_many_active_msg: + .ascii "Multiple active partitions." + .byte 0 + + .balign 4 +dapa: + .short 16 /* Size of packet */ + .short 1 /* Sector count */ + .short 0x7c00 /* Buffer offset */ + .short 0 /* Buffer segment */ + .long 0 /* LSW of LBA */ + .long 0 /* MSW of LBA */ diff --git a/mbr/mbr.ld b/mbr/mbr.ld new file mode 100644 index 00000000..d14ba802 --- /dev/null +++ b/mbr/mbr.ld @@ -0,0 +1,73 @@ +/* + * Linker script for MBR + */ + +/* Script for -z combreloc: combine and sort reloc sections */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +EXTERN(_start) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x600; + .text : + { + *(.text*) + *(.rodata*) + } =0x90909090 + + . = ALIGN(4); + .data : + { + *(.data*) + } + + . = ALIGN(128); + .bss : + { + *(.bss*) + } + + . = 0x7c00; + .bootsec : + { + *(.bootsec) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/mbr.asm b/mbr/oldmbr.asm index 31bf1fdf..31bf1fdf 100644 --- a/mbr.asm +++ b/mbr/oldmbr.asm diff --git a/memdisk/Makefile b/memdisk/Makefile index 1eebe637..72234cab 100644 --- a/memdisk/Makefile +++ b/memdisk/Makefile @@ -17,7 +17,7 @@ gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ M32 := $(call gcc_ok,-m32,) ALIGN := $(call gcc_ok,-falign-functions=0 -falign-jumps=0 -falign-loops=0,-malign-functions=0 -malign-jumps=0 -malign-loops=0) -FREE := $(call gcc_ok,-ffreestanding,) +FREE := $(call gcc_ok,-ffreestanding,) $(call gcc_ok,-fno-stack-protector,) CC = gcc CFLAGS = $(M32) $(FREE) -g -W -Wall -Wno-sign-compare \ diff --git a/memdisk/memdisk.asm b/memdisk/memdisk.asm index 09055d8f..1d3d39de 100644 --- a/memdisk/memdisk.asm +++ b/memdisk/memdisk.asm @@ -6,7 +6,7 @@ ; A program to emulate an INT 13h disk BIOS from a "disk" in extended ; memory. ; -; Copyright (C) 2001-2006 H. Peter Anvin +; Copyright (C) 2001-2007 H. Peter Anvin ; ; 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 @@ -152,8 +152,8 @@ Int13Start: mov bp,sp ; Point BP to the entry stack frame TRACER 'F' ; Note: AH == P_AH here - cmp ah,Int13FuncsMax - jae Invalid_jump + cmp ah,[Int13MaxFunc] + ja Invalid_jump xor al,al ; AL = 0 is standard entry condition mov di,ax shr di,7 ; Convert AH to an offset in DI @@ -870,7 +870,7 @@ Int13Funcs dw Reset ; 00h - RESET %endif Int13FuncsEnd equ $ -Int13FuncsMax equ (Int13FuncsEnd-Int13Funcs) >> 1 +Int13FuncsCnt equ (Int13FuncsEnd-Int13Funcs) >> 1 %if EDD EDD_DPT: @@ -933,8 +933,9 @@ OldInt15 dd 0 ; INT 15h in chain OldDosMem dw 0 ; Old position of DOS mem end BootLoaderID db 0 ; Boot loader ID from header ; ---- MDI structure ends here --- - db 0, 0, 0 ; pad +Int13MaxFunc db Int13FuncsCnt-1 ; Max INT 13h function (to disable EDD) + db 0, 0 ; pad MemInt1588 dw 0 ; 1MB-65MB memory amount (1K) Cylinders dw 0 ; Cylinder count diff --git a/memdisk/memdisk.doc b/memdisk/memdisk.doc index fdcc259e..759a7b27 100644 --- a/memdisk/memdisk.doc +++ b/memdisk/memdisk.doc @@ -89,6 +89,12 @@ d) MEMDISK normally uses the BIOS "INT 15h mover" API to access high safeint Use INT 15h access to protected memory, but invoke INT 15h the way it was *before* MEMDISK was loaded. +e) MEMDISK by default supports EDD/EBIOS on hard disks, but not on + floppy disks. This can be controlled with the options: + + edd Enable EDD/EBIOS + noedd Disable EDD/EBIOS + Some interesting things to note: @@ -136,7 +142,7 @@ http://www.ctyme.com/rbrown.htm, for a detailed description. The MEMDISK info structure currently contains: - [ES:DI] word Total size of structure (currently 27 bytes) + [ES:DI] word Total size of structure (currently 28 bytes) [ES:DI+2] byte MEMDISK minor version [ES:DI+3] byte MEMDISK major version [ES:DI+4] dword Pointer to MEMDISK data in high memory diff --git a/memdisk/setup.c b/memdisk/setup.c index 8c83f039..d1eabc58 100644 --- a/memdisk/setup.c +++ b/memdisk/setup.c @@ -70,8 +70,10 @@ struct patch_area { uint16_t olddosmem; uint8_t bootloaderid; + uint8_t maxint13func; +#define MAXINT13_NOEDD 0x16 - uint8_t _pad[3]; + uint8_t _pad[2]; uint16_t memint1588; uint16_t cylinders; @@ -552,6 +554,7 @@ void setup(syscall_t cs_syscall, void *cs_bounce) com32sys_t regs; uint32_t ramdisk_image, ramdisk_size; int bios_drives; + int do_edd = -1; /* -1 = default, 0 = no, 1 = yes */ /* Set up global variables */ syscall = cs_syscall; @@ -579,11 +582,22 @@ void setup(syscall_t cs_syscall, void *cs_bounce) geometry = get_disk_image_geometry(ramdisk_image, ramdisk_size); - printf("Disk is %s %d, %u K, C/H/S = %u/%u/%u\n", + if (getcmditem("edd") != CMD_NOTFOUND || + getcmditem("ebios") != CMD_NOTFOUND) + do_edd = 1; + else if (getcmditem("noedd") != CMD_NOTFOUND || + getcmditem("noebios") != CMD_NOTFOUND || + getcmditem("cbios") != CMD_NOTFOUND) + do_edd = 0; + else + do_edd = (geometry->driveno & 0x80) ? 1 : 0; + + printf("Disk is %s %d, %u K, C/H/S = %u/%u/%u, EDD %s\n", (geometry->driveno & 0x80) ? "hard disk" : "floppy", geometry->driveno & 0x7f, geometry->sectors >> 1, - geometry->c, geometry->h, geometry->s); + geometry->c, geometry->h, geometry->s, + do_edd ? "on" : "off"); /* Reserve the ramdisk memory */ insertrange(ramdisk_image, ramdisk_size, 2); @@ -633,6 +647,10 @@ void setup(syscall_t cs_syscall, void *cs_bounce) pptr->configflags |= CONFIG_BIGRAW|CONFIG_RAW; } + /* pptr->maxint13func defaults to EDD enabled, if compiled in */ + if (!do_edd) + pptr->maxint13func = MAXINT13_NOEDD; + /* Set up a drive parameter table */ if ( geometry->driveno & 0x80 ) { /* Hard disk */ diff --git a/menu/Makefile b/menu/Makefile index 91a8697e..cee1c3af 100644 --- a/menu/Makefile +++ b/menu/Makefile @@ -17,7 +17,7 @@ gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ then echo $(1); else echo $(2); fi) -M32 := $(call gcc_ok,-m32,) +M32 := $(call gcc_ok,-m32,) $(call gcc_ok,-fno-stack-protector,) CC = gcc LD = ld -m elf_i386 diff --git a/mtools/Makefile b/mtools/Makefile index 26909a30..546e3d14 100644 --- a/mtools/Makefile +++ b/mtools/Makefile @@ -1,8 +1,14 @@ +gcc_ok = $(shell if gcc $(1) ../dummy.c -o /dev/null 2>/dev/null; \ + then echo '$(1)'; else echo '$(2)'; fi) + +comma := , +LDHASH := $(call gcc_ok,-Wl$(comma)--hash-style=both,) + CC = gcc OPTFLAGS = -g -Os INCLUDES = -I. -I.. -I../libfat CFLAGS = -W -Wall -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES) -LDFLAGS = -s +LDFLAGS = $(LDHASH) -s SRCS = syslinux.c ../syslxmod.c ../bootsect_bin.c ../ldlinux_bin.c $(wildcard ../libfat/*.c) OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) diff --git a/mtools/syslinux.c b/mtools/syslinux.c index 29259dff..e65b081f 100644 --- a/mtools/syslinux.c +++ b/mtools/syslinux.c @@ -210,7 +210,7 @@ int main(int argc, char *argv[]) exit(1); } fprintf(mtc, - "MTOOLS_NO_VFAT=1\n" + /* "MTOOLS_NO_VFAT=1\n" */ "MTOOLS_SKIP_CHECK=1\n" /* Needed for some flash memories */ "drive s:\n" " file=\"/proc/%lu/fd/%d\"\n" diff --git a/sample/Makefile b/sample/Makefile index e24ab5be..bacc57ca 100644 --- a/sample/Makefile +++ b/sample/Makefile @@ -17,7 +17,7 @@ gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ then echo $(1); else echo $(2); fi) -M32 := $(call gcc_ok,-m32,) $(call gcc_ok,-ffreestanding,) +M32 := $(call gcc_ok,-m32,) $(call gcc_ok,-ffreestanding,) $(call gcc_ok,-fno-stack-protector,) CC = gcc LD = ld -m elf_i386 @@ -324,10 +324,6 @@ vk_check: ; Find the kernel on disk ; get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/extension -%if IS_SYSLINUX || IS_MDSLINUX ; SYSLINUX has to deal with DOS mangled names... - mov eax,[KernelName+8] ; Save initial extension - mov [exten_table_end],eax ; Last case == initial ext. -%else mov di,KernelName+4*IS_PXELINUX xor al,al mov cx,FILENAME_MAX-5 ; Need 4 chars + null @@ -335,7 +331,6 @@ get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/e jne .no_skip dec di ; Point to final null .no_skip: mov [KernelExtPtr],di -%endif mov bx,exten_table .search_loop: push bx mov di,KernelName ; Search on disk @@ -343,13 +338,9 @@ get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/e pop bx jnz kernel_good mov eax,[bx] ; Try a different extension -%if IS_SYSLINUX || IS_MDSLINUX - mov [KernelName+8],eax -%else mov si,[KernelExtPtr] mov [si],eax mov byte [si+4],0 -%endif add bx,byte 4 cmp bx,exten_table_end jna .search_loop ; allow == case (final case) @@ -493,10 +484,6 @@ kernel_good: mov [KernelCNameLen],di popa -%if IS_SYSLINUX || IS_MDSLINUX - mov ecx,[KernelName+7] - mov cl,'.' -%else push di push ax mov di,KernelName+4*IS_PXELINUX @@ -508,7 +495,6 @@ kernel_good: .one_step: mov ecx,[di-4] ; 4 bytes before end pop ax pop di -%endif ; ; At this point, DX:AX contains the size of the kernel, SI contains @@ -535,19 +521,13 @@ is_unknown_filetype: je is_bss_sector cmp ecx,'.bin' je is_bootsector -%if IS_SYSLINUX || IS_MDSLINUX - cmp ecx,'.bs ' - je is_bootsector - cmp ecx,'.0 ' - je is_bootsector -%else shr ecx,8 cmp ecx,'.bs' je is_bootsector shr ecx,8 cmp cx,'.0' je is_bootsector -%endif + ; Otherwise Linux kernel jmp is_linux_kernel diff --git a/unix/Makefile b/unix/Makefile index 5dfc0513..f0ab279a 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -1,10 +1,16 @@ +gcc_ok = $(shell if gcc $(1) ../dummy.c -o /dev/null 2>/dev/null; \ + then echo '$(1)'; else echo '$(2)'; fi) + +comma := , +LDHASH := $(call gcc_ok,-Wl$(comma)--hash-style=both,) + CC = gcc OPTFLAGS = -g -Os -INCLUDES = -I. -I.. -I../libfat +INCLUDES = -I. -I.. CFLAGS = -W -Wall -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES) -LDFLAGS = -s +LDFLAGS = $(LDHASH) -s -SRCS = syslinux.c ../syslxmod.c ../bootsect_bin.c ../ldlinux_bin.c $(wildcard ../libfat/*.c) +SRCS = syslinux.c ../syslxmod.c ../bootsect_bin.c ../ldlinux_bin.c OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) .SUFFIXES: .c .o .i .s .S diff --git a/unix/syslinux.c b/unix/syslinux.c index 36826a1b..4270d728 100644 --- a/unix/syslinux.c +++ b/unix/syslinux.c @@ -13,7 +13,7 @@ /* * syslinux.c - Linux installer program for SYSLINUX * - * This program ought to be portable. I hope so, at least. + * This is Linux-specific by now. * * This is an alternate version of the installer which doesn't require * mtools, but requires root privilege. @@ -46,23 +46,28 @@ #include <sys/wait.h> #include <sys/mount.h> +#include <sys/ioctl.h> +#include <linux/fs.h> /* FIGETBSZ, FIBMAP */ +#include <linux/msdos_fs.h> /* FAT_IOCTL_SET_ATTRIBUTES, SECTOR_* */ +#ifndef FAT_IOCTL_SET_ATTRIBUTES +# define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, uint32_t) +#endif + +#include <paths.h> +#ifndef _PATH_MOUNT +# define _PATH_MOUNT "/bin/mount" +#endif +#ifndef _PATH_UMOUNT +# define _PATH_UMOUNT "/bin/umount" +#endif +#ifndef _PATH_TMP +# define _PATH_TMP "/tmp/" +#endif + #include "syslinux.h" -#include "libfat.h" #if DO_DIRECT_MOUNT - # include <linux/loop.h> - -#else - -# include <paths.h> -# ifndef _PATH_MOUNT -# define _PATH_MOUNT "/bin/mount" -# endif -# ifndef _PATH_UMOUNT -# define _PATH_UMOUNT "/bin/umount" -# endif - #endif const char *program; /* Name of program */ @@ -156,35 +161,175 @@ ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset) } /* - * Version of the read function suitable for libfat + * Create a block map for ldlinux.sys + */ +int make_block_map(uint32_t *sectors, int len, int dev_fd, int fd) +{ + int nsectors = 0; + int blocksize, nblock, block; + int i; + + (void)dev_fd; + + if (ioctl(fd, FIGETBSZ, &blocksize) < 0) + die("ioctl FIGETBSZ failed"); + + blocksize >>= SECTOR_BITS; /* sectors/block */ + + nblock = 0; + while (len > 0) { + block = nblock++; + if (ioctl(fd, FIBMAP, &block) < 0) + die("ioctl FIBMAP failed"); + + for (i = 0; i < blocksize; i++) { + if (len <= 0) + break; + + *sectors++ = (block*blocksize)+i; + nsectors++; + len -= (1 << SECTOR_BITS); + } + } + + return nsectors; +} + +/* + * Mount routine + */ +int do_mount(int dev_fd, int *cookie, const char *mntpath, const char *fstype) +{ + struct stat st; + + (void)cookie; + + if (fstat(dev_fd, &st) < 0) + return errno; + +#if DO_DIRECT_MOUNT + { + if ( !S_ISBLK(st.st_mode) ) { + /* It's file, need to mount it loopback */ + unsigned int n = 0; + struct loop_info64 loopinfo; + int loop_fd; + + for ( n = 0 ; loop_fd < 0 ; n++ ) { + snprintf(devfdname, sizeof devfdname, "/dev/loop%u", n); + loop_fd = open(devfdname, O_RDWR); + if ( loop_fd < 0 && errno == ENOENT ) { + die("no available loopback device!"); + } + if ( ioctl(loop_fd, LOOP_SET_FD, (void *)dev_fd) ) { + close(loop_fd); loop_fd = -1; + if ( errno != EBUSY ) + die("cannot set up loopback device"); + else + continue; + } + + if ( ioctl(loop_fd, LOOP_GET_STATUS64, &loopinfo) || + (loopinfo.lo_offset = filesystem_offset, + ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo)) ) + die("cannot set up loopback device"); + } + + *cookie = loop_fd; + } else { + snprintf(devfdname, sizeof devfdname, "/proc/%lu/fd/%d", + (unsigned long)mypid, dev_fd); + *cookie = -1; + } + + return mount(devfdname, mntpath, fstype, + MS_NOEXEC|MS_NOSUID, "umask=077,quiet"); + } +#else + { + char devfdname[128], mnt_opts[128]; + pid_t f, w; + int status; + + snprintf(devfdname, sizeof devfdname, "/proc/%lu/fd/%d", + (unsigned long)mypid, dev_fd); + + f = fork(); + if ( f < 0 ) { + return -1; + } else if ( f == 0 ) { + if ( !S_ISBLK(st.st_mode) ) { + snprintf(mnt_opts, sizeof mnt_opts, + "rw,nodev,noexec,loop,offset=%llu,umask=077,quiet", + (unsigned long long)filesystem_offset); + } else { + snprintf(mnt_opts, sizeof mnt_opts, "rw,nodev,noexec,umask=077,quiet"); + } + execl(_PATH_MOUNT, _PATH_MOUNT, "-t", fstype, "-o", mnt_opts, \ + devfdname, mntpath, NULL); + _exit(255); /* execl failed */ + } + + w = waitpid(f, &status, 0); + return ( w != f || status ) ? -1 : 0; + } +#endif +} + +/* + * umount routine */ -int libfat_xpread(intptr_t pp, void *buf, size_t secsize, libfat_sector_t sector) +void do_umount(const char *mntpath, int cookie) { - off_t offset = (off_t)sector * secsize + filesystem_offset; - return xpread(pp, buf, secsize, offset); +#if DO_DIRECT_MOUNT + int loop_fd = cookie; + + if ( umount2(mntpath, 0) ) + die("could not umount path"); + + if ( loop_fd != -1 ) { + ioctl(loop_fd, LOOP_CLR_FD, 0); /* Free loop device */ + close(loop_fd); + loop_fd = -1; + } + +#else + pid_t f = fork(); + pid_t w; + int status; + (void)cookie; + + if ( f < 0 ) { + perror("fork"); + exit(1); + } else if ( f == 0 ) { + execl(_PATH_UMOUNT, _PATH_UMOUNT, mntpath, NULL); + } + + w = waitpid(f, &status, 0); + if ( w != f || status ) { + exit(1); + } +#endif } int main(int argc, char *argv[]) { - static unsigned char sectbuf[512]; + static unsigned char sectbuf[SECTOR_SIZE]; unsigned char *dp; const unsigned char *cdp; int dev_fd, fd; struct stat st; int nb, left; int err = 0; - pid_t f, w; - int status; - char mntname[64], devfdname[64]; + char mntname[128]; char *ldlinux_name, **argp, *opt; int force = 0; /* -f (force) option */ const char *subdir = NULL; - struct libfat_filesystem *fs; - struct libfat_direntry dentry; - libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */ - int32_t ldlinux_cluster; + uint32_t sectors[65]; /* 65 is maximum possible */ int nsectors = 0; const char *errmsg; + int mnt_cookie; (void)argc; /* Unused */ @@ -209,7 +354,8 @@ int main(int argc, char *argv[]) } else if ( *opt == 'd' && argp[1] ) { subdir = *++argp; } else if ( *opt == 'o' && argp[1] ) { - filesystem_offset = (off_t)strtoull(*++argp, NULL, 0); /* Byte offset */ + /* Byte offset */ + filesystem_offset = (off_t)strtoull(*++argp, NULL, 0); } else { usage(); } @@ -235,15 +381,15 @@ int main(int argc, char *argv[]) exit(1); } - if ( !force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) ) { - die("not a block device or regular file (use -f to override)"); + if ( !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode) ) { + die("not a device or regular file"); } - if ( !force && filesystem_offset && !S_ISREG(st.st_mode) ) { - die("not a regular file and an offset specified (use -f to override)"); + if ( filesystem_offset && S_ISBLK(st.st_mode) ) { + die("can't combine an offset with a block device"); } - xpread(dev_fd, sectbuf, 512, filesystem_offset); + xpread(dev_fd, sectbuf, SECTOR_SIZE, filesystem_offset); fsync(dev_fd); /* @@ -267,7 +413,7 @@ int main(int argc, char *argv[]) /* We're root or at least setuid. Make a temp dir and pass all the gunky options to mount. */ - if ( chdir("/tmp") ) { + if ( chdir(_PATH_TMP) ) { perror(program); exit(1); } @@ -276,7 +422,7 @@ int main(int argc, char *argv[]) if ( stat(".", &dst) || !S_ISDIR(dst.st_mode) || (dst.st_mode & TMP_MODE) != TMP_MODE ) { - die("possibly unsafe /tmp permissions"); + die("possibly unsafe " _PATH_TMP " permissions"); } for ( i = 0 ; ; i++ ) { @@ -303,80 +449,29 @@ int main(int argc, char *argv[]) } mntpath = mntname; + } -#if DO_DIRECT_MOUNT - if ( S_ISREG(st.st_mode) ) { - /* It's file, need to mount it loopback */ - unsigned int n = 0; - struct loop_info64 loopinfo; - - for ( n = 0 ; loop_fd < 0 ; n++ ) { - snprintf(devfdname, sizeof devfdname, "/dev/loop%u", n); - loop_fd = open(devfdname, O_RDWR); - if ( loop_fd < 0 && errno == ENOENT ) { - die("no available loopback device!"); - } - if ( ioctl(loop_fd, LOOP_SET_FD, (void *)dev_fd) ) { - close(loop_fd); loop_fd = -1; - if ( errno != EBUSY ) - die("cannot set up loopback device"); - else - continue; - } - - if ( ioctl(loop_fd, LOOP_GET_STATUS64, &loopinfo) || - (loopinfo.lo_offset = filesystem_offset, - ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo)) ) - die("cannot set up loopback device"); - } - } else { - snprintf(devfdname, sizeof devfdname, "/proc/%lu/fd/%d", - (unsigned long)mypid, dev_fd); - } - - if ( mount(devfdname, mntpath, "msdos", - MS_NOEXEC|MS_NOSUID, "umask=077,quiet") ) - die("could not mount filesystem"); - -#else - - snprintf(devfdname, sizeof devfdname, "/proc/%lu/fd/%d", - (unsigned long)mypid, dev_fd); - - f = fork(); - if ( f < 0 ) { - perror(program); - rmdir(mntpath); - exit(1); - } else if ( f == 0 ) { - char mnt_opts[128]; - if ( S_ISREG(st.st_mode) ) { - snprintf(mnt_opts, sizeof mnt_opts, "rw,nodev,noexec,loop,offset=%llu,umask=077,quiet", - (unsigned long long)filesystem_offset); - } else { - snprintf(mnt_opts, sizeof mnt_opts, "rw,nodev,noexec,umask=077,quiet"); - } - execl(_PATH_MOUNT, _PATH_MOUNT, "-t", "msdos", "-o", mnt_opts,\ - devfdname, mntpath, NULL); - _exit(255); /* execl failed */ - } - - w = waitpid(f, &status, 0); - if ( w != f || status ) { - rmdir(mntpath); - exit(1); /* Mount failed */ - } - -#endif + if (do_mount(dev_fd, &mnt_cookie, mntpath, "vfat") && + do_mount(dev_fd, &mnt_cookie, mntpath, "msdos")) { + rmdir(mntpath); + die("mount failed"); } - ldlinux_name = alloca(strlen(mntpath)+14); + ldlinux_name = alloca(strlen(mntpath)+14+ + (subdir ? strlen(subdir)+2 : 0)); if ( !ldlinux_name ) { perror(program); err = 1; goto umount; } - sprintf(ldlinux_name, "%s//ldlinux.sys", mntpath); + sprintf(ldlinux_name, "%s%s%s//ldlinux.sys", + mntpath, subdir ? "//" : "", subdir ? subdir : ""); + + if ((fd = open(ldlinux_name, O_RDONLY)) >= 0) { + uint32_t zero_attr = 0; + ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &zero_attr); + close(fd); + } unlink(ldlinux_name); fd = open(ldlinux_name, O_WRONLY|O_CREAT|O_TRUNC, 0444); @@ -402,81 +497,25 @@ int main(int argc, char *argv[]) left -= nb; } + fsync(fd); /* - * I don't understand why I need this. Does the DOS filesystems - * not honour the mode passed to open()? + * Set the attributes */ - fchmod(fd, 0400); - - close(fd); - - sync(); + { + uint32_t attr = 0x07; /* Hidden+System+Readonly */ + ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr); + } /* - * Now, use libfat to create a block map. This probably - * should be changed to use ioctl(...,FIBMAP,...) since - * this is supposed to be a simple, privileged version - * of the installer. + * Create a block map. */ - fs = libfat_open(libfat_xpread, dev_fd); - ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", &dentry); - secp = sectors; - nsectors = 0; - s = libfat_clustertosector(fs, ldlinux_cluster); - while ( s && nsectors < 65 ) { - *secp++ = s; - nsectors++; - s = libfat_nextsector(fs, s); - } - libfat_close(fs); - - /* Move ldlinux.sys to the desired location */ - if (subdir) { - char *new_ldlinux_name = alloca(strlen(mntpath)+ - strlen(subdir)+15); - int mov_err = 1; + nsectors = make_block_map(sectors, syslinux_ldlinux_len, dev_fd, fd); - if ( new_ldlinux_name ) { - sprintf(new_ldlinux_name, "%s//%s//ldlinux.sys", mntpath, subdir); - - if (!rename(ldlinux_name, new_ldlinux_name)) - mov_err = 0; - } - - if (mov_err) - fprintf(stderr, "%s: warning: unable to move ldlinux.sys: %s\n", - device, strerror(errno)); - } + close(fd); + sync(); umount: -#if DO_DIRECT_MOUNT - - if ( umount2(mntpath, 0) ) - die("could not umount path"); - - if ( loop_fd != -1 ) { - ioctl(loop_fd, LOOP_CLR_FD, 0); /* Free loop device */ - close(loop_fd); - loop_fd = -1; - } - -#else - - f = fork(); - if ( f < 0 ) { - perror("fork"); - exit(1); - } else if ( f == 0 ) { - execl(_PATH_UMOUNT, _PATH_UMOUNT, mntpath, NULL); - } - - w = waitpid(f, &status, 0); - if ( w != f || status ) { - exit(1); - } - -#endif - + do_umount(mntpath, mnt_cookie); sync(); rmdir(mntpath); @@ -491,29 +530,21 @@ umount: /* * Write the now-patched first sector of ldlinux.sys */ - xpwrite(dev_fd, syslinux_ldlinux, 512, filesystem_offset + ((off_t)sectors[0] << 9)); - - /* - * Patch the root directory to set attributes to - * HIDDEN|SYSTEM|READONLY - */ - { - const unsigned char attrib = 0x07; - xpwrite(dev_fd, &attrib, 1, ((off_t)dentry.sector << 9)+dentry.offset+11); - } + xpwrite(dev_fd, syslinux_ldlinux, SECTOR_SIZE, + filesystem_offset+((off_t)sectors[0] << SECTOR_BITS)); /* * To finish up, write the boot sector */ /* Read the superblock again since it might have changed while mounted */ - xpread(dev_fd, sectbuf, 512, filesystem_offset); + xpread(dev_fd, sectbuf, SECTOR_SIZE, filesystem_offset); /* Copy the syslinux code into the boot sector */ syslinux_make_bootsect(sectbuf); /* Write new boot sector */ - xpwrite(dev_fd, sectbuf, 512, filesystem_offset); + xpwrite(dev_fd, sectbuf, SECTOR_SIZE, filesystem_offset); close(dev_fd); sync(); |