summaryrefslogtreecommitdiffstats
path: root/sys/amd64/vmm/vmm_lapic.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/amd64/vmm/vmm_lapic.c')
-rw-r--r--sys/amd64/vmm/vmm_lapic.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/sys/amd64/vmm/vmm_lapic.c b/sys/amd64/vmm/vmm_lapic.c
index 13550b4..0d797e6 100644
--- a/sys/amd64/vmm/vmm_lapic.c
+++ b/sys/amd64/vmm/vmm_lapic.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include "vmm_ipi.h"
#include "vmm_lapic.h"
#include "vlapic.h"
+#include "vmm_instruction_emul.h"
static int
lapic_write(struct vlapic *vlapic, u_int offset, uint64_t val)
@@ -174,3 +175,73 @@ lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t val)
return (handled);
}
+
+int
+lapic_mmio(struct vm *vm, int cpu, u_int offset, int read,
+ uint64_t rip, uint64_t cr3)
+{
+ 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)
+ return (UNHANDLED);
+
+ /*
+ * XXX
+ * The operand register in which we store the result of the
+ * read must be a GPR that we can modify even if the vcpu
+ * is "running". All the GPRs qualify except for %rsp.
+ *
+ * This is a limitation of the vm_set_register() API
+ * and can be fixed if necessary.
+ */
+ if (vie.operand_register == VM_REG_GUEST_RSP)
+ return (UNHANDLED);
+
+ if (read) {
+ if ((vie.opcode_flags & VIE_F_TO_REG) == 0)
+ return (UNHANDLED);
+
+ 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,
+ val);
+ if (error)
+ panic("lapic_mmio: error %d setting gpr %d",
+ 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,
+ &val);
+ if (error) {
+ panic("lapic_mmio: error %d getting gpr %d",
+ error, vie.operand_register);
+ }
+ } else if (vie.opcode_flags & VIE_F_FROM_IMM) {
+ val = vie.immediate;
+ } else {
+ return (UNHANDLED);
+ }
+
+ handled = lapic_write(vlapic, offset, val);
+ }
+
+ return (handled);
+}
OpenPOWER on IntegriCloud