Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102553068
D26209.id76277.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
24 KB
Referenced Files
None
Subscribers
None
D26209.id76277.diff
View Options
Index: lib/libvmmapi/vmmapi.h
===================================================================
--- lib/libvmmapi/vmmapi.h
+++ lib/libvmmapi/vmmapi.h
@@ -176,6 +176,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_unmap_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func,
+ vm_paddr_t gpa, size_t len);
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
@@ -124,7 +124,7 @@
vm->fd = -1;
vm->memflags = 0;
- vm->lowmem_limit = 3 * GB;
+ vm->lowmem_limit = 2 * GB;
vm->name = (char *)(vm + 1);
strcpy(vm->name, name);
@@ -980,6 +980,26 @@
return (ioctl(ctx->fd, VM_MAP_PPTDEV_MMIO, &pptmmio));
}
+int
+vm_unmap_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func,
+ vm_paddr_t gpa, size_t len)
+{
+ struct vm_pptdev_mmio pptmmio;
+
+ bzero(&pptmmio, sizeof(pptmmio));
+ pptmmio.bus = bus;
+ pptmmio.slot = slot;
+ pptmmio.func = func;
+ pptmmio.gpa = gpa;
+ pptmmio.len = len;
+ pptmmio.hpa = 0;
+
+ if (gpa == 0)
+ return (0);
+
+ return (ioctl(ctx->fd, VM_UNMAP_PPTDEV_MMIO, &pptmmio));
+}
+
int
vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func,
uint64_t addr, uint64_t msg, int numvec)
@@ -1640,7 +1660,7 @@
VM_IOAPIC_PULSE_IRQ, VM_IOAPIC_PINCOUNT, VM_ISA_ASSERT_IRQ,
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_UNBIND_PPTDEV, VM_MAP_PPTDEV_MMIO, VM_UNMAP_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_GET_HPET_CAPABILITIES, VM_GET_GPA_PMAP, VM_GLA2GPA,
Index: sys/amd64/include/vmm_dev.h
===================================================================
--- sys/amd64/include/vmm_dev.h
+++ sys/amd64/include/vmm_dev.h
@@ -299,6 +299,7 @@
IOCNUM_BIND_PPTDEV = 40,
IOCNUM_UNBIND_PPTDEV = 41,
IOCNUM_MAP_PPTDEV_MMIO = 42,
+ IOCNUM_UNMAP_PPTDEV_MMIO = 45,
IOCNUM_PPTDEV_MSI = 43,
IOCNUM_PPTDEV_MSIX = 44,
@@ -409,6 +410,8 @@
_IOW('v', IOCNUM_UNBIND_PPTDEV, struct vm_pptdev)
#define VM_MAP_PPTDEV_MMIO \
_IOW('v', IOCNUM_MAP_PPTDEV_MMIO, struct vm_pptdev_mmio)
+#define VM_UNMAP_PPTDEV_MMIO \
+ _IOW('v', IOCNUM_UNMAP_PPTDEV_MMIO, struct vm_pptdev_mmio)
#define VM_PPTDEV_MSI \
_IOW('v', IOCNUM_PPTDEV_MSI, struct vm_pptdev_msi)
#define VM_PPTDEV_MSIX \
Index: sys/amd64/vmm/io/ppt.h
===================================================================
--- sys/amd64/vmm/io/ppt.h
+++ sys/amd64/vmm/io/ppt.h
@@ -34,6 +34,8 @@
int ppt_unassign_all(struct vm *vm);
int ppt_map_mmio(struct vm *vm, int bus, int slot, int func,
vm_paddr_t gpa, size_t len, vm_paddr_t hpa);
+int ppt_unmap_mmio(struct vm *vm, int bus, int slot, int func,
+ vm_paddr_t gpa, size_t len);
int ppt_setup_msi(struct vm *vm, int vcpu, int bus, int slot, int func,
uint64_t addr, uint64_t msg, int numvec);
int ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
Index: sys/amd64/vmm/io/ppt.c
===================================================================
--- sys/amd64/vmm/io/ppt.c
+++ sys/amd64/vmm/io/ppt.c
@@ -218,7 +218,7 @@
}
static void
-ppt_unmap_mmio(struct vm *vm, struct pptdev *ppt)
+ppt_unmap_mmio_all(struct vm *vm, struct pptdev *ppt)
{
int i;
struct pptseg *seg;
@@ -414,7 +414,7 @@
pci_save_state(ppt->dev);
ppt_pci_reset(ppt->dev);
pci_restore_state(ppt->dev);
- ppt_unmap_mmio(vm, ppt);
+ ppt_unmap_mmio_all(vm, ppt);
ppt_teardown_msi(ppt);
ppt_teardown_msix(ppt);
iommu_remove_device(vm_iommu_domain(vm), pci_get_rid(ppt->dev));
@@ -473,6 +473,35 @@
return (ENOENT);
}
+int
+ppt_unmap_mmio(struct vm *vm, int bus, int slot, int func,
+ vm_paddr_t gpa, size_t len)
+{
+ int i, error;
+ struct pptseg *seg;
+ struct pptdev *ppt;
+
+ ppt = ppt_find(bus, slot, func);
+ if (ppt != NULL) {
+ if (ppt->vm != vm)
+ return (EBUSY);
+
+ for (i = 0; i < MAX_MMIOSEGS; i++) {
+ seg = &ppt->mmio[i];
+ if (seg->gpa == gpa && seg->len == len) {
+ error = vm_unmap_mmio(vm, gpa, len);
+ if (error == 0) {
+ seg->gpa = 0;
+ seg->len = 0;
+ }
+ return (error);
+ }
+ }
+ return (ENOSPC);
+ }
+ return (ENOENT);
+}
+
static int
pptintr(void *arg)
{
Index: sys/amd64/vmm/vmm_dev.c
===================================================================
--- sys/amd64/vmm/vmm_dev.c
+++ sys/amd64/vmm/vmm_dev.c
@@ -435,6 +435,7 @@
break;
case VM_MAP_PPTDEV_MMIO:
+ case VM_UNMAP_PPTDEV_MMIO:
case VM_BIND_PPTDEV:
case VM_UNBIND_PPTDEV:
#ifdef COMPAT_FREEBSD12
@@ -520,6 +521,11 @@
pptmmio->func, pptmmio->gpa, pptmmio->len,
pptmmio->hpa);
break;
+ case VM_UNMAP_PPTDEV_MMIO:
+ pptmmio = (struct vm_pptdev_mmio *)data;
+ error = ppt_unmap_mmio(sc->vm, pptmmio->bus, pptmmio->slot,
+ pptmmio->func, pptmmio->gpa, pptmmio->len);
+ break;
case VM_BIND_PPTDEV:
pptdev = (struct vm_pptdev *)data;
error = vm_assign_pptdev(sc->vm, pptdev->bus, pptdev->slot,
Index: sys/dev/pci/pcireg.h
===================================================================
--- sys/dev/pci/pcireg.h
+++ sys/dev/pci/pcireg.h
@@ -1098,3 +1098,15 @@
#define PCIM_OSC_CTL_PCIE_PME 0x04 /* PCIe Native Power Mgt Events */
#define PCIM_OSC_CTL_PCIE_AER 0x08 /* PCIe Advanced Error Reporting */
#define PCIM_OSC_CTL_PCIE_CAP_STRUCT 0x10 /* Various Capability Structures */
+
+/*
+ * GVT-d definitions
+ */
+#define PCIR_BDSM 0x5C /* Base Data of Stolen Memory register */
+#define PCIR_ASLS_CTL 0xFC /* Opregion start address register */
+#define PCIM_BDSM_GSM_MASK 0xFFF00000 /* Bits 31:20 contain base address of gsm */
+#define PCIM_ASLS_OPREGION_MASK 0xFFFFF000 /* Opregion is 4k aligned */
+#define GPU_GSM_SIZE 0x04000000 /* Size of Graphics Stolen Memory */
+#define GPU_GSM_GPA 0x9B000000 /* Guest Physical Address of Graphics Stolen Memory */
+#define GPU_OPREGION_SIZE 0x00003000 /* Size of Opregion */
+#define GPU_OPREGION_GPA 0x9FFFD000 /* Guest Physical Address of Opregion */
Index: usr.sbin/bhyve/Makefile
===================================================================
--- usr.sbin/bhyve/Makefile
+++ usr.sbin/bhyve/Makefile
@@ -43,6 +43,7 @@
pci_hda.c \
pci_fbuf.c \
pci_hostbridge.c \
+ pci_igd_lpc.c \
pci_irq.c \
pci_lpc.c \
pci_nvme.c \
Index: usr.sbin/bhyve/pci_emul.h
===================================================================
--- usr.sbin/bhyve/pci_emul.h
+++ usr.sbin/bhyve/pci_emul.h
@@ -92,6 +92,7 @@
enum pcibar_type type; /* io or memory */
uint64_t size;
uint64_t addr;
+ uint8_t lobits;
};
#define PI_NAMESZ 40
@@ -223,6 +224,8 @@
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);
+void unregister_bar_passthru(struct pci_devinst *pi, int idx);
+void register_bar_passthru(struct pci_devinst *pi, int idx);
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
@@ -459,6 +459,15 @@
return (pci_emul_alloc_pbar(pdi, idx, 0, type, size));
}
+static bool
+is_passthru(struct pci_devinst *pi)
+{
+ if (strcmp(pi->pi_d->pe_emu, "passthru") == 0)
+ return true;
+ else
+ return false;
+}
+
/*
* Register (or unregister) the MMIO or I/O region associated with the BAR
* register 'idx' of an emulated pci device.
@@ -509,15 +518,19 @@
static void
unregister_bar(struct pci_devinst *pi, int idx)
{
-
- modify_bar_registration(pi, idx, 0);
+ if (!is_passthru(pi))
+ modify_bar_registration(pi, idx, 0);
+ else
+ unregister_bar_passthru(pi, idx);
}
static void
register_bar(struct pci_devinst *pi, int idx)
{
-
- modify_bar_registration(pi, idx, 1);
+ if (!is_passthru(pi))
+ modify_bar_registration(pi, idx, 1);
+ else
+ register_bar_passthru(pi, idx);
}
/* Are we decoding i/o port accesses for the emulated pci device? */
@@ -677,9 +690,15 @@
}
cmd = pci_get_cfgdata16(pdi, PCIR_COMMAND);
- if ((cmd & enbit) != enbit)
- pci_set_cfgdata16(pdi, PCIR_COMMAND, cmd | enbit);
- register_bar(pdi, idx);
+ if (is_passthru(pdi)) {
+ if ((cmd & enbit) == enbit)
+ register_bar(pdi, idx);
+ }
+ else {
+ if ((cmd & enbit) != enbit)
+ pci_set_cfgdata16(pdi, PCIR_COMMAND, cmd | enbit);
+ register_bar(pdi, idx);
+ }
return (0);
}
@@ -1799,9 +1818,9 @@
/*
* Ignore all writes beyond the standard config space and return all
- * ones on reads.
+ * ones on reads for non passthru devices.
*/
- if (coff >= PCI_REGMAX + 1) {
+ if (coff >= PCI_REGMAX + 1 && !is_passthru(pi)) {
if (in) {
*eax = 0xffffffff;
/*
@@ -1830,8 +1849,14 @@
needcfg = 1;
}
- if (needcfg)
- *eax = CFGREAD(pi, coff, bytes);
+ if (needcfg) {
+ if (coff <= PCI_REGMAX)
+ *eax = CFGREAD(pi, coff, bytes);
+ else if (coff <= PCI_REGMAX + 4)
+ *eax = 0x00000000;
+ else
+ *eax = 0xFFFFFFFF;
+ }
pci_emul_hdrtype_fixup(bus, slot, coff, bytes, eax);
} else {
@@ -1903,7 +1928,7 @@
pci_emul_capwrite(pi, coff, bytes, *eax, 0, 0);
} else if (coff >= PCIR_COMMAND && coff < PCIR_REVID) {
pci_emul_cmdsts_write(pi, coff, *eax, bytes);
- } else {
+ } else if (coff <= PCI_REGMAX) {
CFGWRITE(pi, coff, *eax, bytes);
}
}
Index: usr.sbin/bhyve/pci_igd_lpc.c
===================================================================
--- /dev/null
+++ usr.sbin/bhyve/pci_igd_lpc.c
@@ -0,0 +1,80 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/pciio.h>
+#include <machine/vmm.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <vmmapi.h>
+
+#include "pci_emul.h"
+
+#ifndef _PATH_DEVPCI
+#define _PATH_DEVPCI "/dev/pci"
+#endif
+
+int pcifd = -1;
+
+static uint32_t
+read_config(long reg, int width)
+{
+ struct pci_io pi;
+
+ bzero(&pi, sizeof(pi));
+ // igd-lpc is always connected to 0:1f.0
+ pi.pi_sel.pc_domain = 0;
+ pi.pi_sel.pc_bus = 0;
+ pi.pi_sel.pc_dev = 0x1f;
+ pi.pi_sel.pc_func = 0;
+ pi.pi_reg = reg;
+ pi.pi_width = width;
+
+ if (ioctl(pcifd, PCIOCREAD, &pi) < 0)
+ return (0);
+ else
+ return (pi.pi_data);
+}
+
+static int
+pci_igd_lpc_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
+{
+ // only allow igd-lpc on 0:1f.0
+ if (pi->pi_bus != 0 || pi->pi_slot != 0x1f || pi->pi_func != 0x00) {
+ warn("igd-lpc only allowed on 0:1f.0");
+ return (-1);
+ }
+
+ // open host device
+ if (pcifd < 0) {
+ pcifd = open(_PATH_DEVPCI, O_RDWR, 0);
+ if (pcifd < 0) {
+ warn("failed to open %s", _PATH_DEVPCI);
+ return (-1);
+ }
+ }
+
+ /*
+ * The VID, DID, REVID, SUBVID and SUBDID of igd-lpc need aligned with physical one.
+ * Without these physical values, GVT-d GOP driver couldn't work.
+ */
+ pci_set_cfgdata16(pi, PCIR_DEVICE, read_config(PCIR_DEVICE, 2));
+ pci_set_cfgdata16(pi, PCIR_VENDOR, read_config(PCIR_VENDOR, 2));
+ pci_set_cfgdata8(pi, PCIR_REVID, read_config(PCIR_REVID, 1));
+ pci_set_cfgdata16(pi, PCIR_SUBVEND_0, read_config(PCIR_SUBVEND_0, 2));
+ pci_set_cfgdata16(pi, PCIR_SUBDEV_0, read_config(PCIR_SUBDEV_0, 2));
+
+ return (0);
+}
+
+struct pci_devemu pci_de_igd_lpc = {
+ .pe_emu = "igd-lpc",
+ .pe_init = pci_igd_lpc_init
+};
+PCI_EMUL_SET(pci_de_igd_lpc);
Index: usr.sbin/bhyve/pci_passthru.c
===================================================================
--- usr.sbin/bhyve/pci_passthru.c
+++ usr.sbin/bhyve/pci_passthru.c
@@ -60,6 +60,7 @@
#include <machine/vmm.h>
#include <vmmapi.h>
#include "pci_emul.h"
+#include "inout.h"
#include "mem.h"
#ifndef _PATH_DEVPCI
@@ -149,6 +150,116 @@
(void)ioctl(pcifd, PCIOCWRITE, &pi); /* XXX */
}
+static int
+pci_emul_io_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
+ uint32_t *eax, void *arg)
+{
+ struct pci_devinst *pdi = arg;
+ struct pci_devemu *pe = pdi->pi_d;
+ uint64_t offset;
+ int i;
+
+ for (i = 0; i <= PCI_BARMAX; i++) {
+ if (pdi->pi_bar[i].type == PCIBAR_IO &&
+ port >= pdi->pi_bar[i].addr &&
+ port + bytes <= pdi->pi_bar[i].addr + pdi->pi_bar[i].size) {
+ offset = port - pdi->pi_bar[i].addr;
+ if (in)
+ *eax = (*pe->pe_barread)(ctx, vcpu, pdi, i,
+ offset, bytes);
+ else
+ (*pe->pe_barwrite)(ctx, vcpu, pdi, i, offset,
+ bytes, *eax);
+ return (0);
+ }
+ }
+ return (-1);
+}
+
+void unregister_bar_passthru(struct pci_devinst *pi, int idx)
+{
+ int error;
+ struct passthru_softc *sc;
+ struct inout_port iop;
+
+ if (pi->pi_bar[idx].addr == 0)
+ return;
+
+ sc = pi->pi_arg;
+
+ switch (pi->pi_bar[idx].type) {
+ case PCIBAR_NONE:
+ case PCIBAR_MEMHI64:
+ break;
+ case PCIBAR_IO:
+ /*
+ * ToDo: Passthrough IO
+ *
+ * Use IO-Bitmap to emulate access to IO ports
+ * Prevent VM_EXIT on access to specified IO ports
+ */
+ bzero(&iop, sizeof(struct inout_port));
+ iop.name = pi->pi_name;
+ iop.port = pi->pi_bar[idx].addr;
+ iop.size = pi->pi_bar[idx].size;
+ error = unregister_inout(&iop);
+ break;
+ case PCIBAR_MEM32:
+ case PCIBAR_MEM64:
+ error = vm_unmap_pptdev_mmio(pi->pi_vmctx, sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, sc->psc_sel.pc_func, pi->pi_bar[idx].addr, pi->pi_bar[idx].size);
+ break;
+ }
+
+ if (error != 0)
+ err(1, __func__);
+}
+
+void register_bar_passthru(struct pci_devinst *pi, int idx)
+{
+ int error;
+ struct passthru_softc *sc;
+ struct inout_port iop;
+
+ sc = pi->pi_arg;
+
+ switch (pi->pi_bar[idx].type) {
+ case PCIBAR_NONE:
+ case PCIBAR_MEMHI64:
+ break;
+ case PCIBAR_IO:
+ /*
+ * ToDo: Passthrough IO
+ *
+ * Use IO-Bitmap to emulate access to IO ports
+ * Prevent VM_EXIT on access to specified IO ports
+ */
+ bzero(&iop, sizeof(struct inout_port));
+ iop.name = pi->pi_name;
+ iop.port = pi->pi_bar[idx].addr;
+ iop.size = pi->pi_bar[idx].size;
+ iop.flags = IOPORT_F_INOUT;
+ iop.handler = pci_emul_io_handler;
+ iop.arg = pi;
+ error = register_inout(&iop);
+ break;
+ case PCIBAR_MEM32:
+ case PCIBAR_MEM64:
+ error = vm_map_pptdev_mmio(pi->pi_vmctx, sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, sc->psc_sel.pc_func, pi->pi_bar[idx].addr, pi->pi_bar[idx].size, sc->psc_bar[idx].addr);
+ /*
+ * If the guest writes a new value to a 64-bit BAR, two writes are neccessary.
+ * vm_map_pptdev_mmio can fail in that case due to an invalid address after the first write.
+ */
+ if (error != 0) {
+ pi->pi_bar[idx].addr = 0;
+ error = 0;
+ }
+ break;
+ }
+
+ if (error != 0)
+ err(1, __func__);
+}
+
#ifdef LEGACY_SUPPORT
static int
passthru_add_msicap(struct pci_devinst *pi, int msgnum, int nextptr)
@@ -581,24 +692,34 @@
sc->psc_bar[i].type = bartype;
sc->psc_bar[i].size = size;
sc->psc_bar[i].addr = base;
+ sc->psc_bar[i].lobits = 0;
/* Allocate the BAR in the guest I/O or MMIO space */
error = pci_emul_alloc_pbar(pi, i, base, bartype, size);
if (error)
return (-1);
+ /*
+ * For passthru devices use same prefetchable property as physical bar
+ */
+ if (bartype == PCIBAR_MEM32 || bartype == PCIBAR_MEM64)
+ {
+ uint8_t lobits = pci_get_cfgdata8(pi, 0x10 + i * 0x04);
+ if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH)
+ lobits |= PCIM_BAR_MEM_PREFETCH;
+ else
+ lobits &= ~PCIM_BAR_MEM_PREFETCH;
+ sc->psc_bar[i].lobits = lobits & 0xF;
+ pci_set_cfgdata8(pi, 0x10 + i * 0x04, lobits);
+ }
+ else
+ sc->psc_bar[i].lobits = PCIM_BAR_IO_SPACE;
+
/* The MSI-X table needs special handling */
if (i == pci_msix_table_bar(pi)) {
error = init_msix_table(ctx, sc, base);
if (error)
return (-1);
- } else if (bartype != PCIBAR_IO) {
- /* Map the physical BAR in the guest MMIO space */
- error = vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus,
- sc->psc_sel.pc_dev, sc->psc_sel.pc_func,
- pi->pi_bar[i].addr, pi->pi_bar[i].size, base);
- if (error)
- return (-1);
}
/*
@@ -633,23 +754,42 @@
goto done;
}
+ /*
+ * Set command register before init of BARs
+ *
+ * cfginitbar checks command register to decide whether to register a new BAR or not
+ */
+ pci_set_cfgdata16(pi, PCIR_COMMAND, read_config(&sc->psc_sel,
+ PCIR_COMMAND, 2));
+
if (cfginitbar(ctx, sc) != 0) {
warnx("failed to initialize BARs for PCI %d/%d/%d",
bus, slot, func);
goto done;
}
- pci_set_cfgdata16(pi, PCIR_COMMAND, read_config(&sc->psc_sel,
- PCIR_COMMAND, 2));
-
error = 0; /* success */
done:
return (error);
}
+
+/*
+ * GVT-d: Declare modified funcs for passthrough of igd-device
+ */
+static int
+passthru_init_igd(struct vmctx *ctx, struct passthru_softc *sc);
+static int
+passthru_cfgread_igd(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+ int coff, int bytes, uint32_t *rv);
+static int
+passthru_cfgwrite_igd(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+ int coff, int bytes, uint32_t val);
+
static int
passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
{
+ char *opt;
int bus, slot, func, error, memflags;
struct passthru_softc *sc;
#ifndef WITHOUT_CAPSICUM
@@ -721,6 +861,12 @@
warnx("invalid passthru options");
return (error);
}
+
+ if ((opt = strchr(opts, ',')) != NULL)
+ {
+ *opt = '\0';
+ opt = opt + 1;
+ }
if (vm_assign_pptdev(ctx, bus, slot, func) != 0) {
warnx("PCI device at %d/%d/%d is not using the ppt(4) driver",
@@ -734,7 +880,16 @@
sc->psc_pi = pi;
/* initialize config space */
- error = cfginit(ctx, pi, bus, slot, func);
+ if ((error = cfginit(ctx, pi, bus, slot, func)) != 0)
+ goto done;
+
+ // init igd (integrated graphics device)
+ if (opt != NULL && strcmp(opt, "igd") == 0) {
+ if ((error = passthru_init_igd(ctx, sc)) != 0)
+ goto done;
+ }
+
+ error = 0; /* success */
done:
if (error) {
free(sc);
@@ -743,6 +898,52 @@
return (error);
}
+static int
+passthru_init_igd(struct vmctx *ctx, struct passthru_softc *sc)
+{
+ int error;
+
+ /*
+ * GVT-d: Create LPC-Device at 0:1f.0
+ *
+ * Otherwise GOP-Driver wouldn't work for Windows
+ */
+ printf("Add igd-lpc at slot 0:1f.0 to enable GVT-d for igd\n");
+ if ((error = pci_parse_slot("0:31:0,igd-lpc")) != 0)
+ goto done;
+
+ /*
+ * GVT-d: Passthrough GPU DSM (Data Stolen Memory)
+ */
+ uint32_t bdsm_val;
+ bdsm_val = read_config(&sc->psc_sel, PCIR_BDSM, 4);
+ if ((error = vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, sc->psc_sel.pc_func, GPU_GSM_GPA, GPU_GSM_SIZE, bdsm_val & PCIM_BDSM_GSM_MASK)) != 0)
+ goto done;
+ pci_set_cfgdata32(sc->psc_pi, PCIR_BDSM, GPU_GSM_GPA | (bdsm_val & ~PCIM_BDSM_GSM_MASK));
+
+ /*
+ * GVT-d: Passthrough Opregion
+ */
+ uint32_t asls_val;
+ asls_val = read_config(&sc->psc_sel, PCIR_ASLS_CTL, 4);
+ if ((error = vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, sc->psc_sel.pc_func, GPU_OPREGION_GPA, GPU_OPREGION_SIZE, asls_val & PCIM_ASLS_OPREGION_MASK)) != 0)
+ goto done;
+ pci_set_cfgdata32(sc->psc_pi, PCIR_ASLS_CTL, GPU_OPREGION_GPA | (asls_val & ~PCIM_ASLS_OPREGION_MASK));
+
+ /*
+ * GVT-d: Change handler for cfg read and writes
+ */
+ sc->psc_pi->pi_d->pe_cfgread = passthru_cfgread_igd;
+ sc->psc_pi->pi_d->pe_cfgwrite = passthru_cfgwrite_igd;
+
+done:
+ if (error) {
+ vm_unmap_pptdev_mmio(ctx, sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, sc->psc_sel.pc_func, GPU_OPREGION_GPA, GPU_OPREGION_SIZE);
+ vm_unmap_pptdev_mmio(ctx, sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, sc->psc_sel.pc_func, GPU_GSM_GPA, GPU_GSM_SIZE);
+ }
+ return (error);
+}
+
static int
bar_access(int coff)
{
@@ -787,11 +988,47 @@
sc = pi->pi_arg;
/*
- * PCI BARs and MSI capability is emulated.
+ * MSI capability is emulated.
*/
- if (bar_access(coff) || msicap_access(sc, coff))
+ if (msicap_access(sc, coff))
return (-1);
+ if (bar_access(coff))
+ {
+ int idx, update_idx;
+
+ idx = (coff - PCIR_BAR(0)) / 4;
+
+ if (pi->pi_bar[idx].type == PCIBAR_MEMHI64)
+ update_idx = idx - 1;
+ else
+ update_idx = idx;
+
+ if (pci_get_cfgdata32(pi, 0x10 + idx * 0x04) == ~0U) {
+ uint64_t size = ~(uint64_t)(pi->pi_bar[update_idx].size - 1);
+ size |= sc->psc_bar[update_idx].lobits;
+ if (pi->pi_bar[idx].type == PCIBAR_MEMHI64)
+ *rv = size >> 32;
+ else
+ *rv = size;
+ if (bytes == 1)
+ *rv = *rv >> (coff & 0x3);
+ else if (bytes == 2)
+ *rv = *rv >> (coff & 0x1);
+ else
+ *rv = *rv;
+ }
+ else {
+ if (bytes == 1)
+ *rv = pci_get_cfgdata8(pi, coff);
+ else if (bytes == 2)
+ *rv = pci_get_cfgdata16(pi, coff);
+ else
+ *rv = pci_get_cfgdata32(pi, coff);
+ }
+ return (0);
+ }
+
#ifdef LEGACY_SUPPORT
/*
* Emulate PCIR_CAP_PTR if this device does not support MSI capability
@@ -803,25 +1040,28 @@
}
#endif
- /*
- * Emulate the command register. If a single read reads both the
- * command and status registers, read the status register from the
- * device's config space.
- */
- if (coff == PCIR_COMMAND) {
- if (bytes <= 2)
- return (-1);
- *rv = read_config(&sc->psc_sel, PCIR_STATUS, 2) << 16 |
- pci_get_cfgdata16(pi, PCIR_COMMAND);
- return (0);
- }
-
/* Everything else just read from the device's config space */
*rv = read_config(&sc->psc_sel, coff, bytes);
return (0);
}
+static int
+passthru_cfgread_igd(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+ int coff, int bytes, uint32_t *rv)
+{
+ /*
+ * GVT-d: Emulate BDSM and ASLS_CTL
+ *
+ * BDSM: contains Base of Data Stolen Memory
+ * ASLS_CTL: contains address of Opregion
+ */
+ if ((coff >= PCIR_BDSM && coff < PCIR_BDSM + 4) || (coff >= PCIR_ASLS_CTL && coff < PCIR_ASLS_CTL + 4))
+ return (-1);
+ else
+ return passthru_cfgread(ctx, vcpu, pi, coff, bytes, rv);
+}
+
static int
passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
int coff, int bytes, uint32_t val)
@@ -832,11 +1072,66 @@
sc = pi->pi_arg;
- /*
- * PCI BARs are emulated
- */
if (bar_access(coff))
- return (-1);
+ {
+ int idx, update_idx;
+ idx = (coff - PCIR_BAR(0)) / 4;
+ switch (pi->pi_bar[idx].type)
+ {
+ case PCIBAR_NONE:
+ pi->pi_bar[idx].addr = 0;
+ break;
+ case PCIBAR_IO:
+ case PCIBAR_MEM32:
+ case PCIBAR_MEM64:
+ case PCIBAR_MEMHI64:
+ if (pi->pi_bar[idx].type == PCIBAR_MEMHI64)
+ update_idx = idx - 1;
+ else
+ update_idx = idx;
+
+ uint16_t cmd = read_config(&sc->psc_sel, PCIR_COMMAND, 2);
+ if ((cmd & PCIM_CMD_MEMEN && pi->pi_bar[idx].type != PCIBAR_IO) ||
+ (cmd & PCIM_CMD_PORTEN && pi->pi_bar[idx].type == PCIBAR_IO)) {
+ unregister_bar_passthru(pi, update_idx);
+ }
+
+ if (val != ~0U) {
+ uint64_t mask, bar;
+ mask = ~(pi->pi_bar[update_idx].size - 1);
+ if (pi->pi_bar[idx].type == PCIBAR_MEMHI64)
+ mask >>= 32;
+ bar = val & mask;
+ if (pi->pi_bar[idx].type != PCIBAR_MEMHI64)
+ bar |= sc->psc_bar[update_idx].lobits;
+ pci_set_cfgdata32(pi, coff, bar);
+
+ uint32_t lo, hi;
+ lo = pci_get_cfgdata32(pi, 0x10 + update_idx * 0x04) & ~0x0F;
+ if (pi->pi_bar[update_idx].type == PCIBAR_MEM64)
+ hi = pci_get_cfgdata32(pi, 0x10 + (update_idx + 1) * 0x04);
+ else
+ hi = 0;
+ if (lo != ~0U && hi != ~0U) {
+ pi->pi_bar[update_idx].addr = (uint64_t)lo | ((uint64_t)hi << 32U);
+ if ((cmd & PCIM_CMD_MEMEN && pi->pi_bar[idx].type != PCIBAR_IO) ||
+ (cmd & PCIM_CMD_PORTEN && pi->pi_bar[idx].type == PCIBAR_IO)) {
+ register_bar_passthru(pi, update_idx);
+ }
+ }
+ else
+ pi->pi_bar[update_idx].addr = 0;
+ }
+ else {
+ pci_set_cfgdata32(pi, coff, ~0U);
+ pi->pi_bar[update_idx].addr = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return (0);
+ }
/*
* MSI capability is emulated
@@ -892,12 +1187,30 @@
pci_set_cfgdata8(pi, PCIR_COMMAND, val);
else if (bytes == 2)
pci_set_cfgdata16(pi, PCIR_COMMAND, val);
+ else
+ pci_set_cfgdata32(pi, PCIR_COMMAND, val);
pci_emul_cmd_changed(pi, cmd_old);
}
return (0);
}
+static int
+passthru_cfgwrite_igd(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+ int coff, int bytes, uint32_t val)
+{
+ /*
+ * GVT-d: Prevent write to BDSM and ASLS_CTL
+ *
+ * BDSM: contains Base of Data Stolen Memory
+ * ASLS_CTL: contains address of Opregion
+ */
+ if (coff == PCIR_BDSM || coff == PCIR_ASLS_CTL)
+ return (0);
+ else
+ return passthru_cfgwrite(ctx, vcpu, pi, coff, bytes, val);
+}
+
static void
passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
uint64_t offset, int size, uint64_t value)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Nov 14, 11:26 PM (9 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14635178
Default Alt Text
D26209.id76277.diff (24 KB)
Attached To
Mode
D26209: GVT-d support for bhyve
Attached
Detach File
Event Timeline
Log In to Comment