From 1dda75c9cdca7105733bfc21e8b4b6d46df19113 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 29 Sep 2008 05:11:51 +0100 Subject: [pcbios] Allow for larger-than-20-byte buffers in e820mangler.S Although the E820 API allows for a caller to provide only a 20-byte buffer, there exists at least one combination (HP BIOS, 32-bit WinPE) that relies on information found only in the "extended attributes" field, which requires a 24-byte buffer. Allow for up to a 64-byte E820 buffer, in the hope of coping with future idiocies like this one. --- src/arch/i386/firmware/pcbios/e820mangler.S | 59 ++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/src/arch/i386/firmware/pcbios/e820mangler.S b/src/arch/i386/firmware/pcbios/e820mangler.S index 437efa77..4fbd6563 100644 --- a/src/arch/i386/firmware/pcbios/e820mangler.S +++ b/src/arch/i386/firmware/pcbios/e820mangler.S @@ -25,6 +25,26 @@ #define SMAP 0x534d4150 +/* Most documentation refers to the E820 buffer as being 20 bytes, and + * the API makes it perfectly legitimate to pass only a 20-byte buffer + * and expect to get valid data. However, some morons at ACPI decided + * to extend the data structure by adding an extra "extended + * attributes" field and by including critical information within this + * field, such as whether or not the region is enabled. A caller who + * passes in only a 20-byte buffer therefore risks getting very, very + * misleading information. + * + * I have personally witnessed an HP BIOS that returns a value of + * 0x0009 in the extended attributes field. If we don't pass this + * value through to the caller, 32-bit WinPE will die, usually with a + * PAGE_FAULT_IN_NONPAGED_AREA blue screen of death. + * + * Allow a ridiculously large maximum value (64 bytes) for the E820 + * buffer as a guard against insufficiently creative idiots in the + * future. + */ +#define E820MAXSIZE 64 + /**************************************************************************** * * Allowed memory windows @@ -204,19 +224,22 @@ get_underlying_e820: /* If the requested region is in the cache, return it */ cmpw %bx, underlying_e820_index - jne 1f + jne 2f pushw %di pushw %si movw $underlying_e820_cache, %si - movw $20, %cx + cmpl underlying_e820_cache_size, %ecx + jbe 1f + movl underlying_e820_cache_size, %ecx +1: pushl %ecx rep movsb + popl %ecx popw %si popw %di - movw $20, %cx incw %bx movl %edx, %eax ret -1: +2: /* If the requested region is earlier than the cached region, * invalidate the cache. */ @@ -250,23 +273,26 @@ get_underlying_e820: pushw %ds popw %es movw $underlying_e820_cache, %di - movl $20, %ecx - movl underlying_e820_ebx, %ebx + cmpl $E820MAXSIZE, %ecx + jbe 1f + movl $E820MAXSIZE, %ecx +1: movl underlying_e820_ebx, %ebx stc pushfw lcall *%cs:int15_vector popw %di popw %es /* Check for error return from underlying e820 call */ - jc 1f /* CF set: error */ + jc 2f /* CF set: error */ cmpl $SMAP, %eax - je 2f /* 'SMAP' missing: error */ -1: /* An error occurred: return values returned by underlying e820 call */ + je 3f /* 'SMAP' missing: error */ +2: /* An error occurred: return values returned by underlying e820 call */ stc /* Force CF set if SMAP was missing */ addr32 leal 16(%esp), %esp /* avoid changing other flags */ ret -2: /* No error occurred */ +3: /* No error occurred */ movl %ebx, underlying_e820_ebx + movl %ecx, underlying_e820_cache_size popl %edx popl %ecx popl %ebx @@ -290,9 +316,14 @@ underlying_e820_ebx: .section ".bss16" underlying_e820_cache: - .space 20 + .space E820MAXSIZE .size underlying_e820_cache, . - underlying_e820_cache + .section ".bss16" +underlying_e820_cache_size: + .long 0 + .size underlying_e820_cache_size, . - underlying_e820_cache_size + /**************************************************************************** * Get windowed e820 region, without empty region stripping * @@ -437,15 +468,15 @@ get_mangled_e820: /* Peek ahead to see if there are any further nonempty regions */ pushal pushw %es - subw $20, %sp + movw %sp, %bp + subw %cx, %sp movl $0xe820, %eax movl $SMAP, %edx - movl $20, %ecx pushw %ss popw %es movw %sp, %di call get_nonempty_e820 - addr32 leal 20(%esp), %esp /* avoid changing flags */ + movw %bp, %sp popw %es popal jnc 99f /* There are further nonempty regions */ -- cgit v1.2.3-55-g7522