FAT: change DOS installer to EXE; additional 32K limit fixes
authorH. Peter Anvin <hpa@zytor.com>
Tue, 19 May 2009 23:30:09 +0000 (16:30 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Tue, 19 May 2009 23:30:09 +0000 (16:30 -0700)
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 <hpa@zytor.com>
16 files changed:
dos/Makefile
dos/argv.c
dos/com16.ld [deleted file]
dos/crt0.S
dos/dosexe.ld [new file with mode: 0644]
dos/header.S [new file with mode: 0644]
dos/malloc.c
dos/syslinux.c
extlinux/main.c
libinstaller/bin2c.pl
libinstaller/syslinux.h
libinstaller/syslxint.h
libinstaller/syslxmod.c
linux/syslinux.c
mtools/syslinux.c
win32/syslinux.c

index fa2ed0a..b8d4445 100644 (file)
@@ -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 $@
index 84888b0..90acf75 100644 (file)
@@ -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 (file)
index 08a1e95..0000000
+++ /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) }
-}
index 62ab80f..3be5712 100644 (file)
@@ -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 (file)
index 0000000..4612b30
--- /dev/null
@@ -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 (file)
index 0000000..c0698b7
--- /dev/null
@@ -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
index 052b0a5..2d74459 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #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;
+}
index 064859f..047dc8f 100644 (file)
@@ -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
index c4ccd53..79123c9 100644 (file)
@@ -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) ) {
index 5a60ca9..07c11dd 100755 (executable)
@@ -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;
index efffb7c..e055425 100644 (file)
 #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 *);
index 3f50e32..fc3932b 100644 (file)
  */
 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 */
index 1766de2..78e226c 100644 (file)
@@ -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;
 }
index 37a54fd..e1b464e 100644 (file)
 
 #include <sys/ioctl.h>
 #include <linux/fs.h>          /* FIGETBSZ, FIBMAP */
-#include <linux/msdos_fs.h>    /* FAT_IOCTL_SET_ATTRIBUTES, SECTOR_* */
+#include <linux/msdos_fs.h>    /* 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 <paths.h>
 #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
index 46b33f4..8ddf42e 100644 (file)
@@ -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) {
index 1699125..7a0fafb 100644 (file)
@@ -36,7 +36,6 @@ void error(char* msg);
 
 #include <winioctl.h>
 
-#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);