summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--com32/gplinclude/disk/common.h19
-rw-r--r--com32/gplinclude/disk/error.h4
-rw-r--r--com32/gplinclude/disk/geom.h306
-rw-r--r--com32/gplinclude/disk/msdos.h8
-rw-r--r--com32/gplinclude/disk/partition.h23
-rw-r--r--com32/gplinclude/disk/read.h10
-rw-r--r--com32/gplinclude/disk/swsusp.h19
-rw-r--r--com32/gplinclude/disk/util.h8
-rw-r--r--com32/gplinclude/disk/write.h14
-rw-r--r--com32/gpllib/Makefile3
-rw-r--r--com32/gpllib/disk/ata.c59
-rw-r--r--com32/gpllib/disk/error.c127
-rw-r--r--com32/gpllib/disk/geom.c240
-rw-r--r--com32/gpllib/disk/labels.c245
-rw-r--r--com32/gpllib/disk/msdos.c149
-rw-r--r--com32/gpllib/disk/read.c113
-rw-r--r--com32/gpllib/disk/swsusp.c31
-rw-r--r--com32/gpllib/disk/util.c30
-rw-r--r--com32/gpllib/disk/write.c113
-rw-r--r--com32/hdt/hdt-ata.c247
-rw-r--r--com32/hdt/hdt-ata.h50
-rw-r--r--com32/hdt/hdt-cli-disk.c163
-rw-r--r--com32/hdt/hdt-cli-hdt.c4
-rw-r--r--com32/hdt/hdt-cli.c8
-rw-r--r--com32/hdt/hdt-cli.h6
-rw-r--r--com32/hdt/hdt-common.c38
-rw-r--r--com32/hdt/hdt-common.h15
-rw-r--r--com32/hdt/hdt-menu-disk.c221
-rw-r--r--com32/hdt/hdt-menu.c2
-rw-r--r--com32/hdt/hdt-menu.h4
-rw-r--r--com32/hdt/hdt-util.c71
-rw-r--r--com32/hdt/hdt-util.h33
-rw-r--r--com32/modules/Makefile2
-rw-r--r--com32/modules/disk.c63
34 files changed, 2054 insertions, 394 deletions
diff --git a/com32/gplinclude/disk/common.h b/com32/gplinclude/disk/common.h
new file mode 100644
index 00000000..6e4f3d61
--- /dev/null
+++ b/com32/gplinclude/disk/common.h
@@ -0,0 +1,19 @@
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <stdint.h>
+
+#define SECTOR 512 /* bytes/sector */
+
+#undef PAGE_SIZE
+#define PAGE_SIZE (1<<12)
+
+struct ebios_dapa {
+ uint16_t len;
+ uint16_t count;
+ uint16_t off;
+ uint16_t seg;
+ uint64_t lba;
+};
+
+#endif /* _COMMON_H_ */
diff --git a/com32/gplinclude/disk/error.h b/com32/gplinclude/disk/error.h
new file mode 100644
index 00000000..3a7614e9
--- /dev/null
+++ b/com32/gplinclude/disk/error.h
@@ -0,0 +1,4 @@
+#ifndef _ERROR_H_
+#define _ERROR_H_
+void get_error(const int, char**);
+#endif /* _UTIL_H_ */
diff --git a/com32/gplinclude/disk/geom.h b/com32/gplinclude/disk/geom.h
new file mode 100644
index 00000000..30dc86bf
--- /dev/null
+++ b/com32/gplinclude/disk/geom.h
@@ -0,0 +1,306 @@
+#ifndef _GEOM_H_
+#define _GEOM_H_
+
+#include <stdint.h>
+
+/**
+ * INT 13 Extensions
+ *
+ * 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 edd_device_parameters {
+ uint16_t len; /* size of returned data */
+ /**
+ * Bitfields for IBM/MS INT 13 Extensions information flags:
+ * Bit(s) Description (Table 00274)
+ * 0 DMA boundary errors handled transparently
+ * 1 cylinder/head/sectors-per-track information is valid
+ * 2 removable drive
+ * 3 write with verify supported
+ * 4 drive has change-line support (required if drive >= 80h is removable)
+ * 5 drive can be locked (required if drive >= 80h is removable)
+ * 6 CHS information set to maximum supported values, not current media
+ * 15-7 reserved (0)
+ **/
+ uint16_t info; /* information flags */
+ uint32_t cylinders; /* number of physical cylinders on drive */
+ uint32_t heads; /* number of physical heads on drive */
+ uint32_t sectors_per_track; /* number of physical sectors per track */
+ uint64_t sectors; /* total number of sectors on drive */
+ uint16_t bytes_per_sector; /* bytes per sector */
+ /* --- v2.0+ --- */
+ uint32_t dpte_pointer; /* EDD configuration parameters, FFFFh:FFFFh if not available */
+ /* --- v3.0 --- */
+ uint16_t device_path_information; /* signature BEDDh to indicate presence of Device Path info */
+ uint8_t device_path_length; /* length of Device Path information, including signature and this byte (24h for v3.0) */
+ uint8_t device_path_reserved; /* reserved (0) */
+ uint16_t device_path_reserved_2; /* reserved (0) */
+ uint8_t host_bus_type[4]; /* ASCIZ name of host bus ("ISA" or "PCI") */
+ uint8_t interface_type[8]; /* ASCIZ name of interface type
+ * "ATA"
+ * "ATAPI"
+ * "SCSI"
+ * "USB"
+ * "1394" IEEE 1394 (FireWire)
+ * "FIBRE" Fibre Channel
+ */
+ /**
+ * Format of EDD v3.0 Interface Path:
+ * Offset Size Description (Table 00275)
+ * ---ISA---
+ * 00h WORD 16-bit base address
+ * 02h 6 BYTEs reserved (0)
+ * ---PCI---
+ * 00h BYTE PCI bus number
+ * 01h BYTE PCI device number
+ * 02h BYTE PCI function number
+ * 03h 5 BYTEs reserved (0)
+ **/
+ union {
+ struct {
+ uint16_t base_address;
+ uint16_t reserved1;
+ uint32_t reserved2;
+ } __attribute__ ((packed)) isa;
+ struct {
+ uint8_t bus;
+ uint8_t slot;
+ uint8_t function;
+ uint8_t channel;
+ uint32_t reserved;
+ } __attribute__ ((packed)) pci;
+ /* pcix is same as pci */
+ struct {
+ uint64_t reserved;
+ } __attribute__ ((packed)) ibnd;
+ struct {
+ uint64_t reserved;
+ } __attribute__ ((packed)) xprs;
+ struct {
+ uint64_t reserved;
+ } __attribute__ ((packed)) htpt;
+ struct {
+ uint64_t reserved;
+ } __attribute__ ((packed)) unknown;
+ } interface_path;
+ /**
+ * Format of EDD v3.0 Device Path:
+ * Offset Size Description (Table 00276)
+ * ---ATA---
+ * 00h BYTE flag: 00h = master, 01h = slave
+ * 01h 7 BYTEs reserved (0)
+ * ---ATAPI---
+ * 00h BYTE flag: 00h = master, 01h = slave
+ * 01h BYTE logical unit number
+ * 02h 6 BYTEs reserved (0)
+ * ---SCSI---
+ * 00h BYTE logical unit number
+ * 01h 7 BYTEs reserved (0)
+ * ---USB---
+ * 00h BYTE to be determined
+ * 01h 7 BYTEs reserved (0)
+ * ---IEEE1394---
+ * 00h QWORD 64-bit FireWire General Unique Identifier (GUID)
+ * ---FibreChannel---
+ * 00h QWORD Word Wide Number (WWN)
+ **/
+ union {
+ struct {
+ uint8_t device;
+ uint8_t reserved1;
+ uint16_t reserved2;
+ uint32_t reserved3;
+ uint64_t reserved4;
+ } __attribute__ ((packed)) ata;
+ struct {
+ uint8_t device;
+ uint8_t lun;
+ uint8_t reserved1;
+ uint8_t reserved2;
+ uint32_t reserved3;
+ uint64_t reserved4;
+ } __attribute__ ((packed)) atapi;
+ struct {
+ uint16_t id;
+ uint64_t lun;
+ uint16_t reserved1;
+ uint32_t reserved2;
+ } __attribute__ ((packed)) scsi;
+ struct {
+ uint64_t serial_number;
+ uint64_t reserved;
+ } __attribute__ ((packed)) usb;
+ struct {
+ uint64_t eui;
+ uint64_t reserved;
+ } __attribute__ ((packed)) i1394;
+ struct {
+ uint64_t wwid;
+ uint64_t lun;
+ } __attribute__ ((packed)) fibre;
+ struct {
+ uint64_t identity_tag;
+ uint64_t reserved;
+ } __attribute__ ((packed)) i2o;
+ struct {
+ uint32_t array_number;
+ uint32_t reserved1;
+ uint64_t reserved2;
+ } __attribute__ ((packed)) raid;
+ struct {
+ uint8_t device;
+ uint8_t reserved1;
+ uint16_t reserved2;
+ uint32_t reserved3;
+ uint64_t reserved4;
+ } __attribute__ ((packed)) sata;
+ struct {
+ uint64_t reserved1;
+ uint64_t reserved2;
+ } __attribute__ ((packed)) unknown;
+ } device_path;
+ uint8_t reserved; /* reserved (0) */
+ uint8_t checksum; /* checksum of bytes 1Eh-40h (two's complement of sum, which makes
+ * 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)
+ * 00h WORD number of cylinders
+ * 02h BYTE number of heads
+ * 03h BYTE A0h (signature indicating translated table)
+ * 04h BYTE number of physical sectors per track
+ * 05h WORD starting write precompensation cylinder number
+ * 07h BYTE reserved
+ * 08h BYTE control byte (see #03198 at INT 41"DISK 0")
+ * 09h WORD number of physical cylinders
+ * 0Bh BYTE number of physical heads
+ * 0Ch WORD cylinder number of landing zone
+ * 0Eh BYTE number of logical sectors per track
+ * 0Fh BYTE checksum
+ * Program: the Phoenix Enhanced Disk Drive Specification is an addition to the
+ * IBM/MS INT 13 extensions
+ *
+ * Format of Phoenix Enhanced Disk Drive Spec Fixed Disk Parameter Table:
+ * Offset Size Description (Table 00278)
+ * 00h WORD physical I/O port base address
+ * 02h WORD disk-drive control port address
+ * 04h BYTE drive flags (see #00279)
+ * 05h BYTE proprietary information
+ * bits 7-4 reserved (0)
+ * bits 3-0: Phoenix proprietary (used by BIOS)
+ * 06h BYTE IRQ for drive (bits 3-0; bits 7-4 reserved and must be 0)
+ * 07h BYTE sector count for multi-sector transfers
+ * 08h BYTE DMA control
+ * bits 7-4: DMA type (0-2) as per ATA-2 specification
+ * bits 3-0: DMA channel
+ * 09h BYTE programmed I/O control
+ * bits 7-4: reserved (0)
+ * bits 3-0: PIO type (1-4) as per ATA-2 specification
+ * 0Ah WORD drive options (see #00280)
+ * 0Ch 2 BYTEs reserved (0)
+ * 0Eh BYTE extension revision level (high nybble=major, low nybble=minor)
+ * (currently 10h for v1.0 and 11h for v1.1-3.0)
+ * 0Fh BYTE 2's complement checksum of bytes 00h-0Eh
+ * 8-bit sum of all bytes 00h-0Fh should equal 00h
+ * SeeAlso: #00277
+ *
+ * Bitfields for Phoenix Enhanced Disk Drive Spec drive flags:
+ * Bit(s) Description (Table 00279)
+ * 7 reserved (1)
+ * 6 LBA enabled
+ * 5 reserved (1)
+ * 4 drive is slave
+ * 3-0 reserved (0)
+ * SeeAlso: #00278,#00280
+ *
+ * Bitfields for Phoenix Enhanced Disk Drive Spec drive options:
+ * Bit(s) Description (Table 00280)
+ * 0 fast PIO enabled
+ * 1 fast DMA access enabled
+ * 2 block PIO (multi-sector transfers) enabled
+ * 3 CHS translation enabled
+ * 4 LBA translation enabled
+ * 5 removable media
+ * 6 ATAPI device (CD-ROM)
+ * 7 32-bit transfer mode
+ * ---v1.1+ ---
+ * 8 ATAPI device uses DRQ to signal readiness for packet command
+ * (must be 0 if bit 6 is 0)
+ * 10-9 translation type (must be 00 if bit 3 is 0)
+ * 00 Phoenix bit-shifting translation
+ * 01 LBA-assisted translation
+ * 10 reserved
+ * 11 proprietary translation
+ * ---v3.0---
+ * 11 Ultra DMA access enabled
+ * 15-12 reserved
+ **/
+
+/*
+ * Values for diskette drive type:
+ * 01h 360K
+ * 02h 1.2M
+ * 03h 720K
+ * 04h 1.44M
+ * 05h ???
+ * reportedly an obscure drive type shipped on some IBM machines,
+ * 2.88M on some machines (at least AMI 486 BIOS)
+ * 06h 2.88M
+ * 10h ATAPI Removable Media Device
+ */
+enum diskette_drive_types {
+ DISKETTE_360K = 1,
+ DISKETTE_1_2M = 2,
+ DISKETTE_720K = 3,
+ DISKETTE_1_44M = 4,
+ DISKETTE_2_88M = 6,
+ DISKETTE_ATAPI = 10,
+};
+
+/**
+ * chs_to_lba - compute lba value from cylinder, head and sector number
+ **/
+static inline int chs_to_lba(const struct driveinfo* drive_info,
+ const unsigned int cylinder, const unsigned int head,
+ const unsigned int sector)
+{
+ /* 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,
+ unsigned int* cylinder, unsigned int* head,
+ unsigned int* sector);
+int get_drive_parameters(struct driveinfo *drive_info);
+
+#endif /* _GEOM_H */
diff --git a/com32/gplinclude/disk/msdos.h b/com32/gplinclude/disk/msdos.h
new file mode 100644
index 00000000..b6dd9481
--- /dev/null
+++ b/com32/gplinclude/disk/msdos.h
@@ -0,0 +1,8 @@
+#ifndef _MSDOS_H_
+#define _MSDOS_H_
+
+#include <disk/geom.h>
+
+int parse_partition_table(struct driveinfo *, void *, int *);
+
+#endif /* _MSDOS_H_ */
diff --git a/com32/gplinclude/disk/partition.h b/com32/gplinclude/disk/partition.h
new file mode 100644
index 00000000..3bffa89e
--- /dev/null
+++ b/com32/gplinclude/disk/partition.h
@@ -0,0 +1,23 @@
+#ifndef _PARTITION_H_
+#define _PARTITION_H_
+
+#include <stdint.h>
+
+#define PARTITION_TABLES_OFFSET 0x1be
+
+/* A DOS partition table entry */
+struct part_entry {
+ uint8_t active_flag; /* 0x80 if "active" */
+ uint8_t start_head;
+ uint8_t start_sect;
+ uint8_t start_cyl;
+ uint8_t ostype;
+ uint8_t end_head;
+ uint8_t end_sect;
+ uint8_t end_cyl;
+ uint32_t start_lba;
+ uint32_t length;
+} __attribute__((packed));
+
+void get_label(int label, char** buffer_label);
+#endif /* _PARTITION_H_ */
diff --git a/com32/gplinclude/disk/read.h b/com32/gplinclude/disk/read.h
new file mode 100644
index 00000000..fee10daf
--- /dev/null
+++ b/com32/gplinclude/disk/read.h
@@ -0,0 +1,10 @@
+#ifndef _READ_H_
+#define _READ_H_
+
+#include <disk/geom.h>
+
+void *read_mbr(int, int*);
+void *dev_read(int, unsigned int, int, int*);
+void *read_sectors(struct driveinfo*, const unsigned int,
+ const int, int *);
+#endif /* _READ_H */
diff --git a/com32/gplinclude/disk/swsusp.h b/com32/gplinclude/disk/swsusp.h
new file mode 100644
index 00000000..54140b3d
--- /dev/null
+++ b/com32/gplinclude/disk/swsusp.h
@@ -0,0 +1,19 @@
+#ifndef _SWSUSP_H_
+#define _SWSUSP_H_
+
+#include <disk/geom.h>
+#include <disk/common.h>
+#include <disk/partition.h>
+
+#define SWSUSP_SIG "S1SUSPEND"
+
+struct swsusp_header {
+ char reserved[PAGE_SIZE - 20 - sizeof(unsigned long) - sizeof(int)];
+ unsigned long image;
+ unsigned int flags; /* Flags to pass to the "boot" kernel */
+ char orig_sig[10];
+ char sig[10];
+} __attribute__((packed));
+
+int swsusp_check(struct driveinfo*, struct part_entry*, int*);
+#endif /* _SWSUSP_H */
diff --git a/com32/gplinclude/disk/util.h b/com32/gplinclude/disk/util.h
new file mode 100644
index 00000000..dd0d5c02
--- /dev/null
+++ b/com32/gplinclude/disk/util.h
@@ -0,0 +1,8 @@
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <com32.h>
+
+int int13_retry(const com32sys_t *inreg, com32sys_t *outreg);
+void get_error(const int, char**);
+#endif /* _UTIL_H_ */
diff --git a/com32/gplinclude/disk/write.h b/com32/gplinclude/disk/write.h
new file mode 100644
index 00000000..be6494fa
--- /dev/null
+++ b/com32/gplinclude/disk/write.h
@@ -0,0 +1,14 @@
+#ifndef _WRITE_H_
+#define _WRITE_H_
+
+#include <disk/geom.h>
+
+int write_sectors(const struct driveinfo*, const unsigned int,
+ const void *, const int, int *);
+int write_verify_sector(struct driveinfo* drive_info,
+ const unsigned int,
+ const void *, int*);
+int write_verify_sectors(struct driveinfo*,
+ const unsigned int,
+ const void *, const int, int *);
+#endif
diff --git a/com32/gpllib/Makefile b/com32/gpllib/Makefile
index 8e47d93f..83f1407a 100644
--- a/com32/gpllib/Makefile
+++ b/com32/gpllib/Makefile
@@ -10,7 +10,8 @@ REQFLAGS += -I../gplinclude
LIBOBJS = dmi/dmi_battery.o dmi/dmi_chassis.o dmi/dmi_memory.o \
dmi/dmi_processor.o dmi/dmi.o dmi/dmi_bios.o dmi/dmi_base_board.o \
- dmi/dmi_ipmi.o cpuid.o vpd/vpd.o
+ dmi/dmi_ipmi.o cpuid.o disk/geom.o disk/read.o disk/write.o disk/msdos.o \
+ disk/util.o disk/labels.o disk/swsusp.o disk/error.o vpd/vpd.o
BINDIR = /usr/bin
LIBDIR = /usr/lib
diff --git a/com32/gpllib/disk/ata.c b/com32/gpllib/disk/ata.c
new file mode 100644
index 00000000..f1716ffa
--- /dev/null
+++ b/com32/gpllib/disk/ata.c
@@ -0,0 +1,59 @@
+/**
+ * ata_id_string - Convert IDENTIFY DEVICE page into string
+ * @id: IDENTIFY DEVICE results we will examine
+ * @s: string into which data is output
+ * @ofs: offset into identify device page
+ * @len: length of string to return. must be an even number.
+ *
+ * The strings in the IDENTIFY DEVICE page are broken up into
+ * 16-bit chunks. Run through the string, and output each
+ * 8-bit chunk linearly, regardless of platform.
+ *
+ * LOCKING:
+ * caller.
+ */
+void ata_id_string(const uint16_t * id, unsigned char *s,
+ unsigned int ofs, unsigned int len)
+{
+ unsigned int c;
+
+ while (len > 0) {
+ c = id[ofs] >> 8;
+ *s = c;
+ s++;
+
+ c = id[ofs] & 0xff;
+ *s = c;
+ s++;
+
+ ofs++;
+ len -= 2;
+ }
+}
+
+/**
+ * ata_id_c_string - Convert IDENTIFY DEVICE page into C string
+ * @id: IDENTIFY DEVICE results we will examine
+ * @s: string into which data is output
+ * @ofs: offset into identify device page
+ * @len: length of string to return. must be an odd number.
+ *
+ * This function is identical to ata_id_string except that it
+ * trims trailing spaces and terminates the resulting string with
+ * null. @len must be actual maximum length (even number) + 1.
+ *
+ * LOCKING:
+ * caller.
+ */
+void ata_id_c_string(const uint16_t * id, unsigned char *s,
+ unsigned int ofs, unsigned int len)
+{
+ unsigned char *p;
+
+ ata_id_string(id, s, ofs, len - 1);
+
+ p = s + strnlen(s, len - 1);
+ while (p > s && p[-1] == ' ')
+ p--;
+ *p = '\0';
+}
diff --git a/com32/gpllib/disk/error.c b/com32/gpllib/disk/error.c
new file mode 100644
index 00000000..763dcfdc
--- /dev/null
+++ b/com32/gpllib/disk/error.c
@@ -0,0 +1,127 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * get_error - decode a disk error status
+ * @status: Error code
+ * @buffer_ptr: Pointer to set to the error message
+ *
+ * A buffer will be allocated to contain the error message.
+ * @buffer_ptr will point to it. The caller will need to free it.
+ **/
+void get_error(int status, char** buffer_ptr)
+{
+ int buffer_size = (80 * sizeof(char));
+ char* buffer = malloc(buffer_size);
+ *buffer_ptr = buffer;
+
+ switch (status) {
+ case 0x0:
+ strncpy(buffer, "successful completion", buffer_size);
+ break;
+ case 0x01:
+ strncpy(buffer, "invalid function in AH or invalid parameter", buffer_size);
+ break;
+ case 0x02:
+ strncpy(buffer, "address mark not found", buffer_size);
+ break;
+ case 0x03:
+ strncpy(buffer, "disk write-protected", buffer_size);
+ break;
+ case 0x04:
+ strncpy(buffer, "sector not found/read error", buffer_size);
+ break;
+ case 0x05:
+ strncpy(buffer, "reset failed (hard disk)", buffer_size);
+ //strncpy(buffer, "data did not verify correctly (TI Professional PC)", buffer_size);
+ break;
+ case 0x06:
+ strncpy(buffer, "disk changed (floppy)", buffer_size);
+ break;
+ case 0x07:
+ strncpy(buffer, "drive parameter activity failed (hard disk)", buffer_size);
+ break;
+ case 0x08:
+ strncpy(buffer, "DMA overrun", buffer_size);
+ break;
+ case 0x09:
+ strncpy(buffer, "data boundary error (attempted DMA across 64K boundary or >80h sectors)", buffer_size);
+ break;
+ case 0x0A:
+ strncpy(buffer, "bad sector detected (hard disk)", buffer_size);
+ break;
+ case 0x0B:
+ strncpy(buffer, "bad track detected (hard disk)", buffer_size);
+ break;
+ case 0x0C:
+ strncpy(buffer, "unsupported track or invalid media", buffer_size);
+ break;
+ case 0x0D:
+ strncpy(buffer, "invalid number of sectors on format (PS/2 hard disk)", buffer_size);
+ break;
+ case 0x0E:
+ strncpy(buffer, "control data address mark detected (hard disk)", buffer_size);
+ break;
+ case 0x0F:
+ strncpy(buffer, "DMA arbitration level out of range (hard disk)", buffer_size);
+ break;
+ case 0x10:
+ strncpy(buffer, "uncorrectable CRC or ECC error on read", buffer_size);
+ break;
+ case 0x11:
+ strncpy(buffer, "data ECC corrected (hard disk)", buffer_size);
+ break;
+ case 0x20:
+ strncpy(buffer, "controller failure", buffer_size);
+ break;
+ case 0x31:
+ strncpy(buffer, "no media in drive (IBM/MS INT 13 extensions)", buffer_size);
+ break;
+ case 0x32:
+ strncpy(buffer, "incorrect drive type stored in CMOS (Compaq)", buffer_size);
+ break;
+ case 0x40:
+ strncpy(buffer, "seek failed", buffer_size);
+ break;
+ case 0x80:
+ strncpy(buffer, "timeout (not ready)", buffer_size);
+ break;
+ case 0xAA:
+ strncpy(buffer, "drive not ready (hard disk)", buffer_size);
+ break;
+ case 0xB0:
+ strncpy(buffer, "volume not locked in drive (INT 13 extensions)", buffer_size);
+ break;
+ case 0xB1:
+ strncpy(buffer, "volume locked in drive (INT 13 extensions)", buffer_size);
+ break;
+ case 0xB2:
+ strncpy(buffer, "volume not removable (INT 13 extensions)", buffer_size);
+ break;
+ case 0xB3:
+ strncpy(buffer, "volume in use (INT 13 extensions)", buffer_size);
+ break;
+ case 0xB4:
+ strncpy(buffer, "lock count exceeded (INT 13 extensions)", buffer_size);
+ break;
+ case 0xB5:
+ strncpy(buffer, "valid eject request failed (INT 13 extensions)", buffer_size);
+ break;
+ case 0xBB:
+ strncpy(buffer, "undefined error (hard disk)", buffer_size);
+ break;
+ case 0xCC:
+ strncpy(buffer, "write fault (hard disk)", buffer_size);
+ break;
+ case 0xE0:
+ strncpy(buffer, "status register error (hard disk)", buffer_size);
+ break;
+ case 0xFF:
+ strncpy(buffer, "sense operation failed (hard disk)", buffer_size);
+ break;
+ default:
+ snprintf(buffer, buffer_size, "unknown error 0x%X, buggy bios?", status);
+ break;
+ }
+}
diff --git a/com32/gpllib/disk/geom.c b/com32/gpllib/disk/geom.c
new file mode 100644
index 00000000..7bbb698d
--- /dev/null
+++ b/com32/gpllib/disk/geom.c
@@ -0,0 +1,240 @@
+#include <com32.h>
+#include <string.h>
+#include <stdio.h>
+#include <disk/geom.h>
+
+#include <stdio.h>
+
+/**
+ * lba_to_chs - split given lba into cylinders/heads/sectors
+ **/
+void lba_to_chs(const struct driveinfo* drive_info, const int lba,
+ unsigned int* cylinder, unsigned int* head,
+ unsigned int* sector)
+{
+ unsigned int track;
+
+ /* 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);
+ }
+}
+
+/**
+ * detect_extensions - detect if we can use extensions
+ *
+ * INT 13 - IBM/MS INT 13 Extensions - INSTALLATION CHECK
+ * AH = 41h
+ * BX = 55AAh
+ * DL = drive (80h-FFh)
+ *
+ * Return: CF set on error (extensions not supported)
+ * AH = 01h (invalid function)
+ * CF clear if successful
+ * BX = AA55h if installed
+ * AH = major version of extensions
+ * 01h = 1.x
+ * 20h = 2.0 / EDD-1.0
+ * 21h = 2.1 / EDD-1.1
+ * 30h = EDD-3.0
+ * AL = internal use
+ * CX = API subset support bitmap (see #00271)
+ * DH = extension version (v2.0+ ??? -- not present in 1.x)
+ *
+ * Note: the Phoenix Enhanced Disk Drive Specification v1.0 uses version 2.0 of
+ * the INT 13 Extensions API
+ *
+ * Bitfields for IBM/MS INT 13 Extensions API support bitmap:
+ * Bit(s) Description (Table 00271)
+ * 0 extended disk access functions (AH=42h-44h,47h,48h) supported
+ * 1 removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h)
+ * supported
+ * 2 enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported
+ * extended drive parameter table is valid (see #00273,#00278)
+ * 3-15 reserved (0)
+ **/
+static int detect_extensions(struct driveinfo* drive_info)
+{
+ com32sys_t getebios, ebios;
+
+ memset(&getebios, 0, sizeof getebios);
+ memset(&ebios, 0, sizeof ebios);
+
+ getebios.eflags.b[0] = 0x3; /* CF set */
+ getebios.ebx.w[0] = 0x55aa;
+ getebios.edx.b[0] = drive_info->disk;
+ getebios.eax.b[1] = 0x41;
+
+ __intcall(0x13, &getebios, &ebios);
+
+ if ( !(ebios.eflags.l & EFLAGS_CF) &&
+ ebios.ebx.w[0] == 0xaa55 ) {
+ 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? */
+}
+
+/**
+ * get_drive_parameters_with_extensions - retrieve disk parameters via AH=48h
+ *
+ * INT 13 - IBM/MS INT 13 Extensions - GET DRIVE PARAMETERS
+ * AH = 48h
+ * DL = drive (80h-FFh)
+ * DS:SI -> buffer for drive parameters
+ * Return: CF clear if successful
+ * AH = 00h
+ * DS:SI buffer filled
+ * CF set on error
+ * AH = error code (see #00234)
+ * BUG: several different Compaq BIOSes incorrectly report high-numbered
+ * drives (such as 90h, B0h, D0h, and F0h) as present, giving them the
+ * same geometry as drive 80h; as a workaround, scan through disk
+ * numbers, stopping as soon as the number of valid drives encountered
+ * equals the value in 0040h:0075h
+ **/
+static int get_drive_parameters_with_extensions(struct driveinfo* drive_info)
+{
+ com32sys_t inreg, outreg;
+ struct device_parameter *dp = __com32.cs_bounce;
+
+ memset(&inreg, 0, sizeof inreg);
+
+ 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);
+
+ /* CF set on error */
+ if ( outreg.eflags.l & EFLAGS_CF )
+ return outreg.eax.b[1];
+
+ memcpy(&drive_info->edd_params, dp, sizeof drive_info->edd_params);
+
+ return 0;
+}
+
+/**
+ * get_drive_parameters_without_extensions - retrieve drive parameters via AH=08h
+ *
+ * INT 13 - DISK - GET DRIVE PARAMETERS (PC,XT286,CONV,PS,ESDI,SCSI)
+ * AH = 08h
+ * DL = drive (bit 7 set for hard disk)
+ *
+ * Return: CF set on error
+ * AH = status (07h) (see #00234)
+ * CF clear if successful
+ * AH = 00h
+ * AL = 00h on at least some BIOSes
+ * BL = drive type (AT/PS2 floppies only) (see #00242)
+ * CH = low eight bits of maximum cylinder number
+ * CL = maximum sector number (bits 5-0)
+ * high two bits of maximum cylinder number (bits 7-6)
+ * DH = maximum head number
+ * DL = number of drives
+ * ES:DI -> drive parameter table (floppies only)
+ *
+ * Notes:
+ * - may return successful even though specified drive is greater than the
+ * number of attached drives of that type (floppy/hard); check DL to
+ * ensure validity
+ * - for systems predating the IBM AT, this call is only valid for hard
+ * disks, as it is implemented by the hard disk BIOS rather than the
+ * ROM BIOS
+ * - Toshiba laptops with HardRAM return DL=02h when called with DL=80h,
+ * but fail on DL=81h. The BIOS data at 40h:75h correctly reports 01h.
+ * may indicate only two drives present even if more are attached; to
+ * ensure a correct count, one can use AH=15h to scan through possible
+ * drives
+ * - for BIOSes which reserve the last cylinder for testing purposes, the
+ * cylinder count is automatically decremented
+ * on PS/1s with IBM ROM DOS 4, nonexistent drives return CF clear,
+ * BX=CX=0000h, and ES:DI = 0000h:0000h
+ * - the PC-Tools PCFORMAT program requires that AL=00h before it will
+ * proceed with the formatting
+ *
+ * BUG: several different Compaq BIOSes incorrectly report high-numbered
+ * drives (such as 90h, B0h, D0h, and F0h) as present, giving them the
+ * same geometry as drive 80h; as a workaround, scan through disk
+ * numbers, stopping as soon as the number of valid drives encountered
+ * equals the value in 0040h:0075h
+ *
+ * SeeAlso: AH=06h"Adaptec",AH=13h"SyQuest",AH=48h,AH=15h,INT 1E
+ * SeeAlso: INT 41"HARD DISK 0"
+ **/
+static int get_drive_parameters_without_extensions(struct driveinfo* drive_info)
+{
+ com32sys_t getparm, parm;
+
+ memset(&getparm, 0, sizeof getparm);
+ memset(&parm, 0, sizeof parm);
+
+ /* 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);
+
+ /* CF set on error */
+ if ( parm.eflags.l & EFLAGS_CF )
+ return parm.eax.b[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->legacy_type = parm.ebx.b[0];
+
+ /* 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->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->legacy_max_cylinder = parm.ecx.b[1] +
+ ((parm.ecx.b[0] & 0xc0) << 2);
+
+ if ( drive_info->legacy_sectors_per_track > 0 )
+ drive_info->cbios = 1; /* Valid geometry */
+
+ return 0;
+}
+
+/**
+ * get_drive_parameters - retrieve drive parameters
+ * @drive_info: driveinfo structure to fill
+ **/
+int get_drive_parameters(struct driveinfo *drive_info)
+{
+ if (detect_extensions(drive_info))
+ return -1;
+
+ if (drive_info->ebios)
+ get_drive_parameters_with_extensions(drive_info);
+
+ return get_drive_parameters_without_extensions(drive_info);
+}
diff --git a/com32/gpllib/disk/labels.c b/com32/gpllib/disk/labels.c
new file mode 100644
index 00000000..cb28be9d
--- /dev/null
+++ b/com32/gpllib/disk/labels.c
@@ -0,0 +1,245 @@
+#include <stdlib.h>
+#include <string.h>
+
+void get_label(int label, char** buffer_label)
+{
+ int buffer_size = (80 * sizeof(char));
+ char* buffer = malloc(buffer_size);
+ *buffer_label = buffer;
+
+ switch (label) {
+ case 0x01: strncpy(buffer, "DOS 12-bit fat", buffer_size); break;
+ case 0x02: strncpy(buffer, "XENIX root", buffer_size); break;
+ case 0x03: strncpy(buffer, "XENIX /usr", buffer_size); break;
+ case 0x04: strncpy(buffer, "DOS 3.0+ 16-bit FAT (up to 32M)", buffer_size); break;
+ case 0x05: strncpy(buffer, "DOS 3.3+ Extended Partition", buffer_size); break;
+ case 0x06: strncpy(buffer, "DOS 3.31+ 16-bit FAT (over 32M)", buffer_size); break;
+ case 0x07: strncpy(buffer, "OS/2 IFS (e.g., HPFS)", buffer_size); break;
+ //case 0x07: strncpy(buffer, "Advanced Unix", buffer_size); break;
+ //case 0x07: strncpy(buffer, "Windows NT NTFS", buffer_size); break;
+ //case 0x07: strncpy(buffer, "QNX2.x (pre-1988)", buffer_size); break;
+ case 0x08: strncpy(buffer, "OS/2 (v1.0-1.3 only)", buffer_size); break;
+ //case 0x08: strncpy(buffer, "AIX boot partition", buffer_size); break;
+ //case 0x08: strncpy(buffer, "SplitDrive", buffer_size); break;
+ //case 0x08: strncpy(buffer, "DELL partition spanning multiple drives", buffer_size); break;
+ //case 0x08: strncpy(buffer, "Commodore DOS", buffer_size); break;
+ //case 0x08: strncpy(buffer, "QNX 1.x and 2.x ("qny")", buffer_size); break;
+ case 0x09: strncpy(buffer, "AIX data partition", buffer_size); break;
+ //case 0x09: strncpy(buffer, "Coherent filesystem", buffer_size); break;
+ //case 0x09: strncpy(buffer, "QNX 1.x and 2.x ("qnz")", buffer_size); break;
+ case 0x0a: strncpy(buffer, "OS/2 Boot Manager", buffer_size); break;
+ //case 0x0a: strncpy(buffer, "Coherent swap partition", buffer_size); break;
+ //case 0x0a: strncpy(buffer, "OPUS", buffer_size); break;
+ case 0x0b: strncpy(buffer, "WIN95 OSR2 32-bit FAT", buffer_size); break;
+ case 0x0c: strncpy(buffer, "WIN95 OSR2 32-bit FAT, LBA-mapped", buffer_size); break;
+ case 0x0e: strncpy(buffer, "WIN95: DOS 16-bit FAT, LBA-mapped", buffer_size); break;
+ case 0x0f: strncpy(buffer, "WIN95: Extended partition, LBA-mapped", buffer_size); break;
+ case 0x10: strncpy(buffer, "OPUS (?)", buffer_size); break;
+ case 0x11: strncpy(buffer, "Hidden DOS 12-bit FAT", buffer_size); break;
+ case 0x12: strncpy(buffer, "Compaq config partition", buffer_size); break;
+ case 0x14: strncpy(buffer, "Hidden DOS 16-bit FAT <32M", buffer_size); break;
+ case 0x16: strncpy(buffer, "Hidden DOS 16-bit FAT >=32M", buffer_size); break;
+ case 0x17: strncpy(buffer, "Hidden IFS (e.g., HPFS)", buffer_size); break;
+ case 0x18: strncpy(buffer, "AST SmartSleep Partition", buffer_size); break;
+ case 0x19: strncpy(buffer, "Unused (Claimed for Willowtech Photon COS)", buffer_size); break;
+ case 0x1b: strncpy(buffer, "Hidden WIN95 OSR2 32-bit FAT", buffer_size); break;
+ case 0x1c: strncpy(buffer, "Hidden WIN95 OSR2 32-bit FAT, LBA-mapped", buffer_size); break;
+ case 0x1e: strncpy(buffer, "Hidden WIN95 16-bit FAT, LBA-mapped", buffer_size); break;
+ case 0x20: strncpy(buffer, "Unused", buffer_size); break;
+ case 0x21: strncpy(buffer, "Reserved", buffer_size); break;
+ //case 0x21: strncpy(buffer, "Unused", buffer_size); break;
+ case 0x22: strncpy(buffer, "Unused", buffer_size); break;
+ case 0x23: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0x24: strncpy(buffer, "NEC DOS 3.x", buffer_size); break;
+ case 0x26: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0x31: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0x32: strncpy(buffer, "NOS", buffer_size); break;
+ case 0x33: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0x34: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0x35: strncpy(buffer, "JFS on OS/2 or eCS", buffer_size); break;
+ case 0x36: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0x38: strncpy(buffer, "THEOS ver 3.2 2gb partition", buffer_size); break;
+ case 0x39: strncpy(buffer, "Plan 9 partition", buffer_size); break;
+ //case 0x39: strncpy(buffer, "THEOS ver 4 spanned partition", buffer_size); break;
+ case 0x3a: strncpy(buffer, "THEOS ver 4 4gb partition", buffer_size); break;
+ case 0x3b: strncpy(buffer, "THEOS ver 4 extended partition", buffer_size); break;
+ case 0x3c: strncpy(buffer, "PartitionMagic recovery partition", buffer_size); break;
+ case 0x3d: strncpy(buffer, "Hidden NetWare", buffer_size); break;
+ case 0x40: strncpy(buffer, "Venix 80286", buffer_size); break;
+ case 0x41: strncpy(buffer, "Linux/MINIX (sharing disk with DRDOS)", buffer_size); break;
+ //case 0x41: strncpy(buffer, "Personal RISC Boot", buffer_size); break;
+ //case 0x41: strncpy(buffer, "PPC PReP (Power PC Reference Platform) Boot", buffer_size); break;
+ case 0x42: strncpy(buffer, "Linux swap (sharing disk with DRDOS)", buffer_size); break;
+ //case 0x42: strncpy(buffer, "SFS (Secure Filesystem)", buffer_size); break;
+ //case 0x42: strncpy(buffer, "Windows 2000 marker", buffer_size); break;
+ case 0x43: strncpy(buffer, "Linux native (sharing disk with DRDOS)", buffer_size); break;
+ case 0x44: strncpy(buffer, "GoBack partition", buffer_size); break;
+ case 0x45: strncpy(buffer, "Boot-US boot manager", buffer_size); break;
+ //case 0x45: strncpy(buffer, "Priam", buffer_size); break;
+ //case 0x45: strncpy(buffer, "EUMEL/Elan", buffer_size); break;
+ case 0x46: strncpy(buffer, "EUMEL/Elan", buffer_size); break;
+ case 0x47: strncpy(buffer, "EUMEL/Elan", buffer_size); break;
+ case 0x48: strncpy(buffer, "EUMEL/Elan", buffer_size); break;
+ case 0x4a: strncpy(buffer, "AdaOS Aquila (Default)", buffer_size); break;
+ //case 0x4a: strncpy(buffer, "ALFS/THIN lightweight filesystem for DOS", buffer_size); break;
+ case 0x4c: strncpy(buffer, "Oberon partition", buffer_size); break;
+ case 0x4d: strncpy(buffer, "QNX4.x", buffer_size); break;
+ case 0x4e: strncpy(buffer, "QNX4.x 2nd part", buffer_size); break;
+ case 0x4f: strncpy(buffer, "QNX4.x 3rd part", buffer_size); break;
+ //case 0x4f: strncpy(buffer, "Oberon partition", buffer_size); break;
+ case 0x50: strncpy(buffer, "OnTrack Disk Manager (older versions) RO", buffer_size); break;
+ //case 0x50: strncpy(buffer, "Lynx RTOS", buffer_size); break;
+ //case 0x50: strncpy(buffer, "Native Oberon (alt)", buffer_size); break;
+ case 0x51: strncpy(buffer, "OnTrack Disk Manager RW (DM6 Aux1)", buffer_size); break;
+ //case 0x51: strncpy(buffer, "Novell", buffer_size); break;
+ case 0x52: strncpy(buffer, "CP/M", buffer_size); break;
+ //case 0x52: strncpy(buffer, "Microport SysV/AT", buffer_size); break;
+ case 0x53: strncpy(buffer, "Disk Manager 6.0 Aux3", buffer_size); break;
+ case 0x54: strncpy(buffer, "Disk Manager 6.0 Dynamic Drive Overlay", buffer_size); break;
+ case 0x55: strncpy(buffer, "EZ-Drive", buffer_size); break;
+ case 0x56: strncpy(buffer, "Golden Bow VFeature Partitioned Volume.", buffer_size); break;
+ //case 0x56: strncpy(buffer, "DM converted to EZ-BIOS", buffer_size); break;
+ case 0x57: strncpy(buffer, "DrivePro", buffer_size); break;
+ //case 0x57: strncpy(buffer, "VNDI Partition", buffer_size); break;
+ case 0x5c: strncpy(buffer, "Priam EDisk", buffer_size); break;
+ case 0x61: strncpy(buffer, "SpeedStor", buffer_size); break;
+ case 0x63: strncpy(buffer, "Unix System V (SCO, ISC Unix, UnixWare, ...), Mach, GNU Hurd", buffer_size); break;
+ case 0x64: strncpy(buffer, "PC-ARMOUR protected partition", buffer_size); break;
+ //case 0x64: strncpy(buffer, "Novell Netware 286, 2.xx", buffer_size); break;
+ case 0x65: strncpy(buffer, "Novell Netware 386, 3.xx or 4.xx", buffer_size); break;
+ case 0x66: strncpy(buffer, "Novell Netware SMS Partition", buffer_size); break;
+ case 0x67: strncpy(buffer, "Novell", buffer_size); break;
+ case 0x68: strncpy(buffer, "Novell", buffer_size); break;
+ case 0x69: strncpy(buffer, "Novell Netware 5+, Novell Netware NSS Partition", buffer_size); break;
+ case 0x70: strncpy(buffer, "DiskSecure Multi-Boot", buffer_size); break;
+ case 0x71: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0x73: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0x74: strncpy(buffer, "Reserved", buffer_size); break;
+ //case 0x74: strncpy(buffer, "Scramdisk partition", buffer_size); break;
+ case 0x75: strncpy(buffer, "IBM PC/IX", buffer_size); break;
+ case 0x76: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0x77: strncpy(buffer, "M2FS/M2CS partition", buffer_size); break;
+ //case 0x77: strncpy(buffer, "VNDI Partition", buffer_size); break;
+ case 0x78: strncpy(buffer, "XOSL FS", buffer_size); break;
+ case 0x7E: strncpy(buffer, " ", buffer_size); break;
+ case 0x80: strncpy(buffer, "MINIX until 1.4a", buffer_size); break;
+ case 0x81: strncpy(buffer, "MINIX since 1.4b, early Linux", buffer_size); break;
+ //case 0x81: strncpy(buffer, "Mitac disk manager", buffer_size); break;
+ //case 0x82: strncpy(buffer, "Prime", buffer_size); break;
+ //case 0x82: strncpy(buffer, "Solaris x86", buffer_size); break;
+ case 0x82: strncpy(buffer, "Linux swap", buffer_size); break;
+ case 0x83: strncpy(buffer, "Linux native (usually ext2fs)", buffer_size); break;
+ case 0x84: strncpy(buffer, "OS/2 hidden C: drive", buffer_size); break;
+ //case 0x84: strncpy(buffer, "Hibernation partition", buffer_size); break;
+ case 0x85: strncpy(buffer, "Linux extended partition", buffer_size); break;
+ //case 0x86: strncpy(buffer, "Old Linux RAID partition superblock", buffer_size); break;
+ case 0x86: strncpy(buffer, "NTFS volume set", buffer_size); break;
+ case 0x87: strncpy(buffer, "NTFS volume set", buffer_size); break;
+ case 0x8a: strncpy(buffer, "Linux Kernel Partition (used by AiR-BOOT)", buffer_size); break;
+ case 0x8b: strncpy(buffer, "Legacy Fault Tolerant FAT32 volume", buffer_size); break;
+ case 0x8c: strncpy(buffer, "Legacy Fault Tolerant FAT32 volume using BIOS extd INT 13h", buffer_size); break;
+ case 0x8d: strncpy(buffer, "Free FDISK hidden Primary DOS FAT12 partitition", buffer_size); break;
+ case 0x8e: strncpy(buffer, "Linux Logical Volume Manager partition", buffer_size); break;
+ case 0x90: strncpy(buffer, "Free FDISK hidden Primary DOS FAT16 partitition", buffer_size); break;
+ case 0x91: strncpy(buffer, "Free FDISK hidden DOS extended partitition", buffer_size); break;
+ case 0x92: strncpy(buffer, "Free FDISK hidden Primary DOS large FAT16 partitition", buffer_size); break;
+ case 0x93: strncpy(buffer, "Hidden Linux native partition", buffer_size); break;
+ //case 0x93: strncpy(buffer, "Amoeba", buffer_size); break;
+ case 0x94: strncpy(buffer, "Amoeba bad block table", buffer_size); break;
+ case 0x95: strncpy(buffer, "MIT EXOPC native partitions", buffer_size); break;
+ case 0x97: strncpy(buffer, "Free FDISK hidden Primary DOS FAT32 partitition", buffer_size); break;
+ case 0x98: strncpy(buffer, "Free FDISK hidden Primary DOS FAT32 partitition (LBA)", buffer_size); break;
+ case 0x99: strncpy(buffer, "DCE376 logical drive", buffer_size); break;
+ case 0x9a: strncpy(buffer, "Free FDISK hidden Primary DOS FAT16 partitition (LBA)", buffer_size); break;
+ case 0x9b: strncpy(buffer, "Free FDISK hidden DOS extended partitition (LBA)", buffer_size); break;
+ case 0x9f: strncpy(buffer, "BSD/OS", buffer_size); break;
+ case 0xa0: strncpy(buffer, "Laptop hibernation partition", buffer_size); break;
+ case 0xa1: strncpy(buffer, "Laptop hibernation partition", buffer_size); break;
+ //case 0xa1: strncpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size); break;
+ case 0xa3: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0xa4: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0xa5: strncpy(buffer, "BSD/386, 386BSD, NetBSD, FreeBSD", buffer_size); break;
+ case 0xa6: strncpy(buffer, "OpenBSD", buffer_size); break;
+ case 0xa7: strncpy(buffer, "NEXTSTEP", buffer_size); break;
+ case 0xa8: strncpy(buffer, "Mac OS-X", buffer_size); break;
+ case 0xa9: strncpy(buffer, "NetBSD", buffer_size); break;
+ case 0xaa: strncpy(buffer, "Olivetti Fat 12 1.44Mb Service Partition", buffer_size); break;
+ case 0xab: strncpy(buffer, "Mac OS-X Boot partition", buffer_size); break;
+ //case 0xab: strncpy(buffer, "GO! partition", buffer_size); break;
+ case 0xae: strncpy(buffer, "ShagOS filesystem", buffer_size); break;
+ case 0xaf: strncpy(buffer, "ShagOS swap partition", buffer_size); break;
+ case 0xb0: strncpy(buffer, "BootStar Dummy", buffer_size); break;
+ case 0xb1: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0xb3: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0xb4: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0xb6: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0xb7: strncpy(buffer, "BSDI BSD/386 filesystem", buffer_size); break;
+ case 0xb8: strncpy(buffer, "BSDI BSD/386 swap partition", buffer_size); break;
+ case 0xbb: strncpy(buffer, "Boot Wizard hidden", buffer_size); break;
+ case 0xbe: strncpy(buffer, "Solaris 8 boot partition", buffer_size); break;
+ case 0xc0: strncpy(buffer, "CTOS", buffer_size); break;
+ //case 0xc0: strncpy(buffer, "REAL/32 secure small partition", buffer_size); break;
+ //case 0xc0: strncpy(buffer, "NTFT Partition", buffer_size); break;
+ case 0xc1: strncpy(buffer, "DRDOS/secured (FAT-12)", buffer_size); break;
+ case 0xc2: strncpy(buffer, "Reserved for DR-DOS 7+", buffer_size); break;
+ //case 0xc2: strncpy(buffer, "Hidden Linux", buffer_size); break;
+ case 0xc3: strncpy(buffer, "Hidden Linux swap", buffer_size); break;
+ case 0xc4: strncpy(buffer, "DRDOS/secured (FAT-16, < 32M)", buffer_size); break;
+ case 0xc5: strncpy(buffer, "DRDOS/secured (extended)", buffer_size); break;
+ case 0xc6: strncpy(buffer, "DRDOS/secured (FAT-16, >= 32M)", buffer_size); break;
+ //case 0xc6: strncpy(buffer, "Windows NT corrupted FAT16 volume/stripe set", buffer_size); break;
+ case 0xc7: strncpy(buffer, "Windows NT corrupted NTFS volume/stripe set", buffer_size); break;
+ //case 0xc7: strncpy(buffer, "Syrinx boot", buffer_size); break;
+ case 0xc8: strncpy(buffer, "(See also ID c2.)", buffer_size); break;
+ case 0xc9: strncpy(buffer, "(See also ID c2.)", buffer_size); break;
+ case 0xca: strncpy(buffer, "(See also ID c2.)", buffer_size); break;
+ case 0xcb: strncpy(buffer, "reserved for DRDOS/secured (FAT32)", buffer_size); break;
+ case 0xcc: strncpy(buffer, "reserved for DRDOS/secured (FAT32, LBA)", buffer_size); break;
+ case 0xcd: strncpy(buffer, "CTOS Memdump?", buffer_size); break;
+ case 0xce: strncpy(buffer, "reserved for DRDOS/secured (FAT16, LBA)", buffer_size); break;
+ case 0xd0: strncpy(buffer, "REAL/32 secure big partition", buffer_size); break;
+ case 0xd1: strncpy(buffer, "Old Multiuser DOS secured FAT12", buffer_size); break;
+ case 0xd4: strncpy(buffer, "Old Multiuser DOS secured FAT16 <32M", buffer_size); break;
+ case 0xd5: strncpy(buffer, "Old Multiuser DOS secured extended partition", buffer_size); break;
+ case 0xd6: strncpy(buffer, "Old Multiuser DOS secured FAT16 >=32M", buffer_size); break;
+ case 0xd8: strncpy(buffer, "CP/M-86", buffer_size); break;
+ case 0xda: strncpy(buffer, "Non-FS Data", buffer_size); break;
+ case 0xdb: strncpy(buffer, "Digital Research CP/M, Concurrent CP/M, Concurrent DOS", buffer_size); break;
+ //case 0xdb: strncpy(buffer, "CTOS (Convergent Technologies OS -Unisys)", buffer_size); break;
+ //case 0xdb: strncpy(buffer, "KDG Telemetry SCPU boot", buffer_size); break;
+ case 0xdd: strncpy(buffer, "Hidden CTOS Memdump?", buffer_size); break;
+ case 0xde: strncpy(buffer, "Dell PowerEdge Server utilities (FAT fs)", buffer_size); break;
+ case 0xdf: strncpy(buffer, "DG/UX virtual disk manager partition", buffer_size); break;
+ //case 0xdf: strncpy(buffer, "BootIt EMBRM", buffer_size); break;
+ case 0xe0: strncpy(buffer, "Reserved by STMicroelectronics for a filesystem called ST AVFS.", buffer_size); break;
+ case 0xe1: strncpy(buffer, "DOS access or SpeedStor 12-bit FAT extended partition", buffer_size); break;
+ case 0xe3: strncpy(buffer, "DOS R/O or SpeedStor", buffer_size); break;
+ case 0xe4: strncpy(buffer, "SpeedStor 16-bit FAT extended partition < 1024 cyl.", buffer_size); break;
+ case 0xe5: strncpy(buffer, "Tandy DOS with logical sectored FAT (According to Powerquest.)", buffer_size); break;
+ //case 0xe5: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0xe6: strncpy(buffer, "Reserved", buffer_size); break;
+ case 0xeb: strncpy(buffer, "BFS (aka BeFS)", buffer_size); break;
+ case 0xed: strncpy(buffer, "Reserved for Matthias Paul's Sprytix", buffer_size); break;
+ case 0xee: strncpy(buffer, "Indication that this legacy MBR is followed by an EFI header", buffer_size); break;
+ case 0xef: strncpy(buffer, "Partition that contains an EFI file system", buffer_size); break;
+ case 0xf0: strncpy(buffer, "Linux/PA-RISC boot loader", buffer_size); break;
+ case 0xf1: strncpy(buffer, "SpeedStor", buffer_size); break;
+ case 0xf2: strncpy(buffer, "DOS 3.3+ secondary partition (Powerquest writes: Unisys DOS with logical sectored FAT.)", buffer_size); break;
+ case 0xf3: strncpy(buffer, "Reserved (Powerquest writes: Storage Dimensions SpeedStor.)", buffer_size); break;
+ case 0xf4: strncpy(buffer, "SpeedStor large partition", buffer_size); break;
+ //case 0xf4: strncpy(buffer, "Prologue single-volume partition", buffer_size); break;
+ case 0xf5: strncpy(buffer, "Prologue multi-volume partition", buffer_size); break;
+ case 0xf6: strncpy(buffer, "Reserved (Powerquest writes: Storage Dimensions SpeedStor. )", buffer_size); break;
+ case 0xfa: strncpy(buffer, "Bochs", buffer_size); break;
+ case 0xfb: strncpy(buffer, "VMware File System partition", buffer_size); break;
+ case 0xfc: strncpy(buffer, "VMware Swap partition", buffer_size); break;
+ case 0xfd: strncpy(buffer, "Linux raid partition with autodetect using persistent superblock (Powerquest writes: Reserved for FreeDOS. )", buffer_size); break;
+ case 0xfe: strncpy(buffer, "SpeedStor > 1024 cyl.", buffer_size); break;
+ //case 0xfe: strncpy(buffer, "LANstep", buffer_size); break;
+ //case 0xfe: strncpy(buffer, "IBM PS/2 IML (Initial Microcode Load) partition, located at the end of the disk.", buffer_size); break;
+ //case 0xfe: strncpy(buffer, "Windows NT Disk Administrator hidden partition", buffer_size); break;
+ //case 0xfe: strncpy(buffer, "Linux Logical Volume Manager partition (old)", buffer_size); break;
+ case 0xff: strncpy(buffer, "Xenix Bad Block Table ", buffer_size); break;
+ default: strncpy(buffer, "Unknown", buffer_size); break;
+ }
+}
diff --git a/com32/gpllib/disk/msdos.c b/com32/gpllib/disk/msdos.c
new file mode 100644
index 00000000..da28b8bb
--- /dev/null
+++ b/com32/gpllib/disk/msdos.c
@@ -0,0 +1,149 @@
+#include <stdlib.h>
+#include <disk/geom.h>
+#include <disk/partition.h>
+#include <disk/read.h>
+
+static inline int is_extended_partition(struct part_entry *ptab)
+{
+ return (ptab->ostype == 0x05 ||
+ ptab->ostype == 0x0f ||
+ ptab->ostype == 0x85);
+}
+static inline int msdos_magic_present(char *ptab)
+{
+ return ( *(uint16_t *)(ptab + 0x1fe) == 0xaa55 );
+}
+
+/**
+ * process_ebr - execute a callback for each partition contained in an ebr
+ * @drive_info: driveinfo struct describing the drive
+ * @ptab_root: part_entry struct describing the root partition (pointing to the ebr)
+ * @ebr_seen: Number of ebr processed
+ * @callback: Callback to execute
+ **/
+static void process_ebr(struct driveinfo *drive_info, struct part_entry *ptab_root,
+ int ebr_seen,
+ void *callback(struct driveinfo *, struct part_entry *, struct part_entry *, int, int, int),
+ int *error, int offset_root)
+{
+ /* The ebr is located at the first sector of the extended partition */
+ char* ebr = read_sectors(drive_info, ptab_root->start_lba+offset_root, 1, error);
+ if (!ebr)
+ return;
+
+ /* Check msdos magic signature */
+ if(!msdos_magic_present(ebr))
+ return;
+ ebr_seen += 1;
+
+ struct part_entry *ptab_child = (struct part_entry *)(ebr + PARTITION_TABLES_OFFSET);
+
+ /* First process the data partitions */
+ for (int i = 0; i < 4; i++) {
+ if (*error)
+ return;
+
+ if (ptab_child[i].start_sect > 0) {
+ if (is_extended_partition(&ptab_child[i])) {
+ continue;
+ }
+
+ /* Check for garbage in the 3rd and 4th entries */
+ if (i > 2) {
+ unsigned int offset = ptab_child->start_lba + ptab_root->start_lba;
+ if ( offset + ptab_child->length <= ptab_root->start_lba ||
+ offset >= ptab_root->start_lba + ptab_root->length ) {
+ continue;
+ }
+ }
+ callback(drive_info,
+ &ptab_child[i],
+ ptab_root,
+ offset_root,
+ i,
+ ebr_seen);
+ }
+ }
+
+ /* Now process the extended partitions */
+ for (int i = 0; i < 4; i++) {
+ if (is_extended_partition(&ptab_child[i])) {
+ callback(drive_info,
+ &ptab_child[i],
+ ptab_root,
+ offset_root,
+ i,
+ ebr_seen);
+ process_ebr(drive_info, &ptab_child[i], ebr_seen + 1, callback, error, ptab_root->start_lba);
+ }
+ }
+}
+
+/**
+ * process_mbr - execute a callback for each partition contained in an {m,e}br
+ * @drive_info: driveinfo struct describing the drive
+ * @ptab: Pointer to the partition table
+ * @callback: Callback to execute
+ * @error: Return the error code (I/O), if needed
+ **/
+static void process_mbr(struct driveinfo *drive_info, struct part_entry *ptab,
+ void *callback(struct driveinfo *, struct part_entry *, struct part_entry *, int, int, int),
+ int *error)
+{
+ for (int i = 0; i < 4; i++) {
+ if (*error)
+ return;
+
+ if (ptab[i].start_sect > 0) {
+ if (is_extended_partition(&ptab[i])) {
+ callback(drive_info,
+ &ptab[i],
+ ptab,
+ 0,
+ i,
+ 0);
+ process_ebr(drive_info, &ptab[i], 0, callback, error, 0);
+ } else
+ callback(drive_info,
+ &ptab[i],
+ ptab,
+ 0,
+ i,
+ 0);
+ }
+ }
+}
+
+/**
+ * parse_partition_table - execute a callback for each partition entry
+ * @d: driveinfo struct describing the drive
+ * @callback: Callback to execute
+ * @error: Return the error code (I/O), if needed
+ *
+ * The signature of the callback should be the following:
+ *
+ * void callback(struct driveinfo *drive_info,
+ * struct part_entry *ptab,
+ * struct part_entry *ptab_root,
+ * int offset_root,
+ * int local_partition_number,
+ * int ebr_seen)
+ **/
+int parse_partition_table(struct driveinfo *d, void *callback, int *error)
+{
+ char *mbr = read_mbr(d->disk, error);
+ if (!mbr)
+ return -1;
+ else {
+ /* Check msdos magic signature */
+ if (!msdos_magic_present(mbr))
+ return -1;
+
+ struct part_entry *ptab = (struct part_entry *)(mbr + PARTITION_TABLES_OFFSET);
+ process_mbr(d, ptab, callback, error);
+ if (*error)
+ return -1;
+ else
+ return 0;
+ }
+}
diff --git a/com32/gpllib/disk/read.c b/com32/gpllib/disk/read.c
new file mode 100644
index 00000000..a5cb120c
--- /dev/null
+++ b/com32/gpllib/disk/read.c
@@ -0,0 +1,113 @@
+#include <com32.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <disk/geom.h>
+#include <disk/read.h>
+#include <disk/util.h>
+#include <disk/common.h>
+
+/**
+ * read_mbr - return a pointer to a malloced buffer containing the mbr
+ * @drive: Drive number
+ * @error: Return the error code on failure
+ **/
+void *read_mbr(int drive, int *error)
+{
+ struct driveinfo drive_info;
+ drive_info.disk = drive;
+
+ /* MBR: lba = 0, 1 sector */
+ return read_sectors(&drive_info, 0, 1, error);
+}
+
+/**
+ * dev_read - read from a drive
+ * @drive: Drive number
+ * @lba: Position to start reading from
+ * @sectors: Number of sectors to read
+ * @error: Return the error code on failure
+ *
+ * High-level routine to read from a hard drive.
+ **/
+void *dev_read(int drive, unsigned int lba, int sectors, int *error)
+{
+ struct driveinfo drive_info;
+ drive_info.disk = drive;
+
+ return read_sectors(&drive_info, lba, sectors, error);
+}
+
+/**
+ * read_sectors - read several sectors from disk
+ * @drive_info: driveinfo struct describing the disk
+ * @lba: Position to read
+ * @sectors: Number of sectors to read
+ * @error: Return the error code on failure
+ *
+ * Return a pointer to a malloc'ed buffer containing the data.
+ **/
+void *read_sectors(struct driveinfo* drive_info, const unsigned int lba,
+ const int sectors, int *error)
+{
+ com32sys_t inreg, outreg;
+ struct ebios_dapa *dapa = __com32.cs_bounce;
+ void *buf = (char *)__com32.cs_bounce + sectors * SECTOR;
+ void *data;
+
+ if (get_drive_parameters(drive_info) == -1)
+ return NULL;
+
+ memset(&inreg, 0, sizeof inreg);
+
+ if (drive_info->ebios) {
+ dapa->len = sizeof(*dapa);
+ dapa->count = sectors;
+ dapa->off = OFFS(buf);
+ dapa->seg = SEG(buf);
+ dapa->lba = lba;
+
+ inreg.esi.w[0] = OFFS(dapa);
+ inreg.ds = SEG(dapa);
+ inreg.edx.b[0] = drive_info->disk;
+ inreg.eax.b[1] = 0x42; /* Extended read */
+ } else {
+ unsigned int c, h, s;
+
+ if (!drive_info->cbios) {
+ /* We failed to get the geometry */
+ if (lba)
+ return NULL; /* Can only read MBR */
+
+ s = 1; h = 0; c = 0;
+ } else
+ lba_to_chs(drive_info, lba, &s, &h, &c);
+
+ if ( s > 63 || h > 256 || c > 1023 )
+ return NULL;
+
+ inreg.eax.w[0] = 0x0201; /* Read one sector */
+ inreg.ecx.b[1] = c & 0xff;
+ inreg.ecx.b[0] = s + (c >> 6);
+ inreg.edx.b[1] = h;
+ inreg.edx.b[0] = drive_info->disk;
+ inreg.ebx.w[0] = OFFS(buf);
+ inreg.es = SEG(buf);
+ }
+
+ /* Perform the read */
+ if (int13_retry(&inreg, &outreg)) {
+ if (error)
+ *error = outreg.eax.b[1];
+ return NULL; /* Give up */
+ } else {
+ if (error)
+ *error = 0;
+ }
+
+ data = malloc(sectors * SECTOR);
+ if (data)
+ memcpy(data, buf, sectors * SECTOR);
+
+ return data;
+}
diff --git a/com32/gpllib/disk/swsusp.c b/com32/gpllib/disk/swsusp.c
new file mode 100644
index 00000000..f627aca4
--- /dev/null
+++ b/com32/gpllib/disk/swsusp.c
@@ -0,0 +1,31 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <disk/swsusp.h>
+#include <disk/read.h>
+#include <disk/geom.h>
+
+/**
+ * swsusp_check - check if a (swap) partition contains the swsusp signature
+ * @drive_info: driveinfo struct describing the disk containing the partition
+ * @ptab; Partition table of the partition
+ * @error: Return the error code on failure
+ **/
+int swsusp_check(struct driveinfo *drive_info, struct part_entry *ptab, int *error)
+{
+ struct swsusp_header *header_p;
+ int offset;
+ int found;
+
+ /* Read first page of the swap device */
+ offset = ptab->start_lba;
+ header_p = (struct swsusp_header *) read_sectors(drive_info, offset, PAGE_SIZE/SECTOR, error);
+
+ if (!header_p)
+ return -1; /* The error code has been stored in `error' */
+ else {
+ found = !memcmp(SWSUSP_SIG, header_p->sig, 10);
+ free(header_p);
+ return found;
+ }
+}
diff --git a/com32/gpllib/disk/util.c b/com32/gpllib/disk/util.c
new file mode 100644
index 00000000..c03ed37b
--- /dev/null
+++ b/com32/gpllib/disk/util.c
@@ -0,0 +1,30 @@
+#include <com32.h>
+#include <stdlib.h>
+#include <string.h>
+#include <disk/geom.h>
+
+#define MAX_NB_RETRIES 6
+
+/**
+ * int13_retry - int13h with error handling
+ * @inreg: int13h function parameters
+ * @outreg: output registers
+ *
+ * Call int 13h, but with retry on failure. Especially floppies need this.
+ **/
+int int13_retry(const com32sys_t *inreg, com32sys_t *outreg)
+{
+ int retry = MAX_NB_RETRIES; /* Number of retries */
+ com32sys_t tmpregs;
+
+ if ( !outreg ) outreg = &tmpregs;
+
+ while ( retry-- ) {
+ __intcall(0x13, inreg, outreg);
+ if ( !(outreg->eflags.l & EFLAGS_CF) )
+ return 0; /* CF=0 => OK */
+ }
+
+ /* If we get here: error */
+ return -1;
+}
diff --git a/com32/gpllib/disk/write.c b/com32/gpllib/disk/write.c
new file mode 100644
index 00000000..cd585481
--- /dev/null
+++ b/com32/gpllib/disk/write.c
@@ -0,0 +1,113 @@
+#include <com32.h>
+#include <stdlib.h>
+#include <string.h>
+#include <disk/read.h>
+#include <disk/write.h>
+#include <disk/common.h>
+#include <disk/util.h>
+
+/**
+ * write_sectors - write several sectors from disk
+ * @drive_info: driveinfo struct describing the disk
+ * @lba: Position to write
+ * @data: Buffer to write
+ * @size: Size of the buffer (number of sectors)
+ * @error: Return the error code on failure
+ **/
+int write_sectors(const struct driveinfo* drive_info, const unsigned int lba,
+ const void *data, const int size, int *error)
+{
+ com32sys_t inreg, outreg;
+ struct ebios_dapa *dapa = __com32.cs_bounce;
+ void *buf = (char *)__com32.cs_bounce + size;
+
+ memcpy(buf, data, size);
+ memset(&inreg, 0, sizeof inreg);
+
+ if ( drive_info->ebios ) {
+ dapa->len = sizeof(*dapa);
+ dapa->count = size;
+ dapa->off = OFFS(buf);
+ dapa->seg = SEG(buf);
+ dapa->lba = lba;
+
+ inreg.esi.w[0] = OFFS(dapa);
+ inreg.ds = SEG(dapa);
+ inreg.edx.b[0] = drive_info->disk;
+ inreg.eax.w[0] = 0x4300; /* Extended write */
+ } else {
+ unsigned int c, h, s;
+
+ if ( !drive_info->cbios ) {
+ /* We failed to get the geometry */
+
+ if ( lba )
+ return -1; /* Can only write MBR */
+
+ s = 1; h = 0; c = 0;
+ } else
+ lba_to_chs(drive_info, lba, &s, &h, &c);
+
+ if ( s > 63 || h > 256 || c > 1023 )
+ return -1;
+
+ inreg.eax.w[0] = 0x0301; /* Write one sector */
+ inreg.ecx.b[1] = c & 0xff;
+ inreg.ecx.b[0] = s + (c >> 6);
+ inreg.edx.b[1] = h;
+ inreg.edx.b[0] = drive_info->disk;
+ inreg.ebx.w[0] = OFFS(buf);
+ inreg.es = SEG(buf);
+ }
+
+ /* Perform the write */
+ if (int13_retry(&inreg, &outreg)) {
+ if (error)
+ *error = outreg.eax.b[1];
+ return -1; /* Give up */
+ } else {
+ if (error)
+ *error = 0;
+ return 0;
+ }
+}
+
+/**
+ * write_verify_sectors - write several sectors from disk
+ * @drive_info: driveinfo struct describing the disk
+ * @lba: Position to write
+ * @data: Buffer to write
+ **/
+int write_verify_sector(struct driveinfo* drive_info,
+ const unsigned int lba,
+ const void *data, int *error)
+{
+ return write_verify_sectors(drive_info, lba, data, SECTOR, error);
+}
+
+/**
+ * write_verify_sectors - write several sectors from disk
+ * @drive_info: driveinfo struct describing the disk
+ * @lba: Position to write
+ * @data: Buffer to write
+ * @size: Size of the buffer (number of sectors)
+ **/
+int write_verify_sectors(struct driveinfo* drive_info,
+ const unsigned int lba,
+ const void *data, const int size, int* error)
+{
+ char *rb;
+ int rv;
+
+ rv = write_sectors(drive_info, lba, data, size, error);
+ if (rv)
+ return rv; /* Write failure */
+
+ rb = read_sectors(drive_info, lba, size, error);
+ if (!rb)
+ return -1; /* Readback failure */
+
+ rv = memcmp(data, rb, SECTOR);
+ free(rb);
+ return rv ? -1 : 0;
+}
diff --git a/com32/hdt/hdt-ata.c b/com32/hdt/hdt-ata.c
index e0d6015c..9ba17ba8 100644
--- a/com32/hdt/hdt-ata.c
+++ b/com32/hdt/hdt-ata.c
@@ -30,252 +30,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <console.h>
-#include <getkey.h>
+#include <disk/geom.h>
+#include <disk/util.h>
#include "com32io.h"
#include "hdt-common.h"
#include "hdt-ata.h"
-
-#ifdef ATA
-/**
- * ata_id_string - Convert IDENTIFY DEVICE page into string
- * @id: IDENTIFY DEVICE results we will examine
- * @s: string into which data is output
- * @ofs: offset into identify device page
- * @len: length of string to return. must be an even number.
- *
- * The strings in the IDENTIFY DEVICE page are broken up into
- * 16-bit chunks. Run through the string, and output each
- * 8-bit chunk linearly, regardless of platform.
- *
- * LOCKING:
- * caller.
- */
-void ata_id_string(const uint16_t * id, unsigned char *s,
- unsigned int ofs, unsigned int len)
-{
- unsigned int c;
-
- while (len > 0) {
- c = id[ofs] >> 8;
- *s = c;
- s++;
-
- c = id[ofs] & 0xff;
- *s = c;
- s++;
-
- ofs++;
- len -= 2;
- }
-}
-
-/**
- * ata_id_c_string - Convert IDENTIFY DEVICE page into C string
- * @id: IDENTIFY DEVICE results we will examine
- * @s: string into which data is output
- * @ofs: offset into identify device page
- * @len: length of string to return. must be an odd number.
- *
- * This function is identical to ata_id_string except that it
- * trims trailing spaces and terminates the resulting string with
- * null. @len must be actual maximum length (even number) + 1.
- *
- * LOCKING:
- * caller.
- */
-void ata_id_c_string(const uint16_t * id, unsigned char *s,
- unsigned int ofs, unsigned int len)
-{
- unsigned char *p;
-
- //WARN_ON(!(len & 1));
-
- ata_id_string(id, s, ofs, len - 1);
-
- p = s + strnlen(s, len - 1);
- while (p > s && p[-1] == ' ')
- p--;
- *p = '\0';
-}
-#endif
-
-/**
- * Call int 13h, but with retry on failure. Especially floppies need this.
- */
-int int13_retry(const com32sys_t * inreg, com32sys_t * outreg)
-{
- int retry = 6; /* Number of retries */
- com32sys_t tmpregs;
-
- if (!outreg)
- outreg = &tmpregs;
-
- while (retry--) {
- __intcall(0x13, inreg, outreg);
- if (!(outreg->eflags.l & EFLAGS_CF))
- return 0; /* CF=0, OK */
- }
-
- return -1; /* Error */
-}
-
-/* Display CPU registers for debugging purposes */
-void printregs(const com32sys_t * r)
-{
- printf("eflags = %08x ds = %04x es = %04x fs = %04x gs = %04x\n"
- "eax = %08x ebx = %08x ecx = %08x edx = %08x\n"
- "ebp = %08x esi = %08x edi = %08x esp = %08x\n",
- r->eflags.l, r->ds, r->es, r->fs, r->gs,
- r->eax.l, r->ebx.l, r->ecx.l, r->edx.l,
- r->ebp.l, r->esi.l, r->edi.l, r->_unused_esp.l);
-}
-
-/* Try to get information for a given disk */
-int get_disk_params(int disk, struct diskinfo *disk_info)
-{
- static com32sys_t getparm, parm, getebios, ebios, inreg, outreg;
- struct device_parameter dp;
-#ifdef ATA
- struct ata_identify_device aid;
-#endif
-
- memset(&(disk_info[disk]), 0, sizeof(struct diskinfo));
-
- disk_info[disk].disk = disk;
- disk_info[disk].ebios = disk_info[disk].cbios = 0;
-
- /* Sending int 13h func 41h to query EBIOS information */
- memset(&getebios, 0, sizeof(com32sys_t));
- memset(&ebios, 0, sizeof(com32sys_t));
-
- /* Get EBIOS support */
- getebios.eax.w[0] = 0x4100;
- getebios.ebx.w[0] = 0x55aa;
- getebios.edx.b[0] = disk;
- getebios.eflags.b[0] = 0x3; /* CF set */
-
- __intcall(0x13, &getebios, &ebios);
-
- /* Detecting EDD support */
- if (!(ebios.eflags.l & EFLAGS_CF) &&
- ebios.ebx.w[0] == 0xaa55 && (ebios.ecx.b[0] & 1)) {
- disk_info[disk].ebios = 1;
- switch (ebios.eax.b[1]) {
- case 32:
- strlcpy(disk_info[disk].edd_version, "1.0", 3);
- break;
- case 33:
- strlcpy(disk_info[disk].edd_version, "1.1", 3);
- break;
- case 48:
- strlcpy(disk_info[disk].edd_version, "3.0", 3);
- break;
- default:
- strlcpy(disk_info[disk].edd_version, "0", 1);
- break;
- }
- }
- /* Get disk parameters -- really only useful for
- * hard disks, but if we have a partitioned floppy
- * it's actually our best chance...
- */
- memset(&getparm, 0, sizeof(com32sys_t));
- memset(&parm, 0, sizeof(com32sys_t));
- getparm.eax.b[1] = 0x08;
- getparm.edx.b[0] = disk;
-
- __intcall(0x13, &getparm, &parm);
-
- if (parm.eflags.l & EFLAGS_CF)
- return disk_info[disk].ebios ? 0 : -1;
-
- disk_info[disk].heads = parm.edx.b[1] + 1;
- disk_info[disk].sectors_per_track = parm.ecx.b[0] & 0x3f;
- if (disk_info[disk].sectors_per_track == 0) {
- disk_info[disk].sectors_per_track = 1;
- } else {
- disk_info[disk].cbios = 1; /* Valid geometry */
- }
-
- /* If geometry isn't valid, no need to try to get more info about the drive*/
- /* Looks like in can confuse some optical drives */
- if (disk_info[disk].cbios != 1) return 0;
-
-/* FIXME: memset to 0 make it fails
- * memset(__com32.cs_bounce, 0, sizeof(struct device_pairameter)); */
- memset(&dp, 0, sizeof(struct device_parameter));
- memset(&inreg, 0, sizeof(com32sys_t));
-
- /* Requesting Extended Read Drive Parameters via int13h func 48h */
- inreg.esi.w[0] = OFFS(__com32.cs_bounce);
- inreg.ds = SEG(__com32.cs_bounce);
- inreg.eax.w[0] = 0x4800;
- inreg.edx.b[0] = disk;
-
- __intcall(0x13, &inreg, &outreg);
-
- /* Saving bounce buffer before anything corrupt it */
- memcpy(&dp, __com32.cs_bounce, sizeof(struct device_parameter));
-
- if (outreg.eflags.l & EFLAGS_CF) {
- more_printf("Disk 0x%X doesn't supports EDD 3.0\n", disk);
- return -1;
- }
-
- /* Copying result to the disk_info structure
- * host_bus_type, interface_type, sectors & cylinders */
- snprintf(disk_info[disk].host_bus_type,
- sizeof disk_info[disk].host_bus_type, "%c%c%c%c",
- dp.host_bus_type[0], dp.host_bus_type[1], dp.host_bus_type[2],
- dp.host_bus_type[3]);
- snprintf(disk_info[disk].interface_type,
- sizeof disk_info[disk].interface_type, "%c%c%c%c%c%c%c%c",
- dp.interface_type[0], dp.interface_type[1],
- dp.interface_type[2], dp.interface_type[3],
- dp.interface_type[4], dp.interface_type[5],
- dp.interface_type[6], dp.interface_type[7]);
- disk_info[disk].sectors = dp.sectors;
- disk_info[disk].cylinders = dp.cylinders;
-
- /*FIXME: we have to find a way to grab the model & fw
- * We do put dummy data until we found a solution */
- snprintf(disk_info[disk].aid.model, sizeof disk_info[disk].aid.model,
- "0x%X", disk);
- snprintf(disk_info[disk].aid.fw_rev, sizeof disk_info[disk].aid.fw_rev,
- "%s", "N/A");
- snprintf(disk_info[disk].aid.serial_no,
- sizeof disk_info[disk].aid.serial_no, "%s", "N/A");
-
- /* Useless stuff before I figure how to send ata packets */
-#ifdef ATA
- memset(__com32.cs_bounce, 0, sizeof(struct device_parameter));
- memset(&aid, 0, sizeof(struct ata_identify_device));
- memset(&inreg, 0, sizeof inreg);
- inreg.ebx.w[0] = OFFS(__com32.cs_bounce + 1024);
- inreg.es = SEG(__com32.cs_bounce + 1024);
- inreg.eax.w[0] = 0x2500;
- inreg.edx.b[0] = disk;
-
- __intcall(0x13, &inreg, &outreg);
-
- memcpy(&aid, __com32.cs_bounce, sizeof(struct ata_identify_device));
-
- if (outreg.eflags.l & EFLAGS_CF) {
- more_printf("Disk 0x%X: Failed to Identify Device\n", disk);
- //FIXME
- return 0;
- }
-// ata_id_c_string(aid, disk_info[disk].fwrev, ATA_ID_FW_REV, sizeof(disk_info[disk].fwrev));
-// ata_id_c_string(aid, disk_info[disk].model, ATA_ID_PROD, sizeof(disk_info[disk].model));
-
- char buff[sizeof(struct ata_identify_device)];
- memcpy(buff, &aid, sizeof(struct ata_identify_device));
- for (int j = 0; j < sizeof(struct ata_identify_device); j++)
- more_printf("model=|%c|\n", buff[j]);
- more_printf("Disk 0x%X : %s %s %s\n", disk, aid.model, aid.fw_rev,
- aid.serial_no);
-#endif
-
- return 0;
-}
diff --git a/com32/hdt/hdt-ata.h b/com32/hdt/hdt-ata.h
index fee4d598..a9550837 100644
--- a/com32/hdt/hdt-ata.h
+++ b/com32/hdt/hdt-ata.h
@@ -30,6 +30,7 @@
#define DEFINE_HDT_ATA_H
#include <com32io.h>
+#include <disk/geom.h>
#include "hdt.h"
struct ata_identify_device {
@@ -50,58 +51,13 @@ struct ata_identify_device {
unsigned short words088_255[168];
} ATTR_PACKED;
-struct diskinfo {
- int disk;
- int ebios; /* EBIOS supported on this disk */
- int cbios; /* CHS geometry is valid */
- int heads;
- int sectors_per_track;
- int sectors;
- int cylinders;
- char edd_version[4];
+struct ata_driveinfo {
struct ata_identify_device aid; /* IDENTIFY xxx DEVICE data */
char host_bus_type[5];
char interface_type[9];
char interface_port;
} ATTR_PACKED;
-/*
- * Get a disk block and return a malloc'd buffer.
- * Uses the disk number and information from disk_info.
- */
-struct ebios_dapa {
- uint16_t len;
- uint16_t count;
- uint16_t off;
- uint16_t seg;
- uint64_t lba;
-};
-
-// BYTE=8
-// WORD=16
-// DWORD=32
-// QWORD=64
-struct device_parameter {
- uint16_t len;
- uint16_t info;
- uint32_t cylinders;
- uint32_t heads;
- uint32_t sectors_per_track;
- uint64_t sectors;
- uint16_t bytes_per_sector;
- uint32_t dpte_pointer;
- uint16_t device_path_information;
- uint8_t device_path_lenght;
- uint8_t device_path_reserved;
- uint16_t device_path_reserved_2;
- uint8_t host_bus_type[4];
- uint8_t interface_type[8];
- uint64_t interace_path;
- uint64_t device_path[2];
- uint8_t reserved;
- uint8_t cheksum;
-} ATTR_PACKED;
-
/* Useless stuff until I manage how to send ata packets */
#ifdef ATA
enum {
@@ -114,9 +70,7 @@ void ata_id_c_string(const uint16_t * id, unsigned char *s, unsigned int ofs,
unsigned int len);
void ata_id_string(const uint16_t * id, unsigned char *s, unsigned int ofs,
unsigned int len);
-int int13_retry(const com32sys_t * inreg, com32sys_t * outreg);
void printregs(const com32sys_t * r);
#endif
-int get_disk_params(int disk, struct diskinfo *disk_info);
#endif
diff --git a/com32/hdt/hdt-cli-disk.c b/com32/hdt/hdt-cli-disk.c
new file mode 100644
index 00000000..506efba7
--- /dev/null
+++ b/com32/hdt/hdt-cli-disk.c
@@ -0,0 +1,163 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 Pierre-Alexandre Meyer - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <disk/geom.h>
+#include <disk/read.h>
+#include <disk/error.h>
+#include <disk/swsusp.h>
+#include <disk/msdos.h>
+
+#include "hdt-cli.h"
+#include "hdt-common.h"
+#include "hdt-util.h"
+
+/**
+ * show_partition_information - print information about a partition
+ * @ptab: part_entry describing the partition
+ * @i: Partition number (UI purposes only)
+ * @ptab_root: part_entry describing the root partition (extended only)
+ * @drive_info: driveinfo struct describing the drive on which the partition
+ * is
+ *
+ * Note on offsets (from hpa, see chain.c32):
+ *
+ * To make things extra confusing: data partition offsets are relative to where
+ * the data partition record is stored, whereas extended partition offsets
+ * are relative to the beginning of the extended partition all the way back
+ * at the MBR... but still not absolute!
+ **/
+static void show_partition_information(struct driveinfo *drive_info,
+ struct part_entry *ptab,
+ struct part_entry *ptab_root,
+ int offset_root, int data_partitions_seen,
+ int ebr_seen)
+{
+ char size[8];
+ char *parttype;
+ int error = 0;
+ char *error_buffer;
+ unsigned int start, end;
+
+ int i = 1 + ebr_seen * 4 + data_partitions_seen;
+
+ start = ptab->start_lba + ptab_root->start_lba + offset_root;
+ end = (ptab->start_lba + ptab_root->start_lba) + ptab->length + offset_root;
+
+ if (ptab->length > 0)
+ sectors_to_size(ptab->length, size);
+ else
+ memset(size, 0, sizeof size);
+
+ get_label(ptab->ostype, &parttype);
+ more_printf(" %2d %s %11d %11d %s %02X %s",
+ i, (ptab->active_flag == 0x80) ? "x" : " ",
+ start,
+ end,
+ size,
+ ptab->ostype, parttype);
+
+ /* Extra info */
+ if (ptab->ostype == 0x82 && swsusp_check(drive_info, ptab, &error)) {
+ more_printf("%s", " (Swsusp sig. detected)");
+ } else if (error) {
+ get_error(error, &error_buffer);
+ more_printf("%s\n", error_buffer);
+ free(error_buffer);
+ }
+
+ more_printf("\n");
+
+ free(parttype);
+}
+
+void main_show_disk(int argc __unused, char **argv __unused,
+ struct s_hardware *hardware)
+{
+ int i = -1;
+ int error;
+ char *error_buffer;
+
+ detect_disks(hardware);
+
+ for (int drive = 0x80; drive < 0xff; drive++) {
+ i++;
+ if (!hardware->disk_info[i].cbios)
+ continue; /* Invalid geometry */
+ struct driveinfo *d = &hardware->disk_info[i];
+ char disk_size[8];
+
+ if ((int) d->edd_params.sectors > 0)
+ sectors_to_size((int) d->edd_params.sectors, disk_size);
+ else
+ memset(disk_size, 0, sizeof disk_size);
+
+ more_printf("DISK 0x%X:\n", d->disk);
+ more_printf(" C/H/S: %d cylinders, %d heads, %d sectors/track\n",
+ d->legacy_max_cylinder + 1, d->legacy_max_head + 1,
+ d->legacy_sectors_per_track);
+ more_printf(" EDD: Version: %X\n", d->edd_version);
+ more_printf(" Size: %s, %d bytes/sector, %d sectors/track\n",
+ disk_size,
+ (int) d->edd_params.bytes_per_sector,
+ (int) d->edd_params.sectors_per_track);
+ more_printf(" Host bus: %s, Interface type: %s\n\n",
+ remove_spaces(d->edd_params.host_bus_type),
+ remove_spaces(d->edd_params.interface_type));
+
+ more_printf(" # B Start End Size Id Type\n");
+ error = 0;
+ if (parse_partition_table(d, &show_partition_information, &error)) {
+ if (error) {
+ more_printf("I/O error: ");
+ get_error(error, &error_buffer);
+ more_printf("%s\n", error_buffer);
+ free(error_buffer);
+ } else
+ more_printf("An unknown error occured.\n");
+ continue;
+ }
+ }
+}
+
+struct cli_module_descr disk_show_modules = {
+ .modules = NULL,
+ .default_callback = main_show_disk,
+};
+
+struct cli_mode_descr disk_mode = {
+ .mode = DISK_MODE,
+ .name = CLI_DISK,
+ .default_modules = NULL,
+ .show_modules = &disk_show_modules,
+ .set_modules = NULL,
+};
diff --git a/com32/hdt/hdt-cli-hdt.c b/com32/hdt/hdt-cli-hdt.c
index b0ee0342..76785a79 100644
--- a/com32/hdt/hdt-cli-hdt.c
+++ b/com32/hdt/hdt-cli-hdt.c
@@ -285,6 +285,10 @@ struct cli_callback_descr list_hdt_show_modules[] = {
.exec = main_show_cpu,
},
{
+ .name = CLI_DISK,
+ .exec = main_show_disk,
+ },
+ {
.name = CLI_PXE,
.exec = main_show_pxe,
},
diff --git a/com32/hdt/hdt-cli.c b/com32/hdt/hdt-cli.c
index 871fd76c..324c74ae 100644
--- a/com32/hdt/hdt-cli.c
+++ b/com32/hdt/hdt-cli.c
@@ -43,6 +43,7 @@ struct cli_mode_descr *list_modes[] = {
&cpu_mode,
&pci_mode,
&vesa_mode,
+ &disk_mode,
&vpd_mode,
NULL,
};
@@ -179,6 +180,12 @@ void set_mode(cli_mode_t mode, struct s_hardware* hardware)
snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ",
CLI_DMI);
break;
+ case DISK_MODE:
+ detect_disks(hardware);
+ hdt_cli.mode = mode;
+ snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ",
+ CLI_DISK);
+ break;
case VPD_MODE:
detect_vpd(hardware);
if (!hardware->is_vpd_valid) {
@@ -189,7 +196,6 @@ void set_mode(cli_mode_t mode, struct s_hardware* hardware)
snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ",
CLI_VPD);
break;
-
default:
/* Invalid mode */
printf("Unknown mode, please choose among:\n");
diff --git a/com32/hdt/hdt-cli.h b/com32/hdt/hdt-cli.h
index c51127ef..9a8e15d7 100644
--- a/com32/hdt/hdt-cli.h
+++ b/com32/hdt/hdt-cli.h
@@ -64,6 +64,7 @@
#define CLI_COMMANDS "commands"
#define CLI_DMI "dmi"
#define CLI_CPU "cpu"
+#define CLI_DISK "disk"
#define CLI_SHOW_LIST "list"
#define CLI_IRQ "irq"
#define CLI_MODES "modes"
@@ -80,6 +81,7 @@ typedef enum {
KERNEL_MODE,
SYSLINUX_MODE,
VESA_MODE,
+ DISK_MODE,
VPD_MODE,
} cli_mode_t;
@@ -138,6 +140,7 @@ struct cli_mode_descr kernel_mode;
struct cli_mode_descr cpu_mode;
struct cli_mode_descr pci_mode;
struct cli_mode_descr vesa_mode;
+struct cli_mode_descr disk_mode;
struct cli_mode_descr vpd_mode;
/* cli helpers */
@@ -173,6 +176,9 @@ void cli_detect_pci(struct s_hardware *hardware);
// CPU STUFF
void main_show_cpu(int argc, char **argv, struct s_hardware *hardware);
+// DISK STUFF
+void main_show_disk(int argc, char **argv, struct s_hardware *hardware);
+
// PXE STUFF
void main_show_pxe(int argc, char **argv, struct s_hardware *hardware);
diff --git a/com32/hdt/hdt-common.c b/com32/hdt/hdt-common.c
index 8cda7f06..0331bd19 100644
--- a/com32/hdt/hdt-common.c
+++ b/com32/hdt/hdt-common.c
@@ -34,6 +34,7 @@
#include "../lib/sys/vesa/vesa.h"
#include "hdt-common.h"
#include "lib-ansi.h"
+#include <disk/util.h>
/* ISOlinux requires a 8.3 format */
void convert_isolinux_filename(char *filename, struct s_hardware *hardware) {
@@ -241,18 +242,31 @@ int detect_vesa(struct s_hardware *hardware) {
/* Try to detect disks from port 0x80 to 0xff */
void detect_disks(struct s_hardware *hardware)
{
- hardware->disk_detection = true;
- for (int drive = 0x80; drive < 0xff; drive++) {
- if (get_disk_params(drive, hardware->disk_info) != 0)
- continue;
- struct diskinfo *d = &hardware->disk_info[drive];
- hardware->disks_count++;
- printf
- (" DISK 0x%X: %s : %s %s: sectors=%d, s/t=%d head=%d : EDD=%s\n",
- drive, d->aid.model, d->host_bus_type, d->interface_type,
- d->sectors, d->sectors_per_track, d->heads,
- d->edd_version);
- }
+ int i = -1;
+ int err;
+ char *error_msg;
+
+ if (hardware->disk_detection)
+ return;
+
+ hardware->disk_detection = true;
+ for (int drive = 0x80; drive < 0xff; drive++) {
+ i++;
+ hardware->disk_info[i].disk = drive;
+ err = get_drive_parameters(&hardware->disk_info[i]);
+
+ /* Do not print output when drive does not exists */
+ if (err == -1)
+ continue;
+
+ if (err) {
+ get_error(err, &error_msg);
+ more_printf("Error 0x%Xh while reading disk 0x%X:\n\t%s\n",
+ err, drive, error_msg);
+ free(error_msg);
+ }
+ hardware->disks_count++;
+ }
}
int detect_pxe(struct s_hardware *hardware)
diff --git a/com32/hdt/hdt-common.h b/com32/hdt/hdt-common.h
index 7e3dc7d8..9fd8a565 100644
--- a/com32/hdt/hdt-common.h
+++ b/com32/hdt/hdt-common.h
@@ -32,6 +32,8 @@
#include <syslinux/pxe.h>
#include "sys/pci.h"
+#include <disk/geom.h>
+
#include "cpuid.h"
#include "dmi/dmi.h"
#include "hdt-ata.h"
@@ -55,6 +57,17 @@ extern int display_line_nb;
display_line_nb++; \
} while (0);
+/* Display CPU registers for debugging purposes */
+static inline void printregs(const com32sys_t * r)
+{
+ printf("eflags = %08x ds = %04x es = %04x fs = %04x gs = %04x\n"
+ "eax = %08x ebx = %08x ecx = %08x edx = %08x\n"
+ "ebp = %08x esi = %08x edi = %08x esp = %08x\n",
+ r->eflags.l, r->ds, r->es, r->fs, r->gs,
+ r->eax.l, r->ebx.l, r->ecx.l, r->edx.l,
+ r->ebp.l, r->esi.l, r->edi.l, r->_unused_esp.l);
+}
+
struct s_pxe {
uint16_t vendor_id;
uint16_t product_id;
@@ -97,7 +110,7 @@ struct s_hardware {
s_cpu cpu; /* CPU information */
s_vpd vpd; /* VPD information */
struct pci_domain *pci_domain; /* PCI Devices */
- struct diskinfo disk_info[256]; /* Disk Information */
+ struct driveinfo disk_info[256]; /* Disk Information */
int disks_count; /* Number of detected disks */
struct s_pxe pxe;
struct s_vesa vesa;
diff --git a/com32/hdt/hdt-menu-disk.c b/com32/hdt/hdt-menu-disk.c
index 02f12f75..2283cafa 100644
--- a/com32/hdt/hdt-menu-disk.c
+++ b/com32/hdt/hdt-menu-disk.c
@@ -26,133 +26,190 @@
* -----------------------------------------------------------------------
*/
+#include <stdlib.h>
+#include <disk/geom.h>
+#include <disk/read.h>
+#include <disk/partition.h>
+#include <disk/error.h>
+
#include "hdt-menu.h"
+#include "hdt-util.h"
+
+static void compute_partition_info(int partnb,
+ struct part_entry *ptab,
+ char menu_title_ref[],
+ char menu_title[])
+{
+ char buffer[56];
+ char statbuffer[STATLEN];
+ int previous_size, size;
+ char previous_unit[3], unit[3]; // GB
+ char size_iec[8]; // GiB
+ sectors_to_size_dec(previous_unit, &previous_size, unit, &size, ptab->length);
+ sectors_to_size(ptab->length, size_iec);
+
+ add_named_menu(menu_title_ref, menu_title, -1);
+ set_menu_pos(5, 17);
+
+ snprintf(buffer, sizeof buffer, "Partition # : %d",
+ partnb);
+ snprintf(statbuffer, sizeof statbuffer, "Partition #: %d",
+ partnb);
+ add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
+
+ snprintf(buffer, sizeof buffer, "Bootable : %s",
+ (ptab->active_flag == 0x80) ? "Yes" : "No");
+ snprintf(statbuffer, sizeof statbuffer, "Bootable: %s",
+ (ptab->active_flag == 0x80) ? "Yes" : "No");
+ add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
+
+ snprintf(buffer, sizeof buffer, "Start : %d",
+ ptab->start_lba);
+ snprintf(statbuffer, sizeof statbuffer, "Start: %d",
+ ptab->start_lba);
+ add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
+
+ snprintf(buffer, sizeof buffer, "End : %d",
+ ptab->start_lba + ptab->length);
+ snprintf(statbuffer, sizeof statbuffer, "End: %d",
+ ptab->start_lba + ptab->length);
+ add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
+
+ snprintf(buffer, sizeof buffer, "Length : %s/%d %s (%d)",
+ size_iec, size, unit, ptab->length);
+ snprintf(statbuffer, sizeof statbuffer, "Length: %s/%d %s (%d)",
+ size_iec, size, unit, ptab->length);
+ add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
+
+ snprintf(buffer, sizeof buffer, "Id : %X",
+ ptab->ostype);
+ snprintf(statbuffer, sizeof statbuffer, "Id: %X",
+ ptab->ostype);
+ add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
+
+ char *parttype;
+ get_label(ptab->ostype, &parttype);
+ snprintf(buffer, sizeof buffer, "Type : %s",
+ parttype);
+ snprintf(statbuffer, sizeof statbuffer, "Type: %s",
+ parttype);
+ add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
+ free(parttype);
+}
/* Compute the disk submenu */
-int compute_disk_module(struct s_my_menu *menu, int nb_sub_disk_menu,
- struct diskinfo *d, int disk_number)
+static int compute_disk_module(struct s_my_menu *menu, int nb_sub_disk_menu,
+ struct driveinfo *d, int disk_number)
{
char buffer[MENULEN + 1];
char statbuffer[STATLEN + 1];
+ char *mbr = NULL;
- /* No need to add no existing devices */
- if (strlen(d[disk_number].aid.model) <= 0)
- return -1;
-
- snprintf(buffer, sizeof buffer, " Disk <%d> ", nb_sub_disk_menu);
+ snprintf(buffer, sizeof buffer, " Disk <0x%X> ", d[disk_number].disk);
menu[nb_sub_disk_menu].menu = add_menu(buffer, -1);
menu[nb_sub_disk_menu].items_count = 0;
- snprintf(buffer, sizeof buffer, "Model : %s",
- d[disk_number].aid.model);
- snprintf(statbuffer, sizeof statbuffer, "Model: %s",
- d[disk_number].aid.model);
- add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
- menu[nb_sub_disk_menu].items_count++;
-
- /* Compute device size */
- char previous_unit[3], unit[3]; //GB
- int previous_size, size = d[disk_number].sectors / 2; // Converting to bytes
- strlcpy(unit, "KB", 2);
- strlcpy(previous_unit, unit, 2);
- previous_size = size;
- if (size > 1000) {
- size = size / 1000;
- strlcpy(unit, "MB", 2);
- if (size > 1000) {
- previous_size = size;
- size = size / 1000;
- strlcpy(previous_unit, unit, 2);
- strlcpy(unit, "GB", 2);
- if (size > 1000) {
- previous_size = size;
- size = size / 1000;
- strlcpy(previous_unit, unit, 2);
- strlcpy(unit, "TB", 2);
- }
- }
- }
+ int previous_size, size;
+ char previous_unit[3], unit[3]; // GB
+ char size_iec[8]; // GiB
+ sectors_to_size_dec(previous_unit, &previous_size, unit, &size, d[disk_number].edd_params.sectors);
+ sectors_to_size(d[disk_number].edd_params.sectors, size_iec);
- snprintf(buffer, sizeof buffer, "Size : %d %s (%d %s)", size,
+ snprintf(buffer, sizeof buffer, "Size : %s/%d %s (%d %s)", size_iec,
+ size, unit, previous_size, previous_unit);
+ snprintf(statbuffer, sizeof statbuffer, "Size: %s/%d %s (%d %s)", size_iec, size,
unit, previous_size, previous_unit);
- snprintf(statbuffer, sizeof statbuffer, "Size: %d %s (%d %s)", size,
- unit, previous_size, previous_unit);
- add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
- menu[nb_sub_disk_menu].items_count++;
-
- snprintf(buffer, sizeof buffer, "Firmware Rev.: %s",
- d[disk_number].aid.fw_rev);
- snprintf(statbuffer, sizeof statbuffer, "Firmware Revision: %s",
- d[disk_number].aid.fw_rev);
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu[nb_sub_disk_menu].items_count++;
- snprintf(buffer, sizeof buffer, "Serial Number: %s",
- d[disk_number].aid.serial_no);
- snprintf(statbuffer, sizeof statbuffer, "Serial Number: %s",
- d[disk_number].aid.serial_no);
- add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
- menu[nb_sub_disk_menu].items_count++;
-
- snprintf(buffer, sizeof buffer, "Interface : %s",
- d[disk_number].interface_type);
+ snprintf(buffer, sizeof buffer, "Interface : %s",
+ d[disk_number].edd_params.interface_type);
snprintf(statbuffer, sizeof statbuffer, "Interface: %s",
- d[disk_number].interface_type);
+ d[disk_number].edd_params.interface_type);
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu[nb_sub_disk_menu].items_count++;
- snprintf(buffer, sizeof buffer, "Host Bus : %s",
- d[disk_number].host_bus_type);
+ snprintf(buffer, sizeof buffer, "Host Bus : %s",
+ d[disk_number].edd_params.host_bus_type);
snprintf(statbuffer, sizeof statbuffer, "Host Bus Type: %s",
- d[disk_number].host_bus_type);
+ d[disk_number].edd_params.host_bus_type);
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu[nb_sub_disk_menu].items_count++;
- snprintf(buffer, sizeof buffer, "Sectors : %d",
- d[disk_number].sectors);
+ snprintf(buffer, sizeof buffer, "Sectors : %d",
+ (int) d[disk_number].edd_params.sectors);
snprintf(statbuffer, sizeof statbuffer, "Sectors: %d",
- d[disk_number].sectors);
+ (int) d[disk_number].edd_params.sectors);
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu[nb_sub_disk_menu].items_count++;
- snprintf(buffer, sizeof buffer, "Heads : %d",
- d[disk_number].heads);
+ snprintf(buffer, sizeof buffer, "Heads : %d",
+ d[disk_number].legacy_max_head + 1);
snprintf(statbuffer, sizeof statbuffer, "Heads: %d",
- d[disk_number].heads);
+ d[disk_number].legacy_max_head + 1);
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu[nb_sub_disk_menu].items_count++;
- snprintf(buffer, sizeof buffer, "Cylinders : %d",
- d[disk_number].cylinders);
+ snprintf(buffer, sizeof buffer, "Cylinders : %d",
+ d[disk_number].legacy_max_cylinder + 1);
snprintf(statbuffer, sizeof statbuffer, "Cylinders: %d",
- d[disk_number].cylinders);
+ d[disk_number].legacy_max_cylinder + 1);
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu[nb_sub_disk_menu].items_count++;
- snprintf(buffer, sizeof buffer, "Sectors/Track: %d",
- d[disk_number].sectors_per_track);
+ snprintf(buffer, sizeof buffer, "Sectors/Track : %d",
+ d[disk_number].legacy_sectors_per_track);
snprintf(statbuffer, sizeof statbuffer, "Sectors per Track: %d",
- d[disk_number].sectors_per_track);
+ d[disk_number].legacy_sectors_per_track);
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu[nb_sub_disk_menu].items_count++;
- snprintf(buffer, sizeof buffer, "Port : 0x%X", disk_number);
- snprintf(statbuffer, sizeof statbuffer, "Port: 0x%X", disk_number);
+ snprintf(buffer, sizeof buffer, "Drive number : 0x%X", d[disk_number].disk);
+ snprintf(statbuffer, sizeof statbuffer, "Drive number: 0x%X", d[disk_number].disk);
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu[nb_sub_disk_menu].items_count++;
- snprintf(buffer, sizeof buffer, "EDD Version : %s",
+ snprintf(buffer, sizeof buffer, "EDD Version : %X",
d[disk_number].edd_version);
- snprintf(statbuffer, sizeof statbuffer, "EDD Version: %s",
+ snprintf(statbuffer, sizeof statbuffer, "EDD Version: %X",
d[disk_number].edd_version);
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu[nb_sub_disk_menu].items_count++;
+ add_sep();
+
+ /* Compute disk partitions menus */
+ mbr = read_mbr(d[disk_number].disk, NULL);
+ if (mbr) {
+ struct part_entry *ptab = (struct part_entry *)(mbr + PARTITION_TABLES_OFFSET);
+ char menu_title[MENULEN + 1];
+ char menu_title_ref[MENULEN + 1];
+ /* The calls to add_item need to be done first to draw the main submenu first */
+ int submenu_done = 0;
+submenu_disk:
+ for (int i = 0; i < 4; i++) {
+ if (ptab[i].ostype) {
+ snprintf(menu_title_ref, sizeof menu_title_ref, "disk_%x_part_%d", d[disk_number].disk, i);
+ snprintf(menu_title, sizeof menu_title, "Disk <%X>, Partition %d", d[disk_number].disk, i);
+ if (!submenu_done)
+ add_item(menu_title, "Partition information (start, end, length, type, ...)",
+ OPT_SUBMENU, menu_title_ref, 0);
+ else
+ compute_partition_info(i, &ptab[i], menu_title_ref, menu_title);
+ }
+ /* Now, draw the sub sub menus */
+ if (i == 3 && !submenu_done) {
+ submenu_done = 1;
+ goto submenu_disk;
+ }
+ }
+ }
+
return 0;
}
/* Compute the Disks menu */
-void compute_disks(struct s_hdt_menu *menu, struct diskinfo *disk_info, struct s_hardware *hardware)
+void compute_disks(struct s_hdt_menu *menu, struct driveinfo *disk_info, struct s_hardware *hardware)
{
char buffer[MENULEN + 1];
int nb_sub_disk_menu = 0;
@@ -161,17 +218,19 @@ void compute_disks(struct s_hdt_menu *menu, struct diskinfo *disk_info, struct s
menu->disk_menu.items_count = 0;
if (hardware->disks_count == 0) return;
- for (int i = 0; i < 0xff; i++) {
- if (compute_disk_module
+ for (int i = 0; i < hardware->disks_count; i++) {
+ if (!hardware->disk_info[i].cbios)
+ continue; /* Invalid geometry */
+ compute_disk_module
((struct s_my_menu*) &(menu->disk_sub_menu), nb_sub_disk_menu, disk_info,
- i) == 0)
- nb_sub_disk_menu++;
+ i);
+ nb_sub_disk_menu++;
}
menu->disk_menu.menu = add_menu(" Disks ", -1);
for (int i = 0; i < nb_sub_disk_menu; i++) {
- snprintf(buffer, sizeof buffer, " Disk <%d> ", i);
+ snprintf(buffer, sizeof buffer, " Disk <%d> ", i+1);
add_item(buffer, "Disk", OPT_SUBMENU, NULL,
menu->disk_sub_menu[i].menu);
menu->disk_menu.items_count++;
diff --git a/com32/hdt/hdt-menu.c b/com32/hdt/hdt-menu.c
index f2bafa4c..a699f72a 100644
--- a/com32/hdt/hdt-menu.c
+++ b/com32/hdt/hdt-menu.c
@@ -293,7 +293,7 @@ void detect_hardware(struct s_hardware *hardware)
printf("CPU: Detecting\n");
cpu_detect(hardware);
- printf("DISKS: Detecting\n");
+ printf("DISKS: Detecting");
detect_disks(hardware);
printf("DMI: Detecting Table\n");
diff --git a/com32/hdt/hdt-menu.h b/com32/hdt/hdt-menu.h
index 70fdb385..1cd2c129 100644
--- a/com32/hdt/hdt-menu.h
+++ b/com32/hdt/hdt-menu.h
@@ -91,9 +91,7 @@ int compute_PCI(struct s_hdt_menu *hdt_menu, struct s_hardware *hardware);
void compute_kernel(struct s_my_menu *menu, struct s_hardware *hardware);
// Disk Stuff
-int compute_disk_module(struct s_my_menu *menu, int nb_sub_disk_menu,
- struct diskinfo *d, int disk_number);
-void compute_disks(struct s_hdt_menu *menu, struct diskinfo *disk_info, struct s_hardware *hardware);
+void compute_disks(struct s_hdt_menu *menu, struct driveinfo *disk_info, struct s_hardware *hardware);
// DMI Stuff
void compute_motherboard(struct s_my_menu *menu, s_dmi * dmi);
diff --git a/com32/hdt/hdt-util.c b/com32/hdt/hdt-util.c
new file mode 100644
index 00000000..5bc566af
--- /dev/null
+++ b/com32/hdt/hdt-util.c
@@ -0,0 +1,71 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 Pierre-Alexandre Meyer - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+void sectors_to_size(int sectors, char *buffer)
+{
+ int b = (sectors / 2);
+ int mib = b >> 10;
+ int gib = mib >> 10;
+ int tib = gib >> 10;
+
+ if (tib > 0)
+ sprintf(buffer, "%3d TiB", tib);
+ else if (gib > 0)
+ sprintf(buffer, "%3d GiB", gib);
+ else if (mib > 0)
+ sprintf(buffer, "%3d MiB", mib);
+ else
+ sprintf(buffer, "%d b", b);
+}
+
+void sectors_to_size_dec(char *previous_unit, int *previous_size, char *unit, int *size, int sectors)
+{
+ *size = sectors / 2; // Converting to bytes
+ strlcpy(unit, "KB", 2);
+ strlcpy(previous_unit, unit, 2);
+ *previous_size = *size;
+ if (*size > 1000) {
+ *size = *size / 1000;
+ strlcpy(unit, "MB", 2);
+ if (*size > 1000) {
+ *previous_size = *size;
+ *size = *size / 1000;
+ strlcpy(previous_unit, unit, 2);
+ strlcpy(unit, "GB", 2);
+ if (*size > 1000) {
+ *previous_size = *size;
+ *size = *size / 1000;
+ strlcpy(previous_unit, unit, 2);
+ strlcpy(unit, "TB", 2);
+ }
+ }
+ }
+}
diff --git a/com32/hdt/hdt-util.h b/com32/hdt/hdt-util.h
new file mode 100644
index 00000000..8c1d6de5
--- /dev/null
+++ b/com32/hdt/hdt-util.h
@@ -0,0 +1,33 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 Pierre-Alexandre Meyer - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#ifndef DEFINE_HDT_UTIL_H
+#define DEFINE_HDT_UTIL_H
+void sectors_to_size(int, char *);
+void sectors_to_size_dec(char *, int *, char *, int *, int);
+#endif
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..e94a36bf
--- /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;
+}