Ping.  Can anyone review this?

________________________________
From: Jordan Hargrave <jordan_hargr...@hotmail.com>
Sent: Tuesday, September 15, 2020 12:54 PM
To: tech@openbsd.org <tech@openbsd.org>; jor...@openbsd.org 
<jor...@openbsd.org>; kette...@openbsd.org <kette...@openbsd.org>
Subject: PATCH: Add vmmpci device for passthrough PCI

This adds a placeholder vmmpci device that will be used for VMD passthrough PCI.

Normally the device will fail to attach unless the PCI domain:bus.dev.func has
been registered with vmmpci_add.  When the device is registered, it will detach
any existing PCI device and reload as vmmpci.  It also attaches an interrupt 
handler
and keeps a running counter of triggered interrupts. VMD will use the counter to
issue commands through to the guest.

diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 2c49f91a1..a69c72c26 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -108,6 +109,7 @@ ksmn*       at pci?                 # AMD K17 temperature 
sensor
 amas*   at pci? disable         # AMD memory configuration
 pchtemp* at pci?                # Intel C610 termperature sensor
 ccp*    at pci?                 # AMD Cryptographic Co-processor
+vmmpci* at pci?                        # VMM Placeholder

 # National Semiconductor LM7[89] and compatible hardware monitors
 lm0     at isa? port 0x290
diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64
index 7a5d40bf4..74c7fe5a9 100644
--- a/sys/arch/amd64/conf/files.amd64
+++ b/sys/arch/amd64/conf/files.amd64
@@ -132,6 +132,10 @@ device     pchb: pcibus, agpbus
 attach  pchb at pci
 file    arch/amd64/pci/pchb.c                   pchb

+device vmmpci
+attach vmmpci at pci
+file   arch/amd64/pci/vmmpci.c                 vmmpci
+
 # AMAS AMD memory address switch
 device  amas
 attach  amas at pci
diff --git a/sys/arch/amd64/include/vmmpci.h b/sys/arch/amd64/include/vmmpci.h
new file mode 100644
index 000000000..e012194df
--- /dev/null
+++ b/sys/arch/amd64/include/vmmpci.h
@@ -0,0 +1,24 @@
+/*     $OpenBSD: vmmvar.h,v 1.70 2020/04/08 07:39:48 pd Exp $  */
+/*
+ * Copyright (c) 2020 Jordan Hargrave <jor...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _VMMPCI_H_
+#define _VMMPCI_H_
+
+int vmmpci_find(int, pcitag_t);
+int vmmpci_add(int, pcitag_t, int);
+int vmmpci_pending(int, pcitag_t, uint32_t *);
+
+#endif
diff --git a/sys/arch/amd64/pci/vmmpci.c b/sys/arch/amd64/pci/vmmpci.c
new file mode 100644
index 000000000..a99efb502
--- /dev/null
+++ b/sys/arch/amd64/pci/vmmpci.c
@@ -0,0 +1,186 @@
+/*     $OpenBSD: pcib.c,v 1.6 2013/05/30 16:15:01 deraadt Exp $        */
+/*     $NetBSD: pcib.c,v 1.6 1997/06/06 23:29:16 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1996 Jordan Hargrave<jordan_hargr...@hotmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <dev/pci/pcidevs.h>
+
+#include <machine/vmmvar.h>
+#include <machine/vmmpci.h>
+
+struct vmmpci_softc {
+       struct device            sc_dev;
+       void                    *sc_ih;
+
+       int                     sc_domain;
+       pci_chipset_tag_t       sc_pc;
+       pcitag_t                sc_tag;
+
+       uint32_t                 pending;                // pending interrupt 
count
+};
+
+#define VP_VALID       0x80000000
+
+/* Keep track of registered devices */
+struct vmmpci_dev {
+       int                     vp_flags;
+       int                     vp_domain;
+       pcitag_t                vp_tag;
+};
+
+int    vmmpci_match(struct device *, void *, void *);
+void   vmmpci_attach(struct device *, struct device *, void *);
+void   vmmpci_callback(struct device *);
+int    vmmpci_print(void *, const char *);
+int     vmmpci_intr(void *arg);
+
+struct cfattach vmmpci_ca = {
+       sizeof(struct vmmpci_softc), vmmpci_match, vmmpci_attach
+};
+
+struct cfdriver vmmpci_cd = {
+       NULL, "vmmpci", DV_DULL
+};
+
+#define MAXVMMPCI 4
+
+struct vmmpci_dev vmmpcis[MAXVMMPCI];
+
+/* Interrupt handler. Increase pending count for ioctl.  TODO:better method? */
+int
+vmmpci_intr(void *arg)
+{
+       struct vmmpci_softc *sc = arg;
+
+       sc->pending++;
+       return 1;
+}
+
+/* Get number of pending interrupts for a device */
+int
+vmmpci_pending(int domain, pcitag_t tag, uint32_t *pending)
+{
+       struct vmmpci_softc *sc;
+
+       /* Are we mapped? */
+       if (!vmmpci_find(domain, tag))
+               return (0);
+
+       /* If we are mapped, the device should be a VMMPCI */
+       sc = (struct vmmpci_softc *)pci_find_bytag(domain, tag);
+       if (sc == NULL)
+               return (0);
+
+       /* Return current pending count */
+       *pending = sc->pending;
+       return (1);
+}
+
+/* Check if this PCI device has been registered */
+int
+vmmpci_find(int domain, pcitag_t tag)
+{
+       int i;
+
+       for (i = 0; i < MAXVMMPCI; i++) {
+               if ((vmmpcis[i].vp_flags & VP_VALID) &&
+                   vmmpcis[i].vp_domain == domain &&
+                   vmmpcis[i].vp_tag == tag)
+                       return (1);
+       }
+       return (0);
+}
+
+/* Add a PCI device to valid passthrough list and reprobe */
+int
+vmmpci_add(int domain, pcitag_t tag, int flags)
+{
+       struct pci_softc *psc;
+       struct device *pd;
+       int i;
+
+       /* Check if we are already mapped */
+       if (vmmpci_find(domain, tag))
+               return (1);
+
+       for (i = 0; i < MAXVMMPCI; i++) {
+               if ((vmmpcis[i].vp_flags & VP_VALID) == 0) {
+                       /* Find parent device */
+                       pd = (struct device *)pci_find_bytag(domain, tag);
+                       if (pd == NULL)
+                               return (0);
+
+                       vmmpcis[i].vp_domain = domain;
+                       vmmpcis[i].vp_tag = tag;
+                       vmmpcis[i].vp_flags = VP_VALID | flags;
+
+                       /* detach the old device, reattach */
+                       psc = (struct pci_softc *)pd->dv_parent;
+                       config_detach(pd, 0);
+
+                       pci_probe_device(psc, tag, NULL, NULL);
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+int
+vmmpci_match(struct device *parent, void *match, void *aux)
+{
+       struct pci_attach_args *pa = aux;
+       int rc;
+
+       /* Check if device is registered, claim it */
+       rc = vmmpci_find(pa->pa_domain, pa->pa_tag);
+       if (rc)
+               return (100);
+       return (0);
+}
+
+void
+vmmpci_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct vmmpci_softc      *sc = (struct vmmpci_softc *)self;
+       struct pci_attach_args   *pa = aux;
+       pci_chipset_tag_t       pc  = pa->pa_pc;
+       pci_intr_handle_t       ih;
+
+       sc->sc_pc  = pc;
+       sc->sc_tag = pa->pa_tag;
+
+       /* Map our interrupt (TODO: what about devices with no interrupt?) */
+       if (pci_intr_map_msi(pa, &ih) || pci_intr_map(pa, &ih)) {
+               printf(": couldn't map interrupt\n");
+               return;
+       }
+       sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, vmmpci_intr,
+                       sc, sc->sc_dev.dv_xname);
+       if (sc->sc_ih == NULL) {
+               printf(": couldn't establish interrupt");
+               return;
+       }
+}
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index bc20739e5..01af8e3b7 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1162,6 +1162,34 @@ pci_disable_legacy_vga(struct device *dev)
         }
 }

+struct device *
+pci_find_bytag(int domain, pcitag_t tag)
+{
+       struct pci_softc *pci;
+       struct pci_dev *pd;
+       int bus, i;
+
+       /* Lookup pci softc by domain/bus */
+       for (i = 0; i < pci_cd.cd_ndevs; i++) {
+               pci = pci_cd.cd_devs[i];
+               if (pci == NULL || pci->sc_domain != domain)
+                       continue;
+               pci_decompose_tag(pci->sc_pc, tag, &bus, NULL, NULL);
+               if (pci->sc_bus == bus)
+                       break;
+       }
+
+       if (!pci)
+               return NULL;
+
+       /* Lookup by tag (devfn) */
+       LIST_FOREACH(pd, &pci->sc_devs, pd_next)
+               if (tag == pd->pd_tag)
+                       return (void *)pd->pd_dev;
+
+       return NULL;
+}
+
 #ifdef USER_PCICONF
 /*
  * This is the user interface to PCI configuration space.
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index e85f6fe81..6cd0b4660 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -284,5 +284,7 @@ const struct pci_quirkdata *
         pci_lookup_quirkdata(pci_vendor_id_t, pci_product_id_t);
 void    pciagp_set_pchb(struct pci_attach_args *);

+struct device *pci_find_bytag(int, pcitag_t);
+
 #endif /* _KERNEL */
 #endif /* _DEV_PCI_PCIVAR_H_ */

Reply via email to