Commit 6d7a5d1e authored by Rusty Russell's avatar Rusty Russell

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: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 7e194144
...@@ -375,11 +375,9 @@ static bool direct_trap(unsigned int num) ...@@ -375,11 +375,9 @@ static bool direct_trap(unsigned int num)
/* /*
* The Host needs to see page faults (for shadow paging and to save the * The Host needs to see page faults (for shadow paging and to save the
* fault address), general protection faults (in/out emulation) and * fault address), general protection faults (in/out emulation) and
* device not available (TS handling), invalid opcode fault (kvm hcall), * device not available (TS handling) and of course, the hypercall trap.
* and of course, the hypercall trap.
*/ */
return num != 14 && num != 13 && num != 7 && return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY;
num != 6 && num != LGUEST_TRAP_ENTRY;
} }
/*:*/ /*:*/
......
...@@ -352,69 +352,6 @@ static int emulate_insn(struct lg_cpu *cpu) ...@@ -352,69 +352,6 @@ static int emulate_insn(struct lg_cpu *cpu)
return 1; return 1;
} }
/*
* Our hypercalls mechanism used to be based on direct software interrupts.
* After Anthony's "Refactor hypercall infrastructure" kvm patch, we decided to
* change over to using kvm hypercalls.
*
* KVM_HYPERCALL is actually a "vmcall" instruction, which generates an invalid
* opcode fault (fault 6) on non-VT cpus, so the easiest solution seemed to be
* an *emulation approach*: if the fault was really produced by an hypercall
* (is_hypercall() does exactly this check), we can just call the corresponding
* hypercall host implementation function.
*
* But these invalid opcode faults are notably slower than software interrupts.
* So we implemented the *patching (or rewriting) approach*: every time we hit
* the KVM_HYPERCALL opcode in Guest code, we patch it to the old "int 0x1f"
* opcode, so next time the Guest calls this hypercall it will use the
* faster trap mechanism.
*
* Matias even benchmarked it to convince you: this shows the average cycle
* cost of a hypercall. For each alternative solution mentioned above we've
* made 5 runs of the benchmark:
*
* 1) direct software interrupt: 2915, 2789, 2764, 2721, 2898
* 2) emulation technique: 3410, 3681, 3466, 3392, 3780
* 3) patching (rewrite) technique: 2977, 2975, 2891, 2637, 2884
*
* One two-line function is worth a 20% hypercall speed boost!
*/
static void rewrite_hypercall(struct lg_cpu *cpu)
{
/*
* This are the opcodes we use to patch the Guest. The opcode for "int
* $0x1f" is "0xcd 0x1f" but vmcall instruction is 3 bytes long, so we
* complete the sequence with a NOP (0x90).
*/
u8 insn[3] = {0xcd, 0x1f, 0x90};
__lgwrite(cpu, guest_pa(cpu, cpu->regs->eip), insn, sizeof(insn));
/*
* The above write might have caused a copy of that page to be made
* (if it was read-only). We need to make sure the Guest has
* up-to-date pagetables. As this doesn't happen often, we can just
* drop them all.
*/
guest_pagetable_clear_all(cpu);
}
static bool is_hypercall(struct lg_cpu *cpu)
{
u8 insn[3];
/*
* This must be the Guest kernel trying to do something.
* The bottom two bits of the CS segment register are the privilege
* level.
*/
if ((cpu->regs->cs & 3) != GUEST_PL)
return false;
/* Is it a vmcall? */
__lgread(cpu, insn, guest_pa(cpu, cpu->regs->eip), sizeof(insn));
return insn[0] == 0x0f && insn[1] == 0x01 && insn[2] == 0xc1;
}
/*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */ /*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
void lguest_arch_handle_trap(struct lg_cpu *cpu) void lguest_arch_handle_trap(struct lg_cpu *cpu)
{ {
...@@ -429,20 +366,6 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu) ...@@ -429,20 +366,6 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
if (emulate_insn(cpu)) if (emulate_insn(cpu))
return; return;
} }
/*
* If KVM is active, the vmcall instruction triggers a General
* Protection Fault. Normally it triggers an invalid opcode
* fault (6):
*/
case 6:
/*
* We need to check if ring == GUEST_PL and faulting
* instruction == vmcall.
*/
if (is_hypercall(cpu)) {
rewrite_hypercall(cpu);
return;
}
break; break;
case 14: /* We've intercepted a Page Fault. */ case 14: /* We've intercepted a Page Fault. */
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment