[pcbios] Guard against register corruption in INT 15,e820 implementations
authorMichael Brown <mcb30@etherboot.org>
Thu, 23 Oct 2008 03:16:31 +0000 (04:16 +0100)
committerMichael Brown <mcb30@etherboot.org>
Thu, 23 Oct 2008 03:20:45 +0000 (04:20 +0100)
Someone at Dell must have a full-time job designing ways to screw up
implementations of INT 15,e820.  This latest gem is courtesy of a Dell
Xanadu system, which arbitrarily decides to obliterate the contents of
%esi.

Preserve %esi, %edi and %ebp across calls to INT 15,e820, in case
someone tries a variation on this trick in future.

src/arch/i386/firmware/pcbios/e820mangler.S
src/arch/i386/firmware/pcbios/memmap.c

index 7b8d104..53e2d7c 100644 (file)
@@ -268,8 +268,10 @@ get_underlying_e820:
        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   %di
        pushw   %ds
        popw    %es
        movw    $underlying_e820_cache, %di
@@ -280,8 +282,10 @@ get_underlying_e820:
        stc
        pushfw
        lcall   *%cs:int15_vector
-       popw    %di
        popw    %es
+       popl    %ebp
+       popl    %edi
+       popl    %esi
        /* Check for error return from underlying e820 call */
        jc      2f /* CF set: error */
        cmpl    $SMAP, %eax
index 9de10a7..848979e 100644 (file)
@@ -167,6 +167,10 @@ static int meme820 ( struct memory_map *memmap ) {
        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 ( "stc\n\t"
                                                   "int $0x15\n\t"
                                                   "pushfw\n\t"
@@ -178,7 +182,7 @@ static int meme820 ( struct memory_map *memmap ) {
                                         "D" ( __from_data16 ( &e820buf ) ),
                                         "c" ( sizeof ( e820buf ) ),
                                         "d" ( SMAP )
-                                      : "memory" );
+                                      : "esi", "memory" );
 
                if ( smap != SMAP ) {
                        DBG ( "INT 15,e820 failed SMAP signature check\n" );