[pcbios] Inhibit INT 15 memory map hiding on brain-dead BIOSes
authorMichael Brown <mcb30@etherboot.org>
Wed, 24 Sep 2008 17:33:31 +0000 (18:33 +0100)
committerMichael Brown <mcb30@etherboot.org>
Wed, 24 Sep 2008 17:33:31 +0000 (18:33 +0100)
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.

src/arch/i386/firmware/pcbios/hidemem.c

index 2e74d3b..202081b 100644 (file)
@@ -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 );