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(®s, 0, sizeof regs); 77 probe_any(0x01, drive, ®s); 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, ®s); 186 c += probe_int13h_15h(drive, ®s); 187 c += probe_int13h_41h(drive, ®s); 188 } 189 c += probe_bda_drive(drive); 190 dskprobe_pause(®s); 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