Просмотр исходного кода

[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 лет назад
Родитель
Сommit
2629b7e2cd

+ 5
- 3
src/arch/i386/core/relocate.c Просмотреть файл

@@ -33,8 +33,10 @@ extern char _etextdata[];
33 33
 /**
34 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 41
  * This finds a suitable location for iPXE near the top of 32-bit
40 42
  * address space, and returns the physical address of the new location
@@ -59,7 +61,7 @@ __asmcall void relocate ( struct i386_all_regs *ix86 ) {
59 61
 
60 62
 	/* Determine maximum usable address */
61 63
 	max = MAX_ADDR;
62
-	if ( ix86->regs.ebp && ( ix86->regs.ebp < max ) ) {
64
+	if ( ix86->regs.ebp < max ) {
63 65
 		max = ix86->regs.ebp;
64 66
 		DBG ( "Limiting relocation to [0,%lx)\n", max );
65 67
 	}

+ 16
- 0
src/arch/i386/firmware/pcbios/memmap.c Просмотреть файл

@@ -63,6 +63,10 @@ struct e820_entry {
63 63
 static struct e820_entry __bss16 ( e820buf );
64 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 71
  * Get size of extended memory via INT 15,e801
68 72
  *
@@ -74,6 +78,12 @@ static unsigned int extmemsize_e801 ( void ) {
74 78
 	unsigned int flags;
75 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 87
 	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
78 88
 					   "int $0x15\n\t"
79 89
 					   "pushfw\n\t"
@@ -164,6 +174,12 @@ static int meme820 ( struct memory_map *memmap ) {
164 174
 	unsigned int flags;
165 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 183
 	/* Clear the E820 buffer.  Do this once before starting,
168 184
 	 * rather than on each call; some BIOSes rely on the contents
169 185
 	 * being preserved between calls.

+ 1
- 1
src/arch/i386/prefix/exeprefix.S Просмотреть файл

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

+ 11
- 2
src/arch/i386/prefix/libprefix.S Просмотреть файл

@@ -622,7 +622,7 @@ install:
622 622
 	/* Image destination = default */
623 623
 	xorl	%edi, %edi
624 624
 	/* Allow arbitrary relocation */
625
-	xorl	%ebp, %ebp
625
+	orl	$0xffffffff, %ebp
626 626
 	/* Install text and data segments */
627 627
 	call	install_prealloc
628 628
 	/* Restore registers and return */
@@ -642,7 +642,9 @@ install:
642 642
  *   %bx  : .data16 segment address
643 643
  *   %esi : Image source physical address (or zero for %cs:0000)
644 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 648
  * Corrupts:
647 649
  *   none
648 650
  ****************************************************************************
@@ -796,6 +798,13 @@ payload_death_message:
796 798
 	movw	%ax, (init_librm_vector+2)
797 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 808
 	/* Call relocate() to determine target address for relocation.
800 809
 	 * relocate() will return with %esi, %edi and %ecx set up
801 810
 	 * ready for the copy to the new location.

+ 3
- 3
src/arch/i386/prefix/romprefix.S Просмотреть файл

@@ -445,7 +445,7 @@ no_pmm:
445 445
 	 * picked up by the initial shell prompt, and we will drop
446 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 449
 	pushw	%cs
450 450
 	call	exec
451 451
 2:
@@ -630,7 +630,7 @@ decompress_to:
630 630
  * Called by the PnP BIOS when it wants to boot us.
631 631
  */
632 632
 bev_entry:
633
-	xorl	%ebp, %ebp	/* Allow relocation */
633
+	orl	$0xffffffff, %ebp	/* Allow arbitrary relocation */
634 634
 	pushw	%cs
635 635
 	call	exec
636 636
 	lret
@@ -665,7 +665,7 @@ int19_entry:
665 665
 	/* Leave keypress in buffer and start iPXE.  The keypress will
666 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 669
 	pushw	%cs
670 670
 	call	exec
671 671
 1:	/* Try to call original INT 19 vector */

+ 1
- 1
src/arch/i386/prefix/undiloader.S Просмотреть файл

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

Загрузка…
Отмена
Сохранить