diff options
| author | Rusty Russell <rusty@rustcorp.com.au> | 2011-07-22 01:09:49 -0400 |
|---|---|---|
| committer | Rusty Russell <rusty@rustcorp.com.au> | 2011-07-22 01:09:49 -0400 |
| commit | 6d7a5d1ea34495ecb1d608f0e40afba7776ee408 (patch) | |
| tree | 23213877e952ad122888a502d07ed112263069d6 /drivers/lguest | |
| parent | 7e1941444f808d8001aa3b63588150c516321a3c (diff) | |
lguest: don't rewrite vmcall instructions
Now we no longer use vmcall, we don't need to rewrite it in the Guest.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/lguest')
| -rw-r--r-- | drivers/lguest/interrupts_and_traps.c | 6 | ||||
| -rw-r--r-- | drivers/lguest/x86/core.c | 77 |
2 files changed, 2 insertions, 81 deletions
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index daaf86631647..f0c171506371 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c | |||
| @@ -375,11 +375,9 @@ static bool direct_trap(unsigned int num) | |||
| 375 | /* | 375 | /* |
| 376 | * The Host needs to see page faults (for shadow paging and to save the | 376 | * The Host needs to see page faults (for shadow paging and to save the |
| 377 | * fault address), general protection faults (in/out emulation) and | 377 | * fault address), general protection faults (in/out emulation) and |
| 378 | * device not available (TS handling), invalid opcode fault (kvm hcall), | 378 | * device not available (TS handling) and of course, the hypercall trap. |
| 379 | * and of course, the hypercall trap. | ||
| 380 | */ | 379 | */ |
| 381 | return num != 14 && num != 13 && num != 7 && | 380 | return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY; |
| 382 | num != 6 && num != LGUEST_TRAP_ENTRY; | ||
| 383 | } | 381 | } |
| 384 | /*:*/ | 382 | /*:*/ |
| 385 | 383 | ||
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index 9f1659c3d1f3..ec0cdfc04e78 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c | |||
| @@ -352,69 +352,6 @@ static int emulate_insn(struct lg_cpu *cpu) | |||
| 352 | return 1; | 352 | return 1; |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | /* | ||
| 356 | * Our hypercalls mechanism used to be based on direct software interrupts. | ||
| 357 | * After Anthony's "Refactor hypercall infrastructure" kvm patch, we decided to | ||
| 358 | * change over to using kvm hypercalls. | ||
| 359 | * | ||
| 360 | * KVM_HYPERCALL is actually a "vmcall" instruction, which generates an invalid | ||
| 361 | * opcode fault (fault 6) on non-VT cpus, so the easiest solution seemed to be | ||
| 362 | * an *emulation approach*: if the fault was really produced by an hypercall | ||
| 363 | * (is_hypercall() does exactly this check), we can just call the corresponding | ||
| 364 | * hypercall host implementation function. | ||
| 365 | * | ||
| 366 | * But these invalid opcode faults are notably slower than software interrupts. | ||
| 367 | * So we implemented the *patching (or rewriting) approach*: every time we hit | ||
| 368 | * the KVM_HYPERCALL opcode in Guest code, we patch it to the old "int 0x1f" | ||
| 369 | * opcode, so next time the Guest calls this hypercall it will use the | ||
| 370 | * faster trap mechanism. | ||
| 371 | * | ||
| 372 | * Matias even benchmarked it to convince you: this shows the average cycle | ||
| 373 | * cost of a hypercall. For each alternative solution mentioned above we've | ||
| 374 | * made 5 runs of the benchmark: | ||
| 375 | * | ||
| 376 | * 1) direct software interrupt: 2915, 2789, 2764, 2721, 2898 | ||
| 377 | * 2) emulation technique: 3410, 3681, 3466, 3392, 3780 | ||
| 378 | * 3) patching (rewrite) technique: 2977, 2975, 2891, 2637, 2884 | ||
| 379 | * | ||
| 380 | * One two-line function is worth a 20% hypercall speed boost! | ||
| 381 | */ | ||
| 382 | static void rewrite_hypercall(struct lg_cpu *cpu) | ||
| 383 | { | ||
| 384 | /* | ||
| 385 | * This are the opcodes we use to patch the Guest. The opcode for "int | ||
| 386 | * $0x1f" is "0xcd 0x1f" but vmcall instruction is 3 bytes long, so we | ||
| 387 | * complete the sequence with a NOP (0x90). | ||
| 388 | */ | ||
| 389 | u8 insn[3] = {0xcd, 0x1f, 0x90}; | ||
| 390 | |||
| 391 | __lgwrite(cpu, guest_pa(cpu, cpu->regs->eip), insn, sizeof(insn)); | ||
| 392 | /* | ||
| 393 | * The above write might have caused a copy of that page to be made | ||
| 394 | * (if it was read-only). We need to make sure the Guest has | ||
| 395 | * up-to-date pagetables. As this doesn't happen often, we can just | ||
| 396 | * drop them all. | ||
| 397 | */ | ||
| 398 | guest_pagetable_clear_all(cpu); | ||
| 399 | } | ||
| 400 | |||
| 401 | static bool is_hypercall(struct lg_cpu *cpu) | ||
| 402 | { | ||
| 403 | u8 insn[3]; | ||
| 404 | |||
| 405 | /* | ||
| 406 | * This must be the Guest kernel trying to do something. | ||
| 407 | * The bottom two bits of the CS segment register are the privilege | ||
| 408 | * level. | ||
| 409 | */ | ||
| 410 | if ((cpu->regs->cs & 3) != GUEST_PL) | ||
| 411 | return false; | ||
| 412 | |||
| 413 | /* Is it a vmcall? */ | ||
| 414 | __lgread(cpu, insn, guest_pa(cpu, cpu->regs->eip), sizeof(insn)); | ||
| 415 | return insn[0] == 0x0f && insn[1] == 0x01 && insn[2] == 0xc1; | ||
| 416 | } | ||
| 417 | |||
| 418 | /*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */ | 355 | /*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */ |
| 419 | void lguest_arch_handle_trap(struct lg_cpu *cpu) | 356 | void lguest_arch_handle_trap(struct lg_cpu *cpu) |
| 420 | { | 357 | { |
| @@ -429,20 +366,6 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu) | |||
| 429 | if (emulate_insn(cpu)) | 366 | if (emulate_insn(cpu)) |
| 430 | return; | 367 | return; |
| 431 | } | 368 | } |
| 432 | /* | ||
| 433 | * If KVM is active, the vmcall instruction triggers a General | ||
| 434 | * Protection Fault. Normally it triggers an invalid opcode | ||
| 435 | * fault (6): | ||
| 436 | */ | ||
| 437 | case 6: | ||
| 438 | /* | ||
| 439 | * We need to check if ring == GUEST_PL and faulting | ||
| 440 | * instruction == vmcall. | ||
| 441 | */ | ||
| 442 | if (is_hypercall(cpu)) { | ||
| 443 | rewrite_hypercall(cpu); | ||
| 444 | return; | ||
| 445 | } | ||
| 446 | break; | 369 | break; |
| 447 | case 14: /* We've intercepted a Page Fault. */ | 370 | case 14: /* We've intercepted a Page Fault. */ |
| 448 | /* | 371 | /* |
