diff options
-rw-r--r-- | src/arch/i386/firmware/pcbios/hidemem.c | 27 |
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 2e74d3b01..202081b6d 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 ); |