[syslinux:elflink] dos: obtain the executable pathname, cleanups

syslinux-bot for H. Peter Anvin hpa at linux.intel.com
Thu Jan 17 09:39:05 PST 2013


Commit-ID:  8f2de46e618a39054fd6e86602391af8da5fcbac
Gitweb:     http://www.syslinux.org/commit/8f2de46e618a39054fd6e86602391af8da5fcbac
Author:     H. Peter Anvin <hpa at linux.intel.com>
AuthorDate: Thu, 17 Jan 2013 09:34:59 -0800
Committer:  H. Peter Anvin <hpa at linux.intel.com>
CommitDate: Thu, 17 Jan 2013 09:34:59 -0800

dos: obtain the executable pathname, cleanups

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 at linux.intel.com>

---
 dos/argv.c              | 62 ++++++++++++++++++++++++++++++++++++++-----------
 dos/crt0.S              | 47 ++++++++++++++++++++++++++-----------
 dos/dosexe.ld           | 23 +++++++++++-------
 dos/getsetsl.c          | 26 ++++++++++++++-------
 dos/mystuff.h           | 59 ++++++++++++++++++++++++++++++++++++++++++++--
 dos/syslinux.c          | 16 ++++---------
 libinstaller/syslxint.h | 17 --------------
 7 files changed, 175 insertions(+), 75 deletions(-)

diff --git a/dos/argv.c b/dos/argv.c
index 056aae5..da28366 100644
--- a/dos/argv.c
+++ b/dos/argv.c
@@ -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;
diff --git a/dos/crt0.S b/dos/crt0.S
index 3be5712..66b52c0 100644
--- a/dos/crt0.S
+++ b/dos/crt0.S
@@ -9,7 +9,7 @@
 	.type _start, at 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 bd6ad8b..733f73d 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 67e954d..fadef43 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 2534441..2d9574d 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 eb8bace..63a3a85 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 e5428b7..59e3e5e 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);


More information about the Syslinux-commits mailing list