summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios')
-rw-r--r--contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/basemem.c46
-rw-r--r--contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/bios_console.c298
-rw-r--r--contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S596
-rw-r--r--contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/fakee820.c93
-rw-r--r--contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/gateA20.c176
-rw-r--r--contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/hidemem.c220
-rw-r--r--contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/memmap.c312
-rw-r--r--contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/pnpbios.c109
8 files changed, 1850 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/basemem.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/basemem.c
new file mode 100644
index 0000000..1ba7d1f
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/basemem.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <realmode.h>
+#include <bios.h>
+#include <basemem.h>
+#include <gpxe/hidemem.h>
+
+/** @file
+ *
+ * Base memory allocation
+ *
+ */
+
+/**
+ * Set the BIOS free base memory counter
+ *
+ * @v new_fbms New free base memory counter (in kB)
+ */
+void set_fbms ( unsigned int new_fbms ) {
+ uint16_t fbms = new_fbms;
+
+ /* Update the BIOS memory counter */
+ put_real ( fbms, BDA_SEG, BDA_FBMS );
+
+ /* Update our hidden memory region map */
+ hide_basemem();
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/bios_console.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/bios_console.c
new file mode 100644
index 0000000..1d18e54
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/bios_console.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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_LICENCE ( GPL2_OR_LATER );
+
+#include <assert.h>
+#include <realmode.h>
+#include <console.h>
+#include <gpxe/ansiesc.h>
+
+#define ATTR_BOLD 0x08
+
+#define ATTR_FCOL_MASK 0x07
+#define ATTR_FCOL_BLACK 0x00
+#define ATTR_FCOL_BLUE 0x01
+#define ATTR_FCOL_GREEN 0x02
+#define ATTR_FCOL_CYAN 0x03
+#define ATTR_FCOL_RED 0x04
+#define ATTR_FCOL_MAGENTA 0x05
+#define ATTR_FCOL_YELLOW 0x06
+#define ATTR_FCOL_WHITE 0x07
+
+#define ATTR_BCOL_MASK 0x70
+#define ATTR_BCOL_BLACK 0x00
+#define ATTR_BCOL_BLUE 0x10
+#define ATTR_BCOL_GREEN 0x20
+#define ATTR_BCOL_CYAN 0x30
+#define ATTR_BCOL_RED 0x40
+#define ATTR_BCOL_MAGENTA 0x50
+#define ATTR_BCOL_YELLOW 0x60
+#define ATTR_BCOL_WHITE 0x70
+
+#define ATTR_DEFAULT ATTR_FCOL_WHITE
+
+/** Current character attribute */
+static unsigned int bios_attr = ATTR_DEFAULT;
+
+/**
+ * Handle ANSI CUP (cursor position)
+ *
+ * @v count Parameter count
+ * @v params[0] Row (1 is top)
+ * @v params[1] Column (1 is left)
+ */
+static void bios_handle_cup ( unsigned int count __unused, int params[] ) {
+ int cx = ( params[1] - 1 );
+ int cy = ( params[0] - 1 );
+
+ if ( cx < 0 )
+ cx = 0;
+ if ( cy < 0 )
+ cy = 0;
+
+ __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+ "int $0x10\n\t"
+ "cli\n\t" )
+ : : "a" ( 0x0200 ), "b" ( 1 ),
+ "d" ( ( cy << 8 ) | cx ) );
+}
+
+/**
+ * Handle ANSI ED (erase in page)
+ *
+ * @v count Parameter count
+ * @v params[0] Region to erase
+ */
+static void bios_handle_ed ( unsigned int count __unused,
+ int params[] __unused ) {
+ /* We assume that we always clear the whole screen */
+ assert ( params[0] == ANSIESC_ED_ALL );
+
+ __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+ "int $0x10\n\t"
+ "cli\n\t" )
+ : : "a" ( 0x0600 ), "b" ( bios_attr << 8 ),
+ "c" ( 0 ), "d" ( 0xffff ) );
+}
+
+/**
+ * Handle ANSI SGR (set graphics rendition)
+ *
+ * @v count Parameter count
+ * @v params List of graphic rendition aspects
+ */
+static void bios_handle_sgr ( unsigned int count, int params[] ) {
+ static const uint8_t bios_attr_fcols[10] = {
+ ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN,
+ ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA,
+ ATTR_FCOL_CYAN, ATTR_FCOL_WHITE,
+ ATTR_FCOL_WHITE, ATTR_FCOL_WHITE /* defaults */
+ };
+ static const uint8_t bios_attr_bcols[10] = {
+ ATTR_BCOL_BLACK, ATTR_BCOL_RED, ATTR_BCOL_GREEN,
+ ATTR_BCOL_YELLOW, ATTR_BCOL_BLUE, ATTR_BCOL_MAGENTA,
+ ATTR_BCOL_CYAN, ATTR_BCOL_WHITE,
+ ATTR_BCOL_BLACK, ATTR_BCOL_BLACK /* defaults */
+ };
+ unsigned int i;
+ int aspect;
+
+ for ( i = 0 ; i < count ; i++ ) {
+ aspect = params[i];
+ if ( aspect == 0 ) {
+ bios_attr = ATTR_DEFAULT;
+ } else if ( aspect == 1 ) {
+ bios_attr |= ATTR_BOLD;
+ } else if ( aspect == 22 ) {
+ bios_attr &= ~ATTR_BOLD;
+ } else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) {
+ bios_attr &= ~ATTR_FCOL_MASK;
+ bios_attr |= bios_attr_fcols[ aspect - 30 ];
+ } else if ( ( aspect >= 40 ) && ( aspect <= 49 ) ) {
+ bios_attr &= ~ATTR_BCOL_MASK;
+ bios_attr |= bios_attr_bcols[ aspect - 40 ];
+ }
+ }
+}
+
+/** BIOS console ANSI escape sequence handlers */
+static struct ansiesc_handler bios_ansiesc_handlers[] = {
+ { ANSIESC_CUP, bios_handle_cup },
+ { ANSIESC_ED, bios_handle_ed },
+ { ANSIESC_SGR, bios_handle_sgr },
+ { 0, NULL }
+};
+
+/** BIOS console ANSI escape sequence context */
+static struct ansiesc_context bios_ansiesc_ctx = {
+ .handlers = bios_ansiesc_handlers,
+};
+
+/**
+ * Print a character to BIOS console
+ *
+ * @v character Character to be printed
+ */
+static void bios_putchar ( int character ) {
+ int discard_a, discard_b, discard_c;
+
+ /* Intercept ANSI escape sequences */
+ character = ansiesc_process ( &bios_ansiesc_ctx, character );
+ if ( character < 0 )
+ return;
+
+ /* Print character with attribute */
+ __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+ /* Skip non-printable characters */
+ "cmpb $0x20, %%al\n\t"
+ "jb 1f\n\t"
+ /* Set attribute */
+ "movw $0x0001, %%cx\n\t"
+ "movb $0x09, %%ah\n\t"
+ "int $0x10\n\t"
+ "\n1:\n\t"
+ /* Print character */
+ "xorw %%bx, %%bx\n\t"
+ "movb $0x0e, %%ah\n\t"
+ "int $0x10\n\t"
+ "cli\n\t" )
+ : "=a" ( discard_a ), "=b" ( discard_b ),
+ "=c" ( discard_c )
+ : "a" ( character ), "b" ( bios_attr )
+ : "ebp" );
+}
+
+/**
+ * Pointer to current ANSI output sequence
+ *
+ * While we are in the middle of returning an ANSI sequence for a
+ * special key, this will point to the next character to return. When
+ * not in the middle of such a sequence, this will point to a NUL
+ * (note: not "will be NULL").
+ */
+static const char *ansi_input = "";
+
+/**
+ * Lowest BIOS scancode of interest
+ *
+ * Most of the BIOS key scancodes that we are interested in are in a
+ * dense range, so subtracting a constant and treating them as offsets
+ * into an array works efficiently.
+ */
+#define BIOS_KEY_MIN 0x42
+
+/** Offset into list of interesting BIOS scancodes */
+#define BIOS_KEY(scancode) ( (scancode) - BIOS_KEY_MIN )
+
+/** Mapping from BIOS scan codes to ANSI escape sequences */
+static const char *ansi_sequences[] = {
+ [ BIOS_KEY ( 0x42 ) ] = "[19~", /* F8 (required for PXE) */
+ [ BIOS_KEY ( 0x47 ) ] = "[H", /* Home */
+ [ BIOS_KEY ( 0x48 ) ] = "[A", /* Up arrow */
+ [ BIOS_KEY ( 0x4b ) ] = "[D", /* Left arrow */
+ [ BIOS_KEY ( 0x4d ) ] = "[C", /* Right arrow */
+ [ BIOS_KEY ( 0x4f ) ] = "[F", /* End */
+ [ BIOS_KEY ( 0x50 ) ] = "[B", /* Down arrow */
+ [ BIOS_KEY ( 0x53 ) ] = "[3~", /* Delete */
+};
+
+/**
+ * Get ANSI escape sequence corresponding to BIOS scancode
+ *
+ * @v scancode BIOS scancode
+ * @ret ansi_seq ANSI escape sequence, if any, otherwise NULL
+ */
+static const char * scancode_to_ansi_seq ( unsigned int scancode ) {
+ unsigned int bios_key = BIOS_KEY ( scancode );
+
+ if ( bios_key < ( sizeof ( ansi_sequences ) /
+ sizeof ( ansi_sequences[0] ) ) ) {
+ return ansi_sequences[bios_key];
+ }
+ DBG ( "Unrecognised BIOS scancode %02x\n", scancode );
+ return NULL;
+}
+
+/**
+ * Get character from BIOS console
+ *
+ * @ret character Character read from console
+ */
+static int bios_getchar ( void ) {
+ uint16_t keypress;
+ unsigned int character;
+ const char *ansi_seq;
+
+ /* If we are mid-sequence, pass out the next byte */
+ if ( ( character = *ansi_input ) ) {
+ ansi_input++;
+ return character;
+ }
+
+ /* Read character from real BIOS console */
+ __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+ "int $0x16\n\t"
+ "cli\n\t" )
+ : "=a" ( keypress ) : "a" ( 0x1000 ) );
+ character = ( keypress & 0xff );
+
+ /* If it's a normal character, just return it */
+ if ( character && ( character < 0x80 ) )
+ return character;
+
+ /* Otherwise, check for a special key that we know about */
+ if ( ( ansi_seq = scancode_to_ansi_seq ( keypress >> 8 ) ) ) {
+ /* Start of escape sequence: return ESC (0x1b) */
+ ansi_input = ansi_seq;
+ return 0x1b;
+ }
+
+ return 0;
+}
+
+/**
+ * Check for character ready to read from BIOS console
+ *
+ * @ret True Character available to read
+ * @ret False No character available to read
+ */
+static int bios_iskey ( void ) {
+ unsigned int discard_a;
+ unsigned int flags;
+
+ /* If we are mid-sequence, we are always ready */
+ if ( *ansi_input )
+ return 1;
+
+ /* Otherwise check the real BIOS console */
+ __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+ "int $0x16\n\t"
+ "pushfw\n\t"
+ "popw %w0\n\t"
+ "cli\n\t" )
+ : "=r" ( flags ), "=a" ( discard_a )
+ : "a" ( 0x0100 ) );
+ return ( ! ( flags & ZF ) );
+}
+
+struct console_driver bios_console __console_driver = {
+ .putchar = bios_putchar,
+ .getchar = bios_getchar,
+ .iskey = bios_iskey,
+};
diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
new file mode 100644
index 0000000..99ca519
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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_LICENCE ( GPL2_OR_LATER )
+
+ .text
+ .arch i386
+ .code16
+
+#define SMAP 0x534d4150
+
+/* Most documentation refers to the E820 buffer as being 20 bytes, and
+ * the API makes it perfectly legitimate to pass only a 20-byte buffer
+ * and expect to get valid data. However, some morons at ACPI decided
+ * to extend the data structure by adding an extra "extended
+ * attributes" field and by including critical information within this
+ * field, such as whether or not the region is enabled. A caller who
+ * passes in only a 20-byte buffer therefore risks getting very, very
+ * misleading information.
+ *
+ * I have personally witnessed an HP BIOS that returns a value of
+ * 0x0009 in the extended attributes field. If we don't pass this
+ * value through to the caller, 32-bit WinPE will die, usually with a
+ * PAGE_FAULT_IN_NONPAGED_AREA blue screen of death.
+ *
+ * Allow a ridiculously large maximum value (64 bytes) for the E820
+ * buffer as a guard against insufficiently creative idiots in the
+ * future.
+ */
+#define E820MAXSIZE 64
+
+/****************************************************************************
+ *
+ * Allowed memory windows
+ *
+ * There are two ways to view this list. The first is as a list of
+ * (non-overlapping) allowed memory regions, sorted by increasing
+ * address. The second is as a list of (non-overlapping) hidden
+ * memory regions, again sorted by increasing address. The second
+ * view is offset by half an entry from the first: think about this
+ * for a moment and it should make sense.
+ *
+ * xxx_memory_window is used to indicate an "allowed region"
+ * structure, hidden_xxx_memory is used to indicate a "hidden region"
+ * structure. Each structure is 16 bytes in length.
+ *
+ ****************************************************************************
+ */
+ .section ".data16", "aw", @progbits
+ .align 16
+ .globl hidemem_base
+ .globl hidemem_umalloc
+ .globl hidemem_textdata
+memory_windows:
+base_memory_window: .long 0x00000000, 0x00000000 /* Start of memory */
+
+hidemem_base: .long 0x000a0000, 0x00000000 /* Changes at runtime */
+ext_memory_window: .long 0x000a0000, 0x00000000 /* 640kB mark */
+
+hidemem_umalloc: .long 0xffffffff, 0xffffffff /* Changes at runtime */
+ .long 0xffffffff, 0xffffffff /* Changes at runtime */
+
+hidemem_textdata: .long 0xffffffff, 0xffffffff /* Changes at runtime */
+ .long 0xffffffff, 0xffffffff /* Changes at runtime */
+
+ .long 0xffffffff, 0xffffffff /* End of memory */
+memory_windows_end:
+
+/****************************************************************************
+ * Truncate region to memory window
+ *
+ * Parameters:
+ * %edx:%eax Start of region
+ * %ecx:%ebx Length of region
+ * %si Memory window
+ * Returns:
+ * %edx:%eax Start of windowed region
+ * %ecx:%ebx Length of windowed region
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+window_region:
+ /* Convert (start,len) to (start, end) */
+ addl %eax, %ebx
+ adcl %edx, %ecx
+ /* Truncate to window start */
+ cmpl 4(%si), %edx
+ jne 1f
+ cmpl 0(%si), %eax
+1: jae 2f
+ movl 4(%si), %edx
+ movl 0(%si), %eax
+2: /* Truncate to window end */
+ cmpl 12(%si), %ecx
+ jne 1f
+ cmpl 8(%si), %ebx
+1: jbe 2f
+ movl 12(%si), %ecx
+ movl 8(%si), %ebx
+2: /* Convert (start, end) back to (start, len) */
+ subl %eax, %ebx
+ sbbl %edx, %ecx
+ /* If length is <0, set length to 0 */
+ jae 1f
+ xorl %ebx, %ebx
+ xorl %ecx, %ecx
+ ret
+ .size window_region, . - window_region
+
+/****************************************************************************
+ * Patch "memory above 1MB" figure
+ *
+ * Parameters:
+ * %ax Memory above 1MB, in 1kB blocks
+ * Returns:
+ * %ax Modified memory above 1M in 1kB blocks
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+patch_1m:
+ pushal
+ /* Convert to (start,len) format and call truncate */
+ xorl %ecx, %ecx
+ movzwl %ax, %ebx
+ shll $10, %ebx
+ xorl %edx, %edx
+ movl $0x100000, %eax
+ movw $ext_memory_window, %si
+ call window_region
+ /* Convert back to "memory above 1MB" format and return via %ax */
+ pushfw
+ shrl $10, %ebx
+ popfw
+ movw %sp, %bp
+ movw %bx, 28(%bp)
+ popal
+ ret
+ .size patch_1m, . - patch_1m
+
+/****************************************************************************
+ * Patch "memory above 16MB" figure
+ *
+ * Parameters:
+ * %bx Memory above 16MB, in 64kB blocks
+ * Returns:
+ * %bx Modified memory above 16M in 64kB blocks
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+patch_16m:
+ pushal
+ /* Convert to (start,len) format and call truncate */
+ xorl %ecx, %ecx
+ shll $16, %ebx
+ xorl %edx, %edx
+ movl $0x1000000, %eax
+ movw $ext_memory_window, %si
+ call window_region
+ /* Convert back to "memory above 16MB" format and return via %bx */
+ pushfw
+ shrl $16, %ebx
+ popfw
+ movw %sp, %bp
+ movw %bx, 16(%bp)
+ popal
+ ret
+ .size patch_16m, . - patch_16m
+
+/****************************************************************************
+ * Patch "memory between 1MB and 16MB" and "memory above 16MB" figures
+ *
+ * Parameters:
+ * %ax Memory between 1MB and 16MB, in 1kB blocks
+ * %bx Memory above 16MB, in 64kB blocks
+ * Returns:
+ * %ax Modified memory between 1MB and 16MB, in 1kB blocks
+ * %bx Modified memory above 16MB, in 64kB blocks
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+patch_1m_16m:
+ call patch_1m
+ call patch_16m
+ /* If 1M region is no longer full-length, kill off the 16M region */
+ cmpw $( 15 * 1024 ), %ax
+ je 1f
+ xorw %bx, %bx
+1: ret
+ .size patch_1m_16m, . - patch_1m_16m
+
+/****************************************************************************
+ * Get underlying e820 memory region to underlying_e820 buffer
+ *
+ * Parameters:
+ * As for INT 15,e820
+ * Returns:
+ * As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that the continuation
+ * value (%ebx) is a 16-bit simple sequence counter (with the high 16
+ * bits ignored), and termination is always via CF=1 rather than
+ * %ebx=0.
+ *
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+get_underlying_e820:
+
+ /* If the requested region is in the cache, return it */
+ cmpw %bx, underlying_e820_index
+ jne 2f
+ pushw %di
+ pushw %si
+ movw $underlying_e820_cache, %si
+ cmpl underlying_e820_cache_size, %ecx
+ jbe 1f
+ movl underlying_e820_cache_size, %ecx
+1: pushl %ecx
+ rep movsb
+ popl %ecx
+ popw %si
+ popw %di
+ incw %bx
+ movl %edx, %eax
+ clc
+ ret
+2:
+ /* If the requested region is earlier than the cached region,
+ * invalidate the cache.
+ */
+ cmpw %bx, underlying_e820_index
+ jbe 1f
+ movw $0xffff, underlying_e820_index
+1:
+ /* If the cache is invalid, reset the underlying %ebx */
+ cmpw $0xffff, underlying_e820_index
+ jne 1f
+ andl $0, underlying_e820_ebx
+1:
+ /* If the cache is valid but the continuation value is zero,
+ * this means that the previous underlying call returned with
+ * %ebx=0. Return with CF=1 in this case.
+ */
+ cmpw $0xffff, underlying_e820_index
+ je 1f
+ cmpl $0, underlying_e820_ebx
+ jne 1f
+ stc
+ ret
+1:
+ /* Get the next region into the cache */
+ pushl %eax
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ pushl %esi /* Some implementations corrupt %esi, so we */
+ pushl %edi /* preserve %esi, %edi and %ebp to be paranoid */
+ pushl %ebp
+ pushw %es
+ pushw %ds
+ popw %es
+ movw $underlying_e820_cache, %di
+ cmpl $E820MAXSIZE, %ecx
+ jbe 1f
+ movl $E820MAXSIZE, %ecx
+1: movl underlying_e820_ebx, %ebx
+ stc
+ pushfw
+ lcall *%cs:int15_vector
+ popw %es
+ popl %ebp
+ popl %edi
+ popl %esi
+ /* Check for error return from underlying e820 call */
+ jc 2f /* CF set: error */
+ cmpl $SMAP, %eax
+ je 3f /* 'SMAP' missing: error */
+2: /* An error occurred: return values returned by underlying e820 call */
+ stc /* Force CF set if SMAP was missing */
+ addr32 leal 16(%esp), %esp /* avoid changing other flags */
+ ret
+3: /* No error occurred */
+ movl %ebx, underlying_e820_ebx
+ movl %ecx, underlying_e820_cache_size
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %eax
+ /* Mark cache as containing this result */
+ incw underlying_e820_index
+
+ /* Loop until found */
+ jmp get_underlying_e820
+ .size get_underlying_e820, . - get_underlying_e820
+
+ .section ".data16", "aw", @progbits
+underlying_e820_index:
+ .word 0xffff /* Initialise to an invalid value */
+ .size underlying_e820_index, . - underlying_e820_index
+
+ .section ".bss16", "aw", @nobits
+underlying_e820_ebx:
+ .long 0
+ .size underlying_e820_ebx, . - underlying_e820_ebx
+
+ .section ".bss16", "aw", @nobits
+underlying_e820_cache:
+ .space E820MAXSIZE
+ .size underlying_e820_cache, . - underlying_e820_cache
+
+ .section ".bss16", "aw", @nobits
+underlying_e820_cache_size:
+ .long 0
+ .size underlying_e820_cache_size, . - underlying_e820_cache_size
+
+/****************************************************************************
+ * Get windowed e820 region, without empty region stripping
+ *
+ * Parameters:
+ * As for INT 15,e820
+ * Returns:
+ * As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that each underlying
+ * region is returned N times, windowed to fit within N visible-memory
+ * windows. Termination is always via CF=1.
+ *
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+get_windowed_e820:
+
+ /* Preserve registers */
+ pushl %esi
+ pushw %bp
+
+ /* Split %ebx into %si:%bx, store original %bx in %bp */
+ pushl %ebx
+ popw %bp
+ popw %si
+
+ /* %si == 0 => start of memory_windows list */
+ testw %si, %si
+ jne 1f
+ movw $memory_windows, %si
+1:
+ /* Get (cached) underlying e820 region to buffer */
+ call get_underlying_e820
+ jc 99f /* Abort on error */
+
+ /* Preserve registers */
+ pushal
+ /* start => %edx:%eax, len => %ecx:%ebx */
+ movl %es:0(%di), %eax
+ movl %es:4(%di), %edx
+ movl %es:8(%di), %ebx
+ movl %es:12(%di), %ecx
+ /* Truncate region to current window */
+ call window_region
+1: /* Store modified values in e820 map entry */
+ movl %eax, %es:0(%di)
+ movl %edx, %es:4(%di)
+ movl %ebx, %es:8(%di)
+ movl %ecx, %es:12(%di)
+ /* Restore registers */
+ popal
+
+ /* Derive continuation value for next call */
+ addw $16, %si
+ cmpw $memory_windows_end, %si
+ jne 1f
+ /* End of memory windows: reset %si and allow %bx to continue */
+ xorw %si, %si
+ jmp 2f
+1: /* More memory windows to go: restore original %bx */
+ movw %bp, %bx
+2: /* Construct %ebx from %si:%bx */
+ pushw %si
+ pushw %bx
+ popl %ebx
+
+98: /* Clear CF */
+ clc
+99: /* Restore registers and return */
+ popw %bp
+ popl %esi
+ ret
+ .size get_windowed_e820, . - get_windowed_e820
+
+/****************************************************************************
+ * Get windowed e820 region, with empty region stripping
+ *
+ * Parameters:
+ * As for INT 15,e820
+ * Returns:
+ * As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that each underlying
+ * region is returned up to N times, windowed to fit within N
+ * visible-memory windows. Empty windows are never returned.
+ * Termination is always via CF=1.
+ *
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+get_nonempty_e820:
+
+ /* Record entry parameters */
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+
+ /* Get next windowed region */
+ call get_windowed_e820
+ jc 99f /* abort on error */
+
+ /* If region is non-empty, finish here */
+ cmpl $0, %es:8(%di)
+ jne 98f
+ cmpl $0, %es:12(%di)
+ jne 98f
+
+ /* Region was empty: restore entry parameters and go to next region */
+ popl %edx
+ popl %ecx
+ popl %eax
+ jmp get_nonempty_e820
+
+98: /* Clear CF */
+ clc
+99: /* Return values from underlying call */
+ addr32 leal 12(%esp), %esp /* avoid changing flags */
+ ret
+ .size get_nonempty_e820, . - get_nonempty_e820
+
+/****************************************************************************
+ * Get mangled e820 region, with empty region stripping
+ *
+ * Parameters:
+ * As for INT 15,e820
+ * Returns:
+ * As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that underlying regions
+ * are windowed to the allowed memory regions. Empty regions are
+ * stripped from the map. Termination is always via %ebx=0.
+ *
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+get_mangled_e820:
+
+ /* Get a nonempty region */
+ call get_nonempty_e820
+ jc 99f /* Abort on error */
+
+ /* Peek ahead to see if there are any further nonempty regions */
+ pushal
+ pushw %es
+ movw %sp, %bp
+ subw %cx, %sp
+ movl $0xe820, %eax
+ movl $SMAP, %edx
+ pushw %ss
+ popw %es
+ movw %sp, %di
+ call get_nonempty_e820
+ movw %bp, %sp
+ popw %es
+ popal
+ jnc 99f /* There are further nonempty regions */
+
+ /* No futher nonempty regions: zero %ebx and clear CF */
+ xorl %ebx, %ebx
+
+99: /* Return */
+ ret
+ .size get_mangled_e820, . - get_mangled_e820
+
+/****************************************************************************
+ * Set/clear CF on the stack as appropriate, assumes stack is as it should
+ * be immediately before IRET
+ ****************************************************************************
+ */
+patch_cf:
+ pushw %bp
+ movw %sp, %bp
+ setc 8(%bp) /* Set/reset CF; clears PF, AF, ZF, SF */
+ popw %bp
+ ret
+
+/****************************************************************************
+ * INT 15,e820 handler
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+int15_e820:
+ pushw %ds
+ pushw %cs:rm_ds
+ popw %ds
+ call get_mangled_e820
+ popw %ds
+ call patch_cf
+ iret
+ .size int15_e820, . - int15_e820
+
+/****************************************************************************
+ * INT 15,e801 handler
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+int15_e801:
+ /* Call previous handler */
+ pushfw
+ lcall *%cs:int15_vector
+ call patch_cf
+ /* Edit result */
+ pushw %ds
+ pushw %cs:rm_ds
+ popw %ds
+ call patch_1m_16m
+ xchgw %ax, %cx
+ xchgw %bx, %dx
+ call patch_1m_16m
+ xchgw %ax, %cx
+ xchgw %bx, %dx
+ popw %ds
+ iret
+ .size int15_e801, . - int15_e801
+
+/****************************************************************************
+ * INT 15,88 handler
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+int15_88:
+ /* Call previous handler */
+ pushfw
+ lcall *%cs:int15_vector
+ call patch_cf
+ /* Edit result */
+ pushw %ds
+ pushw %cs:rm_ds
+ popw %ds
+ call patch_1m
+ popw %ds
+ iret
+ .size int15_88, . - int15_88
+
+/****************************************************************************
+ * INT 15 handler
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+ .globl int15
+int15:
+ /* See if we want to intercept this call */
+ pushfw
+ cmpw $0xe820, %ax
+ jne 1f
+ cmpl $SMAP, %edx
+ jne 1f
+ popfw
+ jmp int15_e820
+1: cmpw $0xe801, %ax
+ jne 2f
+ popfw
+ jmp int15_e801
+2: cmpb $0x88, %ah
+ jne 3f
+ popfw
+ jmp int15_88
+3: popfw
+ ljmp *%cs:int15_vector
+ .size int15, . - int15
+
+ .section ".text16.data", "aw", @progbits
+ .globl int15_vector
+int15_vector:
+ .long 0
+ .size int15_vector, . - int15_vector
diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/fakee820.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/fakee820.c
new file mode 100644
index 0000000..ea116fe
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/fakee820.c
@@ -0,0 +1,93 @@
+/* Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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_LICENCE ( GPL2_OR_LATER );
+
+#include <realmode.h>
+#include <biosint.h>
+
+/** Assembly routine in inline asm */
+extern void int15_fakee820();
+
+/** Original INT 15 handler */
+static struct segoff __text16 ( real_int15_vector );
+#define real_int15_vector __use_text16 ( real_int15_vector )
+
+/** An INT 15,e820 memory map entry */
+struct e820_entry {
+ /** Start of region */
+ uint64_t start;
+ /** Length of region */
+ uint64_t len;
+ /** Type of region */
+ uint32_t type;
+} __attribute__ (( packed ));
+
+#define E820_TYPE_RAM 1 /**< Normal memory */
+#define E820_TYPE_RSVD 2 /**< Reserved and unavailable */
+#define E820_TYPE_ACPI 3 /**< ACPI reclaim memory */
+#define E820_TYPE_NVS 4 /**< ACPI NVS memory */
+
+/** Fake e820 map */
+static struct e820_entry __text16_array ( e820map, [] ) __used = {
+ { 0x00000000ULL, ( 0x000a0000ULL - 0x00000000ULL ), E820_TYPE_RAM },
+ { 0x00100000ULL, ( 0xcfb50000ULL - 0x00100000ULL ), E820_TYPE_RAM },
+ { 0xcfb50000ULL, ( 0xcfb64000ULL - 0xcfb50000ULL ), E820_TYPE_RSVD },
+ { 0xcfb64000ULL, ( 0xcfb66000ULL - 0xcfb64000ULL ), E820_TYPE_RSVD },
+ { 0xcfb66000ULL, ( 0xcfb85c00ULL - 0xcfb66000ULL ), E820_TYPE_ACPI },
+ { 0xcfb85c00ULL, ( 0xd0000000ULL - 0xcfb85c00ULL ), E820_TYPE_RSVD },
+ { 0xe0000000ULL, ( 0xf0000000ULL - 0xe0000000ULL ), E820_TYPE_RSVD },
+ { 0xfe000000ULL, (0x100000000ULL - 0xfe000000ULL ), E820_TYPE_RSVD },
+ {0x100000000ULL, (0x230000000ULL -0x100000000ULL ), E820_TYPE_RAM },
+};
+#define e820map __use_text16 ( e820map )
+
+void fake_e820 ( void ) {
+ __asm__ __volatile__ (
+ TEXT16_CODE ( "\nint15_fakee820:\n\t"
+ "pushfw\n\t"
+ "cmpl $0xe820, %%eax\n\t"
+ "jne 99f\n\t"
+ "cmpl $0x534d4150, %%edx\n\t"
+ "jne 99f\n\t"
+ "pushaw\n\t"
+ "movw %%sp, %%bp\n\t"
+ "andb $~0x01, 22(%%bp)\n\t" /* Clear return CF */
+ "leaw e820map(%%bx), %%si\n\t"
+ "cs rep movsb\n\t"
+ "popaw\n\t"
+ "movl %%edx, %%eax\n\t"
+ "addl $20, %%ebx\n\t"
+ "cmpl %0, %%ebx\n\t"
+ "jne 1f\n\t"
+ "xorl %%ebx,%%ebx\n\t"
+ "\n1:\n\t"
+ "popfw\n\t"
+ "iret\n\t"
+ "\n99:\n\t"
+ "popfw\n\t"
+ "ljmp *%%cs:real_int15_vector\n\t" )
+ : : "i" ( sizeof ( e820map ) ) );
+
+ hook_bios_interrupt ( 0x15, ( unsigned int ) int15_fakee820,
+ &real_int15_vector );
+}
+
+void unfake_e820 ( void ) {
+ unhook_bios_interrupt ( 0x15, ( unsigned int ) int15_fakee820,
+ &real_int15_vector );
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/gateA20.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/gateA20.c
new file mode 100644
index 0000000..1a71472
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/gateA20.c
@@ -0,0 +1,176 @@
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <realmode.h>
+#include <bios.h>
+#include <gpxe/io.h>
+#include <gpxe/timer.h>
+
+#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
+#define K_STATUS 0x64 /* keyboard status */
+#define K_CMD 0x64 /* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL 0x01 /* output buffer full */
+#define K_IBUF_FUL 0x02 /* input buffer full */
+
+#define KC_CMD_WIN 0xd0 /* read output port */
+#define KC_CMD_WOUT 0xd1 /* write output port */
+#define KC_CMD_NULL 0xff /* null command ("pulse nothing") */
+#define KB_SET_A20 0xdf /* enable A20,
+ enable output buffer full interrupt
+ enable data line
+ disable clock line */
+#define KB_UNSET_A20 0xdd /* enable A20,
+ enable output buffer full interrupt
+ enable data line
+ disable clock line */
+
+#define SCP_A 0x92 /* System Control Port A */
+
+enum { Disable_A20 = 0x2400, Enable_A20 = 0x2401, Query_A20_Status = 0x2402,
+ Query_A20_Support = 0x2403 };
+
+enum a20_methods {
+ A20_UNKNOWN = 0,
+ A20_INT15,
+ A20_KBC,
+ A20_SCPA,
+};
+
+#define A20_MAX_RETRIES 32
+#define A20_INT15_RETRIES 32
+#define A20_KBC_RETRIES (2^21)
+#define A20_SCPA_RETRIES (2^21)
+
+/**
+ * Drain keyboard controller
+ */
+static void empty_8042 ( void ) {
+ unsigned long time;
+
+ time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */
+ while ( ( inb ( K_CMD ) & ( K_IBUF_FUL | K_OBUF_FUL ) ) &&
+ currticks() < time ) {
+ iodelay();
+ ( void ) inb_p ( K_RDWR );
+ iodelay();
+ }
+}
+
+/**
+ * Fast test to see if gate A20 is already set
+ *
+ * @v retries Number of times to retry before giving up
+ * @ret set Gate A20 is set
+ */
+static int gateA20_is_set ( int retries ) {
+ static uint32_t test_pattern = 0xdeadbeef;
+ physaddr_t test_pattern_phys = virt_to_phys ( &test_pattern );
+ physaddr_t verify_pattern_phys = ( test_pattern_phys ^ 0x100000 );
+ userptr_t verify_pattern_user = phys_to_user ( verify_pattern_phys );
+ uint32_t verify_pattern;
+
+ do {
+ /* Check for difference */
+ copy_from_user ( &verify_pattern, verify_pattern_user, 0,
+ sizeof ( verify_pattern ) );
+ if ( verify_pattern != test_pattern )
+ return 1;
+
+ /* Avoid false negatives */
+ test_pattern++;
+
+ iodelay();
+
+ /* Always retry at least once, to avoid false negatives */
+ } while ( retries-- >= 0 );
+
+ /* Pattern matched every time; gate A20 is not set */
+ return 0;
+}
+
+/*
+ * Gate A20 for high memory
+ *
+ * Note that this function gets called as part of the return path from
+ * librm's real_call, which is used to make the int15 call if librm is
+ * being used. To avoid an infinite recursion, we make gateA20_set
+ * return immediately if it is already part of the call stack.
+ */
+void gateA20_set ( void ) {
+ static char reentry_guard = 0;
+ static int a20_method = A20_UNKNOWN;
+ unsigned int discard_a;
+ unsigned int scp_a;
+ int retries = 0;
+
+ /* Avoid potential infinite recursion */
+ if ( reentry_guard )
+ return;
+ reentry_guard = 1;
+
+ /* Fast check to see if gate A20 is already enabled */
+ if ( gateA20_is_set ( 0 ) )
+ goto out;
+
+ for ( ; retries < A20_MAX_RETRIES ; retries++ ) {
+ switch ( a20_method ) {
+ case A20_UNKNOWN:
+ case A20_INT15:
+ /* Try INT 15 method */
+ __asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
+ : "=a" ( discard_a )
+ : "a" ( Enable_A20 ) );
+ if ( gateA20_is_set ( A20_INT15_RETRIES ) ) {
+ DBG ( "Enabled gate A20 using BIOS\n" );
+ a20_method = A20_INT15;
+ goto out;
+ }
+ /* fall through */
+ case A20_KBC:
+ /* Try keyboard controller method */
+ empty_8042();
+ outb ( KC_CMD_WOUT, K_CMD );
+ empty_8042();
+ outb ( KB_SET_A20, K_RDWR );
+ empty_8042();
+ outb ( KC_CMD_NULL, K_CMD );
+ empty_8042();
+ if ( gateA20_is_set ( A20_KBC_RETRIES ) ) {
+ DBG ( "Enabled gate A20 using "
+ "keyboard controller\n" );
+ a20_method = A20_KBC;
+ goto out;
+ }
+ /* fall through */
+ case A20_SCPA:
+ /* Try "Fast gate A20" method */
+ scp_a = inb ( SCP_A );
+ scp_a &= ~0x01; /* Avoid triggering a reset */
+ scp_a |= 0x02; /* Enable A20 */
+ iodelay();
+ outb ( scp_a, SCP_A );
+ iodelay();
+ if ( gateA20_is_set ( A20_SCPA_RETRIES ) ) {
+ DBG ( "Enabled gate A20 using "
+ "Fast Gate A20\n" );
+ a20_method = A20_SCPA;
+ goto out;
+ }
+ }
+ }
+
+ /* Better to die now than corrupt memory later */
+ printf ( "FATAL: Gate A20 stuck\n" );
+ while ( 1 ) {}
+
+ out:
+ if ( retries )
+ DBG ( "%d attempts were required to enable A20\n",
+ ( retries + 1 ) );
+ reentry_guard = 0;
+}
+
+void gateA20_unset ( void ) {
+ /* Not currently implemented */
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/hidemem.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/hidemem.c
new file mode 100644
index 0000000..17082c3
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/hidemem.c
@@ -0,0 +1,220 @@
+/* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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_LICENCE ( GPL2_OR_LATER );
+
+#include <assert.h>
+#include <realmode.h>
+#include <biosint.h>
+#include <basemem.h>
+#include <fakee820.h>
+#include <gpxe/init.h>
+#include <gpxe/memmap.h>
+#include <gpxe/hidemem.h>
+
+/** Set to true if you want to test a fake E820 map */
+#define FAKE_E820 0
+
+/** Alignment for hidden memory regions */
+#define ALIGN_HIDDEN 4096 /* 4kB page alignment should be enough */
+
+/**
+ * A hidden region of gPXE
+ *
+ * This represents a region that will be edited out of the system's
+ * memory map.
+ *
+ * This structure is accessed by assembly code, so must not be
+ * changed.
+ */
+struct hidden_region {
+ /** Physical start address */
+ uint64_t start;
+ /** Physical end address */
+ uint64_t end;
+};
+
+/** Hidden base memory */
+extern struct hidden_region __data16 ( hidemem_base );
+#define hidemem_base __use_data16 ( hidemem_base )
+
+/** Hidden umalloc memory */
+extern struct hidden_region __data16 ( hidemem_umalloc );
+#define hidemem_umalloc __use_data16 ( hidemem_umalloc )
+
+/** Hidden text memory */
+extern struct hidden_region __data16 ( hidemem_textdata );
+#define hidemem_textdata __use_data16 ( hidemem_textdata )
+
+/** Assembly routine in e820mangler.S */
+extern void int15();
+
+/** Vector for storing original INT 15 handler */
+extern struct segoff __text16 ( int15_vector );
+#define int15_vector __use_text16 ( int15_vector )
+
+/* The linker defines these symbols for us */
+extern char _textdata[];
+extern char _etextdata[];
+extern char _text16_memsz[];
+#define _text16_memsz ( ( unsigned int ) _text16_memsz )
+extern char _data16_memsz[];
+#define _data16_memsz ( ( unsigned int ) _data16_memsz )
+
+/**
+ * Hide region of memory from system memory map
+ *
+ * @v region Hidden memory region
+ * @v start Start of region
+ * @v end End of region
+ */
+static void hide_region ( struct hidden_region *region,
+ physaddr_t start, physaddr_t end ) {
+
+ /* Some operating systems get a nasty shock if a region of the
+ * E820 map seems to start on a non-page boundary. Make life
+ * safer by rounding out our edited region.
+ */
+ region->start = ( start & ~( ALIGN_HIDDEN - 1 ) );
+ region->end = ( ( end + ALIGN_HIDDEN - 1 ) & ~( ALIGN_HIDDEN - 1 ) );
+
+ DBG ( "Hiding region [%llx,%llx)\n", region->start, region->end );
+}
+
+/**
+ * Hide used base memory
+ *
+ */
+void hide_basemem ( void ) {
+ /* Hide from the top of free base memory to 640kB. Don't use
+ * hide_region(), because we don't want this rounded to the
+ * nearest page boundary.
+ */
+ hidemem_base.start = ( get_fbms() * 1024 );
+}
+
+/**
+ * Hide umalloc() region
+ *
+ */
+void hide_umalloc ( physaddr_t start, physaddr_t end ) {
+ assert ( end <= virt_to_phys ( _textdata ) );
+ hide_region ( &hidemem_umalloc, start, end );
+}
+
+/**
+ * Hide .text and .data
+ *
+ */
+void hide_textdata ( void ) {
+ hide_region ( &hidemem_textdata, virt_to_phys ( _textdata ),
+ virt_to_phys ( _etextdata ) );
+}
+
+/**
+ * Hide Etherboot
+ *
+ * Installs an INT 15 handler to edit Etherboot out of the memory map
+ * returned by the BIOS.
+ */
+static void hide_etherboot ( void ) {
+ struct memory_map memmap;
+ unsigned int rm_ds_top;
+ unsigned int rm_cs_top;
+ unsigned int fbms;
+
+ /* Dump memory map before mangling */
+ DBG ( "Hiding gPXE from system memory map\n" );
+ get_memmap ( &memmap );
+
+ /* Hook in fake E820 map, if we're testing one */
+ if ( FAKE_E820 ) {
+ DBG ( "Hooking in fake E820 map\n" );
+ fake_e820();
+ get_memmap ( &memmap );
+ }
+
+ /* Initialise the hidden regions */
+ hide_basemem();
+ hide_umalloc ( virt_to_phys ( _textdata ), virt_to_phys ( _textdata ) );
+ hide_textdata();
+
+ /* Some really moronic BIOSes bring up the PXE stack via the
+ * UNDI loader entry point and then don't bother to unload it
+ * before overwriting the code and data segments. If this
+ * happens, we really don't want to leave INT 15 hooked,
+ * because that will cause any loaded OS to die horribly as
+ * soon as it attempts to fetch the system memory map.
+ *
+ * We use a heuristic to guess whether or not we are being
+ * loaded sensibly.
+ */
+ rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_memsz + 1024 - 1 ) >> 10 );
+ rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_memsz + 1024 - 1 ) >> 10 );
+ fbms = get_fbms();
+ if ( ( rm_cs_top < fbms ) && ( rm_ds_top < fbms ) ) {
+ DBG ( "Detected potentially unsafe UNDI load at CS=%04x "
+ "DS=%04x FBMS=%dkB\n", rm_cs, rm_ds, fbms );
+ DBG ( "Disabling INT 15 memory hiding\n" );
+ return;
+ }
+
+ /* Hook INT 15 */
+ hook_bios_interrupt ( 0x15, ( unsigned int ) int15,
+ &int15_vector );
+
+ /* Dump memory map after mangling */
+ DBG ( "Hidden gPXE from system memory map\n" );
+ get_memmap ( &memmap );
+}
+
+/**
+ * Unhide Etherboot
+ *
+ * Uninstalls the INT 15 handler installed by hide_etherboot(), if
+ * possible.
+ */
+static void unhide_etherboot ( int flags __unused ) {
+
+ /* If we have more than one hooked interrupt at this point, it
+ * means that some other vector is still hooked, in which case
+ * we can't safely unhook INT 15 because we need to keep our
+ * memory protected. (We expect there to be at least one
+ * hooked interrupt, because INT 15 itself is still hooked).
+ */
+ if ( hooked_bios_interrupts > 1 ) {
+ DBG ( "Cannot unhide: %d interrupt vectors still hooked\n",
+ hooked_bios_interrupts );
+ return;
+ }
+
+ /* Try to unhook INT 15. If it fails, then just leave it
+ * hooked; it takes care of protecting itself. :)
+ */
+ unhook_bios_interrupt ( 0x15, ( unsigned int ) int15,
+ &int15_vector );
+
+ /* Unhook fake E820 map, if used */
+ if ( FAKE_E820 )
+ unfake_e820();
+}
+
+/** Hide Etherboot startup function */
+struct startup_fn hide_etherboot_startup_fn __startup_fn ( STARTUP_EARLY ) = {
+ .startup = hide_etherboot,
+ .shutdown = unhide_etherboot,
+};
diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/memmap.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/memmap.c
new file mode 100644
index 0000000..8a30dba
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/memmap.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <errno.h>
+#include <realmode.h>
+#include <bios.h>
+#include <memsizes.h>
+#include <gpxe/memmap.h>
+
+/**
+ * @file
+ *
+ * Memory mapping
+ *
+ */
+
+/** Magic value for INT 15,e820 calls */
+#define SMAP ( 0x534d4150 )
+
+/** An INT 15,e820 memory map entry */
+struct e820_entry {
+ /** Start of region */
+ uint64_t start;
+ /** Length of region */
+ uint64_t len;
+ /** Type of region */
+ uint32_t type;
+ /** Extended attributes (optional) */
+ uint32_t attrs;
+} __attribute__ (( packed ));
+
+#define E820_TYPE_RAM 1 /**< Normal memory */
+#define E820_TYPE_RESERVED 2 /**< Reserved and unavailable */
+#define E820_TYPE_ACPI 3 /**< ACPI reclaim memory */
+#define E820_TYPE_NVS 4 /**< ACPI NVS memory */
+
+#define E820_ATTR_ENABLED 0x00000001UL
+#define E820_ATTR_NONVOLATILE 0x00000002UL
+#define E820_ATTR_UNKNOWN 0xfffffffcUL
+
+#define E820_MIN_SIZE 20
+
+/** Buffer for INT 15,e820 calls */
+static struct e820_entry __bss16 ( e820buf );
+#define e820buf __use_data16 ( e820buf )
+
+/**
+ * Get size of extended memory via INT 15,e801
+ *
+ * @ret extmem Extended memory size, in kB, or 0
+ */
+static unsigned int extmemsize_e801 ( void ) {
+ uint16_t extmem_1m_to_16m_k, extmem_16m_plus_64k;
+ uint16_t confmem_1m_to_16m_k, confmem_16m_plus_64k;
+ unsigned int flags;
+ unsigned int extmem;
+
+ __asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
+ "int $0x15\n\t"
+ "pushfw\n\t"
+ "popw %w0\n\t" )
+ : "=r" ( flags ),
+ "=a" ( extmem_1m_to_16m_k ),
+ "=b" ( extmem_16m_plus_64k ),
+ "=c" ( confmem_1m_to_16m_k ),
+ "=d" ( confmem_16m_plus_64k )
+ : "a" ( 0xe801 ) );
+
+ if ( flags & CF ) {
+ DBG ( "INT 15,e801 failed with CF set\n" );
+ return 0;
+ }
+
+ if ( ! ( extmem_1m_to_16m_k | extmem_16m_plus_64k ) ) {
+ DBG ( "INT 15,e801 extmem=0, using confmem\n" );
+ extmem_1m_to_16m_k = confmem_1m_to_16m_k;
+ extmem_16m_plus_64k = confmem_16m_plus_64k;
+ }
+
+ extmem = ( extmem_1m_to_16m_k + ( extmem_16m_plus_64k * 64 ) );
+ DBG ( "INT 15,e801 extended memory size %d+64*%d=%d kB "
+ "[100000,%llx)\n", extmem_1m_to_16m_k, extmem_16m_plus_64k,
+ extmem, ( 0x100000 + ( ( ( uint64_t ) extmem ) * 1024 ) ) );
+
+ /* Sanity check. Some BIOSes report the entire 4GB address
+ * space as available, which cannot be correct (since that
+ * would leave no address space available for 32-bit PCI
+ * BARs).
+ */
+ if ( extmem == ( 0x400000 - 0x400 ) ) {
+ DBG ( "INT 15,e801 reported whole 4GB; assuming insane\n" );
+ return 0;
+ }
+
+ return extmem;
+}
+
+/**
+ * Get size of extended memory via INT 15,88
+ *
+ * @ret extmem Extended memory size, in kB
+ */
+static unsigned int extmemsize_88 ( void ) {
+ uint16_t extmem;
+
+ /* Ignore CF; it is not reliable for this call */
+ __asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
+ : "=a" ( extmem ) : "a" ( 0x8800 ) );
+
+ DBG ( "INT 15,88 extended memory size %d kB [100000, %x)\n",
+ extmem, ( 0x100000 + ( extmem * 1024 ) ) );
+ return extmem;
+}
+
+/**
+ * Get size of extended memory
+ *
+ * @ret extmem Extended memory size, in kB
+ *
+ * Note that this is only an approximation; for an accurate picture,
+ * use the E820 memory map obtained via get_memmap();
+ */
+unsigned int extmemsize ( void ) {
+ unsigned int extmem;
+
+ /* Try INT 15,e801 first, then fall back to INT 15,88 */
+ extmem = extmemsize_e801();
+ if ( ! extmem )
+ extmem = extmemsize_88();
+ return extmem;
+}
+
+/**
+ * Get e820 memory map
+ *
+ * @v memmap Memory map to fill in
+ * @ret rc Return status code
+ */
+static int meme820 ( struct memory_map *memmap ) {
+ struct memory_region *region = memmap->regions;
+ uint32_t next = 0;
+ uint32_t smap;
+ size_t size;
+ unsigned int flags;
+ unsigned int discard_D;
+
+ /* Clear the E820 buffer. Do this once before starting,
+ * rather than on each call; some BIOSes rely on the contents
+ * being preserved between calls.
+ */
+ memset ( &e820buf, 0, sizeof ( e820buf ) );
+
+ do {
+ /* Some BIOSes corrupt %esi for fun. Guard against
+ * this by telling gcc that all non-output registers
+ * may be corrupted.
+ */
+ __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t"
+ "stc\n\t"
+ "int $0x15\n\t"
+ "pushfw\n\t"
+ "popw %%dx\n\t"
+ "popl %%ebp\n\t" )
+ : "=a" ( smap ), "=b" ( next ),
+ "=c" ( size ), "=d" ( flags ),
+ "=D" ( discard_D )
+ : "a" ( 0xe820 ), "b" ( next ),
+ "D" ( __from_data16 ( &e820buf ) ),
+ "c" ( sizeof ( e820buf ) ),
+ "d" ( SMAP )
+ : "esi", "memory" );
+
+ if ( smap != SMAP ) {
+ DBG ( "INT 15,e820 failed SMAP signature check\n" );
+ return -ENOTSUP;
+ }
+
+ if ( size < E820_MIN_SIZE ) {
+ DBG ( "INT 15,e820 returned only %zd bytes\n", size );
+ return -EINVAL;
+ }
+
+ if ( flags & CF ) {
+ DBG ( "INT 15,e820 terminated on CF set\n" );
+ break;
+ }
+
+ /* If first region is not RAM, assume map is invalid */
+ if ( ( memmap->count == 0 ) &&
+ ( e820buf.type != E820_TYPE_RAM ) ) {
+ DBG ( "INT 15,e820 failed, first entry not RAM\n" );
+ return -EINVAL;
+ }
+
+ DBG ( "INT 15,e820 region [%llx,%llx) type %d",
+ e820buf.start, ( e820buf.start + e820buf.len ),
+ ( int ) e820buf.type );
+ if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
+ DBG ( " (%s", ( ( e820buf.attrs & E820_ATTR_ENABLED )
+ ? "enabled" : "disabled" ) );
+ if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
+ DBG ( ", non-volatile" );
+ if ( e820buf.attrs & E820_ATTR_UNKNOWN )
+ DBG ( ", other [%08x]", e820buf.attrs );
+ DBG ( ")" );
+ }
+ DBG ( "\n" );
+
+ /* Discard non-RAM regions */
+ if ( e820buf.type != E820_TYPE_RAM )
+ continue;
+
+ /* Check extended attributes, if present */
+ if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
+ if ( ! ( e820buf.attrs & E820_ATTR_ENABLED ) )
+ continue;
+ if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
+ continue;
+ }
+
+ region->start = e820buf.start;
+ region->end = e820buf.start + e820buf.len;
+ region++;
+ memmap->count++;
+
+ if ( memmap->count >= ( sizeof ( memmap->regions ) /
+ sizeof ( memmap->regions[0] ) ) ) {
+ DBG ( "INT 15,e820 too many regions returned\n" );
+ /* Not a fatal error; what we've got so far at
+ * least represents valid regions of memory,
+ * even if we couldn't get them all.
+ */
+ break;
+ }
+ } while ( next != 0 );
+
+ /* Sanity checks. Some BIOSes report complete garbage via INT
+ * 15,e820 (especially at POST time), despite passing the
+ * signature checks. We currently check for a base memory
+ * region (starting at 0) and at least one high memory region
+ * (starting at 0x100000).
+ */
+ if ( memmap->count < 2 ) {
+ DBG ( "INT 15,e820 returned only %d regions; assuming "
+ "insane\n", memmap->count );
+ return -EINVAL;
+ }
+ if ( memmap->regions[0].start != 0 ) {
+ DBG ( "INT 15,e820 region 0 starts at %llx (expected 0); "
+ "assuming insane\n", memmap->regions[0].start );
+ return -EINVAL;
+ }
+ if ( memmap->regions[1].start != 0x100000 ) {
+ DBG ( "INT 15,e820 region 1 starts at %llx (expected 100000); "
+ "assuming insane\n", memmap->regions[0].start );
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * Get memory map
+ *
+ * @v memmap Memory map to fill in
+ */
+void get_memmap ( struct memory_map *memmap ) {
+ unsigned int basemem, extmem;
+ int rc;
+
+ DBG ( "Fetching system memory map\n" );
+
+ /* Clear memory map */
+ memset ( memmap, 0, sizeof ( *memmap ) );
+
+ /* Get base and extended memory sizes */
+ basemem = basememsize();
+ DBG ( "FBMS base memory size %d kB [0,%x)\n",
+ basemem, ( basemem * 1024 ) );
+ extmem = extmemsize();
+
+ /* Try INT 15,e820 first */
+ if ( ( rc = meme820 ( memmap ) ) == 0 ) {
+ DBG ( "Obtained system memory map via INT 15,e820\n" );
+ return;
+ }
+
+ /* Fall back to constructing a map from basemem and extmem sizes */
+ DBG ( "INT 15,e820 failed; constructing map\n" );
+ memmap->regions[0].end = ( basemem * 1024 );
+ memmap->regions[1].start = 0x100000;
+ memmap->regions[1].end = 0x100000 + ( extmem * 1024 );
+ memmap->count = 2;
+}
diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/pnpbios.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/pnpbios.c
new file mode 100644
index 0000000..c572914
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/firmware/pcbios/pnpbios.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <realmode.h>
+#include <pnpbios.h>
+
+/** @file
+ *
+ * PnP BIOS
+ *
+ */
+
+/** PnP BIOS structure */
+struct pnp_bios {
+ /** Signature
+ *
+ * Must be equal to @c PNP_BIOS_SIGNATURE
+ */
+ uint32_t signature;
+ /** Version as BCD (e.g. 1.0 is 0x10) */
+ uint8_t version;
+ /** Length of this structure */
+ uint8_t length;
+ /** System capabilities */
+ uint16_t control;
+ /** Checksum */
+ uint8_t checksum;
+} __attribute__ (( packed ));
+
+/** Signature for a PnP BIOS structure */
+#define PNP_BIOS_SIGNATURE \
+ ( ( '$' << 0 ) + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
+
+/**
+ * Test address for PnP BIOS structure
+ *
+ * @v offset Offset within BIOS segment to test
+ * @ret rc Return status code
+ */
+static int is_pnp_bios ( unsigned int offset ) {
+ union {
+ struct pnp_bios pnp_bios;
+ uint8_t bytes[256]; /* 256 is maximum length possible */
+ } u;
+ size_t len;
+ unsigned int i;
+ uint8_t sum = 0;
+
+ /* Read start of header and verify signature */
+ copy_from_real ( &u.pnp_bios, BIOS_SEG, offset, sizeof ( u.pnp_bios ));
+ if ( u.pnp_bios.signature != PNP_BIOS_SIGNATURE )
+ return -EINVAL;
+
+ /* Read whole header and verify checksum */
+ len = u.pnp_bios.length;
+ copy_from_real ( &u.bytes, BIOS_SEG, offset, len );
+ for ( i = 0 ; i < len ; i++ ) {
+ sum += u.bytes[i];
+ }
+ if ( sum != 0 )
+ return -EINVAL;
+
+ DBG ( "Found PnP BIOS at %04x:%04x\n", BIOS_SEG, offset );
+
+ return 0;
+}
+
+/**
+ * Locate Plug-and-Play BIOS
+ *
+ * @ret pnp_offset Offset of PnP BIOS structure within BIOS segment
+ *
+ * The PnP BIOS structure will be at BIOS_SEG:pnp_offset. If no PnP
+ * BIOS is found, -1 is returned.
+ */
+int find_pnp_bios ( void ) {
+ static int pnp_offset = 0;
+
+ if ( pnp_offset )
+ return pnp_offset;
+
+ for ( pnp_offset = 0 ; pnp_offset < 0x10000 ; pnp_offset += 0x10 ) {
+ if ( is_pnp_bios ( pnp_offset ) == 0 )
+ return pnp_offset;
+ }
+
+ pnp_offset = -1;
+ return pnp_offset;
+}