Home | History | Annotate | Download | only in memdisk
      1 /* ----------------------------------------------------------------------- *
      2  *
      3  *   Copyright 2009 Shao Miller - All Rights Reserved
      4  *
      5  *   This program is free software; you can redistribute it and/or modify
      6  *   it under the terms of the GNU General Public License as published by
      7  *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
      8  *   Boston MA 02111-1307, USA; either version 2 of the License, or
      9  *   (at your option) any later version; incorporated herein by reference.
     10  *
     11  * ----------------------------------------------------------------------- */
     12 
     13 /*
     14  * dskprobe.c
     15  *
     16  * Routines for probing BIOS disk drives
     17  */
     18 
     19 /* Change to 1 for debugging */
     20 #define DBG_DSKPROBE 0
     21 
     22 #include <stdint.h>
     23 #include "memdisk.h"
     24 #include "bda.h"
     25 #include "conio.h"
     26 
     27 /* Function type for printf() */
     28 typedef int (f_printf) (const char *, ...);
     29 
     30 /* Dummy printf() that does nothing */
     31 static f_printf no_printf;
     32 static f_printf *dskprobe_printfs[] = { no_printf, printf };
     33 
     34 #define dskprobe_printf (dskprobe_printfs[DBG_DSKPROBE])
     35 
     36 static void dskprobe_pause(com32sys_t *);
     37 
     38 /* Probe routine function type */
     39 typedef int (f_probe) (uint8_t, com32sys_t *);
     40 static f_probe probe_int13h_08h, probe_int13h_15h, probe_int13h_41h;
     41 
     42 /* We will probe a BIOS drive number using INT 0x13, AH == func */
     43 static void probe_any(uint8_t func, uint8_t drive, com32sys_t * regs)
     44 {
     45     regs->eax.b[1] = func;	/* AH == sub-function for probe */
     46     regs->edx.b[0] = drive;	/* DL == drive number to probe */
     47     intcall(0x13, regs, regs);
     48     return;
     49 }
     50 
     51 /**
     52  * Determine if the return from probe_int13h_01h indicates a failure; a
     53  * return of zero indicates no known failure.
     54  */
     55 static int probe_int13h_01h_fail(int istatus)
     56 {
     57     int status = 0;
     58 
     59     if (istatus >= 256)
     60 	status = istatus;
     61     else
     62 	switch (istatus) {
     63 	case 1: status = istatus;
     64 	}
     65     return status;
     66 }
     67 
     68 /**
     69  * INT 0x13, AH == 0x01: Get status of last command.
     70  */
     71 static int probe_int13h_01h(uint8_t drive)
     72 {
     73     int status;
     74     com32sys_t regs;
     75 
     76     memset(&regs, 0, sizeof regs);
     77     probe_any(0x01, drive, &regs);
     78     status = (regs.eflags.l & 1) * 256 + regs.eax.b[1];
     79     dskprobe_printf("  AH01: CF%d AH%02x", regs.eflags.l & 1, regs.eax.b[1]);
     80     return status;
     81 }
     82 
     83 /**
     84  * INT 0x13, AH == 0x08: Get drive parameters.
     85  */
     86 static int probe_int13h_08h(uint8_t drive, com32sys_t * regs)
     87 {
     88     int present;
     89     int status;
     90 
     91     memset(regs, 0, sizeof *regs);
     92     probe_any(0x08, drive, regs);
     93     dskprobe_printf("  AH08: CF%d AH%02x AL%02x BL%02x DL%02x    ",
     94 		    regs->eflags.l & 1, regs->eax.b[1], regs->eax.b[0],
     95 		    regs->ebx.b[0], regs->edx.b[0]);
     96     present = !(regs->eflags.l & 1) && !regs->eax.b[1];
     97     status = probe_int13h_01h(drive);
     98     present = present && !(probe_int13h_01h_fail(status));
     99     dskprobe_printf("  P%d\n",  present);
    100     return present;
    101 }
    102 
    103 /**
    104  * INT 0x13, AH == 0x15: Get disk type.
    105  */
    106 static int probe_int13h_15h(uint8_t drive, com32sys_t * regs)
    107 {
    108     int present;
    109     int status;
    110 
    111     memset(regs, 0, sizeof *regs);
    112     probe_any(0x15, drive, regs);
    113     dskprobe_printf("  AH15: CF%d AH%02x AL%02x CX%04x DX%04x",
    114 		    regs->eflags.l & 1, regs->eax.b[1], regs->eax.b[0],
    115 		    regs->ecx.w[0], regs->edx.w[0]);
    116     present = !(regs->eflags.l & 1) && regs->eax.b[1];
    117     status = probe_int13h_01h(drive);
    118     present = present && !(probe_int13h_01h_fail(status));
    119     dskprobe_printf("  P%d\n",  present);
    120     return present;
    121 }
    122 
    123 /**
    124  * INT 0x13, AH == 0x41: INT 0x13 extensions installation check.
    125  */
    126 static int probe_int13h_41h(uint8_t drive, com32sys_t * regs)
    127 {
    128     int present;
    129     int status;
    130 
    131     memset(regs, 0, sizeof *regs);
    132     regs->ebx.w[0] = 0x55AA;	/* BX == 0x55AA */
    133     probe_any(0x41, drive, regs);
    134     dskprobe_printf("  AH41: CF%d AH%02x BX%04x CX%04x DH%02x",
    135 		    regs->eflags.l & 1, regs->eax.b[1], regs->ebx.w[0],
    136 		    regs->ecx.w[0], regs->edx.b[1]);
    137     present = !(regs->eflags.l & 1) && (regs->ebx.w[0] == 0xAA55);
    138     status = probe_int13h_01h(drive);
    139     present = present && !(probe_int13h_01h_fail(status));
    140     dskprobe_printf("  P%d\n",  present);
    141     return present;
    142 }
    143 
    144 /*
    145  * We will probe the BIOS Data Area and count the drives found there.
    146  * This heuristic then assumes that all drives of 'drive's type are
    147  * found in a contiguous range, and returns 1 if the probed drive
    148  * is less than or equal to the BDA count.
    149  * This particular function's code is derived from code in setup.c by
    150  * H. Peter Anvin.  Please respect that file's copyright for this function
    151  */
    152 int probe_bda_drive(uint8_t drive)
    153 {
    154     int bios_drives;
    155     int err;
    156 
    157     if (drive & 0x80) {
    158 	bios_drives = rdz_8(BIOS_HD_COUNT);	/* HDD count */
    159     } else {
    160 	uint8_t equip = rdz_8(BIOS_EQUIP);
    161 	if (equip & 1)
    162 	    bios_drives = (equip >> 6) + 1;	/* Floppy count */
    163 	else
    164 	    bios_drives = 0;
    165     }
    166     err = (drive - (drive & 0x80)) >= bios_drives ? 0 : 1;
    167     dskprobe_printf("BDA drive %02x? %d, total count: %d\n", drive, err,
    168 		    bios_drives);
    169     return err;
    170 }
    171 
    172 /*
    173  * We will probe a drive with a few different methods, returning
    174  * the count of succesful probes
    175  */
    176 int multi_probe_drive(uint8_t drive)
    177 {
    178     int c = 0;
    179     com32sys_t regs;
    180 
    181     dskprobe_printf("INT 13 DL%02x:\n", drive);
    182     /* Only probe the BDA for floppies */
    183     if (drive & 0x80) {
    184 
    185 	c += probe_int13h_08h(drive, &regs);
    186 	c += probe_int13h_15h(drive, &regs);
    187 	c += probe_int13h_41h(drive, &regs);
    188     }
    189     c += probe_bda_drive(drive);
    190     dskprobe_pause(&regs);
    191     return c;
    192 }
    193 
    194 /*
    195  * We will probe a contiguous range of BIOS drive, starting with drive
    196  * number 'start'.  We probe with a few different methods, and return
    197  * the first drive which doesn't respond to any of the probes.
    198  */
    199 uint8_t probe_drive_range(uint8_t start)
    200 {
    201     uint8_t drive = start;
    202     while (multi_probe_drive(drive)) {
    203 	drive++;
    204 	/* Check for passing the floppy/HDD boundary */
    205 	if ((drive & 0x7F) == 0)
    206 	    break;
    207     }
    208     return drive;
    209 }
    210 
    211 /* Dummy printf() that does nothing */
    212 static int no_printf(const char *ignored, ...)
    213 {
    214     (void)ignored;
    215     return 0;
    216 }
    217 
    218 /* Pause if we are in debug-mode */
    219 static void dskprobe_pause(com32sys_t * regs)
    220 {
    221     if (!DBG_DSKPROBE)
    222 	return;
    223     dskprobe_printf("Press a key to continue...\n");
    224     memset(regs, 0, sizeof *regs);
    225     regs->eax.w[0] = 0;
    226     intcall(0x16, regs, NULL);
    227     return;
    228 }
    229