summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2008-11-11 21:00:13 +0100
committerMichael Brown2008-11-11 21:00:13 +0100
commit2ca2607b1b29d7c567df7aeb5b769e85ec176fc7 (patch)
treec9ee1c9d4d97f0709d28a8f0c8555db21f19186d
parent[linda] Add support for QLogic 7220-based Infiniband HCAs (diff)
downloadipxe-2ca2607b1b29d7c567df7aeb5b769e85ec176fc7.tar.gz
ipxe-2ca2607b1b29d7c567df7aeb5b769e85ec176fc7.tar.xz
ipxe-2ca2607b1b29d7c567df7aeb5b769e85ec176fc7.zip
[romprefix] Use smaller PMM allocations if possible
The only way that PMM allows us to request a block in a region with A20=0 is to ask for a block with an alignment of 2MB. Due to the PMM API design, the only way we can do this is to ask for a block with a size of 2MB. Unfortunately, some BIOSes will hit problems if we allocate a 2MB block. In particular, it may not be possible to enter the BIOS setup screen; the BIOS setup code attempts a PMM allocation, fails, and hangs the machine. We now try allocating only as much as we need via PMM. If the allocated block has A20=1, we free the allocated block, double the allocation size, and try again. Repeat until either we obtain a block with A20=0 or allocation fails. (This is guaranteed to terminate by the time we reach an allocation size of 2MB.)
-rw-r--r--src/arch/i386/prefix/romprefix.S48
1 files changed, 41 insertions, 7 deletions
diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S
index aa081ef0..7b545f4b 100644
--- a/src/arch/i386/prefix/romprefix.S
+++ b/src/arch/i386/prefix/romprefix.S
@@ -14,6 +14,7 @@
#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
#define PNP_GET_BBS_VERSION 0x60
#define PMM_ALLOCATE 0x0000
+#define PMM_DEALLOCATE 0x0002
/* ROM banner timeout. Based on the configurable BANNER_TIMEOUT in
* config.h, but converted to a number of (18Hz) timer ticks, and
@@ -290,21 +291,52 @@ pmm_scan:
movw $init_message_pmm, %si
xorw %di, %di
call print_message
- /* Try to allocate 2MB block via PMM */
+ /* We have PMM and so a 1kB stack: preserve upper register halves */
+ pushal
+ /* Calculate required allocation size in %esi */
+ movzbl romheader_size, %eax
+ shll $9, %eax
+ addl $_textdata_memsz, %eax
+ orw $0xffff, %ax /* Ensure allocation size is at least 64kB */
+ bsrl %eax, %ecx
+ subw $15, %cx /* Round up and convert to 64kB count */
+ movw $1, %si
+ shlw %cl, %si
+pmm_loop:
+ /* Try to allocate block via PMM */
pushw $0x0006 /* Aligned, extended memory */
pushl $0xffffffff /* No handle */
- pushl $( 0x00200000 / 16 ) /* 2MB in paragraphs */
+ movzwl %si, %eax
+ shll $12, %eax
+ pushl %eax /* Allocation size in paragraphs */
pushw $PMM_ALLOCATE
lcall *%es:7
addw $12, %sp
+ /* Abort if allocation fails */
+ testw %dx, %dx /* %ax==0 even on success, since align>=64kB */
+ jz pmm_fail
+ /* If block has A20==1, free block and try again with twice
+ * the allocation size (and hence alignment).
+ */
+ testw $0x0010, %dx
+ jz got_pmm
+ pushw %dx
+ pushw $0
+ pushw $PMM_DEALLOCATE
+ lcall *%es:7
+ addw $6, %sp
+ addw %si, %si
+ jmp pmm_loop
+got_pmm: /* PMM allocation succeeded */
+ movw %dx, ( image_source + 2 )
movw %dx, %ax
xorw %di, %di
call print_hex_word
- movw %dx, ( image_source + 2 )
- testw %dx, %dx /* %ax==0 even on success, since align=2MB */
- jz no_pmm
- /* PMM allocation succeeded: copy ROM to PMM block */
- pushal /* PMM presence implies 1kB stack */
+ movb $'@', %al
+ call print_character
+ movw %si, %ax
+ call print_hex_byte
+ /* Copy ROM to PMM block */
xorw %ax, %ax
movw %ax, %es
movl image_source, %edi
@@ -323,6 +355,8 @@ pmm_scan:
addb %al, %bl
loop 1b
subb %bl, checksum
+pmm_fail:
+ /* Restore upper register halves */
popal
no_pmm: