diff options
-rw-r--r-- | dos/argv.c | 62 | ||||
-rw-r--r-- | dos/crt0.S | 47 | ||||
-rw-r--r-- | dos/dosexe.ld | 23 | ||||
-rw-r--r-- | dos/getsetsl.c | 26 | ||||
-rw-r--r-- | dos/mystuff.h | 59 | ||||
-rw-r--r-- | dos/syslinux.c | 16 | ||||
-rw-r--r-- | libinstaller/syslxint.h | 17 |
7 files changed, 175 insertions, 75 deletions
@@ -1,6 +1,7 @@ /* ----------------------------------------------------------------------- * * * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2013 Intel Corporation; author: H. Peter Anvin * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -28,48 +29,81 @@ /* * argv.c * - * Parse a single C string into argc and argv (argc is return value.) + * Parse the MS-DOS command line into argc and argv (argc is return value.) * memptr points to available memory. */ #include <inttypes.h> #include <stddef.h> -#include <stdio.h> +#include <stdbool.h> +#include "mystuff.h" #define ALIGN_UP(p,t) ((t *)(((uintptr_t)(p) + (sizeof(t)-1)) & ~(sizeof(t)-1))) extern char __heap_start[]; void *__mem_end = &__heap_start; /* Global variable for use by malloc() */ -int __parse_argv(char ***argv, const char *str) +int __parse_argv(char ***argv) { char *mem = __mem_end; - const char *p = str; + const char *str, *p; char *q = mem; - char *r; + char c, *r; char **arg; - int wasspace = 0; - int argc = 1; + bool wasspace; + int argc; + int len; + size_t offs; + int nulls; + uint16_t nstr; - /* First copy the string, turning whitespace runs into nulls */ + /* Find and copy argv[0] after the environment block */ + set_fs(_PSP.environment); + offs = 0; + nulls = 0; + do { + if (get_8_fs(offs++) == '\0') + nulls++; + else + nulls = 0; + } while (nulls < 2); + + nstr = get_16_fs(offs); + offs += 2; + + /* Copy the null-terminated filename string */ + if (nstr >= 1) { + while ((c = get_8_fs(offs++))) + *q++ = c; + } + *q++ = '\0'; + + /* Now for the command line tail... */ + + len = _PSP.cmdlen; + str = _PSP.cmdtail; + argc = 1; + wasspace = true; + + /* Copy the command tail, turning whitespace runs into nulls */ for (p = str;; p++) { - if (*p <= ' ') { + if (!len || *p <= ' ') { if (!wasspace) { - wasspace = 1; + wasspace = true; *q++ = '\0'; } } else { if (wasspace) { argc++; - wasspace = 0; + wasspace = false; } *q++ = *p; } - /* This test is AFTER we have processed the null byte; + /* This test is AFTER we have processed the end byte; we treat it as a whitespace character so it terminates the last argument */ - if (!*p) + if (!len--) break; } @@ -78,7 +112,7 @@ int __parse_argv(char ***argv, const char *str) *argv = arg; *arg++ = mem; /* argv[0] */ - q--; /* Point q to final null */ + q--; /* Point q to terminal character */ for (r = mem; r < q; r++) { if (*r == '\0') { *arg++ = r + 1; @@ -9,7 +9,7 @@ .type _start,@function _start: # Align the stack and make sure the high half is zero - andl $0xfff8,%esp + andl $0xfffc,%esp # DS, ES points to the PSP at this point pushw %es # Save PSP pointer @@ -26,16 +26,27 @@ _start: shrw $2,%cx rep ; stosl - # Copy the command line into our own segment + # Copy the PSP 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 + movw $_PSP,%di + xorw %si,%si + movw $0x40,%cx + fs ; rep ; movsl + # Verify that this is a supportable DOS version + movw $0x3001,%ax + int $0x21 + xchgb %ah,%al + movw %ax,dos_version + cmpw $0x0314,%ax # DOS >= 3.20? + jae 1f # If so, okay + movw $bad_dos,%dx # Print error message + movb $0x09,%ah + int $0x21 + int $0x20 # Die + +1: # Compute argc and argv (assumes REGPARM) - movl $_cmdline,%edx pushl %eax # Make space for argv movl %esp,%eax calll __parse_argv @@ -44,7 +55,7 @@ _start: # Initialize malloc calll __init_memory_arena - # Now call main... (NOTE: gcc forces main to be regparm 0) + # Now call main popl %eax # argc popl %edx # argv calll main @@ -63,8 +74,18 @@ exit: jmp 1b .size exit,.-exit + .section ".rodata","a" +bad_dos: + .ascii "Unsupported DOS version\r\n$" + .size bad_dos,.-bad_dos + .section ".bss","aw" - .balign 4 -_cmdline: - .space 128 - .size _cmdline,.-_cmdline + .balign 16 + .globl _PSP +_PSP: + .space 256 + .size _PSP, .-_PSP + + /* Purely for sanity */ + .section ".null","a" + .long 0,0,0,0 diff --git a/dos/dosexe.ld b/dos/dosexe.ld index bd6ad8ba..733f73d8 100644 --- a/dos/dosexe.ld +++ b/dos/dosexe.ld @@ -35,16 +35,23 @@ SECTIONS __payload_len = ABSOLUTE(__payload_end) - ABSOLUTE(__payload_start); __payload_dwords = __payload_len >> 2; - __text_lma = __payload_lma + syslinux_size; - __payload_sseg = (__payload_lma - __text_lma) >> 4; - _exe_text_seg = (__text_lma - __header_size) >> 4; + __dgroup_lma = __payload_lma + syslinux_size; + __payload_sseg = (__payload_lma - __dgroup_lma) >> 4; + _exe_text_seg = (__dgroup_lma - __header_size) >> 4; /* * __assert1 = ASSERT((__payload_len == syslinux_ldlinux_size), * "syslinux_size must equal the size of .payload"); */ . = 0; - .text : AT (__text_lma) { + __null = .; + .null : AT(__dgroup_lma) { + *(.null) + } + + . = ALIGN(16); + __text_vma = .; + .text : AT (__text_vma + __dgroup_lma) { *(.text .stub .text.* .gnu.linkonce.t.*) *(.gnu.warning) } =0x90909090 @@ -52,7 +59,7 @@ SECTIONS . = ALIGN(16); __rodata_vma = .; - .rodata : AT (__rodata_vma + __text_lma) { + .rodata : AT (__rodata_vma + __dgroup_lma) { *(.rodata .rodata.* .gnu.linkonce.r.*) } @@ -60,15 +67,15 @@ SECTIONS data within same 128-byte chunk. */ . = ALIGN(128); __data_vma = .; - .data : AT (__data_vma + __text_lma) { + .data : AT (__data_vma + __dgroup_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; + _exe_edata_low = ((_edata + __dgroup_lma) & 511); + _exe_edata_blocks = ((_edata + __dgroup_lma) + 511) >> 9; .bss (NOLOAD) : { __bss_start = .; diff --git a/dos/getsetsl.c b/dos/getsetsl.c index 67e954d1..fadef438 100644 --- a/dos/getsetsl.c +++ b/dos/getsetsl.c @@ -11,15 +11,23 @@ #include <stdlib.h> #include "syslxint.h" +#include "mystuff.h" -#define __noinline __attribute__((noinline)) +static inline void *set_fs_sl(const void *p) +{ + uint16_t seg; + + seg = ds() + ((size_t) p >> 4); + set_fs(seg); + return (void *)((size_t) p & 0xf); +} #if 0 /* unused */ uint8_t get_8_sl(const uint8_t * p) { uint8_t v; - p = set_fs(p); + p = set_fs_sl(p); asm volatile("movb %%fs:%1,%0":"=q" (v):"m"(*p)); return v; } @@ -29,7 +37,7 @@ uint16_t get_16_sl(const uint16_t * p) { uint16_t v; - p = set_fs(p); + p = set_fs_sl(p); asm volatile("movw %%fs:%1,%0":"=r" (v):"m"(*p)); return v; } @@ -38,7 +46,7 @@ uint32_t get_32_sl(const uint32_t * p) { uint32_t v; - p = set_fs(p); + p = set_fs_sl(p); asm volatile("movl %%fs:%1,%0":"=r" (v):"m"(*p)); return v; } @@ -47,7 +55,7 @@ uint32_t get_32_sl(const uint32_t * p) uint64_t get_64_sl(const uint64_t * p) { uint32_t v0, v1; - const uint32_t *pp = (const uint32_t *)set_fs(p); + const uint32_t *pp = (const uint32_t *)set_fs_sl(p); asm volatile("movl %%fs:%1,%0" : "=r" (v0) : "m" (pp[0])); asm volatile("movl %%fs:%1,%0" : "=r" (v1) : "m" (pp[1])); @@ -58,26 +66,26 @@ uint64_t get_64_sl(const uint64_t * p) #if 0 /* unused */ void set_8_sl(uint8_t * p, uint8_t v) { - p = set_fs(p); + p = set_fs_sl(p); asm volatile("movb %1,%%fs:%0":"=m" (*p):"qi"(v)); } #endif void set_16_sl(uint16_t * p, uint16_t v) { - p = set_fs(p); + p = set_fs_sl(p); asm volatile("movw %1,%%fs:%0":"=m" (*p):"ri"(v)); } void set_32_sl(uint32_t * p, uint32_t v) { - p = set_fs(p); + p = set_fs_sl(p); asm volatile("movl %1,%%fs:%0":"=m" (*p):"ri"(v)); } void set_64_sl(uint64_t * p, uint64_t v) { - uint32_t *pp = (uint32_t *)set_fs(p); + uint32_t *pp = (uint32_t *)set_fs_sl(p); asm volatile("movl %1,%%fs:%0" : "=m" (pp[0]) : "ri"((uint32_t)v)); asm volatile("movl %1,%%fs:%0" : "=m" (pp[1]) : "ri"((uint32_t)(v >> 32))); } diff --git a/dos/mystuff.h b/dos/mystuff.h index 25344413..2d9574d6 100644 --- a/dos/mystuff.h +++ b/dos/mystuff.h @@ -2,8 +2,7 @@ #define MYSTUFF_H #include <inttypes.h> - -#define NULL ((void *)0) +#include <stddef.h> unsigned int skip_atou(const char **s); unsigned int atou(const char *s); @@ -21,4 +20,60 @@ struct diskio { int int25_read_sector(unsigned char drive, struct diskio *dio); int int26_write_sector(unsigned char drive, struct diskio *dio); +struct psp { + uint16_t int20; + uint16_t nextpara; + uint8_t resv1; + uint8_t dispatcher[5]; + uint32_t termvector; + uint32_t ctrlcvector; + uint32_t criterrvector; + uint16_t resv2[11]; + uint16_t environment; + uint16_t resv3[23]; + uint8_t fcb[2][16]; + uint32_t resv4; + uint8_t cmdlen; + char cmdtail[127]; +} __attribute__((packed)); + +extern struct psp _PSP; + +static inline __attribute__((const)) +uint16_t ds(void) +{ + uint16_t v; + asm("movw %%ds,%0":"=rm"(v)); + return v; +} + +static inline void set_fs(uint16_t seg) +{ + asm volatile("movw %0,%%fs"::"rm" (seg)); +} + +static inline uint8_t get_8_fs(size_t offs) +{ + uint8_t v; + asm volatile("movb %%fs:%1,%0" + : "=q" (v) : "m" (*(const uint8_t *)offs)); + return v; +} + +static inline uint16_t get_16_fs(size_t offs) +{ + uint16_t v; + asm volatile("movw %%fs:%1,%0" + : "=r" (v) : "m" (*(const uint16_t *)offs)); + return v; +} + +static inline uint32_t get_32_fs(size_t offs) +{ + uint32_t v; + asm volatile("movl %%fs:%1,%0" + : "=r" (v) : "m" (*(const uint32_t *)offs)); + return v; +} + #endif /* MYSTUFF_H */ diff --git a/dos/syslinux.c b/dos/syslinux.c index eb8bace6..63a3a854 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -41,7 +41,7 @@ uint16_t dos_version; void pause(void) { uint16_t ax; - + asm volatile("int $0x16" : "=a" (ax) : "a" (0)); } #else @@ -187,7 +187,7 @@ void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector) dio.sectors = nsecs; dio.bufoffs = (uintptr_t) buf; dio.bufseg = data_segment(); - + if (dos_version >= 0x070a) { /* Try FAT32-aware system call first */ asm volatile("int $0x21 ; jc 1f ; xorw %0,%0\n" @@ -220,7 +220,7 @@ void read_device(int drive, void *buf, size_t nsecs, unsigned int sector) dio.sectors = nsecs; dio.bufoffs = (uintptr_t) buf; dio.bufseg = data_segment(); - + if (dos_version >= 0x070a) { /* Try FAT32-aware system call first */ asm volatile("int $0x21 ; jc 1f ; xorw %0,%0\n" @@ -402,14 +402,6 @@ int libfat_xpread(intptr_t pp, void *buf, size_t secsize, static inline void get_dos_version(void) { - uint16_t ver; - - asm("int $0x21 ; xchgb %%ah,%%al" - : "=a" (ver) - : "a" (0x3001) - : "ebx", "ecx"); - dos_version = ver; - dprintf("DOS version %d.%d\n", (dos_version >> 8), dos_version & 0xff); } @@ -475,7 +467,7 @@ soft_fail: if (hard_lock) { /* Hard locking, only level 4 supported */ /* This is needed for Win9x in DOS mode */ - + err = do_lock(4); if (err) { if (err == 0x0001) { diff --git a/libinstaller/syslxint.h b/libinstaller/syslxint.h index e5428b79..59e3e5ef 100644 --- a/libinstaller/syslxint.h +++ b/libinstaller/syslxint.h @@ -124,23 +124,6 @@ static inline void set_64(uint64_t *p, uint64_t v) */ #ifdef __MSDOS__ -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) p >> 4); - asm volatile ("movw %0,%%fs"::"rm" (seg)); - return (void *)((size_t) p & 0xf); -} - uint8_t get_8_sl(const uint8_t * p); uint16_t get_16_sl(const uint16_t * p); uint32_t get_32_sl(const uint32_t * p); |