Page MenuHomeFreeBSD

D33010.id98568.diff
No OneTemporary

D33010.id98568.diff

diff --git a/usr.sbin/bhyve/pci_passthru.h b/usr.sbin/bhyve/pci_passthru.h
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/pci_passthru.h
@@ -0,0 +1,72 @@
+/*-
+ * 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$
+ */
+
+#pragma once
+
+#include <sys/pciio.h>
+
+#include <vmmapi.h>
+
+#include "pci_emul.h"
+
+typedef int (*cfgread_handler)(struct vmctx *ctx, int vcpu,
+ struct pci_devinst *pi, int coff, int bytes, uint32_t *rv);
+typedef int (*cfgwrite_handler)(struct vmctx *ctx, int vcpu,
+ struct pci_devinst *pi, int coff, int bytes, uint32_t val);
+
+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;
+
+ cfgread_handler psc_pcir_rhandler[PCI_REGMAX + 1];
+ cfgwrite_handler psc_pcir_whandler[PCI_REGMAX + 1];
+};
+
+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 passthru_cfgread_default(struct vmctx *ctx, int vcpu,
+ struct pci_devinst *pi, int coff, int bytes, uint32_t *rv);
+int passthru_cfgread_emulate(struct vmctx *ctx, int vcpu,
+ struct pci_devinst *pi, int coff, int bytes, uint32_t *rv);
+int passthru_cfgwrite_default(struct vmctx *ctx, int vcpu,
+ struct pci_devinst *pi, int coff, int bytes, uint32_t val);
+int passthru_cfgwrite_emulate(struct vmctx *ctx, int vcpu,
+ struct pci_devinst *pi, int coff, int bytes, uint32_t val);
+int set_pcir_handler(struct passthru_softc *sc, uint32_t reg, uint32_t len,
+ cfgread_handler rhandler, cfgwrite_handler whandler);
diff --git a/usr.sbin/bhyve/pci_passthru.c b/usr.sbin/bhyve/pci_passthru.c
--- a/usr.sbin/bhyve/pci_passthru.c
+++ b/usr.sbin/bhyve/pci_passthru.c
@@ -61,12 +61,11 @@
#include <unistd.h>
#include <machine/vmm.h>
-#include <vmmapi.h>
#include "config.h"
#include "debug.h"
-#include "pci_emul.h"
#include "mem.h"
+#include "pci_passthru.h"
#ifndef _PATH_DEVPCI
#define _PATH_DEVPCI "/dev/pci"
@@ -77,21 +76,9 @@
#define MSIX_TABLE_COUNT(ctrl) (((ctrl) & PCIM_MSIXCTRL_TABLE_SIZE) + 1)
#define MSIX_CAPLEN 12
-static int pcifd = -1;
+#define PCI_CAP_START_OFFSET 0x40
-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 pcifd = -1;
static int
msi_caplen(int msgctrl)
@@ -115,7 +102,7 @@
return (len);
}
-static uint32_t
+uint32_t
read_config(const struct pcisel *sel, long reg, int width)
{
struct pci_io pi;
@@ -131,7 +118,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;
@@ -570,6 +557,17 @@
sc->psc_sel.pc_dev = slot;
sc->psc_sel.pc_func = func;
+ /* copy physical PCI header to virtual cfgspace */
+ for (uint32_t i = 0; i < PCI_CAP_START_OFFSET; ++i) {
+ /*
+ * INTLINE and INTPIN shouldn't be aligned with it's physical
+ * value and they are already set by pci_emul_init
+ */
+ if (i == PCIR_INTLINE || i == PCIR_INTPIN)
+ continue;
+ pci_set_cfgdata8(pi, i, read_config(&sc->psc_sel, i, 1));
+ }
+
if (cfginitmsi(sc) != 0) {
warnx("failed to initialize MSI for PCI %d/%d/%d",
bus, slot, func);
@@ -590,6 +588,20 @@
return (error);
}
+int
+set_pcir_handler(struct passthru_softc *sc, uint32_t reg, uint32_t len, cfgread_handler rhandler, cfgwrite_handler whandler)
+{
+ if (reg > PCI_REGMAX || reg + len > PCI_REGMAX + 1)
+ return (-1);
+
+ for (uint32_t i = reg; i < reg + len; ++i) {
+ sc->psc_pcir_rhandler[i] = rhandler;
+ sc->psc_pcir_whandler[i] = whandler;
+ }
+
+ return 0;
+}
+
static int
passthru_legacy_config(nvlist_t *nvl, const char *opts)
{
@@ -678,7 +690,23 @@
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;
+
+ /* set default handler for all PCI registers */
+ if ((error = set_pcir_handler(sc, 0, PCI_REGMAX + 1,
+ passthru_cfgread_default, passthru_cfgwrite_default)) != 0)
+ goto done;
+ /* protect PCI header */
+ if ((error = set_pcir_handler(sc, 0, PCI_CAP_START_OFFSET,
+ passthru_cfgread_emulate, passthru_cfgwrite_emulate)) != 0)
+ goto done;
+ /* allow access to command and status register */
+ if ((error = set_pcir_handler(sc, PCIR_COMMAND, 0x04,
+ passthru_cfgread_default, passthru_cfgwrite_default)) != 0)
+ goto done;
+
+ error = 0; /* success */
done:
if (error) {
free(sc);
@@ -723,29 +751,29 @@
}
static int
-passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
- int coff, int bytes, uint32_t *rv)
+passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int coff,
+ int bytes, uint32_t *rv)
{
struct passthru_softc *sc;
sc = pi->pi_arg;
- /*
- * PCI BARs and MSI capability is emulated.
- */
- if (bar_access(coff) || msicap_access(sc, coff))
- return (-1);
+ return sc->psc_pcir_rhandler[coff](ctx, vcpu, pi, coff, bytes, rv);
+}
+
+int
+passthru_cfgread_default(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+ int coff, int bytes, uint32_t *rv)
+{
+ struct passthru_softc *sc;
+
+ sc = pi->pi_arg;
-#ifdef LEGACY_SUPPORT
/*
- * Emulate PCIR_CAP_PTR if this device does not support MSI capability
- * natively.
+ * MSI capability is emulated.
*/
- if (sc->psc_msi.emulated) {
- if (coff >= PCIR_CAP_PTR && coff < PCIR_CAP_PTR + 4)
- return (-1);
- }
-#endif
+ if (msicap_access(sc, coff))
+ return (-1);
/*
* Emulate the command register. If a single read reads both the
@@ -766,9 +794,28 @@
return (0);
}
+int
+passthru_cfgread_emulate(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+ int coff, int bytes, uint32_t *rv)
+{
+ return (-1);
+}
+
static int
-passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
- int coff, int bytes, uint32_t val)
+passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int coff,
+ int bytes, uint32_t val)
+{
+
+ struct passthru_softc *sc;
+
+ sc = pi->pi_arg;
+
+ return sc->psc_pcir_whandler[coff](ctx, vcpu, pi, coff, bytes, val);
+}
+
+int
+passthru_cfgwrite_default(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+ int coff, int bytes, uint32_t val)
{
int error, msix_table_entries, i;
struct passthru_softc *sc;
@@ -776,12 +823,6 @@
sc = pi->pi_arg;
- /*
- * PCI BARs are emulated
- */
- if (bar_access(coff))
- return (-1);
-
/*
* MSI capability is emulated
*/
@@ -847,6 +888,13 @@
return (0);
}
+int
+passthru_cfgwrite_emulate(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+ int coff, int bytes, uint32_t val)
+{
+ return (-1);
+}
+
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

Mime Type
text/plain
Expires
Sat, May 16, 8:17 PM (3 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33150600
Default Alt Text
D33010.id98568.diff (8 KB)

Event Timeline