summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/memdisk
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/memdisk')
-rw-r--r--contrib/syslinux-4.02/memdisk/Makefile100
-rw-r--r--contrib/syslinux-4.02/memdisk/acpi.h55
-rw-r--r--contrib/syslinux-4.02/memdisk/bda.h56
-rw-r--r--contrib/syslinux-4.02/memdisk/compiler.h9
-rw-r--r--contrib/syslinux-4.02/memdisk/conio.c394
-rw-r--r--contrib/syslinux-4.02/memdisk/conio.h33
-rw-r--r--contrib/syslinux-4.02/memdisk/dskprobe.c114
-rw-r--r--contrib/syslinux-4.02/memdisk/dskprobe.h21
-rw-r--r--contrib/syslinux-4.02/memdisk/e820.h33
-rw-r--r--contrib/syslinux-4.02/memdisk/e820data15
-rw-r--r--contrib/syslinux-4.02/memdisk/e820func.c107
-rw-r--r--contrib/syslinux-4.02/memdisk/e820test.c88
-rw-r--r--contrib/syslinux-4.02/memdisk/eltorito.c58
-rw-r--r--contrib/syslinux-4.02/memdisk/eltorito.h80
-rwxr-xr-xcontrib/syslinux-4.02/memdisk/fdgeo.pl56
-rw-r--r--contrib/syslinux-4.02/memdisk/inflate.c1026
-rw-r--r--contrib/syslinux-4.02/memdisk/memcpy.S86
-rw-r--r--contrib/syslinux-4.02/memdisk/memdisk.h137
-rw-r--r--contrib/syslinux-4.02/memdisk/memdisk.inc1189
-rw-r--r--contrib/syslinux-4.02/memdisk/memdisk.ld140
-rw-r--r--contrib/syslinux-4.02/memdisk/memdisk16.asm793
-rw-r--r--contrib/syslinux-4.02/memdisk/memdisk_chs_512.asm5
-rw-r--r--contrib/syslinux-4.02/memdisk/memdisk_edd_512.asm5
-rw-r--r--contrib/syslinux-4.02/memdisk/memdisk_iso_2048.asm5
-rw-r--r--contrib/syslinux-4.02/memdisk/memdisk_iso_512.asm5
-rw-r--r--contrib/syslinux-4.02/memdisk/memmove.S139
-rw-r--r--contrib/syslinux-4.02/memdisk/memset.S86
-rw-r--r--contrib/syslinux-4.02/memdisk/msetup.c178
-rw-r--r--contrib/syslinux-4.02/memdisk/mstructs.h178
-rwxr-xr-xcontrib/syslinux-4.02/memdisk/postprocess.pl58
-rw-r--r--contrib/syslinux-4.02/memdisk/setup.c1189
-rw-r--r--contrib/syslinux-4.02/memdisk/start32.S101
-rw-r--r--contrib/syslinux-4.02/memdisk/testdata113
-rw-r--r--contrib/syslinux-4.02/memdisk/testdata210
-rw-r--r--contrib/syslinux-4.02/memdisk/testdata314
-rw-r--r--contrib/syslinux-4.02/memdisk/unzip.c391
-rw-r--r--contrib/syslinux-4.02/memdisk/version.h25
37 files changed, 6992 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/memdisk/Makefile b/contrib/syslinux-4.02/memdisk/Makefile
new file mode 100644
index 0000000..d2f20c5
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/Makefile
@@ -0,0 +1,100 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
+## Copyright 2009 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.
+##
+## -----------------------------------------------------------------------
+
+topdir = ..
+include $(topdir)/MCONFIG.embedded
+-include $(topdir)/version.mk
+
+INCLUDES = -I$(topdir)/com32/include
+CFLAGS += -D__MEMDISK__ -DDATE='"$(DATE)"'
+LDFLAGS = $(GCCOPT) -g
+NASM = nasm
+NASMOPT = -O9999
+NFLAGS = -dDATE='"$(DATE)"'
+NINCLUDE =
+
+SRCS = $(wildcard *.asm *.c *.h)
+
+# The DATE is set on the make command line when building binaries for
+# official release. Otherwise, substitute a hex string that is pretty much
+# guaranteed to be unique to be unique from build to build.
+ifndef HEXDATE
+HEXDATE := $(shell $(PERL) ../now.pl $(SRCS))
+endif
+ifndef DATE
+DATE := $(shell sh ../gen-id.sh $(VERSION) $(HEXDATE))
+endif
+
+# Important: init.o16 must be first!!
+OBJS16 = init.o16 init32.o
+OBJS32 = start32.o setup.o msetup.o e820func.o conio.o memcpy.o memset.o \
+ memmove.o unzip.o dskprobe.o eltorito.o \
+ memdisk_chs_512.o memdisk_edd_512.o \
+ memdisk_iso_512.o memdisk_iso_2048.o
+
+CSRC = setup.c msetup.c e820func.c conio.c unzip.c dskprobe.c eltorito.c
+SSRC = start32.S memcpy.S memset.S memmove.S
+NASMSRC = memdisk_chs_512.asm memdisk_edd_512.asm \
+ memdisk_iso_512.asm memdisk_iso_2048.asm \
+ memdisk16.asm
+
+all: memdisk # e820test
+
+# tidy, clean removes everything except the final binary
+tidy dist:
+ rm -f *.o *.s *.tmp *.o16 *.s16 *.bin *.lst *.elf e820test .*.d
+ rm -f *.map
+
+clean: tidy
+
+# spotless also removes the product binary
+spotless: clean
+ rm -f memdisk .depend
+
+memdisk16.o: memdisk16.asm
+
+# Cancel rule
+%.o: %.asm
+
+memdisk16.o: memdisk16.asm
+ ( $(NASM) -M -DDEPEND $(NFLAGS) $(NINCLUDE) -o $@ $< ; echo '' ) > .$@.d ; true
+ $(NASM) -f elf $(NASMOPT) $(NFLAGS) $(NINCLUDE) -o $@ -l $*.lst $<
+
+.PRECIOUS: %.bin
+%.bin: %.asm
+ ( $(NASM) -M -DDEPEND $(NFLAGS) $(NINCLUDE) -o $@ $< ; echo '' ) > .$@.d ; true
+ $(NASM) -f bin $(NASMOPT) $(NFLAGS) $(NINCLUDE) -o $@ -l $*.lst $<
+
+memdisk_%.o: memdisk_%.bin
+ $(LD) -r -b binary -o $@ $<
+
+memdisk16.elf: $(OBJS16)
+ $(LD) -Ttext 0 -o $@ $^
+
+memdisk32.elf: memdisk.ld $(OBJS32)
+ $(LD) -o $@ -T $^
+
+%.bin: %.elf
+ $(OBJCOPY) -O binary $< $@
+
+memdisk: memdisk16.bin memdisk32.bin postprocess.pl
+ $(PERL) postprocess.pl $@ memdisk16.bin memdisk32.bin
+
+e820test: e820test.c e820func.c msetup.c
+ $(CC) -m32 -g $(GCCWARN) -DTEST -o $@ $^
+
+# This file contains the version number, so add a dependency for it
+setup.s: ../version
+
+# Include dependencies file
+-include .*.d
diff --git a/contrib/syslinux-4.02/memdisk/acpi.h b/contrib/syslinux-4.02/memdisk/acpi.h
new file mode 100644
index 0000000..732d116
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/acpi.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ * This file derived almost in its entirety from gPXE.
+ *
+ * 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; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** @file
+ *
+ * ACPI data structures
+ *
+ */
+
+#include <stdint.h>
+
+/**
+ * An ACPI description header
+ *
+ * This is the structure common to the start of all ACPI system
+ * description tables.
+ */
+MEMDISK_PACKED_PREFIX
+struct acpi_description_header {
+ /** ACPI signature (4 ASCII characters) */
+ char signature[4];
+ /** Length of table, in bytes, including header */
+ uint32_t length;
+ /** ACPI Specification minor version number */
+ uint8_t revision;
+ /** To make sum of entire table == 0 */
+ uint8_t checksum;
+ /** OEM identification */
+ char oem_id[6];
+ /** OEM table identification */
+ char oem_table_id[8];
+ /** OEM revision number */
+ uint32_t oem_revision;
+ /** ASL compiler vendor ID */
+ char asl_compiler_id[4];
+ /** ASL compiler revision number */
+ uint32_t asl_compiler_revision;
+} MEMDISK_PACKED_POSTFIX;
+
diff --git a/contrib/syslinux-4.02/memdisk/bda.h b/contrib/syslinux-4.02/memdisk/bda.h
new file mode 100644
index 0000000..cfac441
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/bda.h
@@ -0,0 +1,56 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdint.h>
+
+/* Addresses in the zero page */
+#define BIOS_INT13 (0x13*4) /* INT 13h vector */
+#define BIOS_INT15 (0x15*4) /* INT 15h vector */
+#define BIOS_INT1E (0x1E*4) /* INT 1Eh vector */
+#define BIOS_INT40 (0x40*4) /* INT 13h vector */
+#define BIOS_INT41 (0x41*4) /* INT 41h vector */
+#define BIOS_INT46 (0x46*4) /* INT 46h vector */
+#define BIOS_BASEMEM 0x413 /* Amount of DOS memory */
+#define BIOS_EQUIP 0x410 /* BIOS equipment list */
+#define BIOS_HD_COUNT 0x475 /* Number of hard drives present */
+
+/* Access to objects in the zero page */
+static inline void wrz_8(uint32_t addr, uint8_t data)
+{
+ *((uint8_t *) addr) = data;
+}
+
+static inline void wrz_16(uint32_t addr, uint16_t data)
+{
+ *((uint16_t *) addr) = data;
+}
+
+static inline void wrz_32(uint32_t addr, uint32_t data)
+{
+ *((uint32_t *) addr) = data;
+}
+
+static inline uint8_t rdz_8(uint32_t addr)
+{
+ return *((uint8_t *) addr);
+}
+
+static inline uint16_t rdz_16(uint32_t addr)
+{
+ return *((uint16_t *) addr);
+}
+
+static inline uint32_t rdz_32(uint32_t addr)
+{
+ return *((uint32_t *) addr);
+}
diff --git a/contrib/syslinux-4.02/memdisk/compiler.h b/contrib/syslinux-4.02/memdisk/compiler.h
new file mode 100644
index 0000000..d1b03e0
--- /dev/null
+++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/memdisk/conio.c b/contrib/syslinux-4.02/memdisk/conio.c
new file mode 100644
index 0000000..d1f0862
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/conio.c
@@ -0,0 +1,394 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2008 H. Peter Anvin - 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * conio.c
+ *
+ * Output to the screen
+ */
+
+#include <stdint.h>
+#include "memdisk.h"
+#include "conio.h"
+
+int putchar(int ch)
+{
+ com32sys_t regs;
+
+ if (ch == '\n') {
+ /* \n -> \r\n */
+ putchar('\r');
+ }
+
+ regs.eax.w[0] = 0x0e00 | (ch & 0xff);
+ intcall(0x10, &regs, NULL);
+
+ return ch;
+}
+
+int puts(const char *s)
+{
+ int count = 0;
+
+ while (*s) {
+ putchar(*s);
+ count++;
+ s++;
+ }
+
+ return count;
+}
+
+/*
+ * Oh, it's a waste of space, but oh-so-yummy for debugging. It's just
+ * initialization code anyway, so it doesn't take up space when we're
+ * actually running. This version of printf() does not include 64-bit
+ * support. "Live with it."
+ *
+ * Most of this code was shamelessly snarfed from the Linux kernel, then
+ * modified.
+ */
+
+static inline int isdigit(int ch)
+{
+ return (ch >= '0') && (ch <= '9');
+}
+
+static int skip_atoi(const char **s)
+{
+ int i = 0;
+
+ while (isdigit(**s))
+ i = i * 10 + *((*s)++) - '0';
+ return i;
+}
+
+unsigned int atou(const char *s)
+{
+ unsigned int i = 0;
+ while (isdigit(*s))
+ i = i * 10 + (*s++ - '0');
+ return i;
+}
+
+static int strnlen(const char *s, int maxlen)
+{
+ const char *es = s;
+ while (*es && maxlen) {
+ es++;
+ maxlen--;
+ }
+
+ return (es - s);
+}
+
+#define ZEROPAD 1 /* pad with zero */
+#define SIGN 2 /* unsigned/signed long */
+#define PLUS 4 /* show plus */
+#define SPACE 8 /* space if plus */
+#define LEFT 16 /* left justified */
+#define SPECIAL 32 /* 0x */
+#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+static char *number(char *str, long num, int base, int size, int precision,
+ int type)
+{
+ char c, sign, tmp[66];
+ const char *digits = "0123456789abcdef";
+ int i;
+
+ if (type & LARGE)
+ digits = "0123456789ABCDEF";
+ if (type & LEFT)
+ type &= ~ZEROPAD;
+ if (base < 2 || base > 36)
+ return 0;
+ c = (type & ZEROPAD) ? '0' : ' ';
+ sign = 0;
+ if (type & SIGN) {
+ if (num < 0) {
+ sign = '-';
+ num = -num;
+ size--;
+ } else if (type & PLUS) {
+ sign = '+';
+ size--;
+ } else if (type & SPACE) {
+ sign = ' ';
+ size--;
+ }
+ }
+ if (type & SPECIAL) {
+ if (base == 16)
+ size -= 2;
+ else if (base == 8)
+ size--;
+ }
+ i = 0;
+ if (num == 0)
+ tmp[i++] = '0';
+ else
+ while (num != 0)
+ tmp[i++] = digits[do_div(num, base)];
+ if (i > precision)
+ precision = i;
+ size -= precision;
+ if (!(type & (ZEROPAD + LEFT)))
+ while (size-- > 0)
+ *str++ = ' ';
+ if (sign)
+ *str++ = sign;
+ if (type & SPECIAL) {
+ if (base == 8)
+ *str++ = '0';
+ else if (base == 16) {
+ *str++ = '0';
+ *str++ = digits[33];
+ }
+ }
+ if (!(type & LEFT))
+ while (size-- > 0)
+ *str++ = c;
+ while (i < precision--)
+ *str++ = '0';
+ while (i-- > 0)
+ *str++ = tmp[i];
+ while (size-- > 0)
+ *str++ = ' ';
+ return str;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+ int len;
+ unsigned long num;
+ int i, base;
+ char *str;
+ const char *s;
+
+ int flags; /* flags to number() */
+
+ int field_width; /* width of output field */
+ int precision; /* min. # of digits for integers; max
+ number of chars for from string */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+
+ for (str = buf; *fmt; ++fmt) {
+ if (*fmt != '%') {
+ *str++ = *fmt;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+repeat:
+ ++fmt; /* this also skips first '%' */
+ switch (*fmt) {
+ case '-':
+ flags |= LEFT;
+ goto repeat;
+ case '+':
+ flags |= PLUS;
+ goto repeat;
+ case ' ':
+ flags |= SPACE;
+ goto repeat;
+ case '#':
+ flags |= SPECIAL;
+ goto repeat;
+ case '0':
+ flags |= ZEROPAD;
+ goto repeat;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt))
+ field_width = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0) {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.') {
+ ++fmt;
+ if (isdigit(*fmt))
+ precision = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0)
+ precision = 0;
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+ qualifier = *fmt;
+ ++fmt;
+ }
+
+ /* default base */
+ base = 10;
+
+ switch (*fmt) {
+ case 'c':
+ if (!(flags & LEFT))
+ while (--field_width > 0)
+ *str++ = ' ';
+ *str++ = (unsigned char)va_arg(args, int);
+ while (--field_width > 0)
+ *str++ = ' ';
+ continue;
+
+ case 's':
+ s = va_arg(args, char *);
+ len = strnlen(s, precision);
+
+ if (!(flags & LEFT))
+ while (len < field_width--)
+ *str++ = ' ';
+ for (i = 0; i < len; ++i)
+ *str++ = *s++;
+ while (len < field_width--)
+ *str++ = ' ';
+ continue;
+
+ case 'p':
+ if (field_width == -1) {
+ field_width = 2 * sizeof(void *);
+ flags |= ZEROPAD;
+ }
+ str = number(str,
+ (unsigned long)va_arg(args, void *), 16,
+ field_width, precision, flags);
+ continue;
+
+ case 'n':
+ if (qualifier == 'l') {
+ long *ip = va_arg(args, long *);
+ *ip = (str - buf);
+ } else {
+ int *ip = va_arg(args, int *);
+ *ip = (str - buf);
+ }
+ continue;
+
+ case '%':
+ *str++ = '%';
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'o':
+ base = 8;
+ break;
+
+ case 'X':
+ flags |= LARGE;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ break;
+
+ default:
+ *str++ = '%';
+ if (*fmt)
+ *str++ = *fmt;
+ else
+ --fmt;
+ continue;
+ }
+ if (qualifier == 'l')
+ num = va_arg(args, unsigned long);
+ else if (qualifier == 'h') {
+ num = (unsigned short)va_arg(args, int);
+ if (flags & SIGN)
+ num = (short)num;
+ } else if (flags & SIGN)
+ num = va_arg(args, int);
+ else
+ num = va_arg(args, unsigned int);
+ str = number(str, num, base, field_width, precision, flags);
+ }
+ *str = '\0';
+ return str - buf;
+}
+
+#if 0
+int sprintf(char *buf, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vsprintf(buf, fmt, args);
+ va_end(args);
+ return i;
+}
+#endif
+
+int vprintf(const char *fmt, va_list args)
+{
+ char printf_buf[2048];
+ int printed;
+
+ printed = vsprintf(printf_buf, fmt, args);
+ puts(printf_buf);
+ return printed;
+}
+
+int printf(const char *fmt, ...)
+{
+ va_list args;
+ int printed;
+
+ va_start(args, fmt);
+ printed = vprintf(fmt, args);
+ va_end(args);
+ return printed;
+}
+
+/*
+ * Jump here if all hope is gone...
+ */
+void __attribute__ ((noreturn)) die(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+
+ sti();
+ for (;;)
+ asm volatile("hlt");
+}
diff --git a/contrib/syslinux-4.02/memdisk/conio.h b/contrib/syslinux-4.02/memdisk/conio.h
new file mode 100644
index 0000000..9775e62
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/conio.h
@@ -0,0 +1,33 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2008 H. Peter Anvin - 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * conio.h
+ *
+ * Limited console I/O
+ */
+
+#ifndef CONIO_H
+#define CONIO_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdarg.h>
+
+int putchar(int);
+int puts(const char *);
+int vprintf(const char *, va_list ap);
+int printf(const char *, ...);
+void __attribute__((noreturn)) die(const char *, ...);
+unsigned int atou(const char *);
+
+#endif
diff --git a/contrib/syslinux-4.02/memdisk/dskprobe.c b/contrib/syslinux-4.02/memdisk/dskprobe.c
new file mode 100644
index 0000000..de858bb
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/dskprobe.c
@@ -0,0 +1,114 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * dskprobe.c
+ *
+ * Routines for probing BIOS disk drives
+ */
+
+/*
+ * Uncomment for debugging
+ *
+ * #define DBG_DSKPROBE 1
+ */
+
+#include <stdint.h>
+#include "memdisk.h"
+#include "bda.h"
+#include "conio.h"
+
+/*
+ * We will probe a BIOS drive numer using INT 13h, AH=probe
+ * and will pass along that call's success or failure
+ */
+int probe_int13_ah(uint8_t drive, uint8_t probe)
+{
+ int err;
+ com32sys_t regs;
+
+ memset(&regs, 0, sizeof regs);
+
+ regs.eax.b[1] = probe; /* AH = probe */
+ regs.edx.b[0] = drive; /* DL = drive number to probe */
+ intcall(0x13, &regs, &regs);
+
+ err = !(regs.eflags.l & 1);
+#ifdef DBG_DSKPROBE
+ printf("probe_int13_ah(0x%02x, 0x%02x) == %d\n", drive, probe, err);
+#endif
+ return err;
+}
+
+/*
+ * We will probe the BIOS Data Area and count the drives found there.
+ * This heuristic then assumes that all drives of 'drive's type are
+ * found in a contiguous range, and returns 1 if the probed drive
+ * is less than or equal to the BDA count.
+ * This particular function's code is derived from code in setup.c by
+ * H. Peter Anvin. Please respect that file's copyright for this function
+ */
+int probe_bda_drive(uint8_t drive)
+{
+ int bios_drives;
+ int err;
+
+ if (drive & 0x80) {
+ bios_drives = rdz_8(BIOS_HD_COUNT); /* HDD count */
+ } else {
+ uint8_t equip = rdz_8(BIOS_EQUIP);
+ if (equip & 1)
+ bios_drives = (equip >> 6) + 1; /* Floppy count */
+ else
+ bios_drives = 0;
+ }
+ err = (drive - (drive & 0x80)) >= bios_drives ? 0 : 1;
+#ifdef DBG_DSKPROBE
+ printf("probe_bda_drive(0x%02x) == %d, count: %d\n",
+ drive, err, bios_drives);
+#endif
+ return err;
+}
+
+/*
+ * We will probe a drive with a few different methods, returning
+ * the count of succesful probes
+ */
+int probe_drive(uint8_t drive)
+{
+ int c = 0;
+ /* Only probe the BDA for floppies */
+ if (drive & 0x80) {
+ c += probe_int13_ah(drive, 0x08);
+ c += probe_int13_ah(drive, 0x15);
+ c += probe_int13_ah(drive, 0x41);
+ }
+ c += probe_bda_drive(drive);
+ return c;
+}
+
+/*
+ * We will probe a contiguous range of BIOS drive, starting with drive
+ * number 'start'. We probe with a few different methods, and return
+ * the first drive which doesn't respond to any of the probes.
+ */
+uint8_t probe_drive_range(uint8_t start)
+{
+ uint8_t drive = start;
+ while (probe_drive(drive)) {
+ drive++;
+ /* Check for passing the floppy/HDD boundary */
+ if ((drive & 0x7F) == 0)
+ break;
+ }
+ return drive;
+}
diff --git a/contrib/syslinux-4.02/memdisk/dskprobe.h b/contrib/syslinux-4.02/memdisk/dskprobe.h
new file mode 100644
index 0000000..99bfa66
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/dskprobe.h
@@ -0,0 +1,21 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * dskprobe.h
+ *
+ * Routines for probing BIOS disk drives
+ */
+
+#include <stdint.h>
+
+extern uint8_t probe_drive_range(uint8_t);
diff --git a/contrib/syslinux-4.02/memdisk/e820.h b/contrib/syslinux-4.02/memdisk/e820.h
new file mode 100644
index 0000000..ee956fb
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/e820.h
@@ -0,0 +1,33 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2008 H. Peter Anvin - 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * e820.h
+ *
+ * Common routines for e820 memory map management
+ */
+
+#include <stdint.h>
+
+struct e820range {
+ uint64_t start;
+ uint32_t type;
+} __attribute__ ((packed));
+
+extern struct e820range ranges[];
+extern int nranges;
+extern uint32_t dos_mem, low_mem, high_mem;
+
+extern void e820map_init(void);
+extern void insertrange(uint64_t, uint64_t, uint32_t);
+extern void get_mem(void);
+extern void parse_mem(void);
diff --git a/contrib/syslinux-4.02/memdisk/e820data b/contrib/syslinux-4.02/memdisk/e820data
new file mode 100644
index 0000000..14320aa
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/e820data
@@ -0,0 +1,15 @@
+0000000000000000 000000000009bc00 1 1
+000000000009bc00 0000000000004400 2 1
+00000000000e9800 0000000000016800 2 1
+00000000000e9800 000000000000b400 2 1
+00000000000f5000 000000000000b000 2 9
+0000000000100000 0000000006ee0000 1 1
+0000000006fe0000 000000000000fc00 3 1
+0000000006fefc00 0000000000000400 4 1
+0000000006ff0000 0000000000002000 2 1
+0000000006ff2000 000000000000e000 1 1
+0000000007000000 0000000000100000 2 1
+00000000fff00000 0000000000100000 2 1
+
+0000000000586000 0000000000168000 2 1
+000000000009ba00 0000000000000200 2 1
diff --git a/contrib/syslinux-4.02/memdisk/e820func.c b/contrib/syslinux-4.02/memdisk/e820func.c
new file mode 100644
index 0000000..13c0a6f
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/e820func.c
@@ -0,0 +1,107 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2008 H. Peter Anvin - 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * e820func.c
+ *
+ * E820 range database manager
+ */
+
+#include <stdint.h>
+#ifdef TEST
+#include <string.h>
+#else
+#include "memdisk.h" /* For memset() */
+#endif
+#include "e820.h"
+
+#define MAXRANGES 1024
+/* All of memory starts out as one range of "indeterminate" type */
+struct e820range ranges[MAXRANGES];
+int nranges;
+
+void e820map_init(void)
+{
+ memset(ranges, 0, sizeof(ranges));
+ nranges = 1;
+ ranges[1].type = -1U;
+}
+
+static void insertrange_at(int where, uint64_t start, uint32_t type)
+{
+ int i;
+
+ for (i = nranges; i > where; i--)
+ ranges[i] = ranges[i - 1];
+
+ ranges[where].start = start;
+ ranges[where].type = type;
+
+ nranges++;
+ ranges[nranges].start = 0ULL;
+ ranges[nranges].type = -1U;
+}
+
+void insertrange(uint64_t start, uint64_t len, uint32_t type)
+{
+ uint64_t last;
+ uint32_t oldtype;
+ int i, j;
+
+ /* Remove this to make len == 0 mean all of memory */
+ if (len == 0)
+ return; /* Nothing to insert */
+
+ last = start + len - 1; /* May roll over */
+
+ i = 0;
+ oldtype = -2U;
+ while (start > ranges[i].start && ranges[i].type != -1U) {
+ oldtype = ranges[i].type;
+ i++;
+ }
+
+ /* Consider the replacement policy. This current one is "overwrite." */
+
+ if (start < ranges[i].start || ranges[i].type == -1U)
+ insertrange_at(i++, start, type);
+
+ while (i == 0 || last > ranges[i].start - 1) {
+ oldtype = ranges[i].type;
+ ranges[i].type = type;
+ i++;
+ }
+
+ if (last < ranges[i].start - 1)
+ insertrange_at(i, last + 1, oldtype);
+
+ /* Now the map is correct, but quite possibly not optimal. Scan the
+ map for ranges which are redundant and remove them. */
+ i = j = 1;
+ oldtype = ranges[0].type;
+ while (i < nranges) {
+ if (ranges[i].type == oldtype) {
+ i++;
+ } else {
+ oldtype = ranges[i].type;
+ if (i != j)
+ ranges[j] = ranges[i];
+ i++;
+ j++;
+ }
+ }
+
+ if (i != j) {
+ ranges[j] = ranges[i]; /* Termination sentinel copy */
+ nranges -= (i - j);
+ }
+}
diff --git a/contrib/syslinux-4.02/memdisk/e820test.c b/contrib/syslinux-4.02/memdisk/e820test.c
new file mode 100644
index 0000000..0bd6c4c
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/e820test.c
@@ -0,0 +1,88 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2008 H. Peter Anvin - 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * e820hack.c
+ *
+ * Test of INT 15:E820 canonicalization/manipulation routine
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "e820.h"
+
+void *sys_bounce; /* Dummy */
+
+extern void parse_mem(void);
+extern uint32_t dos_mem, low_mem, high_mem;
+
+void __attribute__ ((noreturn)) die(void)
+{
+ abort();
+}
+
+void printranges(void)
+{
+ int i;
+
+ for (i = 0; i < nranges; i++) {
+ printf("%016llx %016llx %d\n",
+ ranges[i].start,
+ ranges[i + 1].start - ranges[i].start, ranges[i].type);
+ }
+}
+
+int main(void)
+{
+ uint64_t start, len;
+ uint32_t type;
+ char line[BUFSIZ], *p;
+
+ e820map_init();
+ printranges();
+
+ while (fgets(line, BUFSIZ, stdin)) {
+ p = strchr(line, ':');
+ p = p ? p + 1 : line;
+ if (sscanf(p, " %llx %llx %d", &start, &len, &type) == 3) {
+ putchar('\n');
+ printf("%016llx %016llx %d <-\n", start, len, type);
+ putchar('\n');
+ insertrange(start, len, type);
+ printranges();
+ }
+ }
+
+ parse_mem();
+
+ putchar('\n');
+ printf("DOS mem = %#10x (%u K)\n", dos_mem, dos_mem >> 10);
+ printf("Low mem = %#10x (%u K)\n", low_mem, low_mem >> 10);
+ printf("High mem = %#10x (%u K)\n", high_mem, high_mem >> 10);
+ putchar('\n');
+
+ /* Now, steal a chunk (2K) of DOS memory and make sure it registered OK */
+ insertrange(dos_mem - 2048, 2048, 2, 1); /* Type 2 = reserved */
+
+ printranges();
+ parse_mem();
+
+ putchar('\n');
+ printf("DOS mem = %#10x (%u K)\n", dos_mem, dos_mem >> 10);
+ printf("Low mem = %#10x (%u K)\n", low_mem, low_mem >> 10);
+ printf("High mem = %#10x (%u K)\n", high_mem, high_mem >> 10);
+ putchar('\n');
+
+ return 0;
+}
diff --git a/contrib/syslinux-4.02/memdisk/eltorito.c b/contrib/syslinux-4.02/memdisk/eltorito.c
new file mode 100644
index 0000000..7e0ba89
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/eltorito.c
@@ -0,0 +1,58 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * eltorito.c
+ *
+ * EDD-4 El Torito structures and debugging routines
+ */
+
+#include <stdint.h>
+#include "memdisk.h"
+#include "conio.h"
+#include "eltorito.h"
+
+#ifdef DBG_ELTORITO
+void eltorito_dump(uint32_t image)
+{
+ printf("-- El Torito dump --\n", image);
+
+ /* BVD starts at sector 17. */
+ struct edd4_bvd *bvd = (struct edd4_bvd *)(image + 17 * 2048);
+
+ printf("bvd.boot_rec_ind: 0x%02x\n", bvd->boot_rec_ind);
+ printf("bvd.iso9660_id: %c%c%c%c%c\n", bvd->iso9660_id[0],
+ bvd->iso9660_id[1], bvd->iso9660_id[2], bvd->iso9660_id[3],
+ bvd->iso9660_id[4]);
+ printf("bvd.ver: 0x%02x\n", bvd->ver);
+ printf("bvd.eltorito: %s\n", bvd->eltorito);
+ printf("bvd.boot_cat: 0x%08x\n", bvd->boot_cat);
+
+ struct edd4_bootcat *boot_cat =
+ (struct edd4_bootcat *)(image + bvd->boot_cat * 2048);
+
+ printf("boot_cat.validation_entry\n");
+ printf(" .header_id: 0x%02x\n", boot_cat->validation_entry.header_id);
+ printf(" .platform_id: 0x%02x\n", boot_cat->validation_entry.platform_id);
+ printf(" .id_string: %s\n", boot_cat->validation_entry.id_string);
+ printf(" .checksum: 0x%04x\n", boot_cat->validation_entry.checksum);
+ printf(" .key55: 0x%02x\n", boot_cat->validation_entry.key55);
+ printf(" .keyAA: 0x%02x\n", boot_cat->validation_entry.keyAA);
+ printf("boot_cat.initial_entry\n");
+ printf(" .header_id: 0x%02x\n", boot_cat->initial_entry.header_id);
+ printf(" .media_type: 0x%02x\n", boot_cat->initial_entry.media_type);
+ printf(" .load_seg: 0x%04x\n", boot_cat->initial_entry.load_seg);
+ printf(" .system_type: 0x%02x\n", boot_cat->initial_entry.system_type);
+ printf(" .sect_count: %d\n", boot_cat->initial_entry.sect_count);
+ printf(" .load_block: 0x%08x\n", boot_cat->initial_entry.load_block);
+}
+#endif
diff --git a/contrib/syslinux-4.02/memdisk/eltorito.h b/contrib/syslinux-4.02/memdisk/eltorito.h
new file mode 100644
index 0000000..494c4a1
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/eltorito.h
@@ -0,0 +1,80 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009-2010 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * eltorito.h
+ *
+ * EDD-4 El Torito structures and debugging routines
+ */
+
+#include <stdint.h>
+#include "compiler.h"
+
+/* EDD-4 Bootable Optical Disc Drive Boot Volume Descriptor */
+MEMDISK_PACKED_PREFIX
+struct edd4_bvd {
+ uint8_t boot_rec_ind; /* Boot Record Indicator */
+ uint8_t iso9660_id[5]; /* ISO9660 ID */
+ uint8_t ver; /* Descriptor Version */
+ uint8_t eltorito[32]; /* "EL TORITO" etc. */
+ uint8_t res1[32]; /* Reserved */
+ uint32_t boot_cat; /* Boot catalog sector */
+ uint8_t res2[1973]; /* Reserved */
+} MEMDISK_PACKED_POSTFIX;
+
+MEMDISK_PACKED_PREFIX
+struct validation_entry {
+ uint8_t header_id; /* Header ID */
+ uint8_t platform_id; /* Platform ID */
+ uint16_t res1; /* Reserved */
+ uint8_t id_string[24]; /* Manufacturer */
+ uint16_t checksum; /* Sums with whole record to zero */
+ uint8_t key55; /* Key byte 0x55 */
+ uint8_t keyAA; /* Key byte 0xAA */
+} MEMDISK_PACKED_POSTFIX;
+
+MEMDISK_PACKED_PREFIX
+struct initial_entry {
+ uint8_t header_id; /* Header ID */
+ uint8_t media_type; /* Media type */
+ uint16_t load_seg; /* Load segment */
+ uint8_t system_type; /* (Filesystem ID) */
+ uint8_t res1; /* Reserved */
+ uint16_t sect_count; /* Emulated sectors to load */
+ uint32_t load_block; /* Starting sector of image */
+ uint8_t res2[4]; /* Reserved */
+} MEMDISK_PACKED_POSTFIX;
+
+/* EDD-4 Bootable Optical Disc Drive Boot Catalog (fixed-size portions) */
+MEMDISK_PACKED_PREFIX
+struct edd4_bootcat {
+ struct validation_entry validation_entry;
+ struct initial_entry initial_entry;
+} MEMDISK_PACKED_POSTFIX;
+
+/* EDD-4 CD Specification Packet */
+MEMDISK_PACKED_PREFIX
+struct edd4_cd_pkt {
+ uint8_t size; /* Packet size */
+ uint8_t type; /* Boot media type (flags) */
+ uint8_t driveno; /* INT 13h drive number */
+ uint8_t controller; /* Controller index */
+ uint32_t start; /* Starting LBA of image */
+ uint16_t devno; /* Device number */
+ uint16_t userbuf; /* User buffer segment */
+ uint16_t load_seg; /* Load segment */
+ uint16_t sect_count; /* Emulated sectors to load */
+ uint8_t geom1; /* Cylinders bits 0 thru 7 */
+ uint8_t geom2; /* Sects/track 0 thru 5, cyls 8, 9 */
+ uint8_t geom3; /* Heads */
+} MEMDISK_PACKED_POSTFIX;
+
diff --git a/contrib/syslinux-4.02/memdisk/fdgeo.pl b/contrib/syslinux-4.02/memdisk/fdgeo.pl
new file mode 100755
index 0000000..b76727d
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/fdgeo.pl
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+#
+# Try automatic generation of geometries
+#
+
+($k) = @ARGV;
+$sec = int($k*2+0.5);
+
+if ($sec < 320*2) {
+ $c = 40;
+ $h = 1;
+ $type = 1;
+} elsif ($sec < 640*2) {
+ $c = 40;
+ $h = 2;
+ $type = 1;
+} elsif ($sec < 1200*2) {
+ $c = 80;
+ $h = 2;
+ $type = 3;
+} elsif ($sec < 1440*2) {
+ $c = 80;
+ $h = 2;
+ $type = 2;
+} elsif ($sec < 2880*2) {
+ $c = 80;
+ $h = 2;
+ $type = 4;
+} elsif ($sec < 4096*2) {
+ $c = 80;
+ $h = 2;
+ $type = 6;
+} else {
+ printf "%.1fK, %d sectors: ", $sec/2, $sec;
+ print "Considered a hard disk\n";
+ exit 2;
+}
+
+$ok = 0;
+while ($c < 256) {
+ $s = int($sec/($c*$h)+0.5);
+ if ($s <= 63 && $sec == $c*$h*$s) {
+ $ok = 1;
+ last;
+ }
+ $c++;
+}
+
+printf "%.1fK, %d sectors: ", $sec/2, $sec;
+if ($ok) {
+ print "c=$c, h=$h, s=$s, type=$type\n";
+ exit 0;
+} else {
+ print "No valid geometry found (MEMDISK will fake it)\n";
+ exit 1;
+}
diff --git a/contrib/syslinux-4.02/memdisk/inflate.c b/contrib/syslinux-4.02/memdisk/inflate.c
new file mode 100644
index 0000000..e7825f0
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/inflate.c
@@ -0,0 +1,1026 @@
+#define DEBG(x)
+#define DEBG1(x)
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993 */
+
+/*
+ * Adapted for booting Linux by Hannu Savolainen 1993
+ * based on gzip-1.0.3
+ *
+ * Nicolas Pitre <nico@cam.org>, 1999/04/14 :
+ * Little mods for all variable to reside either into rodata or bss segments
+ * by marking constant variables with 'const' and initializing all the others
+ * at run-time only. This allows for the kernel uncompressor to run
+ * directly from Flash or ROM memory on embedded systems.
+ *
+ * Adapted for MEMDISK by H. Peter Anvin, April 2003
+ */
+
+/*
+ Inflate deflated (PKZIP's method 8 compressed) data. The compression
+ method searches for as much of the current string of bytes (up to a
+ length of 258) in the previous 32 K bytes. If it doesn't find any
+ matches (of at least length 3), it codes the next byte. Otherwise, it
+ codes the length of the matched string and its distance backwards from
+ the current position. There is a single Huffman code that codes both
+ single bytes (called "literals") and match lengths. A second Huffman
+ code codes the distance information, which follows a length code. Each
+ length or distance code actually represents a base value and a number
+ of "extra" (sometimes zero) bits to get to add to the base value. At
+ the end of each deflated block is a special end-of-block (EOB) literal/
+ length code. The decoding process is basically: get a literal/length
+ code; if EOB then done; if a literal, emit the decoded byte; if a
+ length then get the distance and emit the referred-to bytes from the
+ sliding window of previously emitted data.
+
+ There are (currently) three kinds of inflate blocks: stored, fixed, and
+ dynamic. The compressor deals with some chunk of data at a time, and
+ decides which method to use on a chunk-by-chunk basis. A chunk might
+ typically be 32 K or 64 K. If the chunk is incompressible, then the
+ "stored" method is used. In this case, the bytes are simply stored as
+ is, eight bits per byte, with none of the above coding. The bytes are
+ preceded by a count, since there is no longer an EOB code.
+
+ If the data is compressible, then either the fixed or dynamic methods
+ are used. In the dynamic method, the compressed data is preceded by
+ an encoding of the literal/length and distance Huffman codes that are
+ to be used to decode this block. The representation is itself Huffman
+ coded, and so is preceded by a description of that code. These code
+ descriptions take up a little space, and so for small blocks, there is
+ a predefined set of codes, called the fixed codes. The fixed method is
+ used if the block codes up smaller that way (usually for quite small
+ chunks), otherwise the dynamic method is used. In the latter case, the
+ codes are customized to the probabilities in the current block, and so
+ can code it much better than the pre-determined fixed codes.
+
+ The Huffman codes themselves are decoded using a multi-level table
+ lookup, in order to maximize the speed of decoding plus the speed of
+ building the decoding tables. See the comments below that precede the
+ lbits and dbits tuning parameters.
+ */
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarly, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #";
+#endif
+
+#define slide window
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model).
+ Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
+ means that v is a literal, 16 < e < 32 means that v is a pointer to
+ the next table, which codes e - 16 bits, and lastly e == 99 indicates
+ an unused code. If a code with e == 99 is looked up, this implies an
+ error in the data. */
+struct huft {
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+/* Function prototypes */
+STATIC int huft_build OF((unsigned *, unsigned, unsigned,
+ const ush *, const ush *, struct huft **, int *));
+STATIC int huft_free OF((struct huft *));
+STATIC int inflate_codes OF((struct huft *, struct huft *, int, int));
+STATIC int inflate_stored OF((void));
+STATIC int inflate_fixed OF((void));
+STATIC int inflate_dynamic OF((void));
+STATIC int inflate_block OF((int *));
+STATIC int inflate OF((void));
+
+/* The inflate algorithm uses a sliding 32 K byte window on the uncompressed
+ stream to find repeated byte strings. This is implemented here as a
+ circular buffer. The index is updated simply by incrementing and then
+ ANDing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32 K area. It is assumed
+ to be usable as if it were declared "uch slide[32768];" or as just
+ "uch *slide;" and then malloc'ed in the latter case. The definition
+ must be in unzip.h, included above. */
+/* unsigned wp; current position in slide */
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static const unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+};
+
+static const ush cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+};
+
+ /* note: see note #13 above about the 258 in this list. */
+static const ush cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
+}; /* 99==invalid */
+
+static const ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577
+};
+
+static const ush cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13
+};
+
+/* Macros for inflate() bit peeking and grabbing.
+ The usage is:
+
+ NEEDBITS(j)
+ x = b & mask_bits[j];
+ DUMPBITS(j)
+
+ where NEEDBITS makes sure that b has at least j bits in it, and
+ DUMPBITS removes the bits from b. The macros use the variable k
+ for the number of bits in b. Normally, b and k are register
+ variables for speed, and are initialized at the beginning of a
+ routine that uses these macros from a global bit buffer and count.
+
+ If we assume that EOB will be the longest code, then we will never
+ ask for bits with NEEDBITS that are beyond the end of the stream.
+ So, NEEDBITS should not read any more bytes than are needed to
+ meet the request. Then no bytes need to be "returned" to the buffer
+ at the end of the last block.
+
+ However, this assumption is not true for fixed blocks--the EOB code
+ is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+ (The EOB code is shorter than other codes because fixed blocks are
+ generally short. So, while a block always has an EOB, many other
+ literal/length codes have a significantly lower probability of
+ showing up at all.) However, by making the first table have a
+ lookup of seven bits, the EOB code will be found in that first
+ lookup, and so will not require that too many bits be pulled from
+ the stream.
+ */
+
+STATIC ulg bb; /* bit buffer */
+STATIC unsigned bk; /* bits in bit buffer */
+
+STATIC const ush mask_bits[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#define NEXTBYTE() (uch)get_byte()
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+STATIC const int lbits = 9; /* bits in base literal/length lookup table */
+STATIC const int dbits = 6; /* bits in base distance lookup table */
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+STATIC unsigned hufts; /* track memory usage */
+
+STATIC int huft_build(b, n, s, d, e, t, m)
+unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
+unsigned n; /* number of codes (assumed <= N_MAX) */
+unsigned s; /* number of simple-valued codes (0..s-1) */
+const ush *d; /* list of base values for non-simple codes */
+const ush *e; /* list of extra bits for non-simple codes */
+struct huft **t; /* result: starting table */
+int *m; /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return zero on success, one if
+ the given code set is incomplete (the tables are still built in this
+ case), two if the input is invalid (all zero length codes or an
+ oversubscribed set of lengths), and three if not enough memory. */
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX + 1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register unsigned i; /* counter, current code */
+ register unsigned j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register unsigned *p; /* pointer into c[], b[], or v[] */
+ register struct huft *q; /* points to current table */
+ struct huft r; /* table entry for structure assignment */
+ struct huft *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX + 1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+ DEBG("huft1 ");
+
+ /* Generate counts for each bit length */
+ memzero(c, sizeof(c));
+ p = b;
+ i = n;
+ do {
+ Tracecv(*p,
+ (stderr,
+ (n - i >= ' '
+ && n - i <= '~' ? "%c %d\n" : "0x%x %d\n"), n - i, *p));
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* Can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) { /* null input--all zero length codes */
+ *t = (struct huft *)NULL;
+ *m = 0;
+ return 0;
+ }
+
+ DEBG("huft2 ");
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned)l > i)
+ l = i;
+ *m = l;
+
+ DEBG("huft3 ");
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ if ((y -= c[i]) < 0)
+ return 2;
+ c[i] += y;
+
+ DEBG("huft4 ");
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1;
+ xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+ DEBG("huft5 ");
+
+ /* Make a table of values in order of bit lengths */
+ p = b;
+ i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+ DEBG("h6 ");
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (struct huft *)NULL; /* just to keep compilers happy */
+ q = (struct huft *)NULL; /* ditto */
+ z = 0; /* ditto */
+ DEBG("h6a ");
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++) {
+ DEBG("h6b ");
+ a = c[k];
+ while (a--) {
+ DEBG("h6b1 ");
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l) {
+ DEBG1("1 ");
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */
+ DEBG1("2 ");
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) { /* try smaller tables up to z bits */
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ DEBG1("3 ");
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q =
+ (struct huft *)malloc((z + 1) * sizeof(struct huft))) ==
+ (struct huft *)NULL) {
+ if (h)
+ huft_free(u[0]);
+ return 3; /* not enough memory */
+ }
+ DEBG1("4 ");
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = (struct huft *)NULL;
+ u[h] = ++q; /* table starts after link */
+
+ DEBG1("5 ");
+ /* connect to last table, if there is one */
+ if (h) {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (uch) l; /* bits to dump before this table */
+ r.e = (uch) (16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h - 1][j] = r; /* connect to last table */
+ }
+ DEBG1("6 ");
+ }
+ DEBG("h6c ");
+
+ /* set up table entry in r */
+ r.b = (uch) (k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s) {
+ r.e = (uch) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (ush) (*p); /* simple code is just the value */
+ p++; /* one compiler does not like *p++ */
+ } else {
+ r.e = (uch) e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+ DEBG("h6d ");
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h]) {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ DEBG("h6e ");
+ }
+ DEBG("h6f ");
+ }
+
+ DEBG("huft7 ");
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+STATIC int huft_free(t)
+struct huft *t; /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register struct huft *p, *q;
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != (struct huft *)NULL) {
+ q = (--p)->v.t;
+ free((char *)p);
+ p = q;
+ }
+ return 0;
+}
+
+STATIC int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td; /* literal/length and distance decoder tables */
+int bl, bd; /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+ Return an error code or zero if it all goes ok. */
+{
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ for (;;) { /* do until end of block */
+ NEEDBITS((unsigned)bl)
+ if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ if (e == 16) { /* then it's a literal */
+ slide[w++] = (uch) t->v.n;
+ Tracevv((stderr, "%c", slide[w - 1]));
+ if (w == WSIZE) {
+ flush_output(w);
+ w = 0;
+ }
+ } else { /* it's an EOB or a length */
+
+ /* exit if end of block */
+ if (e == 15)
+ break;
+
+ /* get length of block to copy */
+ NEEDBITS(e)
+ n = t->v.n + ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e);
+
+ /* decode distance of block to copy */
+ NEEDBITS((unsigned)bd)
+ if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e =
+ (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ NEEDBITS(e)
+ d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "\\[%d,%d]", w - d, n));
+
+ /* do the copy */
+ do {
+ n -= (e =
+ (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+ if (w - d >= e) { /* (this test assumes unsigned comparison) */
+ memcpy(slide + w, slide + d, e);
+ w += e;
+ d += e;
+ } else /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+ do {
+ slide[w++] = slide[d++];
+ Tracevv((stderr, "%c", slide[w - 1]));
+ } while (--e);
+ if (w == WSIZE) {
+ flush_output(w);
+ w = 0;
+ }
+ } while (n);
+ }
+ }
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ /* done */
+ return 0;
+}
+
+STATIC int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+ unsigned n; /* number of bytes in block */
+ unsigned w; /* current window position */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+ DEBG("<stor");
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+ /* go to byte boundary */
+ n = k & 7;
+ DUMPBITS(n);
+
+ /* get the length and its complement */
+ NEEDBITS(16)
+ n = ((unsigned)b & 0xffff);
+ DUMPBITS(16)
+ NEEDBITS(16)
+ if (n != (unsigned)((~b) & 0xffff))
+ return 1; /* error in compressed data */
+ DUMPBITS(16)
+
+ /* read and output the compressed data */
+ while (n--) {
+ NEEDBITS(8)
+ slide[w++] = (uch) b;
+ if (w == WSIZE) {
+ flush_output(w);
+ w = 0;
+ }
+ DUMPBITS(8)
+ }
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ DEBG(">");
+ return 0;
+}
+
+STATIC int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block. We should
+ either replace this with a custom decoder, or at least precompute the
+ Huffman tables. */
+{
+ int i; /* temporary variable */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned l[288]; /* length list for huft_build */
+
+ DEBG("<fix");
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ l[i] = 8;
+ for (; i < 256; i++)
+ l[i] = 9;
+ for (; i < 280; i++)
+ l[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ l[i] = 8;
+ bl = 7;
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+ return i;
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ bd = 5;
+ if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) {
+ huft_free(tl);
+
+ DEBG(">");
+ return i;
+ }
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+STATIC int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+ unsigned ll[288 + 32]; /* literal/length and distance code lengths */
+#else
+ unsigned ll[286 + 30]; /* literal/length and distance code lengths */
+#endif
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+ DEBG("<dyn");
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+ /* read in table lengths */
+ NEEDBITS(5)
+ nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
+ DUMPBITS(5)
+ NEEDBITS(5)
+ nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
+ DUMPBITS(5)
+ NEEDBITS(4)
+ nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
+ DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+ if (nl > 288 || nd > 32)
+#else
+ if (nl > 286 || nd > 30)
+#endif
+ return 1; /* bad lengths */
+
+ DEBG("dyn1 ");
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++) {
+ NEEDBITS(3)
+ ll[border[j]] = (unsigned)b & 7;
+ DUMPBITS(3)
+ }
+ for (; j < 19; j++)
+ ll[border[j]] = 0;
+
+ DEBG("dyn2 ");
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) {
+ if (i == 1)
+ huft_free(tl);
+ return i; /* incomplete code set */
+ }
+
+ DEBG("dyn3 ");
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned)i < n) {
+ NEEDBITS((unsigned)bl)
+ j = (td = tl + ((unsigned)b & m))->b;
+ DUMPBITS(j)
+ j = td->v.n;
+ if (j < 16) /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ else if (j == 16) { /* repeat last length 3 to 6 times */
+ NEEDBITS(2)
+ j = 3 + ((unsigned)b & 3);
+ DUMPBITS(2)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = l;
+ } else if (j == 17) { /* 3 to 10 zero length codes */
+ NEEDBITS(3)
+ j = 3 + ((unsigned)b & 7);
+ DUMPBITS(3)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ } else { /* j == 18: 11 to 138 zero length codes */
+
+ NEEDBITS(7)
+ j = 11 + ((unsigned)b & 0x7f);
+ DUMPBITS(7)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+ DEBG("dyn4 ");
+
+ /* free decoding table for trees */
+ huft_free(tl);
+
+ DEBG("dyn5 ");
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+ DEBG("dyn5a ");
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) {
+ DEBG("dyn5b ");
+ if (i == 1) {
+ error(" incomplete literal tree");
+ huft_free(tl);
+ }
+ return i; /* incomplete code set */
+ }
+ DEBG("dyn5c ");
+ bd = dbits;
+ if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) {
+ DEBG("dyn5d ");
+ if (i == 1) {
+ error(" incomplete distance tree");
+#ifdef PKZIP_BUG_WORKAROUND
+ i = 0;
+ }
+#else
+ huft_free(td);
+ }
+ huft_free(tl);
+ return i; /* incomplete code set */
+#endif
+ }
+
+ DEBG("dyn6 ");
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+ DEBG("dyn7 ");
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+
+ DEBG(">");
+ return 0;
+}
+
+STATIC int inflate_block(e)
+int *e; /* last block flag */
+/* decompress an inflated block */
+{
+ unsigned t; /* block type */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+ DEBG("<blk");
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+ /* read in last block bit */
+ NEEDBITS(1)
+ * e = (int)b & 1;
+ DUMPBITS(1)
+
+ /* read in block type */
+ NEEDBITS(2)
+ t = (unsigned)b & 3;
+ DUMPBITS(2)
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+ /* inflate that block type */
+ if (t == 2)
+ return inflate_dynamic();
+ if (t == 0)
+ return inflate_stored();
+ if (t == 1)
+ return inflate_fixed();
+
+ DEBG(">");
+
+ /* bad block type */
+ return 2;
+}
+
+STATIC int inflate()
+/* decompress an inflated entry */
+{
+ int e; /* last block flag */
+ int r; /* result code */
+ unsigned h; /* maximum struct huft's malloc'ed */
+ void *ptr;
+
+ /* initialize window, bit buffer */
+ wp = 0;
+ bk = 0;
+ bb = 0;
+
+ /* decompress until the last block */
+ h = 0;
+ do {
+ hufts = 0;
+ gzip_mark(&ptr);
+ if ((r = inflate_block(&e)) != 0) {
+ gzip_release(&ptr);
+ return r;
+ }
+ gzip_release(&ptr);
+ if (hufts > h)
+ h = hufts;
+ } while (!e);
+
+ /* Undo too much lookahead. The next read will be byte aligned so we
+ * can discard unused bits in the last meaningful byte.
+ */
+ while (bk >= 8) {
+ bk -= 8;
+ unget_byte();
+ }
+
+ /* flush out slide */
+ flush_output(wp);
+
+ /* return success */
+#ifdef DEBUG
+ fprintf(stderr, "<%u> ", h);
+#endif /* DEBUG */
+ return 0;
+}
+
+/**********************************************************************
+ *
+ * The following are support routines for inflate.c
+ *
+ **********************************************************************/
+
+static ulg crc_32_tab[256];
+static ulg crc; /* initialized in makecrc() so it'll reside in bss */
+#define CRC_VALUE (crc ^ 0xffffffffL)
+
+/*
+ * Code to compute the CRC-32 table. Borrowed from
+ * gzip-1.0.3/makecrc.c.
+ */
+
+static void makecrc(void)
+{
+/* Not copyrighted 1990 Mark Adler */
+
+ unsigned long c; /* crc shift register */
+ unsigned long e; /* polynomial exclusive-or pattern */
+ int i; /* counter for all possible eight bit values */
+ int k; /* byte being shifted into crc apparatus */
+
+ /* terms of polynomial defining this crc (except x^32): */
+ static const int p[] = { 0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26 };
+
+ /* Make exclusive-or pattern from polynomial */
+ e = 0;
+ for (i = 0; i < sizeof(p) / sizeof(int); i++)
+ e |= 1L << (31 - p[i]);
+
+ crc_32_tab[0] = 0;
+
+ for (i = 1; i < 256; i++) {
+ c = 0;
+ for (k = i | 256; k != 1; k >>= 1) {
+ c = c & 1 ? (c >> 1) ^ e : c >> 1;
+ if (k & 1)
+ c ^= e;
+ }
+ crc_32_tab[i] = c;
+ }
+
+ /* this is initialized here so this code could reside in ROM */
+ crc = (ulg) 0xffffffffL; /* shift register contents */
+}
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+/*
+ * Do the uncompression!
+ */
+int gunzip(void)
+{
+ int res;
+
+ /* Decompress */
+ if ((res = inflate())) {
+ switch (res) {
+ case 0:
+ break;
+ case 1:
+ error("invalid compressed format (err=1)");
+ break;
+ case 2:
+ error("invalid compressed format (err=2)");
+ break;
+ case 3:
+ error("out of memory");
+ break;
+ default:
+ error("invalid compressed format (other)");
+ }
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/contrib/syslinux-4.02/memdisk/memcpy.S b/contrib/syslinux-4.02/memdisk/memcpy.S
new file mode 100644
index 0000000..6b986a0
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/memcpy.S
@@ -0,0 +1,86 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * memcpy.S
+ *
+ * Reasonably efficient memcpy, using aligned transfers at least
+ * for the destination operand.
+ */
+
+ .text
+ .globl memcpy
+ .type memcpy, @function
+memcpy:
+ jecxz 1f
+
+ pushl %esi
+ pushl %edi
+ pushl %eax /* Return value */
+
+ movl %eax,%edi
+ movl %edx,%esi
+
+ /* Initial alignment */
+ movl %edi,%edx
+ shrl $1,%edx
+ jnc 11f
+ movsb
+ decl %ecx
+11:
+ movb %cl,%al
+ cmpl $2,%ecx
+ jb 13f
+
+ shrl $1,%edx
+ jnc 12f
+ movsw
+ subl $2,%ecx
+12:
+ /* Bulk transfer */
+ movb %cl,%al
+ shrl $2,%ecx
+ rep; movsl
+
+ /* Final alignment */
+ testb $2,%al
+ jz 14f
+ movsw
+13:
+14:
+ testb $1,%al
+ jz 15f
+ movsb
+15:
+
+ popl %eax /* Return value */
+ popl %edi
+ popl %esi
+1:
+ ret
+
+ .size memcpy, .-memcpy
diff --git a/contrib/syslinux-4.02/memdisk/memdisk.h b/contrib/syslinux-4.02/memdisk/memdisk.h
new file mode 100644
index 0000000..b6b277a
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/memdisk.h
@@ -0,0 +1,137 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2008 H. Peter Anvin - 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * memdisk.h
+ *
+ * Miscellaneous header definitions
+ */
+
+#ifndef MEMDISK_H
+#define MEMDISK_H
+
+#include <stddef.h>
+
+/* We use the com32 interface for calling 16-bit code */
+#include <com32.h>
+
+#define __cdecl __attribute__((cdecl,regparm(0)))
+
+void __cdecl intcall(uint8_t, com32sys_t *, com32sys_t *);
+
+/* Structure passed in from the real-mode code */
+struct real_mode_args {
+ uint32_t rm_return;
+ uint32_t rm_intcall;
+ uint32_t rm_bounce;
+ uint32_t rm_base;
+ uint32_t rm_handle_interrupt;
+ uint32_t rm_gdt;
+ uint32_t rm_size;
+ uint32_t rm_pmjmp;
+ uint32_t rm_rmjmp;
+};
+extern struct real_mode_args rm_args;
+#define sys_bounce ((void *)rm_args.rm_bounce)
+
+/* This is the header in the boot sector/setup area */
+struct setup_header {
+ char cmdline[0x1f1];
+ uint8_t setup_secs;
+ uint16_t syssize;
+ uint16_t swap_dev;
+ uint16_t ram_size;
+ uint16_t vid_mode;
+ uint16_t root_dev;
+ uint16_t boot_flag;
+ uint16_t jump;
+ char header[4];
+ uint16_t version;
+ uint32_t realmode_swtch;
+ uint32_t start_sys;
+ uint8_t type_of_loader;
+ uint8_t loadflags;
+ uint16_t setup_move_size;
+ uint32_t code32_start;
+ uint32_t ramdisk_image;
+ uint32_t ramdisk_size;
+ uint32_t bootsect_kludge;
+ uint16_t head_end_ptr;
+ uint16_t pad1;
+ uint32_t cmd_line_ptr;
+ uint32_t initrd_addr_max;
+ uint32_t esdi;
+ uint32_t edx;
+ uint32_t sssp;
+ uint32_t csip;
+};
+#define shdr ((struct setup_header *)rm_args.rm_base)
+
+/* Standard routines */
+void *memcpy(void *, const void *, size_t);
+void *memset(void *, int, size_t);
+void *memmove(void *, const void *, size_t);
+
+#define strcpy(a,b) __builtin_strcpy(a,b)
+
+static inline size_t strlen(const char *__a)
+{
+ const char *__D;
+ size_t __c;
+
+asm("repne;scasb":"=D"(__D), "=c"(__c)
+: "D"(__a), "c"(-1), "a"(0), "m"(*__a));
+
+ return __D - __a - 1;
+}
+
+/* memcpy() but returns a pointer to end of buffer */
+static inline void *mempcpy(void *__d, const void *__s, unsigned int __n)
+{
+ memcpy(__d, __s, __n);
+ return (void *)((char *)__d + __n);
+}
+
+/* memcmp() */
+static inline int memcmp(const void *__a, const void *__b, unsigned int __n)
+{
+ const unsigned char *__aa = __a;
+ const unsigned char *__bb = __b;
+ int __d;
+
+ while (__n--) {
+ __d = *__bb++ - *__aa++;
+ if (__d)
+ return __d;
+ }
+
+ return 0;
+}
+
+static inline void sti(void)
+{
+ asm volatile("sti");
+}
+
+static inline void cli(void)
+{
+ asm volatile("cli");
+}
+
+/* Decompression */
+extern int check_zip(void *indata, uint32_t size, uint32_t * zbytes_p,
+ uint32_t * dbytes_p, uint32_t * orig_crc,
+ uint32_t * offset_p);
+extern void *unzip(void *indata, uint32_t zbytes, uint32_t dbytes,
+ uint32_t orig_crc, void *target);
+
+#endif
diff --git a/contrib/syslinux-4.02/memdisk/memdisk.inc b/contrib/syslinux-4.02/memdisk/memdisk.inc
new file mode 100644
index 0000000..91040ba
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/memdisk.inc
@@ -0,0 +1,1189 @@
+; -*- fundamental -*- (asm-mode sucks)
+; ****************************************************************************
+;
+; memdisk.inc
+;
+; A program to emulate an INT 13h disk BIOS from a "disk" in extended
+; memory.
+;
+; Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
+; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+; Portions copyright 2009 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.
+;
+; ****************************************************************************
+
+%include "../version.gen"
+
+; %define DEBUG_TRACERS ; Uncomment to get debugging tracers
+
+%ifdef DEBUG_TRACERS
+
+%macro TRACER 1
+ call debug_tracer
+ db %1
+%endmacro
+%macro WRITEHEX2 0-1 al
+%ifnidni %1,al
+ push ax
+ mov al,%1
+ call writehex2
+ pop ax
+%else
+ call writehex2
+%endif
+%endmacro
+%macro WRITEHEX4 0-1 ax
+%ifnidni %1,ax
+ push ax
+ mov ax,%1
+ call writehex4
+ pop ax
+%else
+ call writehex4
+%endif
+%endmacro
+%macro WRITEHEX8 0-1 eax
+%ifnidni %1,eax
+ push eax
+ mov eax,%1
+ call writehex8
+ pop eax
+%else
+ call writehex8
+%endif
+%endmacro
+
+%else ; DEBUG_TRACERS
+
+%macro TRACER 1
+%endmacro
+%macro WRITEHEX2 0-1
+%endmacro
+%macro WRITEHEX4 0-1
+%endmacro
+%macro WRITEHEX8 0-1
+%endmacro
+
+%endif ; DEBUG_TRACERS
+
+; Flags we test our configuration against
+%define CONFIG_READONLY 0x01
+%define CONFIG_RAW 0x02
+%define CONFIG_SAFEINT 0x04
+%define CONFIG_BIGRAW 0x08 ; MUST be 8!
+
+ org 0h
+
+%define SECTORSIZE (1 << SECTORSIZE_LG2)
+
+ ; Parameter registers definition; this is the definition
+ ; of the stack frame.
+%define P_DS word [bp+34]
+%define P_ES word [bp+32]
+%define P_EAX dword [bp+28]
+%define P_HAX word [bp+30]
+%define P_AX word [bp+28]
+%define P_AL byte [bp+28]
+%define P_AH byte [bp+29]
+%define P_ECX dword [bp+24]
+%define P_HCX word [bp+26]
+%define P_CX word [bp+24]
+%define P_CL byte [bp+24]
+%define P_CH byte [bp+25]
+%define P_EDX dword [bp+20]
+%define P_HDX word [bp+22]
+%define P_DX word [bp+20]
+%define P_DL byte [bp+20]
+%define P_DH byte [bp+21]
+%define P_EBX dword [bp+16]
+%define P_HBX word [bp+18]
+%define P_HBXL byte [bp+18]
+%define P_BX word [bp+16]
+%define P_BL byte [bp+16]
+%define P_BH byte [bp+17]
+%define P_EBP dword [bp+8]
+%define P_BP word [bp+8]
+%define P_ESI dword [bp+4]
+%define P_SI word [bp+4]
+%define P_EDI dword [bp]
+%define P_DI word [bp]
+
+ section .text
+ ; These pointers are used by the installer and
+ ; must be first in the binary
+Pointers: dw Int13Start
+ dw Int15Start
+ dw MemDisk_Info ; Portions are patched by installer
+ dw TotalSize
+ dw IretPtr
+
+IretPtr equ Int13Start.iret
+Int13Start:
+ jmp strict near .SafeHookEnd ; 3-byte jump
+ db '$INT13SF' ; Signature for "safe hook"
+ db 'MEMDISK ' ; Vendor ID
+ dd 0 ; SEG:OFF of previous INT 13h hook
+ ; Must be filled in by installer
+ dd 0 ; "Safe hook" flags
+; ---- "Safe hook" structure ends here ---
+
+; This next field should be guaranteed at this position after the
+; "safe hook" structure. This allows for a MEMDISK OS driver to
+; immediately find out the particular parameters using the mBFT
+; and MDI structures. This binary will have the offset to the mBFT
+; in this field to begin with, so the installer knows where the mBFT
+; is. This is akin to the "Pointers" section above. The installer
+; will refill this field with the physical address of the mBFT for
+; future consumers, such as OS drivers.
+ dd mBFT ; Offset from hook to the mBFT
+
+.SafeHookEnd:
+ cmp word [cs:Recursive],0
+ jne recursive
+
+ ; Swap stack
+ mov [cs:Stack],esp
+ mov [cs:Stack+4],ss
+ mov [cs:SavedAX],ax
+ mov ax,cs
+ mov ss,ax
+ mov sp,[cs:MyStack]
+
+%if ELTORITO
+ cmp word [cs:SavedAX],4a00h ; El Torito function?
+ jae our_drive ; We grab it
+%endif
+ ; See if DL points to our class of device (FD, HD)
+ push dx
+ push dx
+ xor dl,[cs:DriveNo]
+ pop dx
+ js .nomatch ; If SF=0, we have a class match here
+ ; 0x00 the sign bit for FD
+ ; 0x80 the sign bit for HD
+ jz our_drive ; If ZF=1, we have an exact match
+ cmp dl,[cs:DriveNo]
+ jb .nomatch ; Drive < Our drive
+ cmp dl,[cs:DriveShiftLimit]
+ jae .nomatch ; Drive > The maximum drive
+ ; number that we will shift for.
+ ; This leaves any higher-up BIOS
+ ; drives alone, such as an optical
+ ; disc drive 0xA0 or 0xE0
+ dec dl ; Drive > Our drive, adjust drive #
+.nomatch:
+ TRACER '!'
+ WRITEHEX2 dl
+ TRACER ','
+ mov ax,[cs:SavedAX]
+ WRITEHEX4
+ inc word [cs:Recursive]
+ pushf
+ call far [cs:OldInt13]
+ pushf
+ dec word [cs:Recursive]
+ push bp
+ mov bp,sp
+ cmp byte [cs:SavedAX+1],08h ; Get drive params function?
+ je .norestoredl ; DL = number of drives
+ cmp byte [cs:SavedAX+1],15h ; Get disk type function?
+ jne .restoredl
+ test byte [bp+4],80h ; Hard disk?
+ jnz .norestoredl ; CX:DX = size of device
+.restoredl:
+ mov dl,[bp+4]
+.norestoredl:
+ push ax
+ push ebx
+ push ds
+ mov ax,[bp+2] ; Flags
+ lds ebx,[cs:Stack]
+ mov [bx+4],al ; Arithmetic flags
+ pop ds
+ pop ebx
+ pop ax
+ pop bp
+ lss esp,[cs:Stack]
+.iret: iret
+
+recursive:
+ TRACER '@'
+jmp_oldint13:
+ jmp far [cs:OldInt13]
+
+our_drive:
+ ; Set up standard entry frame
+ push ds
+ push es
+ mov ds,ax
+ mov es,ax
+ mov ax,[SavedAX]
+ pushad
+ mov bp,sp ; Point BP to the entry stack frame
+ TRACER 'F'
+ WRITEHEX4
+ ; Note: AX == P_AX here
+ cmp ah,Int13FuncsCnt-1
+ ja Invalid_jump
+%if ELTORITO
+ mov al,[CD_PKT.type] ; Check if we are in
+ cmp al,0 ; El Torito no emulation mode
+ ja .emulation ; No. We support the function
+ cmp ah,3fh ; Yes. We must not support functions
+ jbe Invalid_jump ; 0 through 3Fh. Check and decide
+.emulation:
+%endif
+ xor al,al ; AL = 0 is standard entry condition
+ mov di,ax
+ shr di,7 ; Convert AH to an offset in DI
+ call [Int13Funcs+di]
+
+Done: ; Standard routine for return
+ mov P_AX,ax
+DoneWeird:
+ TRACER 'D'
+ xor bx,bx
+ mov es,bx
+ mov bx,[StatusPtr]
+ mov [es:bx],ah ; Save status
+ and ah,ah
+
+ lds ebx,[Stack]
+ ; This sets the low byte (the arithmetic flags) of the
+ ; FLAGS on stack to either 00h (no flags) or 01h (CF)
+ ; depending on if AH was zero or not.
+ setnz [bx+4] ; Set CF iff error
+ popad
+ pop es
+ pop ds
+ lss esp,[cs:Stack]
+ iret
+
+Reset:
+ ; Reset affects multiple drives, so we need to pass it on
+ TRACER 'R'
+ xor ax,ax ; Bottom of memory
+ mov es,ax
+ test dl,dl ; Always pass it on if we are
+ ; resetting HD
+ js .hard_disk ; Bit 7 set
+ ; Some BIOSes get very unhappy if we pass a reset floppy
+ ; command to them and don't actually have any floppies.
+ ; This is a bug, but we have to deal with it nontheless.
+ ; Therefore, if we are the *ONLY* floppy drive, and the
+ ; user didn't request HD reset, then just drop the command.
+ ; BIOS equipment byte, top two bits + 1 == total # of floppies
+ test byte [es:0x410],0C0h
+ jz success
+ jmp .pass_on ; ... otherwise pass it to the BIOS
+.hard_disk:
+ ; ... same thing for hard disks, sigh ...
+ cmp byte [es:0x475],1 ; BIOS variable for number of hard
+ ; disks
+ jbe success
+
+.pass_on:
+ pop ax ; Drop return address
+ popad ; Restore all registers
+ pop es
+ pop ds
+ lss esp,[cs:Stack] ; Restore the stack
+ and dl,80h ; Clear all but the type bit
+ jmp jmp_oldint13
+
+
+Invalid:
+ pop dx ; Drop return address
+Invalid_jump:
+ TRACER 'I'
+ mov ah,01h ; Unsupported function
+ jmp short Done
+
+GetDriveType:
+ test byte [DriveNo],80h
+ mov bl,02h ; Type 02h = floppy with changeline
+ jz .floppy
+ ; Hard disks only! DO NOT set CX:DX for floppies...
+ ; it apparently causes Win98SE DOS to go into an loop
+ ; resetting the drive over and over. Sigh.
+ inc bx ; Type = 03h
+ mov dx,[DiskSize] ; Return the disk size in sectors
+ mov P_DX,dx
+ mov cx,[DiskSize+2]
+ mov P_CX,cx
+.floppy:
+ mov P_AH,bl ; 02h floppy, 03h hard disk
+ pop ax ; Drop return address
+ xor ax,ax ; Success...
+ jmp DoneWeird ; But don't stick it into P_AX
+
+GetStatus:
+ xor ax,ax
+ mov es,ax
+ mov bx,[StatusPtr]
+ mov ah,[bx] ; Copy last status
+ ret
+
+ReadMult:
+ TRACER 'm'
+Read:
+ TRACER 'R'
+ call setup_regs
+do_copy:
+ TRACER '<'
+ call bcopy
+ TRACER '>'
+ movzx ax,P_AL ; AH = 0, AL = transfer count
+ ret
+
+WriteMult:
+ TRACER 'M'
+Write:
+ TRACER 'W'
+ test byte [ConfigFlags],CONFIG_READONLY
+ jnz .readonly
+ call setup_regs
+ xchg esi,edi ; Opposite direction of a Read!
+ jmp short do_copy
+.readonly: mov ah,03h ; Write protected medium
+ ret
+
+ ; Verify integrity; just bounds-check
+Seek:
+Verify:
+ call setup_regs ; Returns error if appropriate
+ ; And fall through to success
+
+CheckIfReady: ; These are always-successful noop functions
+Recalibrate:
+InitWithParms:
+DetectChange:
+EDDDetectChange:
+EDDLock:
+SetMode:
+success:
+ xor ax,ax ; Always successful
+ ret
+
+GetParms:
+ TRACER 'G'
+ mov dl,[DriveCnt] ; Cached data
+ mov P_DL,dl
+ test byte [DriveNo],80h
+ jnz .hd
+ mov P_DI,DPT
+ mov P_ES,cs
+ mov bl,[DriveType]
+ mov P_BL,bl
+.hd:
+ mov ax,[Cylinders]
+ dec ax ; We report the highest #, not the count
+ xchg al,ah
+ shl al,6
+ or al,[Sectors]
+ mov P_CX,ax
+ mov ax,[Heads]
+ dec ax
+ mov P_DH,al
+
+ ;
+ ; Is this MEMDISK installation check?
+ ;
+ cmp P_HAX,'ME'
+ jne .notic
+ cmp P_HCX,'MD'
+ jne .notic
+ cmp P_HDX,'IS'
+ jne .notic
+ cmp P_HBX,'K?'
+ jne .notic
+
+ ; MEMDISK installation check...
+ mov P_HAX,'!M'
+ mov P_HCX,'EM'
+ mov P_HDX,'DI'
+ mov P_HBX,'SK'
+ mov P_ES,cs
+ mov P_DI,MemDisk_Info
+
+.notic:
+ xor ax,ax
+ ret
+;
+; EDD functions -- only if enabled
+;
+%if EDD
+EDDPresence:
+ TRACER 'E'
+ TRACER 'c'
+
+ cmp P_BX,55AAh
+ jne Invalid
+ mov P_BX,0AA55h ; EDD signature
+ mov P_AX,03000h ; EDD 3.0
+ mov P_CX,0007h ; Bit 0 - Fixed disk access subset
+ ; Bit 1 - Locking and ejecting subset
+ ; Bit 2 - EDD subset
+ pop ax ; Drop return address
+ xor ax,ax ; Success
+ jmp DoneWeird ; Success, but AH != 0, sigh...
+
+EDDRead:
+ TRACER 'E'
+ TRACER 'r'
+
+ call edd_setup_regs
+ call bcopy
+ xor ax,ax
+ ret
+
+EDDWrite:
+ TRACER 'E'
+ TRACER 'w'
+
+ call edd_setup_regs
+ xchg esi,edi ; Opposite direction of a Read!
+ call bcopy
+ xor ax,ax
+ ret
+
+EDDVerify:
+EDDSeek:
+ call edd_setup_regs ; Just bounds checking
+ xor ax,ax
+ ret
+
+EDDGetParms:
+ TRACER 'E'
+ TRACER 'p'
+
+ mov es,P_DS
+ mov di,P_SI
+ mov si,EDD_DPT
+
+ lodsw ; Length of our DPT
+ mov cx,[es:di]
+ cmp cx,26 ; Minimum size
+ jb .overrun
+
+ cmp cx,ax
+ jb .oksize
+ mov cx,ax
+
+.oksize:
+ mov ax,cx
+ stosw
+ dec cx
+ dec cx
+ rep movsb
+
+ xor ax,ax
+ ret
+
+.overrun:
+ mov ax,0100h
+ ret
+%endif ; EDD
+
+ ; Set up registers as for a "Read", and compares against disk
+ ; size.
+ ; WARNING: This fails immediately, even if we can transfer some
+ ; sectors. This isn't really the correct behaviour.
+setup_regs:
+
+ ; Convert a CHS address in P_CX/P_DH into an LBA in eax
+ ; CH = cyl[7:0]
+ ; CL[0:5] = sector (1-based) CL[7:6] = cyl[9:8]
+ ; DH = head
+ movzx ecx,P_CX
+ movzx ebx,cl ; Sector number
+ and bl,3Fh
+ dec ebx ; Sector number is 1-based
+ cmp bx,[Sectors]
+ jae .overrun
+ movzx edi,P_DH ; Head number
+ movzx eax,word [Heads]
+ cmp di,ax
+ jae .overrun
+ shr cl,6
+ xchg cl,ch ; Now (E)CX <- cylinder number
+ mul ecx ; eax <- Heads*cyl# (edx <- 0)
+ add eax,edi
+ mul dword [Sectors]
+ add eax,ebx
+ ; Now eax = LBA, edx = 0
+
+ ;
+ ; setup_regs continues...
+ ;
+ ; Note: edi[31:16] and ecx[31:16] = 0 already
+ mov di,P_BX ; Get linear address of target buffer
+ mov cx,P_ES
+ shl ecx,4
+ add edi,ecx ; EDI = address to fetch to
+ movzx ecx,P_AL ; Sector count
+ mov esi,eax
+ add eax,ecx ; LBA of final sector + 1
+ shl esi,SECTORSIZE_LG2 ; LBA -> byte offset
+ add esi,[DiskBuf] ; Get address in high memory
+ cmp eax,[DiskSize] ; Check the high mark against limit
+ ja .overrun
+ shl ecx,SECTORSIZE_LG2-2 ; Convert count to dwords
+ ret
+
+.overrun: pop ax ; Drop setup_regs return address
+ mov ax,0200h ; Missing address mark
+ ret ; Return to Done
+
+ ; Set up registers as for an EDD Read, and compares against disk size.
+%if EDD
+edd_setup_regs:
+ push es
+ mov si,P_SI ; DS:SI -> DAPA
+ mov es,P_DS
+
+ mov dx,[es:si]
+ cmp dx,16
+ jb .baddapa
+
+ cmp dword [es:si+4],-1
+ je .linear_address
+
+ movzx ebx,word [es:si+4] ; Offset
+ movzx edi,word [es:si+6] ; Segment
+ shl edi,4
+ add ebx,edi
+ jmp .got_address
+
+.linear_address:
+ cmp dx,24 ; Must be large enough to hold
+ ; linear address
+ jb .baddapa
+
+ cmp dword [es:si+20],0 ; > 4 GB addresses not supported
+ mov ax,0900h ; "Data boundary error" - bogus, but
+ ; no really better code available
+ jne .error
+
+ mov ebx,[es:si+16]
+
+.got_address:
+ cmp dword [es:si+12],0 ; LBA too large?
+ jne .overrun
+
+ movzx ecx, word [es:si+2] ; Sectors to transfer
+ mov esi,[es:si+8] ; Starting sector
+ mov eax,esi
+ add eax,ecx
+ jc .overrun
+ cmp eax,[DiskSize]
+ ja .overrun
+
+ shl ecx,SECTORSIZE_LG2-2 ; Convert to dwords
+ shl esi,SECTORSIZE_LG2 ; Convert to an offset
+ add esi,[DiskBuf]
+ mov edi,ebx
+ pop es
+ ret
+
+.baddapa:
+ mov ax,0100h ; Invalid command
+ pop es
+ pop ax ; Drop setup_regs return address
+ ret
+
+.overrun:
+ mov ax,0200h ; "Address mark not found" =
+ ; LBA beyond end of disk
+.error:
+ and word [es:si+2],0 ; No sectors transferred
+ pop es
+ pop ax
+ ret
+
+EDDEject:
+ mov ax,0B200h ; Volume Not Removable
+ ret
+%if ELTORITO
+ElToritoTerminate:
+ TRACER 'T'
+ mov ax,[cs:SavedAX]
+ cmp al,1 ; We only support query, not terminate
+ jne ElToritoErr ; Fail
+ cmp dl,7fh ; Terminate all?
+ je .doit
+ cmp dl,[cs:DriveNo] ; Terminate our drive?
+ je .doit
+ jmp ElToritoErr ; Fail
+.doit: mov es,P_DS ; Caller's DS:SI pointed to packet
+ mov di,P_SI ; We'll use ES:DI
+ mov si,CD_PKT.size ; First byte is packet size
+ xor cx,0 ; Empty our count
+ ;mov cl,[ds:si] ; We'll copy that many bytes
+ mov cl,13h
+ rep movsb ; Copy until CX is zero
+ mov ax,0 ; Success
+ ret
+ElToritoEmulate:
+ElToritoBoot:
+ElToritoCatalog:
+ElToritoErr:
+ TRACER '!'
+ mov ax,100h ; Invalid parameter
+ ret
+%endif ; ELTORITO
+%endif ; EDD
+
+;
+; INT 15h intercept routines
+;
+int15_e820:
+ cmp edx,534D4150h ; "SMAP"
+ jne oldint15
+ cmp ecx,20 ; Need 20 bytes
+ jb err86
+ push ds
+ push cs
+ pop ds
+ push edx ; "SMAP"
+ and ebx,ebx
+ jne .renew
+ mov ebx,E820Table
+.renew:
+ add bx,12 ; Advance to next
+ mov eax,[bx-4] ; Type
+ and eax,eax ; Null type?
+ jz .renew ; If so advance to next
+ mov [es:di+16],eax
+ mov eax,[bx-12] ; Start addr (low)
+ mov edx,[bx-8] ; Start addr (high)
+ mov [es:di],eax
+ mov [es:di+4],edx
+ mov eax,[bx] ; End addr (low)
+ mov edx,[bx+4] ; End addr (high)
+ sub eax,[bx-12] ; Derive the length
+ sbb edx,[bx-8]
+ mov [es:di+8],eax ; Length (low)
+ mov [es:di+12],edx ; Length (high)
+ cmp dword [bx+8],-1 ; Type of next = end?
+ jne .notdone
+ xor ebx,ebx ; Done with table
+.notdone:
+ pop eax ; "SMAP"
+ mov edx,eax ; Some systems expect eax = edx = SMAP
+ mov ecx,20 ; Bytes loaded
+ pop ds
+int15_success:
+ mov byte [bp+6], 02h ; Clear CF
+ pop bp
+ iret
+
+err86:
+ mov byte [bp+6], 03h ; Set CF
+ mov ah,86h
+ pop bp
+ iret
+
+Int15Start:
+ push bp
+ mov bp,sp
+ cmp ax,0E820h
+ je near int15_e820
+ cmp ax,0E801h
+ je int15_e801
+ cmp ax,0E881h
+ je int15_e881
+ cmp ah,88h
+ je int15_88
+oldint15: pop bp
+ jmp far [cs:OldInt15]
+
+int15_e801: ; Get mem size for > 64 MB config
+ mov ax,[cs:Mem1MB]
+ mov cx,ax
+ mov bx,[cs:Mem16MB]
+ mov dx,bx
+ jmp short int15_success
+
+int15_e881: ; Get mem size for > 64 MB config
+ ; 32-bit code
+ mov eax,[cs:Mem1MB]
+ mov ecx,eax
+ mov ebx,[cs:Mem16MB]
+ mov edx,ebx
+ jmp short int15_success
+
+int15_88: ; Get extended mem size
+ mov ax,[cs:MemInt1588]
+ jmp short int15_success
+
+;
+; Routine to copy in/out of high memory
+; esi = linear source address
+; edi = linear target address
+; ecx = 32-bit word count
+;
+; Assumes cs = ds = es
+;
+bcopy:
+ push eax
+ push ebx
+ push edx
+ push ebp
+
+ mov bx, real_int15_stub
+
+ test byte [ConfigFlags], CONFIG_RAW|CONFIG_SAFEINT
+ jz .anymode ; Always do the real INT 15h
+
+ smsw ax ; Unprivileged!
+ test al,01h
+ jnz .protmode ; Protmode -> do real INT 15h
+
+.realmode:
+ ; Raw or Safeint mode, and we're in real mode...
+
+ test byte [ConfigFlags], CONFIG_SAFEINT
+ jnz .fakeint15
+
+.raw:
+ TRACER 'r'
+ ; We're in real mode, do it outselves
+
+ pushfd ; <A>
+ push ds ; <B>
+ push es ; <C>
+
+ cli
+ cld
+
+ xor ebx,ebx
+ mov bx,cs
+ shl ebx,4
+ lea edx,[Shaker+ebx]
+ mov [Shaker+2],edx
+
+ ; Test to see if A20 is enabled or not
+ xor ax,ax
+ mov ds,ax
+ dec ax
+ mov es,ax
+
+ mov ax,[0]
+ mov bx,ax
+ xor bx,[es:10h]
+ not ax
+ mov [0],ax
+ mov dx,ax
+ xor dx,[es:10h]
+ not ax
+ mov [0],ax
+
+ or dx,bx
+ push dx ; <D> Save A20 status
+ jnz .skip_a20e
+
+ mov ax,2401h ; Enable A20
+ int 15h
+.skip_a20e:
+ mov dl,[ConfigFlags]
+ and dx,CONFIG_BIGRAW
+ add dx,8
+ ; DX = 16 for BIGRAW, 8 for RAW
+ ; 8 is selector for a 64K flat segment,
+ ; 16 is selector for a 4GB flat segment.
+
+ lgdt [cs:Shaker]
+ mov eax,cr0
+ or al,01h
+ mov cr0,eax
+
+ mov bx,16 ; Large flat segment
+ mov ds,bx
+ mov es,bx
+
+ a32 rep movsd
+
+ ; DX has the appropriate value to put in
+ ; the registers on return
+ mov ds,dx
+ mov es,dx
+
+ and al,~01h
+ mov cr0,eax
+
+ pop dx ; <D> A20 status
+ pop es ; <C>
+ pop ds ; <B>
+
+ and dx,dx
+ jnz .skip_a20d
+ mov ax,2400h ; Disable A20
+ int 15h
+.skip_a20d:
+ popfd ; <A>
+ jmp .done
+
+.fakeint15:
+ ; We're in real mode with CONFIG_SAFEINT, invoke the
+ ; original INT 15h vector. We used to test for the
+ ; INT 15h vector being unchanged here, but that is
+ ; *us*; however, the test was wrong for years (always
+ ; negative) so instead of fixing the test do what we
+ ; tested and don't bother probing.
+ mov bx, fake_int15_stub
+
+.protmode:
+ TRACER 'p'
+.anymode:
+
+.copy_loop:
+ push esi
+ push edi
+ push ecx
+ cmp ecx,4000h
+ jna .safe_size
+ mov ecx,4000h
+.safe_size:
+ push ecx ; Transfer size this cycle
+ mov eax, esi
+ mov [Mover_src1], si
+ shr eax, 16
+ mov [Mover_src1+2], al
+ mov [Mover_src2], ah
+ mov eax, edi
+ mov [Mover_dst1], di
+ shr eax, 16
+ mov [Mover_dst1+2], al
+ mov [Mover_dst2], ah
+ mov si,Mover
+ mov ah, 87h
+ shl cx,1 ; Convert to 16-bit words
+ call bx ; INT 15h stub
+ pop eax ; Transfer size this cycle
+ pop ecx
+ pop edi
+ pop esi
+ jc .error
+ lea esi,[esi+4*eax]
+ lea edi,[edi+4*eax]
+ sub ecx, eax
+ jnz .copy_loop
+ ; CF = 0
+.error:
+.done:
+ pop ebp
+ pop edx
+ pop ebx
+ pop eax
+ ret
+
+real_int15_stub:
+ int 15h
+ cli ; Some BIOSes enable interrupts on INT 15h
+ ret
+
+fake_int15_stub:
+ pushf
+ call far [OldInt15]
+ cli
+ ret
+
+%ifdef DEBUG_TRACERS
+debug_tracer: pushad
+ pushfd
+ mov bp,sp
+ mov bx,[bp+9*4]
+ mov al,[cs:bx]
+ inc word [bp+9*4]
+ mov ah,0Eh
+ mov bx,7
+ int 10h
+ popfd
+ popad
+ ret
+
+writehex2: pushad
+ pushfd
+ mov cx,2
+ ror eax,4
+ jmp writehex_common
+writehex4: pushad
+ pushfd
+ mov cx,4
+ ror eax,12
+ jmp writehex_common
+writehex8: pushad
+ pushfd
+ mov cx,8
+ ror eax,28
+writehex_common:
+.loop: push cx
+ push eax
+ and al,0Fh
+ cmp al,10
+ jb .isdec
+ add al,'a'-'0'-10
+.isdec: add al,'0'
+ mov ah,0Eh
+ mov bx,7
+ int 10h
+ pop eax
+ rol eax,4
+ pop cx
+ loop .loop
+ popfd
+ popad
+ ret
+%endif
+
+ section .data align=16
+ alignb 2
+Int13Funcs dw Reset ; 00h - RESET
+ dw GetStatus ; 01h - GET STATUS
+ dw Read ; 02h - READ
+ dw Write ; 03h - WRITE
+ dw Verify ; 04h - VERIFY
+ dw Invalid ; 05h - FORMAT TRACK
+ dw Invalid ; 06h - FORMAT TRACK AND SET BAD FLAGS
+ dw Invalid ; 07h - FORMAT DRIVE AT TRACK
+ dw GetParms ; 08h - GET PARAMETERS
+ dw InitWithParms ; 09h - INITIALIZE CONTROLLER WITH
+ ; DRIVE PARAMETERS
+ dw Invalid ; 0Ah
+ dw Invalid ; 0Bh
+ dw Seek ; 0Ch - SEEK TO CYLINDER
+ dw Reset ; 0Dh - RESET HARD DISKS
+ dw Invalid ; 0Eh
+ dw Invalid ; 0Fh
+ dw CheckIfReady ; 10h - CHECK IF READY
+ dw Recalibrate ; 11h - RECALIBRATE
+ dw Invalid ; 12h
+ dw Invalid ; 13h
+ dw Invalid ; 14h
+ dw GetDriveType ; 15h - GET DRIVE TYPE
+ dw DetectChange ; 16h - DETECT DRIVE CHANGE
+%if EDD
+ dw Invalid ; 17h
+ dw Invalid ; 18h
+ dw Invalid ; 19h
+ dw Invalid ; 1Ah
+ dw Invalid ; 1Bh
+ dw Invalid ; 1Ch
+ dw Invalid ; 1Dh
+ dw Invalid ; 1Eh
+ dw Invalid ; 1Fh
+ dw Invalid ; 20h
+ dw ReadMult ; 21h - READ MULTIPLE
+ dw WriteMult ; 22h - WRITE MULTIPLE
+ dw SetMode ; 23h - SET CONTROLLER FEATURES
+ dw SetMode ; 24h - SET MULTIPLE MODE
+ dw Invalid ; 25h - IDENTIFY DRIVE
+ dw Invalid ; 26h
+ dw Invalid ; 27h
+ dw Invalid ; 28h
+ dw Invalid ; 29h
+ dw Invalid ; 2Ah
+ dw Invalid ; 2Bh
+ dw Invalid ; 2Ch
+ dw Invalid ; 2Dh
+ dw Invalid ; 2Eh
+ dw Invalid ; 2Fh
+ dw Invalid ; 30h
+ dw Invalid ; 31h
+ dw Invalid ; 32h
+ dw Invalid ; 33h
+ dw Invalid ; 34h
+ dw Invalid ; 35h
+ dw Invalid ; 36h
+ dw Invalid ; 37h
+ dw Invalid ; 38h
+ dw Invalid ; 39h
+ dw Invalid ; 3Ah
+ dw Invalid ; 3Bh
+ dw Invalid ; 3Ch
+ dw Invalid ; 3Dh
+ dw Invalid ; 3Eh
+ dw Invalid ; 3Fh
+ dw Invalid ; 40h
+ dw EDDPresence ; 41h - EDD PRESENCE DETECT
+ dw EDDRead ; 42h - EDD READ
+ dw EDDWrite ; 43h - EDD WRITE
+ dw EDDVerify ; 44h - EDD VERIFY
+ dw EDDLock ; 45h - EDD LOCK/UNLOCK MEDIA
+ dw EDDEject ; 46h - EDD EJECT
+ dw EDDSeek ; 47h - EDD SEEK
+ dw EDDGetParms ; 48h - EDD GET PARAMETERS
+ dw EDDDetectChange ; 49h - EDD MEDIA CHANGE STATUS
+%if ELTORITO ; EDD El Torito Functions
+ ; ELTORITO _must_ also have EDD
+ dw ElToritoEmulate ; 4Ah - Initiate Disk Emulation
+ dw ElToritoTerminate ; 4Bh - Terminate Disk Emulation
+ dw ElToritoBoot ; 4Ch - Initiate Disk Emu. and Reboot
+ dw ElToritoCatalog ; 4Dh - Return Boot Catalog
+%endif ; ELTORITO
+%endif ; EDD
+
+Int13FuncsEnd equ $
+Int13FuncsCnt equ (Int13FuncsEnd-Int13Funcs) >> 1
+
+
+ alignb 8, db 0
+Shaker dw ShakerEnd-$-1 ; Descriptor table limit
+ dd 0 ; Pointer to self
+ dw 0
+
+Shaker_RMDS: dd 0x0000ffff ; 64K data segment
+ dd 0x00009300
+
+Shaker_DS: dd 0x0000ffff ; 4GB data segment
+ dd 0x008f9300
+
+ShakerEnd equ $
+
+ alignb 8, db 0
+
+Mover dd 0, 0, 0, 0 ; Must be zero
+ dw 0ffffh ; 64 K segment size
+Mover_src1: db 0, 0, 0 ; Low 24 bits of source addy
+ db 93h ; Access rights
+ db 00h ; Extended access rights
+Mover_src2: db 0 ; High 8 bits of source addy
+ dw 0ffffh ; 64 K segment size
+Mover_dst1: db 0, 0, 0 ; Low 24 bits of target addy
+ db 93h ; Access rights
+ db 00h ; Extended access rights
+Mover_dst2: db 0 ; High 8 bits of source addy
+Mover_dummy2: dd 0, 0, 0, 0 ; More space for the BIOS
+
+ alignb 16, db 0
+mBFT:
+; Fields common to all ACPI tables
+ dd ' ' ; ACPI signature ("mBFT")
+ ; This is filled-in by the installer
+ ; to avoid an accidentally valid mBFT
+ dd mBFT_Len ; ACPI table length
+ db 1 ; ACPI revision
+ db 0 ; ACPI table checksum
+ db 'MEMDSK' ; ACPI OEM ID
+ db 'Syslinux' ; ACPI OEM table ID
+ dd 0 ; ACPI OEM revision
+ dd 0 ; ACPI ASL compiler vendor ID
+ dd 0 ; ACPI ASL compiler revision
+; The next field is mBFT-specific and filled-in by the installer
+ dd 0 ; "Safe hook" physical address
+
+; Note that the above ends on a DWORD boundary.
+; The MDI has always started at such a boundary.
+; Portions of the MDI are patched by the installer
+MemDisk_Info equ $ ; Pointed to by installation check
+MDI_Bytes dw MDI_Len ; Total bytes in MDI structure
+MDI_Version db VERSION_MINOR, VERSION_MAJOR ; MEMDISK version
+
+DiskBuf dd 0 ; Linear address of high memory disk
+DiskSize dd 0 ; Size of disk in blocks
+CommandLine dw 0, 0 ; Far pointer to saved command line
+
+OldInt13 dd 0 ; INT 13h in chain
+OldInt15 dd 0 ; INT 15h in chain
+
+OldDosMem dw 0 ; Old position of DOS mem end
+BootLoaderID db 0 ; Boot loader ID from header
+ db 0 ; pad
+
+DPT_ptr dw 0 ; If nonzero, pointer to DPT
+ ; Original DPT pointer follows
+
+MDI_Len equ $-MemDisk_Info
+mBFT_Len equ $-mBFT ; mBFT includes the MDI
+
+; ---- MDI structure ends here ---
+DriveShiftLimit db 0ffh ; Installer will probe for
+ ; a range of contiguous drives.
+ ; Any BIOS drives above this region
+ ; shall not be impacted by our
+ ; shifting behaviour
+ db 0 ; pad to a DWORD
+ dw 0 ; pad to a QWORD
+MemInt1588 dw 0 ; 1MB-65MB memory amount (1K)
+
+Cylinders dw 0 ; Cylinder count
+Heads dw 0 ; Head count
+Sectors dd 0 ; Sector count (zero-extended)
+
+Mem1MB dd 0 ; 1MB-16MB memory amount (1K)
+Mem16MB dd 0 ; 16MB-4G memory amount (64K)
+
+DriveNo db 0 ; Our drive number
+DriveType db 0 ; Our drive type (floppies)
+DriveCnt db 0 ; Drive count (from the BIOS)
+
+ConfigFlags db 0 ; Bit 0 - readonly
+
+MyStack dw 0 ; Offset of stack
+StatusPtr dw 0 ; Where to save status (zeroseg ptr)
+
+DPT times 16 db 0 ; BIOS parameter table pointer (floppies)
+OldInt1E dd 0 ; Previous INT 1E pointer (DPT)
+
+%if EDD
+EDD_DPT:
+.length dw 30
+.info dw 0029h
+ ; Bit 0 - DMA boundaries handled transparently
+ ; Bit 3 - Device supports write verify
+ ; Bit 5 - Media is lockable
+.cylinders dd 0 ; Filled in by installer
+.heads dd 0 ; Filled in by installer
+.sectors dd 0 ; Filled in by installer
+.totalsize dd 0, 0 ; Filled in by installer
+.bytespersec dw SECTORSIZE
+.eddtable dw -1, -1 ; Invalid DPTE pointer
+.dpikey dw 0BEDDh ; Device Path Info magic
+.dpilen db 2ch ; DPI len
+.res1 db 0 ; Reserved
+.res2 dw 0 ; Reserved
+.bustype dd 'MEM ' ; Host bus type (4 bytes, space padded)
+.inttype dd 'MEMORY ' ; Interface type (8 bytes, spc. padded)
+.intpath dd 0, 0 ; Interface path
+.devpath dd 0, 0, 0, 0 ; Device path
+.res3 db 0 ; Reserved
+.chksum db 0 ; DPI checksum
+
+%if ELTORITO
+; El Torito CD Specification Packet - mostly filled in by installer
+CD_PKT:
+.size db 13h ; Packet size (19 bytes)
+.type db 0 ; Boot media type (flags)
+.driveno db 0E0h ; INT 13h drive number
+.controller db 0 ; Controller index
+.start dd 0 ; Starting LBA of image
+.devno dw 0 ; Device number
+.user_buf dw 0 ; User buffer segment
+.load_seg dw 0 ; Load segment
+.sect_count dw 0 ; Emulated sectors to load
+.geom1 db 0 ; Cylinders bits 0 thru 7
+.geom2 db 0 ; Sects/track 0 thru 5, cyls 8, 9
+.geom3 db 0 ; Heads
+%endif ; ELTORITO
+
+%endif ; EDD
+
+; End patch area
+
+ alignb 4, db 0
+Stack dd 0 ; Saved SS:ESP on invocation
+ dw 0
+SavedAX dw 0 ; AX saved on invocation
+Recursive dw 0 ; Recursion counter
+
+ alignb 4, db 0 ; We *MUST* end on a dword boundary
+
+E820Table equ $ ; The installer loads the E820 table here
+TotalSize equ $ ; End pointer
diff --git a/contrib/syslinux-4.02/memdisk/memdisk.ld b/contrib/syslinux-4.02/memdisk/memdisk.ld
new file mode 100644
index 0000000..51c3e35
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/memdisk.ld
@@ -0,0 +1,140 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 2009 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for MEMDISK
+ */
+
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+EXTERN(_start)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x100000;
+ PROVIDE (__executable_start = .);
+
+ .init :
+ {
+ KEEP (*(.init))
+ } =0x90909090
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0x90909090
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0x90909090
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+
+ /* Ensure the __preinit_array_start label is properly aligned. We
+ could instead move the label definition inside the section, but
+ the linker would then create the section even if it turns out to
+ be empty, which isn't pretty. */
+ . = ALIGN(4);
+ PROVIDE (__preinit_array_start = .);
+ .preinit_array : { *(.preinit_array) }
+ PROVIDE (__preinit_array_end = .);
+ PROVIDE (__init_array_start = .);
+ .init_array : { *(.init_array) }
+ PROVIDE (__init_array_end = .);
+ PROVIDE (__fini_array_start = .);
+ .fini_array : { *(.fini_array) }
+ PROVIDE (__fini_array_end = .);
+ PROVIDE (__ctors_start = .);
+ .ctors :
+ {
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ PROVIDE (__ctors_end = .);
+ PROVIDE (__dtors_start = .);
+ .dtors :
+ {
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ PROVIDE (__dtors_end = .);
+
+ /* Adjust the address for the data segment. Avoid mixing code and
+ data within same 128-byte chunk. */
+ . = ALIGN(128);
+
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ _edata = .;
+ PROVIDE (edata = .);
+ . = ALIGN(16);
+ .bss :
+ {
+ __bss_start = .;
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+ . = ALIGN(4);
+ __bss_end = .;
+ }
+ _end = .;
+ PROVIDE (end = .);
+
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/contrib/syslinux-4.02/memdisk/memdisk16.asm b/contrib/syslinux-4.02/memdisk/memdisk16.asm
new file mode 100644
index 0000000..6bafae7
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/memdisk16.asm
@@ -0,0 +1,793 @@
+;; -*- fundamental -*-
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; init16.asm
+;;
+;; Routine to initialize and to trampoline into 32-bit
+;; protected memory. This code is derived from bcopy32.inc and
+;; com32.inc in the main SYSLINUX distribution.
+;;
+
+%include '../version.gen'
+
+MY_CS equ 0x0800 ; Segment address to use
+CS_BASE equ (MY_CS << 4) ; Corresponding address
+
+; Low memory bounce buffer
+BOUNCE_SEG equ (MY_CS+0x1000)
+
+%define DO_WBINVD 0
+
+ section .rodata align=16
+ section .data align=16
+ section .bss align=16
+ section .stack align=16 nobits
+stack resb 512
+stack_end equ $
+
+;; -----------------------------------------------------------------------
+;; Kernel image header
+;; -----------------------------------------------------------------------
+
+ section .text ; Must be first in image
+ bits 16
+
+cmdline times 497 db 0 ; We put the command line here
+setup_sects db 0
+root_flags dw 0
+syssize dw 0
+swap_dev dw 0
+ram_size dw 0
+vid_mode dw 0
+root_dev dw 0
+boot_flag dw 0xAA55
+
+_start: jmp short start
+
+ db "HdrS" ; Header signature
+ dw 0x0203 ; Header version number
+
+realmode_swtch dw 0, 0 ; default_switch, SETUPSEG
+start_sys_seg dw 0x1000 ; obsolete
+version_ptr dw memdisk_version-0x200 ; version string ptr
+type_of_loader db 0 ; Filled in by boot loader
+loadflags db 1 ; Please load high
+setup_move_size dw 0 ; Unused
+code32_start dd 0x100000 ; 32-bit start address
+ramdisk_image dd 0 ; Loaded ramdisk image address
+ramdisk_size dd 0 ; Size of loaded ramdisk
+bootsect_kludge dw 0, 0
+heap_end_ptr dw 0
+pad1 dw 0
+cmd_line_ptr dd 0 ; Command line
+ramdisk_max dd 0xffffffff ; Highest allowed ramdisk address
+
+;
+; These fields aren't real setup fields, they're poked in by the
+; 32-bit code.
+;
+b_esdi dd 0 ; ES:DI for boot sector invocation
+b_edx dd 0 ; EDX for boot sector invocation
+b_sssp dd 0 ; SS:SP on boot sector invocation
+b_csip dd 0 ; CS:IP on boot sector invocation
+
+ section .rodata
+memdisk_version:
+ db "MEMDISK ", VERSION_STR, " ", DATE, 0
+
+;; -----------------------------------------------------------------------
+;; End kernel image header
+;; -----------------------------------------------------------------------
+
+;
+; Move ourselves down into memory to reduce the risk of conflicts;
+; then canonicalize CS to match the other segments.
+;
+ section .text
+ bits 16
+start:
+ mov ax,MY_CS
+ mov es,ax
+ movzx cx,byte [setup_sects]
+ inc cx ; Add one for the boot sector
+ shl cx,7 ; Convert to dwords
+ xor si,si
+ xor di,di
+ mov fs,si ; fs <- 0
+ cld
+ rep movsd
+ mov ds,ax
+ mov ss,ax
+ mov esp,stack_end
+ jmp MY_CS:.next
+.next:
+
+;
+; Copy the command line, if there is one
+;
+copy_cmdline:
+ xor di,di ; Bottom of our own segment (= "boot sector")
+ mov eax,[cmd_line_ptr]
+ and eax,eax
+ jz .endcmd ; No command line
+ mov si,ax
+ shr eax,4 ; Convert to segment
+ and si,0x000F ; Starting offset only
+ mov gs,ax
+ mov cx,496 ; Max number of bytes
+.copycmd:
+ gs lodsb
+ and al,al
+ jz .endcmd
+ stosb
+ loop .copycmd
+.endcmd:
+ xor al,al
+ stosb
+
+;
+; Now jump to 32-bit code
+;
+ sti
+ call init32
+;
+; When init32 returns, we have been set up, the new boot sector loaded,
+; and we should go and and run the newly loaded boot sector.
+;
+; The setup function will have poked values into the setup area.
+;
+ movzx edi,word [cs:b_esdi]
+ mov es,word [cs:b_esdi+2]
+ mov edx,[cs:b_edx]
+
+ cli
+ xor esi,esi ; No partition table involved
+ mov ds,si ; Make all the segments consistent
+ mov fs,si
+ mov gs,si
+ lss sp,[cs:b_sssp]
+ movzx esp,sp
+ jmp far [cs:b_csip]
+
+;
+; We enter protected mode, set up a flat 32-bit environment, run rep movsd
+; and then exit. IMPORTANT: This code assumes cs == MY_CS.
+;
+; This code is probably excessively anal-retentive in its handling of
+; segments, but this stuff is painful enough as it is without having to rely
+; on everything happening "as it ought to."
+;
+DummyTSS equ 0x580 ; Hopefully safe place in low mmoery
+
+ section .data
+
+ ; desc base, limit, flags
+%macro desc 3
+ dd (%2 & 0xffff) | ((%1 & 0xffff) << 16)
+ dd (%1 & 0xff000000) | (%2 & 0xf0000) | ((%3 & 0xf0ff) << 8) | ((%1 & 0x00ff0000) >> 16)
+%endmacro
+
+ align 8, db 0
+call32_gdt: dw call32_gdt_size-1 ; Null descriptor - contains GDT
+.adj1: dd call32_gdt+CS_BASE ; pointer for LGDT instruction
+ dw 0
+
+ ; 0008: Dummy TSS to make Intel VT happy
+ ; Should never be actually accessed...
+ desc DummyTSS, 103, 0x8089
+
+ ; 0010: Code segment, use16, readable, dpl 0, base CS_BASE, 64K
+ desc CS_BASE, 0xffff, 0x009b
+
+ ; 0018: Data segment, use16, read/write, dpl 0, base CS_BASE, 64K
+ desc CS_BASE, 0xffff, 0x0093
+
+ ; 0020: Code segment, use32, read/write, dpl 0, base 0, 4G
+ desc 0, 0xfffff, 0xc09b
+
+ ; 0028: Data segment, use32, read/write, dpl 0, base 0, 4G
+ desc 0, 0xfffff, 0xc093
+
+call32_gdt_size: equ $-call32_gdt
+
+err_a20: db 'ERROR: A20 gate not responding!',13,10,0
+
+ section .bss
+ alignb 4
+Return resd 1 ; Return value
+SavedSP resw 1 ; Place to save SP
+A20Tries resb 1
+
+ section .data
+ align 4, db 0
+Target dd 0 ; Target address
+Target_Seg dw 20h ; Target CS
+
+A20Type dw 0 ; Default = unknown
+
+ section .text
+ bits 16
+;
+; Routines to enable and disable (yuck) A20. These routines are gathered
+; from tips from a couple of sources, including the Linux kernel and
+; http://www.x86.org/. The need for the delay to be as large as given here
+; is indicated by Donnie Barnes of RedHat, the problematic system being an
+; IBM ThinkPad 760EL.
+;
+; We typically toggle A20 twice for every 64K transferred.
+;
+%define io_delay call _io_delay
+%define IO_DELAY_PORT 80h ; Invalid port (we hope!)
+%define disable_wait 32 ; How long to wait for a disable
+
+%define A20_DUNNO 0 ; A20 type unknown
+%define A20_NONE 1 ; A20 always on?
+%define A20_BIOS 2 ; A20 BIOS enable
+%define A20_KBC 3 ; A20 through KBC
+%define A20_FAST 4 ; A20 through port 92h
+
+ align 2, db 0
+A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast
+A20DList dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast
+a20_adjust_cnt equ ($-A20List)/2
+
+slow_out: out dx, al ; Fall through
+
+_io_delay: out IO_DELAY_PORT,al
+ out IO_DELAY_PORT,al
+ ret
+
+enable_a20:
+ pushad
+ mov byte [A20Tries],255 ; Times to try to make this work
+
+try_enable_a20:
+
+;
+; Flush the caches
+;
+%if DO_WBINVD
+ call try_wbinvd
+%endif
+
+;
+; If the A20 type is known, jump straight to type
+;
+ mov bp,[A20Type]
+ add bp,bp ; Convert to word offset
+.adj4: jmp word [bp+A20List]
+
+;
+; First, see if we are on a system with no A20 gate
+;
+a20_dunno:
+a20_none:
+ mov byte [A20Type], A20_NONE
+ call a20_test
+ jnz a20_done
+
+;
+; Next, try the BIOS (INT 15h AX=2401h)
+;
+a20_bios:
+ mov byte [A20Type], A20_BIOS
+ mov ax,2401h
+ pushf ; Some BIOSes muck with IF
+ int 15h
+ popf
+
+ call a20_test
+ jnz a20_done
+
+;
+; Enable the keyboard controller A20 gate
+;
+a20_kbc:
+ mov dl, 1 ; Allow early exit
+ call empty_8042
+ jnz a20_done ; A20 live, no need to use KBC
+
+ mov byte [A20Type], A20_KBC ; Starting KBC command sequence
+
+ mov al,0D1h ; Write output port
+ out 064h, al
+ call empty_8042_uncond
+
+ mov al,0DFh ; A20 on
+ out 060h, al
+ call empty_8042_uncond
+
+ ; Apparently the UHCI spec assumes that A20 toggle
+ ; ends with a null command (assumed to be for sychronization?)
+ ; Put it here to see if it helps anything...
+ mov al,0FFh ; Null command
+ out 064h, al
+ call empty_8042_uncond
+
+ ; Verify that A20 actually is enabled. Do that by
+ ; observing a word in low memory and the same word in
+ ; the HMA until they are no longer coherent. Note that
+ ; we don't do the same check in the disable case, because
+ ; we don't want to *require* A20 masking (SYSLINUX should
+ ; work fine without it, if the BIOS does.)
+.kbc_wait: push cx
+ xor cx,cx
+.kbc_wait_loop:
+ call a20_test
+ jnz a20_done_pop
+ loop .kbc_wait_loop
+
+ pop cx
+;
+; Running out of options here. Final attempt: enable the "fast A20 gate"
+;
+a20_fast:
+ mov byte [A20Type], A20_FAST ; Haven't used the KBC yet
+ in al, 092h
+ or al,02h
+ and al,~01h ; Don't accidentally reset the machine!
+ out 092h, al
+
+.fast_wait: push cx
+ xor cx,cx
+.fast_wait_loop:
+ call a20_test
+ jnz a20_done_pop
+ loop .fast_wait_loop
+
+ pop cx
+
+;
+; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up
+; and report failure to the user.
+;
+
+ dec byte [A20Tries]
+ jnz try_enable_a20
+
+
+ ; Error message time
+ mov si,err_a20
+print_err:
+ lodsb
+ and al,al
+ jz die
+ mov bx,7
+ mov ah,0xe
+ int 10h
+ jmp print_err
+
+
+die:
+ sti
+.hlt: hlt
+ jmp short .hlt
+
+;
+; A20 unmasked, proceed...
+;
+a20_done_pop: pop cx
+a20_done: popad
+ ret
+
+;
+; This routine tests if A20 is enabled (ZF = 0). This routine
+; must not destroy any register contents.
+;
+
+; This is the INT 1Fh vector, which is standard PCs is used by the
+; BIOS when the screen is in graphics mode. Even if it is, it points to
+; data, not code, so it should be safe enough to fiddle with.
+A20Test equ (1Fh*4)
+
+a20_test:
+ push ds
+ push es
+ push cx
+ push eax
+ xor ax,ax
+ mov ds,ax ; DS == 0
+ dec ax
+ mov es,ax ; ES == 0FFFFh
+ mov cx,32 ; Loop count
+ mov eax,[A20Test]
+ cmp eax,[es:A20Test+10h]
+ jne .a20_done
+ push eax
+.a20_wait:
+ inc eax
+ mov [A20Test],eax
+ io_delay
+ cmp eax,[es:A20Test+10h]
+ loopz .a20_wait
+ pop dword [A20Test] ; Restore original value
+.a20_done:
+ pop eax
+ pop cx
+ pop es
+ pop ds
+ ret
+
+disable_a20:
+ pushad
+;
+; Flush the caches
+;
+%if DO_WBINVD
+ call try_wbinvd
+%endif
+
+ mov bp,[A20Type]
+ add bp,bp ; Convert to word offset
+.adj5: jmp word [bp+A20DList]
+
+a20d_bios:
+ mov ax,2400h
+ pushf ; Some BIOSes muck with IF
+ int 15h
+ popf
+ jmp short a20d_snooze
+
+;
+; Disable the "fast A20 gate"
+;
+a20d_fast:
+ in al, 092h
+ and al,~03h
+ out 092h, al
+ jmp short a20d_snooze
+
+;
+; Disable the keyboard controller A20 gate
+;
+a20d_kbc:
+ call empty_8042_uncond
+
+ mov al,0D1h
+ out 064h, al ; Write output port
+ call empty_8042_uncond
+
+ mov al,0DDh ; A20 off
+ out 060h, al
+ call empty_8042_uncond
+
+ mov al,0FFh ; Null command/synchronization
+ out 064h, al
+ call empty_8042_uncond
+
+ ; Wait a bit for it to take effect
+a20d_snooze:
+ push cx
+ mov cx, disable_wait
+.delayloop: call a20_test
+ jz .disabled
+ loop .delayloop
+.disabled: pop cx
+a20d_dunno:
+a20d_none:
+ popad
+ ret
+
+;
+; Routine to empty the 8042 KBC controller. If dl != 0
+; then we will test A20 in the loop and exit if A20 is
+; suddenly enabled.
+;
+empty_8042_uncond:
+ xor dl,dl
+empty_8042:
+ call a20_test
+ jz .a20_on
+ and dl,dl
+ jnz .done
+.a20_on: io_delay
+ in al, 064h ; Status port
+ test al,1
+ jz .no_output
+ io_delay
+ in al, 060h ; Read input
+ jmp short empty_8042
+.no_output:
+ test al,2
+ jnz empty_8042
+ io_delay
+.done: ret
+
+;
+; Execute a WBINVD instruction if possible on this CPU
+;
+%if DO_WBINVD
+try_wbinvd:
+ wbinvd
+ ret
+%endif
+
+ section .bss
+ alignb 4
+PMESP resd 1 ; Protected mode %esp
+
+ section .idt nobits align=4096
+ alignb 4096
+pm_idt resb 4096 ; Protected-mode IDT, followed by interrupt stubs
+
+
+
+
+pm_entry: equ 0x100000
+
+ section .rodata
+ align 2, db 0
+call32_rmidt:
+ dw 0ffffh ; Limit
+ dd 0 ; Address
+
+ section .data
+ alignb 2
+call32_pmidt:
+ dw 8*256 ; Limit
+ dd 0 ; Address (entered later)
+
+ section .text
+;
+; This is the main entrypoint in this function
+;
+init32:
+ mov bx,call32_call_start ; Where to go in PM
+
+;
+; Enter protected mode. BX contains the entry point relative to the
+; real-mode CS.
+;
+call32_enter_pm:
+ mov ax,cs
+ mov ds,ax
+ movzx ebp,ax
+ shl ebp,4 ; EBP <- CS_BASE
+ movzx ebx,bx
+ add ebx,ebp ; entry point += CS_BASE
+ cli
+ mov [SavedSP],sp
+ cld
+ call enable_a20
+ mov byte [call32_gdt+8+5],89h ; Mark TSS unbusy
+ o32 lgdt [call32_gdt] ; Set up GDT
+ o32 lidt [call32_pmidt] ; Set up IDT
+ mov eax,cr0
+ or al,1
+ mov cr0,eax ; Enter protected mode
+ jmp 20h:strict dword .in_pm+CS_BASE
+.pm_jmp equ $-6
+
+
+ bits 32
+.in_pm:
+ xor eax,eax ; Available for future use...
+ mov fs,eax
+ mov gs,eax
+ lldt ax
+
+ mov al,28h ; Set up data segments
+ mov es,eax
+ mov ds,eax
+ mov ss,eax
+
+ mov al,08h
+ ltr ax
+
+ mov esp,[ebp+PMESP] ; Load protmode %esp if available
+ jmp ebx ; Go to where we need to go
+
+;
+; This is invoked before first dispatch of the 32-bit code, in 32-bit mode
+;
+call32_call_start:
+ ;
+ ; Set up a temporary stack in the bounce buffer;
+ ; start32.S will override this to point us to the real
+ ; high-memory stack.
+ ;
+ mov esp, (BOUNCE_SEG << 4) + 0x10000
+
+ push dword call32_enter_rm.rm_jmp+CS_BASE
+ push dword call32_enter_pm.pm_jmp+CS_BASE
+ push dword stack_end ; RM size
+ push dword call32_gdt+CS_BASE
+ push dword call32_handle_interrupt+CS_BASE
+ push dword CS_BASE ; Segment base
+ push dword (BOUNCE_SEG << 4) ; Bounce buffer address
+ push dword call32_syscall+CS_BASE ; Syscall entry point
+
+ call pm_entry-CS_BASE ; Run the program...
+
+ ; ... fall through to call32_exit ...
+
+call32_exit:
+ mov bx,call32_done ; Return to command loop
+
+call32_enter_rm:
+ ; Careful here... the PM code may have relocated the
+ ; entire RM code, so we need to figure out exactly
+ ; where we are executing from. If the PM code has
+ ; relocated us, it *will* have adjusted the GDT to
+ ; match, though.
+ call .here
+.here: pop ebp
+ sub ebp,.here
+ o32 sidt [ebp+call32_pmidt]
+ cli
+ cld
+ mov [ebp+PMESP],esp ; Save exit %esp
+ xor esp,esp ; Make sure the high bits are zero
+ jmp 10h:.in_pm16 ; Return to 16-bit mode first
+
+ bits 16
+.in_pm16:
+ mov ax,18h ; Real-mode-like segment
+ mov es,ax
+ mov ds,ax
+ mov ss,ax
+ mov fs,ax
+ mov gs,ax
+
+ lidt [call32_rmidt] ; Real-mode IDT (rm needs no GDT)
+ mov eax,cr0
+ and al,~1
+ mov cr0,eax
+ jmp MY_CS:.in_rm
+.rm_jmp equ $-2
+
+.in_rm: ; Back in real mode
+ mov ax,cs
+ mov ds,ax
+ mov es,ax
+ mov fs,ax
+ mov gs,ax
+ mov ss,ax
+ mov sp,[SavedSP] ; Restore stack
+ jmp bx ; Go to whereever we need to go...
+
+call32_done:
+ call disable_a20
+ sti
+ ret
+
+;
+; 16-bit support code
+;
+ bits 16
+
+;
+; 16-bit interrupt-handling code
+;
+call32_int_rm:
+ pushf ; Flags on stack
+ push cs ; Return segment
+ push word .cont ; Return address
+ push dword edx ; Segment:offset of IVT entry
+ retf ; Invoke IVT routine
+.cont: ; ... on resume ...
+ mov bx,call32_int_resume
+ jmp call32_enter_pm ; Go back to PM
+
+;
+; 16-bit system call handling code
+;
+call32_sys_rm:
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ popad
+ popfd
+ retf ; Invoke routine
+.return:
+ pushfd
+ pushad
+ push ds
+ push es
+ push fs
+ push gs
+ mov bx,call32_sys_resume
+ jmp call32_enter_pm
+
+;
+; 32-bit support code
+;
+ bits 32
+
+;
+; This is invoked on getting an interrupt in protected mode. At
+; this point, we need to context-switch to real mode and invoke
+; the interrupt routine.
+;
+; When this gets invoked, the registers are saved on the stack and
+; AL contains the register number.
+;
+call32_handle_interrupt:
+ movzx eax,al
+ xor ebx,ebx ; Actually makes the code smaller
+ mov edx,[ebx+eax*4] ; Get the segment:offset of the routine
+ mov bx,call32_int_rm
+ jmp call32_enter_rm ; Go to real mode
+
+call32_int_resume:
+ popad
+ iret
+
+;
+; Syscall invocation. We manifest a structure on the real-mode stack,
+; containing the call32sys_t structure from <call32.h> as well as
+; the following entries (from low to high address):
+; - Target offset
+; - Target segment
+; - Return offset
+; - Return segment (== real mode cs)
+; - Return flags
+;
+call32_syscall:
+ pushfd ; Save IF among other things...
+ pushad ; We only need to save some, but...
+ cld
+ call .here
+.here: pop ebp
+ sub ebp,.here
+
+ movzx edi,word [ebp+SavedSP]
+ sub edi,54 ; Allocate 54 bytes
+ mov [ebp+SavedSP],di
+ add edi,ebp ; Create linear address
+
+ mov esi,[esp+11*4] ; Source regs
+ xor ecx,ecx
+ mov cl,11 ; 44 bytes to copy
+ rep movsd
+
+ movzx eax,byte [esp+10*4] ; Interrupt number
+ ; ecx == 0 here; adding it to the EA makes the
+ ; encoding smaller
+ mov eax,[ecx+eax*4] ; Get IVT entry
+ stosd ; Save in stack frame
+ mov ax,call32_sys_rm.return ; Return offset
+ stosw ; Save in stack frame
+ mov eax,ebp
+ shr eax,4 ; Return segment
+ stosw ; Save in stack frame
+ mov eax,[edi-12] ; Return flags
+ and eax,0x200cd7 ; Mask (potentially) unsafe flags
+ mov [edi-12],eax ; Primary flags entry
+ stosw ; Return flags
+
+ mov bx,call32_sys_rm
+ jmp call32_enter_rm ; Go to real mode
+
+ ; On return, the 44-byte return structure is on the
+ ; real-mode stack. call32_enter_pm will leave ebp
+ ; pointing to the real-mode base.
+call32_sys_resume:
+ movzx esi,word [ebp+SavedSP]
+ mov edi,[esp+12*4] ; Dest regs
+ add esi,ebp ; Create linear address
+ and edi,edi ; NULL pointer?
+ jnz .do_copy
+.no_copy: mov edi,esi ; Do a dummy copy-to-self
+.do_copy: xor ecx,ecx
+ mov cl,11 ; 44 bytes
+ rep movsd ; Copy register block
+
+ add word [ebp+SavedSP],44 ; Remove from stack
+
+ popad
+ popfd
+ ret ; Return to 32-bit program
diff --git a/contrib/syslinux-4.02/memdisk/memdisk_chs_512.asm b/contrib/syslinux-4.02/memdisk/memdisk_chs_512.asm
new file mode 100644
index 0000000..bb436f3
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/memdisk_chs_512.asm
@@ -0,0 +1,5 @@
+ [map all memdisk_chs_512.map]
+%define EDD 0
+%define ELTORITO 0
+%define SECTORSIZE_LG2 9 ; log2(sector size)
+%include "memdisk.inc"
diff --git a/contrib/syslinux-4.02/memdisk/memdisk_edd_512.asm b/contrib/syslinux-4.02/memdisk/memdisk_edd_512.asm
new file mode 100644
index 0000000..3a6d5ca
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/memdisk_edd_512.asm
@@ -0,0 +1,5 @@
+ [map all memdisk_edd_512.map]
+%define EDD 1
+%define ELTORITO 0
+%define SECTORSIZE_LG2 9 ; log2(sector size)
+%include "memdisk.inc"
diff --git a/contrib/syslinux-4.02/memdisk/memdisk_iso_2048.asm b/contrib/syslinux-4.02/memdisk/memdisk_iso_2048.asm
new file mode 100644
index 0000000..0c8ffee
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/memdisk_iso_2048.asm
@@ -0,0 +1,5 @@
+ [map all memdisk_iso_2048.map]
+%define EDD 1
+%define ELTORITO 1
+%define SECTORSIZE_LG2 11 ; log2(sector size)
+%include "memdisk.inc"
diff --git a/contrib/syslinux-4.02/memdisk/memdisk_iso_512.asm b/contrib/syslinux-4.02/memdisk/memdisk_iso_512.asm
new file mode 100644
index 0000000..1555b77
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/memdisk_iso_512.asm
@@ -0,0 +1,5 @@
+ [map all memdisk_iso_512.map]
+%define EDD 1
+%define ELTORITO 1
+%define SECTORSIZE_LG2 9 ; log2(sector size)
+%include "memdisk.inc"
diff --git a/contrib/syslinux-4.02/memdisk/memmove.S b/contrib/syslinux-4.02/memdisk/memmove.S
new file mode 100644
index 0000000..b7ac676
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/memmove.S
@@ -0,0 +1,139 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * memmove.S
+ *
+ * Reasonably efficient memmove, using aligned transfers at least
+ * for the destination operand.
+ */
+
+ .globl memmove
+ .type memmove,@function
+ .text
+memmove:
+ jecxz 3f
+
+ pushl %esi
+ pushl %edi
+ pushl %eax /* Return value */
+
+ movl %eax,%edi
+ movl %edx,%esi
+
+ cmpl %edi,%esi
+ jb 1f
+
+ /* source >= dest, forwards move */
+
+ /* Initial alignment */
+ movl %edi,%edx
+ shrl $1,%edx
+ jnc 11f
+ movsb
+ decl %ecx
+11:
+ movb %cl,%al
+ cmpl $2,%ecx
+ jb 13f
+
+ shrl $1,%edx
+ jnc 12f
+ movsw
+ subl $2,%ecx
+12:
+ /* Bulk transfer */
+ movb %cl,%al
+ shrl $2,%ecx
+ rep; movsl
+
+ /* Final alignment */
+ testb $2,%al
+ jz 14f
+ movsw
+13:
+14:
+ testb $1,%al
+ jz 15f
+ movsb
+15:
+ jmp 2f
+
+
+1:
+ /* source < dest, backwards move */
+ std
+ leal -1(%ecx,%esi),%esi
+ leal -1(%ecx,%edi),%edi
+
+ /* Initial alignment */
+ movl %edi,%edx
+ shrl $1,%edx
+ jc 21f
+ movsb
+ decl %ecx
+21:
+ decl %esi
+ decl %edi
+ movb %cl,%al
+ cmpl $2,%ecx
+ jb 23f
+ shrl $1,%edx
+ jc 22f
+ movsw
+ subl $2,%ecx
+22:
+ /* Bulk transfer */
+ subl $2,%esi
+ subl $2,%edi
+ movb %cl,%al
+ shrl $2,%ecx
+ rep; movsl
+
+ /* Final alignment */
+ addl $2,%esi
+ addl $2,%edi
+ testb $2,%al
+ jz 24f
+ movsw
+23:
+24:
+ incl %esi
+ incl %edi
+ testb $1,%al
+ jz 25f
+ movsb
+25:
+ cld
+2:
+ popl %eax /* Return value */
+ popl %edi
+ popl %esi
+3:
+ ret
+
+ .size memmove, .-memmove
diff --git a/contrib/syslinux-4.02/memdisk/memset.S b/contrib/syslinux-4.02/memdisk/memset.S
new file mode 100644
index 0000000..e641415
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/memset.S
@@ -0,0 +1,86 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * memset.S
+ *
+ * Reasonably efficient memset, using aligned transfers at least
+ * for the destination operand.
+ */
+
+ .globl memset
+ .type memset,@function
+ .text
+memset:
+ jecxz 6f
+
+ pushl %edi
+ pushl %ebx
+ pushl %eax /* Return value */
+
+ movl %eax,%edi
+ movb %dl,%dh
+ movzwl %dx,%eax
+ shll $16,%edx
+ orl %edx,%eax
+
+ /* Initial alignment */
+ movl %edi,%edx
+ shrl $1,%edx
+ jnc 1f
+ stosb
+ decl %ecx
+1:
+ movb %cl,%bl
+ cmpl $2,%ecx
+ jb 3f
+ shrl $1,%edx
+ jnc 2f
+ stosw
+ subl $2,%ecx
+2:
+ /* Bulk transfer */
+ movb %cl,%bl
+ shrl $2,%ecx
+ rep; stosl
+
+ testb $2,%bl
+ jz 4f
+ stosw
+3:
+4:
+ testb $1,%bl
+ jz 5f
+ stosb
+5:
+ popl %eax /* Return value */
+ popl %ebx
+ popl %edi
+6:
+ ret
+
+ .size memset, .-memset
diff --git a/contrib/syslinux-4.02/memdisk/msetup.c b/contrib/syslinux-4.02/memdisk/msetup.c
new file mode 100644
index 0000000..f40a2c6
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/msetup.c
@@ -0,0 +1,178 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2008 H. Peter Anvin - 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * msetup.c
+ *
+ * Initialization code for memory-based disk
+ */
+
+#include <stdint.h>
+#ifdef TEST
+# include <string.h>
+# include <stdio.h>
+#else
+# include "memdisk.h"
+# include "conio.h"
+#endif
+#include "e820.h"
+
+uint32_t dos_mem = 0; /* 0-1MB */
+uint32_t low_mem = 0; /* 1-16MB */
+uint32_t high_mem = 0; /* 16+ MB */
+
+#ifndef TEST
+
+static inline int get_e820(void)
+{
+ struct e820_info {
+ uint64_t base;
+ uint64_t len;
+ uint32_t type;
+ } *buf = sys_bounce;
+ uint32_t copied;
+ int range_count = 0;
+ com32sys_t regs;
+
+ memset(&regs, 0, sizeof regs);
+ memset(buf, 0, sizeof *buf);
+
+ do {
+ regs.eax.l = 0x0000e820;
+ regs.ecx.l = sizeof(*buf);
+ regs.edx.l = 0x534d4150;
+ regs.edi.w[0] = OFFS(buf);
+ regs.es = SEG(buf);
+
+ intcall(0x15, &regs, &regs);
+ copied = (regs.eflags.l & 1) ? 0 : regs.ecx.l;
+
+ if (regs.eax.l != 0x534d4150 || copied < 20)
+ break;
+
+ printf("e820: %08x%08x %08x%08x %d\n",
+ (uint32_t) (buf->base >> 32), (uint32_t) buf->base,
+ (uint32_t) (buf->len >> 32), (uint32_t) buf->len, buf->type);
+
+ insertrange(buf->base, buf->len, buf->type);
+ range_count++;
+
+ } while (regs.ebx.l);
+
+ return !range_count;
+}
+
+static inline void get_dos_mem(void)
+{
+ com32sys_t regs;
+
+ memset(&regs, 0, sizeof regs);
+ intcall(0x12, &regs, &regs);
+ insertrange(0, (uint64_t) ((uint32_t) regs.eax.w[0] << 10), 1);
+ printf(" DOS: %d K\n", regs.eax.w[0]);
+}
+
+static inline int get_e801(void)
+{
+ int err;
+ com32sys_t regs;
+
+ memset(&regs, 0, sizeof regs);
+
+ regs.eax.w[0] = 0xe801;
+ intcall(0x15, &regs, &regs);
+
+ if (!(err = regs.eflags.l & 1)) {
+ if (regs.eax.w[0]) {
+ insertrange(0x100000, (uint64_t) ((uint32_t) regs.eax.w[0] << 10),
+ 1);
+ }
+ if (regs.ebx.w[0]) {
+ insertrange(0x1000000, (uint64_t) ((uint32_t) regs.ebx.w[0] << 16),
+ 1);
+ }
+
+ printf("e801: %04x %04x\n", regs.eax.w[0], regs.ebx.w[0]);
+ }
+
+ return err;
+}
+
+static inline int get_88(void)
+{
+ com32sys_t regs;
+ int err;
+
+ memset(&regs, 0, sizeof regs);
+
+ regs.eax.b[1] = 0x88;
+ intcall(0x15, &regs, &regs);
+
+ if (!(err = regs.eflags.l & 1)) {
+ if (regs.eax.w[0]) {
+ insertrange(0x100000, (uint64_t) ((uint32_t) regs.eax.w[0] << 10),
+ 1);
+ }
+
+ printf(" 88: %04x\n", regs.eax.w[0]);
+ }
+
+ return err;
+}
+
+void get_mem(void)
+{
+ if (get_e820()) {
+ get_dos_mem();
+ if (get_e801()) {
+ if (get_88()) {
+ die("MEMDISK: Unable to obtain memory map\n");
+ }
+ }
+ }
+}
+
+#endif /* TEST */
+
+#define PW(x) (1ULL << (x))
+
+void parse_mem(void)
+{
+ struct e820range *ep;
+
+ dos_mem = low_mem = high_mem = 0;
+
+ /* Derive "dos mem", "high mem", and "low mem" from the range array */
+ for (ep = ranges; ep->type != -1U; ep++) {
+ if (ep->type == 1) {
+ /* Only look at memory ranges */
+ if (ep->start == 0) {
+ if (ep[1].start > PW(20))
+ dos_mem = PW(20);
+ else
+ dos_mem = ep[1].start;
+ }
+ if (ep->start <= PW(20) && ep[1].start > PW(20)) {
+ if (ep[1].start > PW(24))
+ low_mem = PW(24) - PW(20);
+ else
+ low_mem = ep[1].start - PW(20);
+ }
+ if (ep->start <= PW(24) && ep[1].start > PW(24)) {
+ if (ep[1].start > PW(32))
+ high_mem = PW(32) - PW(24);
+ else
+ high_mem = ep[1].start - PW(24);
+ }
+ }
+ }
+}
diff --git a/contrib/syslinux-4.02/memdisk/mstructs.h b/contrib/syslinux-4.02/memdisk/mstructs.h
new file mode 100644
index 0000000..fecbff4
--- /dev/null
+++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/memdisk/postprocess.pl b/contrib/syslinux-4.02/memdisk/postprocess.pl
new file mode 100755
index 0000000..fcda478
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/postprocess.pl
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+## -----------------------------------------------------------------------
+##
+## Copyright 2001-2008 H. Peter Anvin - 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., 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.
+##
+## -----------------------------------------------------------------------
+
+#
+# Postprocess the memdisk binary. Used during the 'make' process.
+# We write memdisk16.bin out to the final memdisk kernel, pad it to an
+# integral 512-byte sector length, write this number of sectors into the
+# kernel header field "setup_sects", then append memdisk32.bin
+
+eval { use bytes; };
+
+($out,$file16,$file32) = @ARGV;
+
+open(OUT, "> $out\0") or die "$0: Cannot create file: $out\n";
+eval { binmode OUT; };
+open(FILE, "< $file16\0") or die "$0: Cannot open file: $file16\n";
+eval { binmode FILE };
+
+@info = stat(FILE);
+$size = $info[7];
+
+$sectors = ($size + 511) >> 9;
+$xsize = $sectors << 9;
+
+read(FILE, $f16, $size);
+
+print OUT $f16;
+
+if ( $size != $xsize ) {
+ # Pad to a sector boundary
+ print OUT "\0" x ($xsize-$size);
+}
+
+seek(OUT, 0x1f1, SEEK_SET); # setup_sects
+# All sectors are setup except the first
+print OUT pack("C", $sectors-1);
+
+seek(OUT, $xsize, SEEK_SET);
+close(FILE);
+
+open(FILE, "+< $file32\0") or die "$0: Cannot open file: $file32\n";
+
+while ( ($n = read(FILE, $f32, 65536)) > 0 ) {
+ print OUT $f32;
+}
+
+close(FILE);
+close(OUT);
diff --git a/contrib/syslinux-4.02/memdisk/setup.c b/contrib/syslinux-4.02/memdisk/setup.c
new file mode 100644
index 0000000..3f69cd3
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/setup.c
@@ -0,0 +1,1189 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdint.h>
+#include "bda.h"
+#include "dskprobe.h"
+#include "e820.h"
+#include "conio.h"
+#include "version.h"
+#include "memdisk.h"
+#include "../version.h"
+
+const char memdisk_version[] = "MEMDISK " VERSION_STR " " DATE;
+const char copyright[] =
+ "Copyright " FIRSTYEAR "-" YEAR_STR " H. Peter Anvin et al";
+
+extern const char _binary_memdisk_chs_512_bin_start[];
+extern const char _binary_memdisk_chs_512_bin_end[];
+extern const char _binary_memdisk_chs_512_bin_size[];
+extern const char _binary_memdisk_edd_512_bin_start[];
+extern const char _binary_memdisk_edd_512_bin_end[];
+extern const char _binary_memdisk_edd_512_bin_size[];
+extern const char _binary_memdisk_iso_512_bin_start[];
+extern const char _binary_memdisk_iso_512_bin_end[];
+extern const char _binary_memdisk_iso_512_bin_size[];
+extern const char _binary_memdisk_iso_2048_bin_start[];
+extern const char _binary_memdisk_iso_2048_bin_end[];
+extern const char _binary_memdisk_iso_2048_bin_size[];
+
+/* Pull in structures common to MEMDISK and MDISKCHK.COM */
+#include "mstructs.h"
+
+/* An EDD disk packet */
+struct edd_dsk_pkt {
+ uint8_t size; /* Packet size */
+ uint8_t res1; /* Reserved */
+ uint16_t count; /* Count to transfer */
+ uint32_t buf; /* Buffer pointer */
+ uint64_t start; /* LBA to start from */
+ uint64_t buf64; /* 64-bit buf pointer */
+} __attribute__ ((packed));
+
+/* Change to 1 for El Torito debugging */
+#define DBG_ELTORITO 0
+
+#if DBG_ELTORITO
+extern void eltorito_dump(uint32_t);
+#endif
+
+/*
+ * Routine to seek for a command-line item and return a pointer
+ * to the data portion, if present
+ */
+
+/* Magic return values */
+#define CMD_NOTFOUND ((char *)-1) /* Not found */
+#define CMD_BOOL ((char *)-2) /* Found boolean option */
+#define CMD_HASDATA(X) ((int)(X) >= 0)
+
+static const char *getcmditem(const char *what)
+{
+ const char *p;
+ const char *wp = what;
+ int match = 0;
+
+ for (p = shdr->cmdline; *p; p++) {
+ switch (match) {
+ case 0: /* Ground state */
+ if (*p == ' ')
+ break;
+
+ wp = what;
+ match = 1;
+ /* Fall through */
+
+ case 1: /* Matching */
+ if (*wp == '\0') {
+ if (*p == '=')
+ return p + 1;
+ else if (*p == ' ')
+ return CMD_BOOL;
+ else {
+ match = 2;
+ break;
+ }
+ }
+ if (*p != *wp++)
+ match = 2;
+ break;
+
+ case 2: /* Mismatch, skip rest of option */
+ if (*p == ' ')
+ match = 0; /* Next option */
+ break;
+ }
+ }
+
+ /* Check for matching string at end of line */
+ if (match == 1 && *wp == '\0')
+ return CMD_BOOL;
+
+ return CMD_NOTFOUND;
+}
+
+/*
+ * Check to see if this is a gzip image
+ */
+#define UNZIP_ALIGN 512
+
+extern void _end; /* Symbol signalling end of data */
+
+void unzip_if_needed(uint32_t * where_p, uint32_t * size_p)
+{
+ uint32_t where = *where_p;
+ uint32_t size = *size_p;
+ uint32_t zbytes;
+ uint32_t startrange, endrange;
+ uint32_t gzdatasize, gzwhere;
+ uint32_t orig_crc, offset;
+ uint32_t target = 0;
+ int i, okmem;
+
+ /* Is it a gzip image? */
+ if (check_zip((void *)where, size, &zbytes, &gzdatasize,
+ &orig_crc, &offset) == 0) {
+
+ if (offset + zbytes > size) {
+ /*
+ * Assertion failure; check_zip is supposed to guarantee this
+ * never happens.
+ */
+ die("internal error: check_zip returned nonsense\n");
+ }
+
+ /*
+ * Find a good place to put it: search memory ranges in descending
+ * order until we find one that is legal and fits
+ */
+ okmem = 0;
+ for (i = nranges - 1; i >= 0; i--) {
+ /*
+ * We can't use > 4G memory (32 bits only.) Truncate to 2^32-1
+ * so we don't have to deal with funny wraparound issues.
+ */
+
+ /* Must be memory */
+ if (ranges[i].type != 1)
+ continue;
+
+ /* Range start */
+ if (ranges[i].start >= 0xFFFFFFFF)
+ continue;
+
+ startrange = (uint32_t) ranges[i].start;
+
+ /* Range end (0 for end means 2^64) */
+ endrange = ((ranges[i + 1].start >= 0xFFFFFFFF ||
+ ranges[i + 1].start == 0)
+ ? 0xFFFFFFFF : (uint32_t) ranges[i + 1].start);
+
+ /* Make sure we don't overwrite ourselves */
+ if (startrange < (uint32_t) & _end)
+ startrange = (uint32_t) & _end;
+
+ /* Allow for alignment */
+ startrange =
+ (ranges[i].start + (UNZIP_ALIGN - 1)) & ~(UNZIP_ALIGN - 1);
+
+ /* In case we just killed the whole range... */
+ if (startrange >= endrange)
+ continue;
+
+ /*
+ * Must be large enough... don't rely on gzwhere for this
+ * (wraparound)
+ */
+ if (endrange - startrange < gzdatasize)
+ continue;
+
+ /*
+ * This is where the gz image would be put if we put it in this
+ * range...
+ */
+ gzwhere = (endrange - gzdatasize) & ~(UNZIP_ALIGN - 1);
+
+ /* Cast to uint64_t just in case we're flush with the top byte */
+ if ((uint64_t) where + size >= gzwhere && where < endrange) {
+ /*
+ * Need to move source data to avoid compressed/uncompressed
+ * overlap
+ */
+ uint32_t newwhere;
+
+ if (gzwhere - startrange < size)
+ continue; /* Can't fit both old and new */
+
+ newwhere = (gzwhere - size) & ~(UNZIP_ALIGN - 1);
+ printf("Moving compressed data from 0x%08x to 0x%08x\n",
+ where, newwhere);
+
+ memmove((void *)newwhere, (void *)where, size);
+ where = newwhere;
+ }
+
+ target = gzwhere;
+ okmem = 1;
+ break;
+ }
+
+ if (!okmem)
+ die("Not enough memory to decompress image (need 0x%08x bytes)\n",
+ gzdatasize);
+
+ printf("gzip image: decompressed addr 0x%08x, len 0x%08x: ",
+ target, gzdatasize);
+
+ *size_p = gzdatasize;
+ *where_p = (uint32_t) unzip((void *)(where + offset), zbytes,
+ gzdatasize, orig_crc, (void *)target);
+ }
+}
+
+/*
+ * Figure out the "geometry" of the disk in question
+ */
+struct geometry {
+ uint32_t sectors; /* Sector count */
+ uint32_t c, h, s; /* C/H/S geometry */
+ uint32_t offset; /* Byte offset for disk */
+ uint32_t boot_lba; /* LBA of bootstrap code */
+ uint8_t type; /* Type byte for INT 13h AH=08h */
+ uint8_t driveno; /* Drive no */
+ uint8_t sector_shift; /* Sector size as a power of 2 */
+ const char *hsrc, *ssrc; /* Origins of H and S geometries */
+};
+
+/* Format of a DOS partition table entry */
+struct ptab_entry {
+ uint8_t active;
+ uint8_t start_h, start_s, start_c;
+ uint8_t type;
+ uint8_t end_h, end_s, end_c;
+ uint32_t start;
+ uint32_t size;
+} __attribute__ ((packed));
+
+/* Format of a FAT filesystem superblock */
+struct fat_extra {
+ uint8_t bs_drvnum;
+ uint8_t bs_resv1;
+ uint8_t bs_bootsig;
+ uint32_t bs_volid;
+ char bs_vollab[11];
+ char bs_filsystype[8];
+} __attribute__ ((packed));
+struct fat_super {
+ uint8_t bs_jmpboot[3];
+ char bs_oemname[8];
+ uint16_t bpb_bytspersec;
+ uint8_t bpb_secperclus;
+ uint16_t bpb_rsvdseccnt;
+ uint8_t bpb_numfats;
+ uint16_t bpb_rootentcnt;
+ uint16_t bpb_totsec16;
+ uint8_t bpb_media;
+ uint16_t bpb_fatsz16;
+ uint16_t bpb_secpertrk;
+ uint16_t bpb_numheads;
+ uint32_t bpb_hiddsec;
+ uint32_t bpb_totsec32;
+ union {
+ struct {
+ struct fat_extra extra;
+ } fat16;
+ struct {
+ uint32_t bpb_fatsz32;
+ uint16_t bpb_extflags;
+ uint16_t bpb_fsver;
+ uint32_t bpb_rootclus;
+ uint16_t bpb_fsinfo;
+ uint16_t bpb_bkbootsec;
+ char bpb_reserved[12];
+ /* Clever, eh? Same fields, different offset... */
+ struct fat_extra extra;
+ } fat32 __attribute__ ((packed));
+ } x;
+} __attribute__ ((packed));
+
+/* Format of a DOSEMU header */
+struct dosemu_header {
+ uint8_t magic[7]; /* DOSEMU\0 */
+ uint32_t h;
+ uint32_t s;
+ uint32_t c;
+ uint32_t offset;
+ uint8_t pad[105];
+} __attribute__ ((packed));
+
+#define FOUR(a,b,c,d) (((a) << 24)|((b) << 16)|((c) << 8)|(d))
+
+static const struct geometry *get_disk_image_geometry(uint32_t where,
+ uint32_t size)
+{
+ static struct geometry hd_geometry;
+ struct dosemu_header dosemu;
+ unsigned int sectors, xsectors, v;
+ unsigned int offset;
+ int i;
+ const char *p;
+
+ printf("command line: %s\n", shdr->cmdline);
+
+ hd_geometry.sector_shift = 9; /* Assume floppy/HDD at first */
+
+ offset = 0;
+ if (CMD_HASDATA(p = getcmditem("offset")) && (v = atou(p)))
+ offset = v;
+
+ sectors = xsectors = (size - offset) >> hd_geometry.sector_shift;
+
+ hd_geometry.hsrc = "guess";
+ hd_geometry.ssrc = "guess";
+ hd_geometry.sectors = sectors;
+ hd_geometry.offset = offset;
+
+ if ((p = getcmditem("iso")) != CMD_NOTFOUND) {
+#if DBG_ELTORITO
+ eltorito_dump(where);
+#endif
+ struct edd4_bvd *bvd = (struct edd4_bvd *)(where + 17 * 2048);
+ /* Tiny sanity check */
+ if ((bvd->boot_rec_ind != 0) || (bvd->ver != 1))
+ printf("El Torito BVD sanity check failed.\n");
+ struct edd4_bootcat *boot_cat =
+ (struct edd4_bootcat *)(where + bvd->boot_cat * 2048);
+ /* Another tiny sanity check */
+ if ((boot_cat->validation_entry.platform_id != 0) ||
+ (boot_cat->validation_entry.key55 != 0x55) ||
+ (boot_cat->validation_entry.keyAA != 0xAA))
+ printf("El Torito boot catalog sanity check failed.\n");
+ /* If we have an emulation mode, set the offset to the image */
+ if (boot_cat->initial_entry.media_type)
+ hd_geometry.offset += boot_cat->initial_entry.load_block * 2048;
+ else
+ /* We're a no-emulation mode, so we will boot to an offset */
+ hd_geometry.boot_lba = boot_cat->initial_entry.load_block * 4;
+ if (boot_cat->initial_entry.media_type < 4) {
+ /* We're a floppy emulation mode or our params will be
+ * overwritten by the no emulation mode case
+ */
+ hd_geometry.driveno = 0x00;
+ hd_geometry.c = 80;
+ hd_geometry.h = 2;
+ }
+ switch (boot_cat->initial_entry.media_type) {
+ case 0: /* No emulation */
+ hd_geometry.driveno = 0xE0;
+ hd_geometry.type = 10; /* ATAPI removable media device */
+ hd_geometry.c = 65535;
+ hd_geometry.h = 255;
+ hd_geometry.s = 15;
+ /* 2048-byte sectors, so adjust the size and count */
+ hd_geometry.sector_shift = 11;
+ break;
+ case 1: /* 1.2 MB floppy */
+ hd_geometry.s = 15;
+ hd_geometry.type = 2;
+ sectors = 2400;
+ break;
+ case 2: /* 1.44 MB floppy */
+ hd_geometry.s = 18;
+ hd_geometry.type = 4;
+ sectors = 2880;
+ break;
+ case 3: /* 2.88 MB floppy */
+ hd_geometry.s = 36;
+ hd_geometry.type = 6;
+ sectors = 5760;
+ break;
+ case 4:
+ hd_geometry.driveno = 0x80;
+ hd_geometry.type = 0;
+ break;
+ }
+ sectors = (size - hd_geometry.offset) >> hd_geometry.sector_shift;
+
+ /* For HDD emulation, we figure out the geometry later. Otherwise: */
+ if (hd_geometry.s) {
+ hd_geometry.hsrc = hd_geometry.ssrc = "El Torito";
+ }
+ hd_geometry.sectors = sectors;
+ }
+
+ /* Do we have a DOSEMU header? */
+ memcpy(&dosemu, (char *)where + hd_geometry.offset, sizeof dosemu);
+ if (!memcmp("DOSEMU", dosemu.magic, 7)) {
+ /* Always a hard disk unless overruled by command-line options */
+ hd_geometry.driveno = 0x80;
+ hd_geometry.type = 0;
+ hd_geometry.c = dosemu.c;
+ hd_geometry.h = dosemu.h;
+ hd_geometry.s = dosemu.s;
+ hd_geometry.offset += dosemu.offset;
+ sectors = (size - hd_geometry.offset) >> hd_geometry.sector_shift;
+
+ hd_geometry.hsrc = hd_geometry.ssrc = "DOSEMU";
+ }
+
+ if (CMD_HASDATA(p = getcmditem("c")) && (v = atou(p)))
+ hd_geometry.c = v;
+ if (CMD_HASDATA(p = getcmditem("h")) && (v = atou(p))) {
+ hd_geometry.h = v;
+ hd_geometry.hsrc = "cmd";
+ }
+ if (CMD_HASDATA(p = getcmditem("s")) && (v = atou(p))) {
+ hd_geometry.s = v;
+ hd_geometry.ssrc = "cmd";
+ }
+
+ if (!hd_geometry.h || !hd_geometry.s) {
+ int h, s, max_h, max_s;
+
+ max_h = hd_geometry.h;
+ max_s = hd_geometry.s;
+
+ if (!(max_h | max_s)) {
+ /* Look for a FAT superblock and if we find something that looks
+ enough like one, use geometry from that. This takes care of
+ megafloppy images and unpartitioned hard disks. */
+ const struct fat_extra *extra = NULL;
+ const struct fat_super *fs = (const struct fat_super *)
+ ((char *)where + hd_geometry.offset);
+
+ if ((fs->bpb_media == 0xf0 || fs->bpb_media >= 0xf8) &&
+ (fs->bs_jmpboot[0] == 0xe9 || fs->bs_jmpboot[0] == 0xeb) &&
+ fs->bpb_bytspersec == 512 &&
+ fs->bpb_numheads >= 1 && fs->bpb_numheads <= 256 &&
+ fs->bpb_secpertrk >= 1 && fs->bpb_secpertrk <= 63) {
+ extra =
+ fs->bpb_fatsz16 ? &fs->x.fat16.extra : &fs->x.fat32.extra;
+ if (!
+ (extra->bs_bootsig == 0x29 && extra->bs_filsystype[0] == 'F'
+ && extra->bs_filsystype[1] == 'A'
+ && extra->bs_filsystype[2] == 'T'))
+ extra = NULL;
+ }
+ if (extra) {
+ hd_geometry.driveno = extra->bs_drvnum & 0x80;
+ max_h = fs->bpb_numheads;
+ max_s = fs->bpb_secpertrk;
+ hd_geometry.hsrc = hd_geometry.ssrc = "FAT";
+ }
+ }
+
+ if (!(max_h | max_s)) {
+ /* No FAT filesystem found to steal geometry from... */
+ if ((sectors < 4096 * 2) && (hd_geometry.sector_shift == 9)) {
+ int ok = 0;
+ unsigned int xsectors = sectors;
+
+ hd_geometry.driveno = 0; /* Assume floppy */
+
+ while (!ok) {
+ /* Assume it's a floppy drive, guess a geometry */
+ unsigned int type, track;
+ int c, h, s = 0;
+
+ if (xsectors < 320 * 2) {
+ c = 40;
+ h = 1;
+ type = 1;
+ } else if (xsectors < 640 * 2) {
+ c = 40;
+ h = 2;
+ type = 1;
+ } else if (xsectors < 1200 * 2) {
+ c = 80;
+ h = 2;
+ type = 3;
+ } else if (xsectors < 1440 * 2) {
+ c = 80;
+ h = 2;
+ type = 2;
+ } else if (xsectors < 2880 * 2) {
+ c = 80;
+ h = 2;
+ type = 4;
+ } else {
+ c = 80;
+ h = 2;
+ type = 6;
+ }
+ track = c * h;
+ while (c < 256) {
+ s = xsectors / track;
+ if (s < 63 && (xsectors % track) == 0) {
+ ok = 1;
+ break;
+ }
+ c++;
+ track += h;
+ }
+ if (ok) {
+ max_h = h;
+ max_s = s;
+ hd_geometry.hsrc = hd_geometry.ssrc = "fd";
+ } else {
+ /* No valid floppy geometry, fake it by simulating broken
+ sectors at the end of the image... */
+ xsectors++;
+ }
+ }
+ } else {
+ /* Assume it is a hard disk image and scan for a partition table */
+ const struct ptab_entry *ptab = (const struct ptab_entry *)
+ ((char *)where + hd_geometry.offset + (512 - 2 - 4 * 16));
+
+ /* Assume hard disk */
+ if (!hd_geometry.driveno)
+ hd_geometry.driveno = 0x80;
+
+ if (*(uint16_t *) ((char *)where + hd_geometry.offset + 512 - 2) == 0xaa55) {
+ for (i = 0; i < 4; i++) {
+ if (ptab[i].type && !(ptab[i].active & 0x7f)) {
+ s = (ptab[i].start_s & 0x3f);
+ h = ptab[i].start_h + 1;
+
+ if (max_h < h)
+ max_h = h;
+ if (max_s < s)
+ max_s = s;
+
+ s = (ptab[i].end_s & 0x3f);
+ h = ptab[i].end_h + 1;
+
+ if (max_h < h) {
+ max_h = h;
+ hd_geometry.hsrc = "MBR";
+ }
+ if (max_s < s) {
+ max_s = s;
+ hd_geometry.ssrc = "MBR";
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!max_h)
+ max_h = xsectors > 2097152 ? 255 : 64;
+ if (!max_s)
+ max_s = xsectors > 2097152 ? 63 : 32;
+
+ hd_geometry.h = max_h;
+ hd_geometry.s = max_s;
+ }
+
+ if (!hd_geometry.c)
+ hd_geometry.c = xsectors / (hd_geometry.h * hd_geometry.s);
+
+ if ((p = getcmditem("floppy")) != CMD_NOTFOUND) {
+ hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) & 0x7f : 0;
+ } else if ((p = getcmditem("harddisk")) != CMD_NOTFOUND) {
+ hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) | 0x80 : 0x80;
+ }
+
+ if (hd_geometry.driveno & 0x80) {
+ hd_geometry.type = 0; /* Type = hard disk */
+ } else {
+ if (hd_geometry.type == 0)
+ hd_geometry.type = 0x10; /* ATAPI floppy, e.g. LS-120 */
+ }
+
+ if ((size - hd_geometry.offset) & 0x1ff) {
+ puts("MEMDISK: Image has fractional end sector\n");
+ }
+ if (sectors % (hd_geometry.h * hd_geometry.s)) {
+ puts("MEMDISK: Image seems to have fractional end cylinder\n");
+ }
+ if ((hd_geometry.c * hd_geometry.h * hd_geometry.s) > sectors) {
+ puts("MEMDISK: Image appears to be truncated\n");
+ }
+
+ return &hd_geometry;
+}
+
+/*
+ * Find a $PnP installation check structure; return (ES << 16) + DI value
+ */
+static uint32_t pnp_install_check(void)
+{
+ uint32_t *seg;
+ unsigned char *p, csum;
+ int i, len;
+
+ for (seg = (uint32_t *) 0xf0000; seg < (uint32_t *) 0x100000; seg += 4) {
+ if (*seg == ('$' + ('P' << 8) + ('n' << 16) + ('P' << 24))) {
+ p = (unsigned char *)seg;
+ len = p[5];
+ if (len < 0x21)
+ continue;
+ csum = 0;
+ for (i = len; i; i--)
+ csum += *p++;
+ if (csum != 0)
+ continue;
+
+ return (0xf000 << 16) + (uint16_t) (unsigned long)seg;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Relocate the real-mode code to a new segment
+ */
+struct gdt_ptr {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__ ((packed));
+
+static void set_seg_base(uint32_t gdt_base, int seg, uint32_t v)
+{
+ *(uint16_t *) (gdt_base + seg + 2) = v;
+ *(uint8_t *) (gdt_base + seg + 4) = v >> 16;
+ *(uint8_t *) (gdt_base + seg + 7) = v >> 24;
+}
+
+static void relocate_rm_code(uint32_t newbase)
+{
+ uint32_t gdt_base;
+ uint32_t oldbase = rm_args.rm_base;
+ uint32_t delta = newbase - oldbase;
+
+ cli();
+ memmove((void *)newbase, (void *)oldbase, rm_args.rm_size);
+
+ rm_args.rm_return += delta;
+ rm_args.rm_intcall += delta;
+ rm_args.rm_bounce += delta;
+ rm_args.rm_base += delta;
+ rm_args.rm_gdt += delta;
+ rm_args.rm_pmjmp += delta;
+ rm_args.rm_rmjmp += delta;
+
+ gdt_base = rm_args.rm_gdt;
+
+ *(uint32_t *) (gdt_base + 2) = gdt_base; /* GDT self-pointer */
+
+ /* Segments 0x10 and 0x18 are real-mode-based */
+ set_seg_base(gdt_base, 0x10, rm_args.rm_base);
+ set_seg_base(gdt_base, 0x18, rm_args.rm_base);
+
+ asm volatile ("lgdtl %0"::"m" (*(char *)gdt_base));
+
+ *(uint32_t *) rm_args.rm_pmjmp += delta;
+ *(uint16_t *) rm_args.rm_rmjmp += delta >> 4;
+
+ rm_args.rm_handle_interrupt += delta;
+
+ sti();
+}
+
+static uint8_t checksum_buf(const void *buf, int count)
+{
+ const uint8_t *p = buf;
+ uint8_t c = 0;
+
+ while (count--)
+ c += *p++;
+
+ return c;
+}
+
+static int stack_needed(void)
+{
+ const unsigned int min_stack = 128; /* Minimum stack size */
+ const unsigned int def_stack = 512; /* Default stack size */
+ unsigned int v = 0;
+ const char *p;
+
+ if (CMD_HASDATA(p = getcmditem("stack")))
+ v = atou(p);
+
+ if (!v)
+ v = def_stack;
+
+ if (v < min_stack)
+ v = min_stack;
+
+ return v;
+}
+
+struct real_mode_args rm_args;
+
+/*
+ * Actual setup routine
+ * Returns the drive number (which is then passed in %dl to the
+ * called routine.)
+ */
+void setup(const struct real_mode_args *rm_args_ptr)
+{
+ unsigned int bin_size;
+ char *memdisk_hook;
+ struct memdisk_header *hptr;
+ struct patch_area *pptr;
+ struct mBFT *mbft;
+ uint16_t driverseg;
+ uint32_t driverptr, driveraddr;
+ uint16_t dosmem_k;
+ uint32_t stddosmem;
+ const struct geometry *geometry;
+ unsigned int total_size;
+ unsigned int cmdline_len, stack_len, e820_len;
+ const struct edd4_bvd *bvd;
+ const struct edd4_bootcat *boot_cat = 0;
+ com32sys_t regs;
+ uint32_t ramdisk_image, ramdisk_size;
+ uint32_t boot_base, rm_base;
+ int bios_drives;
+ int do_edd = 1; /* 0 = no, 1 = yes, default is yes */
+ int do_eltorito = 0; /* default is no */
+ int no_bpt; /* No valid BPT presented */
+ uint32_t boot_seg = 0; /* Meaning 0000:7C00 */
+ uint32_t boot_len = 512; /* One sector */
+
+ /* We need to copy the rm_args into their proper place */
+ memcpy(&rm_args, rm_args_ptr, sizeof rm_args);
+ sti(); /* ... then interrupts are safe */
+
+ /* Show signs of life */
+ printf("%s %s\n", memdisk_version, copyright);
+
+ if (!shdr->ramdisk_image || !shdr->ramdisk_size)
+ die("MEMDISK: No ramdisk image specified!\n");
+
+ ramdisk_image = shdr->ramdisk_image;
+ ramdisk_size = shdr->ramdisk_size;
+
+ e820map_init(); /* Initialize memory data structure */
+ get_mem(); /* Query BIOS for memory map */
+ parse_mem(); /* Parse memory map */
+
+ printf("Ramdisk at 0x%08x, length 0x%08x\n", ramdisk_image, ramdisk_size);
+
+ unzip_if_needed(&ramdisk_image, &ramdisk_size);
+
+ geometry = get_disk_image_geometry(ramdisk_image, ramdisk_size);
+
+ if (getcmditem("edd") != CMD_NOTFOUND ||
+ getcmditem("ebios") != CMD_NOTFOUND)
+ do_edd = 1;
+ else if (getcmditem("noedd") != CMD_NOTFOUND ||
+ getcmditem("noebios") != CMD_NOTFOUND ||
+ getcmditem("cbios") != CMD_NOTFOUND)
+ do_edd = 0;
+ else
+ do_edd = (geometry->driveno & 0x80) ? 1 : 0;
+
+ if (getcmditem("iso") != CMD_NOTFOUND) {
+ do_eltorito = 1;
+ do_edd = 1; /* Mandatory */
+ }
+
+ /* Choose the appropriate installable memdisk hook */
+ if (do_eltorito) {
+ if (geometry->sector_shift == 11) {
+ bin_size = (int)&_binary_memdisk_iso_2048_bin_size;
+ memdisk_hook = (char *)&_binary_memdisk_iso_2048_bin_start;
+ } else {
+ bin_size = (int)&_binary_memdisk_iso_512_bin_size;
+ memdisk_hook = (char *)&_binary_memdisk_iso_512_bin_start;
+ }
+ } else {
+ if (do_edd) {
+ bin_size = (int)&_binary_memdisk_edd_512_bin_size;
+ memdisk_hook = (char *)&_binary_memdisk_edd_512_bin_start;
+ } else {
+ bin_size = (int)&_binary_memdisk_chs_512_bin_size;
+ memdisk_hook = (char *)&_binary_memdisk_chs_512_bin_start;
+ }
+ }
+
+ /* Reserve the ramdisk memory */
+ insertrange(ramdisk_image, ramdisk_size, 2);
+ parse_mem(); /* Recompute variables */
+
+ /* Figure out where it needs to go */
+ hptr = (struct memdisk_header *)memdisk_hook;
+ pptr = (struct patch_area *)(memdisk_hook + hptr->patch_offs);
+
+ dosmem_k = rdz_16(BIOS_BASEMEM);
+ pptr->mdi.olddosmem = dosmem_k;
+ stddosmem = dosmem_k << 10;
+ /* If INT 15 E820 and INT 12 disagree, go with the most conservative */
+ if (stddosmem > dos_mem)
+ stddosmem = dos_mem;
+
+ pptr->driveno = geometry->driveno;
+ pptr->drivetype = geometry->type;
+ pptr->cylinders = geometry->c; /* Possible precision loss */
+ pptr->heads = geometry->h;
+ pptr->sectors = geometry->s;
+ pptr->mdi.disksize = geometry->sectors;
+ pptr->mdi.diskbuf = ramdisk_image + geometry->offset;
+ pptr->mdi.sector_shift = geometry->sector_shift;
+ pptr->statusptr = (geometry->driveno & 0x80) ? 0x474 : 0x441;
+
+ pptr->mdi.bootloaderid = shdr->type_of_loader;
+
+ pptr->configflags = CONFIG_SAFEINT; /* Default */
+ /* Set config flags */
+ if (getcmditem("ro") != CMD_NOTFOUND) {
+ pptr->configflags |= CONFIG_READONLY;
+ }
+ if (getcmditem("raw") != CMD_NOTFOUND) {
+ pptr->configflags &= ~CONFIG_MODEMASK;
+ pptr->configflags |= CONFIG_RAW;
+ }
+ if (getcmditem("bigraw") != CMD_NOTFOUND) {
+ pptr->configflags &= ~CONFIG_MODEMASK;
+ pptr->configflags |= CONFIG_BIGRAW | CONFIG_RAW;
+ }
+ if (getcmditem("int") != CMD_NOTFOUND) {
+ pptr->configflags &= ~CONFIG_MODEMASK;
+ /* pptr->configflags |= 0; */
+ }
+ if (getcmditem("safeint") != CMD_NOTFOUND) {
+ pptr->configflags &= ~CONFIG_MODEMASK;
+ pptr->configflags |= CONFIG_SAFEINT;
+ }
+
+ printf("Disk is %s%d, %u%s K, C/H/S = %u/%u/%u (%s/%s), EDD %s, %s\n",
+ (geometry->driveno & 0x80) ? "hd" : "fd",
+ geometry->driveno & 0x7f,
+ geometry->sectors >> 1,
+ (geometry->sectors & 1) ? ".5" : "",
+ geometry->c, geometry->h, geometry->s,
+ geometry->hsrc, geometry->ssrc,
+ do_edd ? "on" : "off",
+ pptr->configflags & CONFIG_READONLY ? "ro" : "rw");
+
+ puts("Using ");
+ switch (pptr->configflags & CONFIG_MODEMASK) {
+ case 0:
+ puts("standard INT 15h");
+ break;
+ case CONFIG_SAFEINT:
+ puts("safe INT 15h");
+ break;
+ case CONFIG_RAW:
+ puts("raw");
+ break;
+ case CONFIG_RAW | CONFIG_BIGRAW:
+ puts("big real mode raw");
+ break;
+ default:
+ printf("unknown %#x", pptr->configflags & CONFIG_MODEMASK);
+ break;
+ }
+ puts(" access to high memory\n");
+
+ /* Set up a drive parameter table */
+ if (geometry->driveno & 0x80) {
+ /* Hard disk */
+ pptr->dpt.hd.max_cyl = geometry->c - 1;
+ pptr->dpt.hd.max_head = geometry->h - 1;
+ pptr->dpt.hd.ctrl = (geometry->h > 8) ? 0x08 : 0;
+ } else {
+ /* Floppy - most of these fields are bogus and mimic
+ a 1.44 MB floppy drive */
+ pptr->dpt.fd.specify1 = 0xdf;
+ pptr->dpt.fd.specify2 = 0x02;
+ pptr->dpt.fd.delay = 0x25;
+ pptr->dpt.fd.sectors = geometry->s;
+ pptr->dpt.fd.bps = 0x02;
+ pptr->dpt.fd.isgap = 0x12;
+ pptr->dpt.fd.dlen = 0xff;
+ pptr->dpt.fd.fgap = 0x6c;
+ pptr->dpt.fd.ffill = 0xf6;
+ pptr->dpt.fd.settle = 0x0f;
+ pptr->dpt.fd.mstart = 0x05;
+ pptr->dpt.fd.maxtrack = geometry->c - 1;
+ pptr->dpt.fd.cmos = geometry->type > 5 ? 5 : geometry->type;
+
+ pptr->dpt.fd.old_fd_dpt = rdz_32(BIOS_INT1E);
+ }
+
+ /* Set up an EDD drive parameter table */
+ if (do_edd) {
+ pptr->edd_dpt.sectors = geometry->sectors;
+ /* The EDD spec has this as <= 15482880 sectors (1024x240x63);
+ this seems to make very little sense. Try for something saner. */
+ if (geometry->c <= 1024 && geometry->h <= 255 && geometry->s <= 63) {
+ pptr->edd_dpt.c = geometry->c;
+ pptr->edd_dpt.h = geometry->h;
+ pptr->edd_dpt.s = geometry->s;
+ /* EDD-4 states that invalid geometry should be returned
+ * for INT 0x13, AH=0x48 "EDD Get Disk Parameters" call on an
+ * El Torito ODD. Check for 2048-byte sector size
+ */
+ if (geometry->sector_shift != 11)
+ pptr->edd_dpt.flags |= 0x0002; /* Geometry valid */
+ }
+ if (!(geometry->driveno & 0x80)) {
+ /* Floppy drive. Mark it as a removable device with
+ media change notification; media is present. */
+ pptr->edd_dpt.flags |= 0x0014;
+ }
+
+ pptr->edd_dpt.devpath[0] = pptr->mdi.diskbuf;
+ pptr->edd_dpt.chksum = -checksum_buf(&pptr->edd_dpt.dpikey, 73 - 30);
+ }
+
+ if (do_eltorito) {
+ bvd = (struct edd4_bvd *)(ramdisk_image + 17 * 2048);
+ boot_cat =
+ (struct edd4_bootcat *)(ramdisk_image + bvd->boot_cat * 2048);
+ pptr->cd_pkt.type = boot_cat->initial_entry.media_type; /* Cheat */
+ pptr->cd_pkt.driveno = geometry->driveno;
+ pptr->cd_pkt.start = boot_cat->initial_entry.load_block;
+ boot_seg = pptr->cd_pkt.load_seg = boot_cat->initial_entry.load_seg;
+ pptr->cd_pkt.sect_count = boot_cat->initial_entry.sect_count;
+ boot_len = pptr->cd_pkt.sect_count * 512;
+ pptr->cd_pkt.geom1 = (uint8_t)(pptr->cylinders) & 0xFF;
+ pptr->cd_pkt.geom2 =
+ (uint8_t)(pptr->sectors) | (uint8_t)((pptr->cylinders >> 2) & 0xC0);
+ pptr->cd_pkt.geom3 = (uint8_t)(pptr->heads);
+ }
+
+ /* The size is given by hptr->total_size plus the size of the E820
+ map -- 12 bytes per range; we may need as many as 2 additional
+ ranges (each insertrange() can worst-case turn 1 area into 3)
+ plus the terminating range, over what nranges currently show. */
+ total_size = hptr->total_size; /* Actual memdisk code */
+ e820_len = (nranges + 3) * sizeof(ranges[0]);
+ total_size += e820_len; /* E820 memory ranges */
+ cmdline_len = strlen(shdr->cmdline) + 1;
+ total_size += cmdline_len; /* Command line */
+ stack_len = stack_needed();
+ total_size += stack_len; /* Stack */
+ printf("Code %u, meminfo %u, cmdline %u, stack %u\n",
+ hptr->total_size, e820_len, cmdline_len, stack_len);
+ printf("Total size needed = %u bytes, allocating %uK\n",
+ total_size, (total_size + 0x3ff) >> 10);
+
+ if (total_size > dos_mem)
+ die("MEMDISK: Insufficient low memory\n");
+
+ driveraddr = stddosmem - total_size;
+ driveraddr &= ~0x3FF;
+
+ printf("Old dos memory at 0x%05x (map says 0x%05x), loading at 0x%05x\n",
+ stddosmem, dos_mem, driveraddr);
+
+ /* Reserve this range of memory */
+ wrz_16(BIOS_BASEMEM, driveraddr >> 10);
+ insertrange(driveraddr, dos_mem - driveraddr, 2);
+ parse_mem();
+
+ pptr->mem1mb = low_mem >> 10;
+ pptr->mem16mb = high_mem >> 16;
+ if (low_mem == (15 << 20)) {
+ /* lowmem maxed out */
+ uint32_t int1588mem = (high_mem >> 10) + (low_mem >> 10);
+ pptr->memint1588 = (int1588mem > 0xffff) ? 0xffff : int1588mem;
+ } else {
+ pptr->memint1588 = low_mem >> 10;
+ }
+
+ printf("1588: 0x%04x 15E801: 0x%04x 0x%04x\n",
+ pptr->memint1588, pptr->mem1mb, pptr->mem16mb);
+
+ driverseg = driveraddr >> 4;
+ driverptr = driverseg << 16;
+
+ /* Anything beyond the end is for the stack */
+ pptr->mystack = (uint16_t) (stddosmem - driveraddr);
+
+ pptr->mdi.oldint13.uint32 = rdz_32(BIOS_INT13);
+ pptr->mdi.oldint15.uint32 = rdz_32(BIOS_INT15);
+
+ /* Adjust the E820 table: if there are null ranges (type 0)
+ at the end, change them to type end of list (-1).
+ This is necessary for the driver to be able to report end
+ of list correctly. */
+ while (nranges && ranges[nranges - 1].type == 0) {
+ ranges[--nranges].type = -1;
+ }
+
+ if (getcmditem("nopassany") != CMD_NOTFOUND) {
+ printf("nopassany specified - we're the only drive of any kind\n");
+ bios_drives = 0;
+ pptr->drivecnt = 0;
+ no_bpt = 1;
+ pptr->mdi.oldint13.uint32 = driverptr + hptr->iret_offs;
+ wrz_8(BIOS_EQUIP, rdz_8(BIOS_EQUIP) & ~0xc1);
+ wrz_8(BIOS_HD_COUNT, 0);
+ } else if (getcmditem("nopass") != CMD_NOTFOUND) {
+ printf("nopass specified - we're the only drive\n");
+ bios_drives = 0;
+ pptr->drivecnt = 0;
+ no_bpt = 1;
+ } else {
+ /* Query drive parameters of this type */
+ memset(&regs, 0, sizeof regs);
+ regs.es = 0;
+ regs.eax.b[1] = 0x08;
+ regs.edx.b[0] = geometry->driveno & 0x80;
+ intcall(0x13, &regs, &regs);
+
+ /* Note: per suggestion from the Interrupt List, consider
+ INT 13 08 to have failed if the sector count in CL is zero. */
+ if ((regs.eflags.l & 1) || !(regs.ecx.b[0] & 0x3f)) {
+ printf("INT 13 08: Failure, assuming this is the only drive\n");
+ pptr->drivecnt = 0;
+ no_bpt = 1;
+ } else {
+ printf("INT 13 08: Success, count = %u, BPT = %04x:%04x\n",
+ regs.edx.b[0], regs.es, regs.edi.w[0]);
+ pptr->drivecnt = regs.edx.b[0];
+ no_bpt = !(regs.es | regs.edi.w[0]);
+ }
+
+ /* Compare what INT 13h returned with the appropriate equipment byte */
+ if (geometry->driveno & 0x80) {
+ bios_drives = rdz_8(BIOS_HD_COUNT);
+ } else {
+ uint8_t equip = rdz_8(BIOS_EQUIP);
+
+ if (equip & 1)
+ bios_drives = (equip >> 6) + 1;
+ else
+ bios_drives = 0;
+ }
+
+ if (pptr->drivecnt > bios_drives) {
+ printf("BIOS equipment byte says count = %d, go with that\n",
+ bios_drives);
+ pptr->drivecnt = bios_drives;
+ }
+ }
+
+ /* Add ourselves to the drive count */
+ pptr->drivecnt++;
+
+ /* Discontiguous drive space. There is no really good solution for this. */
+ if (pptr->drivecnt <= (geometry->driveno & 0x7f))
+ pptr->drivecnt = (geometry->driveno & 0x7f) + 1;
+
+ /* Probe for contiguous range of BIOS drives starting with driveno */
+ pptr->driveshiftlimit = probe_drive_range(geometry->driveno) + 1;
+ if ((pptr->driveshiftlimit & 0x80) != (geometry->driveno & 0x80))
+ printf("We lost the last drive in our class of drives.\n");
+ printf("Drive probing gives drive shift limit: 0x%02x\n",
+ pptr->driveshiftlimit);
+
+ /* Pointer to the command line */
+ pptr->mdi.cmdline.seg_off.offset = bin_size + (nranges + 1) * sizeof(ranges[0]);
+ pptr->mdi.cmdline.seg_off.segment = driverseg;
+
+ /* Copy driver followed by E820 table followed by command line */
+ {
+ unsigned char *dpp = (unsigned char *)(driverseg << 4);
+
+ /* Adjust these pointers to point to the installed image */
+ /* Careful about the order here... the image isn't copied yet! */
+ pptr = (struct patch_area *)(dpp + hptr->patch_offs);
+ hptr = (struct memdisk_header *)dpp;
+
+ /* Actually copy to low memory */
+ dpp = mempcpy(dpp, memdisk_hook, bin_size);
+ dpp = mempcpy(dpp, ranges, (nranges + 1) * sizeof(ranges[0]));
+ dpp = mempcpy(dpp, shdr->cmdline, cmdline_len);
+ }
+
+ /* Note the previous INT 13h hook in the "safe hook" structure */
+ hptr->safe_hook.old_hook.uint32 = pptr->mdi.oldint13.uint32;
+
+ /* Re-fill the "safe hook" mBFT field with the physical address */
+ mbft = (struct mBFT *)(((const char *)hptr) + hptr->safe_hook.mbft);
+ hptr->safe_hook.mbft = (size_t)mbft;
+
+ /* Update various BIOS magic data areas (gotta love this shit) */
+
+ if (geometry->driveno & 0x80) {
+ /* Update BIOS hard disk count */
+ uint8_t nhd = pptr->drivecnt;
+
+ if (nhd > 128)
+ nhd = 128;
+
+ if (!do_eltorito)
+ wrz_8(BIOS_HD_COUNT, nhd);
+ } else {
+ /* Update BIOS floppy disk count */
+ uint8_t equip = rdz_8(BIOS_EQUIP);
+ uint8_t nflop = pptr->drivecnt;
+
+ if (nflop > 4) /* Limit of equipment byte */
+ nflop = 4;
+
+ equip &= 0x3E;
+ if (nflop)
+ equip |= ((nflop - 1) << 6) | 0x01;
+
+ wrz_8(BIOS_EQUIP, equip);
+
+ /* Install DPT pointer if this was the only floppy */
+ if (getcmditem("dpt") != CMD_NOTFOUND ||
+ ((nflop == 1 || no_bpt) && getcmditem("nodpt") == CMD_NOTFOUND)) {
+ /* Do install a replacement DPT into INT 1Eh */
+ pptr->mdi.dpt_ptr =
+ hptr->patch_offs + offsetof(struct patch_area, dpt);
+ }
+ }
+
+ /* Complete the mBFT */
+ mbft->acpi.signature[0] = 'm'; /* "mBFT" */
+ mbft->acpi.signature[1] = 'B';
+ mbft->acpi.signature[2] = 'F';
+ mbft->acpi.signature[3] = 'T';
+ mbft->safe_hook = (size_t)&hptr->safe_hook;
+ mbft->acpi.checksum = -checksum_buf(mbft, mbft->acpi.length);
+
+ /* Install the interrupt handlers */
+ printf("old: int13 = %08x int15 = %08x int1e = %08x\n",
+ rdz_32(BIOS_INT13), rdz_32(BIOS_INT15), rdz_32(BIOS_INT1E));
+
+ wrz_32(BIOS_INT13, driverptr + hptr->int13_offs);
+ wrz_32(BIOS_INT15, driverptr + hptr->int15_offs);
+ if (pptr->mdi.dpt_ptr)
+ wrz_32(BIOS_INT1E, driverptr + pptr->mdi.dpt_ptr);
+
+ printf("new: int13 = %08x int15 = %08x int1e = %08x\n",
+ rdz_32(BIOS_INT13), rdz_32(BIOS_INT15), rdz_32(BIOS_INT1E));
+
+ /* Figure out entry point */
+ if (!boot_seg) {
+ boot_base = 0x7c00;
+ shdr->sssp = 0x7c00;
+ shdr->csip = 0x7c00;
+ } else {
+ boot_base = boot_seg << 4;
+ shdr->sssp = boot_seg << 16;
+ shdr->csip = boot_seg << 16;
+ }
+
+ /* Relocate the real-mode code to below the stub */
+ rm_base = (driveraddr - rm_args.rm_size) & ~15;
+ if (rm_base < boot_base + boot_len)
+ die("MEMDISK: bootstrap too large to load\n");
+
+ relocate_rm_code(rm_base);
+
+ /* Reboot into the new "disk" */
+ puts("Loading boot sector... ");
+
+ memcpy((void *)boot_base,
+ (char *)pptr->mdi.diskbuf + geometry->boot_lba * 512,
+ boot_len);
+
+ if (getcmditem("pause") != CMD_NOTFOUND) {
+ puts("press any key to boot... ");
+ regs.eax.w[0] = 0;
+ intcall(0x16, &regs, NULL);
+ }
+
+ puts("booting...\n");
+
+ /* On return the assembly code will jump to the boot vector */
+ shdr->esdi = pnp_install_check();
+ shdr->edx = geometry->driveno;
+}
+
diff --git a/contrib/syslinux-4.02/memdisk/start32.S b/contrib/syslinux-4.02/memdisk/start32.S
new file mode 100644
index 0000000..4fb0537
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/start32.S
@@ -0,0 +1,101 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Simple stub to get us to the right point in the 32-bit code;
+ * this module must be linked first
+ */
+
+ .section ".init", "ax"
+ .globl _start
+_start:
+ /* Zero the bss */
+ cld
+ movl $__bss_start, %edi
+ movl $__bss_end, %ecx
+ subl %edi, %ecx
+ xorl %eax, %eax
+ shrl $2, %ecx
+ rep ; stosl
+
+ /* Set up the protected-mode IDT and the interrupt jump buffers */
+ movl $idt, %edi
+ movl $ijb, %eax
+ movl $0xee000000, %ebx /* Interrupt gate */
+ movw %cs, %bx /* Target segment */
+
+ /* Make the IDT */
+ movl $256, %ecx
+1:
+ stosl
+ stosl
+ movl %ebx, -6(%edi)
+ addl $8, %eax
+ loop 1b
+
+ /*
+ * Each entry in the interrupt jump buffer contains the following
+ * instructions:
+ *
+ * 60 pushal
+ * b0xx movb $xx, %al # interrupt number
+ * e9xxxxxxxx jmp handle_interrupt
+ */
+ movl $0xe900b060, %eax
+ movl $256, %ecx
+1:
+ movl %eax, (%edi)
+ addl $(1 << 16), %eax
+ movl $handle_interrupt-8, %edx
+ subl %edi, %edx
+ movl %edx, 4(%edi)
+ addl $8, %edi
+ loop 1b
+
+ lidtl idt_ptr
+
+ /* Save arguments, switch stacks */
+ movl %esp, %eax /* Pointer to arguments */
+ movl $__stack_end, %esp
+
+ call setup
+ jmp *(rm_args) /* First argument is return */
+
+ .section ".text","ax"
+ .globl intcall
+ .type intcall, @function
+intcall:
+ jmp *(rm_args+1*4) /* Intcall is argument 1 */
+ .size intcall, .-intcall
+
+ .type handle_interrupt, @function
+handle_interrupt:
+ jmp *(rm_args+4*4) /* Interrupt pointer is argument 4 */
+ .size handle_interrupt, .-handle_interrupt
+
+ .section ".rodata","a"
+idt_ptr:
+ .word 8*256-1
+ .long idt
+ .word 0
+
+ .section ".bss.large","aw"
+ .balign 2048
+idt:
+ .space 8*256
+ijb:
+ .space 8*256
+
+__stack:
+ .space 65536
+__stack_end:
diff --git a/contrib/syslinux-4.02/memdisk/testdata1 b/contrib/syslinux-4.02/memdisk/testdata1
new file mode 100644
index 0000000..34ab566
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/testdata1
@@ -0,0 +1,13 @@
+0000000000000000 000000000009bc00 1
+000000000009bc00 0000000000004400 2
+00000000000e9800 0000000000016800 2
+0000000000100000 0000000006ee0000 1
+0000000006fe0000 000000000000fc00 3
+0000000006fefc00 0000000000000400 4
+0000000006ff0000 0000000000002000 2
+0000000006ff2000 000000000000e000 1
+0000000007000000 0000000000100000 2
+00000000fff00000 0000000000100000 2
+
+0000000000586000 0000000000168000 2
+000000000009ba00 0000000000000200 2
diff --git a/contrib/syslinux-4.02/memdisk/testdata2 b/contrib/syslinux-4.02/memdisk/testdata2
new file mode 100644
index 0000000..8bec5bf
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/testdata2
@@ -0,0 +1,10 @@
+0000000000000000 000000000009bc00 1
+000000000009bc00 0000000000004400 2
+00000000000e9800 0000000000016800 2
+0000000000100000 0000000006ee0000 1
+0000000006fe0000 000000000000fc00 3
+0000000006fefc00 0000000000000400 4
+0000000006ff0000 0000000000002000 2
+0000000006ff2000 000000000000e000 1
+0000000007000000 0000000000100000 2
+00000000fff00000 0000000000100000 2
diff --git a/contrib/syslinux-4.02/memdisk/testdata3 b/contrib/syslinux-4.02/memdisk/testdata3
new file mode 100644
index 0000000..38a4502
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/testdata3
@@ -0,0 +1,14 @@
+0000000000000000 000000000009bc00 1
+000000000009bc00 0000000000004400 2
+00000000000e9800 0000000000016800 2
+0000000000100000 0000000006ee0000 1
+0000000006fe0000 000000000000fc00 3
+0000000006fefc00 0000000000000400 4
+0000002000000000 0000001000000000 1
+0000000006ff0000 0000000000002000 2
+0000000006ff2000 000000000000e000 1
+0000000007000000 0000000000100000 2
+00000000fff00000 0000000000100000 2
+
+0000000000586000 0000000000168000 2
+000000000009ba00 0000000000000200 2
diff --git a/contrib/syslinux-4.02/memdisk/unzip.c b/contrib/syslinux-4.02/memdisk/unzip.c
new file mode 100644
index 0000000..18a1df4
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/unzip.c
@@ -0,0 +1,391 @@
+/*
+ * unzip.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ * puts by Nick Holloway 1993, better puts by Martin Mares 1995
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ *
+ * Adapted for MEMDISK by H. Peter Anvin, April 2003
+ */
+
+#include <stdint.h>
+#include "memdisk.h"
+#include "conio.h"
+
+#undef DEBUG /* Means something different for this file */
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args) args
+#define STATIC static
+
+#define memzero(s, n) memset ((s), 0, (n))
+
+typedef uint8_t uch;
+typedef uint16_t ush;
+typedef uint32_t ulg;
+
+#define WSIZE 0x8000 /* Window size must be at least 32k, */
+ /* and a power of two */
+
+static uch *inbuf; /* input pointer */
+static uch window[WSIZE]; /* sliding output window buffer */
+
+static unsigned insize; /* total input bytes read */
+static unsigned inbytes; /* valid bytes in inbuf */
+static unsigned outcnt; /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+static int fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+static ulg crc_32_tab[256];
+
+/* Get byte from input buffer */
+static inline uch get_byte(void)
+{
+ if (inbytes) {
+ uch b = *inbuf++;
+ inbytes--;
+ return b;
+ } else {
+ return fill_inbuf(); /* Input buffer underrun */
+ }
+}
+
+/* Unget byte from input buffer */
+static inline void unget_byte(void)
+{
+ inbytes++;
+ inbuf--;
+}
+
+static ulg bytes_out = 0; /* Number of bytes output */
+static uch *output_data; /* Output data pointer */
+static ulg output_size; /* Number of output bytes expected */
+
+static void *malloc(int size);
+static void free(void *where);
+
+static ulg free_mem_ptr, free_mem_end_ptr;
+
+#include "inflate.c"
+
+static void *malloc(int size)
+{
+ void *p;
+
+ if (size < 0)
+ error("malloc error");
+
+ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+ p = (void *)free_mem_ptr;
+ free_mem_ptr += size;
+
+ if (free_mem_ptr >= free_mem_end_ptr)
+ error("out of memory");
+
+ return p;
+}
+
+static void free(void *where)
+{
+ /* Don't care */
+ (void)where;
+}
+
+static void gzip_mark(void **ptr)
+{
+ *ptr = (void *)free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+ free_mem_ptr = (long)*ptr;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+ /* This should never happen. We have already pointed the algorithm
+ to all the data we have. */
+ die("failed\nDecompression error: ran out of input data\n");
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, *out, ch;
+
+ if (bytes_out + outcnt > output_size)
+ error("output buffer overrun");
+
+ in = window;
+ out = output_data;
+ for (n = 0; n < outcnt; n++) {
+ ch = *out++ = *in++;
+ c = crc_32_tab[(c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
+ output_data = out;
+ bytes_out += (ulg) outcnt;
+ outcnt = 0;
+}
+
+static void error(char *x)
+{
+ die("failed\nDecompression error: %s\n", x);
+}
+
+/* GZIP header */
+struct gzip_header {
+ uint16_t magic;
+ uint8_t method;
+ uint8_t flags;
+ uint32_t timestamp;
+ uint8_t extra_flags;
+ uint8_t os_type;
+} __attribute__ ((packed));
+/* (followed by optional and variable length "extra", "original name",
+ and "comment" fields) */
+
+struct gzip_trailer {
+ uint32_t crc;
+ uint32_t dbytes;
+} __attribute__ ((packed));
+
+/* PKZIP header. See
+ * <http://www.pkware.com/products/enterprise/white_papers/appnote.html>.
+ */
+struct pkzip_header {
+ uint32_t magic;
+ uint16_t version;
+ uint16_t flags;
+ uint16_t method;
+ uint16_t modified_time;
+ uint16_t modified_date;
+ uint32_t crc;
+ uint32_t zbytes;
+ uint32_t dbytes;
+ uint16_t filename_len;
+ uint16_t extra_len;
+} __attribute__ ((packed));
+/* (followed by optional and variable length "filename" and "extra"
+ fields) */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+/* pkzip flag byte */
+#define PK_ENCRYPTED 0x01 /* bit 0 set: file is encrypted */
+#define PK_DATADESC 0x08 /* bit 3 set: file has trailing "data
+ descriptor" */
+#define PK_UNSUPPORTED 0xFFF0 /* All other bits must be zero */
+
+/* Return 0 if (indata, size) points to a ZIP file, and fill in
+ compressed data size, uncompressed data size, CRC, and offset of
+ data.
+
+ If indata is not a ZIP file, return -1. */
+int check_zip(void *indata, uint32_t size, uint32_t * zbytes_p,
+ uint32_t * dbytes_p, uint32_t * orig_crc, uint32_t * offset_p)
+{
+ struct gzip_header *gzh = (struct gzip_header *)indata;
+ struct pkzip_header *pkzh = (struct pkzip_header *)indata;
+ uint32_t offset;
+
+ if (gzh->magic == 0x8b1f) {
+ struct gzip_trailer *gzt = indata + size - sizeof(struct gzip_trailer);
+ /* We only support method #8, DEFLATED */
+ if (gzh->method != 8) {
+ error("gzip file uses invalid method");
+ return -1;
+ }
+ if (gzh->flags & ENCRYPTED) {
+ error("gzip file is encrypted; not supported");
+ return -1;
+ }
+ if (gzh->flags & CONTINUATION) {
+ error("gzip file is a continuation file; not supported");
+ return -1;
+ }
+ if (gzh->flags & RESERVED) {
+ error("gzip file has unsupported flags");
+ return -1;
+ }
+ offset = sizeof(*gzh);
+ if (gzh->flags & EXTRA_FIELD) {
+ /* Skip extra field */
+ unsigned len = *(unsigned *)(indata + offset);
+ offset += 2 + len;
+ }
+ if (gzh->flags & ORIG_NAME) {
+ /* Discard the old name */
+ uint8_t *p = indata;
+ while (p[offset] != 0 && offset < size) {
+ offset++;
+ }
+ offset++;
+ }
+
+ if (gzh->flags & COMMENT) {
+ /* Discard the comment */
+ uint8_t *p = indata;
+ while (p[offset] != 0 && offset < size) {
+ offset++;
+ }
+ offset++;
+ }
+
+ if (offset > size) {
+ error("gzip file corrupt");
+ return -1;
+ }
+ *zbytes_p = size - offset - sizeof(struct gzip_trailer);
+ *dbytes_p = gzt->dbytes;
+ *orig_crc = gzt->crc;
+ *offset_p = offset;
+ return 0;
+ } else if (pkzh->magic == 0x04034b50UL) {
+ /* Magic number matches pkzip file. */
+
+ offset = sizeof(*pkzh);
+ if (pkzh->flags & PK_ENCRYPTED) {
+ error("pkzip file is encrypted; not supported");
+ return -1;
+ }
+ if (pkzh->flags & PK_DATADESC) {
+ error("pkzip file uses data_descriptor field; not supported");
+ return -1;
+ }
+ if (pkzh->flags & PK_UNSUPPORTED) {
+ error("pkzip file has unsupported flags");
+ return -1;
+ }
+
+ /* We only support method #8, DEFLATED */
+ if (pkzh->method != 8) {
+ error("pkzip file uses invalid method");
+ return -1;
+ }
+ /* skip header */
+ offset = sizeof(*pkzh);
+ /* skip filename */
+ offset += pkzh->filename_len;
+ /* skip extra field */
+ offset += pkzh->extra_len;
+
+ if (offset + pkzh->zbytes > size) {
+ error("pkzip file corrupt");
+ return -1;
+ }
+
+ *zbytes_p = pkzh->zbytes;
+ *dbytes_p = pkzh->dbytes;
+ *orig_crc = pkzh->crc;
+ *offset_p = offset;
+ return 0;
+ } else {
+ /* Magic number does not match. */
+ return -1;
+ }
+
+ error("Internal error in check_zip");
+ return -1;
+}
+
+/*
+ * Decompress the image, trying to flush the end of it as close
+ * to end_mem as possible. Return a pointer to the data block,
+ * and change datalen.
+ */
+extern void _end;
+
+static char heap[65536];
+
+void *unzip(void *indata, uint32_t zbytes, uint32_t dbytes,
+ uint32_t orig_crc, void *target)
+{
+ /* Set up the heap; it is simply a chunk of bss memory */
+ free_mem_ptr = (size_t)heap;
+ free_mem_end_ptr = (size_t)heap + sizeof heap;
+
+ /* Set up input buffer */
+ inbuf = indata;
+ /* Sometimes inflate() looks beyond the end of the compressed data,
+ but it always backs up before it is done. So we give it 4 bytes
+ of slack. */
+ insize = inbytes = zbytes + 4;
+
+ /* Set up output buffer */
+ outcnt = 0;
+ output_data = target;
+ output_size = dbytes;
+ bytes_out = 0;
+
+ makecrc();
+ gunzip();
+
+ /* Verify that gunzip() consumed the entire input. */
+ if (inbytes != 4)
+ error("compressed data length error");
+
+ /* Check the uncompressed data length and CRC. */
+ if (bytes_out != dbytes)
+ error("uncompressed data length error");
+
+ if (orig_crc != CRC_VALUE)
+ error("crc error");
+
+ puts("ok\n");
+
+ return target;
+}
diff --git a/contrib/syslinux-4.02/memdisk/version.h b/contrib/syslinux-4.02/memdisk/version.h
new file mode 100644
index 0000000..46bc7bb
--- /dev/null
+++ b/contrib/syslinux-4.02/memdisk/version.h
@@ -0,0 +1,25 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2002-2008 H. Peter Anvin - 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * version.h
+ *
+ * MEMDISK version data
+ */
+
+#ifndef MEMDISK_VERSION_H
+#define MEMDISK_VERSION_H
+
+#define FIRSTYEAR "2001"
+#define COPYYEAR "2008"
+
+#endif