summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2015-05-22 17:34:22 +0000
committerneel <neel@FreeBSD.org>2015-05-22 17:34:22 +0000
commit4d7716dd23ac606cf6ea30d64fbd0edeb38e0f57 (patch)
tree155b45fee502b21b2abdb34f983c46d3adb155f6
parent318c4f97e694c1972b55450cafe914f39977d179 (diff)
downloadFreeBSD-src-4d7716dd23ac606cf6ea30d64fbd0edeb38e0f57.zip
FreeBSD-src-4d7716dd23ac606cf6ea30d64fbd0edeb38e0f57.tar.gz
Don't rely on the 'VM-exit instruction length' field in the VMCS to always
have an accurate length on an EPT violation. This is not needed by the instruction decoding code because it also has to work with AMD/SVM that does not provide a valid instruction length on a Nested Page Fault. In collaboration with: Leon Dang (ldang@nahannisys.com) Discussed with: grehan MFC after: 1 week
-rw-r--r--sys/amd64/vmm/intel/vmx.c1
-rw-r--r--sys/amd64/vmm/vmm.c23
2 files changed, 11 insertions, 13 deletions
diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c
index 03d755c..4c3f20d 100644
--- a/sys/amd64/vmm/intel/vmx.c
+++ b/sys/amd64/vmm/intel/vmx.c
@@ -1780,6 +1780,7 @@ vmexit_inst_emul(struct vm_exit *vmexit, uint64_t gpa, uint64_t gla)
paging = &vmexit->u.inst_emul.paging;
vmexit->exitcode = VM_EXITCODE_INST_EMUL;
+ vmexit->inst_length = 0;
vmexit->u.inst_emul.gpa = gpa;
vmexit->u.inst_emul.gla = gla;
vmx_paging_info(paging);
diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
index 51c63f5..efaaa7d 100644
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -1256,11 +1256,14 @@ vm_handle_inst_emul(struct vm *vm, int vcpuid, bool *retu)
mem_region_read_t mread;
mem_region_write_t mwrite;
enum vm_cpu_mode cpu_mode;
- int cs_d, error, fault, length;
+ int cs_d, error, fault;
vcpu = &vm->vcpu[vcpuid];
vme = &vcpu->exitinfo;
+ KASSERT(vme->inst_length == 0, ("%s: invalid inst_length %d",
+ __func__, vme->inst_length));
+
gla = vme->u.inst_emul.gla;
gpa = vme->u.inst_emul.gpa;
cs_base = vme->u.inst_emul.cs_base;
@@ -1273,13 +1276,8 @@ vm_handle_inst_emul(struct vm *vm, int vcpuid, bool *retu)
/* Fetch, decode and emulate the faulting instruction */
if (vie->num_valid == 0) {
- /*
- * If the instruction length is not known then assume a
- * maximum size instruction.
- */
- length = vme->inst_length ? vme->inst_length : VIE_INST_SIZE;
error = vmm_fetch_instruction(vm, vcpuid, paging, vme->rip +
- cs_base, length, vie, &fault);
+ cs_base, VIE_INST_SIZE, vie, &fault);
} else {
/*
* The instruction bytes have already been copied into 'vie'
@@ -1297,13 +1295,12 @@ vm_handle_inst_emul(struct vm *vm, int vcpuid, bool *retu)
}
/*
- * If the instruction length was not specified then update it now
- * along with 'nextrip'.
+ * Update 'nextrip' based on the length of the emulated instruction.
*/
- if (vme->inst_length == 0) {
- vme->inst_length = vie->num_processed;
- vcpu->nextrip += vie->num_processed;
- }
+ vme->inst_length = vie->num_processed;
+ vcpu->nextrip += vie->num_processed;
+ VCPU_CTR1(vm, vcpuid, "nextrip updated to %#lx after instruction "
+ "decoding", vcpu->nextrip);
/* return to userland unless this is an in-kernel emulated device */
if (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + PAGE_SIZE) {
OpenPOWER on IntegriCloud