1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 2011 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., 51 Franklin St, Fifth Floor,
8 * Boston MA 02110-1301, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
10 *
11 * ----------------------------------------------------------------------- */
12
13 /****
14 * @file ifmemdsk.c
15 *
16 * This COM32 module detects if there are MEMDISKs established.
17 */
18
19 static const char usage_text[] = "\
20 Usage:\n\
21 ifmemdsk.c32 [<option> [...]] --info [<option> [...]]\n\
22 ifmemdsk.c32 [<option> [...]] [<detected_cmd>] -- [<not_detected_cmd>]\n\
23 \n\
24 Options:\n\
25 --info . . . . . Displays info about MEMDISK(s)\n\
26 --safe-hooks . . Will scan INT 13h \"safe hook\" chain\n\
27 --mbfts . . . . . Will scan memory for MEMDISK mBFTs\n\
28 --no-sequential Suppresses probing all drive numbers\n\
29 \n\
30 If a MEMDISK is found, or if a particular MEMDISK is sought by the options\n\
31 and is found, then the 'detected_cmd' action will be taken, else the\n\
32 'not_detected_cmd' action will be taken.\n\
33 \n";
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <alloca.h>
38 #include <com32.h>
39 #include <console.h>
40 #include <syslinux/boot.h>
41
42 /* Pull in MEMDISK common structures */
43 #include "../../memdisk/mstructs.h"
44
45 /*** Macros */
46 #define M_GET_DRIVE_PARAMS (0x08)
47 #define M_SEGOFFTOPTR(seg, off) (((seg) << 4) + (off))
48 #define M_INT13H M_SEGOFFTOPTR(0x0000, 0x0013 * 4)
49 #define M_FREEBASEMEM M_SEGOFFTOPTR(0x0040, 0x0013)
50 #define M_TOP M_SEGOFFTOPTR(0x9FFF, 0x0000)
51
52 /*** Object types */
53 typedef struct mdi s_mdi;
54 typedef real_addr_t u_segoff;
55 typedef struct safe_hook s_safe_hook;
56 typedef struct mBFT s_mbft;
57
58 /*** Function types */
59 typedef int f_find(void);
60
61 /*** Function declarations */
62 static const s_mdi * installation_check(int);
63 static f_find scan_drives;
64 static f_find walk_safe_hooks;
65 static const s_safe_hook * is_safe_hook(const void *);
66 static const s_mdi * is_memdisk_hook(const s_safe_hook *);
67 static f_find scan_mbfts;
68 static const s_mbft * is_mbft(const void *);
69 static f_find do_nothing;
70 static void memdisk_info(const s_mdi *);
71 static void boot_args(char **);
72 static const char * bootloadername(uint8_t);
73
74 /*** Structure/union definitions */
75
76 /*** Objects */
77 static int show_info = 0;
78
79 /*** Function definitions */
80
main(int argc,char ** argv)81 int main(int argc, char ** argv) {
82 static f_find * do_scan_drives = scan_drives;
83 static f_find * do_walk_safe_hooks = do_nothing;
84 static f_find * do_scan_mbfts = do_nothing;
85 char ** detected_cmd;
86 char ** not_detected_cmd;
87 char ** cmd;
88 char ** cur_arg;
89 int show_usage;
90 int found;
91
92 (void) argc;
93
94 openconsole(&dev_null_r, &dev_stdcon_w);
95
96 detected_cmd = NULL;
97 not_detected_cmd = NULL;
98 show_usage = 1;
99 for (cur_arg = argv + 1; *cur_arg; ++cur_arg) {
100 /* Check for command divider */
101 if (!strcmp(*cur_arg, "--")) {
102 show_usage = 0;
103 *cur_arg = NULL;
104 not_detected_cmd = cur_arg + 1;
105 break;
106 }
107
108 /* Check for '--info' */
109 if (!strcmp(*cur_arg, "--info")) {
110 show_usage = 0;
111 show_info = 1;
112 continue;
113 }
114
115 /* Other options */
116 if (!strcmp(*cur_arg, "--no-sequential")) {
117 do_scan_drives = do_nothing;
118 continue;
119 }
120
121 if (!strcmp(*cur_arg, "--safe-hooks")) {
122 do_walk_safe_hooks = walk_safe_hooks;
123 continue;
124 }
125
126 if (!strcmp(*cur_arg, "--mbfts")) {
127 do_scan_mbfts = scan_mbfts;
128 continue;
129 }
130
131 /* Check for invalid option */
132 if (!memcmp(*cur_arg, "--", sizeof "--" - 1)) {
133 puts("Invalid option!");
134 show_usage = 1;
135 break;
136 }
137
138 /* Set 'detected_cmd' if it's null */
139 if (!detected_cmd)
140 detected_cmd = cur_arg;
141
142 continue;
143 }
144
145 if (show_usage) {
146 fprintf(stderr, usage_text);
147 return 1;
148 }
149
150 found = 0;
151 found += do_walk_safe_hooks();
152 found += do_scan_mbfts();
153 found += do_scan_drives();
154
155 cmd = found ? detected_cmd : not_detected_cmd;
156 if (cmd && *cmd)
157 boot_args(cmd);
158
159 return 0;
160 }
161
installation_check(int drive)162 static const s_mdi * installation_check(int drive) {
163 com32sys_t params, results;
164 int found;
165
166 /* Set parameters for INT 0x13 call */
167 memset(¶ms, 0, sizeof params);
168 params.eax.w[0] = M_GET_DRIVE_PARAMS << 8;
169 params.edx.w[0] = drive;
170 /* 'ME' 'MD' 'IS' 'K?' */
171 params.eax.w[1] = 0x454D;
172 params.ecx.w[1] = 0x444D;
173 params.edx.w[1] = 0x5349;
174 params.ebx.w[1] = 0x3F4B;
175
176 /* Perform the call */
177 __intcall(0x13, ¶ms, &results);
178
179 /* Check result */
180 found = (
181 /* '!M' 'EM' 'DI' 'SK' */
182 results.eax.w[1] == 0x4D21 &&
183 results.ecx.w[1] == 0x4D45 &&
184 results.edx.w[1] == 0x4944 &&
185 results.ebx.w[1] == 0x4B53
186 );
187
188 if (found)
189 return MK_PTR(results.es, results.edi.w[0]);
190
191 return NULL;
192 }
193
scan_drives(void)194 static int scan_drives(void) {
195 int found, drive;
196 const s_mdi * mdi;
197
198 for (found = drive = 0; drive <= 0xFF; ++drive) {
199 mdi = installation_check(drive);
200 if (!mdi)
201 continue;
202
203 memdisk_info(mdi);
204 ++found;
205 continue;
206 }
207
208 return found;
209 }
210
walk_safe_hooks(void)211 static int walk_safe_hooks(void) {
212 static const u_segoff * const int13 = (void *) M_INT13H;
213 const void * addr;
214 int found;
215 const s_safe_hook * hook;
216 const s_mdi * mdi;
217
218 /* INT 0x13 vector */
219 addr = MK_PTR(int13->seg_off.segment, int13->seg_off.offset);
220 found = 0;
221 while (addr) {
222 hook = is_safe_hook(addr);
223 if (!hook)
224 break;
225
226 mdi = is_memdisk_hook(hook);
227 if (mdi) {
228 memdisk_info(mdi);
229 ++found;
230 }
231
232 addr = MK_PTR(
233 hook->old_hook.seg_off.segment,
234 hook->old_hook.seg_off.offset
235 );
236 continue;
237 }
238 return found;
239 }
240
is_safe_hook(const void * addr)241 static const s_safe_hook * is_safe_hook(const void * addr) {
242 static const char magic[] = "$INT13SF";
243 const s_safe_hook * const test = addr;
244
245 if (memcmp(test->signature, magic, sizeof magic - 1))
246 return NULL;
247
248 return test;
249 }
250
is_memdisk_hook(const s_safe_hook * hook)251 static const s_mdi * is_memdisk_hook(const s_safe_hook * hook) {
252 static const char magic[] = "MEMDISK";
253 const s_mbft * mbft;
254
255 if (memcmp(hook->vendor, magic, sizeof magic - 1))
256 return NULL;
257
258 /* An mBFT is always aligned */
259 mbft = MK_PTR(hook->mbft >> 4, 0);
260 return &mbft->mdi;
261 }
262
scan_mbfts(void)263 static int scan_mbfts(void) {
264 static const uint16_t * const free_base_mem = (void *) M_FREEBASEMEM;
265 static const void * const top = (void *) M_TOP;
266 const void * addr;
267 const s_mbft * mbft;
268 int found;
269
270 found = 0;
271 for (addr = MK_PTR(*free_base_mem << 4, 0); addr < top; addr += 1 << 4) {
272 if (!(mbft = is_mbft(addr)))
273 continue;
274
275 memdisk_info(&mbft->mdi);
276 ++found;
277 continue;
278 }
279
280 return found;
281 }
282
is_mbft(const void * addr)283 static const s_mbft * is_mbft(const void * addr) {
284 static const char magic[] = "mBFT";
285 const s_mbft * const test = addr;
286 const uint8_t * ptr, * end;
287 uint8_t chksum;
288
289 if (memcmp(test->acpi.signature, magic, sizeof magic - 1))
290 return NULL;
291
292 if (test->acpi.length != sizeof *test)
293 return NULL;
294
295 end = (void *) (test + 1);
296 chksum = 0;
297 for (ptr = addr; ptr < end; ++ptr)
298 chksum += *ptr;
299 if (chksum)
300 return NULL;
301
302 /* Looks like it's an mBFT! */
303 return test;
304 }
305
do_nothing(void)306 static int do_nothing(void) {
307 return 0;
308 }
309
memdisk_info(const s_mdi * mdi)310 static void memdisk_info(const s_mdi * mdi) {
311 const char * cmdline;
312
313 if (!show_info)
314 return;
315
316 cmdline = MK_PTR(
317 mdi->cmdline.seg_off.segment,
318 mdi->cmdline.seg_off.offset
319 );
320 printf(
321 "Found MEMDISK version %u.%02u:\n"
322 " diskbuf == 0x%08X, disksize == %u sectors\n"
323 " bootloaderid == 0x%02X (%s),\n"
324 " cmdline: %s\n",
325 mdi->version_major,
326 mdi->version_minor,
327 mdi->diskbuf,
328 mdi->disksize,
329 mdi->bootloaderid,
330 bootloadername(mdi->bootloaderid),
331 cmdline
332 );
333 return;
334 }
335
336 /* This function copyright H. Peter Anvin */
boot_args(char ** args)337 static void boot_args(char **args)
338 {
339 int len = 0, a = 0;
340 char **pp;
341 const char *p;
342 char c, *q, *str;
343
344 for (pp = args; *pp; pp++)
345 len += strlen(*pp) + 1;
346
347 q = str = alloca(len);
348 for (pp = args; *pp; pp++) {
349 p = *pp;
350 while ((c = *p++))
351 *q++ = c;
352 *q++ = ' ';
353 a = 1;
354 }
355 q -= a;
356 *q = '\0';
357
358 if (!str[0])
359 syslinux_run_default();
360 else
361 syslinux_run_command(str);
362 }
363
364 /* This function copyright H. Peter Anvin */
bootloadername(uint8_t id)365 static const char *bootloadername(uint8_t id)
366 {
367 static const struct {
368 uint8_t id, mask;
369 const char *name;
370 } *lp, list[] = {
371 {0x00, 0xf0, "LILO"},
372 {0x10, 0xf0, "LOADLIN"},
373 {0x31, 0xff, "SYSLINUX"},
374 {0x32, 0xff, "PXELINUX"},
375 {0x33, 0xff, "ISOLINUX"},
376 {0x34, 0xff, "EXTLINUX"},
377 {0x30, 0xf0, "Syslinux family"},
378 {0x40, 0xf0, "Etherboot"},
379 {0x50, 0xf0, "ELILO"},
380 {0x70, 0xf0, "GrUB"},
381 {0x80, 0xf0, "U-Boot"},
382 {0xA0, 0xf0, "Gujin"},
383 {0xB0, 0xf0, "Qemu"},
384 {0x00, 0x00, "unknown"}
385 };
386
387 for (lp = list;; lp++) {
388 if (((id ^ lp->id) & lp->mask) == 0)
389 return lp->name;
390 }
391 }
392
393