From nobody Mon Feb 16 15:44:30 2026 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fF6XH0Hrgz6RxVm for ; Mon, 16 Feb 2026 15:44:31 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fF6XG5PMyz4P9n for ; Mon, 16 Feb 2026 15:44:30 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1771256670; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=w6Lm6PiK1Hcp0Uhv5ubVFjkurXbgxIxLULnF1o3wOWw=; b=CmCSA1R1WlGPquML45FJYfgVhd5EdV3QZXd7Ezod9aoeMc2ppdPXEd9WrrGaatOpDwlSwl ssqWfNsrvam829yrCvKoBJeGbDfYSSXICJ7XGbiJwhEw2FJGkOxlMuv4A3fnZ68VXYgm4T EpRC8WF5mNZ8Yl5Te8aO4pWqOotjtne+E3w0dGFLPsMV/LDb1tBFhy3/rp80nfeErfZxGu qBe8hZ0FEe7kJIJ6auxi+4Z1E97sJkxyWLZ3RbM6+cCUPXkWgBWBPn33A9iNjw0QXf/4/q ZsYf5iSaQBXH899xqnI82ImBB/o+ooE8bbTLbJWgegaX++7GznHDdi6L5uUNyA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1771256670; a=rsa-sha256; cv=none; b=OPOhKjPlvBNzlpd/UzyvF8DI4CPRxL1hd9jAwm+QVVQI0gi4xk6piTz9s2fK0TJcsxzL0P dq0nYznNGzdsI94emGln9oJCNmmEyjA9pFm0OuZ8nW2sAQtwCrwonl7UxZYxSLxJBEDvyv 7W0+P4u05keq/YPLoEwIhsIXFsLGvrB8oS37VRPU9+xv+XJufgi3F3PjbPiEt9lSHwUEX5 2EYhrmnd8IP+r/qqRW2NKZEQIejPZ8cThEerRi7lmPg3ptPbFaoVzSsJ43IhY97v50Z1Rm G/9VWqiAhHJ6l3MGbGSIZLf7C5Ww52HMjYBfuOt/B5vfKRWnPIlwSfq0M4Cw4g== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1771256670; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=w6Lm6PiK1Hcp0Uhv5ubVFjkurXbgxIxLULnF1o3wOWw=; b=RbB9urjQAbG8y7RRUW/rZcumTnud/0fOD+Z2oLx4cXl5CBpkQVUOBShTePvyGRDtInBoDA hWXapgLYhi2lpV+68IxW2vNDAc31jBDnRh4WRRRd7lqdthUC4RYeNDudapdmYM9qT9Sj47 SdnjKyuGwzt7OImaU/IRTF1PTFJ8v7bC++imIHYuxuZPZj5FnYYMRnLoAFuSDaFzbcx0cs kEnVnFgT5DEDDvIGegFUg5RaR7JId3iHZWpaaw7XKEtVMbNnrfEh0+EGeDhkfhsExjbrul cPO9WmvQQaV3AZEeS64LfYPfxC6ddtJIjqw/50tAzsuKd0V4PzcpvaFpgA45lA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fF6XG4vxGzTZv for ; Mon, 16 Feb 2026 15:44:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1f246 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 16 Feb 2026 15:44:30 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Mark Johnston Subject: git: d80fe2df0ec7 - stable/15 - bhyve: Use PCIOCGETCONF to find the host LPC bridge List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: d80fe2df0ec7561200a4a02cf123e1896b27784c Auto-Submitted: auto-generated Date: Mon, 16 Feb 2026 15:44:30 +0000 Message-Id: <69933b5e.1f246.5b466ec@gitrepo.freebsd.org> The branch stable/15 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=d80fe2df0ec7561200a4a02cf123e1896b27784c commit d80fe2df0ec7561200a4a02cf123e1896b27784c Author: Mark Johnston AuthorDate: 2026-01-26 21:05:06 +0000 Commit: Mark Johnston CommitDate: 2026-02-16 13:42:11 +0000 bhyve: Use PCIOCGETCONF to find the host LPC bridge pci_host_read_config() requires write access to /dev/pci so cannot be used with unprivileged bhyve. The lpc init code uses it to find the host system's LPC bridge device and so was generating warnings with bhyve running as a non-root user. Refactor the implementation to use PCIOCGETCONF instead, which doesn't require any special privileges. This isn't formally necessary, as we only care about copying the host system's identifiers in order to support Intel GPU passthrough (see commit f4ceaff56ddaa), but it's straightforward and lets an unprivileged user run bhyve without seeing warnings about failing to open /dev/pci with write permissions. Reviewed by: corvink, rew MFC after: 3 weeks Sponsored by: The FreeBSD Foundation Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D54851 (cherry picked from commit 1db1e4bdc64f29661592a47f2feb690d7cf37957) --- usr.sbin/bhyve/amd64/pci_lpc.c | 79 +++++++++++++++++++++++++----------------- usr.sbin/bhyve/pci_emul.c | 22 ++++++------ usr.sbin/bhyve/pci_emul.h | 2 +- 3 files changed, 60 insertions(+), 43 deletions(-) diff --git a/usr.sbin/bhyve/amd64/pci_lpc.c b/usr.sbin/bhyve/amd64/pci_lpc.c index ed41a800a2ea..52e9faec22af 100644 --- a/usr.sbin/bhyve/amd64/pci_lpc.c +++ b/usr.sbin/bhyve/amd64/pci_lpc.c @@ -28,10 +28,12 @@ */ #include + #include #include #include +#include #include #include #include @@ -46,7 +48,6 @@ #include "pci_emul.h" #include "pci_irq.h" #include "pci_lpc.h" -#include "pci_passthru.h" #include "pctestdev.h" #include "tpm_device.h" #include "uart_emul.h" @@ -460,34 +461,48 @@ pci_lpc_read(struct pci_devinst *pi __unused, int baridx __unused, #define LPC_SUBDEV_0 0x0000 static int -pci_lpc_get_sel(struct pcisel *const sel) +pci_lpc_get_conf(struct pci_conf *conf) { - assert(sel != NULL); - - memset(sel, 0, sizeof(*sel)); - - for (uint8_t slot = 0; slot <= PCI_SLOTMAX; ++slot) { - uint8_t max_func = 0; - - sel->pc_dev = slot; - sel->pc_func = 0; + struct pci_conf_io pcio; + struct pci_match_conf pmc; + int pcifd; - if (pci_host_read_config(sel, PCIR_HDRTYPE, 1) & PCIM_MFDEV) - max_func = PCI_FUNCMAX; + pcifd = open("/dev/pci", O_RDONLY); + if (pcifd < 0) { + warn("%s: Unable to open /dev/pci", __func__); + return (-1); + } - for (uint8_t func = 0; func <= max_func; ++func) { - sel->pc_func = func; +restart: + memset(&pcio, 0, sizeof(pcio)); + memset(&pmc, 0, sizeof(pmc)); + pmc.pc_class = PCIC_BRIDGE; + pmc.flags = PCI_GETCONF_MATCH_CLASS; + do { + pcio.pat_buf_len = sizeof(pmc); + pcio.num_patterns = 1; + pcio.patterns = &pmc; + pcio.match_buf_len = sizeof(*conf); + pcio.matches = conf; + if (ioctl(pcifd, PCIOCGETCONF, &pcio) == -1) { + warn("%s: ioctl(PCIOCGETCONF) failed", __func__); + break; + } + if (pcio.num_matches == 0) + break; + if (pcio.status == PCI_GETCONF_LIST_CHANGED) + goto restart; - if (pci_host_read_config(sel, PCIR_CLASS, 1) == - PCIC_BRIDGE && - pci_host_read_config(sel, PCIR_SUBCLASS, 1) == - PCIS_BRIDGE_ISA) { - return (0); - } + if (conf->pc_class == PCIC_BRIDGE && + conf->pc_subclass == PCIS_BRIDGE_ISA) { + close(pcifd); + return (0); } - } + } while (pcio.status == PCI_GETCONF_MORE_DEVS); + + close(pcifd); - warnx("%s: Unable to find host selector of LPC bridge.", __func__); + warnx("%s: Unable to find host selector of LPC bridge", __func__); return (-1); } @@ -495,8 +510,7 @@ pci_lpc_get_sel(struct pcisel *const sel) static int pci_lpc_init(struct pci_devinst *pi, nvlist_t *nvl) { - struct pcisel sel = { 0 }; - struct pcisel *selp = NULL; + struct pci_conf conf, *confp; uint16_t device, subdevice, subvendor, vendor; uint8_t revid; @@ -521,15 +535,16 @@ pci_lpc_init(struct pci_devinst *pi, nvlist_t *nvl) if (lpc_init(pi->pi_vmctx) != 0) return (-1); - if (pci_lpc_get_sel(&sel) == 0) - selp = &sel; + confp = NULL; + if (pci_lpc_get_conf(&conf) == 0) + confp = &conf; - vendor = pci_config_read_reg(selp, nvl, PCIR_VENDOR, 2, LPC_VENDOR); - device = pci_config_read_reg(selp, nvl, PCIR_DEVICE, 2, LPC_DEV); - revid = pci_config_read_reg(selp, nvl, PCIR_REVID, 1, LPC_REVID); - subvendor = pci_config_read_reg(selp, nvl, PCIR_SUBVEND_0, 2, + vendor = pci_config_read_reg(confp, nvl, PCIR_VENDOR, 2, LPC_VENDOR); + device = pci_config_read_reg(confp, nvl, PCIR_DEVICE, 2, LPC_DEV); + revid = pci_config_read_reg(confp, nvl, PCIR_REVID, 1, LPC_REVID); + subvendor = pci_config_read_reg(confp, nvl, PCIR_SUBVEND_0, 2, LPC_SUBVEND_0); - subdevice = pci_config_read_reg(selp, nvl, PCIR_SUBDEV_0, 2, + subdevice = pci_config_read_reg(confp, nvl, PCIR_SUBDEV_0, 2, LPC_SUBDEV_0); /* initialize config space */ diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c index 9d6060e3e254..dc27402675ee 100644 --- a/usr.sbin/bhyve/pci_emul.c +++ b/usr.sbin/bhyve/pci_emul.c @@ -353,49 +353,51 @@ pci_print_supported_devices(void) } uint32_t -pci_config_read_reg(const struct pcisel *const host_sel, nvlist_t *nvl, +pci_config_read_reg(const struct pci_conf *host_conf, nvlist_t *nvl, const uint32_t reg, const uint8_t size, const uint32_t def) { const char *config; const nvlist_t *pci_regs; + uint32_t host; assert(size == 1 || size == 2 || size == 4); pci_regs = find_relative_config_node(nvl, "pcireg"); if (pci_regs == NULL) { - return def; + return (def); } switch (reg) { case PCIR_DEVICE: config = get_config_value_node(pci_regs, "device"); + host = host_conf != NULL ? host_conf->pc_device : 0; break; case PCIR_VENDOR: config = get_config_value_node(pci_regs, "vendor"); + host = host_conf != NULL ? host_conf->pc_vendor : 0; break; case PCIR_REVID: config = get_config_value_node(pci_regs, "revid"); + host = host_conf != NULL ? host_conf->pc_revid : 0; break; case PCIR_SUBVEND_0: config = get_config_value_node(pci_regs, "subvendor"); + host = host_conf != NULL ? host_conf->pc_subvendor : 0; break; case PCIR_SUBDEV_0: config = get_config_value_node(pci_regs, "subdevice"); + host = host_conf != NULL ? host_conf->pc_subdevice : 0; break; default: return (-1); } if (config == NULL) { - return def; - } else if (host_sel != NULL && strcmp(config, "host") == 0) { -#ifdef __amd64__ - return pci_host_read_config(host_sel, reg, size); -#else - errx(1, "cannot fetch host PCI configuration"); -#endif + return (def); + } else if (host_conf != NULL && strcmp(config, "host") == 0) { + return (host); } else { - return strtol(config, NULL, 16); + return (strtol(config, NULL, 16)); } } diff --git a/usr.sbin/bhyve/pci_emul.h b/usr.sbin/bhyve/pci_emul.h index 063b4b84e044..29e9717c1593 100644 --- a/usr.sbin/bhyve/pci_emul.h +++ b/usr.sbin/bhyve/pci_emul.h @@ -230,7 +230,7 @@ void pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg); int init_pci(struct vmctx *ctx); void pci_callback(void); -uint32_t pci_config_read_reg(const struct pcisel *host_sel, nvlist_t *nvl, +uint32_t pci_config_read_reg(const struct pci_conf *host_conf, nvlist_t *nvl, uint32_t reg, uint8_t size, uint32_t def); int pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type, uint64_t size);