aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre-Alexandre Meyer <pierre@mouraf.org>2009-04-19 17:11:59 -0700
committerPierre-Alexandre Meyer <pierre@mouraf.org>2009-04-19 18:15:22 -0700
commit62edfe42a1863f69db0c486f705fec17519641c3 (patch)
tree2e498971defdb07f7717a26497403529707c4300
parent1608b94e6f4bc23f8f51598c3cdbb6e961a09ab8 (diff)
downloadsyslinux.git-62edfe42a1863f69db0c486f705fec17519641c3.tar.gz
syslinux.git-62edfe42a1863f69db0c486f705fec17519641c3.tar.xz
syslinux.git-62edfe42a1863f69db0c486f705fec17519641c3.zip
gpllib: Don't clobber legacy C/H/S parameters with EDD ones
Impact: driveinfo structure change, new disk.c32 module Adapt driveinfo structure to store both legacy and EDD parameters. Change utility functions to use EDD when available (C/H/S being a fallback). Add a new disk.c32 module to test the disk library. It will print information (geometry) about every detected drive. Misc.: refactoring, set ES:DI to 0:0 when querying legacy C/H/S Signed-off-by: Pierre-Alexandre Meyer <pierre@mouraf.org>
-rw-r--r--com32/gplinclude/disk/geom.h53
-rw-r--r--com32/gpllib/disk/geom.c106
-rw-r--r--com32/modules/Makefile2
-rw-r--r--com32/modules/disk.c63
4 files changed, 142 insertions, 82 deletions
diff --git a/com32/gplinclude/disk/geom.h b/com32/gplinclude/disk/geom.h
index 54257aea..f0c5b6dd 100644
--- a/com32/gplinclude/disk/geom.h
+++ b/com32/gplinclude/disk/geom.h
@@ -5,26 +5,6 @@
#define SECTOR 512 /* bytes/sector */
-/*
- * Disk parameters
- */
-struct driveinfo {
- int disk;
- int ebios; /* EBIOS supported on this disk */
- int edd_version; /* EBIOS major version */
- int edd_functionality_subset;
- int cbios; /* CHS geometry is valid */
- int heads;
- int sectors;
- int sectors_per_track;
- int bytes_per_sector;
- int cylinder;
- int type; /* Drive type (AT/PS2 floppies only) */
- int drives; /* Number of drives */
- char host_bus_type[5];
- char interface_type[8];
-};
-
struct ebios_dapa {
uint16_t len;
uint16_t count;
@@ -39,7 +19,7 @@ struct ebios_dapa {
* Note: if the size is less than 30 on call, the final DWORD will not be
* returned by a v2.x implementation; similarly for the Device Path info
**/
-struct device_parameter {
+struct edd_device_parameters {
uint16_t len; /* size of returned data */
/**
* Bitfields for IBM/MS INT 13 Extensions information flags:
@@ -195,6 +175,25 @@ struct device_parameter {
* the 8-bit sum of bytes 1Eh-41h equal 00h) */
} __attribute__ ((packed));
+/*
+ * Disk parameters
+ */
+struct driveinfo {
+ int disk; /* Disk port (0x80 - 0xff) */
+ /* Legacy C/H/S */
+ int cbios; /* CHS geometry is valid */
+ int legacy_max_head;
+ int legacy_max_cylinder;
+ int legacy_sectors_per_track;
+ int legacy_max_drive;
+ int legacy_type; /* Drive type (AT/PS2 floppies only) */
+ /* EDD support */
+ int ebios; /* EBIOS supported on this disk */
+ int edd_version; /* EBIOS major version */
+ int edd_functionality_subset;
+ struct edd_device_parameters edd_params;/* EDD parameters */
+};
+
/**
* Format of Phoenix Enhanced Disk Drive Spec translated drive parameter table:
* Offset Size Description (Table 00277)
@@ -297,8 +296,16 @@ static inline int chs_to_lba(const struct driveinfo* drive_info,
const unsigned int cylinder, const unsigned int head,
const unsigned int sector)
{
- return (sector - 1) + (head * drive_info->sectors_per_track) +
- (cylinder * (drive_info->heads + 1) * drive_info->sectors_per_track);
+ /* Use EDD, if valid */
+ if (drive_info->edd_params.sectors_per_track > 0 &&
+ drive_info->edd_params.heads > 0)
+ return (sector - 1) + (head * drive_info->edd_params.sectors_per_track) +
+ (cylinder * (drive_info->edd_params.heads) *
+ drive_info->edd_params.sectors_per_track);
+ else if (drive_info->cbios)
+ return (sector - 1) + (head * drive_info->legacy_sectors_per_track) +
+ (cylinder * (drive_info->legacy_max_head + 1) *
+ drive_info->legacy_sectors_per_track);
}
void lba_to_chs(const struct driveinfo* drive_info, const int lba,
diff --git a/com32/gpllib/disk/geom.c b/com32/gpllib/disk/geom.c
index 870b8d5b..7bbb698d 100644
--- a/com32/gpllib/disk/geom.c
+++ b/com32/gpllib/disk/geom.c
@@ -14,10 +14,19 @@ void lba_to_chs(const struct driveinfo* drive_info, const int lba,
{
unsigned int track;
- *cylinder = (lba % drive_info->sectors_per_track) + 1;
- track = lba / drive_info->sectors_per_track;
- *head = track % drive_info->heads;
- *sector = track / drive_info->heads;
+ /* Use EDD, if valid */
+ if (drive_info->edd_params.sectors_per_track > 0 &&
+ drive_info->edd_params.heads > 0) {
+ *cylinder = (lba % drive_info->edd_params.sectors_per_track) + 1;
+ track = lba / drive_info->edd_params.sectors_per_track;
+ *head = track % drive_info->edd_params.heads;
+ *sector = track / drive_info->edd_params.heads;
+ } else if (drive_info->cbios) {
+ *cylinder = (lba % drive_info->legacy_sectors_per_track) + 1;
+ track = lba / drive_info->legacy_sectors_per_track;
+ *head = track % (drive_info->legacy_max_head + 1);
+ *sector = track / (drive_info->legacy_max_head + 1);
+ }
}
/**
@@ -53,17 +62,17 @@ void lba_to_chs(const struct driveinfo* drive_info, const int lba,
* extended drive parameter table is valid (see #00273,#00278)
* 3-15 reserved (0)
**/
-static void detect_extensions(struct driveinfo* drive_info)
+static int detect_extensions(struct driveinfo* drive_info)
{
com32sys_t getebios, ebios;
- memset(&getebios, 0, sizeof(com32sys_t));
- memset(&ebios, 0, sizeof(com32sys_t));
+ memset(&getebios, 0, sizeof getebios);
+ memset(&ebios, 0, sizeof ebios);
- getebios.eax.w[0] = 0x4100;
+ getebios.eflags.b[0] = 0x3; /* CF set */
getebios.ebx.w[0] = 0x55aa;
getebios.edx.b[0] = drive_info->disk;
- getebios.eflags.b[0] = 0x3; /* CF set */
+ getebios.eax.b[1] = 0x41;
__intcall(0x13, &getebios, &ebios);
@@ -72,7 +81,9 @@ static void detect_extensions(struct driveinfo* drive_info)
drive_info->ebios = 1;
drive_info->edd_version = ebios.eax.b[1];
drive_info->edd_functionality_subset = ebios.ecx.w[0];
- }
+ return 0;
+ } else
+ return -1; /* Drive does not exist? */
}
/**
@@ -96,45 +107,22 @@ static void detect_extensions(struct driveinfo* drive_info)
static int get_drive_parameters_with_extensions(struct driveinfo* drive_info)
{
com32sys_t inreg, outreg;
- struct device_parameter dp;
+ struct device_parameter *dp = __com32.cs_bounce;
- memset(&inreg, 0, sizeof(com32sys_t));
- memset(&outreg, 0, sizeof(com32sys_t));
- memset(&dp, 0, sizeof(struct device_parameter));
+ memset(&inreg, 0, sizeof inreg);
- inreg.esi.w[0] = OFFS(__com32.cs_bounce);
- inreg.ds = SEG(__com32.cs_bounce);
- inreg.eax.w[0] = 0x4800;
+ inreg.esi.w[0] = OFFS(dp);
+ inreg.ds = SEG(dp);
inreg.edx.b[0] = drive_info->disk;
+ inreg.eax.b[1] = 0x48;
__intcall(0x13, &inreg, &outreg);
- /* Saving bounce buffer before anything corrupts it */
- memcpy(&dp, __com32.cs_bounce, sizeof(struct device_parameter));
-
/* CF set on error */
if ( outreg.eflags.l & EFLAGS_CF )
return outreg.eax.b[1];
- /* Override values found without extensions */
- drive_info->cylinder = dp.cylinders;
- drive_info->heads = dp.heads;
- drive_info->sectors = dp.sectors;
- drive_info->bytes_per_sector = dp.bytes_per_sector;
-
- /* The rest of the functions is EDD v3.0+ only */
- if (drive_info->edd_version < 0x30)
- return 0;
-
- /* "ISA" or "PCI" */
- strncpy(drive_info->host_bus_type, (char *) dp.host_bus_type,
- sizeof drive_info->host_bus_type);
-
- strncpy(drive_info->interface_type, (char *) dp.interface_type,
- sizeof drive_info->interface_type);
-
- if ( drive_info->sectors > 0 )
- drive_info->cbios = 1; /* Valid geometry */
+ memcpy(&drive_info->edd_params, dp, sizeof drive_info->edd_params);
return 0;
}
@@ -191,11 +179,14 @@ static int get_drive_parameters_without_extensions(struct driveinfo* drive_info)
{
com32sys_t getparm, parm;
- memset(&getparm, 0, sizeof(com32sys_t));
- memset(&parm, 0, sizeof(com32sys_t));
+ memset(&getparm, 0, sizeof getparm);
+ memset(&parm, 0, sizeof parm);
- getparm.eax.b[1] = 0x08;
+ /* Ralf Brown recommends setting ES:DI to 0:0 */
+ getparm.esi.w[0] = 0;
+ getparm.ds = 0;
getparm.edx.b[0] = drive_info->disk;
+ getparm.eax.b[1] = 0x08;
__intcall(0x13, &getparm, &parm);
@@ -203,32 +194,31 @@ static int get_drive_parameters_without_extensions(struct driveinfo* drive_info)
if ( parm.eflags.l & EFLAGS_CF )
return parm.eax.b[1];
- /* DL contains the maximum drive number but it starts at 0! */
- drive_info->drives = parm.edx.b[0] + 1;
+ /* DL contains the maximum drive number (it starts at 0) */
+ drive_info->legacy_max_drive = parm.edx.b[0];
// XXX broken
/* Drive specified greater than the bumber of attached drives */
//if (drive_info->disk > drive_info->drives)
// return -1;
- drive_info->type = parm.ebx.b[0];
+ drive_info->legacy_type = parm.ebx.b[0];
- /* DH contains the maximum head number but it starts at 0! */
- drive_info->heads = parm.edx.b[1] + 1;
+ /* DH contains the maximum head number (it starts at 0) */
+ drive_info->legacy_max_head = parm.edx.b[1];
/* Maximum sector number (bits 5-0) per track */
- drive_info->sectors_per_track = parm.ecx.b[0] & 0x3f;
+ drive_info->legacy_sectors_per_track = parm.ecx.b[0] & 0x3f;
/*
* Maximum cylinder number:
* CH = low eight bits of maximum cylinder number
* CL = high two bits of maximum cylinder number (bits 7-6)
*/
- drive_info->cylinder = parm.ecx.b[1] +
- ((parm.ecx.b[0] & 0x40) * 256 +
- (parm.ecx.b[0] & 0x80) * 512);
+ drive_info->legacy_max_cylinder = parm.ecx.b[1] +
+ ((parm.ecx.b[0] & 0xc0) << 2);
- if ( drive_info->sectors_per_track > 0 )
+ if ( drive_info->legacy_sectors_per_track > 0 )
drive_info->cbios = 1; /* Valid geometry */
return 0;
@@ -240,11 +230,11 @@ static int get_drive_parameters_without_extensions(struct driveinfo* drive_info)
**/
int get_drive_parameters(struct driveinfo *drive_info)
{
- detect_extensions(drive_info);
+ if (detect_extensions(drive_info))
+ return -1;
- if (drive_info->ebios) {
- get_drive_parameters_without_extensions(drive_info);
- return get_drive_parameters_with_extensions(drive_info);
- } else
- return get_drive_parameters_without_extensions(drive_info);
+ if (drive_info->ebios)
+ get_drive_parameters_with_extensions(drive_info);
+
+ return get_drive_parameters_without_extensions(drive_info);
}
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index ba76268f..76604214 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -19,7 +19,7 @@ topdir = ../..
include ../MCONFIG
MODULES = chain.c32 config.c32 ethersel.c32 mboot.c32 dmitest.c32 \
- cpuidtest.c32 \
+ cpuidtest.c32 disk.c32 \
pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 meminfo.c32 \
sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 kbdmap.c32 cmd.c32 \
vpdtest.c32
diff --git a/com32/modules/disk.c b/com32/modules/disk.c
new file mode 100644
index 00000000..84d737fb
--- /dev/null
+++ b/com32/modules/disk.c
@@ -0,0 +1,63 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 Pierre-Alexandre Meyer - All Rights Reserved
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <console.h>
+#include <stdlib.h>
+#include <string.h>
+#include <disk/geom.h>
+#include <disk/util.h>
+
+int main(int argc __attribute__ (( unused )),
+ char *argv[] __attribute__ (( unused )))
+{
+ char* error_buffer;
+ int err;
+ struct driveinfo drive;
+ struct driveinfo *d = &drive;
+
+ openconsole(&dev_null_r, &dev_stdcon_w);
+
+ for (int disk = 0x80; disk < 0xff; disk++) {
+ memset(d, 0, sizeof(struct driveinfo));
+ d->disk = disk;
+ err = get_drive_parameters(d);
+
+ /* Do not print output when drive does not exists */
+ if (err == -1)
+ continue;
+
+ if (err) {
+ get_error(err, &error_buffer);
+ printf("Error 0x%Xh while reading disk 0x%X:\n %s\n",
+ err, d->disk, error_buffer);
+ free(error_buffer);
+ continue;
+ }
+
+ printf("DISK 0x%X:\n", d->disk);
+ printf(" C/H/S: %d heads, %d cylinders\n",
+ d->legacy_max_head + 1, d->legacy_max_cylinder + 1);
+ printf(" %d sectors/track, %d drives\n",
+ d->legacy_sectors_per_track, d->legacy_max_drive);
+ printf(" EDD: ebios=%d, EDD version: %X\n",
+ d->ebios, d->edd_version);
+ printf(" %d heads, %d cylinders\n",
+ (int) d->edd_params.heads, (int) d->edd_params.cylinders);
+ printf(" %d sectors, %d bytes/sector, %d sectors/track\n",
+ (int) d->edd_params.sectors, (int) d->edd_params.bytes_per_sector,
+ (int) d->edd_params.sectors_per_track);
+ printf(" Host bus: %s, Interface type: %s\n\n",
+ d->edd_params.host_bus_type, d->edd_params.interface_type);
+ }
+ return 0;
+}