Browse Source

[pcbios] Inhibit all calls to INT 15,e820 and INT 15,e801 during POST

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>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
2629b7e2cd

+ 5
- 3
src/arch/i386/core/relocate.c View File

33
 /**
33
 /**
34
  * Relocate iPXE
34
  * Relocate iPXE
35
  *
35
  *
36
- * @v ix86		x86 register dump from prefix
37
- * @ret ix86		x86 registers to return to prefix
36
+ * @v ebp		Maximum address to use for relocation
37
+ * @ret esi		Current physical address
38
+ * @ret edi		New physical address
39
+ * @ret ecx		Length to copy
38
  *
40
  *
39
  * This finds a suitable location for iPXE near the top of 32-bit
41
  * This finds a suitable location for iPXE near the top of 32-bit
40
  * address space, and returns the physical address of the new location
42
  * address space, and returns the physical address of the new location
59
 
61
 
60
 	/* Determine maximum usable address */
62
 	/* Determine maximum usable address */
61
 	max = MAX_ADDR;
63
 	max = MAX_ADDR;
62
-	if ( ix86->regs.ebp && ( ix86->regs.ebp < max ) ) {
64
+	if ( ix86->regs.ebp < max ) {
63
 		max = ix86->regs.ebp;
65
 		max = ix86->regs.ebp;
64
 		DBG ( "Limiting relocation to [0,%lx)\n", max );
66
 		DBG ( "Limiting relocation to [0,%lx)\n", max );
65
 	}
67
 	}

+ 16
- 0
src/arch/i386/firmware/pcbios/memmap.c View File

63
 static struct e820_entry __bss16 ( e820buf );
63
 static struct e820_entry __bss16 ( e820buf );
64
 #define e820buf __use_data16 ( e820buf )
64
 #define e820buf __use_data16 ( e820buf )
65
 
65
 
66
+/** We are running during POST; inhibit INT 15,e820 and INT 15,e801 */
67
+uint8_t __bss16 ( memmap_post );
68
+#define memmap_post __use_data16 ( memmap_post )
69
+
66
 /**
70
 /**
67
  * Get size of extended memory via INT 15,e801
71
  * Get size of extended memory via INT 15,e801
68
  *
72
  *
74
 	unsigned int flags;
78
 	unsigned int flags;
75
 	unsigned int extmem;
79
 	unsigned int extmem;
76
 
80
 
81
+	/* Inhibit INT 15,e801 during POST */
82
+	if ( memmap_post ) {
83
+		DBG ( "INT 15,e801 not available during POST\n" );
84
+		return 0;
85
+	}
86
+
77
 	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
87
 	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
78
 					   "int $0x15\n\t"
88
 					   "int $0x15\n\t"
79
 					   "pushfw\n\t"
89
 					   "pushfw\n\t"
164
 	unsigned int flags;
174
 	unsigned int flags;
165
 	unsigned int discard_D;
175
 	unsigned int discard_D;
166
 
176
 
177
+	/* Inhibit INT 15,e820 during POST */
178
+	if ( memmap_post ) {
179
+		DBG ( "INT 15,e820 not available during POST\n" );
180
+		return -ENOTTY;
181
+	}
182
+
167
 	/* Clear the E820 buffer.  Do this once before starting,
183
 	/* Clear the E820 buffer.  Do this once before starting,
168
 	 * rather than on each call; some BIOSes rely on the contents
184
 	 * rather than on each call; some BIOSes rely on the contents
169
 	 * being preserved between calls.
185
 	 * being preserved between calls.

+ 1
- 1
src/arch/i386/prefix/exeprefix.S View File

114
 	call	alloc_basemem
114
 	call	alloc_basemem
115
 	xorl	%esi, %esi
115
 	xorl	%esi, %esi
116
 	movl	$EXE_DECOMPRESS_ADDRESS, %edi
116
 	movl	$EXE_DECOMPRESS_ADDRESS, %edi
117
-	xorl	%ebp, %ebp
117
+	orl	$0xffffffff, %ebp	/* Allow arbitrary relocation */
118
 	call	install_prealloc
118
 	call	install_prealloc
119
 
119
 
120
 	/* Set up real-mode stack */
120
 	/* Set up real-mode stack */

+ 11
- 2
src/arch/i386/prefix/libprefix.S View File

622
 	/* Image destination = default */
622
 	/* Image destination = default */
623
 	xorl	%edi, %edi
623
 	xorl	%edi, %edi
624
 	/* Allow arbitrary relocation */
624
 	/* Allow arbitrary relocation */
625
-	xorl	%ebp, %ebp
625
+	orl	$0xffffffff, %ebp
626
 	/* Install text and data segments */
626
 	/* Install text and data segments */
627
 	call	install_prealloc
627
 	call	install_prealloc
628
 	/* Restore registers and return */
628
 	/* Restore registers and return */
642
  *   %bx  : .data16 segment address
642
  *   %bx  : .data16 segment address
643
  *   %esi : Image source physical address (or zero for %cs:0000)
643
  *   %esi : Image source physical address (or zero for %cs:0000)
644
  *   %edi : Decompression temporary area physical address (or zero for default)
644
  *   %edi : Decompression temporary area physical address (or zero for default)
645
- *   %ebp : Maximum end address for relocation (or zero for no maximum)
645
+ *   %ebp : Maximum end address for relocation
646
+ *          - 0xffffffff for no maximum
647
+ *          - 0x00000000 to inhibit use of INT 15,e820 and INT 15,e801
646
  * Corrupts:
648
  * Corrupts:
647
  *   none
649
  *   none
648
  ****************************************************************************
650
  ****************************************************************************
796
 	movw	%ax, (init_librm_vector+2)
798
 	movw	%ax, (init_librm_vector+2)
797
 	lcall	*init_librm_vector
799
 	lcall	*init_librm_vector
798
 
800
 
801
+	/* Inhibit INT 15,e820 and INT 15,e801 if applicable */
802
+	testl	%ebp, %ebp
803
+	jnz	1f
804
+	incb	memmap_post
805
+	decl	%ebp
806
+1:
807
+
799
 	/* Call relocate() to determine target address for relocation.
808
 	/* Call relocate() to determine target address for relocation.
800
 	 * relocate() will return with %esi, %edi and %ecx set up
809
 	 * relocate() will return with %esi, %edi and %ecx set up
801
 	 * ready for the copy to the new location.
810
 	 * ready for the copy to the new location.

+ 3
- 3
src/arch/i386/prefix/romprefix.S View File

445
 	 * picked up by the initial shell prompt, and we will drop
445
 	 * picked up by the initial shell prompt, and we will drop
446
 	 * into a shell.
446
 	 * into a shell.
447
 	 */
447
 	 */
448
-	movl	$0xa0000, %ebp	/* Inhibit relocation during POST */
448
+	xorl	%ebp, %ebp	/* Inhibit use of INT 15,e820 and INT 15,e801 */
449
 	pushw	%cs
449
 	pushw	%cs
450
 	call	exec
450
 	call	exec
451
 2:
451
 2:
630
  * Called by the PnP BIOS when it wants to boot us.
630
  * Called by the PnP BIOS when it wants to boot us.
631
  */
631
  */
632
 bev_entry:
632
 bev_entry:
633
-	xorl	%ebp, %ebp	/* Allow relocation */
633
+	orl	$0xffffffff, %ebp	/* Allow arbitrary relocation */
634
 	pushw	%cs
634
 	pushw	%cs
635
 	call	exec
635
 	call	exec
636
 	lret
636
 	lret
665
 	/* Leave keypress in buffer and start iPXE.  The keypress will
665
 	/* Leave keypress in buffer and start iPXE.  The keypress will
666
 	 * cause the usual initial Ctrl-B prompt to be skipped.
666
 	 * cause the usual initial Ctrl-B prompt to be skipped.
667
 	 */
667
 	 */
668
-	xorl	%ebp, %ebp	/* Allow relocation */
668
+	orl	$0xffffffff, %ebp	/* Allow arbitrary relocation */
669
 	pushw	%cs
669
 	pushw	%cs
670
 	call	exec
670
 	call	exec
671
 1:	/* Try to call original INT 19 vector */
671
 1:	/* Try to call original INT 19 vector */

+ 1
- 1
src/arch/i386/prefix/undiloader.S View File

31
 	movw	%es:14(%di), %ax
31
 	movw	%es:14(%di), %ax
32
 	movl	image_source, %esi
32
 	movl	image_source, %esi
33
 	movl	decompress_to, %edi
33
 	movl	decompress_to, %edi
34
-	xorl	%ebp, %ebp		/* Allow relocation */
34
+	orl	$0xffffffff, %ebp	/* Allow arbitrary relocation */
35
 	call	install_prealloc
35
 	call	install_prealloc
36
 	popw	%di
36
 	popw	%di
37
 	/* Call UNDI loader C code */
37
 	/* Call UNDI loader C code */

Loading…
Cancel
Save