Browse Source

[librm] Speed up protected-to-real mode transition under KVM

On an Intel CPU supporting VMX, KVM will emulate instructions while
the CPU state remains "invalid".  In real mode, the CPU state is
defined to be "invalid" if any segment register has a base which is
not equal to (sreg<<4) or a limit which is not equal to 64kB.

We don't actually use the base stored in the REAL_DS descriptor for
any significant purpose.  Change the base stored in this descriptor to
be equal to (REAL_DS<<4).  A segment register loaded with REAL_DS is
then automatically valid in both real and protected modes.  This
allows KVM to stop emulating instructions much sooner.

The only use of REAL_DS for memory accesses currently occurs in the
indirect ljmp within prot_to_real.  Change this to a direct ljmp,
storing rm_cs in .text16 as part of the ljmp instruction.  This
removes the only memory access via REAL_DS (thereby allowing for the
above descriptor base address hack), and also simplifies the ljmp
instruction (which will still have to be emulated).

Load the real-mode interrupt descriptor table register before
switching to real mode, since this avoids triggering an EXCEPTION_NMI
and corresponding VM exit.

This reduces the time taken by prot_to_real under KVM by around 65%.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
5a08b63cb7
2 changed files with 20 additions and 22 deletions
  1. 2
    2
      src/arch/i386/include/librm.h
  2. 18
    20
      src/arch/i386/transitions/librm.S

+ 2
- 2
src/arch/i386/include/librm.h View File

165
 /* Variables in librm.S, present in the normal data segment */
165
 /* Variables in librm.S, present in the normal data segment */
166
 extern uint16_t rm_sp;
166
 extern uint16_t rm_sp;
167
 extern uint16_t rm_ss;
167
 extern uint16_t rm_ss;
168
-extern uint16_t __data16 ( rm_cs );
169
-#define rm_cs __use_data16 ( rm_cs )
168
+extern uint16_t __text16 ( rm_cs );
169
+#define rm_cs __use_text16 ( rm_cs )
170
 extern uint16_t __text16 ( rm_ds );
170
 extern uint16_t __text16 ( rm_ds );
171
 #define rm_ds __use_text16 ( rm_ds )
171
 #define rm_ds __use_text16 ( rm_ds )
172
 
172
 

+ 18
- 20
src/arch/i386/transitions/librm.S View File

72
 
72
 
73
 	.org	gdt + REAL_DS	
73
 	.org	gdt + REAL_DS	
74
 real_ds:	/* 16 bit real mode data segment */
74
 real_ds:	/* 16 bit real mode data segment */
75
-	.word	0xffff, 0
75
+	.word	0xffff, ( REAL_DS << 4 )
76
 	.byte	0, 0x93, 0x00, 0
76
 	.byte	0, 0x93, 0x00, 0
77
 
77
 
78
 gdt_end:
78
 gdt_end:
111
 	/* Store rm_cs and text16, set up real_cs segment */
111
 	/* Store rm_cs and text16, set up real_cs segment */
112
 	xorl	%eax, %eax
112
 	xorl	%eax, %eax
113
 	movw	%cs, %ax
113
 	movw	%cs, %ax
114
-	movw	%ax, rm_cs
114
+	movw	%ax, %cs:rm_cs
115
 	shll	$4, %eax
115
 	shll	$4, %eax
116
 	movw	$real_cs, %bx
116
 	movw	$real_cs, %bx
117
 	call	set_seg_base
117
 	call	set_seg_base
118
 	addr32 leal	(%eax, %edi), %ebx
118
 	addr32 leal	(%eax, %edi), %ebx
119
 	movl	%ebx, rm_text16
119
 	movl	%ebx, rm_text16
120
 
120
 
121
-	/* Store rm_ds and data16, set up real_ds segment */
121
+	/* Store rm_ds and data16 */
122
 	xorl	%eax, %eax
122
 	xorl	%eax, %eax
123
 	movw	%ds, %ax
123
 	movw	%ds, %ax
124
 	movw	%ax, %cs:rm_ds
124
 	movw	%ax, %cs:rm_ds
125
 	shll	$4, %eax
125
 	shll	$4, %eax
126
-	movw	$real_ds, %bx
127
-	call	set_seg_base
128
 	addr32 leal	(%eax, %edi), %ebx
126
 	addr32 leal	(%eax, %edi), %ebx
129
 	movl	%ebx, rm_data16
127
 	movl	%ebx, rm_data16
130
 
128
 
241
 	ret
239
 	ret
242
 
240
 
243
 	/* Default real-mode interrupt descriptor table */
241
 	/* Default real-mode interrupt descriptor table */
244
-	.section ".data16", "aw", @progbits
242
+	.section ".data", "aw", @progbits
245
 rm_idtr:
243
 rm_idtr:
246
 	.word 0xffff /* limit */
244
 	.word 0xffff /* limit */
247
 	.long 0 /* base */
245
 	.long 0 /* base */
287
 	/* Record protected-mode %esp (after removal of data) */
285
 	/* Record protected-mode %esp (after removal of data) */
288
 	movl	%esi, pm_esp
286
 	movl	%esi, pm_esp
289
 
287
 
288
+	/* Reset IDTR to the real-mode defaults */
289
+	lidt	rm_idtr
290
+
290
 	/* Load real-mode segment limits */
291
 	/* Load real-mode segment limits */
291
 	movw	$REAL_DS, %ax
292
 	movw	$REAL_DS, %ax
292
 	movw	%ax, %ds
293
 	movw	%ax, %ds
302
 	movl	%cr0, %eax
303
 	movl	%cr0, %eax
303
 	andb	$0!CR0_PE, %al
304
 	andb	$0!CR0_PE, %al
304
 	movl	%eax, %cr0
305
 	movl	%eax, %cr0
305
-	ljmp	*p2r_jump_vector
306
-p2r_jump_target:
307
-
306
+p2r_ljmp_rm_cs:
307
+	ljmp	$0, $1f
308
+1:
308
 	/* Set up real-mode data segments and stack pointer */
309
 	/* Set up real-mode data segments and stack pointer */
309
 	movw	%cs:rm_ds, %ax
310
 	movw	%cs:rm_ds, %ax
310
 	movw	%ax, %ds
311
 	movw	%ax, %ds
314
 	movw	%bp, %ss
315
 	movw	%bp, %ss
315
 	movl	%edx, %esp
316
 	movl	%edx, %esp
316
 
317
 
317
-	/* Reset IDTR to the real-mode defaults */
318
-	data32 lidt rm_idtr
319
-
320
 	/* Return to real-mode address */
318
 	/* Return to real-mode address */
321
 	data32 ret
319
 	data32 ret
322
 
320
 
323
 
321
 
324
 	/* Real-mode code and data segments.  Assigned by the call to
322
 	/* Real-mode code and data segments.  Assigned by the call to
325
 	 * init_librm.  rm_cs doubles as the segment part of the jump
323
 	 * init_librm.  rm_cs doubles as the segment part of the jump
326
-	 * vector used by prot_to_real.  rm_ds is located in .text16
327
-	 * rather than .data16 because code needs to be able to locate
328
-	 * the data segment.
324
+	 * instruction used by prot_to_real.  Both are located in
325
+	 * .text16 rather than .data16: rm_cs since it forms part of
326
+	 * the jump instruction within the code segment, and rm_ds
327
+	 * since real-mode code needs to be able to locate the data
328
+	 * segment with no other reference available.
329
 	 */
329
 	 */
330
-	.section ".data16", "aw", @progbits
331
-p2r_jump_vector:
332
-	.word	p2r_jump_target
333
 	.globl rm_cs
330
 	.globl rm_cs
334
-rm_cs:	.word 0
335
-	.globl rm_ds
331
+	.equ	rm_cs, ( p2r_ljmp_rm_cs + 3 )
332
+
336
 	.section ".text16.data", "aw", @progbits
333
 	.section ".text16.data", "aw", @progbits
334
+	.globl rm_ds
337
 rm_ds:	.word 0
335
 rm_ds:	.word 0
338
 
336
 
339
 /****************************************************************************
337
 /****************************************************************************

Loading…
Cancel
Save