summaryrefslogtreecommitdiffstats
path: root/sys/amd64/vmm/vmm_lapic.c
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2012-11-28 00:02:17 +0000
committerneel <neel@FreeBSD.org>2012-11-28 00:02:17 +0000
commit36ab9a2e1ab7d2b1884270275584f989cfd65e2b (patch)
tree8cf47855850351281fdc988a8a65fb469fbfb73f /sys/amd64/vmm/vmm_lapic.c
parent76430d4106c5cb90837c5f728272d9f249e085c4 (diff)
downloadFreeBSD-src-36ab9a2e1ab7d2b1884270275584f989cfd65e2b.zip
FreeBSD-src-36ab9a2e1ab7d2b1884270275584f989cfd65e2b.tar.gz
Revamp the x86 instruction emulation in bhyve.
On a nested page table fault the hypervisor will: - fetch the instruction using the guest %rip and %cr3 - decode the instruction in 'struct vie' - emulate the instruction in host kernel context for local apic accesses - any other type of mmio access is punted up to user-space (e.g. ioapic) The decoded instruction is passed as collateral to the user-space process that is handling the PAGING exit. The emulation code is fleshed out to include more addressing modes (e.g. SIB) and more types of operands (e.g. imm8). The source code is unified into a single file (vmm_instruction_emul.c) that is compiled into vmm.ko as well as /usr/sbin/bhyve. Reviewed by: grehan Obtained from: NetApp
Diffstat (limited to 'sys/amd64/vmm/vmm_lapic.c')
-rw-r--r--sys/amd64/vmm/vmm_lapic.c83
1 files changed, 32 insertions, 51 deletions
diff --git a/sys/amd64/vmm/vmm_lapic.c b/sys/amd64/vmm/vmm_lapic.c
index bb22122..dabcf06 100644
--- a/sys/amd64/vmm/vmm_lapic.c
+++ b/sys/amd64/vmm/vmm_lapic.c
@@ -34,12 +34,12 @@ __FBSDID("$FreeBSD$");
#include <sys/smp.h>
#include <x86/specialreg.h>
+#include <x86/apicreg.h>
#include <machine/vmm.h>
#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)
@@ -177,64 +177,45 @@ lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t val)
}
int
-lapic_mmio(struct vm *vm, int cpu, u_int offset, int read, struct vie *vie)
+lapic_mmio_write(void *vm, int cpu, uint64_t gpa, uint64_t wval, int size,
+ void *arg)
{
- int handled, error;
- uint64_t val;
+ int error;
+ uint64_t off;
struct vlapic *vlapic;
- const int UNHANDLED = 0;
+ off = gpa - DEFAULT_APIC_BASE;
+
+ /*
+ * Memory mapped local apic accesses must be 4 bytes wide and
+ * aligned on a 16-byte boundary.
+ */
+ if (size != 4 || off & 0xf)
+ return (EINVAL);
vlapic = vm_lapic(vm, cpu);
+ error = vlapic_op_mem_write(vlapic, off, DWORD, wval);
+ return (error);
+}
+
+int
+lapic_mmio_read(void *vm, int cpu, uint64_t gpa, uint64_t *rval, int size,
+ void *arg)
+{
+ int error;
+ uint64_t off;
+ struct vlapic *vlapic;
- /* Only 32-bit accesses to local apic */
- if (vie->op_size != VIE_OP_SIZE_32BIT)
- return (UNHANDLED);
+ off = gpa - DEFAULT_APIC_BASE;
/*
- * 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.
+ * Memory mapped local apic accesses must be 4 bytes wide and
+ * aligned on a 16-byte boundary.
*/
- 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);
- }
+ if (size != 4 || off & 0xf)
+ return (EINVAL);
- return (handled);
+ vlapic = vm_lapic(vm, cpu);
+ error = vlapic_op_mem_read(vlapic, off, DWORD, rval);
+ return (error);
}
OpenPOWER on IntegriCloud