···375375 /*376376 * The Host needs to see page faults (for shadow paging and to save the377377 * fault address), general protection faults (in/out emulation) and378378- * device not available (TS handling), invalid opcode fault (kvm hcall),379379- * and of course, the hypercall trap.378378+ * device not available (TS handling) and of course, the hypercall trap.380379 */381381- return num != 14 && num != 13 && num != 7 &&382382- num != 6 && num != LGUEST_TRAP_ENTRY;380380+ return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY;383381}384382/*:*/385383
-77
drivers/lguest/x86/core.c
···352352 return 1;353353}354354355355-/*356356- * Our hypercalls mechanism used to be based on direct software interrupts.357357- * After Anthony's "Refactor hypercall infrastructure" kvm patch, we decided to358358- * change over to using kvm hypercalls.359359- *360360- * KVM_HYPERCALL is actually a "vmcall" instruction, which generates an invalid361361- * opcode fault (fault 6) on non-VT cpus, so the easiest solution seemed to be362362- * an *emulation approach*: if the fault was really produced by an hypercall363363- * (is_hypercall() does exactly this check), we can just call the corresponding364364- * hypercall host implementation function.365365- *366366- * But these invalid opcode faults are notably slower than software interrupts.367367- * So we implemented the *patching (or rewriting) approach*: every time we hit368368- * the KVM_HYPERCALL opcode in Guest code, we patch it to the old "int 0x1f"369369- * opcode, so next time the Guest calls this hypercall it will use the370370- * faster trap mechanism.371371- *372372- * Matias even benchmarked it to convince you: this shows the average cycle373373- * cost of a hypercall. For each alternative solution mentioned above we've374374- * made 5 runs of the benchmark:375375- *376376- * 1) direct software interrupt: 2915, 2789, 2764, 2721, 2898377377- * 2) emulation technique: 3410, 3681, 3466, 3392, 3780378378- * 3) patching (rewrite) technique: 2977, 2975, 2891, 2637, 2884379379- *380380- * One two-line function is worth a 20% hypercall speed boost!381381- */382382-static void rewrite_hypercall(struct lg_cpu *cpu)383383-{384384- /*385385- * This are the opcodes we use to patch the Guest. The opcode for "int386386- * $0x1f" is "0xcd 0x1f" but vmcall instruction is 3 bytes long, so we387387- * complete the sequence with a NOP (0x90).388388- */389389- u8 insn[3] = {0xcd, 0x1f, 0x90};390390-391391- __lgwrite(cpu, guest_pa(cpu, cpu->regs->eip), insn, sizeof(insn));392392- /*393393- * The above write might have caused a copy of that page to be made394394- * (if it was read-only). We need to make sure the Guest has395395- * up-to-date pagetables. As this doesn't happen often, we can just396396- * drop them all.397397- */398398- guest_pagetable_clear_all(cpu);399399-}400400-401401-static bool is_hypercall(struct lg_cpu *cpu)402402-{403403- u8 insn[3];404404-405405- /*406406- * This must be the Guest kernel trying to do something.407407- * The bottom two bits of the CS segment register are the privilege408408- * level.409409- */410410- if ((cpu->regs->cs & 3) != GUEST_PL)411411- return false;412412-413413- /* Is it a vmcall? */414414- __lgread(cpu, insn, guest_pa(cpu, cpu->regs->eip), sizeof(insn));415415- return insn[0] == 0x0f && insn[1] == 0x01 && insn[2] == 0xc1;416416-}417417-418355/*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */419356void lguest_arch_handle_trap(struct lg_cpu *cpu)420357{···365428 if (cpu->regs->errcode == 0) {366429 if (emulate_insn(cpu))367430 return;368368- }369369- /*370370- * If KVM is active, the vmcall instruction triggers a General371371- * Protection Fault. Normally it triggers an invalid opcode372372- * fault (6):373373- */374374- case 6:375375- /*376376- * We need to check if ring == GUEST_PL and faulting377377- * instruction == vmcall.378378- */379379- if (is_hypercall(cpu)) {380380- rewrite_hypercall(cpu);381381- return;382431 }383432 break;384433 case 14: /* We've intercepted a Page Fault. */