diff options
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 46f3669a..4f96b2da 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 516d2fc8..6f90e453 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 18158ae3..5cfe8eda 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; +} |