diff options
Diffstat (limited to 'contrib/syslinux-4.02/memdisk')
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, ®s, 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(®s, 0, sizeof regs); + + regs.eax.b[1] = probe; /* AH = probe */ + regs.edx.b[0] = drive; /* DL = drive number to probe */ + intcall(0x13, ®s, ®s); + + 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(®s, 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, ®s, ®s); + 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(®s, 0, sizeof regs); + intcall(0x12, ®s, ®s); + 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(®s, 0, sizeof regs); + + regs.eax.w[0] = 0xe801; + intcall(0x15, ®s, ®s); + + 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(®s, 0, sizeof regs); + + regs.eax.b[1] = 0x88; + intcall(0x15, ®s, ®s); + + 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(®s, 0, sizeof regs); + regs.es = 0; + regs.eax.b[1] = 0x08; + regs.edx.b[0] = geometry->driveno & 0x80; + intcall(0x13, ®s, ®s); + + /* 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, ®s, 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 |