diff options
author | H. Peter Anvin <hpa@zytor.com> | 2009-11-13 13:40:35 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-11-13 13:44:08 -0800 |
commit | fcd383ae04ef0382ad93b83ba82112104aa986e0 (patch) | |
tree | e776b8ac21a52f41a3924806ebaf42594ce45c23 /dos | |
parent | 6ee958bf9f830b59fd10d3a83c0fa1d5f30d4809 (diff) | |
download | syslinux-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/Makefile | 3 | ||||
-rw-r--r-- | dos/int2526.S | 76 | ||||
-rw-r--r-- | dos/mystuff.h | 10 | ||||
-rw-r--r-- | dos/syslinux.c | 44 |
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"); } |