memdisk/dskprobe: Show the status of the last command when debugging
[profile/ivi/syslinux.git] / memdisk / dskprobe.c
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((void *)(&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\n", 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
90     memset(regs, 0, sizeof *regs);
91     probe_any(0x08, drive, regs);
92     present = !(regs->eflags.l & 1) && !regs->eax.b[1];
93     dskprobe_printf("  AH08: P%d CF%d AH%02x AL%02x BL%02x DL%02x\n", present,
94                     regs->eflags.l & 1, regs->eax.b[1], regs->eax.b[0],
95                     regs->ebx.b[0], regs->edx.b[0]);
96     return present;
97 }
98
99 /**
100  * INT 0x13, AH == 0x15: Get disk type.
101  */
102 static int probe_int13h_15h(uint8_t drive, com32sys_t * regs)
103 {
104     int present;
105     int status;
106
107     memset(regs, 0, sizeof *regs);
108     probe_any(0x15, drive, regs);
109     present = !(regs->eflags.l & 1) && regs->eax.b[1];
110     status = probe_int13h_01h(drive);
111     probe_int13h_01h_fail(status);
112     dskprobe_printf("  AH15: P%d CF%d AH%02x AL%02x CX%04x DX%04x\n", present,
113                     regs->eflags.l & 1, regs->eax.b[1], regs->eax.b[0],
114                     regs->ecx.w[0], regs->edx.w[0]);
115     return present;
116 }
117
118 /**
119  * INT 0x13, AH == 0x41: INT 0x13 extensions installation check.
120  */
121 static int probe_int13h_41h(uint8_t drive, com32sys_t * regs)
122 {
123     int present;
124
125     memset(regs, 0, sizeof *regs);
126     regs->ebx.w[0] = 0x55AA;    /* BX == 0x55AA */
127     probe_any(0x41, drive, regs);
128     present = !(regs->eflags.l & 1) && (regs->ebx.w[0] == 0xAA55);
129     dskprobe_printf("  AH41: P%d CF%d BX%04x AH%02x DH%02x\n", present,
130                     regs->eflags.l & 1, regs->ebx.w[0], regs->eax.b[1],
131                     regs->edx.b[1]);
132     return present;
133 }
134
135 /*
136  * We will probe the BIOS Data Area and count the drives found there.
137  * This heuristic then assumes that all drives of 'drive's type are
138  * found in a contiguous range, and returns 1 if the probed drive
139  * is less than or equal to the BDA count.
140  * This particular function's code is derived from code in setup.c by
141  * H. Peter Anvin.  Please respect that file's copyright for this function
142  */
143 int probe_bda_drive(uint8_t drive)
144 {
145     int bios_drives;
146     int err;
147
148     if (drive & 0x80) {
149         bios_drives = rdz_8(BIOS_HD_COUNT);     /* HDD count */
150     } else {
151         uint8_t equip = rdz_8(BIOS_EQUIP);
152         if (equip & 1)
153             bios_drives = (equip >> 6) + 1;     /* Floppy count */
154         else
155             bios_drives = 0;
156     }
157     err = (drive - (drive & 0x80)) >= bios_drives ? 0 : 1;
158     dskprobe_printf("BDA drive %02x? %d, total count: %d\n", drive, err,
159                     bios_drives);
160     return err;
161 }
162
163 /*
164  * We will probe a drive with a few different methods, returning
165  * the count of succesful probes
166  */
167 int multi_probe_drive(uint8_t drive)
168 {
169     int c = 0;
170     com32sys_t regs;
171
172     dskprobe_printf("INT 13 DL%02x:\n", drive);
173     /* Only probe the BDA for floppies */
174     if (drive & 0x80) {
175
176         c += probe_int13h_08h(drive, &regs);
177         c += probe_int13h_15h(drive, &regs);
178         c += probe_int13h_41h(drive, &regs);
179     }
180     c += probe_bda_drive(drive);
181     dskprobe_pause(&regs);
182     return c;
183 }
184
185 /*
186  * We will probe a contiguous range of BIOS drive, starting with drive
187  * number 'start'.  We probe with a few different methods, and return
188  * the first drive which doesn't respond to any of the probes.
189  */
190 uint8_t probe_drive_range(uint8_t start)
191 {
192     uint8_t drive = start;
193     while (multi_probe_drive(drive)) {
194         drive++;
195         /* Check for passing the floppy/HDD boundary */
196         if ((drive & 0x7F) == 0)
197             break;
198     }
199     return drive;
200 }
201
202 /* Dummy printf() that does nothing */
203 static int no_printf(const char *ignored, ...)
204 {
205     (void)ignored;
206     return 0;
207 }
208
209 /* Pause if we are in debug-mode */
210 static void dskprobe_pause(com32sys_t * regs)
211 {
212     if (!DBG_DSKPROBE)
213         return;
214     dskprobe_printf("Press a key to continue...\n");
215     memset(regs, 0, sizeof *regs);
216     regs->eax.w[0] = 0;
217     intcall(0x16, regs, NULL);
218     return;
219 }