Introduce biosdiskreset(), and call it to reset the disk (with Int
0x13 Function 0) after a read error. This is a requirement mentioned in most BIOS documentation. This answers PR 18591. Incidentally, on the Soekris Engineering net45x1 single-board computer, this fixes a bug where the bootloader corrupts the kernel while loading it from certain varieties of CompactFlash card (especially varieties identified by NetBSD as <TOSHIBA THNCF064MBA>).
This commit is contained in:
parent
5ad5ca60a5
commit
e57ba8d648
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: bios_disk.S,v 1.8 2000/05/21 16:59:28 perry Exp $ */
|
||||
/* $NetBSD: bios_disk.S,v 1.9 2002/10/10 18:52:42 dyoung Exp $ */
|
||||
|
||||
/*
|
||||
* Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
|
||||
@ -58,6 +58,41 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
#define addr32 .byte 0x67
|
||||
#define data32 .byte 0x66
|
||||
|
||||
/*
|
||||
# BIOS call "INT 0x13 Function 0x0" to reset the disk subsystem
|
||||
# Call with %ah = 0x0
|
||||
# %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
|
||||
# Return:
|
||||
# %al = 0x0 on success; err code on failure
|
||||
*/
|
||||
ENTRY(biosdiskreset)
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
pushl %ebx
|
||||
push %edx
|
||||
push %edi
|
||||
|
||||
movb 8(%ebp), %dl # device
|
||||
|
||||
call _C_LABEL(prot_to_real) # enter real mode
|
||||
|
||||
movb $0x0, %ah # subfunction
|
||||
int $0x13
|
||||
setc %bl
|
||||
movb %ah, %bh # save error code
|
||||
|
||||
data32
|
||||
call _C_LABEL(real_to_prot) # back to protected mode
|
||||
|
||||
xorl %eax, %eax
|
||||
movw %bx, %ax # return value in %ax
|
||||
|
||||
pop %edi
|
||||
pop %edx
|
||||
popl %ebx
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
/*
|
||||
# BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
|
||||
# Call with %ah = 0x2
|
||||
@ -69,6 +104,9 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
# %es:%bx = segment:offset of buffer
|
||||
# Return:
|
||||
# %al = 0x0 on success; err code on failure
|
||||
#
|
||||
# Note: On failure, you must reset the disk with biosdiskreset() before
|
||||
# sending another command.
|
||||
*/
|
||||
ENTRY(biosread)
|
||||
pushl %ebp
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: biosdisk_ll.c,v 1.11 2001/07/07 22:57:57 perry Exp $ */
|
||||
/* $NetBSD: biosdisk_ll.c,v 1.12 2002/10/10 18:52:42 dyoung Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996
|
||||
@ -50,6 +50,7 @@ extern long ourseg;
|
||||
extern int get_diskinfo __P((int));
|
||||
extern void int13_getextinfo __P((int, struct biosdisk_ext13info *));
|
||||
extern int int13_extension __P((int));
|
||||
extern int biosdiskreset __P((int));
|
||||
extern int biosread __P((int, int, int, int, int, char *));
|
||||
extern int biosextread __P((int, void *));
|
||||
static int do_read __P((struct biosdisk_ll *, int, int, char *));
|
||||
@ -130,8 +131,10 @@ do_read(d, dblk, num, buf)
|
||||
ext.seg = ourseg;
|
||||
ext.sec = dblk;
|
||||
|
||||
if (biosextread(d->dev, &ext))
|
||||
if (biosextread(d->dev, &ext)) {
|
||||
(void)biosdiskreset(d->dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ext.cnt;
|
||||
} else {
|
||||
@ -144,8 +147,10 @@ do_read(d, dblk, num, buf)
|
||||
if (nsec > num)
|
||||
nsec = num;
|
||||
|
||||
if (biosread(d->dev, cyl, head, sec, nsec, buf))
|
||||
if (biosread(d->dev, cyl, head, sec, nsec, buf)) {
|
||||
(void)biosdiskreset(d->dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nsec;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user