aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2013-01-17 09:34:59 -0800
committerH. Peter Anvin <hpa@linux.intel.com>2013-01-17 09:34:59 -0800
commit8f2de46e618a39054fd6e86602391af8da5fcbac (patch)
tree781ad53cd80a9c1d2ca68024fee8fd32dec9f09a
parentd5e63aca6de51f9a70e9f78e2cc5ee3d32a18614 (diff)
downloadsyslinux-8f2de46e618a39054fd6e86602391af8da5fcbac.tar.gz
syslinux-8f2de46e618a39054fd6e86602391af8da5fcbac.tar.xz
syslinux-8f2de46e618a39054fd6e86602391af8da5fcbac.zip
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@linux.intel.com>
-rw-r--r--dos/argv.c62
-rw-r--r--dos/crt0.S47
-rw-r--r--dos/dosexe.ld23
-rw-r--r--dos/getsetsl.c26
-rw-r--r--dos/mystuff.h59
-rw-r--r--dos/syslinux.c16
-rw-r--r--libinstaller/syslxint.h17
7 files changed, 175 insertions, 75 deletions
diff --git a/dos/argv.c b/dos/argv.c
index 056aae59..da283666 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 3be57125..66b52c06 100644
--- a/dos/crt0.S
+++ b/dos/crt0.S
@@ -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);