svn commit: r240978 - in projects/bhyve/sys/amd64/vmm: . intel
Neel Natu
neel at FreeBSD.org
Thu Sep 27 00:27:59 UTC 2012
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);
More information about the svn-src-projects
mailing list