[syslinux] [PATCH] ifmemdsk.c32: Allow boot options based on presence of MEMDISK

Shao Miller Shao.Miller at yrdsb.edu.on.ca
Sat Aug 6 02:43:27 PDT 2011


Below, attached, and available at the 'ifmemdsk' branch at:

   
http://git.zytor.com/?p=users/sha0/syslinux.git;a=commitdiff;h=a975c12919bbd48739fede4ebfe099d98b87192e

Review welcome!

- Shao Miller

-----

 From a975c12919bbd48739fede4ebfe099d98b87192e Mon Sep 17 00:00:00 2001
From: Shao Miller <shao.miller at yrdsb.edu.on.ca>
Date: Sat, 6 Aug 2011 05:24:46 -0400
Subject: [PATCH] ifmemdsk.c32: Allow boot options based on presence of 
MEMDISK

Like 'ifcpu.c32' and 'ifplop.c32', this COMBOOT32 module will
check for the presence of MEMDISK(s) and choose one of two
(optionally) specified commands.

Signed-off-by: Shao Miller <shao.miller at yrdsb.edu.on.ca>
---
  NEWS                     |    1 +
  com32/modules/ifmemdsk.c |  389 
++++++++++++++++++++++++++++++++++++++++++++++
  2 files changed, 390 insertions(+), 0 deletions(-)
  create mode 100755 com32/modules/ifmemdsk.c

diff --git a/NEWS b/NEWS
index 88adba1..7700504 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ Changes in 4.05:
        on virtually all systems since the beginning, and has been
        totally broken since 4.00 at least.  Use MEMDISK instead.
      * chain.c32: Support chaining ReactOS' FreeLdr (Shao Miller)
+        * ifmemdsk.c32: Choose boot option based on presence of MEMDISK

  Changes in 4.04:
      * PXELINUX: Fix handling of unqualified DNS names.
diff --git a/com32/modules/ifmemdsk.c b/com32/modules/ifmemdsk.c
new file mode 100755
index 0000000..d36f5ec
--- /dev/null
+++ b/com32/modules/ifmemdsk.c
@@ -0,0 +1,389 @@
+/* 
----------------------------------------------------------------------- *
+ *
+ *   Copyright 2011 Shao Miller - All Rights Reserved
+ *
+ *   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., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * 
----------------------------------------------------------------------- */
+
+/****
+ * @file ifmemdsk.c
+ *
+ * This COM32 module detects if there are MEMDISKs established.
+ */
+
+static const char usage_text[] = "\
+Usage:\n\
+  ifmemdsk.c32 [<option> [...]] --info [<option> [...]]\n\
+  ifmemdsk.c32 [<option> [...]] [<detected_cmd>] -- [<not_detected_cmd>]\n\
+\n\
+Options:\n\
+  --info  . . . . . Displays info about MEMDISK(s)\n\
+  --safe-hooks . .  Will scan INT 13h \"safe hook\" chain\n\
+  --mbfts . . . . . Will scan memory for MEMDISK mBFTs\n\
+  --no-sequential   Suppresses probing all drive numbers\n\
+\n\
+If a MEMDISK is found, or if a particular MEMDISK is sought by the 
options\n\
+and is found, then the 'detected_cmd' action will be taken, else the\n\
+'not_detected_cmd' action will be taken.\n\
+\n";
+
+#include <stdio.h>
+#include <string.h>
+#include <alloca.h>
+#include <com32.h>
+#include <console.h>
+#include <syslinux/boot.h>
+
+/* Pull in MEMDISK common structures */
+#include "../../memdisk/mstructs.h"
+
+/*** Macros */
+#define M_GET_DRIVE_PARAMS (0x08)
+#define M_INT13H ((0x0000 << 4) + 0x0013 * 4)
+#define M_FREEBASEMEM ((0x0040 << 4) + 0x0013)
+#define M_TOP ((0x9FFF << 4) + 0x0000)
+
+/*** Object types */
+typedef struct mdi s_mdi;
+typedef real_addr_t u_segoff;
+typedef struct safe_hook s_safe_hook;
+typedef struct mBFT s_mbft;
+
+/*** Function types */
+typedef int f_find(void);
+
+/*** Function declarations */
+static const s_mdi * installation_check(int);
+static f_find scan_drives;
+static f_find walk_safe_hooks;
+static const s_safe_hook * is_safe_hook(const void *);
+static const s_mdi * is_memdisk_hook(const s_safe_hook *);
+static f_find scan_mbfts;
+static const s_mbft * is_mbft(const void *);
+static f_find do_nothing;
+static void memdisk_info(const s_mdi *);
+static void boot_args(char **);
+static const char * bootloadername(uint8_t);
+
+/*** Structure/union definitions */
+
+/*** Objects */
+static int show_info = 0;
+
+/*** Function definitions */
+
+int main(int argc, char ** argv) {
+    static f_find * do_scan_drives = scan_drives;
+    static f_find * do_walk_safe_hooks = do_nothing;
+    static f_find * do_scan_mbfts = do_nothing;
+    char ** detected_cmd;
+    char ** not_detected_cmd;
+    char ** cmd;
+    char ** cur_arg;
+    int show_usage;
+    int found;
+
+    (void) argc;
+
+    openconsole(&dev_null_r, &dev_stdcon_w);
+
+    detected_cmd = NULL;
+    not_detected_cmd = NULL;
+    show_usage = 1;
+    for (cur_arg = argv + 1; *cur_arg; ++cur_arg) {
+        /* Check for command divider */
+        if (!strcmp(*cur_arg, "--")) {
+            show_usage = 0;
+            *cur_arg = NULL;
+            not_detected_cmd = cur_arg + 1;
+            break;
+          }
+
+        /* Check for '--info' */
+        if (!strcmp(*cur_arg, "--info")) {
+            show_usage = 0;
+            show_info = 1;
+            continue;
+          }
+
+        if (!strcmp(*cur_arg, "--no-sequential")) {
+            do_scan_drives = do_nothing;
+            continue;
+          }
+
+        if (!strcmp(*cur_arg, "--safe-hooks")) {
+            do_walk_safe_hooks = walk_safe_hooks;
+            continue;
+          }
+
+        if (!strcmp(*cur_arg, "--mbfts")) {
+            do_scan_mbfts = scan_mbfts;
+            continue;
+          }
+
+        /* Check for invalid option */
+        if (!memcmp(*cur_arg, "--", sizeof "--" - 1)) {
+            puts("Invalid option!");
+            show_usage = 1;
+            break;
+          }
+
+        /* Set 'detected_cmd' if it's null */
+        if (!detected_cmd)
+          detected_cmd = cur_arg;
+
+        continue;
+      }
+
+    if (show_usage) {
+        fprintf(stderr, usage_text);
+        return 1;
+      }
+
+    found = 0;
+    found += do_walk_safe_hooks();
+    found += do_scan_mbfts();
+    found += do_scan_drives();
+
+    cmd = found ? detected_cmd : not_detected_cmd;
+    if (cmd)
+      boot_args(cmd);
+
+    return 0;
+  }
+
+static const s_mdi * installation_check(int drive) {
+    com32sys_t params, results;
+    int found;
+
+    /* Set parameters for INT 0x13 call */
+    memset(&params, 0, sizeof params);
+    params.eax.w[0] = M_GET_DRIVE_PARAMS << 8;
+    params.edx.w[0] = drive;
+    /* 'ME' 'MD' 'IS' 'K?' */
+    params.eax.w[1] = 0x454D;
+    params.ecx.w[1] = 0x444D;
+    params.edx.w[1] = 0x5349;
+    params.ebx.w[1] = 0x3F4B;
+
+    /* Perform the call */
+    __intcall(0x13, &params, &results);
+
+    /* Check result */
+    found = (
+        /* '!M' 'EM' 'DI' 'SK' */
+        results.eax.w[1] == 0x4D21 &&
+        results.ecx.w[1] == 0x4D45 &&
+        results.edx.w[1] == 0x4944 &&
+        results.ebx.w[1] == 0x4B53
+      );
+
+    if (found)
+      return MK_PTR(results.es, results.edi.w[0]);
+
+    return NULL;
+  }
+
+static int scan_drives(void) {
+    int found, drive;
+    const s_mdi * mdi;
+
+    for (found = drive = 0; drive <= 0xFF; ++drive) {
+        mdi = installation_check(drive);
+        if (!mdi)
+          continue;
+
+        memdisk_info(mdi);
+        ++found;
+        continue;
+      }
+
+    return found;
+  }
+
+static int walk_safe_hooks(void) {
+    static const u_segoff * const int13 = (void *) M_INT13H;
+    const void * addr;
+    int found;
+    const s_safe_hook * hook;
+    const s_mdi * mdi;
+
+    /* INT 0x13 vector */
+    addr = MK_PTR(int13->seg_off.segment, int13->seg_off.offset);
+    found = 0;
+    while ((hook = is_safe_hook(addr))) {
+        if ((mdi = is_memdisk_hook(hook))) {
+            memdisk_info(mdi);
+            ++found;
+          }
+
+        addr = MK_PTR(
+            hook->old_hook.seg_off.segment,
+            hook->old_hook.seg_off.offset
+          );
+        continue;
+      }
+    return found;
+  }
+
+static const s_safe_hook * is_safe_hook(const void * addr) {
+    static const char magic[] = "$INT13SF";
+    const s_safe_hook * test;
+
+    test = addr;
+    if (memcmp(test->signature, magic, sizeof magic - 1))
+      return NULL;
+
+    return addr;
+  }
+
+static const s_mdi * is_memdisk_hook(const s_safe_hook * hook) {
+    static const char magic[] = "MEMDISK";
+    const s_mbft * mbft;
+
+    if (memcmp(hook->vendor, magic, sizeof magic - 1))
+      return NULL;
+
+    /* An mBFT is always aligned */
+    mbft = MK_PTR(hook->mbft >> 4, 0);
+    return &mbft->mdi;
+  }
+
+static int scan_mbfts(void) {
+    static const uint16_t * const free_base_mem = (void *) M_FREEBASEMEM;
+    static const void * const top = (void *) M_TOP;
+    const void * addr;
+    const s_mbft * mbft;
+    int found;
+
+    addr = MK_PTR(*free_base_mem << 4, 0);
+    found = 0;
+    for (addr = MK_PTR(*free_base_mem << 4, 0); addr < top; addr += 1 
<< 4) {
+        if (!(mbft = is_mbft(addr)))
+          continue;
+
+        memdisk_info(&mbft->mdi);
+        ++found;
+        continue;
+      }
+
+    return found;
+  }
+
+static const s_mbft * is_mbft(const void * addr) {
+    static const char magic[] = "mBFT";
+    const s_mbft * const test = addr;
+
+    if (memcmp(test->acpi.signature, magic, sizeof magic - 1))
+      return NULL;
+
+    if (test->acpi.length != sizeof *test)
+      return NULL;
+
+    {   const uint8_t * const end = (void *) (test + 1);
+        const uint8_t * ptr;
+        uint8_t chksum;
+
+        chksum = 0;
+        for (ptr = addr; ptr < end; ++ptr)
+          chksum += *ptr;
+        if (chksum)
+          return NULL;
+      }
+
+    /* Looks like it's a mBFT! */
+    return test;
+  }
+
+static int do_nothing(void) {
+    return 0;
+  }
+
+static void memdisk_info(const s_mdi * mdi) {
+    const char * cmdline;
+
+    if (!show_info)
+      return;
+
+    cmdline = MK_PTR(
+        mdi->cmdline.seg_off.segment,
+        mdi->cmdline.seg_off.offset
+      );
+    printf(
+        "Found MEMDISK version %u.%02u:\n"
+        "  diskbuf == 0x%08X, disksize == %u sectors\n"
+        "  bootloaderid == 0x%02X (%s),\n"
+        "  cmdline: %s\n",
+        mdi->version_major,
+        mdi->version_minor,
+        mdi->diskbuf,
+        mdi->disksize,
+        mdi->bootloaderid,
+        bootloadername(mdi->bootloaderid),
+        cmdline
+      );
+    return;
+  }
+
+/* This function copyright H. Peter Anvin */
+static void boot_args(char **args)
+{
+    int len = 0, a = 0;
+    char **pp;
+    const char *p;
+    char c, *q, *str;
+
+    for (pp = args; *pp; pp++)
+    len += strlen(*pp) + 1;
+
+    q = str = alloca(len);
+    for (pp = args; *pp; pp++) {
+    p = *pp;
+    while ((c = *p++))
+        *q++ = c;
+    *q++ = ' ';
+    a = 1;
+    }
+    q -= a;
+    *q = '\0';
+
+    if (!str[0])
+    syslinux_run_default();
+    else
+    syslinux_run_command(str);
+}
+
+/* This function copyright H. Peter Anvin */
+static 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;
+    }
+}
+
-- 
1.6.0.4


-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: 0001-ifmemdsk.c32-Allow-boot-options-based-on-presence-o.patch
URL: <http://www.zytor.com/pipermail/syslinux/attachments/20110806/6cc11219/attachment.ksh>


More information about the Syslinux mailing list