Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Aug 2022 22:25:33 GMT
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: baf753cc196e - main - bhyve: Support other schemes for naming pass-through devices.
Message-ID:  <202208192225.27JMPXtu068474@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=baf753cc196e2308828c7fb9b0385d5fe17ecdc2

commit baf753cc196e2308828c7fb9b0385d5fe17ecdc2
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2022-08-19 21:55:29 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-08-19 21:58:55 +0000

    bhyve: Support other schemes for naming pass-through devices.
    
    Permit naming pass through devices using the syntax accepted by
    pciconf (pci[<domain>:]<bus>:<slot>:<func>) as well as by device name
    (e.g. "ppt0").
    
    While here, fix an error in the manpage that had the bus and slot
    arguments for the original /-delimited scheme swapped.
    
    Reviewed by:    imp, markj
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D36147
---
 usr.sbin/bhyve/bhyve.8        |  27 ++++++++--
 usr.sbin/bhyve/bhyve_config.5 |  12 ++++-
 usr.sbin/bhyve/pci_passthru.c | 112 ++++++++++++++++++++++++++++++++++++------
 3 files changed, 131 insertions(+), 20 deletions(-)

diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
index 92534d226499..84e031f1340c 100644
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 28, 2021
+.Dd August 19, 2022
 .Dt BHYVE 8
 .Os
 .Sh NAME
@@ -390,6 +390,7 @@ Network device backends:
 .Xc
 .El
 .Sm on
+.Pp
 If
 .Cm mac
 is not specified, the MAC address is derived from a fixed OUI and the
@@ -520,14 +521,32 @@ to that file.
 .El
 .Pp
 Pass-through device backends:
-.Bl -tag -width 10n
-.It Ns Ar slot Ns Cm \&/ Ns Ar bus Ns Cm \&/ Ns Ar function
-Connect to a PCI device on the host at the selector described by
+.Sm off
+.Bl -bullet
+.It
+.Cm ppt Ar N Oo , Ar passthru-device-options Oc
+.It
+.Ns Ar bus Cm \&/ Ar slot Cm \&/ Ar function
+.Op , Ar passthru-device-options
+.It
+.Cm pci Ar bus Cm : Ar slot Cm : Ns Ar function
+.Op , Ar passthru-device-options
+.El
+.Sm on
+.Pp
+Connect to a PCI device on the host either named ppt
+.Ns Ar N
+or at the selector described by
 .Ar slot ,
 .Ar bus ,
 and
 .Ar function
 numbers.
+.Pp
+The
+.Ar passthru-device-options
+are:
+.Bl -tag -width 10n
 .It Cm rom= Ns Ar romfile
 Add
 .Ar romfile
diff --git a/usr.sbin/bhyve/bhyve_config.5 b/usr.sbin/bhyve/bhyve_config.5
index 20109170b094..94a8a4d5cb1d 100644
--- a/usr.sbin/bhyve/bhyve_config.5
+++ b/usr.sbin/bhyve/bhyve_config.5
@@ -23,7 +23,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd June 30, 2022
+.Dd August 19, 2022
 .Dt BHYVE_CONFIG 5
 .Os
 .Sh NAME
@@ -575,6 +575,12 @@ If set, allocate a memory disk as the backing store.
 The value of this variable is the size of the memory disk in megabytes.
 .El
 .Ss PCI Passthrough Settings
+The
+.Xr ppt 4
+device driver must be attached to the
+PCI device being passed through.
+The device to pass through can be identified either by name or its
+host PCI bus location.
 .Bl -column "Name" "integer" "Default"
 .It Sy Name Ta Sy Format Ta Sy Default Ta Sy Description
 .It Va bus Ta integer Ta Ta
@@ -583,6 +589,10 @@ Host PCI bus address of device to pass through.
 Host PCI slot address of device to pass through.
 .It Va func Ta integer Ta Ta
 Host PCI function address of device to pass through.
+.It Va pptdev Ta string Ta Ta
+Name of a
+.Xr ppt 4
+device to pass through.
 .It Va rom Ta path Ta Ta
 ROM file of the device which will be executed by OVMF to init the device.
 .El
diff --git a/usr.sbin/bhyve/pci_passthru.c b/usr.sbin/bhyve/pci_passthru.c
index 2b2f240fafe3..43e70d42e2b2 100644
--- a/usr.sbin/bhyve/pci_passthru.c
+++ b/usr.sbin/bhyve/pci_passthru.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
 #ifndef WITHOUT_CAPSICUM
 #include <capsicum_helpers.h>
 #endif
+#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -132,7 +133,7 @@ pcifd_init(void)
 		errx(EX_OSERR, "Unable to apply rights for sandbox");
 
 	const cap_ioctl_t pcifd_ioctls[] = { PCIOCREAD, PCIOCWRITE, PCIOCGETBAR,
-		PCIOCBARIO, PCIOCBARMMAP };
+		PCIOCBARIO, PCIOCBARMMAP, PCIOCGETCONF };
 	if (caph_ioctls_limit(pcifd, pcifd_ioctls, nitems(pcifd_ioctls)) == -1)
 		errx(EX_OSERR, "Unable to apply rights for sandbox");
 #endif
@@ -645,30 +646,39 @@ done:
 static int
 passthru_legacy_config(nvlist_t *nvl, const char *opts)
 {
+	const char *cp;
+	char *tofree;
 	char value[16];
 	int bus, slot, func;
 
 	if (opts == NULL)
 		return (0);
 
-	if (sscanf(opts, "%d/%d/%d", &bus, &slot, &func) != 3) {
+	cp = strchr(opts, ',');
+
+	if (strncmp(opts, "ppt", strlen("ppt")) == 0) {
+		tofree = strndup(opts, cp - opts);
+		set_config_value_node(nvl, "pptdev", tofree);
+		free(tofree);
+	} else if (sscanf(opts, "pci0:%d:%d:%d", &bus, &slot, &func) == 3 ||
+	    sscanf(opts, "pci%d:%d:%d", &bus, &slot, &func) == 3 ||
+	    sscanf(opts, "%d/%d/%d", &bus, &slot, &func) == 3) {
+		snprintf(value, sizeof(value), "%d", bus);
+		set_config_value_node(nvl, "bus", value);
+		snprintf(value, sizeof(value), "%d", slot);
+		set_config_value_node(nvl, "slot", value);
+		snprintf(value, sizeof(value), "%d", func);
+		set_config_value_node(nvl, "func", value);
+	} else {
 		EPRINTLN("passthru: invalid options \"%s\"", opts);
 		return (-1);
 	}
 
-	snprintf(value, sizeof(value), "%d", bus);
-	set_config_value_node(nvl, "bus", value);
-	snprintf(value, sizeof(value), "%d", slot);
-	set_config_value_node(nvl, "slot", value);
-	snprintf(value, sizeof(value), "%d", func);
-	set_config_value_node(nvl, "func", value);
-
-	opts = strchr(opts, ',');
-	if (opts == NULL) {
+	if (cp == NULL) {
 		return (0);
 	}
 
-	return pci_parse_legacy_config(nvl, opts + 1);
+	return (pci_parse_legacy_config(nvl, cp + 1));
 }
 
 static int
@@ -722,6 +732,72 @@ passthru_init_rom(struct vmctx *const ctx, struct passthru_softc *const sc,
 	return (0);
 }
 
+static bool
+passthru_lookup_pptdev(const char *name, int *bus, int *slot, int *func)
+{
+	struct pci_conf_io pc;
+	struct pci_conf conf[1];
+	struct pci_match_conf patterns[1];
+	char *cp;
+
+	bzero(&pc, sizeof(struct pci_conf_io));
+	pc.match_buf_len = sizeof(conf);
+	pc.matches = conf;
+
+	bzero(&patterns, sizeof(patterns));
+
+	/*
+	 * The pattern structure requires the unit to be split out from
+	 * the driver name.  Walk backwards from the end of the name to
+	 * find the start of the unit.
+	 */
+	cp = strchr(name, '\0');
+	assert(cp != NULL);
+	while (cp != name && isdigit(cp[-1]))
+		cp--;
+	if (cp == name || !isdigit(*cp)) {
+		EPRINTLN("Invalid passthru device name %s", name);
+		return (false);
+	}
+	if ((size_t)(cp - name) + 1 > sizeof(patterns[0].pd_name)) {
+		EPRINTLN("Passthru device name %s is too long", name);
+		return (false);
+	}
+	memcpy(patterns[0].pd_name, name, cp - name);
+	patterns[0].pd_unit = strtol(cp, &cp, 10);
+	if (*cp != '\0') {
+		EPRINTLN("Invalid passthru device name %s", name);
+		return (false);
+	}
+	patterns[0].flags = PCI_GETCONF_MATCH_NAME | PCI_GETCONF_MATCH_UNIT;
+	pc.num_patterns = 1;
+	pc.pat_buf_len = sizeof(patterns);
+	pc.patterns = patterns;
+
+	if (ioctl(pcifd, PCIOCGETCONF, &pc) == -1) {
+		EPRINTLN("ioctl(PCIOCGETCONF): %s", strerror(errno));
+		return (false);
+	}
+	if (pc.status != PCI_GETCONF_LAST_DEVICE &&
+	    pc.status != PCI_GETCONF_MORE_DEVS) {
+		EPRINTLN("error returned from PCIOCGETCONF ioctl");
+		return (false);
+	}
+	if (pc.num_matches == 0) {
+		EPRINTLN("Passthru device %s not found", name);
+		return (false);
+	}
+
+	if (conf[0].pc_sel.pc_domain != 0) {
+		EPRINTLN("Passthru device %s on unsupported domain", name);
+		return (false);
+	}
+	*bus = conf[0].pc_sel.pc_bus;
+	*slot = conf[0].pc_sel.pc_dev;
+	*func = conf[0].pc_sel.pc_func;
+	return (true);
+}
+
 static int
 passthru_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
 {
@@ -751,9 +827,15 @@ passthru_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
 	var = atoi(value);						\
 } while (0)
 
-	GET_INT_CONFIG(bus, "bus");
-	GET_INT_CONFIG(slot, "slot");
-	GET_INT_CONFIG(func, "func");
+	value = get_config_value_node(nvl, "pptdev");
+	if (value != NULL) {
+		if (!passthru_lookup_pptdev(value, &bus, &slot, &func))
+			return (error);
+	} else {
+		GET_INT_CONFIG(bus, "bus");
+		GET_INT_CONFIG(slot, "slot");
+		GET_INT_CONFIG(func, "func");
+	}
 
 	if (vm_assign_pptdev(ctx, bus, slot, func) != 0) {
 		warnx("PCI device at %d/%d/%d is not using the ppt(4) driver",



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202208192225.27JMPXtu068474>