]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[prefix] Use 16-bit protected mode for access to high memory
authorMichael Brown <mcb30@ipxe.org>
Wed, 26 Jan 2011 23:04:43 +0000 (23:04 +0000)
committerMichael Brown <mcb30@ipxe.org>
Wed, 26 Jan 2011 23:24:44 +0000 (23:24 +0000)
Flat real mode works perfectly on real hardware, but seems to cause
problems for some hypervisors.  Revert to using 16-bit protected mode
(and returning to real mode with 4GB limits, so as not to break PMM
BIOSes).

Allow the code specific to the .mrom format to continue to assume that
flat real mode works, since this format is specific to real hardware.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/i386/prefix/libprefix.S
src/arch/i386/prefix/mromprefix.S

index 340e74be23a026aa6c0312f807601b51f74e61ea..c8fbe95bead7b6440f373c092f25e49860d1ec84 100644 (file)
@@ -24,6 +24,9 @@ FILE_LICENCE ( GPL2_OR_LATER )
 /* Image compression enabled */
 #define COMPRESS 1
 
+/* Protected mode flag */
+#define CR0_PE 1
+
 /*****************************************************************************
  * Utility function: print character (with LF -> LF,CR translation)
  *
@@ -229,41 +232,153 @@ print_kill_line:
  *   None
  ****************************************************************************
  */
-#if ! COMPRESS
        .section ".prefix.lib", "awx", @progbits
        .code16
 copy_bytes:
-       pushl %ecx
+       pushl   %ecx
        rep addr32 movsb
-       popl %ecx
+       popl    %ecx
        ret
-       .size copy_bytes, . - copy_bytes
-#endif /* COMPRESS */
+       .size   copy_bytes, . - copy_bytes
 
 /****************************************************************************
- * install_block
+ * zero_bytes
  *
- * Install block to specified address
+ * Zero bytes
  *
  * Parameters:
- *   %esi : source physical address (must be a multiple of 16)
- *   %edi : destination physical address (must be a multiple of 16)
- *   %ecx : length of (decompressed) data
- *   %edx : total length of block (including any uninitialised data portion)
+ *   %ds:esi : source address
+ *   %es:edi : destination address
+ *   %ecx : length
  * Returns:
- *   %esi : next source physical address (will be a multiple of 16)
- *   %edi : next destination physical address (will be a multiple of 16)
+ *   %ds:esi : next source address
+ *   %es:edi : next destination address
  * Corrupts:
- *   none
+ *   None
  ****************************************************************************
  */
        .section ".prefix.lib", "awx", @progbits
        .code16
-install_block:
+zero_bytes:
+       pushl   %ecx
+       pushw   %ax
+       xorw    %ax, %ax
+       rep addr32 stosb
+       popw    %ax
+       popl    %ecx
+       ret
+       .size   zero_bytes, . - zero_bytes
+
+/****************************************************************************
+ * process_bytes
+ *
+ * Call memcpy()-like function
+ *
+ * Parameters:
+ *   %esi : source physical address
+ *   %edi : destination physical address
+ *   %ecx : length
+ *   %bx : memcpy()-like function to call, passing parameters:
+ *          %ds:esi : source address
+ *          %es:edi : destination address
+ *          %ecx : length
+ *         and returning:
+ *          %ds:esi : next source address
+ *          %es:edi : next destination address
+ * Returns:
+ *   %esi : next source physical address
+ *   %edi : next destination physical address
+ * Corrupts:
+ *   None
+ ****************************************************************************
+ */
+       .section ".prefix.lib", "awx", @progbits
+       .code16
+process_bytes:
+
+#ifndef KEEP_IT_REAL
+
        /* Preserve registers */
+       pushfw
+       pushl   %eax
+       pushl   %ebp
+
+       /* Construct GDT on stack (since .prefix may not be writable) */
+       .equ    PM_DS, 0x18     /* Flat data segment */
+       pushl   $0x008f9300
+       pushl   $0x0000ffff
+       .equ    PM_SS, 0x10     /* Stack segment based at %ss:0000 */
+       pushl   $0x008f0930
+       pushw   %ss
+       pushw   $0xffff
+       .equ    PM_CS, 0x08     /* Code segment based at %cs:0000 */
+       pushl   $0x008f09b0
+       pushw   %cs
+       pushw   $0xffff
+       pushl   $0              /* Base and length */
+       pushw   %ss
+       pushw   $0x1f
+       movzwl  %sp, %ebp
+       shll    $4, 0x02(%bp)
+       addl    %ebp, 0x02(%bp)
+       shll    $4, 0x0a(%bp)
+       shll    $4, 0x12(%bp)
+       subw    $8, %sp
+       sgdt    -8(%bp)
+
+       /* Switch to protected mode */
+       pushw   %gs
+       pushw   %fs
+       pushw   %es
+       pushw   %ds
+       pushw   %ss
+       pushw   %cs
+       pushw   $2f
+       cli
+       data32 lgdt (%bp)
+       movl    %cr0, %eax
+       orb     $CR0_PE, %al
+       movl    %eax, %cr0
+       ljmp    $PM_CS, $1f
+1:     movw    $PM_SS, %ax
+       movw    %ax, %ss
+       movw    $PM_DS, %ax
+       movw    %ax, %ds
+       movw    %ax, %es
+       movw    %ax, %fs
+       movw    %ax, %gs
+
+       /* Call memcpy()-like function */
+       call    *%bx
+
+       /* Return to (flat) real mode */
+       movl    %cr0, %eax
+       andb    $0!CR0_PE, %al
+       movl    %eax, %cr0
+       lret
+2:     /* lret will ljmp to here */
+       popw    %ss
+       popw    %ds
+       popw    %es
+       popw    %fs
+       popw    %gs
+
+       /* Restore GDT */
+       data32 lgdt -8(%bp)
+       addw    $( 8 /* saved GDT */ + ( PM_DS + 8 ) /* GDT on stack */ ), %sp
+
+       /* Restore registers and return */
+       popl    %ebp
+       popl    %eax
+       popfw
+       ret
+
+#else /* KEEP_IT_REAL */
+
+       /* Preserve registers */
+       pushl   %eax
        pushw   %ds
        pushw   %es
-       pushl   %ecx
        
        /* Convert %esi and %edi to %ds:esi and %es:edi */
        shrl    $4, %esi
@@ -275,21 +390,66 @@ install_block:
        xorw    %di, %di
        shll    $4, %edi
 
+       /* Call memcpy()-like function */
+       call    *%bx
+
+       /* Convert %ds:esi and %es:edi back to physical addresses */
+       xorl    %eax, %eax
+       movw    %ds, %cx
+       shll    $4, %eax
+       addl    %eax, %esi
+       xorl    %eax, %eax
+       movw    %es, %cx
+       shll    $4, %eax
+       addl    %eax, %edi
+
+       /* Restore registers and return */
+       popw    %es
+       popw    %ds
+       popl    %eax
+       ret
+
+#endif /* KEEP_IT_REAL */
+
+       .size   process_bytes, . - process_bytes
+
+/****************************************************************************
+ * install_block
+ *
+ * Install block to specified address
+ *
+ * Parameters:
+ *   %esi : source physical address (must be a multiple of 16)
+ *   %edi : destination physical address (must be a multiple of 16)
+ *   %ecx : length of (decompressed) data
+ *   %edx : total length of block (including any uninitialised data portion)
+ * Returns:
+ *   %esi : next source physical address (will be a multiple of 16)
+ *   %edi : next destination physical address (will be a multiple of 16)
+ * Corrupts:
+ *   none
+ ****************************************************************************
+ */
+       .section ".prefix.lib", "awx", @progbits
+       .code16
+install_block:
+       /* Preserve registers */
+       pushl   %ecx
+       pushw   %bx
+
+       /* Decompress (or copy) source to destination */
 #if COMPRESS
-       /* Decompress source to destination */
-       call    decompress16
+       movw    $decompress16, %bx
 #else
-       /* Copy source to destination */
-       call    copy_bytes
+       movw    $copy_bytes, %bx
 #endif
+       call    process_bytes
 
        /* Zero .bss portion */
        negl    %ecx
        addl    %edx, %ecx
-       pushw   %ax
-       xorw    %ax, %ax
-       rep addr32 stosb
-       popw    %ax
+       movw    $zero_bytes, %bx
+       call    process_bytes
 
        /* Round up %esi and %edi to start of next blocks */
        addl    $0xf, %esi
@@ -297,20 +457,9 @@ install_block:
        addl    $0xf, %edi
        andl    $~0xf, %edi
 
-       /* Convert %ds:esi and %es:edi back to physical addresses */
-       xorl    %ecx, %ecx
-       movw    %ds, %cx
-       shll    $4, %ecx
-       addl    %ecx, %esi
-       xorl    %ecx, %ecx
-       movw    %es, %cx
-       shll    $4, %ecx
-       addl    %ecx, %edi
-
        /* Restore registers and return */
+       popw    %bx
        popl    %ecx
-       popw    %es
-       popw    %ds
        ret
        .size install_block, . - install_block
 
@@ -612,11 +761,10 @@ payload_death_message:
 
        /* Copy code to new location */
        pushl   %edi
-       pushw   %ax
-       xorw    %ax, %ax
-       movw    %ax, %es
-       es rep addr32 movsb
-       popw    %ax
+       pushw   %bx
+       movw    $copy_bytes, %bx
+       call    process_bytes
+       popw    %bx
        popl    %edi
 
        /* Initialise librm at new location */
index 989cea1efa9026367dd23eb9be04760d8958aad6..3e177d001fa7cedd193d98a321cdd001c4010058 100644 (file)
@@ -151,7 +151,12 @@ find_mem_bar:
        /* Copy payload to buffer, or set buffer address to BAR address */
        testl   %esi, %esi
        jz      1f
-       /* We have a buffer; copy payload to it */
+       /* We have a buffer; copy payload to it.  Since .mrom is
+        * designed specifically for real hardware, we assume that
+        * flat real mode is working properly.  (In the unlikely event
+        * that this code is run inside a hypervisor that doesn't
+        * properly support flat real mode, it will die horribly.)
+        */
        pushl   %esi
        pushw   %es
        movl    %esi, %edi