Date: Mon, 8 Jul 2013 19:40:51 +0000 (UTC) From: Neel Natu <neel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r253044 - in projects/bhyve_npt_pmap: sys/amd64/include sys/amd64/vmm sys/amd64/vmm/intel usr.sbin/bhyve Message-ID: <201307081940.r68Jep39091253@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: neel Date: Mon Jul 8 19:40:50 2013 New Revision: 253044 URL: http://svnweb.freebsd.org/changeset/base/253044 Log: Fault in guest memory in response to EPT faults. The EPT faults are distinguished as follows: - Faults that point to an address that is assigned to a "memory" region will be resolved using vm_fault() - All other EPT faults are resolved via instruction emulation under the assumption that they happened because of an instruction accessing MMIO. Modified: projects/bhyve_npt_pmap/sys/amd64/include/vmm.h projects/bhyve_npt_pmap/sys/amd64/vmm/intel/vmx.c projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c projects/bhyve_npt_pmap/usr.sbin/bhyve/bhyverun.c Modified: projects/bhyve_npt_pmap/sys/amd64/include/vmm.h ============================================================================== --- projects/bhyve_npt_pmap/sys/amd64/include/vmm.h Mon Jul 8 19:19:29 2013 (r253043) +++ projects/bhyve_npt_pmap/sys/amd64/include/vmm.h Mon Jul 8 19:40:50 2013 (r253044) @@ -98,6 +98,7 @@ int vm_gpabase2memseg(struct vm *vm, vm_ struct vm_memory_segment *seg); int vm_get_memobj(struct vm *vm, vm_paddr_t gpa, size_t len, vm_offset_t *offset, struct vm_object **object); +boolean_t vm_mem_allocated(struct vm *vm, vm_paddr_t gpa); int vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval); int vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val); int vm_get_seg_desc(struct vm *vm, int vcpu, int reg, @@ -269,6 +270,8 @@ struct vm_exit { struct { uint64_t gpa; struct vie vie; + int inst_emulation; + int fault_type; } paging; /* * VMX specific payload. Used when there is no "better" Modified: projects/bhyve_npt_pmap/sys/amd64/vmm/intel/vmx.c ============================================================================== --- projects/bhyve_npt_pmap/sys/amd64/vmm/intel/vmx.c Mon Jul 8 19:19:29 2013 (r253043) +++ projects/bhyve_npt_pmap/sys/amd64/vmm/intel/vmx.c Mon Jul 8 19:40:50 2013 (r253044) @@ -1175,7 +1175,22 @@ vmx_emulate_cr_access(struct vmx *vmx, i } static int -vmx_ept_fault(struct vm *vm, int cpu, +ept_fault_type(uint64_t ept_qual) +{ + int fault_type = 0; + + if (ept_qual & EPT_VIOLATION_INST_FETCH) + fault_type |= VM_PROT_EXECUTE; + if (ept_qual & EPT_VIOLATION_DATA_READ) + fault_type |= VM_PROT_READ; + if (ept_qual & EPT_VIOLATION_DATA_WRITE) + fault_type |= VM_PROT_WRITE; + + return (fault_type); +} + +static int +vmx_inst_emul(struct vm *vm, int cpu, uint64_t gla, uint64_t gpa, uint64_t rip, int inst_length, uint64_t cr3, uint64_t ept_qual, struct vie *vie) { @@ -1223,7 +1238,7 @@ vmx_ept_fault(struct vm *vm, int cpu, static int vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) { - int error, handled; + int error, handled, emulation; struct vmcs *vmcs; struct vmxctx *vmxctx; uint32_t eax, ecx, edx; @@ -1334,15 +1349,30 @@ vmx_exit_process(struct vmx *vmx, int vc break; case EXIT_REASON_EPT_FAULT: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_EPT_FAULT, 1); - gla = vmcs_gla(); + /* + * If 'gpa' lies within the address space allocated to + * memory then this must be a nested page fault otherwise + * this must be an instruction that accesses MMIO space. + */ gpa = vmcs_gpa(); - cr3 = vmcs_guest_cr3(); - handled = vmx_ept_fault(vmx->vm, vcpu, gla, gpa, - vmexit->rip, vmexit->inst_length, - cr3, qual, &vmexit->u.paging.vie); + if (vm_mem_allocated(vmx->vm, gpa)) { + handled = 0; + emulation = 0; + } else { + emulation = 1; + gla = vmcs_gla(); + cr3 = vmcs_guest_cr3(); + vie_init(&vmexit->u.paging.vie); + handled = vmx_inst_emul(vmx->vm, vcpu, gla, gpa, + vmexit->rip, vmexit->inst_length, + cr3, qual, &vmexit->u.paging.vie); + } + if (!handled) { vmexit->exitcode = VM_EXITCODE_PAGING; vmexit->u.paging.gpa = gpa; + vmexit->u.paging.inst_emulation = emulation; + vmexit->u.paging.fault_type = ept_fault_type(qual); } break; default: Modified: projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c ============================================================================== --- projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c Mon Jul 8 19:19:29 2013 (r253043) +++ projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c Mon Jul 8 19:40:50 2013 (r253044) @@ -49,6 +49,8 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_page.h> #include <vm/pmap.h> #include <vm/vm_map.h> +#include <vm/vm_extern.h> +#include <vm/vm_param.h> #include <machine/vm.h> #include <machine/pcb.h> @@ -364,26 +366,20 @@ vm_unmap_mmio(struct vm *vm, vm_paddr_t return (ENXIO); /* XXX fixme */ } -/* - * Returns TRUE if 'gpa' is available for allocation and FALSE otherwise - */ -static boolean_t -vm_gpa_available(struct vm *vm, vm_paddr_t gpa) +boolean_t +vm_mem_allocated(struct vm *vm, vm_paddr_t gpa) { int i; vm_paddr_t gpabase, gpalimit; - if (gpa & PAGE_MASK) - panic("vm_gpa_available: gpa (0x%016lx) not page aligned", gpa); - for (i = 0; i < vm->num_mem_segs; i++) { gpabase = vm->mem_segs[i].gpa; gpalimit = gpabase + vm->mem_segs[i].len; if (gpa >= gpabase && gpa < gpalimit) - return (FALSE); + return (TRUE); } - return (TRUE); + return (FALSE); } /* @@ -403,10 +399,10 @@ vm_malloc(struct vm *vm, vm_paddr_t gpa, available = allocated = 0; g = gpa; while (g < gpa + len) { - if (vm_gpa_available(vm, g)) - available++; - else + if (vm_mem_allocated(vm, g)) allocated++; + else + available++; g += PAGE_SIZE; } @@ -657,11 +653,14 @@ restart: critical_exit(); + if (error) + goto done; + /* * Oblige the guest's desire to 'hlt' by sleeping until the vcpu * is ready to run. */ - if (error == 0 && vme->exitcode == VM_EXITCODE_HLT) { + if (vme->exitcode == VM_EXITCODE_HLT) { vcpu_lock(vcpu); /* @@ -699,6 +698,39 @@ restart: goto restart; } + if (vme->exitcode == VM_EXITCODE_PAGING && + vme->u.paging.inst_emulation == 0) { + int rv; + struct thread *td; + struct proc *p; + struct vm_map *map; + vm_prot_t ftype; + + td = curthread; + p = td->td_proc; + map = &vm->vmspace->vm_map; + ftype = vme->u.paging.fault_type; + + PROC_LOCK(p); + p->p_lock++; + PROC_UNLOCK(p); + + rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL); + + PROC_LOCK(p); + p->p_lock--; + PROC_UNLOCK(p); + + if (rv == KERN_SUCCESS) { + rip = vme->rip; + goto restart; + } else { + /* XXX */ + vme->inst_length = 0; + } + } + +done: return (error); } Modified: projects/bhyve_npt_pmap/usr.sbin/bhyve/bhyverun.c ============================================================================== --- projects/bhyve_npt_pmap/usr.sbin/bhyve/bhyverun.c Mon Jul 8 19:19:29 2013 (r253043) +++ projects/bhyve_npt_pmap/usr.sbin/bhyve/bhyverun.c Mon Jul 8 19:40:50 2013 (r253044) @@ -440,8 +440,11 @@ vmexit_paging(struct vmctx *ctx, struct int err; stats.vmexit_paging++; - err = emulate_mem(ctx, *pvcpu, vmexit->u.paging.gpa, - &vmexit->u.paging.vie); + if (vmexit->u.paging.inst_emulation) { + err = emulate_mem(ctx, *pvcpu, vmexit->u.paging.gpa, + &vmexit->u.paging.vie); + } else + err = ESRCH; if (err) { if (err == EINVAL) {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201307081940.r68Jep39091253>