summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/transitions/librm.S
diff options
context:
space:
mode:
authorMichael Brown2014-04-28 02:21:08 +0200
committerMichael Brown2014-04-28 02:21:08 +0200
commit6d4deeeb6c652975917545f624e9816128d931b0 (patch)
tree1f50ebc7005516be350c0b60284084a6edbfab08 /src/arch/i386/transitions/librm.S
parent[intel] Push new RX descriptors in batches (diff)
downloadipxe-6d4deeeb6c652975917545f624e9816128d931b0.tar.gz
ipxe-6d4deeeb6c652975917545f624e9816128d931b0.tar.xz
ipxe-6d4deeeb6c652975917545f624e9816128d931b0.zip
[librm] Use genuine real mode to accelerate operation in virtual machines
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>
Diffstat (limited to 'src/arch/i386/transitions/librm.S')
-rw-r--r--src/arch/i386/transitions/librm.S40
1 files changed, 35 insertions, 5 deletions
diff --git a/src/arch/i386/transitions/librm.S b/src/arch/i386/transitions/librm.S
index 02d25b22..b5affdb8 100644
--- a/src/arch/i386/transitions/librm.S
+++ b/src/arch/i386/transitions/librm.S
@@ -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
@@ -507,6 +507,36 @@ real_call:
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
*
* The real-mode stack pointer is stored here whenever real_to_prot