summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2008-09-24 19:33:31 +0200
committerMichael Brown2008-09-24 19:33:31 +0200
commit887d77c27ac6ccdb13892ab05e50281e63df6bbf (patch)
tree195dc9a42cd1e4eee891641b19411877aa5b0c3c
parent[settings] Add the uristring setting type (diff)
downloadipxe-887d77c27ac6ccdb13892ab05e50281e63df6bbf.tar.gz
ipxe-887d77c27ac6ccdb13892ab05e50281e63df6bbf.tar.xz
ipxe-887d77c27ac6ccdb13892ab05e50281e63df6bbf.zip
[pcbios] Inhibit INT 15 memory map hiding on brain-dead BIOSes
Some really moronic BIOSes bring up the PXE stack via the UNDI loader entry point during POST, 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 detect whether or not we are being loaded at the top of free base memory. If we determine that we are being loaded at some other arbitrary location in base memory, then we assume that it's not safe to hook INT 15.
-rw-r--r--src/arch/i386/firmware/pcbios/hidemem.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/src/arch/i386/firmware/pcbios/hidemem.c b/src/arch/i386/firmware/pcbios/hidemem.c
index 2e74d3b0..202081b6 100644
--- a/src/arch/i386/firmware/pcbios/hidemem.c
+++ b/src/arch/i386/firmware/pcbios/hidemem.c
@@ -64,6 +64,10 @@ extern struct segoff __text16 ( int15_vector );
/* The linker defines these symbols for us */
extern char _text[];
extern char _end[];
+extern char _text16_size[];
+#define _text16_size ( ( unsigned int ) _text16_size )
+extern char _data16_size[];
+#define _data16_size ( ( unsigned int ) _data16_size )
/**
* Hide region of memory from system memory map
@@ -123,6 +127,9 @@ void hide_text ( void ) {
*/
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" );
@@ -133,6 +140,26 @@ static void hide_etherboot ( void ) {
hide_umalloc ( virt_to_phys ( _text ), virt_to_phys ( _text ) );
hide_text();
+ /* 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_size + 1024 - 1 ) >> 10 );
+ rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_size + 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 );