From 2f1433edca4c2759ce204bf40dace4f9e2a81cd9 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 10 Nov 2009 22:09:14 -0800 Subject: dos: make DOS installer work under WinME At least under WinME, the DOS installer did not work as advertised. With these modifications, it seems to work okay. Signed-off-by: H. Peter Anvin --- dos/Makefile | 1 + dos/syslinux.c | 112 ++++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 85 insertions(+), 28 deletions(-) (limited to 'dos') diff --git a/dos/Makefile b/dos/Makefile index fa2ed0ac..56d2e076 100644 --- a/dos/Makefile +++ b/dos/Makefile @@ -17,6 +17,7 @@ topdir = .. include $(topdir)/MCONFIG.embedded +# CFLAGS += -DDEBUG LDFLAGS = -T com16.ld OPTFLAGS = -g INCLUDES = -include code16.h -nostdinc -iwithprefix include \ diff --git a/dos/syslinux.c b/dos/syslinux.c index 02ae84b9..4adbd381 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -1,6 +1,7 @@ /* ----------------------------------------------------------------------- * * * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +21,7 @@ #include #include #include +#include #include "mystuff.h" #include "syslinux.h" @@ -69,8 +71,9 @@ int creat(const char *filename, int mode) dprintf("creat(\"%s\", 0x%x)\n", filename, mode); rv = 0x3C00; - asm volatile ("int $0x21 ; setc %0":"=bcdm" (err), "+a"(rv) - :"c"(mode), "d"(filename)); + asm volatile ("int $0x21 ; setc %0" + : "=bcdm" (err), "+a" (rv) + : "c" (mode), "d" (filename)); if (err) { dprintf("rv = %d\n", rv); die("cannot open ldlinux.sys"); @@ -138,7 +141,7 @@ uint16_t data_segment(void) { uint16_t ds; -asm("movw %%ds,%0":"=rm"(ds)); + asm("movw %%ds,%0" : "=rm"(ds)); return ds; } @@ -151,6 +154,7 @@ struct diskio { void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector) { uint8_t err; + uint16_t errnum; struct diskio dio; dprintf("write_device(%d,%p,%u,%u)\n", drive, buf, nsecs, sector); @@ -160,16 +164,30 @@ void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector) dio.bufoffs = (uintptr_t) buf; dio.bufseg = data_segment(); - asm volatile ("int $0x26 ; setc %0 ; popfw":"=abcdm" (err) - :"a"(drive - 1), "b"(&dio), "c"(-1), "d"(buf), "m"(dio)); + if (dos_version >= 0x0710) { + asm volatile("int $0x21 ; setc %0" + : "=bcdm" (err), "=a" (errnum) + : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive), + "S" (1), "m" (dio) + : "memory"); + } else { + asm volatile("int $0x26 ; setc %0 ; popfw" + : "=bcdm" (err), "=a" (errnum) + : "a" (drive-1), "b" (&dio), "c" (-1), "d" (buf), + "m" (dio) + : "esi", "memory"); + } - if (err) + if (err) { + dprintf("rv = %04x\n", errnum); die("sector write error"); + } } void read_device(int drive, const void *buf, size_t nsecs, unsigned int sector) { uint8_t err; + uint16_t errnum; struct diskio dio; dprintf("read_device(%d,%p,%u,%u)\n", drive, buf, nsecs, sector); @@ -179,11 +197,23 @@ void read_device(int drive, const void *buf, size_t nsecs, unsigned int sector) dio.bufoffs = (uintptr_t) buf; dio.bufseg = data_segment(); - asm volatile ("int $0x25 ; setc %0 ; popfw":"=abcdm" (err) - :"a"(drive - 1), "b"(&dio), "c"(-1), "d"(buf), "m"(dio)); + if (dos_version >= 0x0710) { + asm volatile("int $0x21 ; setc %0" + : "=bcdm" (err), "=a" (errnum) + : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive), + "S" (0), "m" (dio)); + } else { + asm volatile("int $0x25 ; setc %0 ; popfw" + : "=bcdm" (err), "=a" (errnum) + : "a" (drive-1), "b" (&dio), "c" (-1), "d" (buf), + "m" (dio) + : "esi"); + } - if (err) + if (err) { + dprintf("rv = %04x\n", errnum); die("sector read error"); + } } /* Both traditional DOS and FAT32 DOS return this structure, but @@ -218,15 +248,17 @@ uint32_t get_partition_offset(int drive) dp.specfunc = 1; /* Get current information */ rv = 0x440d; - asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv), "=m"(dp) - :"b"(drive), "c"(0x0860), "d"(&dp)); + asm volatile ("int $0x21 ; setc %0" + :"=abcdm" (err), "+a"(rv), "=m"(dp) + :"b" (drive), "c" (0x0860), "d" (&dp)); if (!err) return dp.hiddensecs; rv = 0x440d; - asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv), "=m"(dp) - :"b"(drive), "c"(0x4860), "d"(&dp)); + asm volatile ("int $0x21 ; setc %0" + : "=abcdm" (err), "+a" (rv), "=m" (dp) + : "b" (drive), "c" (0x4860), "d" (&dp)); if (!err) return dp.hiddensecs; @@ -259,22 +291,26 @@ void write_mbr(int drive, const void *buf) uint16_t rv; uint8_t err; - dprintf("write_mbr(%d,%p)\n", drive, buf); + dprintf("write_mbr(%d,%p)", drive, buf); mbr.bufferoffset = (uintptr_t) buf; mbr.bufferseg = data_segment(); rv = 0x440d; - asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv) + asm volatile ("int $0x21 ; setc %0" : "=bcdm" (err), "+a"(rv) :"c"(0x0841), "d"(&mbr), "b"(drive), "m"(mbr)); - if (!err) + dprintf(" rv(0841) = %04x", rv); + if (!err) { + dprintf("\n"); return; + } rv = 0x440d; - asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv) + asm volatile ("int $0x21 ; setc %0" : "=bcdm" (err), "+a"(rv) :"c"(0x4841), "d"(&mbr), "b"(drive), "m"(mbr)); + dprintf(" rv(4841) = %04x\n", rv); if (err) die("mbr write error"); } @@ -293,15 +329,29 @@ void read_mbr(int drive, const void *buf) asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv) :"c"(0x0861), "d"(&mbr), "b"(drive), "m"(mbr)); - if (!err) + dprintf(" rv(0861) = %04x", rv); + if (!err) { + dprintf("\n"); return; + } rv = 0x440d; asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv) :"c"(0x4861), "d"(&mbr), "b"(drive), "m"(mbr)); + dprintf(" rv(4841) = %04x\n", rv); if (err) die("mbr read error"); + + dprintf("Bytes: %02x %02x %02x %02x %02x %02x %02x %02x\n", + ((const uint8_t *)buf)[0], + ((const uint8_t *)buf)[1], + ((const uint8_t *)buf)[2], + ((const uint8_t *)buf)[3], + ((const uint8_t *)buf)[4], + ((const uint8_t *)buf)[5], + ((const uint8_t *)buf)[6], + ((const uint8_t *)buf)[7]); } /* This call can legitimately fail, and we don't care, so ignore error return */ @@ -359,10 +409,11 @@ void lock_device(int level) while ((lock_level >> 8) < level) { uint16_t new_level = lock_level + 0x0100; - dprintf("Trying lock %04x...\n", new_level); - rv = 0x444d; - asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv) - :"b"(new_level), "c"(lock_call), "d"(0x0001)); + dprintf("Trying lock %04x... ", new_level); + rv = 0x440d; + asm volatile ("int $0x21 ; setc %0" : "=bcdm" (err), "+a"(rv) + : "b" (new_level), "c" (lock_call), "d" (0x0001)); + dprintf("%s %04x\n", err ? "err" : "ok", rv); if (err) { /* rv == 0x0001 means this call is not supported, if so we assume locking isn't needed (e.g. Win9x in DOS-only mode) */ @@ -396,8 +447,10 @@ void unlock_device(int level) while ((lock_level >> 8) > level) { uint16_t new_level = lock_level - 0x0100; rv = 0x440d; - asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv) - :"b"(new_level), "c"(unlock_call)); + dprintf("Trying unlock %04x... ", new_level); + asm volatile ("int $0x21 ; setc %0" : "=bcdm" (err), "+a"(rv) + : "b" (new_level), "c" (unlock_call)); + dprintf("%s %04x\n", err ? "err" : "ok", rv); lock_level = new_level; } } @@ -438,6 +491,8 @@ static void adjust_mbr(int device, int writembr, int set_active) struct mbr_entry *me = (struct mbr_entry *)(sectbuf + 446); int found = 0; + dprintf("Searching for partition offset: %08x\n", offset); + for (i = 0; i < 4; i++) { if (me->startlba == offset) { me->active = 0x80; @@ -449,7 +504,7 @@ static void adjust_mbr(int device, int writembr, int set_active) } if (found < 1) { - die("partition not found"); + die("partition not found (-a is not implemented for logical partitions)"); } else if (found > 1) { die("multiple aliased partitions found"); } @@ -556,10 +611,11 @@ int main(int argc, char *argv[]) ldlinux_name[0] = dev_fd | 0x40; - set_attributes(ldlinux_name, 0); - fd = creat(ldlinux_name, 0x07); /* SYSTEM HIDDEN READONLY */ + set_attributes(ldlinux_name, 0x00); + fd = creat(ldlinux_name, 0); write_file(fd, syslinux_ldlinux, syslinux_ldlinux_len); close(fd); + set_attributes(ldlinux_name, 0x07); /* SYSTEM HIDDEN READONLY */ /* * Now, use libfat to create a block map. This probably @@ -631,7 +687,7 @@ int main(int argc, char *argv[]) /* * Write the now-patched first sector of ldlinux.sys */ - lock_device(3); + /* lock_device(3); -- doesn't seem to be needed */ write_device(dev_fd, syslinux_ldlinux, 1, sectors[0]); /* -- cgit v1.2.3 From fc9c70d47083adcb3c2fae440c44a1dc4895a8fd Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 10 Nov 2009 23:43:19 -0800 Subject: dos: try to handle both raw DOS mode and Windows mode The locking API works very different in raw DOS mode and in Windows mode. The hierarchial locking is only available in the latter mode; in the former mode we can only use levels 0 and 4. Signed-off-by: H. Peter Anvin --- dos/syslinux.c | 114 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 31 deletions(-) (limited to 'dos') diff --git a/dos/syslinux.c b/dos/syslinux.c index 4adbd381..31797075 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -32,8 +32,15 @@ uint16_t dos_version; #ifdef DEBUG # define dprintf printf +void pause(void) +{ + uint16_t ax; + + asm volatile("int $0x16" : "=a" (ax) : "a" (0)); +} #else # define dprintf(...) ((void)0) +# define pause() ((void)0) #endif void __attribute__ ((noreturn)) usage(void) @@ -320,7 +327,7 @@ void read_mbr(int drive, const void *buf) uint16_t rv; uint8_t err; - dprintf("read_mbr(%d,%p)\n", drive, buf); + dprintf("read_mbr(%d,%p)", drive, buf); mbr.bufferoffset = (uintptr_t) buf; mbr.bufferseg = data_segment(); @@ -377,55 +384,95 @@ int libfat_xpread(intptr_t pp, void *buf, size_t secsize, static inline void get_dos_version(void) { - uint16_t ver = 0x3001; -asm("int $0x21 ; xchgb %%ah,%%al": "+a"(ver): :"ebx", "ecx"); + 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); } /* The locking interface relies on static variables. A massive hack :( */ -static uint16_t lock_level; +static uint8_t lock_level, lock_drive; static inline void set_lock_device(uint8_t device) { - lock_level = device; + lock_level = 0; + lock_drive = device; } -void lock_device(int level) +static int do_lock(uint8_t level) { + uint16_t level_arg = lock_drive + (level << 8); uint16_t rv; uint8_t err; - uint16_t lock_call; - - if (dos_version < 0x0700) - return; /* Win9x/NT only */ - #if 0 /* DOS 7.10 = Win95 OSR2 = first version with FAT32 */ - lock_call = (dos_version >= 0x0710) ? 0x484A : 0x084A; + uint16_t lock_call = (dos_version >= 0x0710) ? 0x484A : 0x084A; #else - lock_call = 0x084A; /* MSDN says this is OK for all filesystems */ + uint16_t lock_call = 0x084A; /* MSDN says this is OK for all filesystems */ #endif - while ((lock_level >> 8) < level) { - uint16_t new_level = lock_level + 0x0100; - dprintf("Trying lock %04x... ", new_level); - rv = 0x440d; - asm volatile ("int $0x21 ; setc %0" : "=bcdm" (err), "+a"(rv) - : "b" (new_level), "c" (lock_call), "d" (0x0001)); - dprintf("%s %04x\n", err ? "err" : "ok", rv); + dprintf("Trying lock %04x... ", level_arg); + asm volatile ("int $0x21 ; setc %0" + : "=bcdm" (err), "=a" (rv) + : "a" (0x440d), "b" (level_arg), + "c" (lock_call), "d" (0x0001)); + dprintf("%s %04x\n", err ? "err" : "ok", rv); + + return err ? rv : 0; +} + +void lock_device(int level) +{ + static int hard_lock = 0; + int err; + + if (dos_version < 0x0700) + return; /* Win9x/NT only */ + + if (!hard_lock) { + /* Assume hierarchial "soft" locking supported */ + + while ((lock_level >> 8) < level) { + int new_level = lock_level + 1; + err = do_lock(new_level); + if (err) { + if (err == 0x0001) { + /* Try hard locking next */ + hard_lock = 1; + } + goto soft_fail; + } + + lock_level = new_level; + } + return; + } + +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) { - /* rv == 0x0001 means this call is not supported, if so we - assume locking isn't needed (e.g. Win9x in DOS-only mode) */ - if (rv == 0x0001) + if (err == 0x0001) { + /* Assume locking is not needed */ return; - else - die("could not lock device"); + } + goto hard_fail; } - lock_level = new_level; + lock_level = 4; + return; } - return; + +hard_fail: + die("could not lock device"); } void unlock_device(int level) @@ -444,12 +491,17 @@ void unlock_device(int level) unlock_call = 0x086A; /* MSDN says this is OK for all filesystems */ #endif - while ((lock_level >> 8) > level) { - uint16_t new_level = lock_level - 0x0100; + if (lock_level == 4 && level > 0) + return; /* Only drop the hard lock at the end */ + + while (lock_level > level) { + uint8_t new_level = (lock_level == 4) ? 0 : lock_level - 1; + uint16_t level_arg = (new_level << 8) + lock_drive; rv = 0x440d; dprintf("Trying unlock %04x... ", new_level); - asm volatile ("int $0x21 ; setc %0" : "=bcdm" (err), "+a"(rv) - : "b" (new_level), "c" (unlock_call)); + asm volatile ("int $0x21 ; setc %0" + : "=bcdm" (err), "+a" (rv) + : "b" (level_arg), "c" (unlock_call)); dprintf("%s %04x\n", err ? "err" : "ok", rv); lock_level = new_level; } -- cgit v1.2.3 From d1169ea4907b9b4a8cd73ed60d4e96160d05212f Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 10 Nov 2009 23:50:10 -0800 Subject: dos: fix the soft-locking loop Code the soft-locking loop correctly. Signed-off-by: H. Peter Anvin --- dos/syslinux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dos') diff --git a/dos/syslinux.c b/dos/syslinux.c index 31797075..1cdf418b 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -437,7 +437,7 @@ void lock_device(int level) if (!hard_lock) { /* Assume hierarchial "soft" locking supported */ - while ((lock_level >> 8) < level) { + while (lock_level < level) { int new_level = lock_level + 1; err = do_lock(new_level); if (err) { -- cgit v1.2.3 From e79ba125c9c8eb3816d164d86b5264b21868f7af Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 11 Nov 2009 15:52:37 -0800 Subject: dos: DOS version 7.10 is 0x070a, not 0x0710... Fix DOS version 7.10 (first FAT32-capable version) check. Perhaps we should just call the FAT32 calls blindly and fall back to the old calls if they fail? Signed-off-by: H. Peter Anvin --- dos/syslinux.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'dos') diff --git a/dos/syslinux.c b/dos/syslinux.c index 1cdf418b..d054c4ce 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -171,7 +171,7 @@ void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector) dio.bufoffs = (uintptr_t) buf; dio.bufseg = data_segment(); - if (dos_version >= 0x0710) { + if (dos_version >= 0x070a) { asm volatile("int $0x21 ; setc %0" : "=bcdm" (err), "=a" (errnum) : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive), @@ -204,7 +204,7 @@ void read_device(int drive, const void *buf, size_t nsecs, unsigned int sector) dio.bufoffs = (uintptr_t) buf; dio.bufseg = data_segment(); - if (dos_version >= 0x0710) { + if (dos_version >= 0x070a) { asm volatile("int $0x21 ; setc %0" : "=bcdm" (err), "=a" (errnum) : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive), @@ -411,7 +411,7 @@ static int do_lock(uint8_t level) uint8_t err; #if 0 /* DOS 7.10 = Win95 OSR2 = first version with FAT32 */ - uint16_t lock_call = (dos_version >= 0x0710) ? 0x484A : 0x084A; + uint16_t lock_call = (dos_version >= 0x070a) ? 0x484A : 0x084A; #else uint16_t lock_call = 0x084A; /* MSDN says this is OK for all filesystems */ #endif @@ -486,7 +486,7 @@ void unlock_device(int level) #if 0 /* DOS 7.10 = Win95 OSR2 = first version with FAT32 */ - unlock_call = (dos_version >= 0x0710) ? 0x486A : 0x086A; + unlock_call = (dos_version >= 0x070a) ? 0x486A : 0x086A; #else unlock_call = 0x086A; /* MSDN says this is OK for all filesystems */ #endif -- cgit v1.2.3 From e5a014f403aabb9400f309a0bef08288d6421107 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 11 Nov 2009 16:05:34 -0800 Subject: dos: always try the FAT32-aware direct I/O calls first Always try the FAT32-aware direct I/O calls before trying the legacy raw I/O calls. The reason for doing this is that the FAT32 stuff may be implemented as an add-on. Signed-off-by: H. Peter Anvin --- dos/syslinux.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'dos') diff --git a/dos/syslinux.c b/dos/syslinux.c index d054c4ce..ca2fd8e1 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -171,13 +171,15 @@ void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector) dio.bufoffs = (uintptr_t) buf; dio.bufseg = data_segment(); - if (dos_version >= 0x070a) { - asm volatile("int $0x21 ; setc %0" - : "=bcdm" (err), "=a" (errnum) - : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive), - "S" (1), "m" (dio) - : "memory"); - } else { + /* Try FAT32-aware system call first */ + asm volatile("int $0x21 ; setc %0" + : "=bcdm" (err), "=a" (errnum) + : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive), + "S" (1), "m" (dio) + : "memory"); + + if (err && errnum == 0x0001) { + /* Try legacy system call */ asm volatile("int $0x26 ; setc %0 ; popfw" : "=bcdm" (err), "=a" (errnum) : "a" (drive-1), "b" (&dio), "c" (-1), "d" (buf), @@ -204,12 +206,14 @@ void read_device(int drive, const void *buf, size_t nsecs, unsigned int sector) dio.bufoffs = (uintptr_t) buf; dio.bufseg = data_segment(); - if (dos_version >= 0x070a) { - asm volatile("int $0x21 ; setc %0" - : "=bcdm" (err), "=a" (errnum) - : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive), - "S" (0), "m" (dio)); - } else { + /* Try FAT32-aware system call first */ + asm volatile("int $0x21 ; setc %0" + : "=bcdm" (err), "=a" (errnum) + : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive), + "S" (0), "m" (dio)); + + if (err && errnum == 0x0001) { + /* Try legacy system call */ asm volatile("int $0x25 ; setc %0 ; popfw" : "=bcdm" (err), "=a" (errnum) : "a" (drive-1), "b" (&dio), "c" (-1), "d" (buf), -- cgit v1.2.3 From cbc7af0a4246fd5caad90ed3a6812a8f227e87c5 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 11 Nov 2009 16:28:20 -0800 Subject: dos: drop unneeded .eh_frame section gcc will produce an .eh_frame section, which we have no use for. Signed-off-by: H. Peter Anvin --- dos/Makefile | 2 +- dos/com16.ld | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'dos') diff --git a/dos/Makefile b/dos/Makefile index 56d2e076..2f1b7981 100644 --- a/dos/Makefile +++ b/dos/Makefile @@ -49,7 +49,7 @@ spotless: clean installer: -syslinux.elf: $(OBJS) libcom.a +syslinux.elf: $(OBJS) libcom.a com16.ld $(LD) $(LDFLAGS) -o $@ $^ libcom.a: $(LIBOBJS) diff --git a/dos/com16.ld b/dos/com16.ld index 08a1e95e..5f82b73a 100644 --- a/dos/com16.ld +++ b/dos/com16.ld @@ -123,5 +123,8 @@ SECTIONS .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } - /DISCARD/ : { *(.note.GNU-stack) } + /DISCARD/ : { + *(.note.GNU-stack) + *(.eh_frame) + } } -- cgit v1.2.3 From 6ee958bf9f830b59fd10d3a83c0fa1d5f30d4809 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 11 Nov 2009 16:29:53 -0800 Subject: dos: don't add the linker script twice on the ld command line My version of the linker can deal with it, but others might not be so smart. Signed-off-by: H. Peter Anvin --- dos/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dos') diff --git a/dos/Makefile b/dos/Makefile index 2f1b7981..6d87d64a 100644 --- a/dos/Makefile +++ b/dos/Makefile @@ -50,7 +50,7 @@ spotless: clean installer: syslinux.elf: $(OBJS) libcom.a com16.ld - $(LD) $(LDFLAGS) -o $@ $^ + $(LD) $(LDFLAGS) -o $@ $(filter-out %.ld,$^) libcom.a: $(LIBOBJS) -rm -f $@ -- cgit v1.2.3 From fcd383ae04ef0382ad93b83ba82112104aa986e0 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 13 Nov 2009 13:40:35 -0800 Subject: dos: int 25/26 may be register-dirty; wrap them in assembly int 25h and int 26h are known to be register-dirty for some versions of DOS -- unlike int 21h, which is usually clean. As such, wrap those in assembly functions. Signed-off-by: H. Peter Anvin --- dos/Makefile | 3 ++- dos/int2526.S | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dos/mystuff.h | 10 ++++++++ dos/syslinux.c | 44 +++++++++++----------------------- 4 files changed, 102 insertions(+), 31 deletions(-) create mode 100644 dos/int2526.S (limited to 'dos') diff --git a/dos/Makefile b/dos/Makefile index 6d87d64a..9d8ce33c 100644 --- a/dos/Makefile +++ b/dos/Makefile @@ -30,7 +30,8 @@ SRCS = syslinux.c \ ../libinstaller/mbr_bin.c \ $(wildcard ../libfat/*.c) OBJS = crt0.o $(patsubst %.c,%.o,$(notdir $(SRCS))) -LIBOBJS = conio.o memcpy.o memset.o skipatou.o atou.o malloc.o free.o \ +LIBOBJS = int2526.o conio.o memcpy.o memset.o skipatou.o atou.o \ + malloc.o free.o \ argv.o printf.o __divdi3.o __udivmoddi4.o VPATH = .:../libfat:../libinstaller diff --git a/dos/int2526.S b/dos/int2526.S new file mode 100644 index 00000000..bcb7707e --- /dev/null +++ b/dos/int2526.S @@ -0,0 +1,76 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * int 0x25 and 0x26 direct sector access + * + * Use assembly wrapper functions for these system calls, since unlike + * int 0x21 calls they are "dirty" and can destroy unrelated registers. + * + * NOTE: these all assume the data buffer is in the data segment, i.e. + * %ds == %es == dio.bufseg. + * + * Usage: int int25_read_sector(drive, dio) + * Usage: int int26_write_sector(drive, dio) + */ + + .code16gcc + .text + + .globl int25_read_sector + .type int25_read_sector, @function +int25_read_sector: + pushl %ebp + pushl %edi + pushl %esi + pushl %ebx + + decw %ax /* AL = drive number (0 = A:) */ + movw %dx, %bx /* BX = dio structure */ + movw 6(%bx), %dx /* DX = data buffer */ + movw $-1, %cx + int $0x25 + jc 1f + xorw %ax, %ax /* Error code: 0 = no error */ +1: + popfw + movzwl %ax, %eax + popl %ebx + popl %esi + popl %edi + popl %ebp + retl + + .globl int26_write_sector + .type int26_write_sector, @function +int26_write_sector: + pushl %ebp + pushl %edi + pushl %esi + pushl %ebx + + decw %ax /* AL = drive number (0 = A:) */ + movw %dx, %bx /* BX = dio structure */ + movw 6(%bx), %dx /* DX = data buffer */ + movw $-1, %cx + int $0x26 + jc 1f + xorw %ax, %ax /* Error code: 0 = no error */ +1: + popfw + movzwl %ax, %eax + popl %ebx + popl %esi + popl %edi + popl %ebp + retl diff --git a/dos/mystuff.h b/dos/mystuff.h index fbf4e75b..25344413 100644 --- a/dos/mystuff.h +++ b/dos/mystuff.h @@ -1,6 +1,8 @@ #ifndef MYSTUFF_H #define MYSTUFF_H +#include + #define NULL ((void *)0) unsigned int skip_atou(const char **s); @@ -11,4 +13,12 @@ static inline int isdigit(int ch) return (ch >= '0') && (ch <= '9'); } +struct diskio { + uint32_t startsector; + uint16_t sectors; + uint16_t bufoffs, bufseg; +} __attribute__ ((packed)); +int int25_read_sector(unsigned char drive, struct diskio *dio); +int int26_write_sector(unsigned char drive, struct diskio *dio); + #endif /* MYSTUFF_H */ diff --git a/dos/syslinux.c b/dos/syslinux.c index ca2fd8e1..650c48f6 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -152,15 +152,8 @@ uint16_t data_segment(void) return ds; } -struct diskio { - uint32_t startsector; - uint16_t sectors; - uint16_t bufoffs, bufseg; -} __attribute__ ((packed)); - void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector) { - uint8_t err; uint16_t errnum; struct diskio dio; @@ -172,22 +165,18 @@ void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector) dio.bufseg = data_segment(); /* Try FAT32-aware system call first */ - asm volatile("int $0x21 ; setc %0" - : "=bcdm" (err), "=a" (errnum) + asm volatile("int $0x21 ; jc 1f ; xorw %0,%0\n" + "1:" + : "=a" (errnum) : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive), "S" (1), "m" (dio) : "memory"); - if (err && errnum == 0x0001) { - /* Try legacy system call */ - asm volatile("int $0x26 ; setc %0 ; popfw" - : "=bcdm" (err), "=a" (errnum) - : "a" (drive-1), "b" (&dio), "c" (-1), "d" (buf), - "m" (dio) - : "esi", "memory"); - } + /* If not supported, try the legacy system call (int2526.S) */ + if (errnum == 0x0001) + errnum = int26_write_sector(drive, &dio); - if (err) { + if (errnum) { dprintf("rv = %04x\n", errnum); die("sector write error"); } @@ -195,7 +184,6 @@ void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector) void read_device(int drive, const void *buf, size_t nsecs, unsigned int sector) { - uint8_t err; uint16_t errnum; struct diskio dio; @@ -207,21 +195,17 @@ void read_device(int drive, const void *buf, size_t nsecs, unsigned int sector) dio.bufseg = data_segment(); /* Try FAT32-aware system call first */ - asm volatile("int $0x21 ; setc %0" - : "=bcdm" (err), "=a" (errnum) + asm volatile("int $0x21 ; jc 1f ; xorw %0,%0\n" + "1:" + : "=a" (errnum) : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive), "S" (0), "m" (dio)); - if (err && errnum == 0x0001) { - /* Try legacy system call */ - asm volatile("int $0x25 ; setc %0 ; popfw" - : "=bcdm" (err), "=a" (errnum) - : "a" (drive-1), "b" (&dio), "c" (-1), "d" (buf), - "m" (dio) - : "esi"); - } + /* If not supported, try the legacy system call (int2526.S) */ + if (errnum == 0x0001) + errnum = int25_read_sector(drive, &dio); - if (err) { + if (errnum) { dprintf("rv = %04x\n", errnum); die("sector read error"); } -- cgit v1.2.3