diff options
Diffstat (limited to 'contrib/syslinux-4.02/dosutil/mdiskchk.c')
-rw-r--r-- | contrib/syslinux-4.02/dosutil/mdiskchk.c | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/dosutil/mdiskchk.c b/contrib/syslinux-4.02/dosutil/mdiskchk.c new file mode 100644 index 0000000..47bb08e --- /dev/null +++ b/contrib/syslinux-4.02/dosutil/mdiskchk.c @@ -0,0 +1,357 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2003-2008 H. Peter Anvin - All Rights Reserved + * Portions copyright 2010 Shao Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * mdiskchk.c + * + * DOS program to check for the existence of a memdisk. + * + * This program can be compiled for DOS with the OpenWatcom compiler + * (http://www.openwatcom.org/): + * + * wcl -3 -osx -mt mdiskchk.c + */ + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <i86.h> /* For MK_FP() */ + +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; + +/* Pull in MEMDISK common structures */ +#include "../memdisk/mstructs.h" + +struct memdiskinfo { + struct mdi mdi; + + /* We add our own fields at the end */ + int cylinders; + int heads; + int sectors; +}; + +struct memdiskinfo *query_memdisk(int drive) +{ + static struct memdiskinfo mm; + uint32_t _eax, _ebx, _ecx, _edx; + uint16_t _es, _di; + unsigned char _dl = drive; + uint16_t bytes; + + __asm { + .386; + mov eax, 454d0800h; + mov ecx, 444d0000h; + mov edx, 53490000h; + mov dl, _dl; + mov ebx, 3f4b0000h; + int 13h; + mov _eax, eax; + mov _ecx, ecx; + mov _edx, edx; + mov _ebx, ebx; + mov _es, es; + mov _di, di; + } + + if (_eax >> 16 != 0x4d21 || + _ecx >> 16 != 0x4d45 || _edx >> 16 != 0x4944 || _ebx >> 16 != 0x4b53) + return NULL; + + memset(&mm, 0, sizeof mm); + + bytes = *(uint16_t far *) MK_FP(_es, _di); + + /* 27 is the most we know how to handle */ + if (bytes > 27) + bytes = 27; + + _fmemcpy((void far *)&mm, (void far *)MK_FP(_es, _di), bytes); + + mm.cylinders = ((_ecx >> 8) & 0xff) + ((_ecx & 0xc0) << 2) + 1; + mm.heads = ((_edx >> 8) & 0xff) + 1; + mm.sectors = (_ecx & 0x3f); + + return &mm; +} + +const char *bootloadername(uint8_t id) +{ + static const struct { + uint8_t id, mask; + const char *name; + } *lp, list[] = { + {0x00, 0xf0, "LILO"}, + {0x10, 0xf0, "LOADLIN"}, + {0x31, 0xff, "SYSLINUX"}, + {0x32, 0xff, "PXELINUX"}, + {0x33, 0xff, "ISOLINUX"}, + {0x34, 0xff, "EXTLINUX"}, + {0x30, 0xf0, "SYSLINUX family"}, + {0x40, 0xf0, "Etherboot"}, + {0x50, 0xf0, "ELILO"}, + {0x70, 0xf0, "GrUB"}, + {0x80, 0xf0, "U-Boot"}, + {0xA0, 0xf0, "Gujin"}, + {0xB0, 0xf0, "Qemu"}, + {0x00, 0x00, "unknown"} + }; + + for (lp = list;; lp++) { + if (((id ^ lp->id) & lp->mask) == 0) + return lp->name; + } +} + +/* The function type for an output function */ +#define OUTPUT_FUNC_DECL(x) \ +void x(const int d, const struct memdiskinfo * const m) +typedef OUTPUT_FUNC_DECL((*output_func)); + +/* Show MEMDISK information for the passed structure */ +static OUTPUT_FUNC_DECL(normal_output) +{ + if (m == NULL) + return; + printf("Drive %02X is MEMDISK %u.%02u:\n" + "\tAddress = 0x%08lx, len = %lu sectors, chs = %u/%u/%u,\n" + "\tloader = 0x%02x (%s),\n" + "\tcmdline = %Fs\n", + d, m->mdi.version_major, m->mdi.version_minor, + m->mdi.diskbuf, m->mdi.disksize, m->cylinders, m->heads, m->sectors, + m->mdi.bootloaderid, bootloadername(m->mdi.bootloaderid), + MK_FP(m->mdi.cmdline.seg_off.segment, + m->mdi.cmdline.seg_off.offset)); +} + +/* Yield DOS SET command(s) as output for each MEMDISK kernel argument */ +static OUTPUT_FUNC_DECL(batch_output) +{ + if (m != NULL) { + char buf[256], *bc; + const char far *c = + MK_FP(m->mdi.cmdline.seg_off.segment, + m->mdi.cmdline.seg_off.offset); + const char *have_equals, is_set[] = "=1"; + + while (*c != '\0') { + /* Skip whitespace */ + while (isspace(*c)) + c++; + if (*c == '\0') + /* Trailing whitespace. That's enough processing */ + break; + /* Walk the kernel arguments while filling the buffer, + * looking for space or NUL or checking for a full buffer + */ + bc = buf; + have_equals = is_set; + while ((*c != '\0') && !isspace(*c) && + (bc < &buf[sizeof(buf) - 1])) { + /* Check if the param is "x=y" */ + if (*c == '=') + /* "=1" not needed */ + have_equals = &is_set[sizeof(is_set) - 1]; + *bc = *c; + c++; + bc++; + } + /* Found the end of the parameter and optional value sequence */ + *bc = '\0'; + printf("set %s%s\n", buf, have_equals); + } + } +} + +/* We do not output batch file output by default. We show MEMDISK info */ +static output_func show_memdisk = normal_output; + +/* A generic function type */ +#define MDISKCHK_FUNC_DECL(x) \ +void x(void) +typedef MDISKCHK_FUNC_DECL((*mdiskchk_func)); + +static MDISKCHK_FUNC_DECL(do_nothing) +{ + return; +} + +static MDISKCHK_FUNC_DECL(show_usage) +{ + printf("\nUsage: mdiskchk [--safe-hooks] [--mbfts] [--batch-output]\n" + "\n" + "Action: --safe-hooks . . Will scan INT 13h \"safe hook\" chain\n" + " --mbfts . . . . Will scan memory for MEMDISK mBFTs\n" + " --batch-output . Will output SET command output based\n" + " on MEMDISK kernel arguments\n" + " --no-sequential Suppresses probing all drive numbers\n"); +} + +/* Search memory for mBFTs and report them via the output method */ +static MDISKCHK_FUNC_DECL(show_mbfts) +{ + const uint16_t far * const free_base_mem = + MK_FP(0x0040, 0x0013); + int seg; + uint8_t chksum; + uint32_t i; + const struct mBFT far *mbft; + struct memdiskinfo m; + struct patch_area far *patch_area; + + for (seg = *free_base_mem / 16; seg < 0x9FFF; seg++) { + mbft = MK_FP(seg, 0); + /* Check for signature */ + if (mbft->acpi.signature[0] != 'm' || + mbft->acpi.signature[1] != 'B' || + mbft->acpi.signature[2] != 'F' || + mbft->acpi.signature[3] != 'T') + continue; + if (mbft->acpi.length != sizeof(struct mBFT)) + continue; + /* Check sum */ + chksum = 0; + for (i = 0; i < sizeof(struct mBFT); i++) + chksum += ((const uint8_t far *)mbft)[i]; + if (chksum) + continue; + /* Copy the MDI from the mBFT */ + _fmemcpy((void far *)&m, &mbft->mdi, sizeof(struct mdi)); + /* Adjust C/H/S since we actually know + * it directly for any MEMDISK with an mBFT + */ + patch_area = (struct patch_area far *)&mbft->mdi; + m.cylinders = patch_area->cylinders; + m.heads = patch_area->heads; + m.sectors = patch_area->sectors; + show_memdisk(patch_area->driveno, &m); + } +} + +/* Walk the "safe hook" chain as far as possible + * and report MEMDISKs that we find via the output method + */ +static MDISKCHK_FUNC_DECL(show_safe_hooks) +{ + const real_addr_t far * const int13 = + MK_FP(0x0000, 0x0013 * sizeof(real_addr_t)); + const struct safe_hook far *hook = + MK_FP(int13->seg_off.segment, int13->seg_off.offset); + + while ((hook->signature[0] == '$') && + (hook->signature[1] == 'I') && + (hook->signature[2] == 'N') && + (hook->signature[3] == 'T') && + (hook->signature[4] == '1') && + (hook->signature[5] == '3') && + (hook->signature[6] == 'S') && + (hook->signature[7] == 'F')) { + /* Found a valid "safe hook" */ + if ((hook->vendor[0] == 'M') && + (hook->vendor[1] == 'E') && + (hook->vendor[2] == 'M') && + (hook->vendor[3] == 'D') && + (hook->vendor[4] == 'I') && + (hook->vendor[5] == 'S') && + (hook->vendor[6] == 'K')) { + /* Found a valid MEMDISK "safe hook". It will have an mBFT */ + const struct mBFT far *mbft; + struct memdiskinfo m; + struct patch_area far *patch_area; + + /* Copy the MDI from the mBFT. Offset is a misnomer here */ + mbft = MK_FP(hook->mbft >> 4, 0); /* Always aligned */ + _fmemcpy((void far *)&m, &mbft->mdi, sizeof(struct mdi)); + /* Adjust C/H/S since we actually know + * it directly for any MEMDISK with an mBFT + */ + patch_area = (struct patch_area far *)&mbft->mdi; + m.cylinders = patch_area->cylinders; + m.heads = patch_area->heads; + m.sectors = patch_area->sectors; + show_memdisk(patch_area->driveno, &m); + } /* if */ + /* Step to the next hook in the "safe hook" chain */ + hook = MK_FP(hook->old_hook.seg_off.segment, + hook->old_hook.seg_off.offset); + } /* while */ +} + +int main(int argc, char *argv[]) +{ + int d; + int found = 0; + int sequential_scan = 1; /* Classic behaviour */ + const struct memdiskinfo *m; + + /* Default behaviour */ + mdiskchk_func usage = do_nothing, + safe_hooks = do_nothing, + mbfts = do_nothing; + + /* For each argument */ + while (--argc) { + /* Argument should begin with one of these chars */ + if ((*argv[argc] != '/') && (*argv[argc] != '-')) { + /* It doesn't. Print usage soon */ + usage = show_usage; + break; + } + argv[argc]++; + + /* Next char might be '-' as in "--safe-hooks" */ + if (*argv[argc] == '-') + argv[argc]++; + + switch (*argv[argc]) { + case 'S': + case 's': + safe_hooks = show_safe_hooks; + break; + case 'M': + case 'm': + mbfts = show_mbfts; + break; + case 'B': + case 'b': + show_memdisk = batch_output; + break; + case 'N': + case 'n': + sequential_scan = 0; + break; + default: + usage = show_usage; + } /* switch */ + } /* while */ + + safe_hooks(); + mbfts(); + if (!sequential_scan) + goto skip_sequential; + for (d = 0; d <= 0xff; d++) { + m = query_memdisk(d); + if (m != NULL) { + found++; + show_memdisk(d, m); + } + } +skip_sequential: + usage(); + + return found; +} + |