Home | History | Annotate | Download | only in modules
      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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    306 static int do_nothing(void) {
    307     return 0;
    308   }
    309 
    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 */
    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 */
    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