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 */
probe_any(uint8_t func,uint8_t drive,com32sys_t * regs)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 */
probe_int13h_01h_fail(int istatus)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 */
probe_int13h_01h(uint8_t drive)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 */
probe_int13h_08h(uint8_t drive,com32sys_t * regs)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 */
probe_int13h_15h(uint8_t drive,com32sys_t * regs)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 */
probe_int13h_41h(uint8_t drive,com32sys_t * regs)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 */
probe_bda_drive(uint8_t drive)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 */
multi_probe_drive(uint8_t drive)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 */
probe_drive_range(uint8_t start)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 */
no_printf(const char * ignored,...)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 */
dskprobe_pause(com32sys_t * regs)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