mdiskchk: Support three new features
authorShao Miller <shao.miller@yrdsb.edu.on.ca>
Tue, 9 Mar 2010 23:33:35 +0000 (18:33 -0500)
committerShao Miller <sha0@terminus.zytor.com>
Fri, 11 Jun 2010 05:08:41 +0000 (22:08 -0700)
MDISKCHK.COM now supports three new modes:

mdiskchk.com --mbfts
  This mode will scan between free base memory and
  0xA00000 looking for MEMDISK mBFTs.  For each one
  found, its detail will be reported.

mdiskchk.com --safe-hooks
  This mode will attempt to walk the chain of INT 13h
  "safe hooks".  For each MEMDISK "safe hook" found,
  its detail will be reported.

mdiskchk.com --batch-output
  This mode suppresses the normal detail report and
  instead outputs a list of DOS SET commands.  This
  is useful if one wishes to populate a batch file
  and call that batch file to set DOS environment
  variables, so that programs have access to those
  MEMDISK kernel arguments passed at boot-time.

These command-line options may be combined.

For example, your AUTOEXEC.BAT might go:
  @echo off
  echo @echo off>setenv.bat
  mdiskchk.com -m -s -b>>setenv.bat
  call setenv.bat>nul

Signed-off-by: Shao Miller <shao.miller@yrdsb.edu.on.ca>
dosutil/mdiskchk.c
dosutil/mdiskchk.com

index 42aa511..ddc5763 100644 (file)
@@ -1,6 +1,7 @@
 /* -*- 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
@@ -21,6 +22,7 @@
  * wcl -3 -osx -mt mdiskchk.c
  */
 
+#include <ctype.h>
 #include <stdio.h>
 #include <string.h>
 #include <i86.h>               /* For MK_FP() */
@@ -29,18 +31,15 @@ typedef unsigned long uint32_t;
 typedef unsigned short uint16_t;
 typedef unsigned char uint8_t;
 
+/* OpenWatcom uses a packed structure prefix */
+#define MEMDISK_PACKED_PREFIX _Packed
+#define MEMDISK_PACKED_POSTFIX
+
+/* Pull in MEMDISK common structures */
+#include "../memdisk/mstructs.h"
+
 struct memdiskinfo {
-    uint16_t bytes;            /* Bytes from memdisk */
-    uint16_t version;          /* Memdisk version */
-    uint32_t base;             /* Base of disk in high memory */
-    uint32_t size;             /* Size of disk in sectors */
-    char far *cmdline;         /* Command line */
-    void far *oldint13;                /* Old INT 13h */
-    void far *oldint15;                /* Old INT 15h */
-    uint16_t olddosmem;
-    uint8_t bootloaderid;
-
-    uint8_t _pad;
+    struct mdi mdi;
 
     /* We add our own fields at the end */
     int cylinders;
@@ -121,25 +120,233 @@ const char *bootloadername(uint8_t id)
     }
 }
 
+/* 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");
+}
+
+/* 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.offset >> 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;
-    struct memdiskinfo *m;
+    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;
+           default:
+               usage = show_usage;
+       } /* switch */
+   } /* while */
+
+    safe_hooks();
+    mbfts();
     for (d = 0; d <= 0xff; d++) {
-       if ((m = query_memdisk(d)) != NULL) {
-           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->version >> 8, m->version & 0xff,
-                  m->base, m->size, m->cylinders, m->heads, m->sectors,
-                  m->bootloaderid, bootloadername(m->bootloaderid),
-                  m->cmdline);
+       m = query_memdisk(d);
+       if (m != NULL) {
            found++;
+           show_memdisk(d, m);
        }
     }
+    usage();
 
     return found;
 }
+
index 7825751..5a6cc8e 100644 (file)
Binary files a/dosutil/mdiskchk.com and b/dosutil/mdiskchk.com differ