Ping. Any replies or commeents on this?
On Tue, Sep 15, 2020 at 12:54:49PM -0500, Jordan Hargrave wrote:
> 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 <[email protected]>
> + *
> + * 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<[email protected]>
> + *
> + * 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_ */