From 0fa4369624b4637a7e36ed22e89a759031f08327 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 19 May 2009 16:30:09 -0700 Subject: [PATCH] FAT: change DOS installer to EXE; additional 32K limit fixes Additional fixes for the 32K limits in the installers. In the case of the DOS installer, that means changing it from COM format to EXE format (since COM format has a 63K hard limit); retain the name syslinux.com for user compatibility, though (DOS doesn't care what the extension except for pathname search; if it finds an MZ EXE header it will use it.) With the change to EXE means having to handle more than one segment. Since we don't have a real DOS compiler we have to wing it a bit. Signed-off-by: H. Peter Anvin --- dos/Makefile | 10 ++-- dos/argv.c | 4 +- dos/com16.ld | 127 ---------------------------------------------- dos/crt0.S | 29 ++++++++--- dos/dosexe.ld | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ dos/header.S | 31 ++++++++++++ dos/malloc.c | 32 ++++++------ dos/syslinux.c | 63 +++++++++++++++++++---- extlinux/main.c | 8 +-- libinstaller/bin2c.pl | 4 +- libinstaller/syslinux.h | 22 ++++---- libinstaller/syslxint.h | 36 +++++++------ libinstaller/syslxmod.c | 120 ++++++++++++++++++++++++++++++++++++++------ linux/syslinux.c | 22 +++++--- mtools/syslinux.c | 20 +++++--- win32/syslinux.c | 9 ++-- 16 files changed, 442 insertions(+), 226 deletions(-) delete mode 100644 dos/com16.ld create mode 100644 dos/dosexe.ld create mode 100644 dos/header.S diff --git a/dos/Makefile b/dos/Makefile index fa2ed0a..b8d4445 100644 --- a/dos/Makefile +++ b/dos/Makefile @@ -17,7 +17,9 @@ topdir = .. include $(topdir)/MCONFIG.embedded -LDFLAGS = -T com16.ld +CFLAGS += -D__MSDOS__ + +LDFLAGS = -T dosexe.ld OPTFLAGS = -g INCLUDES = -include code16.h -nostdinc -iwithprefix include \ -I. -I.. -I../libfat -I ../libinstaller @@ -28,7 +30,7 @@ SRCS = syslinux.c \ ../libinstaller/ldlinux_bin.c \ ../libinstaller/mbr_bin.c \ $(wildcard ../libfat/*.c) -OBJS = crt0.o $(patsubst %.c,%.o,$(notdir $(SRCS))) +OBJS = header.o crt0.o $(patsubst %.c,%.o,$(notdir $(SRCS))) LIBOBJS = conio.o memcpy.o memset.o skipatou.o atou.o malloc.o free.o \ argv.o printf.o __divdi3.o __udivmoddi4.o @@ -48,8 +50,8 @@ spotless: clean installer: -syslinux.elf: $(OBJS) libcom.a - $(LD) $(LDFLAGS) -o $@ $^ +syslinux.elf: $(OBJS) dosexe.ld libcom.a + $(LD) $(LDFLAGS) -o $@ $(OBJS) libcom.a libcom.a: $(LIBOBJS) -rm -f $@ diff --git a/dos/argv.c b/dos/argv.c index 84888b0..90acf75 100644 --- a/dos/argv.c +++ b/dos/argv.c @@ -38,8 +38,8 @@ #define ALIGN_UP(p,t) ((t *)(((uintptr_t)(p) + (sizeof(t)-1)) & ~(sizeof(t)-1))) -extern char _end[]; /* Symbol created by linker */ -void *__mem_end = &_end; /* Global variable for use by malloc() */ +extern char __heap_start[]; +void *__mem_end = &__heap_start; /* Global variable for use by malloc() */ int __parse_argv(char ***argv, const char *str) { diff --git a/dos/com16.ld b/dos/com16.ld deleted file mode 100644 index 08a1e95..0000000 --- a/dos/com16.ld +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Linker script for COM16 binaries - */ - -/* 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: */ - . = 0x100; - PROVIDE (__executable_start = .); - - .init : - { - KEEP (*(.init)) - } =0x90909090 - .text : - { - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } =0x90909090 - .fini : - { - KEEP (*(.fini)) - } =0x90909090 - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - - /* Ensure the __preinit_array_start label is properly aligned. We - could instead move the label definition inside the section, but - the linker would then create the section even if it turns out to - be empty, which isn't pretty. */ - . = ALIGN(4); - PROVIDE (__preinit_array_start = .); - .preinit_array : { *(.preinit_array) } - PROVIDE (__preinit_array_end = .); - PROVIDE (__init_array_start = .); - .init_array : { *(.init_array) } - PROVIDE (__init_array_end = .); - PROVIDE (__fini_array_start = .); - .fini_array : { *(.fini_array) } - PROVIDE (__fini_array_end = .); - PROVIDE (__ctors_start = .); - .ctors : - { - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - PROVIDE (__ctors_end = .); - PROVIDE (__dtors_start = .); - .dtors : - { - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - PROVIDE (__dtors_end = .); - - /* Adjust the address for the data segment. Avoid mixing code and - data within same 128-byte chunk. */ - . = ALIGN(128); - - .data : - { - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); - } - . = ALIGN(32 / 8); - _end = .; - PROVIDE (end = .); - - /* 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/dos/crt0.S b/dos/crt0.S index 62ab80f..3be5712 100644 --- a/dos/crt0.S +++ b/dos/crt0.S @@ -4,27 +4,38 @@ # error "This file assumes -mregparm=3 -DREGPARM=3" #endif - .section ".init","ax" + .section ".text","ax" .globl _start .type _start,@function _start: # Align the stack and make sure the high half is zero andl $0xfff8,%esp + # DS, ES points to the PSP at this point + pushw %es # Save PSP pointer + movw %cs,%ax + movw %ax,%ds + movw %ax,%es + # Clear the .bss cld xorl %eax,%eax movw $__bss_start,%di - movw $_end+3,%cx + movw $__bss_end+3,%cx subw %di,%cx shrw $2,%cx rep ; stosl + # Copy the command line into our own segment + popw %fs # FS -> PSP + movw $_cmdline,%di + movzbw %fs:0x80,%cx + movw $0x81,%si + fs ; rep ; movsb + # Already zero-terminated since we're writing into clean bss + # Compute argc and argv (assumes REGPARM) - xorl %edx,%edx - movzbw 0x80,%bx - movb %dl,0x81(%bx) # Zero-terminate string - movb $0x81,%dl + movl $_cmdline,%edx pushl %eax # Make space for argv movl %esp,%eax calll __parse_argv @@ -51,3 +62,9 @@ exit: 1: hlt jmp 1b .size exit,.-exit + + .section ".bss","aw" + .balign 4 +_cmdline: + .space 128 + .size _cmdline,.-_cmdline diff --git a/dos/dosexe.ld b/dos/dosexe.ld new file mode 100644 index 0000000..4612b30 --- /dev/null +++ b/dos/dosexe.ld @@ -0,0 +1,131 @@ +/* + * Linker script for an MS-DOS EXE binary; this hard-codes a simple + * MZ header without relocations. + * + * For documentation on the MS-DOS MZ EXE format, see: + * http://www.delorie.com/djgpp/doc/exe/ + */ + + +/* 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 +{ + . = 0; + /* EXE header, from header.S */ + .header : { + *(.header) + } =0 + + . = ALIGN(16); + __header_size = .; + __payload_lma = .; + + . = 0; + .payload : AT (__payload_lma) { + __payload_start = .; + ldlinux_bin.o(.data) + __payload_end = .; + } + __payload_len = __payload_end - __payload_start; + __payload_dwords = __payload_len >> 2; + + . = ALIGN(16); + __text_lma = __payload_lma + .; + __payload_sseg = (__payload_lma - __text_lma) >> 4; + _exe_text_seg = (__text_lma - __header_size) >> 4; + + . = 0; + .text : AT (__text_lma) { + *(.text .stub .text.* .gnu.linkonce.t.*) + *(.gnu.warning) + } =0x90909090 + _etext = .; + + . = ALIGN(16); + __rodata_vma = .; + .rodata : AT (__rodata_vma + __text_lma) { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + /* Adjust the address for the data segment. Avoid mixing code and + data within same 128-byte chunk. */ + . = ALIGN(128); + __data_vma = .; + .data : AT (__data_vma + __text_lma) { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; + + _exe_edata_low = ((_edata + __text_lma) & 511); + _exe_edata_blocks = ((_edata + __text_lma) + 511) >> 9; + + .bss (NOLOAD) : { + __bss_start = .; + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + __bss_end = .; + } + + . = ALIGN(16); + .heap (NOLOAD) : { + __heap_start = .; + *(.heap) + __heap_end = .; + } + + . = ALIGN(16); + .stack (NOLOAD) : { + __stack_start = .; + *(.stack) + __stack_end = .; + } + . = ALIGN(16); + _end = .; + + _exe_bss_paras = (_end - __bss_start) >> 4; + + + /* 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/dos/header.S b/dos/header.S new file mode 100644 index 0000000..c0698b7 --- /dev/null +++ b/dos/header.S @@ -0,0 +1,31 @@ +STACK_SIZE = 8192 +HEAP_SIZE = 16384 + + .section ".header","a" + .balign 512 +__header_start: + .short 0x5a4d + .short _exe_edata_low + .short _exe_edata_blocks + .short 0 /* Relocation count */ + .short (__header_end - __header_start) >> 4 + .short _exe_bss_paras + .short _exe_bss_paras + .short _exe_text_seg /* SP */ + .short __stack_end + .short 0 /* Checksum */ + .short _start + .short _exe_text_seg /* CS */ + .short __reloc + .short 0 /* Overlay number */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ +__reloc: + .balign 512 +__header_end: + + .section ".heap","aw" + .space HEAP_SIZE + + .section ".stack","aw" + .space STACK_SIZE diff --git a/dos/malloc.c b/dos/malloc.c index 052b0a5..2d74459 100644 --- a/dos/malloc.c +++ b/dos/malloc.c @@ -5,6 +5,7 @@ */ #include +#include #include "malloc.h" struct free_arena_header __malloc_head = @@ -19,29 +20,16 @@ struct free_arena_header __malloc_head = &__malloc_head }; -/* This is extern so it can be overridden by the user application */ -const size_t __stack_size = 4096; - -static inline size_t sp(void) -{ - uint32_t sp; - asm volatile("movl %%esp,%0" : "=rm" (sp)); - return sp; -} - -extern void *__mem_end; +extern void *__mem_end; /* In argv.c */ void __init_memory_arena(void) { + extern char __heap_end[]; struct free_arena_header *fp; - size_t start, total_space; - start = (size_t)ARENA_ALIGN_UP(__mem_end); - total_space = sp() - start; - - fp = (struct free_arena_header *)start; + fp = (struct free_arena_header *)__mem_end; fp->a.type = ARENA_TYPE_FREE; - fp->a.size = total_space - __stack_size; + fp->a.size = __heap_end - (char *)__mem_end; /* Insert into chains */ fp->a.next = fp->a.prev = &__malloc_head; @@ -112,3 +100,13 @@ void *malloc(size_t size) /* Nothing found... need to request a block from the kernel */ return NULL; /* No kernel to get stuff from */ } + +void *calloc(size_t nmemb, size_t size) +{ + void *p; + size *= nmemb; + p = malloc(size); + if (p) + memset(p, 0, size); + return p; +} diff --git a/dos/syslinux.c b/dos/syslinux.c index 064859f..047dc8f 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -114,6 +114,35 @@ int rename(const char *oldname, const char *newname) return 0; } +extern const char __payload_sseg[]; +static uint16_t ldlinux_seg; + +ssize_t write_ldlinux(int fd) +{ + uint32_t offset = 0; + uint16_t rv; + uint8_t err; + + while (offset < syslinux_ldlinux_len) { + uint32_t chunk = syslinux_ldlinux_len - offset; + if (chunk > 32768) + chunk = 32768; + asm volatile("pushw %%ds ; " + "movw %6,%%ds ; " + "int $0x21 ; " + "popw %%ds ; " + "setc %0" + : "=bcdm" (err), "=a" (rv) + : "a" (0x4000), "b" (fd), "c" (chunk), "d" (offset & 15), + "SD" ((uint16_t)(ldlinux_seg + (offset >> 4)))); + if ( err || rv == 0 ) + die("file write error"); + offset += rv; + } + + return offset; +} + ssize_t write_file(int fd, const void *buf, size_t count) { uint16_t rv; @@ -123,10 +152,9 @@ ssize_t write_file(int fd, const void *buf, size_t count) dprintf("write_file(%d,%p,%u)\n", fd, buf, count); while ( count ) { - rv = 0x4000; asm volatile("int $0x21 ; setc %0" - : "=abcdm" (err), "+a" (rv) - : "b" (fd), "c" (count), "d" (buf)); + : "=bcdm" (err), "=a" (rv) + : "a" (0x4000), "b" (fd), "c" (count), "d" (buf)); if ( err || rv == 0 ) die("file write error"); @@ -480,7 +508,9 @@ int main(int argc, char *argv[]) char **argp, *opt; int force = 0; /* -f (force) option */ struct libfat_filesystem *fs; - libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */ + libfat_sector_t s, *secp; + libfat_sector_t *sectors; + int ldlinux_sectors; int32_t ldlinux_cluster; int nsectors; const char *device = NULL, *bootsecfile = NULL; @@ -491,6 +521,9 @@ int main(int argc, char *argv[]) const char *subdir = NULL; int stupid = 0; int raid_mode = 0; + int patch_sectors; + + ldlinux_seg = (size_t)__payload_sseg + data_segment(); dprintf("argv = %p\n", argv); for ( i = 0 ; i <= argc ; i++ ) @@ -572,7 +605,7 @@ int main(int argc, char *argv[]) set_attributes(ldlinux_name, 0); fd = creat(ldlinux_name, 0x07); /* SYSTEM HIDDEN READONLY */ - write_file(fd, syslinux_ldlinux, syslinux_ldlinux_len); + write_ldlinux(fd); close(fd); /* @@ -581,13 +614,15 @@ int main(int argc, char *argv[]) * this is supposed to be a simple, privileged version * of the installer. */ + ldlinux_sectors = (syslinux_ldlinux_len+SECTOR_SIZE-1) >> SECTOR_BITS; + sectors = calloc(ldlinux_sectors, sizeof *sectors); lock_device(2); fs = libfat_open(libfat_xpread, dev_fd); ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL); secp = sectors; nsectors = 0; s = libfat_clustertosector(fs, ldlinux_cluster); - while ( s && nsectors < 65 ) { + while ( s && nsectors < ldlinux_sectors ) { *secp++ = s; nsectors++; s = libfat_nextsector(fs, s); @@ -640,13 +675,23 @@ int main(int argc, char *argv[]) /* * Patch ldlinux.sys and the boot sector */ - syslinux_patch(sectors, nsectors, stupid, raid_mode); + i = syslinux_patch(sectors, nsectors, stupid, raid_mode); + patch_sectors = (i + 511) >> 9; /* - * Write the now-patched first sector of ldlinux.sys + * Overwrite the now-patched ldlinux.sys */ lock_device(3); - write_device(dev_fd, syslinux_ldlinux, 1, sectors[0]); + for (i = 0; i < patch_sectors; i++) { + uint16_t si, di, cx; + si = 0; + di = (size_t)sectbuf; + cx = 512 >> 2; + asm volatile("movw %3,%%fs ; fs ; rep ; movsl" + : "+S" (si), "+D" (di), "+c" (cx) + : "abd" ((uint16_t)(ldlinux_seg + (i << (9-4))))); + write_device(dev_fd, sectbuf, 1, sectors[i]); + } /* * Muck with the MBR, if desired, while we hold the lock diff --git a/extlinux/main.c b/extlinux/main.c index c4ccd53..79123c9 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -233,7 +233,7 @@ sectmap(int fd, uint32_t *sectors, int nsectors) return -1; /* Number of sectors per block */ - blksize >>= SECTOR_SHIFT; + blksize >>= SECTOR_BITS; nblk = 0; while ( nsectors ) { @@ -336,7 +336,7 @@ get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) geo->heads = opt.heads ?: 64; geo->sectors = opt.sectors ?: 32; - geo->cylinders = totalbytes/(geo->heads*geo->sectors << SECTOR_SHIFT); + geo->cylinders = totalbytes/(geo->heads*geo->sectors << SECTOR_BITS); geo->start = 0; if ( !opt.sectors && !opt.heads ) @@ -386,7 +386,7 @@ patch_file_and_bootblock(int fd, int dirfd, int devfd) bs = (struct boot_sector *)boot_block; - totalsectors = totalbytes >> SECTOR_SHIFT; + totalsectors = totalbytes >> SECTOR_BITS; if ( totalsectors >= 65536 ) { set_16(&bs->bsSectors, 0); } else { @@ -410,7 +410,7 @@ patch_file_and_bootblock(int fd, int dirfd, int devfd) /* Construct the boot file */ dprintf("directory inode = %lu\n", (unsigned long) dirst.st_ino); - nsect = (boot_image_len+SECTOR_SIZE-1) >> SECTOR_SHIFT; + nsect = (boot_image_len+SECTOR_SIZE-1) >> SECTOR_BITS; nsect += 2; /* Two sectors for the ADV */ sectp = alloca(sizeof(uint32_t)*nsect); if ( sectmap(fd, sectp, nsect) ) { diff --git a/libinstaller/bin2c.pl b/libinstaller/bin2c.pl index 5a60ca9..07c11dd 100755 --- a/libinstaller/bin2c.pl +++ b/libinstaller/bin2c.pl @@ -69,10 +69,10 @@ if ($align != 0) { } } -printf "\n};\n\nunsigned int %s_len = %u;\n", $table_name, $total_len; +printf "\n};\n\nconst unsigned int %s_len = %u;\n", $table_name, $total_len; @st = stat STDIN; -printf "\nint %s_mtime = %d;\n", $table_name, $st[9]; +printf "\nconst int %s_mtime = %d;\n", $table_name, $st[9]; exit 0; diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h index efffb7c..e055425 100644 --- a/libinstaller/syslinux.h +++ b/libinstaller/syslinux.h @@ -17,17 +17,21 @@ #include "advconst.h" /* The standard boot sector and ldlinux image */ -extern unsigned char syslinux_bootsect[]; -extern unsigned int syslinux_bootsect_len; -extern int syslinux_bootsect_mtime; +extern unsigned char syslinux_bootsect[]; +extern const unsigned int syslinux_bootsect_len; +extern const int syslinux_bootsect_mtime; -extern unsigned char syslinux_ldlinux[]; -extern unsigned int syslinux_ldlinux_len; -extern int syslinux_ldlinux_mtime; +extern unsigned char syslinux_ldlinux[]; +extern const unsigned int syslinux_ldlinux_len; +extern const int syslinux_ldlinux_mtime; -extern unsigned char syslinux_mbr[]; -extern unsigned int syslinux_mbr_len; -extern int syslinux_mbr_mtime; +extern unsigned char syslinux_mbr[]; +extern const unsigned int syslinux_mbr_len; +extern const int syslinux_mbr_mtime; + +/* Sector size assumptions... */ +#define SECTOR_BITS 9 +#define SECTOR_SIZE (1 << SECTOR_BITS) /* This takes a boot sector and merges in the syslinux fields */ void syslinux_make_bootsect(void *); diff --git a/libinstaller/syslxint.h b/libinstaller/syslxint.h index 3f50e32..fc3932b 100644 --- a/libinstaller/syslxint.h +++ b/libinstaller/syslxint.h @@ -20,16 +20,17 @@ */ static inline uint8_t get_8(const uint8_t *p) { - return *(const uint8_t *)p; + return *p; } static inline uint16_t get_16(const uint16_t *p) { #if defined(__i386__) || defined(__x86_64__) /* Littleendian and unaligned-capable */ - return *(const uint16_t *)p; + return *p; #else - return (uint16_t)p[0] + ((uint16_t)p[1] << 8); + const uint8_t *pp = (const uint8_t *)p; + return (uint16_t)pp[0] + ((uint16_t)pp[1] << 8); #endif } @@ -37,21 +38,28 @@ static inline uint32_t get_32(const uint32_t *p) { #if defined(__i386__) || defined(__x86_64__) /* Littleendian and unaligned-capable */ - return *(const uint32_t *)p; + return *p; #else - return (uint32_t)p[0] + ((uint32_t)p[1] << 8) + - ((uint32_t)p[2] << 16) + ((uint32_t)p[3] << 24); + const uint8_t *pp = (const uint8_t *)p; + return (uint32_t)pp[0] + ((uint32_t)pp[1] << 8) + + ((uint32_t)pp[2] << 16) + ((uint32_t)pp[3] << 24); #endif } +static inline void set_8(uint8_t *p, uint8_t v) +{ + *p = v; +} + static inline void set_16(uint16_t *p, uint16_t v) { #if defined(__i386__) || defined(__x86_64__) /* Littleendian and unaligned-capable */ *(uint16_t *)p = v; #else - p[0] = (v & 0xff); - p[1] = ((v >> 8) & 0xff); + uint8_t *pp = (uint8_t *)p; + pp[0] = (v & 0xff); + pp[1] = ((v >> 8) & 0xff); #endif } @@ -61,16 +69,14 @@ static inline void set_32(uint32_t *p, uint32_t v) /* Littleendian and unaligned-capable */ *(uint32_t *)p = v; #else - p[0] = (v & 0xff); - p[1] = ((v >> 8) & 0xff); - p[2] = ((v >> 16) & 0xff); - p[3] = ((v >> 24) & 0xff); + uint8_t *pp = (uint8_t *)p; + pp[0] = (v & 0xff); + pp[1] = ((v >> 8) & 0xff); + pp[2] = ((v >> 16) & 0xff); + pp[3] = ((v >> 24) & 0xff); #endif } -#define SECTOR_SHIFT 9 /* 512-byte sectors */ -#define SECTOR_SIZE (1 << SECTOR_SHIFT) - #define LDLINUX_MAGIC 0x3eb202fe /* Patch area for disk-based installers */ diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c index 1766de2..78e226c 100644 --- a/libinstaller/syslxmod.c +++ b/libinstaller/syslxmod.c @@ -121,6 +121,88 @@ const char *syslinux_check_bootsect(const void *bs) } /* + * Special handling for the MS-DOS derivative: syslinux_ldlinux + * is a "far" object... + */ +#ifdef __MSDOS__ + +extern const char __payload_sseg[]; /* Symbol from linker */ + +static inline __attribute__((const)) uint16_t ds(void) +{ + uint16_t v; + asm("movw %%ds,%0" : "=rm" (v)); + return v; +} + +static inline void *set_fs(const void *p) +{ + uint16_t seg; + + seg = ds() + (size_t)__payload_sseg; + seg += (size_t)p >> 4; + asm volatile("movw %0,%%fs" : : "rm" (seg)); + return (void *)((size_t)p & 0xf); +} + +static inline uint8_t get_8_sl(const uint8_t *p) +{ + uint8_t v; + + p = set_fs(p); + asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*p)); + return v; +} + +static inline uint16_t get_16_sl(const uint16_t *p) +{ + uint16_t v; + + p = set_fs(p); + asm volatile("movw %%fs:%1,%0" : "=r" (v) : "m" (*p)); + return v; +} + +static inline uint32_t get_32_sl(const uint32_t *p) +{ + uint32_t v; + + p = set_fs(p); + asm volatile("movl %%fs:%1,%0" : "=r" (v) : "m" (*p)); + return v; +} + +static inline void set_8_sl(uint8_t *p, uint8_t v) +{ + p = set_fs(p); + asm volatile("movb %1,%%fs:%0" : "=m" (*p) : "qi" (v)); +} + +static inline void set_16_sl(uint16_t *p, uint16_t v) +{ + p = set_fs(p); + asm volatile("movw %1,%%fs:%0" : "=m" (*p) : "ri" (v)); +} + +static inline void set_32_sl(uint32_t *p, uint32_t v) +{ + p = set_fs(p); + asm volatile("movl %1,%%fs:%0" : "=m" (*p) : "ri" (v)); +} + +#else + +/* Sane system ... */ +#define get_8_sl(x) get_8(x) +#define get_16_sl(x) get_16(x) +#define get_32_sl(x) get_32(x) +#define set_8_sl(x,y) set_8(x,y) +#define set_16_sl(x,y) set_16(x,y) +#define set_32_sl(x,y) set_32(x,y) + +#endif + +/* * This patches the boot sector and the beginning of ldlinux.sys * based on an ldlinux.sys sector map passed in. Typically this is * handled by writing ldlinux.sys, mapping it, and then overwrite it @@ -128,7 +210,8 @@ const char *syslinux_check_bootsect(const void *bs) * an OS which does block reallocation, then overwrite it with * direct access since the location is known. * - * Return 0 if successful, otherwise -1. + * Returns the number of modified bytes in ldlinux.sys if successful, + * otherwise -1. */ int syslinux_patch(const uint32_t *sectors, int nsectors, int stupid, int raid_mode) @@ -137,7 +220,7 @@ int syslinux_patch(const uint32_t *sectors, int nsectors, uint32_t *wp; int nsect = (syslinux_ldlinux_len+511) >> 9; uint32_t csum; - int i, dw, nptrs; + int i, dw, nptrs, rv; if ( nsectors < nsect ) return -1; @@ -157,33 +240,38 @@ int syslinux_patch(const uint32_t *sectors, int nsectors, set_32(&sbs->NextSector, *sectors++); /* Search for LDLINUX_MAGIC to find the patch area */ - for (wp = (uint32_t *)syslinux_ldlinux; get_32(wp) != LDLINUX_MAGIC; wp++) + for (wp = (uint32_t *)syslinux_ldlinux; get_32_sl(wp) != LDLINUX_MAGIC; wp++) ; patcharea = (struct patch_area *)wp; /* Set up the totals */ dw = syslinux_ldlinux_len >> 2; /* COMPLETE dwords, excluding ADV */ - set_16(&patcharea->data_sectors, nsect); /* Not including ADVs */ - set_16(&patcharea->adv_sectors, 0); /* ADVs not supported yet */ - set_32(&patcharea->dwords, dw); - set_32(&patcharea->currentdir, 0); + set_16_sl(&patcharea->data_sectors, nsect); /* Not including ADVs */ + set_16_sl(&patcharea->adv_sectors, 0); /* ADVs not supported yet */ + set_32_sl(&patcharea->dwords, dw); + set_32_sl(&patcharea->currentdir, 0); /* Set the sector pointers */ - wp = (uint32_t *)((char *)syslinux_ldlinux+get_16(&patcharea->secptroffset)); - nptrs = get_16(&patcharea->secptrcnt); + wp = (uint32_t *)((char *)syslinux_ldlinux+get_16_sl(&patcharea->secptroffset)); + nptrs = get_16_sl(&patcharea->secptrcnt); + + while (nsect--) { + set_32_sl(wp++, *sectors++); + nptrs--; + } + while (nptrs--) + set_32_sl(wp++, 0); - memset(wp, 0, nptrs*4); - while ( nsect-- ) - set_32(wp++, *sectors++); + rv = (char *)wp - (char *)syslinux_ldlinux; /* Now produce a checksum */ - set_32(&patcharea->checksum, 0); + set_32_sl(&patcharea->checksum, 0); csum = LDLINUX_MAGIC; for (i = 0, wp = (uint32_t *)syslinux_ldlinux; i < dw; i++, wp++) - csum -= get_32(wp); /* Negative checksum */ + csum -= get_32_sl(wp); /* Negative checksum */ - set_32(&patcharea->checksum, csum); + set_32_sl(&patcharea->checksum, csum); - return 0; + return rv; } diff --git a/linux/syslinux.c b/linux/syslinux.c index 37a54fd..e1b464e 100644 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -48,10 +48,12 @@ #include #include /* FIGETBSZ, FIBMAP */ -#include /* FAT_IOCTL_SET_ATTRIBUTES, SECTOR_* */ +#include /* FAT_IOCTL_SET_ATTRIBUTES */ #ifndef FAT_IOCTL_SET_ATTRIBUTES # define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, uint32_t) #endif +#undef SECTOR_SIZE +#undef SECTOR_BITS #include #ifndef _PATH_MOUNT @@ -325,10 +327,13 @@ int main(int argc, char *argv[]) char mntname[128]; char *ldlinux_name, **argp, *opt; const char *subdir = NULL; - uint32_t sectors[65]; /* 65 is maximum possible */ + uint32_t *sectors; + int ldlinux_sectors; int nsectors = 0; const char *errmsg; int mnt_cookie; + int patch_sectors; + int i; int force = 0; /* -f (force) option */ int stupid = 0; /* -s (stupid) option */ @@ -514,6 +519,8 @@ int main(int argc, char *argv[]) /* * Create a block map. */ + ldlinux_sectors = (syslinux_ldlinux_len+SECTOR_SIZE-1) >> SECTOR_BITS; + sectors = calloc(ldlinux_sectors, sizeof *sectors); nsectors = make_block_map(sectors, syslinux_ldlinux_len, dev_fd, fd); close(fd); @@ -530,13 +537,16 @@ umount: /* * Patch ldlinux.sys and the boot sector */ - syslinux_patch(sectors, nsectors, stupid, raid_mode); + i = syslinux_patch(sectors, nsectors, stupid, raid_mode); + patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_BITS; /* - * Write the now-patched first sector of ldlinux.sys + * Write the now-patched first sectors of ldlinux.sys */ - xpwrite(dev_fd, syslinux_ldlinux, SECTOR_SIZE, - filesystem_offset+((off_t)sectors[0] << SECTOR_BITS)); + for (i = 0; i < patch_sectors; i++) { + xpwrite(dev_fd, syslinux_ldlinux + i*SECTOR_SIZE, SECTOR_SIZE, + filesystem_offset+((off_t)sectors[i] << SECTOR_BITS)); + } /* * To finish up, write the boot sector diff --git a/mtools/syslinux.c b/mtools/syslinux.c index 46b33f4..8ddf42e 100644 --- a/mtools/syslinux.c +++ b/mtools/syslinux.c @@ -134,10 +134,13 @@ int main(int argc, char *argv[]) int mtc_fd; FILE *mtc, *mtp; struct libfat_filesystem *fs; - libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */ + libfat_sector_t s, *secp; + libfat_sector_t *sectors; int32_t ldlinux_cluster; int nsectors; const char *errmsg; + int ldlinux_sectors, patch_sectors; + int i; int force = 0; /* -f (force) option */ int stupid = 0; /* -s (stupid) option */ @@ -247,12 +250,14 @@ int main(int argc, char *argv[]) /* * Now, use libfat to create a block map */ + ldlinux_sectors = (syslinux_ldlinux_len+SECTOR_SIZE-1) >> SECTOR_BITS; + sectors = calloc(ldlinux_sectors, sizeof *sectors); fs = libfat_open(libfat_xpread, dev_fd); ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL); secp = sectors; nsectors = 0; s = libfat_clustertosector(fs, ldlinux_cluster); - while ( s && nsectors < 65 ) { + while ( s && nsectors < ldlinux_sectors ) { *secp++ = s; nsectors++; s = libfat_nextsector(fs, s); @@ -260,11 +265,14 @@ int main(int argc, char *argv[]) libfat_close(fs); /* Patch ldlinux.sys and the boot sector */ - syslinux_patch(sectors, nsectors, stupid, raid_mode); + i = syslinux_patch(sectors, nsectors, stupid, raid_mode); + patch_sectors = (i + 511) >> 9; - /* Write the now-patched first sector of ldlinux.sys */ - xpwrite(dev_fd, syslinux_ldlinux, 512, - filesystem_offset + ((off_t)sectors[0] << 9)); + /* Write the now-patched first sectors of ldlinux.sys */ + for (i = 0; i < patch_sectors; i++) { + xpwrite(dev_fd, syslinux_ldlinux + i*512, 512, + filesystem_offset + ((off_t)sectors[i] << 9)); + } /* Move ldlinux.sys to the desired location */ if (subdir) { diff --git a/win32/syslinux.c b/win32/syslinux.c index 1699125..7a0fafb 100644 --- a/win32/syslinux.c +++ b/win32/syslinux.c @@ -36,7 +36,6 @@ void error(char* msg); #include -#define SECTOR_SIZE 512 #define PART_TABLE 0x1be #define PART_SIZE 0x10 #define PART_COUNT 4 @@ -252,7 +251,9 @@ int main(int argc, char *argv[]) static char ldlinux_name[] = "?:\\ldlinux.sys" ; const char *errmsg; struct libfat_filesystem *fs; - libfat_sector_t s, *secp, sectors[65]; /* 65 is maximum possible */ + libfat_sector_t s, *secp; + libfat_sector_t *sectors; + int ldlinux_sectors; uint32_t ldlinux_cluster; int nsectors; const char *bootsecfile = NULL; @@ -414,12 +415,14 @@ int main(int argc, char *argv[]) } /* Map the file (is there a better way to do this?) */ + ldlinux_sectors = (syslinux_ldlinux_len+SECTOR_SIZE-1) >> SECTOR_BITS; + sectors = calloc(ldlinux_sectors, sizeof *sectors); fs = libfat_open(libfat_readfile, (intptr_t)d_handle); ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL); secp = sectors; nsectors = 0; s = libfat_clustertosector(fs, ldlinux_cluster); - while ( s && nsectors < 65 ) { + while ( s && nsectors < ldlinux_sectors ) { *secp++ = s; nsectors++; s = libfat_nextsector(fs, s); -- 2.7.4