From c24bc349ead939d90b5784dbff3cd9fdb9d83ba8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 25 Sep 2008 03:34:26 +0100 Subject: [PATCH] [pcbios] Add facility for testing arbitrary E820 memory maps We seem to be having issues with various E820 memory maps. These problems are often difficult to reproduce, requiring access to the specific system exhibiting the problem. Add a facility for hooking in a fake E820 map generator, using an arbitrary map defined in a C array, solely in order to be able to test the map-mangling code against arbitrary E820 maps. --- src/arch/i386/firmware/pcbios/fakee820.c | 90 ++++++++++++++++++++++++ src/arch/i386/firmware/pcbios/hidemem.c | 15 ++++ src/arch/i386/include/fakee820.h | 7 ++ 3 files changed, 112 insertions(+) create mode 100644 src/arch/i386/firmware/pcbios/fakee820.c create mode 100644 src/arch/i386/include/fakee820.h diff --git a/src/arch/i386/firmware/pcbios/fakee820.c b/src/arch/i386/firmware/pcbios/fakee820.c new file mode 100644 index 00000000..e171edfd --- /dev/null +++ b/src/arch/i386/firmware/pcbios/fakee820.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2008 Michael Brown . + * + * 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. + */ + +#include +#include + +/** 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" + "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" + "clc\n\t" + "lret $2\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/src/arch/i386/firmware/pcbios/hidemem.c b/src/arch/i386/firmware/pcbios/hidemem.c index 202081b6..c9df7bd0 100644 --- a/src/arch/i386/firmware/pcbios/hidemem.c +++ b/src/arch/i386/firmware/pcbios/hidemem.c @@ -19,10 +19,14 @@ #include #include #include +#include #include #include #include +/** 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 */ @@ -135,6 +139,13 @@ static void hide_etherboot ( void ) { 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 ( _text ), virt_to_phys ( _text ) ); @@ -194,6 +205,10 @@ static void unhide_etherboot ( int flags __unused ) { */ unhook_bios_interrupt ( 0x15, ( unsigned int ) int15, &int15_vector ); + + /* Unhook fake E820 map, if used */ + if ( FAKE_E820 ) + unfake_e820(); } /** Hide Etherboot startup function */ diff --git a/src/arch/i386/include/fakee820.h b/src/arch/i386/include/fakee820.h new file mode 100644 index 00000000..f1fe8aff --- /dev/null +++ b/src/arch/i386/include/fakee820.h @@ -0,0 +1,7 @@ +#ifndef _FAKEE820_H +#define _FAKEE820_H + +extern void fake_e820 ( void ); +extern void unfake_e820 ( void ); + +#endif /* _FAKEE820_H */