diff options
Diffstat (limited to 'dos')
-rw-r--r-- | dos/Makefile | 16 | ||||
-rw-r--r-- | dos/argv.c | 4 | ||||
-rw-r--r-- | dos/com16.ld | 130 | ||||
-rw-r--r-- | dos/crt0.S | 29 | ||||
-rw-r--r-- | dos/dosexe.ld | 131 | ||||
-rw-r--r-- | dos/header.S | 46 | ||||
-rw-r--r-- | dos/malloc.c | 32 | ||||
-rw-r--r-- | dos/stdlib.h | 1 | ||||
-rw-r--r-- | dos/syslinux.c | 72 |
9 files changed, 286 insertions, 175 deletions
diff --git a/dos/Makefile b/dos/Makefile index 9d8ce33c..0bd7d41e 100644 --- a/dos/Makefile +++ b/dos/Makefile @@ -17,8 +17,10 @@ topdir = .. include $(topdir)/MCONFIG.embedded +CFLAGS += -D__MSDOS__ # CFLAGS += -DDEBUG -LDFLAGS = -T com16.ld + +LDFLAGS = -T dosexe.ld OPTFLAGS = -g INCLUDES = -include code16.h -nostdinc -iwithprefix include \ -I. -I.. -I../libfat -I ../libinstaller @@ -29,7 +31,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 = int2526.o conio.o memcpy.o memset.o skipatou.o atou.o \ malloc.o free.o \ argv.o printf.o __divdi3.o __udivmoddi4.o @@ -50,8 +52,8 @@ spotless: clean installer: -syslinux.elf: $(OBJS) libcom.a com16.ld - $(LD) $(LDFLAGS) -o $@ $(filter-out %.ld,$^) +syslinux.elf: $(OBJS) dosexe.ld libcom.a + $(LD) $(LDFLAGS) -o $@ $(OBJS) libcom.a libcom.a: $(LIBOBJS) -rm -f $@ @@ -60,9 +62,11 @@ libcom.a: $(LIBOBJS) syslinux.com: syslinux.elf $(OBJCOPY) -O binary $< $@ + $(UPX) --lzma --ultra-brute $@ || \ + $(UPX) --ultra-brute $@ || \ + true %.com: %.asm - ( $(NASM) -M -DDEPEND $(NASMOPT) -o $@ -M $< && echo '' ) > .$@.d; true - $(NASM) $(NASMOPT) -f bin -o $@ -l $*.lst $< + $(NASM) $(NASMOPT) -f bin -o $@ -MP -MD .$@.d -l $*.lst $< -include .*.d *.tmp @@ -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 5f82b73a..00000000 --- a/dos/com16.ld +++ /dev/null @@ -1,130 +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) - *(.eh_frame) - } -} @@ -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..e7504471 --- /dev/null +++ b/dos/header.S @@ -0,0 +1,46 @@ +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? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .short 0 /* Unknown/pad? */ + .long 0 /* Pointer to Windows PE header */ +__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 3cfcbb2c..55c78c4c 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 = { @@ -18,29 +19,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; @@ -111,3 +99,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/stdlib.h b/dos/stdlib.h index e0597ce8..71af6907 100644 --- a/dos/stdlib.h +++ b/dos/stdlib.h @@ -7,6 +7,7 @@ typedef unsigned int size_t; void __attribute__ ((noreturn)) exit(int); void *malloc(size_t); +void *calloc(size_t, size_t); void free(void *); #endif diff --git a/dos/syslinux.c b/dos/syslinux.c index 650c48f6..61020a1f 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -121,6 +121,33 @@ int rename(const char *oldname, const char *newname) return 0; } +extern const char __payload_sseg[]; +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; @@ -130,9 +157,8 @@ 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)); + asm volatile ("int $0x21 ; setc %0":"=bcdm" (err), "=a"(rv) + :"a"(0x4000), "b"(fd), "c"(count), "d"(buf)); if (err || rv == 0) die("file write error"); @@ -513,7 +539,7 @@ struct mbr_entry { static void adjust_mbr(int device, int writembr, int set_active) { - static unsigned char sectbuf[512]; + static unsigned char sectbuf[SECTOR_SIZE]; int i; if (!writembr && !set_active) @@ -555,13 +581,15 @@ static void adjust_mbr(int device, int writembr, int set_active) int main(int argc, char *argv[]) { - static unsigned char sectbuf[512]; + static unsigned char sectbuf[SECTOR_SIZE]; int dev_fd, fd; static char ldlinux_name[] = "@:\\ldlinux.sys"; 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; @@ -572,6 +600,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++) @@ -651,9 +682,9 @@ int main(int argc, char *argv[]) ldlinux_name[0] = dev_fd | 0x40; - set_attributes(ldlinux_name, 0x00); - fd = creat(ldlinux_name, 0); - write_file(fd, syslinux_ldlinux, syslinux_ldlinux_len); + set_attributes(ldlinux_name, 0); + fd = creat(ldlinux_name, 0); /* SYSTEM HIDDEN READONLY */ + write_ldlinux(fd); close(fd); set_attributes(ldlinux_name, 0x07); /* SYSTEM HIDDEN READONLY */ @@ -663,13 +694,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_SHIFT; + 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); @@ -722,13 +755,24 @@ 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 + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* - * Write the now-patched first sector of ldlinux.sys + * Overwrite the now-patched ldlinux.sys */ /* lock_device(3); -- doesn't seem to be needed */ - 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 = SECTOR_SIZE >> 2; + asm volatile ("movw %3,%%fs ; fs ; rep ; movsl":"+S" (si), "+D"(di), + "+c"(cx) + :"abd"((uint16_t) + (ldlinux_seg + (i << (SECTOR_SHIFT - 4))))); + write_device(dev_fd, sectbuf, 1, sectors[i]); + } /* * Muck with the MBR, if desired, while we hold the lock @@ -749,7 +793,7 @@ int main(int argc, char *argv[]) if (bootsecfile) { unlock_device(0); fd = creat(bootsecfile, 0x20); /* ARCHIVE */ - write_file(fd, sectbuf, 512); + write_file(fd, sectbuf, SECTOR_SIZE); close(fd); } else { write_device(dev_fd, sectbuf, 1, 0); |