dos: obtain the executable pathname, cleanups
authorH. Peter Anvin <hpa@linux.intel.com>
Thu, 17 Jan 2013 17:34:59 +0000 (09:34 -0800)
committerH. Peter Anvin <hpa@linux.intel.com>
Thu, 17 Jan 2013 17:34:59 +0000 (09:34 -0800)
DOS actually does provide the fully qualified pathname to the
executable, which would be useful to make ldlinux.c32 data rather than
live inside the executable itself -- it has gotten too large.

Also, move some DOS internals -- inline functions only used inside the
dos directory -- out of libinstaller.

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
dos/argv.c
dos/crt0.S
dos/dosexe.ld
dos/getsetsl.c
dos/mystuff.h
dos/syslinux.c
libinstaller/syslxint.h

index 056aae5..da28366 100644 (file)
@@ -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
 /*
  * 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;
index 3be5712..66b52c0 100644 (file)
@@ -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
index bd6ad8b..733f73d 100644 (file)
@@ -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 = .;
index 67e954d..fadef43 100644 (file)
 #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)));
 }
index 2534441..2d9574d 100644 (file)
@@ -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 */
index eb8bace..63a3a85 100644 (file)
@@ -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) {
index e5428b7..59e3e5e 100644 (file)
@@ -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);