summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2014-05-02 14:18:55 +0200
committerMichael Brown2014-05-02 16:23:21 +0200
commitc64747db5040d860c9c77f2673c4cce287249bbd (patch)
tree1c9ddbd0516a5240916bcd79eae9ca4652c13ffa
parent[librm] Speed up protected-to-real mode transition under KVM (diff)
downloadipxe-c64747db5040d860c9c77f2673c4cce287249bbd.tar.gz
ipxe-c64747db5040d860c9c77f2673c4cce287249bbd.tar.xz
ipxe-c64747db5040d860c9c77f2673c4cce287249bbd.zip
[librm] Speed up real-to-protected mode transition under KVM
Ensure that all segment registers have zero in the low two bits before transitioning to protected mode. This allows the CPU state to immediately be deemed to be "valid", and eliminates the need for any further emulated instructions. Load the protected-mode interrupt descriptor table after switching to protected mode, since this avoids triggering an EXCEPTION_NMI and corresponding VM exit. This reduces the time taken by real_to_prot under KVM by around 50%. Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/arch/i386/prefix/libprefix.S5
-rw-r--r--src/arch/i386/transitions/librm.S19
-rw-r--r--src/arch/i386/transitions/librm_mgmt.c3
3 files changed, 22 insertions, 5 deletions
diff --git a/src/arch/i386/prefix/libprefix.S b/src/arch/i386/prefix/libprefix.S
index 197a86bc8..3aee415f5 100644
--- a/src/arch/i386/prefix/libprefix.S
+++ b/src/arch/i386/prefix/libprefix.S
@@ -522,8 +522,11 @@ alloc_basemem:
subw $_data16_memsz_pgh, %ax
pushw %ax
- /* Calculate .text16 segment address */
+ /* Calculate .text16 segment address. Round down to ensure
+ * low bits are zero, to speed up mode transitions under KVM.
+ */
subw $_text16_memsz_pgh, %ax
+ andb $~0x03, %al
pushw %ax
/* Update FBMS */
diff --git a/src/arch/i386/transitions/librm.S b/src/arch/i386/transitions/librm.S
index 0d8110ac1..eaf520b3e 100644
--- a/src/arch/i386/transitions/librm.S
+++ b/src/arch/i386/transitions/librm.S
@@ -200,10 +200,22 @@ real_to_prot:
addr32 leal (%eax,%edx), %esi
subl rm_virt_offset, %esi
+ /* Load protected-mode global descriptor table */
+ data32 lgdt gdtr
+
+ /* Zero segment registers. This wastes around 12 cycles on
+ * real hardware, but saves a substantial number of emulated
+ * instructions under KVM.
+ */
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+
/* Switch to protected mode */
cli
- data32 lgdt gdtr
- data32 lidt idtr
movl %cr0, %eax
orb $CR0_PE, %al
movl %eax, %cr0
@@ -220,6 +232,9 @@ r2p_pmode:
movw %ax, %ss
movl pm_esp, %esp
+ /* Load protected-mode interrupt descriptor table */
+ lidt idtr
+
/* Record real-mode %ss:sp (after removal of data) */
movw %bp, rm_ss
addl %ecx, %edx
diff --git a/src/arch/i386/transitions/librm_mgmt.c b/src/arch/i386/transitions/librm_mgmt.c
index dee143572..f90d49b02 100644
--- a/src/arch/i386/transitions/librm_mgmt.c
+++ b/src/arch/i386/transitions/librm_mgmt.c
@@ -26,10 +26,9 @@ static struct interrupt_vector intr_vec[ IRQ_MAX + 1 ];
struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) ));
/** The interrupt descriptor table register */
-struct idtr __data16 ( idtr ) = {
+struct idtr idtr = {
.limit = ( sizeof ( idt ) - 1 ),
};
-#define idtr __use_data16 ( idtr )
/**
* Allocate space on the real-mode stack and copy data there from a