aboutsummaryrefslogtreecommitdiffstats
path: root/sample
diff options
context:
space:
mode:
authorErwan Velu <erwan.velu@free.fr>2009-02-11 23:22:51 +0100
committerH. Peter Anvin <hpa@zytor.com>2009-02-25 20:58:40 -0800
commit53abd39e9dfdecf607105afcbf70c83028f253db (patch)
tree357a268632d4742cef464eb2cc735ba2d2d170bd /sample
parent0e7c4726848368d36026ca418c6c8ec77107925c (diff)
downloadsyslinux-53abd39e9dfdecf607105afcbf70c83028f253db.tar.gz
syslinux-53abd39e9dfdecf607105afcbf70c83028f253db.tar.xz
syslinux-53abd39e9dfdecf607105afcbf70c83028f253db.zip
hdt: Initial harddrive detection
Diffstat (limited to 'sample')
-rw-r--r--sample/hdt.c208
1 files changed, 205 insertions, 3 deletions
diff --git a/sample/hdt.c b/sample/hdt.c
index 54177445..5de75cd5 100644
--- a/sample/hdt.c
+++ b/sample/hdt.c
@@ -34,6 +34,7 @@
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
#include <console.h>
#include "com32io.h"
#include "menu.h"
@@ -50,12 +51,135 @@
#define PWDATTR 0x74
#define EDITPROMPT 21
-//#define WITH_PCI 1
+#define WITH_PCI 1
#define WITH_MENU_DISPLAY 1
+
+#define SECTOR 512 /* bytes/sector */
+
unsigned char MAIN_MENU, CPU_MENU, MOBO_MENU, CHASSIS_MENU, BIOS_MENU, SYSTEM_MENU, PCI_MENU;
unsigned char MEMORY_MENU, MEMORY_SUBMENU[32], BATTERY_MENU;
bool is_dmi_valid=false;
+struct diskinfo {
+ int disk;
+ int ebios; /* EBIOS supported on this disk */
+ int cbios; /* CHS geometry is valid */
+ int head;
+ int sect;
+ char edd_version[4];
+};
+
+/*
+ * 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;
+};
+
+struct device_parameter {
+ uint16_t len;
+ uint16_t info;
+ uint32_t cylinders;
+ uint32_t head;
+ 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;
+ char host_bus_type[4];
+ char interface_type[8];
+ uint32_t interace_path;
+ uint32_t device_path[2];
+ uint8_t reserved;
+ uint8_t cheksum;
+};
+
+/*
+ * Call int 13h, but with retry on failure. Especially floppies need this.
+ */
+static 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 */
+}
+
+
+static void *read_sector(struct diskinfo disk_info, unsigned int lba)
+{
+ com32sys_t inreg;
+ struct ebios_dapa *dapa = __com32.cs_bounce;
+ void *buf = (char *)__com32.cs_bounce + SECTOR;
+ void *data;
+
+ memset(&inreg, 0, sizeof inreg);
+
+ if ( disk_info.ebios ) {
+ dapa->len = sizeof(*dapa);
+ dapa->count = 1; /* 1 sector */
+ 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] = disk_info.disk;
+ inreg.eax.b[1] = 0x42; /* Extended read */
+ } else {
+ unsigned int c, h, s, t;
+
+ if ( !disk_info.cbios ) {
+ /* We failed to get the geometry */
+
+ if ( lba )
+ return NULL; /* Can only read MBR */
+
+ s = 1; h = 0; c = 0;
+ } else {
+ s = (lba % disk_info.sect) + 1;
+ t = lba / disk_info.sect; /* Track = head*cyl */
+ h = t % disk_info.head;
+ c = t / disk_info.head;
+ }
+ 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] = disk_info.disk;
+ inreg.ebx.w[0] = OFFS(buf);
+ inreg.es = SEG(buf);
+ }
+
+ if (int13_retry(&inreg, NULL))
+ return NULL;
+
+ data = malloc(SECTOR);
+ if (data)
+ memcpy(data, buf, SECTOR);
+ return data;
+}
+
+
TIMEOUTCODE ontimeout()
{
beep();
@@ -83,6 +207,70 @@ void keys_handler(t_menusystem *ms, t_menuitem *mi,unsigned int scancode)
}
}
+
+static int get_disk_params(int disk, struct diskinfo *disk_info)
+{
+ static com32sys_t getparm, parm, getebios, ebios, inreg,outreg;
+ struct device_parameter *dp = __com32.cs_bounce;
+
+ memset(&inreg, 0, sizeof inreg);
+
+ disk_info[disk].disk = disk;
+ disk_info[disk].ebios = disk_info[disk].cbios = 0;
+
+ /* 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);
+
+ 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: strcpy(disk_info[disk].edd_version,"1.0"); break;
+ case 33: strcpy(disk_info[disk].edd_version,"1.1"); break;
+ case 48: strcpy(disk_info[disk].edd_version,"3.0"); break;
+ default: strcpy(disk_info[disk].edd_version,"0"); break;
+ }
+ }
+
+ /* Get disk parameters -- really only useful for
+ hard disks, but if we have a partitioned floppy
+ it's actually our best chance... */
+ 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].head = parm.edx.b[1]+1;
+ disk_info[disk].sect = parm.ecx.b[0] & 0x3f;
+ if ( disk_info[disk].sect == 0 ) {
+ disk_info[disk].sect = 1;
+ } else {
+ disk_info[disk].cbios = 1; /* Valid geometry */
+ }
+
+ inreg.esi.w[0] = OFFS(dp);
+ inreg.ds = SEG(dp);
+ inreg.eax.w[0] = 0x4800;
+ inreg.edx.b[0] = disk;
+
+ __intcall(0x13, &inreg, &outreg);
+
+ if ( parm.eflags.l & EFLAGS_CF )
+ printf("Error while detecting disk parameters\n");
+
+ printf("RESULT=0x%X 0x%X 0x%X 0x%X\n",dp->host_bus_type[0],dp->host_bus_type[1],dp->host_bus_type[2],dp->host_bus_type[3]);
+return 0;
+}
+
int detect_dmi(s_dmi *dmi) {
if ( ! dmi_iterate() ) {
printf("No DMI Structure found\n");
@@ -93,6 +281,16 @@ int detect_dmi(s_dmi *dmi) {
return 0;
}
+void detect_disks(struct diskinfo *disk_info) {
+ char *buf;
+ for (int drive = 0x80; drive <= 0xff; drive++) {
+ if (get_disk_params(drive,disk_info))
+ continue;
+
+ printf("DISK: 0x%X, sector=%d head=%d : EDD=%s\n",drive,disk_info[drive].sect,disk_info[drive].head,disk_info[drive].edd_version);
+ }
+}
+
void compute_PCI(unsigned char *menu,struct pci_domain **pci_domain) {
char buffer[MENULEN];
char infobar[MENULEN];
@@ -376,10 +574,13 @@ void setup_env() {
reg_ontimeout(ontimeout,1000,0);
}
-void detect_hardware(s_dmi *dmi, s_cpu *cpu, struct pci_domain **pci_domain) {
+void detect_hardware(s_dmi *dmi, s_cpu *cpu, struct pci_domain **pci_domain, struct diskinfo *disk_info) {
printf("CPU: Detecting\n");
detect_cpu(cpu);
+ printf("DISKS: Detecting\n");
+ detect_disks(disk_info);
+
printf("DMI: Detecting Table\n");
if (detect_dmi(dmi) == 0)
is_dmi_valid=true;
@@ -455,10 +656,11 @@ int main(void)
s_dmi dmi;
s_cpu cpu;
struct pci_domain *pci_domain=NULL;
+ struct diskinfo disk_info[255];
setup_env();
- detect_hardware(&dmi,&cpu,&pci_domain);
+ detect_hardware(&dmi,&cpu,&pci_domain,disk_info);
compute_submenus(&dmi,&cpu,&pci_domain);