Kaynağa Gözat

[librm] Speed up protected-mode calls under KVM

When making a call from real mode to protected mode, we save and
restore the global and interrupt descriptor table registers.  The
restore currently takes place after returning to real mode, which
generates two EXCEPTION_NMIs and corresponding VM exits when running
under KVM on an Intel CPU.

Avoid the VM exits by restoring the descriptor table registers inside
prot_to_real, while still running in protected mode.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 yıl önce
ebeveyn
işleme
bcfaf119a7
1 değiştirilmiş dosya ile 35 ekleme ve 19 silme
  1. 35
    19
      src/arch/i386/transitions/librm.S

+ 35
- 19
src/arch/i386/transitions/librm.S Dosyayı Görüntüle

@@ -253,12 +253,6 @@ r2p_pmode:
253 253
 	/* Return to virtual address */
254 254
 	ret
255 255
 
256
-	/* Default real-mode interrupt descriptor table */
257
-	.section ".data", "aw", @progbits
258
-rm_idtr:
259
-	.word 0xffff /* limit */
260
-	.long 0 /* base */
261
-
262 256
 /****************************************************************************
263 257
  * prot_to_real (protected-mode near call, 32-bit real-mode return address)
264 258
  *
@@ -275,12 +269,22 @@ rm_idtr:
275 269
  *
276 270
  * Parameters: 
277 271
  *   %ecx : number of bytes to move from PM stack to RM stack
272
+ *   %esi : real-mode global and interrupt descriptor table registers
278 273
  *
279 274
  ****************************************************************************
280 275
  */
281 276
 	.section ".text", "ax", @progbits
282 277
 	.code32
283 278
 prot_to_real:
279
+	/* Copy real-mode global descriptor table register to RM code segment */
280
+	movl	text16, %edi
281
+	leal	rm_gdtr(%edi), %edi
282
+	movsw
283
+	movsl
284
+
285
+	/* Load real-mode interrupt descriptor table register */
286
+	lidt	(%esi)
287
+
284 288
 	/* Add return address to data to be moved to RM stack */
285 289
 	addl	$4, %ecx
286 290
 	
@@ -300,9 +304,6 @@ prot_to_real:
300 304
 	/* Record protected-mode %esp (after removal of data) */
301 305
 	movl	%esi, pm_esp
302 306
 
303
-	/* Reset IDTR to the real-mode defaults */
304
-	lidt	rm_idtr
305
-
306 307
 	/* Load real-mode segment limits */
307 308
 	movw	$REAL_DS, %ax
308 309
 	movw	%ax, %ds
@@ -314,6 +315,8 @@ prot_to_real:
314 315
 	.section ".text16", "ax", @progbits
315 316
 	.code16
316 317
 p2r_rmode:
318
+	/* Load real-mode GDT */
319
+	data32 lgdt %cs:rm_gdtr
317 320
 	/* Switch to real mode */
318 321
 	movl	%cr0, %eax
319 322
 	andb	$0!CR0_PE, %al
@@ -349,6 +352,12 @@ p2r_ljmp_rm_cs:
349 352
 	.globl rm_ds
350 353
 rm_ds:	.word 0
351 354
 
355
+	/* Real-mode global and interrupt descriptor table registers */
356
+	.section ".text16.data", "aw", @progbits
357
+rm_gdtr:
358
+	.word 0 /* Limit */
359
+	.long 0 /* Base */
360
+
352 361
 /****************************************************************************
353 362
  * prot_call (real-mode far call, 16-bit real-mode far return address)
354 363
  *
@@ -384,8 +393,8 @@ rm_ds:	.word 0
384 393
  */
385 394
 
386 395
 #define PC_OFFSET_GDT ( 0 )
387
-#define PC_OFFSET_IDT ( PC_OFFSET_GDT + 8 /* pad to 8 to keep alignment */ )
388
-#define PC_OFFSET_IX86 ( PC_OFFSET_IDT + 8 /* pad to 8 to keep alignment */ )
396
+#define PC_OFFSET_IDT ( PC_OFFSET_GDT + 6 )
397
+#define PC_OFFSET_IX86 ( PC_OFFSET_IDT + 6 )
389 398
 #define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
390 399
 #define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
391 400
 #define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 )
@@ -403,10 +412,10 @@ prot_call:
403 412
 	pushw	%ds
404 413
 	pushw	%ss
405 414
 	pushw	%cs
406
-	subw	$16, %sp
415
+	subw	$PC_OFFSET_IX86, %sp
407 416
 	movw	%sp, %bp
408
-	sidt	8(%bp)
409
-	sgdt	(%bp)
417
+	sidt	PC_OFFSET_IDT(%bp)
418
+	sgdt	PC_OFFSET_GDT(%bp)
410 419
 
411 420
 	/* For sanity's sake, clear the direction flag as soon as possible */
412 421
 	cld
@@ -426,16 +435,14 @@ pc_pmode:
426 435
 
427 436
 	/* Switch to real mode and move register dump back to RM stack */
428 437
 	movl	$PC_OFFSET_END, %ecx
438
+	movl	%esp, %esi
429 439
 	pushl	$pc_rmode
430 440
 	jmp	prot_to_real
431 441
 	.section ".text16", "ax", @progbits
432 442
 	.code16
433 443
 pc_rmode:
434
-	/* Reload GDT and IDT, restore registers and flags and return */
435
-	movw	%sp, %bp
436
-	data32 lgdt (%bp)
437
-	data32 lidt 8(%bp)
438
-	addw	$20, %sp /* also skip %cs and %ss */
444
+	/* Restore registers and flags and return */
445
+	addw	$( PC_OFFSET_IX86 + 4 /* also skip %cs and %ss */ ), %sp
439 446
 	popw	%ds
440 447
 	popw	%es
441 448
 	popw	%fs
@@ -489,6 +496,7 @@ real_call:
489 496
 	/* Switch to real mode and move register dump to RM stack  */
490 497
 	movl	$( RC_OFFSET_RETADDR + 4 /* function pointer copy */ ), %ecx
491 498
 	pushl	$rc_rmode
499
+	movl	$rm_default_gdtr_idtr, %esi
492 500
 	jmp	prot_to_real
493 501
 	.section ".text16", "ax", @progbits
494 502
 	.code16
@@ -520,6 +528,14 @@ rc_pmode:
520 528
 	.section ".data16", "aw", @progbits
521 529
 rc_function:	.word 0, 0
522 530
 
531
+	/* Default real-mode global and interrupt descriptor table registers */
532
+	.section ".data", "aw", @progbits
533
+rm_default_gdtr_idtr:
534
+	.word 0		/* Global descriptor table limit */
535
+	.long 0		/* Global descriptor table base */
536
+	.word 0x03ff	/* Interrupt descriptor table limit */
537
+	.long 0		/* Interrupt descriptor table base */
538
+
523 539
 /****************************************************************************
524 540
  * flatten_real_mode (real-mode near call)
525 541
  *

Loading…
İptal
Kaydet