]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[librm] Use genuine real mode to accelerate operation in virtual machines
authorMichael Brown <mcb30@ipxe.org>
Mon, 28 Apr 2014 00:21:08 +0000 (01:21 +0100)
committerMichael Brown <mcb30@ipxe.org>
Mon, 28 Apr 2014 00:21:08 +0000 (01:21 +0100)
We currently use flat real mode wherever real mode is required.  This
guarantees that we will not surprise some unsuspecting external caller
which has carefully set up flat real mode by suddenly reducing the
segment limits to 64kB.

However, operating in flat real mode imposes a severe performance
penalty in some virtualisation environments, since some CPUs cannot
fully virtualise flat real mode and so the hypervisor must fall back
to emulation.  In particular, operating under KVM on a pre-Westmere
Intel CPU will be at least an order of magnitude slower, to the point
that there is a visible teletype effect when printing anything to the
BIOS console.  (Older versions of KVM used to cheat and ignore the
"flat" part of flat real mode, which masked the problem.)

Switch (back) to using genuine real mode with 64kB segment limits
instead of flat real mode.  Hopefully this won't break anything.

Add an explicit switch to flat real mode before returning to the BIOS
from the ROM prefix, since we know that a PMM BIOS will call the ROM
initialisation point (and potentially the BEV) in flat real mode.

As noted in previous commit messages, it is not possible to restore
the real-mode segment limits after a transition to protected mode,
since there is no way to know which protected-mode segment descriptor
was originally used to initialise the limit portion of the segment
register.

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

index 69f35f78c5ae4bfb241fdb19a426ae789898f2bc..ae18f05d038eb2b62fabfef0c16d335599b8d39c 100644 (file)
@@ -754,6 +754,9 @@ exec:       /* Set %ds = %cs */
        call    prot_call
        popl    %eax /* discard */
 
+       /* Set up flat real mode for return to BIOS */
+       call    flatten_real_mode
+
        /* Uninstall iPXE */
        call    uninstall
 
index 02d25b22c0c2e23e2fa1541a12fde11d9e0bdc40..b5affdb89f2d02e9627a237a83c15cf1784d1cd2 100644 (file)
@@ -66,15 +66,15 @@ physical_ds:        /* 32 bit protected mode data segment, physical addresses */
        .byte   0, 0x93, 0xcf, 0        
 
        .org    gdt + REAL_CS, 0
-real_cs:       /* 16 bit flat real mode code segment */
+real_cs:       /* 16 bit real mode code segment */
        .word   0xffff, 0
-       .byte   0, 0x9b, 0x8f, 0
+       .byte   0, 0x9b, 0x00, 0
 
        .org    gdt + REAL_DS   
-real_ds:       /* 16 bit flat real mode data segment */
+real_ds:       /* 16 bit real mode data segment */
        .word   0xffff, 0
-       .byte   0, 0x93, 0x8f, 0
-       
+       .byte   0, 0x93, 0x00, 0
+
 gdt_end:
        .equ    gdt_length, gdt_end - gdt
 
@@ -506,6 +506,36 @@ real_call:
        .section ".data16", "aw", @progbits
 rc_function:   .word 0, 0
 
+/****************************************************************************
+ * flatten_real_mode (real-mode near call)
+ *
+ * Switch to flat real mode
+ *
+ ****************************************************************************
+ */
+       .section ".text16", "ax", @progbits
+       .code16
+       .globl flatten_real_mode
+flatten_real_mode:
+       /* Modify GDT to use flat real mode */
+       movb    $0x8f, real_cs + 6
+       movb    $0x8f, real_ds + 6
+       /* Call dummy protected-mode function */
+       pushl   $flatten_dummy
+       pushw   %cs
+       call    prot_call
+       addw    $4, %sp
+       /* Restore GDT */
+       movb    $0x00, real_cs + 6
+       movb    $0x00, real_ds + 6
+       /* Return */
+       ret
+
+       .section ".text", "ax", @progbits
+       .code32
+flatten_dummy:
+       ret
+
 /****************************************************************************
  * Stored real-mode and protected-mode stack pointers
  *