]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[pcbios] Inhibit all calls to INT 15,e820 and INT 15,e801 during POST
authorMichael Brown <mcb30@ipxe.org>
Mon, 11 Mar 2013 00:50:52 +0000 (00:50 +0000)
committerMichael Brown <mcb30@ipxe.org>
Mon, 11 Mar 2013 01:20:01 +0000 (01:20 +0000)
Many BIOSes do not construct the full system memory map until after
calling the option ROM initialisation entry points.  For several
years, we have added sanity checks and workarounds to accommodate
charming quirks such as BIOSes which report the entire 32-bit address
space (including all memory-mapped PCI BARs) as being usable RAM.

The IBM x3650 takes quirky behaviour to a new extreme.  Calling either
INT 15,e820 or INT 15,e801 during POST doesn't just get you invalid
data.  We could cope with invalid data.  Instead, these nominally
read-only API calls manage to trash some internal BIOS state, with the
result that the system memory map is _never_ constructed.  This tends
to confuse subsequent bootloaders and operating systems.

[ GRUB 0.97 fails in a particularly amusing way.  Someone thought it
would be a good idea for memcpy() to check that the destination memory
region is a valid part of the system memory map; if not, then memcpy()
will sulk, fail, and return NULL.  This breaks pretty much every use
of memcpy() including, for example, those inserted implicitly by gcc
to copy non-const initialisers.  Debugging is _fun_ when a simple call
to printf() manages to create an infinite recursion, exhaust the
available stack space, and shut down the CPU. ]

Fix by completely inhibiting calls to INT 15,e820 and INT 15,e801
during POST.

We do now allow relocation during POST up to the maximum address
returned by INT 15,88 (which seems so far to always be safe).  This
allows us to continue to have a reasonable size of external heap, even
if the PMM allocation is close to the 1MB mark.

The downside of allowing relocation during POST is that we may
overwrite PMM-allocated memory in use by other option ROMs.  However,
the downside of inhibiting relocation, when combined with also
inhibiting calls to INT 15,e820 and INT 15,e801, would be that we
might have no external heap available: this would make booting an OS
impossible and could prevent some devices from even completing
initialisation.

On balance, the lesser evil is probably to allow relocation during
POST (up to the limit provided by INT 15,88).  Entering iPXE during
POST is a rare operation; on the even rarer systems where doing so
happens to overwrite a PMM-allocated region, then there exists a
fairly simple workaround: if the user enters iPXE during POST and
wishes to exit iPXE, then the user must reboot.  This is an acceptable
cost, given the rarity of the situation and the simplicity of the
workaround.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/i386/core/relocate.c
src/arch/i386/firmware/pcbios/memmap.c
src/arch/i386/prefix/exeprefix.S
src/arch/i386/prefix/libprefix.S
src/arch/i386/prefix/romprefix.S
src/arch/i386/prefix/undiloader.S

index b9b029443d1aac181759d0e80da2124f9cbbc80d..5fbf2d2c27a419be250a8d2e74535c231398de00 100644 (file)
@@ -33,8 +33,10 @@ extern char _etextdata[];
 /**
  * Relocate iPXE
  *
- * @v ix86             x86 register dump from prefix
- * @ret ix86           x86 registers to return to prefix
+ * @v ebp              Maximum address to use for relocation
+ * @ret esi            Current physical address
+ * @ret edi            New physical address
+ * @ret ecx            Length to copy
  *
  * This finds a suitable location for iPXE near the top of 32-bit
  * address space, and returns the physical address of the new location
@@ -59,7 +61,7 @@ __asmcall void relocate ( struct i386_all_regs *ix86 ) {
 
        /* Determine maximum usable address */
        max = MAX_ADDR;
-       if ( ix86->regs.ebp && ( ix86->regs.ebp < max ) ) {
+       if ( ix86->regs.ebp < max ) {
                max = ix86->regs.ebp;
                DBG ( "Limiting relocation to [0,%lx)\n", max );
        }
index cf659226467baf3cd4db68be24172ef31affc27c..0937a7ce279655b10342153c853b386e71b3e96c 100644 (file)
@@ -63,6 +63,10 @@ struct e820_entry {
 static struct e820_entry __bss16 ( e820buf );
 #define e820buf __use_data16 ( e820buf )
 
+/** We are running during POST; inhibit INT 15,e820 and INT 15,e801 */
+uint8_t __bss16 ( memmap_post );
+#define memmap_post __use_data16 ( memmap_post )
+
 /**
  * Get size of extended memory via INT 15,e801
  *
@@ -74,6 +78,12 @@ static unsigned int extmemsize_e801 ( void ) {
        unsigned int flags;
        unsigned int extmem;
 
+       /* Inhibit INT 15,e801 during POST */
+       if ( memmap_post ) {
+               DBG ( "INT 15,e801 not available during POST\n" );
+               return 0;
+       }
+
        __asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
                                           "int $0x15\n\t"
                                           "pushfw\n\t"
@@ -164,6 +174,12 @@ static int meme820 ( struct memory_map *memmap ) {
        unsigned int flags;
        unsigned int discard_D;
 
+       /* Inhibit INT 15,e820 during POST */
+       if ( memmap_post ) {
+               DBG ( "INT 15,e820 not available during POST\n" );
+               return -ENOTTY;
+       }
+
        /* Clear the E820 buffer.  Do this once before starting,
         * rather than on each call; some BIOSes rely on the contents
         * being preserved between calls.
index acd3f83cd39e087bb685718a0b368055fd5b06b3..cb61287d315b574103004e6f3749e2fd4d42b29f 100644 (file)
@@ -114,7 +114,7 @@ _exe_start:
        call    alloc_basemem
        xorl    %esi, %esi
        movl    $EXE_DECOMPRESS_ADDRESS, %edi
-       xorl    %ebp, %ebp
+       orl     $0xffffffff, %ebp       /* Allow arbitrary relocation */
        call    install_prealloc
 
        /* Set up real-mode stack */
index 0bd80b0abad93d5a037c7109737a81b430a023c9..197a86bc8e8a9b8215878a20c469ea84dba960c6 100644 (file)
@@ -622,7 +622,7 @@ install:
        /* Image destination = default */
        xorl    %edi, %edi
        /* Allow arbitrary relocation */
-       xorl    %ebp, %ebp
+       orl     $0xffffffff, %ebp
        /* Install text and data segments */
        call    install_prealloc
        /* Restore registers and return */
@@ -642,7 +642,9 @@ install:
  *   %bx  : .data16 segment address
  *   %esi : Image source physical address (or zero for %cs:0000)
  *   %edi : Decompression temporary area physical address (or zero for default)
- *   %ebp : Maximum end address for relocation (or zero for no maximum)
+ *   %ebp : Maximum end address for relocation
+ *          - 0xffffffff for no maximum
+ *          - 0x00000000 to inhibit use of INT 15,e820 and INT 15,e801
  * Corrupts:
  *   none
  ****************************************************************************
@@ -796,6 +798,13 @@ payload_death_message:
        movw    %ax, (init_librm_vector+2)
        lcall   *init_librm_vector
 
+       /* Inhibit INT 15,e820 and INT 15,e801 if applicable */
+       testl   %ebp, %ebp
+       jnz     1f
+       incb    memmap_post
+       decl    %ebp
+1:
+
        /* Call relocate() to determine target address for relocation.
         * relocate() will return with %esi, %edi and %ecx set up
         * ready for the copy to the new location.
index 35d037eff8b44a8775fe27118351191ccdc7e9d0..18fef75e49b18b05da659eaec2e0c23a64646b3d 100644 (file)
@@ -445,7 +445,7 @@ no_pmm:
         * picked up by the initial shell prompt, and we will drop
         * into a shell.
         */
-       movl    $0xa0000, %ebp  /* Inhibit relocation during POST */
+       xorl    %ebp, %ebp      /* Inhibit use of INT 15,e820 and INT 15,e801 */
        pushw   %cs
        call    exec
 2:
@@ -630,7 +630,7 @@ decompress_to:
  * Called by the PnP BIOS when it wants to boot us.
  */
 bev_entry:
-       xorl    %ebp, %ebp      /* Allow relocation */
+       orl     $0xffffffff, %ebp       /* Allow arbitrary relocation */
        pushw   %cs
        call    exec
        lret
@@ -665,7 +665,7 @@ int19_entry:
        /* Leave keypress in buffer and start iPXE.  The keypress will
         * cause the usual initial Ctrl-B prompt to be skipped.
         */
-       xorl    %ebp, %ebp      /* Allow relocation */
+       orl     $0xffffffff, %ebp       /* Allow arbitrary relocation */
        pushw   %cs
        call    exec
 1:     /* Try to call original INT 19 vector */
index bb3d469be58959c47bb8a6bddae203d0a9c32268..ccdd816e6686a8120d4f3e43ae7a5027836b0bd1 100644 (file)
@@ -31,7 +31,7 @@ undiloader:
        movw    %es:14(%di), %ax
        movl    image_source, %esi
        movl    decompress_to, %edi
-       xorl    %ebp, %ebp              /* Allow relocation */
+       orl     $0xffffffff, %ebp       /* Allow arbitrary relocation */
        call    install_prealloc
        popw    %di
        /* Call UNDI loader C code */