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 /usr.sbin | |
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 'usr.sbin')
-rw-r--r-- | usr.sbin/bhyve/Makefile | 5 | ||||
-rw-r--r-- | usr.sbin/bhyve/fbsdrun.c | 4 | ||||
-rw-r--r-- | usr.sbin/bhyve/instruction_emul.c | 641 | ||||
-rw-r--r-- | usr.sbin/bhyve/instruction_emul.h | 36 | ||||
-rw-r--r-- | usr.sbin/bhyve/ioapic.c | 1 | ||||
-rw-r--r-- | usr.sbin/bhyve/mem.c | 51 | ||||
-rw-r--r-- | usr.sbin/bhyve/mem.h | 2 | ||||
-rw-r--r-- | usr.sbin/bhyve/pci_passthru.c | 1 |
8 files changed, 44 insertions, 697 deletions
diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile index 9dc7a53..c45b904 100644 --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -7,11 +7,14 @@ PROG= bhyve DEBUG_FLAGS= -g -O0 SRCS= acpi.c atpic.c consport.c dbgport.c elcr.c fbsdrun.c inout.c -SRCS+= instruction_emul.c ioapic.c mem.c mevent.c mptbl.c +SRCS+= ioapic.c mem.c mevent.c mptbl.c SRCS+= pci_emul.c pci_hostbridge.c pci_passthru.c pci_virtio_block.c SRCS+= pci_virtio_net.c pci_uart.c pit_8254.c pmtmr.c post.c rtc.c uart.c SRCS+= xmsr.c spinup_ap.c +.PATH: ${.CURDIR}/../../sys/amd64/vmm +SRCS+= vmm_instruction_emul.c + NO_MAN= DPADD= ${LIBVMMAPI} ${LIBMD} ${LIBPTHREAD} diff --git a/usr.sbin/bhyve/fbsdrun.c b/usr.sbin/bhyve/fbsdrun.c index 43fa797..b1c7098 100644 --- a/usr.sbin/bhyve/fbsdrun.c +++ b/usr.sbin/bhyve/fbsdrun.c @@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$"); #include "mptbl.h" #include "pci_emul.h" #include "xmsr.h" -#include "instruction_emul.h" #include "ioapic.h" #include "spinup_ap.h" @@ -455,7 +454,8 @@ vmexit_paging(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) stats.vmexit_paging++; err = emulate_mem(ctx, *pvcpu, vmexit->u.paging.gpa, vmexit->rip, - vmexit->u.paging.cr3, vmexit->u.paging.rwx); + vmexit->u.paging.cr3, vmexit->u.paging.rwx, + &vmexit->u.paging.vie); if (err) { if (err == EINVAL) { diff --git a/usr.sbin/bhyve/instruction_emul.c b/usr.sbin/bhyve/instruction_emul.c deleted file mode 100644 index 78c3608..0000000 --- a/usr.sbin/bhyve/instruction_emul.c +++ /dev/null @@ -1,641 +0,0 @@ -/*- - * Copyright (c) 2012 Sandvine, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <strings.h> -#include <unistd.h> -#include <assert.h> -#include <machine/vmm.h> -#include <vmmapi.h> - -#include "fbsdrun.h" -#include "mem.h" -#include "instruction_emul.h" - -#define PREFIX_LOCK 0xF0 -#define PREFIX_REPNE 0xF2 -#define PREFIX_REPE 0xF3 -#define PREFIX_CS_OVERRIDE 0x2E -#define PREFIX_SS_OVERRIDE 0x36 -#define PREFIX_DS_OVERRIDE 0x3E -#define PREFIX_ES_OVERRIDE 0x26 -#define PREFIX_FS_OVERRIDE 0x64 -#define PREFIX_GS_OVERRIDE 0x65 -#define PREFIX_BRANCH_NOT_TAKEN 0x2E -#define PREFIX_BRANCH_TAKEN 0x3E -#define PREFIX_OPSIZE 0x66 -#define is_opsz_prefix(x) ((x) == PREFIX_OPSIZE) -#define PREFIX_ADDRSIZE 0x67 - -#define OPCODE_2BYTE_ESCAPE 0x0F -#define OPCODE_3BYTE_ESCAPE 0x38 - -#define MODRM_MOD_MASK 0xC0 -#define MODRM_MOD_SHIFT 6 -#define MODRM_RM_MASK 0x07 -#define MODRM_RM_SHIFT 0 -#define MODRM_REG_MASK 0x38 -#define MODRM_REG_SHIFT 3 - -#define MOD_INDIRECT 0x0 -#define MOD_INDIRECT_DISP8 0x1 -#define MOD_INDIRECT_DISP32 0x2 -#define MOD_DIRECT 0x3 - -#define RM_EAX 0x0 -#define RM_ECX 0x1 -#define RM_EDX 0x2 -#define RM_EBX 0x3 -#define RM_SIB 0x4 -#define RM_DISP32 0x5 -#define RM_EBP RM_DISP32 -#define RM_ESI 0x6 -#define RM_EDI 0x7 - -#define REG_EAX 0x0 -#define REG_ECX 0x1 -#define REG_EDX 0x2 -#define REG_EBX 0x3 -#define REG_ESP 0x4 -#define REG_EBP 0x5 -#define REG_ESI 0x6 -#define REG_EDI 0x7 -#define REG_R8 0x8 -#define REG_R9 0x9 -#define REG_R10 0xA -#define REG_R11 0xB -#define REG_R12 0xC -#define REG_R13 0xD -#define REG_R14 0xE -#define REG_R15 0xF - -#define HAS_MODRM 1 -#define FROM_RM (1<<1) -#define FROM_REG (1<<2) -#define TO_RM (1<<3) -#define TO_REG (1<<4) -#define ZEXT (1<<5) -#define FROM_8 (1<<6) -#define FROM_16 (1<<7) -#define TO_8 (1<<8) -#define TO_16 (1<<9) - -#define REX_MASK 0xF0 -#define REX_PREFIX 0x40 -#define is_rex_prefix(x) ( ((x) & REX_MASK) == REX_PREFIX ) -#define REX_W_MASK 0x8 -#define REX_R_MASK 0x4 -#define REX_X_MASK 0x2 -#define REX_B_MASK 0x1 - -#define is_prefix(x) ((x) == PREFIX_LOCK || (x) == PREFIX_REPNE || \ - (x) == PREFIX_REPE || (x) == PREFIX_CS_OVERRIDE || \ - (x) == PREFIX_SS_OVERRIDE || (x) == PREFIX_DS_OVERRIDE || \ - (x) == PREFIX_ES_OVERRIDE || (x) == PREFIX_FS_OVERRIDE || \ - (x) == PREFIX_GS_OVERRIDE || (x) == PREFIX_BRANCH_NOT_TAKEN || \ - (x) == PREFIX_BRANCH_TAKEN || (x) == PREFIX_OPSIZE || \ - (x) == PREFIX_ADDRSIZE || is_rex_prefix((x))) - -#define PAGE_FRAME_MASK 0x80 -#define PAGE_OFFSET_MASK 0xFFF -#define PAGE_TABLE_ENTRY_MASK (~PAGE_OFFSET_MASK) -#define PML4E_OFFSET_MASK 0x0000FF8000000000 -#define PML4E_SHIFT 39 - -#define INSTR_VERIFY - -struct decoded_instruction -{ - void *instruction; - uint8_t *opcode; - uint8_t *modrm; - uint8_t *sib; - uint8_t *displacement; - uint8_t *immediate; - - uint16_t opcode_flags; - - uint8_t addressing_mode; - uint8_t rm; - uint8_t reg; - uint8_t opsz; - uint8_t rex_r; - uint8_t rex_w; - uint8_t rex_b; - uint8_t rex_x; - - int32_t disp; -}; - -static enum vm_reg_name vm_reg_name_mappings[] = { - [REG_EAX] = VM_REG_GUEST_RAX, - [REG_EBX] = VM_REG_GUEST_RBX, - [REG_ECX] = VM_REG_GUEST_RCX, - [REG_EDX] = VM_REG_GUEST_RDX, - [REG_ESP] = VM_REG_GUEST_RSP, - [REG_EBP] = VM_REG_GUEST_RBP, - [REG_ESI] = VM_REG_GUEST_RSI, - [REG_EDI] = VM_REG_GUEST_RDI, - [REG_R8] = VM_REG_GUEST_R8, - [REG_R9] = VM_REG_GUEST_R9, - [REG_R10] = VM_REG_GUEST_R10, - [REG_R11] = VM_REG_GUEST_R11, - [REG_R12] = VM_REG_GUEST_R12, - [REG_R13] = VM_REG_GUEST_R13, - [REG_R14] = VM_REG_GUEST_R14, - [REG_R15] = VM_REG_GUEST_R15 -}; - -uint16_t one_byte_opcodes[256] = { - [0x88] = HAS_MODRM | FROM_REG | TO_RM | TO_8 | FROM_8, - [0x89] = HAS_MODRM | FROM_REG | TO_RM, - [0x8B] = HAS_MODRM | FROM_RM | TO_REG, -}; - -uint16_t two_byte_opcodes[256] = { - [0xB6] = HAS_MODRM | FROM_RM | TO_REG | ZEXT | FROM_8, - [0xB7] = HAS_MODRM | FROM_RM | TO_REG | ZEXT | FROM_16, -}; - -static uintptr_t -gla2gpa(uint64_t gla, uint64_t guest_cr3) -{ - uint64_t *table; - uint64_t mask, entry; - int level, shift; - uintptr_t page_frame; - - table = paddr_guest2host(guest_cr3 & PAGE_TABLE_ENTRY_MASK); - mask = PML4E_OFFSET_MASK; - shift = PML4E_SHIFT; - for (level = 0; level < 4; ++level) - { - entry = table[(gla & mask) >> shift]; - table = (uint64_t*)(entry & PAGE_TABLE_ENTRY_MASK); - - /* This entry does not point to another page table */ - if (entry & PAGE_FRAME_MASK || level >= 3) - break; - - table = paddr_guest2host((uintptr_t)table); - mask >>= 9; - shift -= 9; - } - - mask = (1 << shift) - 1; - page_frame = ((uintptr_t)table & ~mask); - return (page_frame | (gla & mask)); -} - -static void * -gla2hla(uint64_t gla, uint64_t guest_cr3) -{ - uintptr_t gpa; - - gpa = gla2gpa(gla, guest_cr3); - - return (paddr_guest2host(gpa)); -} - -/* - * Decodes all of the prefixes of the instruction. Only a subset of REX - * prefixes are currently supported. If any unsupported prefix is - * encountered, returns -1. - */ -static int -decode_prefixes(struct decoded_instruction *decoded) -{ - uint8_t *current_prefix; - - current_prefix = decoded->instruction; - - if (is_rex_prefix(*current_prefix)) { - decoded->rex_w = *current_prefix & REX_W_MASK; - decoded->rex_r = *current_prefix & REX_R_MASK; - decoded->rex_x = *current_prefix & REX_X_MASK; - decoded->rex_b = *current_prefix & REX_B_MASK; - current_prefix++; - } else if (is_opsz_prefix(*current_prefix)) { - decoded->opsz = 1; - current_prefix++; - } else if (is_prefix(*current_prefix)) { - return (-1); - } - - decoded->opcode = current_prefix; - return (0); -} - -/* - * Decodes the instruction's opcode. If the opcode is not understood, returns - * -1 indicating an error. Sets the instruction's mod_rm pointer to the - * location of the ModR/M field. - */ -static int -decode_opcode(struct decoded_instruction *decoded) -{ - uint8_t opcode; - uint16_t flags; - int extra; - - opcode = *decoded->opcode; - extra = 0; - - if (opcode != 0xf) - flags = one_byte_opcodes[opcode]; - else { - opcode = *(decoded->opcode + 1); - flags = two_byte_opcodes[opcode]; - extra = 1; - } - - if (!flags) - return (-1); - - if (flags & HAS_MODRM) { - decoded->modrm = decoded->opcode + 1 + extra; - } - - decoded->opcode_flags = flags; - - return (0); -} - -/* - * Decodes the instruction's ModR/M field. Sets the instruction's sib pointer - * to the location of the SIB if one is expected to be present, or 0 if not. - */ -static int -decode_mod_rm(struct decoded_instruction *decoded) -{ - uint8_t modrm; - uint8_t *extension_operands; - - if (decoded->modrm) { - modrm = *decoded->modrm; - - decoded->addressing_mode = (modrm & MODRM_MOD_MASK) >> MODRM_MOD_SHIFT; - decoded->rm = (modrm & MODRM_RM_MASK) >> MODRM_RM_SHIFT; - decoded->reg = (modrm & MODRM_REG_MASK) >> MODRM_REG_SHIFT; - - if (decoded->rex_b) - decoded->rm |= (1<<3); - - if (decoded->rex_r) - decoded->reg |= (1<<3); - - extension_operands = decoded->modrm + 1; - - if (decoded->rm == RM_SIB) { - decoded->sib = decoded->modrm + 1; - extension_operands = decoded->sib + 1; - } - - switch (decoded->addressing_mode) { - case MOD_INDIRECT: - case MOD_DIRECT: - decoded->displacement = 0; - break; - case MOD_INDIRECT_DISP8: - decoded->displacement = extension_operands; - break; - case MOD_INDIRECT_DISP32: - decoded->displacement = extension_operands; - break; - } - } - - return (0); -} - -/* - * Decodes the instruction's SIB field. No such instructions are currently - * supported, so do nothing and return -1 if there is a SIB field, 0 otherwise. - */ -static int -decode_sib(struct decoded_instruction *decoded) -{ - - if (decoded->sib) - return (-1); - - return (0); -} - -/* - * Grabs and saves the instruction's immediate operand and displacement if - * they are present. Immediates are not currently supported, so if an - * immediate is present it will return -1 indicating an error. - */ -static int -decode_extension_operands(struct decoded_instruction *decoded) -{ - - if (decoded->displacement) { - if (decoded->addressing_mode == MOD_INDIRECT_DISP8) { - decoded->disp = *((int8_t *)decoded->displacement); - } else if (decoded->addressing_mode == MOD_INDIRECT_DISP32) { - decoded->disp = *((int32_t *)decoded->displacement); - } - } - - if (decoded->immediate) { - return (-1); - } - - return (0); -} - -static int -decode_instruction(void *instr, struct decoded_instruction *decoded) -{ - int error; - - bzero(decoded, sizeof(*decoded)); - decoded->instruction = instr; - - error = decode_prefixes(decoded); - if (error) - return (error); - - error = decode_opcode(decoded); - if (error) - return (error); - - error = decode_mod_rm(decoded); - if (error) - return (error); - - error = decode_sib(decoded); - if (error) - return (error); - - error = decode_extension_operands(decoded); - if (error) - return (error); - - return (0); -} - -static enum vm_reg_name -get_vm_reg_name(uint8_t reg) -{ - - return (vm_reg_name_mappings[reg]); -} - -static uint64_t -adjust_operand(const struct decoded_instruction *instruction, uint64_t val, - int size) -{ - uint64_t ret; - - if (instruction->opcode_flags & ZEXT) { - switch (size) { - case 1: - ret = val & 0xff; - break; - case 2: - ret = val & 0xffff; - break; - case 4: - ret = val & 0xffffffff; - break; - case 8: - ret = val; - break; - default: - break; - } - } else { - /* - * Extend the sign - */ - switch (size) { - case 1: - ret = (int8_t)(val & 0xff); - break; - case 2: - ret = (int16_t)(val & 0xffff); - break; - case 4: - ret = (int32_t)(val & 0xffffffff); - break; - case 8: - ret = val; - break; - default: - break; - } - } - - return (ret); -} - -static int -get_operand(struct vmctx *vm, int vcpu, uint64_t gpa, uint64_t guest_cr3, - const struct decoded_instruction *instruction, uint64_t *operand, - struct mem_range *mr) -{ - enum vm_reg_name regname; - uint64_t reg; - int error; - uint8_t rm, addressing_mode, size; - - if (instruction->opcode_flags & FROM_RM) { - rm = instruction->rm; - addressing_mode = instruction->addressing_mode; - } else if (instruction->opcode_flags & FROM_REG) { - rm = instruction->reg; - addressing_mode = MOD_DIRECT; - } else - return (-1); - - /* - * Determine size of operand - */ - size = 4; - if (instruction->opcode_flags & FROM_8) { - size = 1; - } else if (instruction->opcode_flags & FROM_16 || - instruction->opsz) { - size = 2; - } - - regname = get_vm_reg_name(rm); - error = vm_get_register(vm, vcpu, regname, ®); - if (error) - return (error); - - switch (addressing_mode) { - case MOD_DIRECT: - *operand = reg; - error = 0; - break; - case MOD_INDIRECT: - case MOD_INDIRECT_DISP8: - case MOD_INDIRECT_DISP32: -#ifdef INSTR_VERIFY - { - uintptr_t target; - - target = gla2gpa(reg, guest_cr3); - target += instruction->disp; - assert(gpa == target); - } -#endif - error = (*mr->handler)(vm, vcpu, MEM_F_READ, gpa, size, - operand, mr->arg1, mr->arg2); - break; - default: - return (-1); - } - - if (!error) - *operand = adjust_operand(instruction, *operand, size); - - return (error); -} - -static uint64_t -adjust_write(uint64_t reg, uint64_t operand, int size) -{ - uint64_t val; - - switch (size) { - case 1: - val = (reg & ~0xff) | (operand & 0xff); - break; - case 2: - val = (reg & ~0xffff) | (operand & 0xffff); - break; - case 4: - val = (reg & ~0xffffffff) | (operand & 0xffffffff); - break; - case 8: - val = operand; - default: - break; - } - - return (val); -} - -static int -perform_write(struct vmctx *vm, int vcpu, uint64_t gpa, uint64_t guest_cr3, - const struct decoded_instruction *instruction, uint64_t operand, - struct mem_range *mr) -{ - enum vm_reg_name regname; - uintptr_t target; - int error; - int size; - uint64_t reg; - uint8_t addressing_mode; - - if (instruction->opcode_flags & TO_RM) { - reg = instruction->rm; - addressing_mode = instruction->addressing_mode; - } else if (instruction->opcode_flags & TO_REG) { - reg = instruction->reg; - addressing_mode = MOD_DIRECT; - } else - return (-1); - - /* - * Determine the operand size. rex.w has priority - */ - size = 4; - if (instruction->rex_w) { - size = 8; - } else if (instruction->opcode_flags & TO_8) { - size = 1; - } else if (instruction->opsz) { - size = 2; - }; - - switch(addressing_mode) { - case MOD_DIRECT: - regname = get_vm_reg_name(reg); - error = vm_get_register(vm, vcpu, regname, ®); - if (error) - return (error); - operand = adjust_write(reg, operand, size); - - return (vm_set_register(vm, vcpu, regname, operand)); - case MOD_INDIRECT: - case MOD_INDIRECT_DISP8: - case MOD_INDIRECT_DISP32: -#ifdef INSTR_VERIFY - regname = get_vm_reg_name(reg); - error = vm_get_register(vm, vcpu, regname, ®); - assert(!error); - target = gla2gpa(reg, guest_cr3); - target += instruction->disp; - assert(gpa == target); -#endif - error = (*mr->handler)(vm, vcpu, MEM_F_WRITE, gpa, size, - &operand, mr->arg1, mr->arg2); - return (error); - default: - return (-1); - } -} - -static int -emulate_decoded_instruction(struct vmctx *vm, int vcpu, uint64_t gpa, - uint64_t cr3, - const struct decoded_instruction *instruction, - struct mem_range *mr) -{ - uint64_t operand; - int error; - - error = get_operand(vm, vcpu, gpa, cr3, instruction, &operand, mr); - if (error) - return (error); - - return perform_write(vm, vcpu, gpa, cr3, instruction, operand, mr); -} - -int -emulate_instruction(struct vmctx *vm, int vcpu, uint64_t rip, uint64_t cr3, - uint64_t gpa, int flags, struct mem_range *mr) -{ - struct decoded_instruction instr; - int error; - void *instruction; - - instruction = gla2hla(rip, cr3); - - error = decode_instruction(instruction, &instr); - if (!error) - error = emulate_decoded_instruction(vm, vcpu, gpa, cr3, - &instr, mr); - - return (error); -} diff --git a/usr.sbin/bhyve/instruction_emul.h b/usr.sbin/bhyve/instruction_emul.h deleted file mode 100644 index ef85796..0000000 --- a/usr.sbin/bhyve/instruction_emul.h +++ /dev/null @@ -1,36 +0,0 @@ -/*- - * Copyright (c) 2012 Sandvine, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _INSTRUCTION_EMUL_H_ -#define _INSTRUCTION_EMUL_H_ - -int emulate_instruction(struct vmctx *vm, int vcpu, uint64_t rip, - uint64_t cr3, uint64_t gpa, int flags, - struct mem_range *mr); - -#endif diff --git a/usr.sbin/bhyve/ioapic.c b/usr.sbin/bhyve/ioapic.c index ea6e47c..47dd833 100644 --- a/usr.sbin/bhyve/ioapic.c +++ b/usr.sbin/bhyve/ioapic.c @@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$"); #include "inout.h" #include "mem.h" -#include "instruction_emul.h" #include "fbsdrun.h" #include <stdio.h> diff --git a/usr.sbin/bhyve/mem.c b/usr.sbin/bhyve/mem.c index deb91dc..dc43ff4 100644 --- a/usr.sbin/bhyve/mem.c +++ b/usr.sbin/bhyve/mem.c @@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$"); #include <assert.h> #include "mem.h" -#include "instruction_emul.h" struct mmio_rb_range { RB_ENTRY(mmio_rb_range) mr_link; /* RB tree links */ @@ -134,33 +133,57 @@ mmio_rb_dump(void) RB_GENERATE(mmio_rb_tree, mmio_rb_range, mr_link, mmio_rb_range_compare); +static int +mem_read(void *ctx, int vcpu, uint64_t gpa, uint64_t *rval, int size, void *arg) +{ + int error; + struct mem_range *mr = arg; + + error = (*mr->handler)(ctx, vcpu, MEM_F_READ, gpa, size, + rval, mr->arg1, mr->arg2); + return (error); +} + +static int +mem_write(void *ctx, int vcpu, uint64_t gpa, uint64_t wval, int size, void *arg) +{ + int error; + struct mem_range *mr = arg; + + error = (*mr->handler)(ctx, vcpu, MEM_F_WRITE, gpa, size, + &wval, mr->arg1, mr->arg2); + return (error); +} + int emulate_mem(struct vmctx *ctx, int vcpu, uint64_t paddr, uint64_t rip, - uint64_t cr3, int mode) + uint64_t cr3, int mode, struct vie *vie) { struct mmio_rb_range *entry; int err; - err = 0; - /* * First check the per-vCPU cache */ if (mmio_hint[vcpu] && paddr >= mmio_hint[vcpu]->mr_base && paddr <= mmio_hint[vcpu]->mr_end) { - err = emulate_instruction(ctx, vcpu, rip, cr3, paddr, mode, - &mmio_hint[vcpu]->mr_param); - } else { - if (mmio_rb_lookup(paddr, &entry)) { - err = ENOENT; - } else { - mmio_hint[vcpu] = entry; - err = emulate_instruction(ctx, vcpu, rip, cr3, paddr, - mode, &entry->mr_param); - } + entry = mmio_hint[vcpu]; + } else + entry = NULL; + + if (entry == NULL) { + if (mmio_rb_lookup(paddr, &entry)) + return (ESRCH); + + /* Update the per-vCPU cache */ + mmio_hint[vcpu] = entry; } + assert(entry != NULL && entry == mmio_hint[vcpu]); + + err = vmm_emulate_instruction(ctx, vcpu, paddr, vie, + mem_read, mem_write, &entry->mr_param); return (err); } diff --git a/usr.sbin/bhyve/mem.h b/usr.sbin/bhyve/mem.h index 53c4f72..b34c1fd 100644 --- a/usr.sbin/bhyve/mem.h +++ b/usr.sbin/bhyve/mem.h @@ -51,7 +51,7 @@ struct mem_range { void init_mem(void); int emulate_mem(struct vmctx *, int vcpu, uint64_t paddr, uint64_t rip, - uint64_t cr3, int mode); + uint64_t cr3, int mode, struct vie *vie); int register_mem(struct mem_range *memp); diff --git a/usr.sbin/bhyve/pci_passthru.c b/usr.sbin/bhyve/pci_passthru.c index 7ac6e3d..28abb6b 100644 --- a/usr.sbin/bhyve/pci_passthru.c +++ b/usr.sbin/bhyve/pci_passthru.c @@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$"); #include <vmmapi.h> #include "pci_emul.h" #include "mem.h" -#include "instruction_emul.h" #ifndef _PATH_DEVPCI #define _PATH_DEVPCI "/dev/pci" |