summaryrefslogtreecommitdiff
path: root/dos
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-05-19 16:30:09 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-05-19 16:30:09 -0700
commit0fa4369624b4637a7e36ed22e89a759031f08327 (patch)
tree4aa1cf5c87d36153cee3c727d5f77498c0042983 /dos
parentc9ad266f64f9ee81a859bdf70c1190ee0cc1bc19 (diff)
downloadsyslinux-0fa4369624b4637a7e36ed22e89a759031f08327.tar.gz
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 <hpa@zytor.com>
Diffstat (limited to 'dos')
-rw-r--r--dos/Makefile10
-rw-r--r--dos/argv.c4
-rw-r--r--dos/com16.ld127
-rw-r--r--dos/crt0.S29
-rw-r--r--dos/dosexe.ld131
-rw-r--r--dos/header.S31
-rw-r--r--dos/malloc.c32
-rw-r--r--dos/syslinux.c63
8 files changed, 262 insertions, 165 deletions
diff --git a/dos/Makefile b/dos/Makefile
index fa2ed0ac..b8d4445f 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 84888b03..90acf75d 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 08a1e95e..00000000
--- 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 62ab80ff..3be57125 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 00000000..4612b30a
--- /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 00000000..c0698b7f
--- /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 052b0a5a..2d74459c 100644
--- a/dos/malloc.c
+++ b/dos/malloc.c
@@ -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;
+}
diff --git a/dos/syslinux.c b/dos/syslinux.c
index 064859f7..047dc8f8 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