From nobody Tue Feb 3 04:48:39 2026 X-Original-To: dev-commits-src-all@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 4f4rbW6FXMz6R5rb for ; Tue, 03 Feb 2026 04:48:39 +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 4f4rbW4G8Jz3tl1 for ; Tue, 03 Feb 2026 04:48:39 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1770094119; 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=NTQPYV8fNTivexi1GBJRlJHylNRkSJ6HUbhOXMTWf/g=; b=HlyfMw9cK3U4NeawAy8F1yGWE8GWOFCe4oPrqcYSuf1jPmGCw+Re7ZcdXnuYaWidTflQ4y m//Gc8k5cTAuLimOnCgNHEjk2s9v0fT1RsuE1/QnhIj/vHmeENQ8s8tCOAFJ35MHGDmM0h 3iaIW4yzliuNIwPf5Ldcn7vHYArKArRQp0bnMhy0juRqLurIpzEStE0TmoiKijOYIoPsEm keQfUWaIVTxybmBAdq6jUJrp97TNDThRsSeRD4d7+W5KH5UNT6+e2D3ZPedkLv1jQrwPfY 9uZMrzZKN/529e4EUeVEuUw9a5asjhROUUbXaCTLo/q8ZIZkLErqOAu2WYtYbw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1770094119; a=rsa-sha256; cv=none; b=U7fB5Nv64TC0/2GtqFv6kj+HRRhS56G1i1m/WejpsLnPnC1S5J0SPhtKcZ6UlSu3re+MJM ShyJBg4gsoKDvvSy7ia9yUk6eyZkiboJF/h4VwuE2mju4jUZT4y/v4jL15dDkbOB0pyXs0 scnn8cbeFX+OO+ufGUIblvGEaKQvyzFfv9djA3HMRwKOzGIZXeQfKuPl4L1+Vrz5gI0cCE dzTfPTTwy/ayRsHe/bJe7jERwwJWbWPMUDaxg5zbYDDZ8h5KqlNPXi3GkmRnF02aYFeXh2 W7rpuoFF4l4ZKIE7tD9+pYl3tm7nFKSWx6pC06dIQbUv33qVwCqs9DqqdymU2Q== 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=1770094119; 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=NTQPYV8fNTivexi1GBJRlJHylNRkSJ6HUbhOXMTWf/g=; b=RQpxR4hdjGSYaIvy0MTa78JJ3vgfdsSpC1Kv/b0QHqdHTvFRfCBzlnX3lf7BmtTw9g2woM 3mOnj2JKtkTbTyOwBfel/Q6U0b566pQS+P81V1q0pmoeYLeGvQcBha9awLSsMXEdu1oETN u+0leS3dN1IA+gVy8bRMfOZEt8AFbCvBdXjSuDwOxf9IXGE6pCzNY2u4QjDqcbuyX1M1ln YwGTPBEru9GTlV17oWXObsxLcWfPiu/0QVZRBgL8S+fPqRH5Tpo/qYuTgxQXky7l/bYNC1 D2vpAlof+2DHxvJWl/nNUWGqbxsowsTeMu6e9TDePTCfFM/iEB25WnwLA4yFrw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4f4rbW3TS6zxlP for ; Tue, 03 Feb 2026 04:48:39 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 469e9 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 03 Feb 2026 04:48:39 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kyle Evans Subject: git: e6fa918c4a3e - main - tpm: crb: add support for the Pluton startmethod List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: e6fa918c4a3ebeb4bcae7614dbb281bda35e06e1 Auto-Submitted: auto-generated Date: Tue, 03 Feb 2026 04:48:39 +0000 Message-Id: <69817e27.469e9.1b5f3e6b@gitrepo.freebsd.org> The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=e6fa918c4a3ebeb4bcae7614dbb281bda35e06e1 commit e6fa918c4a3ebeb4bcae7614dbb281bda35e06e1 Author: Kyle Evans AuthorDate: 2026-02-03 04:48:22 +0000 Commit: Kyle Evans CommitDate: 2026-02-03 04:48:32 +0000 tpm: crb: add support for the Pluton startmethod The Pluton startmethod uses a simple doorbell mechanism to wakeup the TPM unit after we've issued various forms of state change, with the registers to use specified in the startmethod-specific segment of the TPM2 table (up to 12 bytes after the StartMethod). At the very least, this is the kind of TPM in use by my AMD Zen 4-based Minisforum machine. Differential Revision: https://reviews.freebsd.org/D53683 --- sys/dev/tpm/tpm_crb.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 207 insertions(+), 5 deletions(-) diff --git a/sys/dev/tpm/tpm_crb.c b/sys/dev/tpm/tpm_crb.c index 28b4f21eccfb..26b53e7a621d 100644 --- a/sys/dev/tpm/tpm_crb.c +++ b/sys/dev/tpm/tpm_crb.c @@ -75,8 +75,52 @@ #define TPM_CRB_INT_ENABLE_BIT BIT(31) +struct tpmcrb_sc; +/* Attach */ +typedef bool (sm_attach_t)(struct tpmcrb_sc *, void *, size_t); +/* State change notification (timeout == 0 for 'no timeout') */ +typedef bool (sm_statechange_t)(struct tpmcrb_sc *, int); + +struct tpmcrb_sm_cfg { + sm_attach_t *sm_attach; + sm_statechange_t *sm_statechange; + sm_statechange_t *sm_cmdready; +}; + +static sm_attach_t pluton_attach; +static sm_statechange_t pluton_doorbell; + +static const struct tpmcrb_sm_cfg_map { + int acpi_sm; + const char *desc; + const struct tpmcrb_sm_cfg sm_cfg; +} tpmcrb_sm_cfg_map[] = { + { + .acpi_sm = TPM2_START_METHOD_CRB, + .desc = "Trusted Platform Module 2.0, CRB mode", + .sm_cfg = { NULL }, /* No notifications required */ + }, + { + .acpi_sm = ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON, + .desc = "Trusted Platform Module 2.0, CRB mode (Pluton)", + .sm_cfg = { + .sm_attach = &pluton_attach, + .sm_statechange = &pluton_doorbell, + .sm_cmdready = &pluton_doorbell, + }, + }, +}; + struct tpmcrb_sc { struct tpm_sc base; + const struct tpmcrb_sm_cfg *sm_cfg; + union { + /* StartMethod data */ + struct { + uint64_t start_reg; + uint64_t reply_reg; + } pluton; + }; bus_size_t cmd_off; bus_size_t rsp_off; size_t cmd_buf_size; @@ -99,23 +143,46 @@ static bool tpmcrb_cancel_cmd(struct tpm_sc *sc); char *tpmcrb_ids[] = {"MSFT0101", NULL}; +static const struct tpmcrb_sm_cfg_map * +tpmcrb_acpi_startmethod_cfg(int method) +{ + const struct tpmcrb_sm_cfg_map *entry; + + for (size_t i = 0; i < nitems(tpmcrb_sm_cfg_map); i++) { + entry = &tpmcrb_sm_cfg_map[i]; + + if (method == entry->acpi_sm) + return (entry); + } + + return (NULL); +} + static int tpmcrb_acpi_probe(device_t dev) { - int err; + int err, smethod; + const struct tpmcrb_sm_cfg_map *sm_cfg_map; ACPI_TABLE_TPM23 *tbl; ACPI_STATUS status; + err = ACPI_ID_PROBE(device_get_parent(dev), dev, tpmcrb_ids, NULL); if (err > 0) return (err); /*Find TPM2 Header*/ status = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **) &tbl); - if(ACPI_FAILURE(status) || - tbl->StartMethod != TPM2_START_METHOD_CRB) + if (ACPI_FAILURE(status)) + return (ENXIO); + + smethod = tbl->StartMethod; + AcpiPutTable((ACPI_TABLE_HEADER *)tbl); + + sm_cfg_map = tpmcrb_acpi_startmethod_cfg(smethod); + if (sm_cfg_map == NULL) return (ENXIO); - device_set_desc(dev, "Trusted Platform Module 2.0, CRB mode"); - return (err); + device_set_desc(dev, sm_cfg_map->desc); + return (0); } static ACPI_STATUS @@ -141,6 +208,40 @@ tpmcrb_fix_buff_offsets(ACPI_RESOURCE *res, void *arg) return (AE_OK); } +static bool +tpmcrb_attach_startmethod(struct tpmcrb_sc *crb_sc) +{ + const struct tpmcrb_sm_cfg_map *sm_cfg_map; + const struct tpmcrb_sm_cfg *sm_cfg; + ACPI_TABLE_TPM23 *tbl; + void *smdata; + ACPI_STATUS status; + bool ret; + + /* + * Grab what we need from the StartMethod. + */ + status = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **)(void **)&tbl); + if (ACPI_FAILURE(status)) + return (false); + + sm_cfg_map = tpmcrb_acpi_startmethod_cfg(tbl->StartMethod); + MPASS(sm_cfg_map != NULL); + sm_cfg = &sm_cfg_map->sm_cfg; + + crb_sc->sm_cfg = sm_cfg; + smdata = tbl + 1; + if (sm_cfg->sm_attach != NULL) { + ret = (*sm_cfg->sm_attach)(crb_sc, smdata, + tbl->Header.Length - sizeof(*tbl)); + } else { + ret = true; + } + + AcpiPutTable((ACPI_TABLE_HEADER *)tbl); + return (ret); +} + static int tpmcrb_attach(device_t dev) { @@ -166,6 +267,11 @@ tpmcrb_attach(device_t dev) return (ENXIO); } + if (!tpmcrb_attach_startmethod(crb_sc)) { + tpmcrb_detach(dev); + return (ENXIO); + } + if(!tpmcrb_request_locality(sc, 0)) { tpmcrb_detach(dev); return (ENXIO); @@ -301,6 +407,30 @@ tpmcrb_cancel_cmd(struct tpm_sc *sc) return (true); } +static bool +tpmcrb_notify_cmdready(struct tpmcrb_sc *crb_sc, int timeout) +{ + sm_statechange_t *cmdready_fn; + + cmdready_fn = crb_sc->sm_cfg->sm_cmdready; + if (cmdready_fn == NULL) + return (true); + + return ((*cmdready_fn)(crb_sc, timeout)); +} + +static bool +tpmcrb_notify_state_changing(struct tpmcrb_sc *crb_sc, int timeout) +{ + sm_statechange_t *statechange_fn; + + statechange_fn = crb_sc->sm_cfg->sm_statechange; + if (statechange_fn == NULL) + return (true); + + return ((*statechange_fn)(crb_sc, timeout)); +} + static bool tpmcrb_state_idle(struct tpmcrb_sc *crb_sc, bool wait) { @@ -312,6 +442,9 @@ tpmcrb_state_idle(struct tpmcrb_sc *crb_sc, bool wait) sc = &crb_sc->base; OR4(sc, TPM_CRB_CTRL_REQ, TPM_CRB_CTRL_REQ_GO_IDLE); + if (!tpmcrb_notify_state_changing(crb_sc, timeout)) + return (false); + if (timeout > 0) { mask = TPM_CRB_CTRL_STS_IDLE_BIT; if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_STS, mask, mask, @@ -333,6 +466,9 @@ tpmcrb_state_ready(struct tpmcrb_sc *crb_sc, bool wait) sc = &crb_sc->base; OR4(sc, TPM_CRB_CTRL_REQ, TPM_CRB_CTRL_REQ_GO_READY); + if (!tpmcrb_notify_state_changing(crb_sc, timeout)) + return (false); + if (timeout > 0) { mask = TPM_CRB_CTRL_REQ_GO_READY; if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_STS, mask, !mask, @@ -406,6 +542,13 @@ tpmcrb_transmit(device_t dev, size_t length) TPM_WRITE_4(dev, TPM_CRB_CTRL_START, TPM_CRB_CTRL_START_CMD); TPM_WRITE_BARRIER(dev, TPM_CRB_CTRL_START, 4); + if (!tpmcrb_notify_cmdready(crb_sc, timeout)) { + device_printf(dev, + "Timeout while waiting for device to ready\n"); + if (!tpmcrb_cancel_cmd(sc)) + return (EIO); + } + mask = ~0; if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_START, mask, ~mask, timeout)) { device_printf(dev, @@ -429,6 +572,10 @@ tpmcrb_transmit(device_t dev, size_t length) bus_read_region_stream_1(sc->mem_res, crb_sc->rsp_off + TPM_HEADER_SIZE, &sc->buf[TPM_HEADER_SIZE], bytes_available - TPM_HEADER_SIZE); + /* + * No need to wait for the transition to idle on the way out, we can + * relinquish locality right away. + */ if (!tpmcrb_state_idle(crb_sc, false)) { device_printf(dev, "Failed to transition to idle state post-send\n"); @@ -442,6 +589,61 @@ tpmcrb_transmit(device_t dev, size_t length) return (0); } +/* StartMethod Implementation Details */ + +/** Pluton **/ +struct tpmcrb_startmethod_pluton { + uint64_t sm_startaddr; + uint64_t sm_replyaddr; +}; + +static bool +pluton_attach(struct tpmcrb_sc *crb_sc, void *smdataregion, size_t datasz) +{ + struct tpmcrb_startmethod_pluton *smdata; + struct tpm_sc *sc; + rman_res_t base_addr, end_addr; + + if (datasz < sizeof(*smdata)) + return (false); + + smdata = smdataregion; + sc = &crb_sc->base; + + base_addr = rman_get_start(sc->mem_res); + end_addr = rman_get_end(sc->mem_res); + /* Sanity check */ + if (smdata->sm_startaddr < base_addr || + smdata->sm_startaddr > end_addr || + smdata->sm_replyaddr < base_addr || + smdata->sm_replyaddr > end_addr) + return (false); + + crb_sc->pluton.start_reg = smdata->sm_startaddr - base_addr; + crb_sc->pluton.reply_reg = smdata->sm_replyaddr - base_addr; + return (true); +} + +static bool +pluton_doorbell(struct tpmcrb_sc *crb_sc, int timeout) +{ + struct tpm_sc *sc; + device_t dev; + + sc = &crb_sc->base; + dev = sc->dev; + TPM_WRITE_4(dev, crb_sc->pluton.start_reg, 1); + TPM_WRITE_BARRIER(dev, crb_sc->pluton.start_reg, 4); + + if (timeout > 0) { + if (!tpm_wait_for_u32(sc, crb_sc->pluton.reply_reg, ~0U, 1, + timeout)) + return (false); + } + + return (true); +} + /* ACPI Driver */ static device_method_t tpmcrb_methods[] = { DEVMETHOD(device_probe, tpmcrb_acpi_probe),