Browse Source

[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 years ago
parent
commit
bcfaf119a7
1 changed files with 35 additions and 19 deletions
  1. 35
    19
      src/arch/i386/transitions/librm.S

+ 35
- 19
src/arch/i386/transitions/librm.S View File

253
 	/* Return to virtual address */
253
 	/* Return to virtual address */
254
 	ret
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
  * prot_to_real (protected-mode near call, 32-bit real-mode return address)
257
  * prot_to_real (protected-mode near call, 32-bit real-mode return address)
264
  *
258
  *
275
  *
269
  *
276
  * Parameters: 
270
  * Parameters: 
277
  *   %ecx : number of bytes to move from PM stack to RM stack
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
 	.section ".text", "ax", @progbits
276
 	.section ".text", "ax", @progbits
282
 	.code32
277
 	.code32
283
 prot_to_real:
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
 	/* Add return address to data to be moved to RM stack */
288
 	/* Add return address to data to be moved to RM stack */
285
 	addl	$4, %ecx
289
 	addl	$4, %ecx
286
 	
290
 	
300
 	/* Record protected-mode %esp (after removal of data) */
304
 	/* Record protected-mode %esp (after removal of data) */
301
 	movl	%esi, pm_esp
305
 	movl	%esi, pm_esp
302
 
306
 
303
-	/* Reset IDTR to the real-mode defaults */
304
-	lidt	rm_idtr
305
-
306
 	/* Load real-mode segment limits */
307
 	/* Load real-mode segment limits */
307
 	movw	$REAL_DS, %ax
308
 	movw	$REAL_DS, %ax
308
 	movw	%ax, %ds
309
 	movw	%ax, %ds
314
 	.section ".text16", "ax", @progbits
315
 	.section ".text16", "ax", @progbits
315
 	.code16
316
 	.code16
316
 p2r_rmode:
317
 p2r_rmode:
318
+	/* Load real-mode GDT */
319
+	data32 lgdt %cs:rm_gdtr
317
 	/* Switch to real mode */
320
 	/* Switch to real mode */
318
 	movl	%cr0, %eax
321
 	movl	%cr0, %eax
319
 	andb	$0!CR0_PE, %al
322
 	andb	$0!CR0_PE, %al
349
 	.globl rm_ds
352
 	.globl rm_ds
350
 rm_ds:	.word 0
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
  * prot_call (real-mode far call, 16-bit real-mode far return address)
362
  * prot_call (real-mode far call, 16-bit real-mode far return address)
354
  *
363
  *
384
  */
393
  */
385
 
394
 
386
 #define PC_OFFSET_GDT ( 0 )
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
 #define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
398
 #define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
390
 #define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
399
 #define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
391
 #define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 )
400
 #define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 )
403
 	pushw	%ds
412
 	pushw	%ds
404
 	pushw	%ss
413
 	pushw	%ss
405
 	pushw	%cs
414
 	pushw	%cs
406
-	subw	$16, %sp
415
+	subw	$PC_OFFSET_IX86, %sp
407
 	movw	%sp, %bp
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
 	/* For sanity's sake, clear the direction flag as soon as possible */
420
 	/* For sanity's sake, clear the direction flag as soon as possible */
412
 	cld
421
 	cld
426
 
435
 
427
 	/* Switch to real mode and move register dump back to RM stack */
436
 	/* Switch to real mode and move register dump back to RM stack */
428
 	movl	$PC_OFFSET_END, %ecx
437
 	movl	$PC_OFFSET_END, %ecx
438
+	movl	%esp, %esi
429
 	pushl	$pc_rmode
439
 	pushl	$pc_rmode
430
 	jmp	prot_to_real
440
 	jmp	prot_to_real
431
 	.section ".text16", "ax", @progbits
441
 	.section ".text16", "ax", @progbits
432
 	.code16
442
 	.code16
433
 pc_rmode:
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
 	popw	%ds
446
 	popw	%ds
440
 	popw	%es
447
 	popw	%es
441
 	popw	%fs
448
 	popw	%fs
489
 	/* Switch to real mode and move register dump to RM stack  */
496
 	/* Switch to real mode and move register dump to RM stack  */
490
 	movl	$( RC_OFFSET_RETADDR + 4 /* function pointer copy */ ), %ecx
497
 	movl	$( RC_OFFSET_RETADDR + 4 /* function pointer copy */ ), %ecx
491
 	pushl	$rc_rmode
498
 	pushl	$rc_rmode
499
+	movl	$rm_default_gdtr_idtr, %esi
492
 	jmp	prot_to_real
500
 	jmp	prot_to_real
493
 	.section ".text16", "ax", @progbits
501
 	.section ".text16", "ax", @progbits
494
 	.code16
502
 	.code16
520
 	.section ".data16", "aw", @progbits
528
 	.section ".data16", "aw", @progbits
521
 rc_function:	.word 0, 0
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
  * flatten_real_mode (real-mode near call)
540
  * flatten_real_mode (real-mode near call)
525
  *
541
  *

Loading…
Cancel
Save