/* * edd.c - real mode bios library for discovering EDD capabilities of * BIOS drives * * Matt Wilson * * Copyright 2000 Red Hat, Inc. * * This software may be freely redistributed under the terms of the GNU * library public license. * * You should have received a copy of the GNU Library Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include "lrmi.h" #include "edd.h" static int edd_lrmi_initialized = 0; static int edd_lrmi_init (void) { if (edd_lrmi_initialized) return EDD_SUCCESS; if (iopl(3)) { fprintf (stderr, "ERROR: failed to set iopl permissions\n"); return EDD_ERROR; } if (ioperm(0, 0x400, 1)) { fprintf (stderr, "ERROR: failed to set ioperm permissions\n"); return EDD_ERROR; } /* Initialize LRMI. */ if(LRMI_init() == 1) { edd_lrmi_initialized = 1; return EDD_SUCCESS; } fprintf (stderr, "ERROR: failed to initialize lrmi library\n"); return EDD_ERROR; } EDDParameters * edd_get_parameters (EDDCapability *ec) { struct LRMI_regs regs; EDDParameters *ep, *ret; return NULL; if (edd_lrmi_init() == EDD_ERROR) { return NULL; } (unsigned char *) ep = LRMI_alloc_real(sizeof(EDDParameters)); if (ep == NULL) { return NULL; } memset(ep, 0, sizeof(EDDParameters)); memset(®s, 0, sizeof(regs)); if (ec->version.major == 3) ep->buffer_size = 0x42; else if (ec->version.major == 2) ep->buffer_size = 0x1e; else ep->buffer_size = 0x1a; regs.eax = 0x4800; regs.edx = ec->drive & 0x00ff; regs.es = ((u_int32_t) ep) >> 4; regs.edi = ((u_int32_t) ep) & 0x0f; printf ("%p -> 0x%x 0x%x\n", ep, regs.es, regs.edi); if(LRMI_int(0x13, ®s) == 0) { LRMI_free_real((unsigned char *) ep); return NULL; } /* XXX check return */ printf ("0x%x\n", regs.eax); printf ("0x%x\n", regs.flags); ret = malloc (sizeof (EDDParameters)); if (ret == NULL) { fprintf (stderr, "out of memory\n"); abort(); } memcpy (ret, ep, sizeof (EDDParameters)); LRMI_free_real((unsigned char *) ep); return ret; } EDDCapability * edd_supported(int drive) { struct LRMI_regs regs; FILE *f = fopen("/proc/cmdline", "r"); if (f) { char buf[100]; fgets(buf, sizeof(buf) - 1, f); fclose(f); if (strstr(buf, "lba32")) { EDDCapability *ec = malloc (sizeof (EDDCapability)); ec->edd = 1; return ec; } } if (edd_lrmi_init() == EDD_ERROR) { return NULL; } memset(®s, 0, sizeof(regs)); regs.eax = 0x4100; regs.ebx = 0x55aa; regs.edx = drive & 0xff; /* Do it. */ if (LRMI_int (0x13, ®s) == 0) { return NULL; } /* Check for successful return. */ if(regs.ebx == 0xaa55) { /* Supported, report capabilities */ EDDCapability *ec = malloc (sizeof (EDDCapability)); memset (ec, 0, sizeof (EDDCapability)); if (ec == NULL) { fprintf (stderr, "out of memory\n"); abort(); } if ((regs.eax & 0xff00) == 0x0100) { ec->version.major = 1; ec->version.minor = 0; } else if ((regs.eax & 0xff00) == 0x2000) { ec->version.major = 2; ec->version.minor = 0; } else if ((regs.eax & 0xff00) == 0x2100) { ec->version.major = 2; ec->version.minor = 1; } else if ((regs.eax & 0xff00) == 0x3000) { ec->version.major = 3; ec->version.minor = 0; } else { /* fprintf (stderr, "WARNING: Unknown EDD version 0x%x supported\n", */ /* regs.eax & 0xff00); */ /* XXX hack, get rid of stderr output */ ec->version.major = 1; ec->version.minor = 0; } if (regs.ecx & EDD_CAPABILITY_EDA) ec->eda = 1; if (regs.ecx & EDD_CAPABILITY_REMOVABLE) ec->removable = 1; if (regs.ecx & EDD_CAPABILITY_EDD) ec->edd = 1; ec->drive = drive; return ec; } else { /* Not supported. */ return NULL; } } #ifdef TESTING int main (void) { int i; EDDCapability *ec; EDDParameters *ep; for (i = 0x80; i < 0x90; i++) { if ((ec = edd_supported(i))) { printf ("edd version %d.%d supported on 0x%x\n", ec->version.major, ec->version.minor, i); printf (" extended disk access %s\n", ec->eda ? "supported" : "not supported"); printf (" removable media functions %s\n", ec->removable ? "supported" : "not supported"); printf (" edd functions %s\n", ec->edd ? "supported" : "not supported"); ep = edd_get_parameters (ec); if (ep) { printf ("heads: %d cyl: %d sec/track: %d\n", ep->heads, ep->cyls, ep->sectors); free (ep); } else printf ("get_parameters call failed\n"); free (ec); } else printf ("edd not supported on 0x%x\n", i); } return 0; } #endif