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(¶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 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