2 * PUPA -- Preliminary Universal Programming Architecture for GRUB
3 * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
4 * Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
6 * PUPA 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 PUPA; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <pupa/machine/biosdisk.h>
22 #include <pupa/machine/memory.h>
23 #include <pupa/disk.h>
25 #include <pupa/types.h>
26 #include <pupa/misc.h>
28 #include <pupa/term.h>
30 /* Drive Parameters. */
31 struct pupa_biosdisk_drp
35 pupa_uint32_t cylinders
;
37 pupa_uint32_t sectors
;
38 pupa_uint64_t total_sectors
;
39 pupa_uint16_t bytes_per_sector
;
40 /* ver 2.0 or higher */
41 pupa_uint32_t EDD_configuration_parameters
;
42 /* ver 3.0 or higher */
43 pupa_uint16_t signature_dpi
;
44 pupa_uint8_t length_dpi
;
45 pupa_uint8_t reserved
[3];
46 pupa_uint8_t name_of_host_bus
[4];
47 pupa_uint8_t name_of_interface_type
[8];
48 pupa_uint8_t interface_path
[8];
49 pupa_uint8_t device_path
[8];
50 pupa_uint8_t reserved2
;
51 pupa_uint8_t checksum
;
53 /* XXX: This is necessary, because the BIOS of Thinkpad X20
54 writes a garbage to the tail of drive parameters,
55 regardless of a size specified in a caller. */
56 pupa_uint8_t dummy
[16];
57 } __attribute__ ((packed
));
59 /* Disk Address Packet. */
60 struct pupa_biosdisk_dap
63 pupa_uint8_t reserved
;
67 } __attribute__ ((packed
));
71 pupa_biosdisk_get_drive (const char *name
)
75 if ((name
[0] != 'f' && name
[0] != 'h') || name
[1] != 'd')
78 drive
= pupa_strtoul (name
+ 2, 0, 10);
79 if (pupa_errno
!= PUPA_ERR_NONE
)
88 pupa_error (PUPA_ERR_UNKNOWN_DEVICE
, "not a biosdisk");
93 pupa_biosdisk_call_hook (int (*hook
) (const char *name
), int drive
)
97 pupa_sprintf (name
, (drive
& 0x80) ? "hd%d" : "fd%d", drive
& (~0x80));
102 pupa_biosdisk_iterate (int (*hook
) (const char *name
))
107 /* For floppy disks, we can get the number safely. */
108 num_floppies
= pupa_biosdisk_get_num_floppies ();
109 for (drive
= 0; drive
< num_floppies
; drive
++)
110 if (pupa_biosdisk_call_hook (hook
, drive
))
113 /* For hard disks, attempt to read the MBR. */
114 for (drive
= 0x80; drive
< 0x88; drive
++)
116 if (pupa_biosdisk_rw_standard (0x02, drive
, 0, 0, 1, 1,
117 PUPA_MEMORY_MACHINE_SCRATCH_SEG
) != 0)
120 if (pupa_biosdisk_call_hook (hook
, drive
))
128 pupa_biosdisk_open (const char *name
, pupa_disk_t disk
)
130 unsigned long total_sectors
= 0;
132 struct pupa_biosdisk_data
*data
;
134 drive
= pupa_biosdisk_get_drive (name
);
138 disk
->has_partitions
= (drive
& 0x80);
141 data
= (struct pupa_biosdisk_data
*) pupa_malloc (sizeof (*data
));
153 version
= pupa_biosdisk_check_int13_extensions (drive
);
156 struct pupa_biosdisk_drp
*drp
157 = (struct pupa_biosdisk_drp
*) PUPA_MEMORY_MACHINE_SCRATCH_ADDR
;
159 /* Clear out the DRP. */
160 pupa_memset (drp
, 0, sizeof (*drp
));
161 drp
->size
= sizeof (*drp
);
162 if (pupa_biosdisk_get_diskinfo_int13_extensions (drive
, drp
))
164 data
->flags
= PUPA_BIOSDISK_FLAG_LBA
;
166 /* FIXME: 2TB limit. */
167 if (drp
->total_sectors
)
168 total_sectors
= drp
->total_sectors
& ~0L;
170 /* Some buggy BIOSes doesn't return the total sectors
171 correctly but returns zero. So if it is zero, compute
172 it by C/H/S returned by the LBA BIOS call. */
173 total_sectors
= drp
->cylinders
* drp
->heads
* drp
->sectors
;
178 if (pupa_biosdisk_get_diskinfo_standard (drive
,
181 &data
->sectors
) != 0)
184 return pupa_error (PUPA_ERR_BAD_DEVICE
, "cannot get C/H/S values");
188 total_sectors
= data
->cylinders
* data
->heads
* data
->sectors
;
190 disk
->total_sectors
= total_sectors
;
193 return PUPA_ERR_NONE
;
197 pupa_biosdisk_close (pupa_disk_t disk
)
199 pupa_free (disk
->data
);
202 /* For readability. */
203 #define PUPA_BIOSDISK_READ 0
204 #define PUPA_BIOSDISK_WRITE 1
207 pupa_biosdisk_rw (int cmd
, pupa_disk_t disk
,
208 unsigned long sector
, unsigned long size
,
211 struct pupa_biosdisk_data
*data
= disk
->data
;
213 if (data
->flags
& PUPA_BIOSDISK_FLAG_LBA
)
215 struct pupa_biosdisk_dap
*dap
;
217 dap
= (struct pupa_biosdisk_dap
*) (PUPA_MEMORY_MACHINE_SCRATCH_ADDR
219 << PUPA_DISK_SECTOR_BITS
));
220 dap
->length
= sizeof (*dap
);
223 dap
->buffer
= segment
<< 16; /* The format SEGMENT:ADDRESS. */
226 if (pupa_biosdisk_rw_int13_extensions (cmd
+ 0x42, data
->drive
, dap
))
228 /* Fall back to the CHS mode. */
229 data
->flags
&= ~PUPA_BIOSDISK_FLAG_LBA
;
230 disk
->total_sectors
= data
->cylinders
* data
->heads
* data
->sectors
;
231 return pupa_biosdisk_rw (cmd
, disk
, sector
, size
, segment
);
236 unsigned coff
, hoff
, soff
;
239 soff
= sector
% data
->sectors
+ 1;
240 head
= sector
/ data
->sectors
;
241 hoff
= head
% data
->heads
;
242 coff
= head
/ data
->heads
;
244 if (coff
>= data
->cylinders
)
245 return pupa_error (PUPA_ERR_OUT_OF_RANGE
, "out of disk");
247 if (pupa_biosdisk_rw_standard (cmd
+ 0x02, data
->drive
,
248 coff
, hoff
, soff
, size
, segment
))
252 case PUPA_BIOSDISK_READ
:
253 return pupa_error (PUPA_ERR_READ_ERROR
, "biosdisk read error");
254 case PUPA_BIOSDISK_WRITE
:
255 return pupa_error (PUPA_ERR_WRITE_ERROR
, "biosdisk write error");
260 return PUPA_ERR_NONE
;
264 pupa_biosdisk_read (pupa_disk_t disk
, unsigned long sector
,
265 unsigned long size
, char *buf
)
267 struct pupa_biosdisk_data
*data
= disk
->data
;
273 len
= data
->sectors
- (sector
% data
->sectors
);
277 if (pupa_biosdisk_rw (PUPA_BIOSDISK_READ
, disk
, sector
, len
,
278 PUPA_MEMORY_MACHINE_SCRATCH_SEG
))
281 pupa_memcpy (buf
, (void *) PUPA_MEMORY_MACHINE_SCRATCH_ADDR
,
282 len
<< PUPA_DISK_SECTOR_BITS
);
283 buf
+= len
<< PUPA_DISK_SECTOR_BITS
;
292 pupa_biosdisk_write (pupa_disk_t disk
, unsigned long sector
,
293 unsigned long size
, const char *buf
)
295 struct pupa_biosdisk_data
*data
= disk
->data
;
301 len
= data
->sectors
- (sector
% data
->sectors
);
305 pupa_memcpy ((void *) PUPA_MEMORY_MACHINE_SCRATCH_ADDR
, buf
,
306 len
<< PUPA_DISK_SECTOR_BITS
);
308 if (pupa_biosdisk_rw (PUPA_BIOSDISK_WRITE
, disk
, sector
, len
,
309 PUPA_MEMORY_MACHINE_SCRATCH_SEG
))
312 buf
+= len
<< PUPA_DISK_SECTOR_BITS
;
320 static struct pupa_disk_dev pupa_biosdisk_dev
=
323 .iterate
= pupa_biosdisk_iterate
,
324 .open
= pupa_biosdisk_open
,
325 .close
= pupa_biosdisk_close
,
326 .read
= pupa_biosdisk_read
,
327 .write
= pupa_biosdisk_write
,
332 pupa_biosdisk_init (void)
334 pupa_disk_dev_register (&pupa_biosdisk_dev
);