Page MenuHomeFreeBSD

D26506.id.diff
No OneTemporary

D26506.id.diff

Index: lib/libvmmapi/vmmapi.h
===================================================================
--- lib/libvmmapi/vmmapi.h
+++ lib/libvmmapi/vmmapi.h
@@ -41,7 +41,7 @@
* API version for out-of-tree consumers like grub-bhyve for making compile
* time decisions.
*/
-#define VMMAPI_VERSION 0103 /* 2 digit major followed by 2 digit minor */
+#define VMMAPI_VERSION 0104 /* 2 digit major followed by 2 digit minor */
struct iovec;
struct vmctx;
@@ -73,6 +73,8 @@
VM_SYSMEM,
VM_BOOTROM,
VM_FRAMEBUFFER,
+ VM_VIDEOBIOS,
+ VM_NOTHING /* Last entry */
};
/*
@@ -111,6 +113,12 @@
int vm_mmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, int segid,
vm_ooffset_t segoff, size_t len, int prot);
+/*
+ * Unmap a memory segment previously mapped with the given parameters.
+ */
+int vm_munmap_memseg(struct vmctx *ctx, vm_paddr_t gpa,
+ int segid, vm_ooffset_t segoff);
+
int vm_create(const char *name);
int vm_get_device_fd(struct vmctx *ctx);
struct vmctx *vm_open(const char *name);
@@ -176,6 +184,8 @@
int vm_unassign_pptdev(struct vmctx *ctx, int bus, int slot, int func);
int vm_map_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func,
vm_paddr_t gpa, size_t len, vm_paddr_t hpa);
+int vm_get_vbios(struct vmctx *ctx, int bus, int slot, int func,
+ uint16_t vendor, uint16_t dev_id, void *bios, uint64_t *size);
int vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot,
int func, uint64_t addr, uint64_t msg, int numvec);
int vm_setup_pptdev_msix(struct vmctx *ctx, int vcpu, int bus, int slot,
Index: lib/libvmmapi/vmmapi.c
===================================================================
--- lib/libvmmapi/vmmapi.c
+++ lib/libvmmapi/vmmapi.c
@@ -61,9 +61,13 @@
#include "vmmapi.h"
+#define KB (1024UL)
#define MB (1024 * 1024UL)
#define GB (1024 * 1024 * 1024UL)
+#define VGAMEM_START (640*KB)
+#define VGAMEM_END (VGAMEM_START + 128*KB)
+
/*
* Size of the guard region before and after the virtual address space
* mapping the guest physical memory. This must be a multiple of the
@@ -87,6 +91,10 @@
#define CREATE(x) sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x)))
#define DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x)))
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
static int
vm_device_open(const char *name)
{
@@ -227,8 +235,10 @@
*/
error = vm_mmap_getnext(ctx, &gpa, &segid, &off, &len, &prot, &flags);
if (error == 0 && gpa == memmap.gpa) {
- if (segid != memmap.segid || off != memmap.segoff ||
- prot != memmap.prot || flags != memmap.flags) {
+ /* Allow other segments to align with SYSMEM borders */
+ if ((segid != VM_SYSMEM || memmap.segid == VM_SYSMEM) &&
+ (segid != memmap.segid || off != memmap.segoff ||
+ prot != memmap.prot || flags != memmap.flags)) {
errno = EEXIST;
return (-1);
} else {
@@ -251,6 +261,24 @@
return (0);
}
+int
+vm_munmap_memseg(struct vmctx *ctx, vm_paddr_t gpa,
+ int segid, vm_ooffset_t segoff)
+{
+ struct vm_memmap memmap;
+ int error;
+
+ memmap.gpa = gpa;
+ memmap.segid = segid;
+ memmap.segoff = segoff;
+ memmap.len = 0;
+ memmap.prot = 0;
+ memmap.flags = 0;
+
+ error = ioctl(ctx->fd, VM_MMAP_MEMSEG, &memmap);
+ return (error);
+}
+
int
vm_mmap_getnext(struct vmctx *ctx, vm_paddr_t *gpa, int *segid,
vm_ooffset_t *segoff, size_t *len, int *prot, int *flags)
@@ -420,9 +448,23 @@
return (error);
}
+ /*
+ * Leave a memory hole for VGA memory.
+ */
+ if (ctx->lowmem > VGAMEM_END) {
+ gpa = VGAMEM_END;
+ len = ctx->lowmem - VGAMEM_END;
+ error = setup_memory_segment(ctx, gpa, len, baseaddr);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Add up to 640 KB of base memory.
+ */
if (ctx->lowmem > 0) {
gpa = 0;
- len = ctx->lowmem;
+ len = min(ctx->lowmem, VGAMEM_START);
error = setup_memory_segment(ctx, gpa, len, baseaddr);
if (error)
return (error);
@@ -446,7 +488,13 @@
if (ctx->lowmem > 0) {
if (gaddr < ctx->lowmem && len <= ctx->lowmem &&
- gaddr + len <= ctx->lowmem)
+ gaddr + len <= VGAMEM_START)
+ return (ctx->baseaddr + gaddr);
+ }
+
+ if (ctx->lowmem > VGAMEM_END) {
+ if (gaddr >= VGAMEM_END && gaddr < ctx->lowmem &&
+ len <= ctx->lowmem && gaddr + len <= ctx->lowmem)
return (ctx->baseaddr + gaddr);
}
@@ -980,6 +1028,33 @@
return (ioctl(ctx->fd, VM_MAP_PPTDEV_MMIO, &pptmmio));
}
+int
+vm_get_vbios(struct vmctx *ctx, int bus, int slot, int func,
+ uint16_t vendor, uint16_t dev_id, void *bios, uint64_t *size)
+{
+ int error;
+ struct vm_vbios vbios;
+
+ bzero(&vbios, sizeof(vbios));
+ vbios.bus = bus;
+ vbios.slot = slot;
+ vbios.func = func;
+ vbios.vendor = vendor;
+ vbios.dev_id = dev_id;
+ vbios.bios = bios;
+ if (size != NULL)
+ vbios.size = *size;
+ else
+ vbios.size = 0;
+
+ error = ioctl(ctx->fd, VM_GET_VBIOS, &vbios);
+
+ if (size)
+ *size = vbios.size;
+
+ return (error);
+}
+
int
vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func,
uint64_t addr, uint64_t msg, int numvec)
@@ -1311,10 +1386,6 @@
return (error);
}
-#ifndef min
-#define min(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
int
vm_copy_setup(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging,
uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt,
@@ -1641,8 +1712,8 @@
VM_ISA_DEASSERT_IRQ, VM_ISA_PULSE_IRQ, VM_ISA_SET_IRQ_TRIGGER,
VM_SET_CAPABILITY, VM_GET_CAPABILITY, VM_BIND_PPTDEV,
VM_UNBIND_PPTDEV, VM_MAP_PPTDEV_MMIO, VM_PPTDEV_MSI,
- VM_PPTDEV_MSIX, VM_INJECT_NMI, VM_STATS, VM_STAT_DESC,
- VM_SET_X2APIC_STATE, VM_GET_X2APIC_STATE,
+ VM_PPTDEV_MSIX, VM_GET_VBIOS, VM_INJECT_NMI,
+ VM_STATS, VM_STAT_DESC, VM_SET_X2APIC_STATE, VM_GET_X2APIC_STATE,
VM_GET_HPET_CAPABILITIES, VM_GET_GPA_PMAP, VM_GLA2GPA,
VM_GLA2GPA_NOFAULT,
VM_ACTIVATE_CPU, VM_GET_CPUS, VM_SUSPEND_CPU, VM_RESUME_CPU,
Index: sys/amd64/include/vmm_dev.h
===================================================================
--- sys/amd64/include/vmm_dev.h
+++ sys/amd64/include/vmm_dev.h
@@ -141,6 +141,16 @@
size_t len;
};
+struct vm_vbios {
+ int bus;
+ int slot;
+ int func;
+ uint16_t vendor;
+ uint16_t dev_id;
+ void *bios;
+ uint64_t size;
+};
+
struct vm_pptdev_msi {
int vcpu;
int bus;
@@ -301,6 +311,7 @@
IOCNUM_MAP_PPTDEV_MMIO = 42,
IOCNUM_PPTDEV_MSI = 43,
IOCNUM_PPTDEV_MSIX = 44,
+ IOCNUM_GET_VBIOS = 46,
/* statistics */
IOCNUM_VM_STATS = 50,
@@ -413,6 +424,8 @@
_IOW('v', IOCNUM_PPTDEV_MSI, struct vm_pptdev_msi)
#define VM_PPTDEV_MSIX \
_IOW('v', IOCNUM_PPTDEV_MSIX, struct vm_pptdev_msix)
+#define VM_GET_VBIOS \
+ _IOWR('v', IOCNUM_GET_VBIOS, struct vm_vbios)
#define VM_INJECT_NMI \
_IOW('v', IOCNUM_INJECT_NMI, struct vm_nmi)
#define VM_STATS \
Index: sys/amd64/vmm/amd/amdgpu.h
===================================================================
--- /dev/null
+++ sys/amd64/vmm/amd/amdgpu.h
@@ -0,0 +1,10 @@
+
+#ifndef _AMD_AMDGPU_H_
+#define _AMD_AMDGPU_H_
+
+#include <machine/vmm_dev.h>
+
+int vm_amdgpu_get_vbios(struct vm *vm, int bus, int slot, int func,
+ uint16_t vendor, uint16_t dev_id, void *bios, uint64_t *size);
+
+#endif /* !_AMD_AMDGPU_H_ */
Index: sys/amd64/vmm/amd/amdgpu.c
===================================================================
--- /dev/null
+++ sys/amd64/vmm/amd/amdgpu.c
@@ -0,0 +1,270 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+
+
+#include <sys/param.h>
+#include <sys/bitstring.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/rangeset.h>
+#include <sys/rwlock.h>
+#include <sys/sbuf.h>
+#include <sys/sx.h>
+#include <sys/turnstile.h>
+#include <sys/vmem.h>
+#include <sys/vmmeter.h>
+#include <sys/sched.h>
+#include <sys/sysctl.h>
+#include <sys/smp.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_pageout.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_phys.h>
+#include <vm/vm_radix.h>
+#include <vm/vm_reserv.h>
+#include <vm/uma.h>
+
+#include <machine/pmap.h>
+#include <machine/vmm.h>
+#include <machine/vmparam.h>
+
+#include "amd/amdgpu.h"
+#include "contrib/dev/acpica/include/acpi.h"
+#include "contrib/dev/acpica/include/acpixf.h"
+
+#define GFP_NATIVE_MASK (M_NOWAIT | M_WAITOK | M_USE_RESERVE | M_ZERO)
+#define GFP_KERNEL M_WAITOK
+
+//MALLOC_DECLARE(M_KMALLOC);
+MALLOC_DECLARE(M_VMMDEV);
+
+typedef unsigned gfp_t;
+
+static inline gfp_t
+linux_check_m_flags(gfp_t flags)
+{
+ const gfp_t m = M_NOWAIT | M_WAITOK;
+
+ /* make sure either M_NOWAIT or M_WAITOK is set */
+ if ((flags & m) == 0)
+ flags |= M_NOWAIT;
+ else if ((flags & m) == m)
+ flags &= ~M_WAITOK;
+
+ /* mask away LinuxKPI specific flags */
+ return (flags & GFP_NATIVE_MASK);
+}
+
+static inline void *
+kmalloc(size_t size, gfp_t flags)
+{
+ return (malloc(size, M_VMMDEV, linux_check_m_flags(flags)));
+}
+
+static inline void
+kfree(const void *ptr)
+{
+ free(__DECONST(void *, ptr), M_VMMDEV);
+}
+
+static inline void *
+kmemdup(const void *src, size_t len, gfp_t gfp)
+{
+ void *dst;
+
+ dst = kmalloc(len, gfp);
+ if (dst != NULL) {
+ memcpy(dst, src, len);
+ }
+ return (dst);
+}
+
+#define AMD_VBIOS_SIGNATURE " 761295520"
+#define AMD_VBIOS_SIGNATURE_OFFSET 0x30
+#define AMD_VBIOS_SIGNATURE_SIZE sizeof(AMD_VBIOS_SIGNATURE)
+#define AMD_VBIOS_SIGNATURE_END (AMD_VBIOS_SIGNATURE_OFFSET + AMD_VBIOS_SIGNATURE_SIZE)
+#define AMD_IS_VALID_VBIOS(p) ((p)[0] == 0x55 && (p)[1] == 0xAA)
+#define AMD_VBIOS_LENGTH(p) ((p)[2] << 9)
+
+#define acpi_get_table AcpiGetTable
+
+typedef struct {
+ uint32_t Signature;
+ uint32_t TableLength; //Length
+ uint8_t Revision;
+ uint8_t Checksum;
+ uint8_t OemId[6];
+ uint8_t OemTableId[8]; //UINT64 OemTableId;
+ uint32_t OemRevision;
+ uint32_t CreatorId;
+ uint32_t CreatorRevision;
+} AMD_ACPI_DESCRIPTION_HEADER;
+
+typedef struct {
+ AMD_ACPI_DESCRIPTION_HEADER SHeader;
+ uint8_t TableUUID[16]; //0x24
+ uint32_t VBIOSImageOffset; //0x34. Offset to the first GOP_VBIOS_CONTENT block from the beginning of the stucture.
+ uint32_t Lib1ImageOffset; //0x38. Offset to the first GOP_LIB1_CONTENT block from the beginning of the stucture.
+ uint32_t Reserved[4]; //0x3C
+}UEFI_ACPI_VFCT;
+
+typedef struct {
+ uint32_t PCIBus; //0x4C
+ uint32_t PCIDevice; //0x50
+ uint32_t PCIFunction; //0x54
+ uint16_t VendorID; //0x58
+ uint16_t DeviceID; //0x5A
+ uint16_t SSVID; //0x5C
+ uint16_t SSID; //0x5E
+ uint32_t Revision; //0x60
+ uint32_t ImageLength; //0x64
+}VFCT_IMAGE_HEADER;
+
+
+typedef struct {
+ VFCT_IMAGE_HEADER VbiosHeader;
+ uint8_t VbiosContent[1];
+}GOP_VBIOS_CONTENT;
+
+/* Check if current bios is an ATOM BIOS.
+ * Return true if it is ATOM BIOS. Otherwise, return false.
+ */
+static bool check_atom_bios(uint8_t *bios, size_t size)
+{
+ uint16_t tmp, bios_header_start;
+
+ if (!bios || size < 0x49) {
+ // vbios mem is null or mem size is wrong
+ return false;
+ }
+
+ if (!AMD_IS_VALID_VBIOS(bios)) {
+ // BIOS signature incorrect
+ return false;
+ }
+
+ bios_header_start = bios[0x48] | (bios[0x49] << 8);
+ if (!bios_header_start) {
+ // Can't locate bios header
+ return false;
+ }
+
+ tmp = bios_header_start + 4;
+ if (size < tmp) {
+ // BIOS header is broken
+ return false;
+ }
+
+ if (!memcmp(bios + tmp, "ATOM", 4) ||
+ !memcmp(bios + tmp, "MOTA", 4)) {
+ // ATOMBIOS detected
+ return true;
+ }
+
+ return false;
+}
+
+static int
+amdgpu_get_vbios_vfct(struct vm *vm, int bus, int slot, int func,
+ uint16_t vendor, uint16_t dev_id, void **bios, uint64_t *size)
+{
+ if (vm == NULL || bios == NULL || size == NULL)
+ return EINVAL;
+
+ struct acpi_table_header *hdr;
+ uint32_t tbl_size;
+ UEFI_ACPI_VFCT *vfct;
+ unsigned offset;
+
+ if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
+ return ENOENT;
+
+ tbl_size = hdr->Length;
+
+ if (tbl_size < sizeof(UEFI_ACPI_VFCT))
+ return ENODEV;
+
+ vfct = (UEFI_ACPI_VFCT *)hdr;
+ offset = vfct->VBIOSImageOffset;
+
+ while (offset < tbl_size) {
+ GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset);
+ VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;
+
+ offset += sizeof(VFCT_IMAGE_HEADER);
+ if (offset > tbl_size)
+ return ENODEV;
+
+ offset += vhdr->ImageLength;
+ if (offset > tbl_size)
+ return ENODEV;
+
+ if (vhdr->ImageLength &&
+ vhdr->PCIBus == bus &&
+ vhdr->PCIDevice == slot &&
+ vhdr->PCIFunction == func &&
+ vhdr->VendorID == vendor &&
+ vhdr->DeviceID == dev_id) {
+ *bios = kmemdup(&vbios->VbiosContent,
+ vhdr->ImageLength,
+ GFP_KERNEL);
+
+ if (!check_atom_bios((uint8_t *)*bios, vhdr->ImageLength)) {
+ kfree(*bios);
+ return ENODEV;
+ }
+ *size = vhdr->ImageLength;
+ return 0;
+ }
+ }
+
+ return ENOENT;
+}
+
+int
+vm_amdgpu_get_vbios(struct vm *vm, int bus, int slot, int func,
+ uint16_t vendor, uint16_t dev_id, void *bios, uint64_t *size)
+{
+ int error;
+ void *bios_base;
+ uint64_t bios_size;
+
+ error = 0;
+
+ if (amdgpu_get_vbios_vfct(vm, bus, slot, func, vendor, dev_id, &bios_base, &bios_size) == 0)
+ goto done;
+
+ return ENOENT;
+
+done:
+
+ if (bios) {
+ *size = min(bios_size, *size);
+ error = copyout(bios_base, bios, *size);
+ } else {
+ *size = bios_size;
+ }
+
+ kfree(bios_base);
+
+ return (error);
+}
Index: sys/amd64/vmm/vmm.c
===================================================================
--- sys/amd64/vmm/vmm.c
+++ sys/amd64/vmm/vmm.c
@@ -133,7 +133,7 @@
bool sysmem;
struct vm_object *object;
};
-#define VM_MAX_MEMSEGS 3
+#define VM_MAX_MEMSEGS 4
struct mem_map {
vm_paddr_t gpa;
@@ -256,6 +256,8 @@
static void vm_free_memmap(struct vm *vm, int ident);
static bool sysmem_mapping(struct vm *vm, struct mem_map *mm);
static void vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr);
+static int vm_munmap_memseg(struct vm *vm, vm_paddr_t gpa,
+ int segid, vm_ooffset_t segoff);
#ifdef KTR
static const char *
@@ -729,7 +731,7 @@
vm_ooffset_t last;
int i, error;
- if (prot == 0 || (prot & ~(VM_PROT_ALL)) != 0)
+ if ((len != 0 && prot == 0) || (prot & ~(VM_PROT_ALL)) != 0)
return (EINVAL);
if (flags & ~VM_MEMMAP_F_WIRED)
@@ -743,12 +745,16 @@
return (EINVAL);
last = first + len;
- if (first < 0 || first >= last || last > seg->len)
+ if (first < 0 || first > last || last > seg->len)
return (EINVAL);
if ((gpa | first | last) & PAGE_MASK)
return (EINVAL);
+ /* The same thing at the same place but with zero length means unmap */
+ if (len == 0)
+ return vm_munmap_memseg(vm, gpa, segid, first);
+
map = NULL;
for (i = 0; i < VM_MAX_MEMMAPS; i++) {
m = &vm->mem_maps[i];
@@ -787,6 +793,26 @@
return (0);
}
+static int
+vm_munmap_memseg(struct vm *vm, vm_paddr_t gpa, int segid, vm_ooffset_t segoff)
+{
+ struct mem_map *m;
+ int i;
+
+ for (i = 0; i < VM_MAX_MEMMAPS; i++) {
+ m = &vm->mem_maps[i];
+ if (m->gpa == gpa && m->segid == segid && m->segoff == segoff)
+ break;
+ }
+
+ if (i >= VM_MAX_MEMMAPS)
+ return (ENOENT);
+
+ vm_free_memmap(vm, i);
+
+ return (0);
+}
+
int
vm_mmap_getnext(struct vm *vm, vm_paddr_t *gpa, int *segid,
vm_ooffset_t *segoff, size_t *len, int *prot, int *flags)
Index: sys/amd64/vmm/vmm_dev.c
===================================================================
--- sys/amd64/vmm/vmm_dev.c
+++ sys/amd64/vmm/vmm_dev.c
@@ -60,6 +60,7 @@
#include <machine/vmm_snapshot.h>
#include <x86/apicreg.h>
+#include "amd/amdgpu.h"
#include "vmm_lapic.h"
#include "vmm_stat.h"
#include "vmm_mem.h"
@@ -366,6 +367,7 @@
struct vm_capability *vmcap;
struct vm_pptdev *pptdev;
struct vm_pptdev_mmio *pptmmio;
+ struct vm_vbios *vbios;
struct vm_pptdev_msi *pptmsi;
struct vm_pptdev_msix *pptmsix;
struct vm_nmi *vmnmi;
@@ -435,6 +437,7 @@
break;
case VM_MAP_PPTDEV_MMIO:
+ case VM_GET_VBIOS:
case VM_BIND_PPTDEV:
case VM_UNBIND_PPTDEV:
#ifdef COMPAT_FREEBSD12
@@ -520,6 +523,12 @@
pptmmio->func, pptmmio->gpa, pptmmio->len,
pptmmio->hpa);
break;
+ case VM_GET_VBIOS:
+ vbios = (struct vm_vbios *)data;
+ // currently only amd cpus are supported
+ error = vm_amdgpu_get_vbios(sc->vm, vbios->bus, vbios->slot, vbios->func,
+ vbios->vendor, vbios->dev_id, vbios->bios, &vbios->size);
+ break;
case VM_BIND_PPTDEV:
pptdev = (struct vm_pptdev *)data;
error = vm_assign_pptdev(sc->vm, pptdev->bus, pptdev->slot,
Index: sys/modules/vmm/Makefile
===================================================================
--- sys/modules/vmm/Makefile
+++ sys/modules/vmm/Makefile
@@ -56,7 +56,8 @@
npt.c \
ivrs_drv.c \
amdvi_hw.c \
- svm_msr.c
+ svm_msr.c \
+ amdgpu.c
.if ${KERN_OPTS:MBHYVE_SNAPSHOT} != ""
SRCS+= vmm_snapshot.c
Index: usr.sbin/bhyve/Makefile
===================================================================
--- usr.sbin/bhyve/Makefile
+++ usr.sbin/bhyve/Makefile
@@ -9,6 +9,8 @@
PROG= bhyve
PACKAGE= bhyve
+# DEBUG_FLAGS= -g -O0 --coverage -DWITHOUT_CAPSICUM
+
MAN= bhyve.8
BHYVE_SYSDIR?=${SRCTOP}
@@ -38,6 +40,7 @@
net_backends.c \
net_utils.c \
pci_ahci.c \
+ pci_apu-d.c \
pci_e82545.c \
pci_emul.c \
pci_hda.c \
@@ -103,6 +106,7 @@
LIBADD+= crypto
.endif
+CFLAGS+= -no-integrated-as
CFLAGS+= -I${BHYVE_SYSDIR}/sys/dev/e1000
CFLAGS+= -I${BHYVE_SYSDIR}/sys/dev/mii
CFLAGS+= -I${BHYVE_SYSDIR}/sys/dev/usb/controller
Index: usr.sbin/bhyve/pci_apu-d.c
===================================================================
--- /dev/null
+++ usr.sbin/bhyve/pci_apu-d.c
@@ -0,0 +1,282 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Beckhoff Automation GmbH & Co. KG
+ * 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 OR 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$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <dev/io/iodev.h>
+#include <dev/pci/pcireg.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <machine/iodev.h>
+#include <machine/vmm.h>
+
+#include "inout.h"
+#include "pci_passthru.h"
+#include "vga.h"
+
+#define KB (1024UL)
+#define MB (1024 * 1024UL)
+#define GB (1024 * 1024 * 1024UL)
+
+#define VBIOS_ADDR 0xC0000
+
+#ifndef _PATH_DEVIO
+#define _PATH_DEVIO "/dev/io"
+#endif
+
+static int iofd = -1;
+
+uint32_t rom_space = 0;
+
+static int
+passthru_port_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg)
+{
+ int error;
+ struct iodev_pio_req pio;
+ pio.access = in ? IODEV_PIO_READ : IODEV_PIO_WRITE;
+ pio.port = port;
+ pio.width = bytes;
+ pio.val = in ? 0 : *eax;
+
+ error = ioctl(iofd, IODEV_PIO, &pio);
+
+ if (in)
+ *eax = pio.val;
+
+ return error;
+}
+
+static int
+apu_d_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
+{
+ int error;
+ struct passthru_softc *sc;
+
+ error = 0;
+
+ /*
+ * That's a little hack to allow shadowing of ROM
+ * EFI copies the ROM to MMIO space
+ * Alloc 16 MB of MMIO space for nothing. So, EFI can use this space
+ */
+ if (rom_space == 0) {
+ rom_space = pci_emul_alloc_mmio(PCIBAR_MEM32, 16*MB, 16*MB-1);
+ pci_parse_slot("0:3:0,apu-d-dummy");
+ }
+
+ if ((error = passthru_init(ctx, pi, opts)) != 0)
+ goto done;
+
+ sc = pi->pi_arg;
+
+ // enable mem and io
+ int16_t cmd;
+ cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
+ cmd |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
+ pci_set_cfgdata16(pi, PCIR_COMMAND, cmd);
+ cmd = read_config(&sc->psc_sel, PCIR_COMMAND, 0x02);
+ cmd |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
+ write_config(&sc->psc_sel, PCIR_COMMAND, 0x02, cmd);
+
+ /* passthrough VGA ports */
+ if (iofd < 0) {
+ iofd = open(_PATH_DEVIO, O_RDWR, 0);
+ if (iofd < 0) {
+ warn("failed to open %s", _PATH_DEVIO);
+ }
+ }
+ struct inout_port iop;
+ bzero(&iop, sizeof(iop));
+ iop.name = "VGA";
+ for (int port = VGA_IOPORT_START; port <= VGA_IOPORT_END; port++) {
+ iop.port = port;
+ iop.size = 1;
+ iop.flags = IOPORT_F_INOUT;
+ iop.handler = passthru_port_handler;
+ iop.arg = NULL;
+
+ error = register_inout(&iop);
+ assert(error == 0);
+ }
+
+ /* passthrough VGA memory */
+ if ((error = vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, sc->psc_sel.pc_func, 640*KB, 128*KB, 640*KB)) != 0) {
+ warnx("vm_map_pptdev_mmio (%d): %d", error, errno);
+ error = 0;
+ }
+
+ uint16_t vendor, dev_id;
+ uint64_t bios_size;
+ vendor = read_config(&sc->psc_sel, PCIR_VENDOR, 0x02);
+ dev_id = read_config(&sc->psc_sel, PCIR_DEVICE, 0x02);
+
+ vm_get_vbios(ctx, sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, sc->psc_sel.pc_func, vendor, dev_id, NULL, &bios_size);
+
+ // round up size to a power of two
+ // check in descendig order to avoid endless loop
+ pi->pi_vbios.len = 1ULL << 63;
+ while (pi->pi_vbios.len > bios_size) {
+ pi->pi_vbios.len >>= 1;
+ }
+ pi->pi_vbios.len <<= 1;
+ pi->pi_vbios.gpa = VBIOS_ADDR;
+ pi->pi_vbios.hpa = (uint64_t)vm_create_devmem(ctx, VM_VIDEOBIOS, "videobios", pi->pi_vbios.len);
+ if ((void *)pi->pi_vbios.hpa == MAP_FAILED) {
+ warnx("vm_create_devmem: %x", errno);
+ error = -1;
+ goto done;
+ }
+
+ vm_get_vbios(ctx, sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, sc->psc_sel.pc_func, vendor, dev_id, (void *)pi->pi_vbios.hpa, &bios_size);
+
+ if ((error = pci_emul_alloc_rom(pi, VM_VIDEOBIOS, pi->pi_vbios.gpa, pi->pi_vbios.len)) != 0) {
+ warnx("pci_emul_alloc_rom: %x", error);
+ goto done;
+ }
+
+done:
+ return (error);
+}
+
+static int
+apu_d_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int coff, int bytes, uint32_t val)
+{
+ /* ROM is emulated */
+ if (coff >= PCIR_BIOS && coff < PCIR_BIOS + 4) {
+ return (-1);
+ } else {
+ return passthru_cfgwrite(ctx, vcpu, pi, coff, bytes, val);
+ }
+}
+
+static int
+apu_d_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int coff, int bytes, uint32_t *rv)
+{
+ /* ROM is emulated */
+ if (coff >= PCIR_BIOS && coff < PCIR_BIOS + 4) {
+ return (-1);
+ } else {
+ return passthru_cfgread(ctx, vcpu, pi, coff, bytes, rv);
+ }
+}
+
+static void
+apu_d_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, uint64_t offset, int size, uint64_t value)
+{
+ passthru_write(ctx, vcpu, pi, baridx, offset, size, value);
+}
+
+static uint64_t
+apu_d_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, uint64_t offset, int size)
+{
+ return passthru_read(ctx, vcpu, pi, baridx, offset, size);
+}
+
+struct pci_devemu apu_d = {
+ .pe_emu = "apu-d",
+ .pe_init = apu_d_init,
+ .pe_cfgwrite = apu_d_cfgwrite,
+ .pe_cfgread = apu_d_cfgread,
+ .pe_barwrite = apu_d_write,
+ .pe_barread = apu_d_read,
+};
+PCI_EMUL_SET(apu_d);
+
+/*
+ * This device signals EFI the rom_space
+ */
+static int
+apu_d_dummy_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
+{
+ pci_set_cfgdata16(pi, PCIR_COMMAND, PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN);
+
+ return (0);
+}
+
+static int
+apu_d_dummy_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int coff, int bytes, uint32_t val)
+{
+ /* BAR is emulated */
+ if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(0) + 4) {
+ switch (bytes) {
+ case 1:
+ pci_set_cfgdata8(pi, coff, val);
+ break;
+ case 2:
+ pci_set_cfgdata16(pi, coff, val);
+ break;
+ case 4:
+ pci_set_cfgdata32(pi, coff, val);
+ break;
+ }
+ return (0);
+ } else {
+ return (-1);
+ }
+}
+
+static int
+apu_d_dummy_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int coff, int bytes, uint32_t *rv)
+{
+ /* BAR is emulated */
+ if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(0) + 4) {
+ uint32_t bar = pci_get_cfgdata32(pi, PCIR_BAR(0));
+ if (bar == 0xFFFFFFFF) {
+ *rv = (uint32_t)~(16*MB - 1);
+ } else {
+ *rv = rom_space | PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
+ }
+ *rv >>= 8 * (coff & 0x03);
+ return (0);
+ } else {
+ return (-1);
+ }
+}
+
+struct pci_devemu apu_d_dummy = {
+ .pe_emu = "apu-d-dummy",
+ .pe_init = apu_d_dummy_init,
+ .pe_cfgwrite = apu_d_dummy_cfgwrite,
+ .pe_cfgread = apu_d_dummy_cfgread,
+};
+PCI_EMUL_SET(apu_d_dummy);
Index: usr.sbin/bhyve/pci_emul.h
===================================================================
--- usr.sbin/bhyve/pci_emul.h
+++ usr.sbin/bhyve/pci_emul.h
@@ -85,7 +85,8 @@
PCIBAR_IO,
PCIBAR_MEM32,
PCIBAR_MEM64,
- PCIBAR_MEMHI64
+ PCIBAR_MEMHI64,
+ PCIBAR_ROM,
};
struct pcibar {
@@ -116,6 +117,12 @@
PENDING
};
+struct pci_vbiosemu {
+ uint64_t hpa;
+ uint64_t len;
+ uint64_t gpa;
+};
+
struct pci_devinst {
struct pci_devemu *pi_d;
struct vmctx *pi_vmctx;
@@ -158,6 +165,11 @@
u_char pi_cfgdata[PCI_REGMAX + 1];
struct pcibar pi_bar[PCI_BARMAX + 1];
+ struct pcibar pi_rom_bar;
+ int pi_rom_segment;
+ int pi_rom_enabled;
+
+ struct pci_vbiosemu pi_vbios;
};
struct msicap {
@@ -223,6 +235,9 @@
enum pcibar_type type, uint64_t size);
int pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx,
uint64_t hostbase, enum pcibar_type type, uint64_t size);
+int pci_emul_alloc_rom(struct pci_devinst *pdi, int segid,
+ uint32_t addr, uint32_t size);
+uint64_t pci_emul_alloc_mmio(enum pcibar_type type, uint64_t size, uint64_t mask);
int pci_emul_add_msicap(struct pci_devinst *pi, int msgnum);
int pci_emul_add_pciecap(struct pci_devinst *pi, int pcie_device_type);
void pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes,
Index: usr.sbin/bhyve/pci_emul.c
===================================================================
--- usr.sbin/bhyve/pci_emul.c
+++ usr.sbin/bhyve/pci_emul.c
@@ -33,6 +33,7 @@
#include <sys/param.h>
#include <sys/linker_set.h>
+#include <sys/mman.h>
#include <ctype.h>
#include <errno.h>
@@ -582,6 +583,76 @@
register_bar(pi, idx);
}
+int
+pci_emul_alloc_rom(struct pci_devinst *pdi, int segid,
+ uint32_t addr, uint32_t size)
+{
+ /* The segment ID must be valid */
+ if (segid <= VM_SYSMEM || segid >= VM_NOTHING)
+ return (-1);
+
+ /* The size must be a power of two >= 4 KiB */
+ if ((size & (size - 1)) != 0 || size < 4096)
+ return (-2);
+
+ /* The address must be at a multiple of size */
+ if ((addr & (size - 1)) != 0)
+ return (-3);
+
+ pdi->pi_rom_segment = segid;
+ pdi->pi_rom_bar.type = PCIBAR_ROM;
+ pdi->pi_rom_bar.addr = addr;
+ pdi->pi_rom_bar.size = size;
+ pdi->pi_rom_enabled = 0;
+
+ pci_set_cfgdata32(pdi, PCIR_BIOS, addr);
+
+ return (0);
+}
+
+static int
+update_rom_address(struct pci_devinst *pdi)
+{
+ uint32_t bar, addr;
+ int enable;
+
+ /* Grab info directly from the config data */
+ bar = pci_get_cfgdata32(pdi, PCIR_BIOS);
+ enable = (bar & PCIM_BIOS_ENABLE)? 1 : 0;
+ addr = bar & PCIM_BIOS_ADDR_MASK;
+
+ /* Ignore the mapping if we don't have a ROM segment to map */
+ if (!pdi->pi_rom_segment) {
+ pdi->pi_rom_bar.addr = addr;
+ return (0);
+ }
+
+ /* Something has changed; unmap the segment if it's mapped */
+ if (pdi->pi_rom_enabled) {
+ vm_munmap_memseg(pdi->pi_vmctx, pdi->pi_rom_bar.addr,
+ pdi->pi_rom_segment, 0);
+ }
+
+ pdi->pi_rom_enabled = enable && memen(pdi);
+ pdi->pi_rom_bar.addr = addr;
+
+ /* Map the segment only if both ROM and global Memory Space are on */
+ if (pdi->pi_rom_enabled) {
+ int error;
+
+ error = vm_mmap_memseg(pdi->pi_vmctx, pdi->pi_rom_bar.addr,
+ pdi->pi_rom_segment, 0, pdi->pi_rom_bar.size,
+ PROT_READ | PROT_EXEC);
+
+ if (error) {
+ perror("ROM mapping failed");
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
int
pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase,
enum pcibar_type type, uint64_t size)
@@ -684,6 +755,44 @@
return (0);
}
+// mask should be a power of 2 minus 1 (e.g. 0x000FFFFF)
+uint64_t
+pci_emul_alloc_mmio(enum pcibar_type type, uint64_t size, uint64_t mask)
+{
+ int error;
+
+ error = 1;
+
+ uint64_t *baseptr, limit, base;
+
+ switch (type) {
+ case PCIBAR_IO:
+ baseptr = &pci_emul_iobase;
+ limit = PCI_EMUL_IOLIMIT;
+ break;
+ case PCIBAR_MEM32:
+ baseptr = &pci_emul_membase32;
+ limit = PCI_EMUL_MEMLIMIT32;
+ break;
+ case PCIBAR_MEM64:
+ baseptr = &pci_emul_membase64;
+ limit = PCI_EMUL_MEMLIMIT64;
+ break;
+ default:
+ return 0;
+ }
+
+ // align base
+ base = (*baseptr + mask) & ~mask;
+
+ if (base + size > limit)
+ return 0;
+
+ *baseptr = base + size;
+
+ return base;
+}
+
#define CAP_START_OFFSET 0x40
static int
pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen)
@@ -1736,6 +1845,9 @@
}
}
+ if ((changed & PCIM_CMD_MEMEN))
+ update_rom_address(pi);
+
/*
* If INTx has been unmasked and is pending, assert the
* interrupt.
@@ -1899,6 +2011,25 @@
}
pci_set_cfgdata32(pi, coff, bar);
+ /*
+ * The BAR register for an Expansion ROM is slightly different.
+ */
+ } else if (coff >= PCIR_BIOS && coff < PCIR_BIOS + 4) {
+
+ /* Well, it's ignored for ordinary BAR registers... */
+ if (bytes != 4 || (coff & 0x3) != 0)
+ return;
+
+ /* Refuse to enable unless we have a BIOS */
+ mask = ~(pi->pi_rom_bar.size - 1);
+ if (pi->pi_rom_bar.size > 0)
+ mask |= PCIM_BIOS_ENABLE;
+
+ /* Make the change and update ROM location */
+ bar = *eax & mask;
+ pci_set_cfgdata32(pi, coff, bar);
+ update_rom_address(pi);
+
} else if (pci_emul_iscap(pi, coff)) {
pci_emul_capwrite(pi, coff, bytes, *eax, 0, 0);
} else if (coff >= PCIR_COMMAND && coff < PCIR_REVID) {
Index: usr.sbin/bhyve/pci_passthru.h
===================================================================
--- /dev/null
+++ usr.sbin/bhyve/pci_passthru.h
@@ -0,0 +1,63 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Beckhoff Automation GmbH & Co. KG
+ * 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 OR 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$
+ */
+
+#ifndef __PCI_PASSTHRU_H__
+#define __PCI_PASSTHRU_H__
+
+#include <sys/pciio.h>
+
+#include <vmmapi.h>
+
+#include "pci_emul.h"
+
+struct passthru_softc {
+ struct pci_devinst *psc_pi;
+ struct pcibar psc_bar[PCI_BARMAX + 1];
+ struct {
+ int capoff;
+ int msgctrl;
+ int emulated;
+ } psc_msi;
+ struct {
+ int capoff;
+ } psc_msix;
+ struct pcisel psc_sel;
+};
+
+uint32_t read_config(const struct pcisel *sel, long reg, int width);
+void write_config(const struct pcisel *sel, long reg, int width, uint32_t data);
+int bar_access(int coff);
+int passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts);
+int passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int coff, int bytes, uint32_t val);
+int passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int coff, int bytes, uint32_t *rv);
+void passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, uint64_t offset, int size, uint64_t value);
+uint64_t passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, uint64_t offset, int size);
+
+#endif
Index: usr.sbin/bhyve/pci_passthru.c
===================================================================
--- usr.sbin/bhyve/pci_passthru.c
+++ usr.sbin/bhyve/pci_passthru.c
@@ -61,6 +61,7 @@
#include <vmmapi.h>
#include "pci_emul.h"
#include "mem.h"
+#include "pci_passthru.h"
#ifndef _PATH_DEVPCI
#define _PATH_DEVPCI "/dev/pci"
@@ -83,20 +84,6 @@
static int iofd = -1;
static int memfd = -1;
-struct passthru_softc {
- struct pci_devinst *psc_pi;
- struct pcibar psc_bar[PCI_BARMAX + 1];
- struct {
- int capoff;
- int msgctrl;
- int emulated;
- } psc_msi;
- struct {
- int capoff;
- } psc_msix;
- struct pcisel psc_sel;
-};
-
static int
msi_caplen(int msgctrl)
{
@@ -119,7 +106,7 @@
return (len);
}
-static uint32_t
+uint32_t
read_config(const struct pcisel *sel, long reg, int width)
{
struct pci_io pi;
@@ -135,7 +122,7 @@
return (pi.pi_data);
}
-static void
+void
write_config(const struct pcisel *sel, long reg, int width, uint32_t data)
{
struct pci_io pi;
@@ -647,7 +634,7 @@
return (error);
}
-static int
+int
passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
{
int bus, slot, func, error, memflags;
@@ -743,7 +730,7 @@
return (error);
}
-static int
+int
bar_access(int coff)
{
if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1))
@@ -778,7 +765,7 @@
coff < sc->psc_msix.capoff + MSIX_CAPLEN);
}
-static int
+int
passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
int coff, int bytes, uint32_t *rv)
{
@@ -822,7 +809,7 @@
return (0);
}
-static int
+int
passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
int coff, int bytes, uint32_t val)
{
@@ -898,7 +885,7 @@
return (0);
}
-static void
+void
passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
uint64_t offset, int size, uint64_t value)
{
@@ -921,7 +908,7 @@
}
}
-static uint64_t
+uint64_t
passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
uint64_t offset, int size)
{

File Metadata

Mime Type
text/plain
Expires
Sun, May 17, 9:55 PM (18 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33211941
Default Alt Text
D26506.id.diff (35 KB)

Event Timeline