diff options
-rw-r--r-- | com32/gplinclude/disk/geom.h | 53 | ||||
-rw-r--r-- | com32/gpllib/disk/geom.c | 106 | ||||
-rw-r--r-- | com32/modules/Makefile | 2 | ||||
-rw-r--r-- | com32/modules/disk.c | 63 |
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; +} |