aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFeng Tang <feng.tang@intel.com>2010-07-14 11:08:06 +0800
committerFeng Tang <feng.tang@intel.com>2010-07-20 11:10:04 +0800
commitff6ef23ed4e8459dbe6e97d0a016e8f89f5da258 (patch)
tree05dfeec6bf56aff95159d4e9dde2dbd267dc1a2a
parent3400a8754214f4cd69d49d85c0396665d7a6415f (diff)
downloadsyslinux-ff6ef23ed4e8459dbe6e97d0a016e8f89f5da258.tar.gz
syslinux-ff6ef23ed4e8459dbe6e97d0a016e8f89f5da258.tar.xz
syslinux-ff6ef23ed4e8459dbe6e97d0a016e8f89f5da258.zip
elflink: add new files
new file: com32/include/getopt.h new file: com32/include/ilog2.h new file: com32/lib/getopt_long.c new file: com32/lib/sys/sleep.c new file: com32/sysdump/acpi.c new file: com32/sysdump/be_srec.c new file: com32/sysdump/rbtree.c new file: com32/sysdump/rbtree.h new file: dos/getsetsl.c new file: dos/memmove.S new file: libinstaller/advio.c new file: libinstaller/fat.c new file: libinstaller/linuxioctl.h new file: memdisk/compiler.h new file: memdisk/mstructs.h new file: utils/memdiskfind.c
-rw-r--r--com32/include/getopt.h22
-rw-r--r--com32/include/ilog2.h48
-rw-r--r--com32/lib/getopt_long.c152
-rw-r--r--com32/lib/sys/sleep.c22
-rw-r--r--com32/sysdump/acpi.c259
-rw-r--r--com32/sysdump/be_srec.c85
-rw-r--r--com32/sysdump/rbtree.c132
-rw-r--r--com32/sysdump/rbtree.h53
-rw-r--r--dos/getsetsl.c100
-rw-r--r--dos/memmove.S36
-rw-r--r--libinstaller/advio.c162
-rw-r--r--libinstaller/fat.c129
-rw-r--r--libinstaller/linuxioctl.h47
-rw-r--r--memdisk/compiler.h9
-rw-r--r--memdisk/mstructs.h178
-rw-r--r--utils/memdiskfind.c158
16 files changed, 1592 insertions, 0 deletions
diff --git a/com32/include/getopt.h b/com32/include/getopt.h
new file mode 100644
index 00000000..71c41cd9
--- /dev/null
+++ b/com32/include/getopt.h
@@ -0,0 +1,22 @@
+#ifndef _GETOPT_H
+#define _GETOPT_H
+
+#include <klibc/extern.h>
+
+struct option {
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+enum {
+ no_argument = 0,
+ required_argument = 1,
+ optional_argument = 2,
+};
+
+__extern int getopt_long(int, char *const *, const char *,
+ const struct option *, int *);
+
+#endif /* _GETOPT_H */
diff --git a/com32/include/ilog2.h b/com32/include/ilog2.h
new file mode 100644
index 00000000..91a50576
--- /dev/null
+++ b/com32/include/ilog2.h
@@ -0,0 +1,48 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef _ILOG2_H
+#define _ILOG2_H
+
+/*
+ * Computes floor(log2(x)) -- undefined for x = 0.
+ */
+
+#include <klibc/compiler.h>
+#include <stdint.h>
+
+static inline __constfunc uint32_t ilog2(uint32_t __v)
+{
+# if __GNUC__ >= 4
+ return __builtin_clz(__v) ^ 31;
+# else
+ asm("bsrl %1,%0" : "=r" (__v) : "rm" (__v));
+ return __v;
+# endif
+}
+
+#endif /* _ILOG2_H */
diff --git a/com32/lib/getopt_long.c b/com32/lib/getopt_long.c
new file mode 100644
index 00000000..e3d064b0
--- /dev/null
+++ b/com32/lib/getopt_long.c
@@ -0,0 +1,152 @@
+/*
+ * getopt.c
+ *
+ * getopt_long(), or at least a common subset thereof:
+ *
+ * - Option reordering is not supported
+ * - -W foo is not supported
+ * - First optstring character "-" not supported.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+char *optarg;
+int optind, opterr, optopt;
+static struct getopt_private_state {
+ const char *optptr;
+ const char *last_optstring;
+ char *const *last_argv;
+} pvt;
+
+static inline const char *option_matches(const char *arg_str,
+ const char *opt_name)
+{
+ while (*arg_str != '\0' && *arg_str != '=') {
+ if (*arg_str++ != *opt_name++)
+ return NULL;
+ }
+
+ if (*opt_name)
+ return NULL;
+
+ return arg_str;
+}
+
+int getopt_long(int argc, char *const *argv, const char *optstring,
+ const struct option *longopts, int *longindex)
+{
+ const char *carg;
+ const char *osptr;
+ int opt;
+
+ /* getopt() relies on a number of different global state
+ variables, which can make this really confusing if there is
+ more than one use of getopt() in the same program. This
+ attempts to detect that situation by detecting if the
+ "optstring" or "argv" argument have changed since last time
+ we were called; if so, reinitialize the query state. */
+
+ if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
+ optind < 1 || optind > argc) {
+ /* optind doesn't match the current query */
+ pvt.last_optstring = optstring;
+ pvt.last_argv = argv;
+ optind = 1;
+ pvt.optptr = NULL;
+ }
+
+ carg = argv[optind];
+
+ /* First, eliminate all non-option cases */
+
+ if (!carg || carg[0] != '-' || !carg[1])
+ return -1;
+
+ if (carg[1] == '-') {
+ const struct option *lo;
+ const char *opt_end = NULL;
+
+ optind++;
+
+ /* Either it's a long option, or it's -- */
+ if (!carg[2]) {
+ /* It's -- */
+ return -1;
+ }
+
+ for (lo = longopts; lo->name; lo++) {
+ if ((opt_end = option_matches(carg+2, lo->name)))
+ break;
+ }
+ if (!opt_end)
+ return '?';
+
+ if (longindex)
+ *longindex = lo-longopts;
+
+ if (*opt_end == '=') {
+ if (lo->has_arg)
+ optarg = (char *)opt_end+1;
+ else
+ return '?';
+ } else if (lo->has_arg == 1) {
+ if (!(optarg = argv[optind]))
+ return '?';
+ optind++;
+ }
+
+ if (lo->flag) {
+ *lo->flag = lo->val;
+ return 0;
+ } else {
+ return lo->val;
+ }
+ }
+
+ if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
+ /* Someone frobbed optind, change to new opt. */
+ pvt.optptr = carg + 1;
+ }
+
+ opt = *pvt.optptr++;
+
+ if (opt != ':' && (osptr = strchr(optstring, opt))) {
+ if (osptr[1] == ':') {
+ if (*pvt.optptr) {
+ /* Argument-taking option with attached
+ argument */
+ optarg = (char *)pvt.optptr;
+ optind++;
+ } else {
+ /* Argument-taking option with non-attached
+ argument */
+ if (argv[optind + 1]) {
+ optarg = (char *)argv[optind+1];
+ optind += 2;
+ } else {
+ /* Missing argument */
+ optind++;
+ return (optstring[0] == ':')
+ ? ':' : '?';
+ }
+ }
+ return opt;
+ } else {
+ /* Non-argument-taking option */
+ /* pvt.optptr will remember the exact position to
+ resume at */
+ if (!*pvt.optptr)
+ optind++;
+ return opt;
+ }
+ } else {
+ /* Unknown option */
+ optopt = opt;
+ if (!*pvt.optptr)
+ optind++;
+ return '?';
+ }
+}
diff --git a/com32/lib/sys/sleep.c b/com32/lib/sys/sleep.c
new file mode 100644
index 00000000..8a51c1c0
--- /dev/null
+++ b/com32/lib/sys/sleep.c
@@ -0,0 +1,22 @@
+/*
+ * sys/sleep.c
+ */
+
+#include <unistd.h>
+#include <sys/times.h>
+#include <syslinux/idle.h>
+
+unsigned int msleep(unsigned int msec)
+{
+ clock_t start = times(NULL);
+
+ while (times(NULL) - start < msec)
+ syslinux_idle();
+
+ return 0;
+}
+
+unsigned int sleep(unsigned int seconds)
+{
+ return msleep(seconds * 1000);
+}
diff --git a/com32/sysdump/acpi.c b/com32/sysdump/acpi.c
new file mode 100644
index 00000000..8671fc8a
--- /dev/null
+++ b/com32/sysdump/acpi.c
@@ -0,0 +1,259 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Dump ACPI information
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "sysdump.h"
+#include "backend.h"
+#include "rbtree.h"
+
+struct acpi_rsdp {
+ uint8_t magic[8]; /* "RSD PTR " */
+ uint8_t csum;
+ char oemid[6];
+ uint8_t rev;
+ uint32_t rsdt_addr;
+ uint32_t len;
+ uint64_t xsdt_addr;
+ uint8_t xcsum;
+ uint8_t rsvd[3];
+};
+
+struct acpi_hdr {
+ char sig[4]; /* Signature */
+ uint32_t len;
+ uint8_t rev;
+ uint8_t csum;
+ char oemid[6];
+ char oemtblid[16];
+ uint32_t oemrev;
+ uint32_t creatorid;
+ uint32_t creatorrev;
+};
+
+struct acpi_rsdt {
+ struct acpi_hdr hdr;
+ uint32_t entry[0];
+};
+
+struct acpi_xsdt {
+ struct acpi_hdr hdr;
+ uint64_t entry[0];
+};
+
+static struct rbtree *rb_types, *rb_addrs;
+
+static bool rb_has(struct rbtree **tree, uint64_t key)
+{
+ struct rbtree *node;
+
+ node = rb_search(*tree, key);
+ if (node && node->key == key)
+ return true;
+
+ node = malloc(sizeof *node);
+ if (node) {
+ node->key = key;
+ *tree = rb_insert(*tree, node);
+ }
+ return false;
+}
+
+static inline bool addr_ok(uint64_t addr)
+{
+ /* We can only handle 32-bit addresses for now... */
+ return addr <= 0xffffffff;
+}
+
+enum tbl_errs {
+ ERR_NONE, /* No errors */
+ ERR_CSUM, /* Invalid checksum */
+ ERR_SIZE, /* Impossibly large table */
+ ERR_NOSIG /* No signature */
+};
+
+static uint8_t checksum_range(const void *start, uint32_t size)
+{
+ const uint8_t *p = start;
+ uint8_t csum = 0;
+
+ while (size--)
+ csum += *p++;
+
+ return csum;
+}
+
+static enum tbl_errs is_valid_table(const void *ptr)
+{
+ const struct acpi_hdr *hdr = ptr;
+
+ if (hdr->sig[0] == 0)
+ return ERR_NOSIG;
+
+ if (hdr->len < 10 || hdr->len > (1 << 20)) {
+ /* Either insane or too large to dump */
+ return ERR_SIZE;
+ }
+
+ return checksum_range(hdr, hdr->len) == 0 ? ERR_NONE : ERR_CSUM;
+}
+
+static const struct acpi_rsdp *scan_for_rsdp(uint32_t base, uint32_t end)
+{
+ for (base &= ~15; base < end-20; base += 16) {
+ const struct acpi_rsdp *rsdp = (const struct acpi_rsdp *)base;
+
+ if (memcmp(rsdp->magic, "RSD PTR ", 8))
+ continue;
+
+ if (checksum_range(rsdp, 20))
+ continue;
+
+ if (rsdp->rev > 0) {
+ if (base + rsdp->len >= end ||
+ checksum_range(rsdp, rsdp->len))
+ continue;
+ }
+
+ return rsdp;
+ }
+
+ return NULL;
+}
+
+static const struct acpi_rsdp *find_rsdp(void)
+{
+ uint32_t ebda;
+ const struct acpi_rsdp *rsdp;
+
+ ebda = (*(uint16_t *)0x40e) << 4;
+ if (ebda >= 0x70000 && ebda < 0xa0000) {
+ rsdp = scan_for_rsdp(ebda, ebda+1024);
+
+ if (rsdp)
+ return rsdp;
+ }
+
+ return scan_for_rsdp(0xe0000, 0x100000);
+}
+
+static void dump_table(struct backend *be,
+ const char name[], const void *ptr, uint32_t len)
+{
+ char namebuf[64];
+ uint32_t name_key = *(uint32_t *)name;
+
+ if (rb_has(&rb_addrs, (size_t)ptr))
+ return; /* Already dumped this table */
+
+ if (!rb_has(&rb_types, name_key)) {
+ snprintf(namebuf, sizeof namebuf, "acpi/%4.4s", name);
+ cpio_mkdir(be, namebuf);
+ }
+
+ snprintf(namebuf, sizeof namebuf, "acpi/%4.4s/%08x", name, (uint32_t)ptr);
+ cpio_hdr(be, MODE_FILE, len, namebuf);
+
+ write_data(be, ptr, len);
+}
+
+static void dump_rsdt(struct backend *be, const struct acpi_rsdp *rsdp)
+{
+ const struct acpi_rsdt *rsdt;
+ uint32_t i, n;
+
+ rsdt = (const struct acpi_rsdt *)rsdp->rsdt_addr;
+
+ if (memcmp(rsdt->hdr.sig, "RSDT", 4) || is_valid_table(rsdt) > ERR_CSUM)
+ return;
+
+ dump_table(be, rsdt->hdr.sig, rsdt, rsdt->hdr.len);
+
+ if (rsdt->hdr.len < 36)
+ return;
+
+ n = (rsdt->hdr.len - 36) >> 2;
+
+ for (i = 0; i < n; i++) {
+ const struct acpi_hdr *hdr = (const struct acpi_hdr *)(rsdt->entry[i]);
+
+ if (is_valid_table(hdr) <= ERR_CSUM)
+ dump_table(be, hdr->sig, hdr, hdr->len);
+ }
+}
+
+static void dump_xsdt(struct backend *be, const struct acpi_rsdp *rsdp)
+{
+ const struct acpi_xsdt *xsdt;
+ uint32_t rsdp_len = rsdp->rev > 0 ? rsdp->len : 20;
+ uint32_t i, n;
+
+ if (rsdp_len < 34)
+ return;
+
+ if (!addr_ok(rsdp->xsdt_addr))
+ return;
+
+ xsdt = (const struct acpi_xsdt *)(size_t)rsdp->xsdt_addr;
+
+ if (memcmp(xsdt->hdr.sig, "XSDT", 4) || is_valid_table(xsdt) > ERR_CSUM)
+ return;
+
+ dump_table(be, xsdt->hdr.sig, xsdt, xsdt->hdr.len);
+
+ if (xsdt->hdr.len < 36)
+ return;
+
+ n = (xsdt->hdr.len - 36) >> 3;
+
+ for (i = 0; i < n; i++) {
+ const struct acpi_hdr *hdr;
+ if (addr_ok(xsdt->entry[i])) {
+ hdr = (const struct acpi_hdr *)(size_t)(xsdt->entry[i]);
+
+ if (is_valid_table(hdr) <= ERR_CSUM)
+ dump_table(be, hdr->sig, hdr, hdr->len);
+ }
+ }
+}
+
+void dump_acpi(struct backend *be)
+{
+ const struct acpi_rsdp *rsdp;
+ uint32_t rsdp_len;
+
+ rsdp = find_rsdp();
+
+ printf("Dumping ACPI... ");
+
+ if (!rsdp)
+ return; /* No ACPI information found */
+
+ cpio_mkdir(be, "acpi");
+
+ rsdp_len = rsdp->rev > 0 ? rsdp->len : 20;
+
+ dump_table(be, "RSDP", rsdp, rsdp_len);
+
+ dump_rsdt(be, rsdp);
+ dump_xsdt(be, rsdp);
+
+ rb_destroy(rb_types);
+ rb_destroy(rb_addrs);
+
+ printf("done.\n");
+}
diff --git a/com32/sysdump/be_srec.c b/com32/sysdump/be_srec.c
new file mode 100644
index 00000000..fc69c886
--- /dev/null
+++ b/com32/sysdump/be_srec.c
@@ -0,0 +1,85 @@
+/*
+ * S-records dump routine -- dumps S-records on the console
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <minmax.h>
+#include "backend.h"
+
+/* Write a single S-record */
+static int write_srecord(unsigned int len, unsigned int alen,
+ uint32_t addr, uint8_t type, const void *data)
+{
+ char buf[2+2+8+255*2+2+2];
+ char *p = buf;
+ uint8_t csum;
+ const uint8_t *dptr = data;
+ unsigned int i;
+
+ switch (alen) {
+ case 2:
+ addr &= 0xffff;
+ break;
+ case 3:
+ addr &= 0xffffff;
+ break;
+ case 4:
+ break;
+ }
+
+ csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24);
+ for (i = 0; i < len; i++)
+ csum += dptr[i];
+ csum = 0xff-csum;
+
+ p += sprintf(p, "S%c%02X%0*X", type, len+alen+1, alen*2, addr);
+ for (i = 0; i < len; i++)
+ p += sprintf(p, "%02X", dptr[i]);
+ p += sprintf(p, "%02X\n", csum);
+
+ fputs(buf, stdout);
+ return 0;
+}
+
+static int be_srec_write(struct backend *be)
+{
+ char name[33];
+ const char *buf;
+ size_t len, chunk, offset, hdrlen;
+
+ buf = be->outbuf;
+ len = be->zbytes;
+
+ putchar('\n');
+
+ hdrlen = snprintf(name, sizeof name, "%.32s",
+ be->argv[0] ? be->argv[0] : "");
+
+ /* Write head record */
+ write_srecord(hdrlen, 2, 0, '0', name);
+
+ /* Write data records */
+ offset = 0;
+ while (len) {
+ chunk = min(len, (size_t)32);
+
+ write_srecord(chunk, 4, offset, '3', buf);
+ buf += chunk;
+ len -= chunk;
+ offset += chunk;
+ }
+
+ /* Write termination record */
+ write_srecord(0, 4, 0, '7', NULL);
+
+ return 0;
+}
+
+struct backend be_srec = {
+ .name = "srec",
+ .helpmsg = "[filename]",
+ .minargs = 0,
+ .write = be_srec_write,
+};
diff --git a/com32/sysdump/rbtree.c b/com32/sysdump/rbtree.c
new file mode 100644
index 00000000..1d10e098
--- /dev/null
+++ b/com32/sysdump/rbtree.c
@@ -0,0 +1,132 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2009 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * rbtree.c
+ *
+ * Simple implementation of a left-leaning red-black tree with 64-bit
+ * integer keys. The search operation will return the highest node <=
+ * the key; only search and insert are supported, but additional
+ * standard llrbtree operations can be coded up at will.
+ *
+ * See http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf for
+ * information about left-leaning red-black trees.
+ */
+
+#include <stdlib.h>
+#include "rbtree.h"
+
+struct rbtree *rb_search(struct rbtree *tree, uint64_t key)
+{
+ struct rbtree *best = NULL;
+
+ while (tree) {
+ if (tree->key == key)
+ return tree;
+ else if (tree->key > key)
+ tree = tree->left;
+ else {
+ best = tree;
+ tree = tree->right;
+ }
+ }
+ return best;
+}
+
+static bool is_red(struct rbtree *h)
+{
+ return h && h->red;
+}
+
+static struct rbtree *rotate_left(struct rbtree *h)
+{
+ struct rbtree *x = h->right;
+ h->right = x->left;
+ x->left = h;
+ x->red = x->left->red;
+ x->left->red = true;
+ return x;
+}
+
+static struct rbtree *rotate_right(struct rbtree *h)
+{
+ struct rbtree *x = h->left;
+ h->left = x->right;
+ x->right = h;
+ x->red = x->right->red;
+ x->right->red = true;
+ return x;
+}
+
+static void color_flip(struct rbtree *h)
+{
+ h->red = !h->red;
+ h->left->red = !h->left->red;
+ h->right->red = !h->right->red;
+}
+
+struct rbtree *rb_insert(struct rbtree *tree, struct rbtree *node)
+{
+ node->left = node->right = NULL;
+ node->red = false;
+
+ if (!tree) {
+ node->red = true;
+ return node;
+ }
+
+ if (is_red(tree->left) && is_red(tree->right))
+ color_flip(tree);
+
+ if (node->key < tree->key)
+ tree->left = rb_insert(tree->left, node);
+ else
+ tree->right = rb_insert(tree->right, node);
+
+ if (is_red(tree->right))
+ tree = rotate_left(tree);
+
+ if (is_red(tree->left) && is_red(tree->left->left))
+ tree = rotate_right(tree);
+
+ return tree;
+}
+
+void rb_destroy(struct rbtree *tree)
+{
+ if (tree->left)
+ rb_destroy(tree->left);
+ if (tree->right)
+ rb_destroy(tree->right);
+ free(tree);
+}
diff --git a/com32/sysdump/rbtree.h b/com32/sysdump/rbtree.h
new file mode 100644
index 00000000..dcdcd6ba
--- /dev/null
+++ b/com32/sysdump/rbtree.h
@@ -0,0 +1,53 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2009 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef NASM_RBTREE_H
+#define NASM_RBTREE_H
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+/* This structure should be embedded in a larger data structure;
+ the final output from rb_search() can then be converted back
+ to the larger data structure via container_of(). */
+struct rbtree {
+ uint64_t key;
+ struct rbtree *left, *right;
+ bool red;
+};
+
+struct rbtree *rb_insert(struct rbtree *, struct rbtree *);
+struct rbtree *rb_search(struct rbtree *, uint64_t);
+void rb_destroy(struct rbtree *);
+
+#endif /* NASM_RBTREE_H */
diff --git a/dos/getsetsl.c b/dos/getsetsl.c
new file mode 100644
index 00000000..a48f3df2
--- /dev/null
+++ b/dos/getsetsl.c
@@ -0,0 +1,100 @@
+/*
+ * Special handling for the MS-DOS derivative: syslinux_ldlinux
+ * is a "far" object...
+ */
+
+#define _XOPEN_SOURCE 500 /* Required on glibc 2.x */
+#define _BSD_SOURCE
+#include <inttypes.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "syslxint.h"
+
+#define __noinline __attribute__((noinline))
+
+#if 0 /* unused */
+uint8_t get_8_sl(const uint8_t * p)
+{
+ uint8_t v;
+
+ p = set_fs(p);
+ asm volatile("movb %%fs:%1,%0":"=q" (v):"m"(*p));
+ return v;
+}
+#endif
+
+uint16_t get_16_sl(const uint16_t * p)
+{
+ uint16_t v;
+
+ p = set_fs(p);
+ asm volatile("movw %%fs:%1,%0":"=r" (v):"m"(*p));
+ return v;
+}
+
+uint32_t get_32_sl(const uint32_t * p)
+{
+ uint32_t v;
+
+ p = set_fs(p);
+ asm volatile("movl %%fs:%1,%0":"=r" (v):"m"(*p));
+ return v;
+}
+
+#if 0 /* unused */
+uint64_t get_64_sl(const uint64_t * p)
+{
+ uint32_t v0, v1;
+ const uint32_t *pp = (const uint32_t *)set_fs(p);
+
+ asm volatile("movl %%fs:%1,%0" : "=r" (v0) : "m" (pp[0]));
+ asm volatile("movl %%fs:%1,%0" : "=r" (v1) : "m" (pp[1]));
+ return v0 + ((uint64_t)v1 << 32);
+}
+#endif
+
+#if 0 /* unused */
+void set_8_sl(uint8_t * p, uint8_t v)
+{
+ p = set_fs(p);
+ asm volatile("movb %1,%%fs:%0":"=m" (*p):"qi"(v));
+}
+#endif
+
+void set_16_sl(uint16_t * p, uint16_t v)
+{
+ p = set_fs(p);
+ asm volatile("movw %1,%%fs:%0":"=m" (*p):"ri"(v));
+}
+
+void set_32_sl(uint32_t * p, uint32_t v)
+{
+ p = set_fs(p);
+ asm volatile("movl %1,%%fs:%0":"=m" (*p):"ri"(v));
+}
+
+void set_64_sl(uint64_t * p, uint64_t v)
+{
+ uint32_t *pp = (uint32_t *)set_fs(p);
+ asm volatile("movl %1,%%fs:%0" : "=m" (pp[0]) : "ri"((uint32_t)v));
+ asm volatile("movl %1,%%fs:%0" : "=m" (pp[1]) : "ri"((uint32_t)(v >> 32)));
+}
+
+void memcpy_to_sl(void *dst, const void *src, size_t len)
+{
+ uint16_t seg;
+ uint16_t off;
+
+ seg = ldlinux_seg + ((size_t)dst >> 4);
+ off = (size_t)dst & 15;
+
+ asm volatile("pushw %%es ; "
+ "movw %3,%%es ; "
+ "rep ; movsb ; "
+ "popw %%es"
+ : "+D" (off), "+S" (src), "+c" (len)
+ : "r" (seg)
+ : "memory");
+}
diff --git a/dos/memmove.S b/dos/memmove.S
new file mode 100644
index 00000000..1ab2cb23
--- /dev/null
+++ b/dos/memmove.S
@@ -0,0 +1,36 @@
+#
+# memmove.S
+#
+# Simple 16-bit memmove() implementation
+#
+
+ .text
+ .code16gcc
+ .globl memmove
+ .type memmove, @function
+memmove:
+ pushw %di
+ pushw %si
+ movw %ax,%di
+ movw %dx,%si
+ cmpw %si,%di
+ ja 1f
+ # The third argument is already in cx
+ cld
+ rep ; movsb
+2:
+ popw %si
+ popw %di
+ ret
+
+1: /* si <= di, need reverse copy */
+ add %cx,%di
+ add %cx,%si
+ dec %di
+ dec %si
+ std
+ rep ; movsb
+ cld
+ jmp 2b
+
+ .size memmove,.-memmove
diff --git a/libinstaller/advio.c b/libinstaller/advio.c
new file mode 100644
index 00000000..56f607d0
--- /dev/null
+++ b/libinstaller/advio.c
@@ -0,0 +1,162 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * advio.c
+ *
+ * Linux ADV I/O
+ *
+ * Return 0 on success, -1 on error, and set errno.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "syslxint.h"
+#include "syslxcom.h"
+
+/*
+ * Read the ADV from an existing instance, or initialize if invalid.
+ * Returns -1 on fatal errors, 0 if ADV is okay, 1 if the ADV is
+ * invalid, and 2 if the file does not exist.
+ */
+int read_adv(const char *path, const char *cfg)
+{
+ char *file;
+ int fd = -1;
+ struct stat st;
+ int err = 0;
+ int rv;
+
+ rv = asprintf(&file, "%s%s%s", path,
+ path[0] && path[strlen(path) - 1] == '/' ? "" : "/", cfg);
+
+ if (rv < 0 || !file) {
+ perror(program);
+ return -1;
+ }
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ if (errno != ENOENT) {
+ err = -1;
+ } else {
+ syslinux_reset_adv(syslinux_adv);
+ err = 2; /* Nonexistence is not a fatal error */
+ }
+ } else if (fstat(fd, &st)) {
+ err = -1;
+ } else if (st.st_size < 2 * ADV_SIZE) {
+ /* Too small to be useful */
+ syslinux_reset_adv(syslinux_adv);
+ err = 0; /* Nothing to read... */
+ } else if (xpread(fd, syslinux_adv, 2 * ADV_SIZE,
+ st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
+ err = -1;
+ } else {
+ /* We got it... maybe? */
+ err = syslinux_validate_adv(syslinux_adv) ? 1 : 0;
+ }
+
+ if (err < 0)
+ perror(file);
+
+ if (fd >= 0)
+ close(fd);
+
+ free(file);
+
+ return err;
+}
+
+/*
+ * Update the ADV in an existing installation.
+ */
+int write_adv(const char *path, const char *cfg)
+{
+ unsigned char advtmp[2 * ADV_SIZE];
+ char *file;
+ int fd = -1;
+ struct stat st, xst;
+ int err = 0;
+ int rv;
+
+ rv = asprintf(&file, "%s%s%s", path,
+ path[0] && path[strlen(path) - 1] == '/' ? "" : "/", cfg);
+
+ if (rv < 0 || !file) {
+ perror(program);
+ return -1;
+ }
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ err = -1;
+ } else if (fstat(fd, &st)) {
+ err = -1;
+ } else if (st.st_size < 2 * ADV_SIZE) {
+ /* Too small to be useful */
+ err = -2;
+ } else if (xpread(fd, advtmp, 2 * ADV_SIZE,
+ st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
+ err = -1;
+ } else {
+ /* We got it... maybe? */
+ err = syslinux_validate_adv(advtmp) ? -2 : 0;
+ if (!err) {
+ /* Got a good one, write our own ADV here */
+ clear_attributes(fd);
+
+ /* Need to re-open read-write */
+ close(fd);
+ fd = open(file, O_RDWR | O_SYNC);
+ if (fd < 0) {
+ err = -1;
+ } else if (fstat(fd, &xst) || xst.st_ino != st.st_ino ||
+ xst.st_dev != st.st_dev || xst.st_size != st.st_size) {
+ fprintf(stderr, "%s: race condition on write\n", file);
+ err = -2;
+ }
+ /* Write our own version ... */
+ if (xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
+ st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
+ err = -1;
+ }
+
+ sync();
+ set_attributes(fd);
+ }
+ }
+
+ if (err == -2)
+ fprintf(stderr, "%s: cannot write auxilliary data (need --update)?\n",
+ file);
+ else if (err == -1)
+ perror(file);
+
+ if (fd >= 0)
+ close(fd);
+ if (file)
+ free(file);
+
+ return err;
+}
diff --git a/libinstaller/fat.c b/libinstaller/fat.c
new file mode 100644
index 00000000..e2101353
--- /dev/null
+++ b/libinstaller/fat.c
@@ -0,0 +1,129 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author H. Peter Anvin
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * fat.c - Initial sanity check for FAT-based installers
+ */
+
+#define _XOPEN_SOURCE 500 /* Required on glibc 2.x */
+#define _BSD_SOURCE
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "syslinux.h"
+#include "syslxint.h"
+
+void syslinux_make_bootsect(void *bs)
+{
+ struct boot_sector *bootsect = bs;
+ const struct boot_sector *sbs =
+ (const struct boot_sector *)boot_sector;
+
+ memcpy(&bootsect->bsHead, &sbs->bsHead, bsHeadLen);
+ memcpy(&bootsect->bsCode, &sbs->bsCode, bsCodeLen);
+}
+
+/*
+ * Check to see that what we got was indeed an MS-DOS boot sector/superblock;
+ * Return NULL if OK and otherwise an error message;
+ */
+const char *syslinux_check_bootsect(const void *bs)
+{
+ int veryold;
+ int sectorsize;
+ long long sectors, fatsectors, dsectors;
+ long long clusters;
+ int rootdirents, clustersize;
+ const struct boot_sector *sectbuf = bs;
+
+ veryold = 0;
+
+ /* Must be 0xF0 or 0xF8..0xFF */
+ if (get_8(&sectbuf->bsMedia) != 0xF0 && get_8(&sectbuf->bsMedia) < 0xF8)
+ return "invalid media signature (not a FAT filesystem?)";
+
+ sectorsize = get_16(&sectbuf->bsBytesPerSec);
+ if (sectorsize == SECTOR_SIZE)
+ ; /* ok */
+ else if (sectorsize >= 512 && sectorsize <= 4096 &&
+ (sectorsize & (sectorsize - 1)) == 0)
+ return "unsupported sectors size";
+ else
+ return "impossible sector size";
+
+ clustersize = get_8(&sectbuf->bsSecPerClust);
+ if (clustersize == 0 || (clustersize & (clustersize - 1)))
+ return "impossible cluster size";
+
+ sectors = get_16(&sectbuf->bsSectors);
+ sectors = sectors ? sectors : get_32(&sectbuf->bsHugeSectors);
+
+ dsectors = sectors - get_16(&sectbuf->bsResSectors);
+
+ fatsectors = get_16(&sectbuf->bsFATsecs);
+ fatsectors = fatsectors ? fatsectors : get_32(&sectbuf->bs32.FATSz32);
+ fatsectors *= get_8(&sectbuf->bsFATs);
+ dsectors -= fatsectors;
+
+ rootdirents = get_16(&sectbuf->bsRootDirEnts);
+ dsectors -= (rootdirents + sectorsize / 32 - 1) / sectorsize;
+
+ if (dsectors < 0)
+ return "negative number of data sectors";
+
+ if (fatsectors == 0)
+ return "zero FAT sectors";
+
+ clusters = dsectors / clustersize;
+
+ if (clusters < 0xFFF5) {
+ /* FAT12 or FAT16 */
+
+ if (!get_16(&sectbuf->bsFATsecs))
+ return "zero FAT sectors (FAT12/16)";
+
+ if (get_8(&sectbuf->bs16.BootSignature) == 0x29) {
+ if (!memcmp(&sectbuf->bs16.FileSysType, "FAT12 ", 8)) {
+ if (clusters >= 0xFF5)
+ return "more than 4084 clusters but claims FAT12";
+ } else if (!memcmp(&sectbuf->bs16.FileSysType, "FAT16 ", 8)) {
+ if (clusters < 0xFF5)
+ return "less than 4084 clusters but claims FAT16";
+ } else if (!memcmp(&sectbuf->bs16.FileSysType, "FAT32 ", 8)) {
+ return "less than 65525 clusters but claims FAT32";
+ } else if (memcmp(&sectbuf->bs16.FileSysType, "FAT ", 8)) {
+ static char fserr[] =
+ "filesystem type \"????????\" not supported";
+ memcpy(fserr + 17, &sectbuf->bs16.FileSysType, 8);
+ return fserr;
+ }
+ }
+ } else if (clusters < 0x0FFFFFF5) {
+ /*
+ * FAT32...
+ *
+ * Moving the FileSysType and BootSignature was a lovely stroke
+ * of M$ idiocy...
+ */
+ if (get_8(&sectbuf->bs32.BootSignature) != 0x29 ||
+ memcmp(&sectbuf->bs32.FileSysType, "FAT32 ", 8))
+ return "missing FAT32 signature";
+ } else {
+ return "impossibly large number of clusters";
+ }
+
+ return NULL;
+}
diff --git a/libinstaller/linuxioctl.h b/libinstaller/linuxioctl.h
new file mode 100644
index 00000000..7ef919a3
--- /dev/null
+++ b/libinstaller/linuxioctl.h
@@ -0,0 +1,47 @@
+/*
+ * linuxioctl.h
+ *
+ * Wrapper for Linux ioctl definitions, including workarounds
+ */
+
+#ifndef LIBINSTALLER_LINUXIOCTL_H
+#define LIBINSTALLER_LINUXIOCTL_H
+
+#include <sys/ioctl.h>
+
+#define statfs _kernel_statfs /* HACK to deal with broken 2.4 distros */
+
+#include <linux/fd.h> /* Floppy geometry */
+#include <linux/hdreg.h> /* Hard disk geometry */
+
+#include <linux/fs.h> /* FIGETBSZ, FIBMAP, FS_IOC_FIEMAP */
+#include <linux/msdos_fs.h> /* FAT_IOCTL_SET_ATTRIBUTES */
+
+#undef SECTOR_SIZE /* Defined in msdos_fs.h for no good reason */
+#undef SECTOR_BITS
+#include <linux/ext2_fs.h> /* EXT2_IOC_* */
+
+#ifndef FAT_IOCTL_GET_ATTRIBUTES
+# define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, __u32)
+#endif
+
+#ifndef FAT_IOCTL_SET_ATTRIBUTES
+# define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, __u32)
+#endif
+
+#include <linux/fiemap.h> /* FIEMAP definitions */
+
+#ifndef FS_IOC_FIEMAP
+# define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap)
+#endif
+
+#undef statfs
+
+#if defined(__linux__) && !defined(BLKGETSIZE64)
+/* This takes a u64, but the size field says size_t. Someone screwed big. */
+# define BLKGETSIZE64 _IOR(0x12,114,size_t)
+#endif
+
+#include <linux/loop.h>
+
+#endif /* LIBINSTALLER_LINUXIOCTL_H */
diff --git a/memdisk/compiler.h b/memdisk/compiler.h
new file mode 100644
index 00000000..d1b03e06
--- /dev/null
+++ b/memdisk/compiler.h
@@ -0,0 +1,9 @@
+
+#ifdef __WATCOMC__
+# define MEMDISK_PACKED_PREFIX _Packed
+# define MEMDISK_PACKED_POSTFIX
+#else
+/* Assume GNU C for now */
+# define MEMDISK_PACKED_PREFIX
+# define MEMDISK_PACKED_POSTFIX __attribute__((packed))
+#endif
diff --git a/memdisk/mstructs.h b/memdisk/mstructs.h
new file mode 100644
index 00000000..fecbff40
--- /dev/null
+++ b/memdisk/mstructs.h
@@ -0,0 +1,178 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Portions copyright 2009-2010 Shao Miller
+ * [El Torito code, mBFT, "safe hook"]
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/* These structures are common to MEMDISK and MDISKCHK.COM */
+
+#include <stdint.h>
+#include "compiler.h"
+
+struct seg_off {
+ uint16_t offset;
+ uint16_t segment;
+};
+
+typedef union {
+ struct seg_off seg_off;
+ uint32_t uint32;
+} real_addr_t;
+
+/* Forward declaration */
+struct mBFT;
+
+MEMDISK_PACKED_PREFIX
+struct safe_hook {
+ uint8_t jump[3]; /* Max. three bytes for jump */
+ uint8_t signature[8]; /* "$INT13SF" */
+ uint8_t vendor[8]; /* "MEMDISK " */
+ real_addr_t old_hook; /* SEG:OFF for previous INT 13h hook */
+ uint32_t flags; /* "Safe hook" flags */
+ /* The next field is a MEMDISK extension to the "safe hook" structure */
+ uint32_t mbft;
+} MEMDISK_PACKED_POSTFIX;
+
+struct memdisk_header {
+ uint16_t int13_offs;
+ uint16_t int15_offs;
+ uint16_t patch_offs;
+ uint16_t total_size;
+ uint16_t iret_offs;
+ struct safe_hook safe_hook;
+};
+
+MEMDISK_PACKED_PREFIX
+/* EDD disk parameter table */
+struct edd_dpt {
+ uint16_t len; /* Length of table */
+ uint16_t flags; /* Information flags */
+ uint32_t c; /* Physical cylinders (count!) */
+ uint32_t h; /* Physical heads (count!) */
+ uint32_t s; /* Physical sectors/track (count!) */
+ uint64_t sectors; /* Total sectors */
+ uint16_t bytespersec; /* Bytes/sector */
+ real_addr_t dpte; /* DPTE pointer */
+ uint16_t dpikey; /* Device Path Info magic */
+ uint8_t dpilen; /* Device Path Info length */
+ uint8_t res1; /* Reserved */
+ uint16_t res2; /* Reserved */
+ uint8_t bustype[4]; /* Host bus type */
+ uint8_t inttype[8]; /* Interface type */
+ uint64_t intpath; /* Interface path */
+ uint64_t devpath[2]; /* Device path (double QuadWord!) */
+ uint8_t res3; /* Reserved */
+ uint8_t chksum; /* DPI checksum */
+} MEMDISK_PACKED_POSTFIX;
+
+/* Requirement for struct edd4_cd_pkt */
+#include "../memdisk/eltorito.h"
+
+/* Official MEMDISK Info structure ("MDI") */
+MEMDISK_PACKED_PREFIX
+struct mdi {
+ const uint16_t bytes;
+ const uint8_t version_minor;
+ const uint8_t version_major;
+
+ uint32_t diskbuf;
+ uint32_t disksize;
+ real_addr_t cmdline;
+
+ real_addr_t oldint13;
+ real_addr_t oldint15;
+
+ uint16_t olddosmem;
+ uint8_t bootloaderid;
+ uint8_t sector_shift;
+
+ uint16_t dpt_ptr;
+} MEMDISK_PACKED_POSTFIX;
+
+/* Requirement for struct acpi_description_header */
+#include "../memdisk/acpi.h"
+
+MEMDISK_PACKED_PREFIX
+struct mBFT {
+ struct acpi_description_header acpi;
+ uint32_t safe_hook; /* "Safe hook" physical address */
+ struct mdi mdi;
+} MEMDISK_PACKED_POSTFIX;
+
+/* The Disk Parameter Table may be required */
+typedef union {
+ struct hd_dpt {
+ uint16_t max_cyl; /* Max cylinder */
+ uint8_t max_head; /* Max head */
+ uint8_t junk1[5]; /* Obsolete junk, leave at zero */
+ uint8_t ctrl; /* Control byte */
+ uint8_t junk2[7]; /* More obsolete junk */
+ } hd;
+ struct fd_dpt {
+ uint8_t specify1; /* "First specify byte" */
+ uint8_t specify2; /* "Second specify byte" */
+ uint8_t delay; /* Delay until motor turn off */
+ uint8_t sectors; /* Sectors/track */
+
+ uint8_t bps; /* Bytes/sector (02h = 512) */
+ uint8_t isgap; /* Length of intersector gap */
+ uint8_t dlen; /* Data length (0FFh) */
+ uint8_t fgap; /* Formatting gap */
+
+ uint8_t ffill; /* Format fill byte */
+ uint8_t settle; /* Head settle time (ms) */
+ uint8_t mstart; /* Motor start time */
+ uint8_t maxtrack; /* Maximum track number */
+
+ uint8_t rate; /* Data transfer rate */
+ uint8_t cmos; /* CMOS type */
+ uint8_t pad[2];
+
+ uint32_t old_fd_dpt; /* Extension: pointer to old INT 1Eh */
+ } fd;
+} dpt_t;
+
+MEMDISK_PACKED_PREFIX
+struct patch_area {
+ struct mdi mdi;
+
+ uint8_t driveshiftlimit; /* Do not shift drives above this region */
+ uint8_t _pad2; /* Pad to DWORD */
+ uint16_t _pad3; /* Pad to QWORD */
+
+ uint16_t memint1588;
+
+ uint16_t cylinders;
+ uint16_t heads;
+ uint32_t sectors;
+
+ uint32_t mem1mb;
+ uint32_t mem16mb;
+
+ uint8_t driveno;
+ uint8_t drivetype;
+ uint8_t drivecnt;
+ uint8_t configflags;
+
+#define CONFIG_READONLY 0x01
+#define CONFIG_RAW 0x02
+#define CONFIG_SAFEINT 0x04
+#define CONFIG_BIGRAW 0x08 /* MUST be 8! */
+#define CONFIG_MODEMASK 0x0e
+
+ uint16_t mystack;
+ uint16_t statusptr;
+
+ dpt_t dpt;
+ struct edd_dpt edd_dpt;
+ struct edd4_cd_pkt cd_pkt; /* Only really in a memdisk_iso_* hook */
+} MEMDISK_PACKED_POSTFIX;
diff --git a/utils/memdiskfind.c b/utils/memdiskfind.c
new file mode 100644
index 00000000..decc788f
--- /dev/null
+++ b/utils/memdiskfind.c
@@ -0,0 +1,158 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * memdiskfind.c
+ *
+ * Simple utility to search for a MEMDISK instance and output the parameters
+ * needed to use the "phram" driver in Linux to map it.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include "../memdisk/mstructs.h"
+
+#define MBFT_MIN_LENGTH (36+4+26)
+
+static bool valid_mbft(const struct mBFT *mbft, size_t space)
+{
+ uint8_t csum;
+ size_t i;
+
+ if (memcmp(mbft->acpi.signature, "mBFT", 4))
+ return false;
+
+ if (mbft->acpi.length < MBFT_MIN_LENGTH)
+ return false;
+
+ if (mbft->acpi.length > space)
+ return false;
+
+ if ((size_t)mbft->acpi.length != (size_t)mbft->mdi.bytes + 36+4)
+ return false;
+
+ csum = 0;
+ for (i = 0; i < mbft->acpi.length; i++)
+ csum += ((const uint8_t *)mbft)[i];
+
+ if (csum)
+ return false;
+
+ return true;
+}
+
+static void output_params(const struct mBFT *mbft)
+{
+ int sector_shift = mbft->mdi.sector_shift;
+
+ if (!sector_shift)
+ sector_shift = 9;
+
+ printf("%#x,%#x\n",
+ mbft->mdi.diskbuf, mbft->mdi.disksize << sector_shift);
+}
+
+static size_t memlimit(void)
+{
+ char txtline[256], user[256];
+ size_t maxram = 0;
+ unsigned long long start, end;
+ FILE *iomem;
+
+ iomem = fopen("/proc/iomem", "r");
+ if (!iomem)
+ return 0;
+
+ while (fgets(txtline, sizeof txtline, iomem) != NULL) {
+ if (sscanf(txtline, "%llx-%llx : %[^\n]", &start, &end, user) != 3)
+ continue;
+ if (strcmp(user, "System RAM"))
+ continue;
+ if (start >= 0xa0000)
+ continue;
+ maxram = (end >= 0xa0000) ? 0xa0000 : end+1;
+ }
+ fclose(iomem);
+
+ return maxram;
+}
+
+int main(int argc, char *argv[])
+{
+ const char *map;
+ int memfd;
+ size_t fbm;
+ const char *ptr, *end;
+ size_t page = sysconf(_SC_PAGESIZE);
+ size_t mapbase, maplen;
+ int err = 1;
+
+ (void)argc;
+
+ mapbase = memlimit() & ~(page - 1);
+ if (!mapbase)
+ return 2;
+
+ memfd = open("/dev/mem", O_RDONLY);
+ if (memfd < 0) {
+ fprintf(stderr, "%s: cannot open /dev/mem: %s\n",
+ argv[0], strerror(errno));
+ return 2;
+ }
+
+ map = mmap(NULL, page, PROT_READ, MAP_SHARED, memfd, 0);
+ if (map == MAP_FAILED) {
+ fprintf(stderr, "%s: cannot map page 0: %s\n",
+ argv[0], strerror(errno));
+ return 2;
+ }
+
+ fbm = *(uint16_t *)(map + 0x413) << 10;
+ if (fbm < mapbase)
+ fbm = mapbase;
+
+ munmap((void *)map, page);
+
+ if (fbm < 64*1024 || fbm >= 640*1024)
+ return 1;
+
+ maplen = 0xa0000 - mapbase;
+ map = mmap(NULL, maplen, PROT_READ, MAP_SHARED, memfd, mapbase);
+ if (map == MAP_FAILED) {
+ fprintf(stderr, "%s: cannot map base memory: %s\n",
+ argv[0], strerror(errno));
+ return 2;
+ }
+
+ ptr = map + (fbm - mapbase);
+ end = map + (0xa0000 - mapbase);
+ while (ptr < end) {
+ if (valid_mbft((const struct mBFT *)ptr, end-ptr)) {
+ output_params((const struct mBFT *)ptr);
+ err = 0;
+ break;
+ }
+ ptr += 16;
+ }
+
+ munmap((void *)map, maplen);
+
+ return err;
+}