diff options
author | neel <neel@FreeBSD.org> | 2012-11-28 00:02:17 +0000 |
---|---|---|
committer | neel <neel@FreeBSD.org> | 2012-11-28 00:02:17 +0000 |
commit | 36ab9a2e1ab7d2b1884270275584f989cfd65e2b (patch) | |
tree | 8cf47855850351281fdc988a8a65fb469fbfb73f /sys/amd64/vmm/vmm_lapic.c | |
parent | 76430d4106c5cb90837c5f728272d9f249e085c4 (diff) | |
download | FreeBSD-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.c | 83 |
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); } |