• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&params, 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, &params, &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