Date: Thu, 27 Sep 2012 00:27:58 +0000 (UTC) From: Neel Natu <neel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r240978 - in projects/bhyve/sys/amd64/vmm: . intel Message-ID: <201209270027.q8R0RwpD019625@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: neel Date: Thu Sep 27 00:27:58 2012 New Revision: 240978 URL: http://svn.freebsd.org/changeset/base/240978 Log: Intel VT-x provides the length of the instruction at the time of the nested page table fault. Use this when fetching the instruction bytes from the guest memory. Also modify the lapic_mmio() API so that a decoded instruction is fed into it instead of having it fetch the instruction bytes from the guest. This is useful for hardware assists like SVM that provide the faulting instruction as part of the vmexit. Modified: projects/bhyve/sys/amd64/vmm/intel/vmx.c projects/bhyve/sys/amd64/vmm/vmm_instruction_emul.c projects/bhyve/sys/amd64/vmm/vmm_instruction_emul.h projects/bhyve/sys/amd64/vmm/vmm_lapic.c projects/bhyve/sys/amd64/vmm/vmm_lapic.h Modified: projects/bhyve/sys/amd64/vmm/intel/vmx.c ============================================================================== --- projects/bhyve/sys/amd64/vmm/intel/vmx.c Wed Sep 26 23:07:00 2012 (r240977) +++ projects/bhyve/sys/amd64/vmm/intel/vmx.c Thu Sep 27 00:27:58 2012 (r240978) @@ -1146,9 +1146,11 @@ vmx_emulate_cr_access(struct vmx *vmx, i static int vmx_lapic_fault(struct vm *vm, int cpu, - uint64_t gpa, uint64_t rip, uint64_t cr3, uint64_t ept_qual) + uint64_t gpa, uint64_t rip, int inst_length, + uint64_t cr3, uint64_t ept_qual) { int read, write, handled; + struct vie vie; /* * For this to be a legitimate access to the local apic: @@ -1180,7 +1182,14 @@ vmx_lapic_fault(struct vm *vm, int cpu, return (UNHANDLED); } - handled = lapic_mmio(vm, cpu, gpa - DEFAULT_APIC_BASE, read, rip, cr3); + /* Fetch, decode and emulate the faulting instruction */ + if (vmm_fetch_instruction(vm, rip, inst_length, cr3, &vie) != 0) + return (UNHANDLED); + + if (vmm_decode_instruction(&vie) != 0) + return (UNHANDLED); + + handled = lapic_mmio(vm, cpu, gpa - DEFAULT_APIC_BASE, read, &vie); return (handled); } @@ -1275,7 +1284,8 @@ vmx_exit_process(struct vmx *vmx, int vc gpa = vmcs_gpa(); cr3 = vmcs_guest_cr3(); handled = vmx_lapic_fault(vmx->vm, vcpu, - gpa, vmexit->rip, cr3, qual); + gpa, vmexit->rip, vmexit->inst_length, + cr3, qual); if (!handled) { vmexit->exitcode = VM_EXITCODE_PAGING; vmexit->u.paging.cr3 = cr3; Modified: projects/bhyve/sys/amd64/vmm/vmm_instruction_emul.c ============================================================================== --- projects/bhyve/sys/amd64/vmm/vmm_instruction_emul.c Wed Sep 26 23:07:00 2012 (r240977) +++ projects/bhyve/sys/amd64/vmm/vmm_instruction_emul.c Thu Sep 27 00:27:58 2012 (r240978) @@ -128,9 +128,9 @@ error: return (-1); } -void -vmm_fetch_instruction(struct vm *vm, uint64_t rip, uint64_t cr3, - struct vie *vie) +int +vmm_fetch_instruction(struct vm *vm, uint64_t rip, int inst_length, + uint64_t cr3, struct vie *vie) { int n, err; uint64_t hpa, gpa, gpaend; @@ -139,17 +139,18 @@ vmm_fetch_instruction(struct vm *vm, uin * XXX cache previously fetched instructions using 'rip' as the tag */ + if (inst_length > VIE_INST_SIZE) + panic("vmm_fetch_instruction: invalid length %d", inst_length); + vie_init(vie); - /* - * Copy up to 15 bytes of the instruction stream into 'vie' - */ - while (vie->num_valid < VIE_INST_SIZE) { + /* Copy the instruction into 'vie' */ + while (vie->num_valid < inst_length) { err = gla2gpa(vm, rip, cr3, &gpa, &gpaend); if (err) break; - n = min(VIE_INST_SIZE - vie->num_valid, gpaend - gpa); + n = min(inst_length - vie->num_valid, gpaend - gpa); hpa = vm_gpa2hpa(vm, gpa, n); if (hpa == -1) @@ -160,6 +161,11 @@ vmm_fetch_instruction(struct vm *vm, uin rip += n; vie->num_valid += n; } + + if (vie->num_valid == inst_length) + return (0); + else + return (-1); } static int Modified: projects/bhyve/sys/amd64/vmm/vmm_instruction_emul.h ============================================================================== --- projects/bhyve/sys/amd64/vmm/vmm_instruction_emul.h Wed Sep 26 23:07:00 2012 (r240977) +++ projects/bhyve/sys/amd64/vmm/vmm_instruction_emul.h Thu Sep 27 00:27:58 2012 (r240978) @@ -83,8 +83,8 @@ struct vie { struct vm; -void vmm_fetch_instruction(struct vm *vm, uint64_t rip, uint64_t cr3, - struct vie *vie); +int vmm_fetch_instruction(struct vm *vm, uint64_t rip, int inst_length, + uint64_t cr3, struct vie *vie); int vmm_decode_instruction(struct vie *vie); Modified: projects/bhyve/sys/amd64/vmm/vmm_lapic.c ============================================================================== --- projects/bhyve/sys/amd64/vmm/vmm_lapic.c Wed Sep 26 23:07:00 2012 (r240977) +++ projects/bhyve/sys/amd64/vmm/vmm_lapic.c Thu Sep 27 00:27:58 2012 (r240978) @@ -177,25 +177,18 @@ lapic_wrmsr(struct vm *vm, int cpu, u_in } int -lapic_mmio(struct vm *vm, int cpu, u_int offset, int read, - uint64_t rip, uint64_t cr3) +lapic_mmio(struct vm *vm, int cpu, u_int offset, int read, struct vie *vie) { int handled, error; uint64_t val; - struct vie vie; struct vlapic *vlapic; const int UNHANDLED = 0; vlapic = vm_lapic(vm, cpu); - vmm_fetch_instruction(vm, rip, cr3, &vie); - - if (vmm_decode_instruction(&vie) != 0) - return (UNHANDLED); - /* Only 32-bit accesses to local apic */ - if (vie.op_size != VIE_OP_SIZE_32BIT) + if (vie->op_size != VIE_OP_SIZE_32BIT) return (UNHANDLED); /* @@ -207,35 +200,35 @@ lapic_mmio(struct vm *vm, int cpu, u_int * This is a limitation of the vm_set_register() API * and can be fixed if necessary. */ - if (vie.operand_register == VM_REG_GUEST_RSP) + if (vie->operand_register == VM_REG_GUEST_RSP) return (UNHANDLED); if (read) { - if ((vie.opcode_flags & VIE_F_TO_REG) == 0) + if ((vie->opcode_flags & VIE_F_TO_REG) == 0) return (UNHANDLED); - if (vie.operand_register >= VM_REG_LAST) + if (vie->operand_register >= VM_REG_LAST) return (UNHANDLED); handled = lapic_read(vlapic, offset, &val); if (handled) { - error = vm_set_register(vm, cpu, vie.operand_register, + error = vm_set_register(vm, cpu, vie->operand_register, val); if (error) panic("lapic_mmio: error %d setting gpr %d", - error, vie.operand_register); + error, vie->operand_register); } } else { - if ((vie.opcode_flags & VIE_F_FROM_REG) && - (vie.operand_register < VM_REG_LAST)) { - error = vm_get_register(vm, cpu, vie.operand_register, + if ((vie->opcode_flags & VIE_F_FROM_REG) && + (vie->operand_register < VM_REG_LAST)) { + error = vm_get_register(vm, cpu, vie->operand_register, &val); if (error) { panic("lapic_mmio: error %d getting gpr %d", - error, vie.operand_register); + error, vie->operand_register); } - } else if (vie.opcode_flags & VIE_F_FROM_IMM) { - val = vie.immediate; + } else if (vie->opcode_flags & VIE_F_FROM_IMM) { + val = vie->immediate; } else { return (UNHANDLED); } Modified: projects/bhyve/sys/amd64/vmm/vmm_lapic.h ============================================================================== --- projects/bhyve/sys/amd64/vmm/vmm_lapic.h Wed Sep 26 23:07:00 2012 (r240977) +++ projects/bhyve/sys/amd64/vmm/vmm_lapic.h Thu Sep 27 00:27:58 2012 (r240978) @@ -30,13 +30,13 @@ #define _VMM_LAPIC_H_ struct vm; +struct vie; boolean_t lapic_msr(u_int num); int lapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval); int lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t wval); -int lapic_mmio(struct vm *vm, int cpu, u_int offset, int read, - uint64_t rip, uint64_t cr3); +int lapic_mmio(struct vm *vm, int cpu, u_int offset, int rd, struct vie *); void lapic_timer_tick(struct vm *vm, int cpu);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201209270027.q8R0RwpD019625>