Index: lib/libvmmapi/vmmapi.h =================================================================== --- lib/libvmmapi/vmmapi.h +++ lib/libvmmapi/vmmapi.h @@ -34,6 +34,8 @@ #include #include +#include + /* * API version for out-of-tree consumers like grub-bhyve for making compile * time decisions. @@ -147,6 +149,8 @@ int vm_ioapic_deassert_irq(struct vmctx *ctx, int irq); int vm_ioapic_pulse_irq(struct vmctx *ctx, int irq); int vm_ioapic_pincount(struct vmctx *ctx, int *pincount); +int vm_readwrite_kernemu_device(struct vmctx *ctx, int vcpu, + vm_paddr_t gpa, bool write, int size, uint64_t *value); int vm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq); int vm_isa_deassert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq); int vm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq); Index: lib/libvmmapi/vmmapi.c =================================================================== --- lib/libvmmapi/vmmapi.c +++ lib/libvmmapi/vmmapi.c @@ -756,6 +756,25 @@ return (ioctl(ctx->fd, VM_IOAPIC_PINCOUNT, pincount)); } +int +vm_readwrite_kernemu_device(struct vmctx *ctx, int vcpu, vm_paddr_t gpa, + bool write, int size, uint64_t *value) +{ + struct vm_readwrite_kernemu_device irp = { + .vcpuid = vcpu, + .write = write, + .access_width = fls(size) - 1, + .gpa = gpa, + .value = write ? *value : ~0ul, + }; + int rc; + + rc = ioctl(ctx->fd, VM_READWRITE_KERNEMU_DEV, &irp); + if (rc == 0 && !write) + *value = irp.value; + return (rc); +} + int vm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) { Index: sys/amd64/include/vmm_dev.h =================================================================== --- sys/amd64/include/vmm_dev.h +++ sys/amd64/include/vmm_dev.h @@ -233,6 +233,16 @@ uint16_t maxcpus; }; +struct vm_readwrite_kernemu_device { + int vcpuid; + unsigned write : 1; + unsigned access_width : 3; + unsigned _unused : 28; + uint64_t gpa; + uint64_t value; +}; +_Static_assert(sizeof(struct vm_readwrite_kernemu_device) == 24, "ABI"); + enum { /* general routines */ IOCNUM_ABIVERS = 0, @@ -260,6 +270,7 @@ IOCNUM_GET_SEGMENT_DESCRIPTOR = 23, IOCNUM_SET_REGISTER_SET = 24, IOCNUM_GET_REGISTER_SET = 25, + IOCNUM_READWRITE_KERNEMU_DEV = 26, /* interrupt injection */ IOCNUM_GET_INTINFO = 28, @@ -340,6 +351,9 @@ _IOW('v', IOCNUM_SET_REGISTER_SET, struct vm_register_set) #define VM_GET_REGISTER_SET \ _IOWR('v', IOCNUM_GET_REGISTER_SET, struct vm_register_set) +#define VM_READWRITE_KERNEMU_DEV \ + _IOWR('v', IOCNUM_READWRITE_KERNEMU_DEV, \ + struct vm_readwrite_kernemu_device) #define VM_INJECT_EXCEPTION \ _IOW('v', IOCNUM_INJECT_EXCEPTION, struct vm_exception) #define VM_LAPIC_IRQ \ Index: sys/amd64/vmm/vmm_dev.c =================================================================== --- sys/amd64/vmm/vmm_dev.c +++ sys/amd64/vmm/vmm_dev.c @@ -55,6 +55,7 @@ #include #include #include +#include #include "vmm_lapic.h" #include "vmm_stat.h" @@ -379,6 +380,7 @@ struct vm_rtc_data *rtcdata; struct vm_memmap *mm; struct vm_cpu_topology *topology; + struct vm_readwrite_kernemu_device *kernemu; uint64_t *regvals; int *regnums; @@ -555,6 +557,40 @@ case VM_IOAPIC_PINCOUNT: *(int *)data = vioapic_pincount(sc->vm); break; + case VM_READWRITE_KERNEMU_DEV: { + mem_region_write_t mwrite; + mem_region_read_t mread; + bool arg; + + kernemu = (void *)data; + + if (kernemu->access_width > 0) + size = (1u << kernemu->access_width); + else + size = 1; + + if (kernemu->gpa >= DEFAULT_APIC_BASE && kernemu->gpa < DEFAULT_APIC_BASE + PAGE_SIZE) { + mread = lapic_mmio_read; + mwrite = lapic_mmio_write; + } else if (kernemu->gpa >= VIOAPIC_BASE && kernemu->gpa < VIOAPIC_BASE + VIOAPIC_SIZE) { + mread = vioapic_mmio_read; + mwrite = vioapic_mmio_write; + } else if (kernemu->gpa >= VHPET_BASE && kernemu->gpa < VHPET_BASE + VHPET_SIZE) { + mread = vhpet_mmio_read; + mwrite = vhpet_mmio_write; + } else { + error = EINVAL; + break; + } + + if (kernemu->write) + error = mwrite(sc->vm, kernemu->vcpuid, kernemu->gpa, + kernemu->value, size, &arg); + else + error = mread(sc->vm, kernemu->vcpuid, kernemu->gpa, + &kernemu->value, size, &arg); + break; + } case VM_ISA_ASSERT_IRQ: isa_irq = (struct vm_isa_irq *)data; error = vatpic_assert_irq(sc->vm, isa_irq->atpic_irq); Index: usr.sbin/bhyve/Makefile =================================================================== --- usr.sbin/bhyve/Makefile +++ usr.sbin/bhyve/Makefile @@ -16,6 +16,7 @@ SRCS= \ atkbdc.c \ acpi.c \ + apic.c \ audio.c \ bhyvegc.c \ bhyverun.c \ @@ -72,6 +73,8 @@ spinup_ap.c \ iov.c +CFLAGS.apic.c+= -I${SRCTOP}/sys/amd64 + .PATH: ${BHYVE_SYSDIR}/sys/amd64/vmm SRCS+= vmm_instruction_emul.c Index: usr.sbin/bhyve/apic.h =================================================================== --- /dev/null +++ usr.sbin/bhyve/apic.h @@ -0,0 +1,32 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright 2020 Conrad Meyer . 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 THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR 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$ + */ + +#pragma once + +void apic_init(void); Index: usr.sbin/bhyve/apic.c =================================================================== --- /dev/null +++ usr.sbin/bhyve/apic.c @@ -0,0 +1,98 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright 2020 Conrad Meyer . 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 THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR 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. + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +struct vm; +struct vm_hpet_cap; +#include +#include + +#include +#include +#include + +#include "apic.h" +#include "mem.h" + +static int +apic_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr, int size, + uint64_t *val, void *arg1 __unused, long arg2 __unused) +{ + if (vm_readwrite_kernemu_device(ctx, vcpu, addr, (dir == MEM_F_WRITE), + size, val) != 0) + return (errno); + return (0); +} + +static struct mem_range lapic_mmio = { + .name = "kern-lapic-mmio", + .base = DEFAULT_APIC_BASE, + .size = PAGE_SIZE, + .flags = MEM_F_RW | MEM_F_IMMUTABLE, + .handler = apic_handler, + +}; +static struct mem_range ioapic_mmio = { + .name = "kern-ioapic-mmio", + .base = VIOAPIC_BASE, + .size = VIOAPIC_SIZE, + .flags = MEM_F_RW | MEM_F_IMMUTABLE, + .handler = apic_handler, +}; +static struct mem_range hpet_mmio = { + .name = "kern-hpet-mmio", + .base = VHPET_BASE, + .size = VHPET_SIZE, + .flags = MEM_F_RW | MEM_F_IMMUTABLE, + .handler = apic_handler, +}; + +void +apic_init(void) +{ + int rc; + + rc = register_mem(&lapic_mmio); + if (rc != 0) + errc(4, rc, "register_mem: LAPIC (0x%08x)", + (unsigned)lapic_mmio.base); + rc = register_mem(&ioapic_mmio); + if (rc != 0) + errc(4, rc, "register_mem: IOAPIC (0x%08x)", + (unsigned)ioapic_mmio.base); + rc = register_mem(&hpet_mmio); + if (rc != 0) + errc(4, rc, "register_mem: HPET (0x%08x)", + (unsigned)hpet_mmio.base); +} Index: usr.sbin/bhyve/bhyverun.c =================================================================== --- usr.sbin/bhyve/bhyverun.c +++ usr.sbin/bhyve/bhyverun.c @@ -69,6 +69,7 @@ #include "bhyverun.h" #include "acpi.h" +#include "apic.h" #include "atkbdc.h" #include "bootrom.h" #include "inout.h" @@ -1176,6 +1177,7 @@ init_mem(); init_inout(); + apic_init(); init_bootrom(ctx); atkbdc_init(ctx); pci_irq_init(ctx);