syslinux/dosutil/mdiskchk.c
<<
>>
Prefs
   1/* -*- c -*- ------------------------------------------------------------- *
   2 *
   3 *   Copyright 2003-2008 H. Peter Anvin - All Rights Reserved
   4 *   Portions copyright 2010 Shao Miller
   5 *
   6 *   This program is free software; you can redistribute it and/or modify
   7 *   it under the terms of the GNU General Public License as published by
   8 *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
   9 *   Boston MA 02111-1307, USA; either version 2 of the License, or
  10 *   (at your option) any later version; incorporated herein by reference.
  11 *
  12 * ----------------------------------------------------------------------- */
  13
  14/*
  15 * mdiskchk.c
  16 *
  17 * DOS program to check for the existence of a memdisk.
  18 *
  19 * This program can be compiled for DOS with the OpenWatcom compiler
  20 * (http://www.openwatcom.org/):
  21 *
  22 * wcl -3 -osx -mt mdiskchk.c
  23 */
  24
  25#include <ctype.h>
  26#include <stdio.h>
  27#include <string.h>
  28#include <i86.h>                /* For MK_FP() */
  29
  30typedef unsigned long uint32_t;
  31typedef unsigned short uint16_t;
  32typedef unsigned char uint8_t;
  33
  34/* Pull in MEMDISK common structures */
  35#include "../memdisk/mstructs.h"
  36
  37struct memdiskinfo {
  38    struct mdi mdi;
  39
  40    /* We add our own fields at the end */
  41    int cylinders;
  42    int heads;
  43    int sectors;
  44};
  45
  46struct memdiskinfo *query_memdisk(int drive)
  47{
  48    static struct memdiskinfo mm;
  49    uint32_t _eax, _ebx, _ecx, _edx;
  50    uint16_t _es, _di;
  51    unsigned char _dl = drive;
  52    uint16_t bytes;
  53
  54    __asm {
  55        .386;
  56        mov eax, 454d0800h;
  57        mov ecx, 444d0000h;
  58        mov edx, 53490000h;
  59        mov dl, _dl;
  60        mov ebx, 3f4b0000h;
  61        int 13h;
  62        mov _eax, eax;
  63        mov _ecx, ecx;
  64        mov _edx, edx;
  65        mov _ebx, ebx;
  66        mov _es, es;
  67        mov _di, di;
  68    }
  69
  70    if (_eax >> 16 != 0x4d21 ||
  71        _ecx >> 16 != 0x4d45 || _edx >> 16 != 0x4944 || _ebx >> 16 != 0x4b53)
  72        return NULL;
  73
  74    memset(&mm, 0, sizeof mm);
  75
  76    bytes = *(uint16_t far *) MK_FP(_es, _di);
  77
  78    /* 27 is the most we know how to handle */
  79    if (bytes > 27)
  80        bytes = 27;
  81
  82    _fmemcpy((void far *)&mm, (void far *)MK_FP(_es, _di), bytes);
  83
  84    mm.cylinders = ((_ecx >> 8) & 0xff) + ((_ecx & 0xc0) << 2) + 1;
  85    mm.heads = ((_edx >> 8) & 0xff) + 1;
  86    mm.sectors = (_ecx & 0x3f);
  87
  88    return &mm;
  89}
  90
  91const char *bootloadername(uint8_t id)
  92{
  93    static const struct {
  94        uint8_t id, mask;
  95        const char *name;
  96    } *lp, list[] = {
  97        {0x00, 0xf0, "LILO"}, 
  98        {0x10, 0xf0, "LOADLIN"},
  99        {0x31, 0xff, "SYSLINUX"},
 100        {0x32, 0xff, "PXELINUX"},
 101        {0x33, 0xff, "ISOLINUX"},
 102        {0x34, 0xff, "EXTLINUX"},
 103        {0x30, 0xf0, "SYSLINUX family"},
 104        {0x40, 0xf0, "Etherboot"},
 105        {0x50, 0xf0, "ELILO"},
 106        {0x70, 0xf0, "GrUB"},
 107        {0x80, 0xf0, "U-Boot"},
 108        {0xA0, 0xf0, "Gujin"},
 109        {0xB0, 0xf0, "Qemu"},
 110        {0x00, 0x00, "unknown"}
 111    };
 112
 113    for (lp = list;; lp++) {
 114        if (((id ^ lp->id) & lp->mask) == 0)
 115            return lp->name;
 116    }
 117}
 118
 119/* The function type for an output function */
 120#define OUTPUT_FUNC_DECL(x) \
 121void x(const int d, const struct memdiskinfo * const m)
 122typedef OUTPUT_FUNC_DECL((*output_func));
 123
 124/* Show MEMDISK information for the passed structure */
 125static OUTPUT_FUNC_DECL(normal_output)
 126{
 127    if (m == NULL)
 128        return;
 129    printf("Drive %02X is MEMDISK %u.%02u:\n"
 130           "\tAddress = 0x%08lx, len = %lu sectors, chs = %u/%u/%u,\n"
 131           "\tloader = 0x%02x (%s),\n"
 132           "\tcmdline = %Fs\n",
 133           d, m->mdi.version_major, m->mdi.version_minor,
 134           m->mdi.diskbuf, m->mdi.disksize, m->cylinders, m->heads, m->sectors,
 135           m->mdi.bootloaderid, bootloadername(m->mdi.bootloaderid),
 136           MK_FP(m->mdi.cmdline.seg_off.segment,
 137                 m->mdi.cmdline.seg_off.offset));
 138}
 139
 140/* Yield DOS SET command(s) as output for each MEMDISK kernel argument */
 141static OUTPUT_FUNC_DECL(batch_output)
 142{
 143    if (m != NULL) {
 144        char buf[256], *bc;
 145        const char far *c =
 146            MK_FP(m->mdi.cmdline.seg_off.segment,
 147                  m->mdi.cmdline.seg_off.offset);
 148        const char *have_equals, is_set[] = "=1";
 149
 150        while (*c != '\0') {
 151            /* Skip whitespace */
 152            while (isspace(*c))
 153                c++;
 154            if (*c == '\0')
 155                /* Trailing whitespace.  That's enough processing */
 156                break;
 157            /* Walk the kernel arguments while filling the buffer,
 158             * looking for space or NUL or checking for a full buffer
 159             */
 160            bc = buf;
 161            have_equals = is_set;
 162            while ((*c != '\0') && !isspace(*c) &&
 163                   (bc < &buf[sizeof(buf) - 1])) {
 164                /* Check if the param is "x=y" */
 165                if (*c == '=')
 166                    /* "=1" not needed */
 167                    have_equals = &is_set[sizeof(is_set) - 1];
 168                *bc = *c;
 169                c++;
 170                bc++;
 171            }
 172            /* Found the end of the parameter and optional value sequence */
 173            *bc = '\0';
 174            printf("set %s%s\n", buf, have_equals);
 175        }
 176    }
 177}
 178
 179/* We do not output batch file output by default.  We show MEMDISK info */
 180static output_func show_memdisk = normal_output;
 181
 182/* A generic function type */
 183#define MDISKCHK_FUNC_DECL(x) \
 184void x(void)
 185typedef MDISKCHK_FUNC_DECL((*mdiskchk_func));
 186
 187static MDISKCHK_FUNC_DECL(do_nothing)
 188{
 189    return;
 190}
 191
 192static MDISKCHK_FUNC_DECL(show_usage)
 193{
 194    printf("\nUsage: mdiskchk [--safe-hooks] [--mbfts] [--batch-output]\n"
 195           "\n"
 196           "Action: --safe-hooks . . Will scan INT 13h \"safe hook\" chain\n"
 197           "        --mbfts . . . .  Will scan memory for MEMDISK mBFTs\n"
 198           "        --batch-output . Will output SET command output based\n"
 199           "                         on MEMDISK kernel arguments\n"
 200           "        --no-sequential  Suppresses probing all drive numbers\n");
 201}
 202
 203/* Search memory for mBFTs and report them via the output method */
 204static MDISKCHK_FUNC_DECL(show_mbfts)
 205{
 206    const uint16_t far * const free_base_mem =
 207        MK_FP(0x0040, 0x0013);
 208    int seg;
 209    uint8_t chksum;
 210    uint32_t i;
 211    const struct mBFT far *mbft;
 212    struct memdiskinfo m;
 213    struct patch_area far *patch_area;
 214
 215    for (seg = *free_base_mem / 16; seg < 0x9FFF; seg++) {
 216        mbft = MK_FP(seg, 0);
 217        /* Check for signature */
 218        if (mbft->acpi.signature[0] != 'm' ||
 219            mbft->acpi.signature[1] != 'B' ||
 220            mbft->acpi.signature[2] != 'F' ||
 221            mbft->acpi.signature[3] != 'T')
 222            continue;
 223        if (mbft->acpi.length != sizeof(struct mBFT))
 224            continue;
 225        /* Check sum */
 226        chksum = 0;
 227        for (i = 0; i < sizeof(struct mBFT); i++)
 228            chksum += ((const uint8_t far *)mbft)[i];
 229        if (chksum)
 230            continue;
 231        /* Copy the MDI from the mBFT */
 232        _fmemcpy((void far *)&m, &mbft->mdi, sizeof(struct mdi));
 233        /* Adjust C/H/S since we actually know
 234         * it directly for any MEMDISK with an mBFT
 235         */
 236        patch_area = (struct patch_area far *)&mbft->mdi;
 237        m.cylinders = patch_area->cylinders;
 238        m.heads = patch_area->heads;
 239        m.sectors = patch_area->sectors;
 240        show_memdisk(patch_area->driveno, &m);
 241    }
 242}
 243
 244/* Walk the "safe hook" chain as far as possible
 245 * and report MEMDISKs that we find via the output method
 246 */
 247static MDISKCHK_FUNC_DECL(show_safe_hooks)
 248{
 249    const real_addr_t far * const int13 =
 250        MK_FP(0x0000, 0x0013 * sizeof(real_addr_t));
 251    const struct safe_hook far *hook =
 252        MK_FP(int13->seg_off.segment, int13->seg_off.offset);
 253
 254    while ((hook->signature[0] == '$') &&
 255           (hook->signature[1] == 'I') &&
 256           (hook->signature[2] == 'N') &&
 257           (hook->signature[3] == 'T') &&
 258           (hook->signature[4] == '1') &&
 259           (hook->signature[5] == '3') &&
 260           (hook->signature[6] == 'S') &&
 261           (hook->signature[7] == 'F')) {
 262        /* Found a valid "safe hook" */
 263        if ((hook->vendor[0] == 'M') &&
 264            (hook->vendor[1] == 'E') &&
 265            (hook->vendor[2] == 'M') &&
 266            (hook->vendor[3] == 'D') &&
 267            (hook->vendor[4] == 'I') &&
 268            (hook->vendor[5] == 'S') &&
 269            (hook->vendor[6] == 'K')) {
 270            /* Found a valid MEMDISK "safe hook".  It will have an mBFT */
 271            const struct mBFT far *mbft;
 272            struct memdiskinfo m;
 273            struct patch_area far *patch_area;
 274
 275            /* Copy the MDI from the mBFT.  Offset is a misnomer here */
 276            mbft = MK_FP(hook->mbft >> 4, 0);   /* Always aligned */
 277            _fmemcpy((void far *)&m, &mbft->mdi, sizeof(struct mdi));
 278            /* Adjust C/H/S since we actually know
 279             * it directly for any MEMDISK with an mBFT
 280             */
 281            patch_area = (struct patch_area far *)&mbft->mdi;
 282            m.cylinders = patch_area->cylinders;
 283            m.heads = patch_area->heads;
 284            m.sectors = patch_area->sectors;
 285            show_memdisk(patch_area->driveno, &m);
 286        } /* if */
 287        /* Step to the next hook in the "safe hook" chain */
 288        hook = MK_FP(hook->old_hook.seg_off.segment,
 289                     hook->old_hook.seg_off.offset);
 290    } /* while */
 291}
 292
 293int main(int argc, char *argv[])
 294{
 295    int d;
 296    int found = 0;
 297    int sequential_scan = 1;    /* Classic behaviour */
 298    const struct memdiskinfo *m;
 299
 300    /* Default behaviour */
 301    mdiskchk_func usage = do_nothing,
 302        safe_hooks = do_nothing,
 303        mbfts = do_nothing;
 304
 305    /* For each argument */
 306    while (--argc) {
 307        /* Argument should begin with one of these chars */
 308        if ((*argv[argc] != '/') && (*argv[argc] != '-')) {
 309            /* It doesn't.  Print usage soon */
 310            usage = show_usage;
 311            break;
 312        }
 313        argv[argc]++;
 314
 315        /* Next char might be '-' as in "--safe-hooks" */
 316        if (*argv[argc] == '-')
 317            argv[argc]++;
 318
 319        switch (*argv[argc]) {
 320            case 'S':
 321            case 's':
 322                safe_hooks = show_safe_hooks;
 323                break;
 324            case 'M':
 325            case 'm':
 326                mbfts = show_mbfts;
 327                break;
 328            case 'B':
 329            case 'b':
 330                show_memdisk = batch_output;
 331                break;
 332            case 'N':
 333            case 'n':
 334                sequential_scan = 0;
 335                break;
 336            default:
 337                usage = show_usage;
 338        } /* switch */
 339   } /* while */
 340
 341    safe_hooks();
 342    mbfts();
 343    if (!sequential_scan)
 344        goto skip_sequential;
 345    for (d = 0; d <= 0xff; d++) {
 346        m = query_memdisk(d);
 347        if (m != NULL) {
 348            found++;
 349            show_memdisk(d, m);
 350        }
 351    }
 352skip_sequential:
 353    usage();
 354
 355    return found;
 356}
 357
 358
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.