mirror of
https://git.savannah.gnu.org/git/grub.git
synced 2026-10-21 14:59:34 +00:00
cleanups for low level disk I/O and a minor bug fix
This commit is contained in:
1 parent
08ca05f500
commit
0daef3e856
21 files changed
+6741
-741
No files matched your search
+321
-332
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
|
||||
* Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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
|
||||
@@ -335,370 +336,292 @@ realcseg:
|
||||
|
||||
|
||||
/*
|
||||
* biosdisk(write, drive, geometry, sector, nsec, segment)
|
||||
* Read/write "nsec" sectors from disk to real segment "segment"
|
||||
* offset zero
|
||||
* int biosdisk_int13_extensions (int ah, int drive, void *dap)
|
||||
*
|
||||
* Will try INT 0x13 LBA (AH=0x42/0x43) or standard (AH=0x2/0x3)
|
||||
* depending on probed geometry. For addresses out of the translated
|
||||
* area, it returns BIOS_GEOMETRY_ERROR.
|
||||
* Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
|
||||
* is passed for disk address packet. If an error occurs, return
|
||||
* non-zero, otherwise zero.
|
||||
*/
|
||||
|
||||
ENTRY(biosdisk)
|
||||
push %ebp
|
||||
mov %esp, %ebp
|
||||
ENTRY(biosdisk_int13_extensions)
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
|
||||
push %ebx
|
||||
push %ecx
|
||||
push %edx
|
||||
push %esi
|
||||
push %edi
|
||||
|
||||
/* Check whether we have LBA. */
|
||||
movl 0x10(%ebp), %eax
|
||||
andb 0xc(%eax), %eax
|
||||
andl $BIOSDISK_FLAG_LBA_EXTENSION, %eax
|
||||
jz disk_compute_args /* nope. */
|
||||
|
||||
/* set up disk address packet for extended calls (LBA mode) */
|
||||
movl 0x14(%ebp), %eax /* absolute block number */
|
||||
movl %eax, dap_block
|
||||
xorl %eax, %eax
|
||||
movl %eax, dap_block + 4
|
||||
|
||||
movb 0x18(%ebp), %al /* number of sectors */
|
||||
movw %ax, dap_blocks
|
||||
|
||||
/* set up the buffer address */
|
||||
xorl %eax, %eax
|
||||
movw 0x1c(%ebp), %ax /* segment */
|
||||
shll $16, %eax
|
||||
movl %eax, dap_buffer
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
pushl %esi
|
||||
|
||||
/* compute the address of disk_address_packet */
|
||||
movl $disk_address_packet, %eax
|
||||
movl 0x10(%ebp), %eax
|
||||
movw %ax, %si
|
||||
xorw %ax, %ax
|
||||
shrl $4, %eax
|
||||
movw %ax, %cx /* save the segment to cx */
|
||||
movw %ax, %cx /* save the segment to cx */
|
||||
|
||||
xorb %bl, %bl
|
||||
movb 0x8(%ebp), %bh /* read=0, write=1 */
|
||||
addb $0x42, %bh /* convert to extended subfunction */
|
||||
|
||||
movb 0xc(%ebp), %dl /* drive */
|
||||
|
||||
call EXT_C(prot_to_real) /* enter real mode */
|
||||
/* drive */
|
||||
movb 0xc(%ebp), %dl
|
||||
/* ah */
|
||||
movb 0x8(%ebp), %dh
|
||||
/* enter real mode */
|
||||
call EXT_C(prot_to_real)
|
||||
|
||||
.code16
|
||||
|
||||
movb %dh, %ah
|
||||
movw %cx, %ds
|
||||
movw %bx, %ax
|
||||
int $0x13 /* do the operation */
|
||||
|
||||
/* FIXME: force people to help test LBA support before releasing 0.6 */
|
||||
#define NO_INT13_FALLBACK 1
|
||||
#ifdef NO_INT13_FALLBACK
|
||||
/* Save return value. */
|
||||
movb %ah, %bl
|
||||
int $0x13 /* do the operation */
|
||||
movb %ah, %dl /* save return value */
|
||||
/* clear the data segment */
|
||||
xorw %ax, %ax
|
||||
movw %ax, %ds
|
||||
/* back to protected mode */
|
||||
data32
|
||||
jmp disk_exit_16
|
||||
#else
|
||||
/* set success return value */
|
||||
movb $0, %bl
|
||||
|
||||
/* did we actually succeed? */
|
||||
data32
|
||||
jnc disk_exit_16
|
||||
|
||||
data32
|
||||
call EXT_C(real_to_prot) /* back to protected mode */
|
||||
#endif
|
||||
call EXT_C(real_to_prot)
|
||||
.code32
|
||||
|
||||
/* either failed, or a floppy, so try standard BIOS calls */
|
||||
disk_compute_args:
|
||||
/*
|
||||
* GEOMETRY is a structure representing the BIOS geometry:
|
||||
* 32 bit flags (bytes 12-15)
|
||||
* 32 bit cylinders (bytes 8-11)
|
||||
* 32 bit heads (bytes 4-7)
|
||||
* 32 bit sectors (bytes 0-3)
|
||||
*/
|
||||
movb %dl, %al /* return value in %eax */
|
||||
|
||||
/* set up original sector number */
|
||||
xorl %edx, %edx
|
||||
movl 0x14(%ebp), %eax
|
||||
|
||||
/* get the pointer to GEOMETRY */
|
||||
movl 0x10(%ebp), %edi
|
||||
|
||||
/* get sector offset, place in %ecx */
|
||||
movl 0x8(%edi), %ebx
|
||||
divl %ebx
|
||||
movl %edx, %ecx
|
||||
|
||||
/* get track offset (head number) in %edx,
|
||||
and cylinder offset in %eax */
|
||||
xorl %edx, %edx
|
||||
movl 0x4(%edi), %ebx
|
||||
divl %ebx
|
||||
|
||||
/* check cylinder offset, is there a geometry problem here? */
|
||||
movl (%edi), %ebx
|
||||
cmpl %ebx, %eax
|
||||
|
||||
/* if not, go on to standard read function */
|
||||
jl disk_use_standard_bios
|
||||
|
||||
movl $BIOSDISK_ERROR_GEOMETRY, %eax
|
||||
jmp disk_exit_32
|
||||
|
||||
.align 4
|
||||
disk_address_packet:
|
||||
.byte 0x10 /* length of packet */
|
||||
.byte 0 /* reserved */
|
||||
dap_blocks:
|
||||
.word 0 /* number of blocks */
|
||||
dap_buffer:
|
||||
.long 0 /* buffer address */
|
||||
dap_block:
|
||||
.long 0 /* absolute block number */
|
||||
.long 0
|
||||
|
||||
/*
|
||||
* This portion implements the BIOS standardized
|
||||
* INT 0x13/AH=<subfunc> interface.
|
||||
*/
|
||||
disk_use_standard_bios:
|
||||
|
||||
shll $8, %edx /* get head number to %dh */
|
||||
xchgl %eax, %ecx /* cylinder to %cx, sector to %al */
|
||||
#ifdef AWARD_INT13_EXTENSIONS
|
||||
/* FIXME: cylinder; bits 10,11 of cyl are in %dh */
|
||||
#endif
|
||||
/* cylinder; bits 8,9 of cyl are in %cl */
|
||||
xchgb %ch, %cl
|
||||
shlb $6, %cl
|
||||
incb %al /* sector; sec starts from 1, not 0 */
|
||||
orb %al, %cl
|
||||
movb 0xc(%ebp), %dl /* drive */
|
||||
|
||||
/* prot_to_real will set %es to 0, so must set it ourselves
|
||||
after it is called */
|
||||
movb 0x18(%ebp), %bl /* number of sectors */
|
||||
movb 0x8(%ebp), %bh /* read=0, write=1 */
|
||||
addb $0x2, %bh /* convert to subfunction */
|
||||
shll $16, %ebx /* shift num sect. and subfunction */
|
||||
movw 0x1c(%ebp), %bx /* segment */
|
||||
|
||||
call EXT_C(prot_to_real) /* enter real mode */
|
||||
.code16
|
||||
|
||||
movw %bx, %es /* load segment */
|
||||
/*
|
||||
* Shift num sectors and subfunction back
|
||||
*/
|
||||
data32
|
||||
shrl $16, %ebx
|
||||
pushw %bx /* save num sectors */
|
||||
xorw %bx, %bx
|
||||
|
||||
movw $3, %si
|
||||
|
||||
disk_loop:
|
||||
popw %ax /* restore num sectors */
|
||||
pushw %ax /* save num sectors */
|
||||
|
||||
/* BIOS call for reading/writing */
|
||||
int $0x13
|
||||
|
||||
/* set success return value */
|
||||
movb $0, %bl
|
||||
|
||||
/* did we actually succeed? */
|
||||
data32
|
||||
jnc disk_exit_16
|
||||
|
||||
/* do we try again? */
|
||||
decw %si
|
||||
cmpw $0, %si
|
||||
|
||||
/* if this isn't the third try, go again */
|
||||
data32
|
||||
jne disk_loop
|
||||
|
||||
/* save return value */
|
||||
movb %ah, %bl
|
||||
|
||||
disk_exit_16:
|
||||
data32
|
||||
call EXT_C(real_to_prot) /* back to protected mode */
|
||||
.code32
|
||||
|
||||
movb %bl, %al /* return value in %eax */
|
||||
|
||||
disk_exit_32:
|
||||
pop %edi
|
||||
pop %esi
|
||||
pop %edx
|
||||
pop %ecx
|
||||
pop %ebx
|
||||
pop %ebp
|
||||
popl %esi
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %ebp
|
||||
|
||||
ret
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* int biosdisk_standard (int ah, int drive, int coff, int hoff, int soff,
|
||||
* int nsec, int segment)
|
||||
*
|
||||
* get_diskinfo(drive, geometry): return a structure that represents the
|
||||
* max number of sectors and heads and cylinders for DRIVE in GEOMETRY.
|
||||
* If an error occures, return non-zero, otherwise return zero.
|
||||
*
|
||||
* Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
|
||||
* NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
|
||||
* return non-zero, otherwise zero.
|
||||
*/
|
||||
|
||||
ENTRY(get_diskinfo)
|
||||
ENTRY(biosdisk_standard)
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
pushl %edi
|
||||
pushl %esi
|
||||
|
||||
movw 0x8(%ebp), %dx /* diskinfo(drive #) */
|
||||
/* set up CHS information */
|
||||
movl 0x10(%ebp), %eax
|
||||
movb %al, %ch
|
||||
movb 0x18(%ebp), %al
|
||||
shlb $2, %al
|
||||
shrw $2, %ax
|
||||
movb %al, %cl
|
||||
movb 0x14(%ebp), %dh
|
||||
/* drive */
|
||||
movb 0xc(%ebp), %dl
|
||||
/* segment */
|
||||
movw 0x20(%ebp), %bx
|
||||
/* save nsec and ah to %di */
|
||||
movb 0x8(%ebp), %ah
|
||||
movb 0x1c(%ebp), %al
|
||||
movw %ax, %di
|
||||
/* enter real mode */
|
||||
call EXT_C(prot_to_real)
|
||||
|
||||
call EXT_C(prot_to_real) /* enter real mode */
|
||||
.code16
|
||||
movw %bx, %es
|
||||
xorw %bx, %bx
|
||||
movw $3, %si /* attempt at least three times */
|
||||
|
||||
movb %dl, %al
|
||||
andb $0x80, %al
|
||||
data32
|
||||
jnz hard_drive
|
||||
1:
|
||||
movw %di, %ax
|
||||
int $0x13 /* do the operation */
|
||||
jnc 2f /* check if successful */
|
||||
|
||||
/*
|
||||
* Perform floppy probe!
|
||||
*/
|
||||
|
||||
movl $probe_values-1, %esi
|
||||
|
||||
probe_loop:
|
||||
/* reset floppy controller INT 13h AH=0 */
|
||||
movb %ah, %bl /* save return value */
|
||||
/* if fail, reset the disk system */
|
||||
xorw %ax, %ax
|
||||
int $0x13
|
||||
|
||||
incw %si
|
||||
movb (%si), %cl
|
||||
|
||||
/* if number of sectors is 0, display error and die */
|
||||
cmpb $0, %cl
|
||||
|
||||
data32
|
||||
je probe_failed
|
||||
|
||||
/* perform read */
|
||||
movw $SCRATCHSEG, %ax
|
||||
movw %ax, %es
|
||||
xorw %bx, %bx
|
||||
movw $0x201, %ax
|
||||
movb $0, %ch
|
||||
movb $0, %dh
|
||||
int $0x13
|
||||
|
||||
data32
|
||||
jc probe_loop
|
||||
|
||||
/* %cl is already the correct value! */
|
||||
movb $1, %dh
|
||||
movb $79, %ch
|
||||
|
||||
xorb %bh, %bh /* no BIOS extensions */
|
||||
data32
|
||||
jmp probe_success
|
||||
|
||||
probe_values:
|
||||
.byte 36, 18, 15, 9, 0
|
||||
|
||||
hard_drive:
|
||||
/* Check for LBA. */
|
||||
movb $0x41, %ah
|
||||
movw $0x55aa, %bx
|
||||
int $0x13 /* int 13 extensions install check */
|
||||
|
||||
data32
|
||||
jc 1f /* invalid function */
|
||||
cmpw $0xaa55, %bx
|
||||
data32
|
||||
jne 1f /* failed magic */
|
||||
|
||||
andb $1, %cx
|
||||
data32
|
||||
jz 1f /* LBA not supported */
|
||||
|
||||
/* Wahoo! Got LBA! */
|
||||
movl $BIOSDISK_FLAG_LBA_EXTENSION, %edi
|
||||
/* FIXME: Should use INT 13 AH=42h */
|
||||
data32
|
||||
jmp 2f
|
||||
|
||||
1: xorl %edi, %edi /* Too bad, no LBA */
|
||||
2: movb $0x8, %ah /* ask for disk info */
|
||||
int $0x13
|
||||
|
||||
data32
|
||||
jc probe_failed
|
||||
|
||||
/* es:di = parameter table */
|
||||
/* carry = 0 */
|
||||
|
||||
probe_success:
|
||||
/*
|
||||
* Store the information for CHS and BIOS extension to registers:
|
||||
* 32 bit BIOS extension -> edi
|
||||
* 32 bit cylinder -> ebx
|
||||
* 32 bit head -> ecx
|
||||
* 32 bit sector -> edx
|
||||
*/
|
||||
#ifdef AWARD_INT13_EXTENSIONS
|
||||
movb %dh, %al /* bits 10,11 of cylinder count */
|
||||
andb $0xc0, %al
|
||||
shlw $2, %ax /* << 2 */
|
||||
#endif
|
||||
movb %cl, %al /* bits 8,9 of cylinder count */
|
||||
andb $0xc0, %al
|
||||
shlw $2, %ax /* << 2 */
|
||||
movb %ch, %al /* Lower 8 bits */
|
||||
movswl %ax, %ebx /* max cylinder */
|
||||
incl %ebx /* number of cylinders */
|
||||
shll $16, %eax /* << 16 */
|
||||
|
||||
#ifdef AWARD_INT13_EXTENSIONS
|
||||
andb $0x3f, %dh /* mask off cylinder gunk */
|
||||
#endif
|
||||
movb %dh, %al /* max head */
|
||||
|
||||
andb $0x3f, %cl /* mask off cylinder gunk */
|
||||
movsbl %cl, %edx /* max sector (and # sectors) */
|
||||
|
||||
movsbl %al, %ecx
|
||||
incl %ecx /* number of heads */
|
||||
|
||||
data32
|
||||
jmp got_drive
|
||||
|
||||
probe_failed:
|
||||
/*
|
||||
* Urk. Call failed. It is not supported for floppies by old
|
||||
* BIOSes, but it should work for all hard drives!!
|
||||
*
|
||||
* Return a 1 here... presume there is no drive present. ????
|
||||
*/
|
||||
|
||||
decw %si
|
||||
cmpw $0, %si
|
||||
je 2f
|
||||
xorb %bl, %bl
|
||||
jmp 1b /* retry */
|
||||
2:
|
||||
/* back to protected mode */
|
||||
data32
|
||||
call EXT_C(real_to_prot)
|
||||
.code32
|
||||
|
||||
movl $1, %eax
|
||||
movb %bl, %al /* return value in %eax */
|
||||
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
|
||||
ret
|
||||
|
||||
|
||||
/*
|
||||
* int check_int13_extensions (int drive)
|
||||
*
|
||||
* Check if LBA is supported for DRIVE. If it is supported, then return
|
||||
* the major version of extensions, otherwise zero.
|
||||
*/
|
||||
|
||||
ENTRY(check_int13_extensions)
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
|
||||
/* drive */
|
||||
movb 0x8(%ebp), %dl
|
||||
/* enter real mode */
|
||||
call EXT_C(prot_to_real)
|
||||
|
||||
.code16
|
||||
movb $0x41, %ah
|
||||
movw $0x55aa, %bx
|
||||
int $0x13 /* do the operation */
|
||||
|
||||
/* check the result */
|
||||
jc 1f
|
||||
cmpw $0xaa55, %bx
|
||||
jne 1f
|
||||
andw $1, %cx
|
||||
jz 1f
|
||||
|
||||
movb %ah, %bl /* save the major version into %bl */
|
||||
jmp 2f
|
||||
1:
|
||||
xorb %bl, %bl
|
||||
2:
|
||||
/* back to protected mode */
|
||||
data32
|
||||
call EXT_C(real_to_prot)
|
||||
.code32
|
||||
|
||||
movb %bl, %al /* return value in %eax */
|
||||
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
popl %ebp
|
||||
|
||||
ret
|
||||
|
||||
|
||||
/*
|
||||
* int get_diskinfo_int13_extensions (int drive, void *drp)
|
||||
*
|
||||
* Return the geometry of DRIVE in a drive parameters, DRP. If an error
|
||||
* occurs, then return non-zero, otherwise zero.
|
||||
*/
|
||||
|
||||
ENTRY(get_diskinfo_int13_extensions)
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
|
||||
pushl %ebx
|
||||
pushl %edx
|
||||
pushl %esi
|
||||
|
||||
/* compute the address of drive parameters */
|
||||
movl 0xc(%ebp), %eax
|
||||
movw %ax, %si
|
||||
xorw %ax, %ax
|
||||
shrl $4, %eax
|
||||
movw %ax, %bx /* save the segment into %bx */
|
||||
/* drive */
|
||||
movb 0x8(%ebp), %dl
|
||||
/* enter real mode */
|
||||
call EXT_C(prot_to_real)
|
||||
|
||||
.code16
|
||||
movb $0x48, %ah
|
||||
movw %bx, %ds
|
||||
int $0x13 /* do the operation */
|
||||
movb %ah, %bl /* save return value in %bl */
|
||||
/* clear the data segment */
|
||||
xorw %ax, %ax
|
||||
movw %ax, %ds
|
||||
/* back to protected mode */
|
||||
data32
|
||||
call EXT_C(real_to_prot)
|
||||
.code32
|
||||
|
||||
movb %bl, %al /* return value in %eax */
|
||||
|
||||
popl %esi
|
||||
popl %edx
|
||||
popl %ebx
|
||||
popl %ebp
|
||||
|
||||
ret
|
||||
|
||||
|
||||
/*
|
||||
* int get_diskinfo_standard (int drive, unsigned long *cylinders,
|
||||
* unsigned long *heads, unsigned long *sectors)
|
||||
*
|
||||
* Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
|
||||
* error occurs, then return non-zero, otherwise zero.
|
||||
*/
|
||||
|
||||
ENTRY(get_diskinfo_standard)
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
pushl %edi
|
||||
|
||||
/* drive */
|
||||
movb 0x8(%ebp), %dl
|
||||
/* enter real mode */
|
||||
call EXT_C(prot_to_real)
|
||||
|
||||
.code16
|
||||
movb $0x8, %ah
|
||||
int $0x13 /* do the operation */
|
||||
movb %ah, %bl /* save return value in %bl */
|
||||
/* back to protected mode */
|
||||
data32
|
||||
call EXT_C(real_to_prot)
|
||||
.code32
|
||||
|
||||
/* restore %ebp */
|
||||
leal 0x10(%esp), %ebp
|
||||
|
||||
/* heads */
|
||||
movb %dh, %al
|
||||
incl %eax /* the number of heads is counted from zero */
|
||||
movl 0x10(%ebp), %edi
|
||||
movl %eax, (%edi)
|
||||
|
||||
/* sectors */
|
||||
xorl %eax, %eax
|
||||
movb %cl, %al
|
||||
andb $0x3f, %al
|
||||
movl 0x14(%ebp), %edi
|
||||
movl %eax, (%edi)
|
||||
|
||||
/* cylinders */
|
||||
shrb $6, %cl
|
||||
movb %cl, %ah
|
||||
movb %ch, %al
|
||||
incl %eax /* the number of cylinders is
|
||||
counted from zero */
|
||||
movl 0xc(%ebp), %edi
|
||||
movl %eax, (%edi)
|
||||
|
||||
xorl %eax, %eax
|
||||
movb %bl, %al /* return value in %eax */
|
||||
|
||||
popl %edi
|
||||
popl %edx
|
||||
popl %ecx
|
||||
@@ -707,23 +630,89 @@ probe_failed:
|
||||
|
||||
ret
|
||||
|
||||
|
||||
/*
|
||||
* int get_diskinfo_floppy (int drive, unsigned long *cylinders,
|
||||
* unsigned long *heads, unsigned long *sectors)
|
||||
*
|
||||
* Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
|
||||
* error occurs, then return non-zero, otherwise zero.
|
||||
*/
|
||||
|
||||
ENTRY(get_diskinfo_floppy)
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
pushl %esi
|
||||
|
||||
/* drive */
|
||||
movb 0x8(%ebp), %dl
|
||||
/* enter real mode */
|
||||
call EXT_C(prot_to_real)
|
||||
|
||||
.code16
|
||||
got_drive:
|
||||
/* init probe value */
|
||||
movl $probe_values-1, %esi
|
||||
1:
|
||||
xorw %ax, %ax
|
||||
int $0x13 /* reset floppy controller */
|
||||
|
||||
incw %si
|
||||
movb (%si), %cl
|
||||
cmpb $0, %cl /* probe failed if zero */
|
||||
je 2f
|
||||
|
||||
/* perform read */
|
||||
movw $SCRATCHSEG, %ax
|
||||
movw %ax, %es
|
||||
xorw %bx, %bx
|
||||
movw $0x0201, %ax
|
||||
movb $0, %ch
|
||||
movb $0, %dh
|
||||
int $0x13
|
||||
|
||||
/* FIXME: Read from floppy may fail even if the geometry is correct.
|
||||
So should retry at least three times. */
|
||||
jc 1b /* next value */
|
||||
|
||||
/* succeed */
|
||||
jmp 2f
|
||||
|
||||
probe_values:
|
||||
.byte 36, 18, 15, 9, 0
|
||||
|
||||
2:
|
||||
/* back to protected mode */
|
||||
data32
|
||||
call EXT_C(real_to_prot) /* back to protected mode */
|
||||
call EXT_C(real_to_prot)
|
||||
.code32
|
||||
|
||||
/* set up return structure */
|
||||
movl 0x0c(%ebp), %eax
|
||||
movl %ebx, (%eax)
|
||||
movl %ecx, 0x04(%eax)
|
||||
movl %edx, 0x08(%eax)
|
||||
movl %edi, 0x0c(%eax)
|
||||
/* restore %ebp */
|
||||
leal 0x10(%esp), %ebp
|
||||
|
||||
xorl %eax, %eax
|
||||
/* cylinders */
|
||||
movl 0xc(%ebp), %eax
|
||||
movl $80, %ebx
|
||||
movl %ebx, (%eax)
|
||||
/* heads */
|
||||
movl 0x10(%ebp), %eax
|
||||
movl $2, %ebx
|
||||
movl %ebx, (%eax)
|
||||
/* sectors */
|
||||
movl 0x14(%ebp), %eax
|
||||
movzbl %cl, %ebx
|
||||
movl %ebx, (%eax)
|
||||
|
||||
/* return value in %eax */
|
||||
xorl %eax, %eax
|
||||
cmpb $0, %cl
|
||||
jne 3f
|
||||
incl %eax /* %eax = 1 (non-zero) */
|
||||
3:
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/* bios.c - implement C part of low-level BIOS disk input and output */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
|
||||
/* These are defined in asm.S, and never be used elsewhere, so declare the
|
||||
prototypes here. */
|
||||
extern int biosdisk_int13_extensions (int ah, int drive, void *dap);
|
||||
extern int biosdisk_standard (int ah, int drive,
|
||||
int coff, int hoff, int soff,
|
||||
int nsec, int segment);
|
||||
extern int check_int13_extensions (int drive);
|
||||
extern int get_diskinfo_int13_extensions (int drive, void *drp);
|
||||
extern int get_diskinfo_standard (int drive,
|
||||
unsigned long *cylinders,
|
||||
unsigned long *heads,
|
||||
unsigned long *sectors);
|
||||
extern int get_diskinfo_floppy (int drive,
|
||||
unsigned long *cylinders,
|
||||
unsigned long *heads,
|
||||
unsigned long *sectors);
|
||||
|
||||
|
||||
/* Read/write NSEC sectors starting from SECTOR in DRIVE disk with GEOMETRY
|
||||
from/into SEGMENT segment. If READ is BIOSDISK_READ, then read it,
|
||||
else if READ is BIOSDISK_WRITE, then write it. If an geometry error
|
||||
occurs, return BIOSDISK_ERROR_GEOMETRY, and if other error occurs, then
|
||||
return the error number. Otherwise, return 0. */
|
||||
int
|
||||
biosdisk (int read, int drive, struct geometry *geometry,
|
||||
int sector, int nsec, int segment)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (geometry->flags & BIOSDISK_FLAG_LBA_EXTENSION)
|
||||
{
|
||||
struct disk_address_packet
|
||||
{
|
||||
unsigned char length;
|
||||
unsigned char reserved;
|
||||
unsigned short blocks;
|
||||
unsigned long buffer;
|
||||
unsigned long long block;
|
||||
} dap;
|
||||
|
||||
if (sector >= geometry->total_sectors)
|
||||
return BIOSDISK_ERROR_GEOMETRY;
|
||||
|
||||
/* FIXME: sizeof (DAP) must be 0x10. Should assert that the compiler
|
||||
can't add any padding. */
|
||||
dap.length = sizeof (dap);
|
||||
dap.block = sector;
|
||||
dap.blocks = nsec;
|
||||
/* This is undocumented part. The address is formated in
|
||||
SEGMENT:ADDRESS. */
|
||||
dap.buffer = segment << 16;
|
||||
|
||||
err = biosdisk_int13_extensions (read + 0x42, drive, &dap);
|
||||
|
||||
#define NO_INT13_FALLBACK 1
|
||||
#ifndef NO_INT13_FALLBACK
|
||||
if (err)
|
||||
{
|
||||
geometry->flags &= ~BIOSDISK_FLAG_LBA_EXTENSION;
|
||||
geometry->total_sectors = (geometry->cylinders
|
||||
* geometry->heads
|
||||
* geometry->sectors);
|
||||
return biosdisk (read, drive, geometry, sector, nsec, segment);
|
||||
}
|
||||
#endif /* ! NO_INT13_FALLBACK */
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int cylinder_offset, head_offset, sector_offset;
|
||||
int head;
|
||||
|
||||
/* SECTOR_OFFSET is counted from one, while HEAD_OFFSET and
|
||||
CYLINDER_OFFSET are counted from zero. */
|
||||
sector_offset = sector % geometry->sectors + 1;
|
||||
head = sector / geometry->sectors;
|
||||
head_offset = head % geometry->heads;
|
||||
cylinder_offset = head / geometry->heads;
|
||||
|
||||
if (cylinder_offset >= geometry->cylinders)
|
||||
return BIOSDISK_ERROR_GEOMETRY;
|
||||
|
||||
err = biosdisk_standard (read + 0x02, drive,
|
||||
cylinder_offset, head_offset, sector_offset,
|
||||
nsec, segment);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Return the geometry of DRIVE in GEOMETRY. If an error occurs, return
|
||||
non-zero, otherwise zero. */
|
||||
int
|
||||
get_diskinfo (int drive, struct geometry *geometry)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Clear GEOMETRY. */
|
||||
memset (geometry, 0, sizeof (struct geometry));
|
||||
|
||||
if (drive & 0x80)
|
||||
{
|
||||
/* hard disk */
|
||||
int version;
|
||||
unsigned long total_sectors = 0;
|
||||
|
||||
version = check_int13_extensions (drive);
|
||||
if (version)
|
||||
{
|
||||
struct drive_parameters
|
||||
{
|
||||
unsigned short size;
|
||||
unsigned short flags;
|
||||
unsigned long cylinders;
|
||||
unsigned long heads;
|
||||
unsigned long sectors;
|
||||
unsigned long long total_sectors;
|
||||
unsigned short bytes_per_sector;
|
||||
/* ver 2.0 or higher */
|
||||
unsigned long EDD_configuration_parameters;
|
||||
/* ver 3.0 or higher */
|
||||
unsigned short signature_dpi;
|
||||
unsigned char length_dpi;
|
||||
unsigned char reserved[3];
|
||||
unsigned char name_of_host_bus[4];
|
||||
unsigned char name_of_interface_type[8];
|
||||
unsigned char interface_path[8];
|
||||
unsigned char device_path[8];
|
||||
unsigned char reserved2;
|
||||
unsigned char checksum;
|
||||
} drp;
|
||||
|
||||
drp.size = sizeof (drp);
|
||||
err = get_diskinfo_int13_extensions (drive, &drp);
|
||||
if (! err)
|
||||
{
|
||||
geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION;
|
||||
|
||||
/* Check if CHS information is valid. */
|
||||
if (drp.flags & 0x02)
|
||||
{
|
||||
total_sectors = (geometry->cylinders
|
||||
* geometry->heads
|
||||
* geometry->sectors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't pass GEOMETRY directly, but pass each element instead,
|
||||
so that we can change the structure easily. */
|
||||
err = get_diskinfo_standard (drive,
|
||||
&geometry->cylinders,
|
||||
&geometry->heads,
|
||||
&geometry->sectors);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (! total_sectors)
|
||||
{
|
||||
total_sectors = (geometry->cylinders
|
||||
* geometry->heads
|
||||
* geometry->sectors);
|
||||
}
|
||||
geometry->total_sectors = total_sectors;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* floppy disk */
|
||||
err = get_diskinfo_floppy (drive,
|
||||
&geometry->cylinders,
|
||||
&geometry->heads,
|
||||
&geometry->sectors);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
geometry->total_sectors = (geometry->cylinders
|
||||
* geometry->heads
|
||||
* geometry->sectors);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -406,7 +406,7 @@ real_open_partition (int flags)
|
||||
bsd_evil_hack = 0;
|
||||
current_slice = 0;
|
||||
part_start = 0;
|
||||
part_length = buf_geom.sectors * buf_geom.heads * buf_geom.cylinders;
|
||||
part_length = buf_geom.total_sectors;
|
||||
|
||||
if (current_drive & 0x80)
|
||||
{
|
||||
|
||||
+5
-1
@@ -309,7 +309,9 @@ extern int fsys_type;
|
||||
extern int block_file;
|
||||
#endif /* NO_BLOCK_FILES */
|
||||
|
||||
/* The information for a disk geometry */
|
||||
/* The information for a disk geometry. The CHS information is only for
|
||||
DOS/Partition table compatibility, and the real number of sectors is
|
||||
stored in TOTAL_SECTORS. */
|
||||
struct geometry
|
||||
{
|
||||
/* The number of cylinders */
|
||||
@@ -318,6 +320,8 @@ struct geometry
|
||||
unsigned long heads;
|
||||
/* The number of sectors */
|
||||
unsigned long sectors;
|
||||
/* The total number of sectors */
|
||||
unsigned long total_sectors;
|
||||
/* Flags */
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ print_entries(int y, int size, int first, char *menu_entries)
|
||||
else
|
||||
putchar(' ');
|
||||
|
||||
get_entry(menu_entries, first, 0);
|
||||
menu_entries = get_entry (menu_entries, first, 0);
|
||||
|
||||
for (i = 1; i <= size; i++)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user