1
/* bios.c - implement C part of low-level BIOS disk input and output */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 1999,2000 Free Software Foundation, Inc.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
/* These are defined in asm.S, and never be used elsewhere, so declare the
26
extern int biosdisk_int13_extensions (int ah, int drive, void *dap);
27
extern int biosdisk_standard (int ah, int drive,
28
int coff, int hoff, int soff,
29
int nsec, int segment);
30
extern int check_int13_extensions (int drive);
31
extern int get_diskinfo_int13_extensions (int drive, void *drp);
32
extern int get_diskinfo_standard (int drive,
33
unsigned long *cylinders,
35
unsigned long *sectors);
37
extern int get_diskinfo_floppy (int drive,
38
unsigned long *cylinders,
40
unsigned long *sectors);
44
/* Read/write NSEC sectors starting from SECTOR in DRIVE disk with GEOMETRY
45
from/into SEGMENT segment. If READ is BIOSDISK_READ, then read it,
46
else if READ is BIOSDISK_WRITE, then write it. If an geometry error
47
occurs, return BIOSDISK_ERROR_GEOMETRY, and if other error occurs, then
48
return the error number. Otherwise, return 0. */
50
biosdisk (int read, int drive, struct geometry *geometry,
51
int sector, int nsec, int segment)
55
if (geometry->flags & BIOSDISK_FLAG_LBA_EXTENSION)
57
struct disk_address_packet
60
unsigned char reserved;
61
unsigned short blocks;
63
unsigned long long block;
66
/* XXX: Don't check the geometry by default, because some buggy
67
BIOSes don't return the number of total sectors correctly,
68
even if they have working LBA support. Hell. */
69
#ifdef NO_BUGGY_BIOS_IN_THE_WORLD
70
if (sector >= geometry->total_sectors)
71
return BIOSDISK_ERROR_GEOMETRY;
72
#endif /* NO_BUGGY_BIOS_IN_THE_WORLD */
74
/* FIXME: sizeof (DAP) must be 0x10. Should assert that the compiler
75
can't add any padding. */
76
dap.length = sizeof (dap);
80
/* This is undocumented part. The address is formated in
82
dap.buffer = segment << 16;
84
err = biosdisk_int13_extensions (read + 0x42, drive, &dap);
86
/* #undef NO_INT13_FALLBACK */
87
#ifndef NO_INT13_FALLBACK
90
geometry->flags &= ~BIOSDISK_FLAG_LBA_EXTENSION;
91
geometry->total_sectors = (geometry->cylinders
94
return biosdisk (read, drive, geometry, sector, nsec, segment);
96
#endif /* ! NO_INT13_FALLBACK */
101
int cylinder_offset, head_offset, sector_offset;
104
/* SECTOR_OFFSET is counted from one, while HEAD_OFFSET and
105
CYLINDER_OFFSET are counted from zero. */
106
sector_offset = sector % geometry->sectors + 1;
107
head = sector / geometry->sectors;
108
head_offset = head % geometry->heads;
109
cylinder_offset = head / geometry->heads;
111
if (cylinder_offset >= geometry->cylinders)
112
return BIOSDISK_ERROR_GEOMETRY;
114
err = biosdisk_standard (read + 0x02, drive,
115
cylinder_offset, head_offset, sector_offset,
122
/* Return the geometry of DRIVE in GEOMETRY. If an error occurs, return
123
non-zero, otherwise zero. */
125
get_diskinfo (int drive, struct geometry *geometry)
129
/* Clear the flags. */
136
unsigned long total_sectors = 0;
138
version = check_int13_extensions (drive);
141
struct drive_parameters
144
unsigned short flags;
145
unsigned long cylinders;
147
unsigned long sectors;
148
unsigned long long total_sectors;
149
unsigned short bytes_per_sector;
150
/* ver 2.0 or higher */
151
unsigned long EDD_configuration_parameters;
152
/* ver 3.0 or higher */
153
unsigned short signature_dpi;
154
unsigned char length_dpi;
155
unsigned char reserved[3];
156
unsigned char name_of_host_bus[4];
157
unsigned char name_of_interface_type[8];
158
unsigned char interface_path[8];
159
unsigned char device_path[8];
160
unsigned char reserved2;
161
unsigned char checksum;
163
/* XXX: This is necessary, because the BIOS of Thinkpad X20
164
writes a garbage to the tail of drive parameters,
165
regardless of a size specified in a caller. */
166
unsigned char dummy[16];
167
} __attribute__ ((packed)) drp;
169
/* It is safe to clear out DRP. */
170
grub_memset (&drp, 0, sizeof (drp));
172
drp.size = sizeof (drp);
173
err = get_diskinfo_int13_extensions (drive, &drp);
176
/* Set the LBA flag. */
177
geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION;
179
/* I'm not sure if GRUB should check the bit 1 of DRP.FLAGS,
180
so I omit the check for now. - okuji */
181
/* if (drp.flags & (1 << 1)) */
183
/* FIXME: when the 2TB limit becomes critical, we must
184
change the type of TOTAL_SECTORS to unsigned long
186
if (drp.total_sectors)
187
total_sectors = drp.total_sectors & ~0L;
189
/* Some buggy BIOSes doesn't return the total sectors
190
correctly but returns zero. So if it is zero, compute
191
it by C/H/S returned by the LBA BIOS call. */
192
total_sectors = drp.cylinders * drp.heads * drp.sectors;
196
/* Don't pass GEOMETRY directly, but pass each element instead,
197
so that we can change the structure easily. */
198
err = get_diskinfo_standard (drive,
199
&geometry->cylinders,
207
total_sectors = (geometry->cylinders
209
* geometry->sectors);
211
geometry->total_sectors = total_sectors;
217
/* First, try INT 13 AH=8h call. */
218
err = get_diskinfo_standard (drive,
219
&geometry->cylinders,
224
/* If fails, then try floppy-specific probe routine. */
226
err = get_diskinfo_floppy (drive,
227
&geometry->cylinders,
235
geometry->total_sectors = (geometry->cylinders
237
* geometry->sectors);