summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bhyve/pci_emul.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bhyve/pci_emul.c')
-rw-r--r--usr.sbin/bhyve/pci_emul.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
index 32a3deb..cb09b7c 100644
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -740,6 +740,38 @@ msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
CFGWRITE(pi, offset, val, bytes);
}
+void
+pciecap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
+ int bytes, uint32_t val)
+{
+
+ /* XXX don't write to the readonly parts */
+ CFGWRITE(pi, offset, val, bytes);
+}
+
+#define PCIECAP_VERSION 0x2
+int
+pci_emul_add_pciecap(struct pci_devinst *pi, int type)
+{
+ int err;
+ struct pciecap pciecap;
+
+ CTASSERT(sizeof(struct pciecap) == 60);
+
+ if (type != PCIEM_TYPE_ROOT_PORT)
+ return (-1);
+
+ bzero(&pciecap, sizeof(pciecap));
+
+ pciecap.capid = PCIY_EXPRESS;
+ pciecap.pcie_capabilities = PCIECAP_VERSION | PCIEM_TYPE_ROOT_PORT;
+ pciecap.link_capabilities = 0x411; /* gen1, x1 */
+ pciecap.link_status = 0x11; /* gen1, x1 */
+
+ err = pci_emul_add_capability(pi, (u_char *)&pciecap, sizeof(pciecap));
+ return (err);
+}
+
/*
* This function assumes that 'coff' is in the capabilities region of the
* config space.
@@ -782,6 +814,9 @@ pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val)
case PCIY_MSIX:
msixcap_cfgwrite(pi, capoff, offset, bytes, val);
break;
+ case PCIY_EXPRESS:
+ pciecap_cfgwrite(pi, capoff, offset, bytes, val);
+ break;
default:
break;
}
@@ -811,12 +846,29 @@ pci_emul_iscap(struct pci_devinst *pi, int offset)
return (found);
}
+static int
+pci_emul_fallback_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr,
+ int size, uint64_t *val, void *arg1, long arg2)
+{
+ /*
+ * Ignore writes; return 0xff's for reads. The mem read code
+ * will take care of truncating to the correct size.
+ */
+ if (dir == MEM_F_READ) {
+ *val = 0xffffffffffffffff;
+ }
+
+ return (0);
+}
+
void
init_pci(struct vmctx *ctx)
{
+ struct mem_range memp;
struct pci_devemu *pde;
struct slotinfo *si;
int slot, func;
+ int error;
pci_emul_iobase = PCI_EMUL_IOBASE;
pci_emul_membase32 = PCI_EMUL_MEMBASE32;
@@ -844,6 +896,20 @@ init_pci(struct vmctx *ctx)
lirq[11].li_generic = 1;
lirq[12].li_generic = 1;
lirq[15].li_generic = 1;
+
+ /*
+ * Setup the PCI hole to return 0xff's when accessed in a region
+ * with no devices
+ */
+ memset(&memp, 0, sizeof(struct mem_range));
+ memp.name = "PCI hole";
+ memp.flags = MEM_F_RW;
+ memp.base = lomem_sz;
+ memp.size = (4ULL * 1024 * 1024 * 1024) - lomem_sz;
+ memp.handler = pci_emul_fallback_handler;
+
+ error = register_mem_fallback(&memp);
+ assert(error == 0);
}
int
OpenPOWER on IntegriCloud