summaryrefslogtreecommitdiff
path: root/dos
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-11-13 13:40:35 -0800
committerH. Peter Anvin <hpa@zytor.com>2009-11-13 13:44:08 -0800
commitfcd383ae04ef0382ad93b83ba82112104aa986e0 (patch)
treee776b8ac21a52f41a3924806ebaf42594ce45c23 /dos
parent6ee958bf9f830b59fd10d3a83c0fa1d5f30d4809 (diff)
downloadsyslinux-fcd383ae04ef0382ad93b83ba82112104aa986e0.tar.gz
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 <hpa@zytor.com>
Diffstat (limited to 'dos')
-rw-r--r--dos/Makefile3
-rw-r--r--dos/int2526.S76
-rw-r--r--dos/mystuff.h10
-rw-r--r--dos/syslinux.c44
4 files changed, 102 insertions, 31 deletions
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 <inttypes.h>
+
#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");
}