aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);