* [RFC 0/4] tpm_crb: Add command and response buffer chunking support
@ 2026-03-24 7:17 Arun Menon
2026-03-24 7:18 ` [RFC 1/4] tpm_crb: Add definition of TPM CRB chunking fields Arun Menon
` (4 more replies)
0 siblings, 5 replies; 11+ messages in thread
From: Arun Menon @ 2026-03-24 7:17 UTC (permalink / raw)
To: linux-kernel
Cc: linux-integrity, Jason Gunthorpe, Jarkko Sakkinen, Peter Huewe,
Arun Menon
The new version of TCG TPM v185 (currently under review [1]) supports
sending data/commands in chunks for the CRB (Command Response Buffer)
interface. This is in line with the initiative to support PQC algorithms.
This series implements the logic to send and receive larger TPM
cmd/rsp between the linux guest and the TPM backend in chunks.
Currently, the TPM CRB driver is limited by the physical size of the
MMIO window. When userspace attempts to send a payload that exceeds this
size, the driver rejects it.
This series introduces chunking support. The driver now checks the CRB
interface capability for CRB_INTF_CAP_CRB_CHUNK. If supported by the
backend, the driver will slice oversized commands into MMIO-sized
chunks, signalling the backend via CRB_START_NEXT_CHUNK, and finalizing
with CRB_START_INVOKE. Responses are also read back in a similar chunked
manner.
If the backend does not support chunking, the driver retains its legacy
behaviour and enforces the standard size limits.
This feature also requires the QEMU to interpret the data in chunks and
forward it to the TPM backend and subsequently dispatch the TPM response
in chunks back to the linux guest. This is implemented in [2]
[1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_rc1_121225.pdf
[2] https://lore.kernel.org/qemu-devel/20260319135316.37412-1-armenon@redhat.com/
Arun Menon (4):
tpm_crb: Add definition of TPM CRB chunking fields
tpm_crb: Add new wrapper function to invoke start method
tpm_crb: Implement command and response chunking logic
tpm: Increase TPM_BUFSIZE to 64kB for chunking support
drivers/char/tpm/tpm.h | 2 +-
drivers/char/tpm/tpm_crb.c | 194 ++++++++++++++++++++++++++-----------
2 files changed, 137 insertions(+), 59 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread* [RFC 1/4] tpm_crb: Add definition of TPM CRB chunking fields 2026-03-24 7:17 [RFC 0/4] tpm_crb: Add command and response buffer chunking support Arun Menon @ 2026-03-24 7:18 ` Arun Menon 2026-03-24 7:18 ` [RFC 2/4] tpm_crb: Add new wrapper function to invoke start method Arun Menon ` (3 subsequent siblings) 4 siblings, 0 replies; 11+ messages in thread From: Arun Menon @ 2026-03-24 7:18 UTC (permalink / raw) To: linux-kernel Cc: linux-integrity, Jason Gunthorpe, Jarkko Sakkinen, Peter Huewe, Arun Menon - Add 2 new registers for invoking the start method and add CRB_INTF_CAP_CRB_CHUNK as the new TCG TPM specifies this CRB Interface Identifier that decides if chunking is allowed. - Refer section 6.4.2.2 of the specification document [1] [1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_rc1_121225.pdf Signed-off-by: Arun Menon <armenon@redhat.com> --- drivers/char/tpm/tpm_crb.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 6c25305c256ef..67c0061d4cab7 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -56,12 +56,18 @@ enum crb_ctrl_sts { enum crb_start { CRB_START_INVOKE = BIT(0), + CRB_START_RESP_RETRY = BIT(1), + CRB_START_NEXT_CHUNK = BIT(2), }; enum crb_cancel { CRB_CANCEL_INVOKE = BIT(0), }; +enum crb_intf { + CRB_INTF_CAP_CRB_CHUNK = BIT(10), +}; + struct crb_regs_head { u32 loc_state; u32 reserved1; -- 2.53.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC 2/4] tpm_crb: Add new wrapper function to invoke start method 2026-03-24 7:17 [RFC 0/4] tpm_crb: Add command and response buffer chunking support Arun Menon 2026-03-24 7:18 ` [RFC 1/4] tpm_crb: Add definition of TPM CRB chunking fields Arun Menon @ 2026-03-24 7:18 ` Arun Menon 2026-03-24 10:42 ` Jarkko Sakkinen 2026-03-24 7:18 ` [RFC 3/4] tpm_crb: Implement command and response chunking logic Arun Menon ` (2 subsequent siblings) 4 siblings, 1 reply; 11+ messages in thread From: Arun Menon @ 2026-03-24 7:18 UTC (permalink / raw) To: linux-kernel Cc: linux-integrity, Jason Gunthorpe, Jarkko Sakkinen, Peter Huewe, Arun Menon - Extract start invocation code into a separate function called crb_trigger_tpm. This will be helpful in repeatedly calling the start method with different bits set to toggle between start, nextChunk or crbRspRetry behaviours. - Based on the bit set, we signal the TPM to consume contents of the command/response buffer. - No functional change intended. Signed-off-by: Arun Menon <armenon@redhat.com> --- drivers/char/tpm/tpm_crb.c | 50 ++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 67c0061d4cab7..10128d078245c 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -445,6 +445,32 @@ static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) } #endif +static int crb_trigger_tpm(struct tpm_chip *chip, u32 start_cmd) +{ + struct crb_priv *priv = dev_get_drvdata(&chip->dev); + int rc; + /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs + * report only ACPI start but in practice seems to require both + * CRB start, hence invoking CRB start method if hid == MSFT0101. + */ + if (priv->sm == ACPI_TPM2_COMMAND_BUFFER || + priv->sm == ACPI_TPM2_MEMORY_MAPPED || + !strcmp(priv->hid, "MSFT0101")) + iowrite32(start_cmd, &priv->regs_t->ctrl_start); + if (priv->sm == ACPI_TPM2_START_METHOD || + priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) + rc = crb_do_acpi_start(chip); + if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) { + iowrite32(start_cmd, &priv->regs_t->ctrl_start); + rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); + } + if (priv->sm == ACPI_TPM2_CRB_WITH_ARM_FFA) { + iowrite32(start_cmd, &priv->regs_t->ctrl_start); + rc = tpm_crb_ffa_start(CRB_FFA_START_TYPE_COMMAND, chip->locality); + } + return rc; +} + static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) { struct crb_priv *priv = dev_get_drvdata(&chip->dev); @@ -470,29 +496,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) /* Make sure that cmd is populated before issuing start. */ wmb(); - /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs - * report only ACPI start but in practice seems to require both - * CRB start, hence invoking CRB start method if hid == MSFT0101. - */ - if (priv->sm == ACPI_TPM2_COMMAND_BUFFER || - priv->sm == ACPI_TPM2_MEMORY_MAPPED || - !strcmp(priv->hid, "MSFT0101")) - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); - - if (priv->sm == ACPI_TPM2_START_METHOD || - priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) - rc = crb_do_acpi_start(chip); - - if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) { - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); - rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); - } - - if (priv->sm == ACPI_TPM2_CRB_WITH_ARM_FFA) { - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); - rc = tpm_crb_ffa_start(CRB_FFA_START_TYPE_COMMAND, chip->locality); - } - + rc = crb_trigger_tpm(chip, CRB_START_INVOKE); if (rc) return rc; -- 2.53.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [RFC 2/4] tpm_crb: Add new wrapper function to invoke start method 2026-03-24 7:18 ` [RFC 2/4] tpm_crb: Add new wrapper function to invoke start method Arun Menon @ 2026-03-24 10:42 ` Jarkko Sakkinen 2026-03-24 12:43 ` Arun Menon 0 siblings, 1 reply; 11+ messages in thread From: Jarkko Sakkinen @ 2026-03-24 10:42 UTC (permalink / raw) To: Arun Menon; +Cc: linux-kernel, linux-integrity, Jason Gunthorpe, Peter Huewe On Tue, Mar 24, 2026 at 12:48:01PM +0530, Arun Menon wrote: > - Extract start invocation code into a separate function called > crb_trigger_tpm. This will be helpful in repeatedly calling the > start method with different bits set to toggle between start, > nextChunk or crbRspRetry behaviours. > - Based on the bit set, we signal the TPM to consume > contents of the command/response buffer. > - No functional change intended. Please write a proper commit message, which is not a task list. > > Signed-off-by: Arun Menon <armenon@redhat.com> > --- > drivers/char/tpm/tpm_crb.c | 50 ++++++++++++++++++++------------------ > 1 file changed, 27 insertions(+), 23 deletions(-) > > diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c > index 67c0061d4cab7..10128d078245c 100644 > --- a/drivers/char/tpm/tpm_crb.c > +++ b/drivers/char/tpm/tpm_crb.c > @@ -445,6 +445,32 @@ static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) > } > #endif > > +static int crb_trigger_tpm(struct tpm_chip *chip, u32 start_cmd) > +{ > + struct crb_priv *priv = dev_get_drvdata(&chip->dev); > + int rc; > + /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs > + * report only ACPI start but in practice seems to require both > + * CRB start, hence invoking CRB start method if hid == MSFT0101. > + */ > + if (priv->sm == ACPI_TPM2_COMMAND_BUFFER || > + priv->sm == ACPI_TPM2_MEMORY_MAPPED || > + !strcmp(priv->hid, "MSFT0101")) > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > + if (priv->sm == ACPI_TPM2_START_METHOD || > + priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) > + rc = crb_do_acpi_start(chip); > + if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) { > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > + rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); > + } > + if (priv->sm == ACPI_TPM2_CRB_WITH_ARM_FFA) { > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > + rc = tpm_crb_ffa_start(CRB_FFA_START_TYPE_COMMAND, chip->locality); > + } > + return rc; > +} > + > static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > { > struct crb_priv *priv = dev_get_drvdata(&chip->dev); > @@ -470,29 +496,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > /* Make sure that cmd is populated before issuing start. */ > wmb(); > > - /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs > - * report only ACPI start but in practice seems to require both > - * CRB start, hence invoking CRB start method if hid == MSFT0101. > - */ > - if (priv->sm == ACPI_TPM2_COMMAND_BUFFER || > - priv->sm == ACPI_TPM2_MEMORY_MAPPED || > - !strcmp(priv->hid, "MSFT0101")) > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > - > - if (priv->sm == ACPI_TPM2_START_METHOD || > - priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) > - rc = crb_do_acpi_start(chip); > - > - if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) { > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > - rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); > - } > - > - if (priv->sm == ACPI_TPM2_CRB_WITH_ARM_FFA) { > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > - rc = tpm_crb_ffa_start(CRB_FFA_START_TYPE_COMMAND, chip->locality); > - } > - > + rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > if (rc) > return rc; > > -- > 2.53.0 > BR, Jarkko ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC 2/4] tpm_crb: Add new wrapper function to invoke start method 2026-03-24 10:42 ` Jarkko Sakkinen @ 2026-03-24 12:43 ` Arun Menon 0 siblings, 0 replies; 11+ messages in thread From: Arun Menon @ 2026-03-24 12:43 UTC (permalink / raw) To: Jarkko Sakkinen Cc: linux-kernel, linux-integrity, Jason Gunthorpe, Peter Huewe On Tue, Mar 24, 2026 at 12:42:19PM +0200, Jarkko Sakkinen wrote: > On Tue, Mar 24, 2026 at 12:48:01PM +0530, Arun Menon wrote: > > - Extract start invocation code into a separate function called > > crb_trigger_tpm. This will be helpful in repeatedly calling the > > start method with different bits set to toggle between start, > > nextChunk or crbRspRetry behaviours. > > - Based on the bit set, we signal the TPM to consume > > contents of the command/response buffer. > > - No functional change intended. > > Please write a proper commit message, which is not a task list. Yes, I shall do that. Thank you for taking a look. > > > > > Signed-off-by: Arun Menon <armenon@redhat.com> > > --- > > drivers/char/tpm/tpm_crb.c | 50 ++++++++++++++++++++------------------ > > 1 file changed, 27 insertions(+), 23 deletions(-) > > > > diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c > > index 67c0061d4cab7..10128d078245c 100644 > > --- a/drivers/char/tpm/tpm_crb.c > > +++ b/drivers/char/tpm/tpm_crb.c > > @@ -445,6 +445,32 @@ static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) > > } > > #endif > > > > +static int crb_trigger_tpm(struct tpm_chip *chip, u32 start_cmd) > > +{ > > + struct crb_priv *priv = dev_get_drvdata(&chip->dev); > > + int rc; > > + /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs > > + * report only ACPI start but in practice seems to require both > > + * CRB start, hence invoking CRB start method if hid == MSFT0101. > > + */ > > + if (priv->sm == ACPI_TPM2_COMMAND_BUFFER || > > + priv->sm == ACPI_TPM2_MEMORY_MAPPED || > > + !strcmp(priv->hid, "MSFT0101")) > > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > > + if (priv->sm == ACPI_TPM2_START_METHOD || > > + priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) > > + rc = crb_do_acpi_start(chip); > > + if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) { > > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > > + rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); > > + } > > + if (priv->sm == ACPI_TPM2_CRB_WITH_ARM_FFA) { > > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > > + rc = tpm_crb_ffa_start(CRB_FFA_START_TYPE_COMMAND, chip->locality); > > + } > > + return rc; > > +} > > + > > static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > > { > > struct crb_priv *priv = dev_get_drvdata(&chip->dev); > > @@ -470,29 +496,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > > /* Make sure that cmd is populated before issuing start. */ > > wmb(); > > > > - /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs > > - * report only ACPI start but in practice seems to require both > > - * CRB start, hence invoking CRB start method if hid == MSFT0101. > > - */ > > - if (priv->sm == ACPI_TPM2_COMMAND_BUFFER || > > - priv->sm == ACPI_TPM2_MEMORY_MAPPED || > > - !strcmp(priv->hid, "MSFT0101")) > > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > > - > > - if (priv->sm == ACPI_TPM2_START_METHOD || > > - priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) > > - rc = crb_do_acpi_start(chip); > > - > > - if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) { > > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > > - rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); > > - } > > - > > - if (priv->sm == ACPI_TPM2_CRB_WITH_ARM_FFA) { > > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > > - rc = tpm_crb_ffa_start(CRB_FFA_START_TYPE_COMMAND, chip->locality); > > - } > > - > > + rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > > if (rc) > > return rc; > > > > -- > > 2.53.0 > > > > BR, Jarkko > Regards, Arun Menon ^ permalink raw reply [flat|nested] 11+ messages in thread
* [RFC 3/4] tpm_crb: Implement command and response chunking logic 2026-03-24 7:17 [RFC 0/4] tpm_crb: Add command and response buffer chunking support Arun Menon 2026-03-24 7:18 ` [RFC 1/4] tpm_crb: Add definition of TPM CRB chunking fields Arun Menon 2026-03-24 7:18 ` [RFC 2/4] tpm_crb: Add new wrapper function to invoke start method Arun Menon @ 2026-03-24 7:18 ` Arun Menon 2026-03-24 10:45 ` Jarkko Sakkinen 2026-03-24 7:18 ` [RFC 4/4] tpm: Increase TPM_BUFSIZE to 64kB for chunking support Arun Menon 2026-03-24 10:41 ` [RFC 0/4] tpm_crb: Add command and response buffer " Jarkko Sakkinen 4 siblings, 1 reply; 11+ messages in thread From: Arun Menon @ 2026-03-24 7:18 UTC (permalink / raw) To: linux-kernel Cc: linux-integrity, Jason Gunthorpe, Jarkko Sakkinen, Peter Huewe, Arun Menon Add support for sending and receiving TPM command data in chunks when the payload exceeds the physical size of the hardware MMIO window. This introduces the following changes: - crb_map_io(): Checks the device interface capability to determine if chunking is supported, setting the chunking_supported flag. It also stores the hardware's maximum response buffer size in priv->rsp_size. - crb_send(): Iteratively writes command chunks to the fixed priv->cmd MMIO window. It signals the TPM backend to process intermediate chunks using CRB_START_NEXT_CHUNK, and signals the final chunk to begin execution using CRB_START_INVOKE. - crb_recv(): Parses the expected response size from the initial TPM header. It then iteratively reads chunks from the fixed priv->rsp MMIO window into the destination buffer, advancing the buffer offset until the complete response is retrieved. Signed-off-by: Arun Menon <armenon@redhat.com> --- drivers/char/tpm/tpm_crb.c | 150 +++++++++++++++++++++++++++---------- 1 file changed, 109 insertions(+), 41 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 10128d078245c..fb63cc3737253 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -104,11 +104,13 @@ struct crb_priv { u8 __iomem *cmd; u8 __iomem *rsp; u32 cmd_size; + u32 rsp_size; u32 smc_func_id; u32 __iomem *pluton_start_addr; u32 __iomem *pluton_reply_addr; u8 ffa_flags; u8 ffa_attributes; + bool chunking_supported; }; struct tpm2_crb_smc { @@ -368,38 +370,6 @@ static u8 crb_status(struct tpm_chip *chip) return sts; } -static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) -{ - struct crb_priv *priv = dev_get_drvdata(&chip->dev); - unsigned int expected; - - /* A sanity check that the upper layer wants to get at least the header - * as that is the minimum size for any TPM response. - */ - if (count < TPM_HEADER_SIZE) - return -EIO; - - /* If this bit is set, according to the spec, the TPM is in - * unrecoverable condition. - */ - if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) - return -EIO; - - /* Read the first 8 bytes in order to get the length of the response. - * We read exactly a quad word in order to make sure that the remaining - * reads will be aligned. - */ - memcpy_fromio(buf, priv->rsp, 8); - - expected = be32_to_cpup((__be32 *)&buf[2]); - if (expected > count || expected < TPM_HEADER_SIZE) - return -EIO; - - memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8); - - return expected; -} - static int crb_do_acpi_start(struct tpm_chip *chip) { union acpi_object *obj; @@ -474,6 +444,8 @@ static int crb_trigger_tpm(struct tpm_chip *chip, u32 start_cmd) static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) { struct crb_priv *priv = dev_get_drvdata(&chip->dev); + size_t offset = 0; + size_t chunk_size; int rc = 0; /* Zero the cancel register so that the next command will not get @@ -481,7 +453,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) */ iowrite32(0, &priv->regs_t->ctrl_cancel); - if (len > priv->cmd_size) { + if (len > priv->cmd_size && !priv->chunking_supported) { dev_err(&chip->dev, "invalid command count value %zd %d\n", len, priv->cmd_size); return -E2BIG; @@ -491,16 +463,101 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) __crb_cmd_ready(&chip->dev, priv, chip->locality); - memcpy_toio(priv->cmd, buf, len); + while (offset < len) { + chunk_size = min_t(size_t, len - offset, priv->cmd_size); + + memcpy_toio(priv->cmd, buf + offset, chunk_size); + offset += chunk_size; + + /* Make sure that cmd is populated before issuing start. */ + wmb(); + if (offset < len) { + rc = crb_trigger_tpm(chip, CRB_START_NEXT_CHUNK); + if (rc) + return rc; + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_start, + CRB_START_NEXT_CHUNK, 0, TPM2_TIMEOUT_C)) { + dev_err(&chip->dev, + "Timeout waiting for backend to consume chunk\n"); + return -ETIME; + } + } else { + rc = crb_trigger_tpm(chip, CRB_START_INVOKE); + if (rc) + return rc; + } + } + return crb_try_pluton_doorbell(priv, false); +} - /* Make sure that cmd is populated before issuing start. */ - wmb(); +static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) +{ + struct crb_priv *priv = dev_get_drvdata(&chip->dev); + unsigned int expected; + size_t offset = 0; + size_t chunk_size; + size_t first_read; + int rc; - rc = crb_trigger_tpm(chip, CRB_START_INVOKE); - if (rc) - return rc; + /* A sanity check that the upper layer wants to get at least the header + * as that is the minimum size for any TPM response. + */ + if (count < TPM_HEADER_SIZE) + return -EIO; - return crb_try_pluton_doorbell(priv, false); + /* If this bit is set, according to the spec, the TPM is in + * unrecoverable condition. + */ + if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) + return -EIO; + + /* Read the first 8 bytes in order to get the length of the response. + * We read exactly a quad word in order to make sure that the remaining + * reads will be aligned. + */ + memcpy_fromio(buf, priv->rsp, 8); + + expected = be32_to_cpup((__be32 *)&buf[2]); + if (expected > count || expected < TPM_HEADER_SIZE) + return -EIO; + + /* + * Set chunk_size by comparing the size of the buffer that the upper layer has + * allocated (count) to the hardware tpm limit (priv->rsp_size). + * This is to prevent buffer overflow while writing to buf. + */ + chunk_size = min_t(size_t, count, priv->rsp_size); + + /* + * Compare the actual size of the response we found in the header to the chunk_size. + */ + first_read = min_t(size_t, expected, chunk_size); + + memcpy_fromio(&buf[8], &priv->rsp[8], first_read - 8); + offset = first_read; + + while (offset < expected) { + if (!priv->chunking_supported) { + dev_err(&chip->dev, "Response larger than MMIO and chunking not supported\n"); + return -EIO; + } + + rc = crb_trigger_tpm(chip, CRB_START_NEXT_CHUNK); + if (rc) + return rc; + + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_start, + CRB_START_NEXT_CHUNK, 0, TPM2_TIMEOUT_C)) { + dev_err(&chip->dev, "Timeout waiting for backend response\n"); + return -ETIME; + } + + chunk_size = min_t(size_t, expected - offset, priv->rsp_size); + memcpy_fromio(buf + offset, priv->rsp, chunk_size); + offset += chunk_size; + } + + return expected; } static void crb_cancel(struct tpm_chip *chip) @@ -727,6 +784,15 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, goto out; } + if (priv->regs_h) { + u32 intf_id = ioread32((u32 __iomem *)&priv->regs_h->intf_id); + + if (intf_id & CRB_INTF_CAP_CRB_CHUNK) { + priv->chunking_supported = true; + dev_info(dev, "CRB Chunking is supported by backend\n"); + } + } + memcpy_fromio(&__rsp_pa, &priv->regs_t->ctrl_rsp_pa, 8); rsp_pa = le64_to_cpu(__rsp_pa); rsp_size = ioread32(&priv->regs_t->ctrl_rsp_size); @@ -764,8 +830,10 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, priv->rsp = priv->cmd; out: - if (!ret) + if (!ret) { priv->cmd_size = cmd_size; + priv->rsp_size = rsp_size; + } __crb_go_idle(dev, priv, 0); -- 2.53.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [RFC 3/4] tpm_crb: Implement command and response chunking logic 2026-03-24 7:18 ` [RFC 3/4] tpm_crb: Implement command and response chunking logic Arun Menon @ 2026-03-24 10:45 ` Jarkko Sakkinen 2026-03-24 12:46 ` Arun Menon 0 siblings, 1 reply; 11+ messages in thread From: Jarkko Sakkinen @ 2026-03-24 10:45 UTC (permalink / raw) To: Arun Menon; +Cc: linux-kernel, linux-integrity, Jason Gunthorpe, Peter Huewe On Tue, Mar 24, 2026 at 12:48:02PM +0530, Arun Menon wrote: > Add support for sending and receiving TPM command data in chunks when > the payload exceeds the physical size of the hardware MMIO window. > > This introduces the following changes: > > - crb_map_io(): Checks the device interface capability to determine if > chunking is supported, setting the chunking_supported flag. It also > stores the hardware's maximum response buffer size in priv->rsp_size. > - crb_send(): Iteratively writes command chunks to the fixed priv->cmd > MMIO window. It signals the TPM backend to process intermediate chunks > using CRB_START_NEXT_CHUNK, and signals the final chunk to begin > execution using CRB_START_INVOKE. > - crb_recv(): Parses the expected response size from the initial TPM > header. It then iteratively reads chunks from the fixed priv->rsp > MMIO window into the destination buffer, advancing the buffer offset > until the complete response is retrieved. > > Signed-off-by: Arun Menon <armenon@redhat.com> This is also just description of wha this adds. I'd lessen the detail and write a description that describes motivation and logic of the change. It's a good test for author knowledge, as if you really get the topic you can explain its gist. In addition, it can be reflected to implementation (vs. the descriptions that are pseudocode in English) Since this RFC and QEMU does not have the feature in release it is good to polish stuff like this. > --- > drivers/char/tpm/tpm_crb.c | 150 +++++++++++++++++++++++++++---------- > 1 file changed, 109 insertions(+), 41 deletions(-) > > diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c > index 10128d078245c..fb63cc3737253 100644 > --- a/drivers/char/tpm/tpm_crb.c > +++ b/drivers/char/tpm/tpm_crb.c > @@ -104,11 +104,13 @@ struct crb_priv { > u8 __iomem *cmd; > u8 __iomem *rsp; > u32 cmd_size; > + u32 rsp_size; > u32 smc_func_id; > u32 __iomem *pluton_start_addr; > u32 __iomem *pluton_reply_addr; > u8 ffa_flags; > u8 ffa_attributes; > + bool chunking_supported; > }; > > struct tpm2_crb_smc { > @@ -368,38 +370,6 @@ static u8 crb_status(struct tpm_chip *chip) > return sts; > } > > -static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) > -{ > - struct crb_priv *priv = dev_get_drvdata(&chip->dev); > - unsigned int expected; > - > - /* A sanity check that the upper layer wants to get at least the header > - * as that is the minimum size for any TPM response. > - */ > - if (count < TPM_HEADER_SIZE) > - return -EIO; > - > - /* If this bit is set, according to the spec, the TPM is in > - * unrecoverable condition. > - */ > - if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) > - return -EIO; > - > - /* Read the first 8 bytes in order to get the length of the response. > - * We read exactly a quad word in order to make sure that the remaining > - * reads will be aligned. > - */ > - memcpy_fromio(buf, priv->rsp, 8); > - > - expected = be32_to_cpup((__be32 *)&buf[2]); > - if (expected > count || expected < TPM_HEADER_SIZE) > - return -EIO; > - > - memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8); > - > - return expected; > -} > - > static int crb_do_acpi_start(struct tpm_chip *chip) > { > union acpi_object *obj; > @@ -474,6 +444,8 @@ static int crb_trigger_tpm(struct tpm_chip *chip, u32 start_cmd) > static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > { > struct crb_priv *priv = dev_get_drvdata(&chip->dev); > + size_t offset = 0; > + size_t chunk_size; > int rc = 0; > > /* Zero the cancel register so that the next command will not get > @@ -481,7 +453,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > */ > iowrite32(0, &priv->regs_t->ctrl_cancel); > > - if (len > priv->cmd_size) { > + if (len > priv->cmd_size && !priv->chunking_supported) { > dev_err(&chip->dev, "invalid command count value %zd %d\n", > len, priv->cmd_size); > return -E2BIG; > @@ -491,16 +463,101 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) > __crb_cmd_ready(&chip->dev, priv, chip->locality); > > - memcpy_toio(priv->cmd, buf, len); > + while (offset < len) { > + chunk_size = min_t(size_t, len - offset, priv->cmd_size); > + > + memcpy_toio(priv->cmd, buf + offset, chunk_size); > + offset += chunk_size; > + > + /* Make sure that cmd is populated before issuing start. */ > + wmb(); > + if (offset < len) { > + rc = crb_trigger_tpm(chip, CRB_START_NEXT_CHUNK); > + if (rc) > + return rc; > + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_start, > + CRB_START_NEXT_CHUNK, 0, TPM2_TIMEOUT_C)) { > + dev_err(&chip->dev, > + "Timeout waiting for backend to consume chunk\n"); > + return -ETIME; > + } > + } else { > + rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > + if (rc) > + return rc; > + } > + } > + return crb_try_pluton_doorbell(priv, false); > +} > > - /* Make sure that cmd is populated before issuing start. */ > - wmb(); > +static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) > +{ > + struct crb_priv *priv = dev_get_drvdata(&chip->dev); > + unsigned int expected; > + size_t offset = 0; > + size_t chunk_size; > + size_t first_read; > + int rc; > > - rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > - if (rc) > - return rc; > + /* A sanity check that the upper layer wants to get at least the header > + * as that is the minimum size for any TPM response. > + */ > + if (count < TPM_HEADER_SIZE) > + return -EIO; > > - return crb_try_pluton_doorbell(priv, false); > + /* If this bit is set, according to the spec, the TPM is in > + * unrecoverable condition. > + */ > + if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) > + return -EIO; > + > + /* Read the first 8 bytes in order to get the length of the response. > + * We read exactly a quad word in order to make sure that the remaining > + * reads will be aligned. > + */ > + memcpy_fromio(buf, priv->rsp, 8); > + > + expected = be32_to_cpup((__be32 *)&buf[2]); > + if (expected > count || expected < TPM_HEADER_SIZE) > + return -EIO; > + > + /* > + * Set chunk_size by comparing the size of the buffer that the upper layer has > + * allocated (count) to the hardware tpm limit (priv->rsp_size). > + * This is to prevent buffer overflow while writing to buf. > + */ > + chunk_size = min_t(size_t, count, priv->rsp_size); > + > + /* > + * Compare the actual size of the response we found in the header to the chunk_size. > + */ > + first_read = min_t(size_t, expected, chunk_size); > + > + memcpy_fromio(&buf[8], &priv->rsp[8], first_read - 8); > + offset = first_read; > + > + while (offset < expected) { > + if (!priv->chunking_supported) { > + dev_err(&chip->dev, "Response larger than MMIO and chunking not supported\n"); > + return -EIO; > + } > + > + rc = crb_trigger_tpm(chip, CRB_START_NEXT_CHUNK); > + if (rc) > + return rc; > + > + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_start, > + CRB_START_NEXT_CHUNK, 0, TPM2_TIMEOUT_C)) { > + dev_err(&chip->dev, "Timeout waiting for backend response\n"); > + return -ETIME; > + } > + > + chunk_size = min_t(size_t, expected - offset, priv->rsp_size); > + memcpy_fromio(buf + offset, priv->rsp, chunk_size); > + offset += chunk_size; > + } > + > + return expected; > } > > static void crb_cancel(struct tpm_chip *chip) > @@ -727,6 +784,15 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, > goto out; > } > > + if (priv->regs_h) { > + u32 intf_id = ioread32((u32 __iomem *)&priv->regs_h->intf_id); > + > + if (intf_id & CRB_INTF_CAP_CRB_CHUNK) { > + priv->chunking_supported = true; > + dev_info(dev, "CRB Chunking is supported by backend\n"); > + } > + } > + > memcpy_fromio(&__rsp_pa, &priv->regs_t->ctrl_rsp_pa, 8); > rsp_pa = le64_to_cpu(__rsp_pa); > rsp_size = ioread32(&priv->regs_t->ctrl_rsp_size); > @@ -764,8 +830,10 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, > priv->rsp = priv->cmd; > > out: > - if (!ret) > + if (!ret) { > priv->cmd_size = cmd_size; > + priv->rsp_size = rsp_size; > + } > > __crb_go_idle(dev, priv, 0); > > -- > 2.53.0 > BR, Jarkko ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC 3/4] tpm_crb: Implement command and response chunking logic 2026-03-24 10:45 ` Jarkko Sakkinen @ 2026-03-24 12:46 ` Arun Menon 0 siblings, 0 replies; 11+ messages in thread From: Arun Menon @ 2026-03-24 12:46 UTC (permalink / raw) To: Jarkko Sakkinen Cc: linux-kernel, linux-integrity, Jason Gunthorpe, Peter Huewe On Tue, Mar 24, 2026 at 12:45:29PM +0200, Jarkko Sakkinen wrote: > On Tue, Mar 24, 2026 at 12:48:02PM +0530, Arun Menon wrote: > > Add support for sending and receiving TPM command data in chunks when > > the payload exceeds the physical size of the hardware MMIO window. > > > > This introduces the following changes: > > > > - crb_map_io(): Checks the device interface capability to determine if > > chunking is supported, setting the chunking_supported flag. It also > > stores the hardware's maximum response buffer size in priv->rsp_size. > > - crb_send(): Iteratively writes command chunks to the fixed priv->cmd > > MMIO window. It signals the TPM backend to process intermediate chunks > > using CRB_START_NEXT_CHUNK, and signals the final chunk to begin > > execution using CRB_START_INVOKE. > > - crb_recv(): Parses the expected response size from the initial TPM > > header. It then iteratively reads chunks from the fixed priv->rsp > > MMIO window into the destination buffer, advancing the buffer offset > > until the complete response is retrieved. > > > > Signed-off-by: Arun Menon <armenon@redhat.com> > > This is also just description of wha this adds. I'd lessen the detail > and write a description that describes motivation and logic of the > change. It's a good test for author knowledge, as if you really get > the topic you can explain its gist. In addition, it can be reflected > to implementation (vs. the descriptions that are pseudocode in English) Sure, I will replace the commit message with motivation+logic instead of explaining the code step by step. > > Since this RFC and QEMU does not have the feature in release it is > good to polish stuff like this. > > > --- > > drivers/char/tpm/tpm_crb.c | 150 +++++++++++++++++++++++++++---------- > > 1 file changed, 109 insertions(+), 41 deletions(-) > > > > diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c > > index 10128d078245c..fb63cc3737253 100644 > > --- a/drivers/char/tpm/tpm_crb.c > > +++ b/drivers/char/tpm/tpm_crb.c > > @@ -104,11 +104,13 @@ struct crb_priv { > > u8 __iomem *cmd; > > u8 __iomem *rsp; > > u32 cmd_size; > > + u32 rsp_size; > > u32 smc_func_id; > > u32 __iomem *pluton_start_addr; > > u32 __iomem *pluton_reply_addr; > > u8 ffa_flags; > > u8 ffa_attributes; > > + bool chunking_supported; > > }; > > > > struct tpm2_crb_smc { > > @@ -368,38 +370,6 @@ static u8 crb_status(struct tpm_chip *chip) > > return sts; > > } > > > > -static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) > > -{ > > - struct crb_priv *priv = dev_get_drvdata(&chip->dev); > > - unsigned int expected; > > - > > - /* A sanity check that the upper layer wants to get at least the header > > - * as that is the minimum size for any TPM response. > > - */ > > - if (count < TPM_HEADER_SIZE) > > - return -EIO; > > - > > - /* If this bit is set, according to the spec, the TPM is in > > - * unrecoverable condition. > > - */ > > - if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) > > - return -EIO; > > - > > - /* Read the first 8 bytes in order to get the length of the response. > > - * We read exactly a quad word in order to make sure that the remaining > > - * reads will be aligned. > > - */ > > - memcpy_fromio(buf, priv->rsp, 8); > > - > > - expected = be32_to_cpup((__be32 *)&buf[2]); > > - if (expected > count || expected < TPM_HEADER_SIZE) > > - return -EIO; > > - > > - memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8); > > - > > - return expected; > > -} > > - > > static int crb_do_acpi_start(struct tpm_chip *chip) > > { > > union acpi_object *obj; > > @@ -474,6 +444,8 @@ static int crb_trigger_tpm(struct tpm_chip *chip, u32 start_cmd) > > static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > > { > > struct crb_priv *priv = dev_get_drvdata(&chip->dev); > > + size_t offset = 0; > > + size_t chunk_size; > > int rc = 0; > > > > /* Zero the cancel register so that the next command will not get > > @@ -481,7 +453,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > > */ > > iowrite32(0, &priv->regs_t->ctrl_cancel); > > > > - if (len > priv->cmd_size) { > > + if (len > priv->cmd_size && !priv->chunking_supported) { > > dev_err(&chip->dev, "invalid command count value %zd %d\n", > > len, priv->cmd_size); > > return -E2BIG; > > @@ -491,16 +463,101 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > > if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) > > __crb_cmd_ready(&chip->dev, priv, chip->locality); > > > > - memcpy_toio(priv->cmd, buf, len); > > + while (offset < len) { > > + chunk_size = min_t(size_t, len - offset, priv->cmd_size); > > + > > + memcpy_toio(priv->cmd, buf + offset, chunk_size); > > + offset += chunk_size; > > + > > + /* Make sure that cmd is populated before issuing start. */ > > + wmb(); > > + if (offset < len) { > > + rc = crb_trigger_tpm(chip, CRB_START_NEXT_CHUNK); > > + if (rc) > > + return rc; > > + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_start, > > + CRB_START_NEXT_CHUNK, 0, TPM2_TIMEOUT_C)) { > > + dev_err(&chip->dev, > > + "Timeout waiting for backend to consume chunk\n"); > > + return -ETIME; > > + } > > + } else { > > + rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > > + if (rc) > > + return rc; > > + } > > + } > > + return crb_try_pluton_doorbell(priv, false); > > +} > > > > - /* Make sure that cmd is populated before issuing start. */ > > - wmb(); > > +static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) > > +{ > > + struct crb_priv *priv = dev_get_drvdata(&chip->dev); > > + unsigned int expected; > > + size_t offset = 0; > > + size_t chunk_size; > > + size_t first_read; > > + int rc; > > > > - rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > > - if (rc) > > - return rc; > > + /* A sanity check that the upper layer wants to get at least the header > > + * as that is the minimum size for any TPM response. > > + */ > > + if (count < TPM_HEADER_SIZE) > > + return -EIO; > > > > - return crb_try_pluton_doorbell(priv, false); > > + /* If this bit is set, according to the spec, the TPM is in > > + * unrecoverable condition. > > + */ > > + if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) > > + return -EIO; > > + > > + /* Read the first 8 bytes in order to get the length of the response. > > + * We read exactly a quad word in order to make sure that the remaining > > + * reads will be aligned. > > + */ > > + memcpy_fromio(buf, priv->rsp, 8); > > + > > + expected = be32_to_cpup((__be32 *)&buf[2]); > > + if (expected > count || expected < TPM_HEADER_SIZE) > > + return -EIO; > > + > > + /* > > + * Set chunk_size by comparing the size of the buffer that the upper layer has > > + * allocated (count) to the hardware tpm limit (priv->rsp_size). > > + * This is to prevent buffer overflow while writing to buf. > > + */ > > + chunk_size = min_t(size_t, count, priv->rsp_size); > > + > > + /* > > + * Compare the actual size of the response we found in the header to the chunk_size. > > + */ > > + first_read = min_t(size_t, expected, chunk_size); > > + > > + memcpy_fromio(&buf[8], &priv->rsp[8], first_read - 8); > > + offset = first_read; > > + > > + while (offset < expected) { > > + if (!priv->chunking_supported) { > > + dev_err(&chip->dev, "Response larger than MMIO and chunking not supported\n"); > > + return -EIO; > > + } > > + > > + rc = crb_trigger_tpm(chip, CRB_START_NEXT_CHUNK); > > + if (rc) > > + return rc; > > + > > + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_start, > > + CRB_START_NEXT_CHUNK, 0, TPM2_TIMEOUT_C)) { > > + dev_err(&chip->dev, "Timeout waiting for backend response\n"); > > + return -ETIME; > > + } > > + > > + chunk_size = min_t(size_t, expected - offset, priv->rsp_size); > > + memcpy_fromio(buf + offset, priv->rsp, chunk_size); > > + offset += chunk_size; > > + } > > + > > + return expected; > > } > > > > static void crb_cancel(struct tpm_chip *chip) > > @@ -727,6 +784,15 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, > > goto out; > > } > > > > + if (priv->regs_h) { > > + u32 intf_id = ioread32((u32 __iomem *)&priv->regs_h->intf_id); > > + > > + if (intf_id & CRB_INTF_CAP_CRB_CHUNK) { > > + priv->chunking_supported = true; > > + dev_info(dev, "CRB Chunking is supported by backend\n"); > > + } > > + } > > + > > memcpy_fromio(&__rsp_pa, &priv->regs_t->ctrl_rsp_pa, 8); > > rsp_pa = le64_to_cpu(__rsp_pa); > > rsp_size = ioread32(&priv->regs_t->ctrl_rsp_size); > > @@ -764,8 +830,10 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, > > priv->rsp = priv->cmd; > > > > out: > > - if (!ret) > > + if (!ret) { > > priv->cmd_size = cmd_size; > > + priv->rsp_size = rsp_size; > > + } > > > > __crb_go_idle(dev, priv, 0); > > > > -- > > 2.53.0 > > > > BR, Jarkko > Regards, Arun Menon ^ permalink raw reply [flat|nested] 11+ messages in thread
* [RFC 4/4] tpm: Increase TPM_BUFSIZE to 64kB for chunking support 2026-03-24 7:17 [RFC 0/4] tpm_crb: Add command and response buffer chunking support Arun Menon ` (2 preceding siblings ...) 2026-03-24 7:18 ` [RFC 3/4] tpm_crb: Implement command and response chunking logic Arun Menon @ 2026-03-24 7:18 ` Arun Menon 2026-03-24 10:41 ` [RFC 0/4] tpm_crb: Add command and response buffer " Jarkko Sakkinen 4 siblings, 0 replies; 11+ messages in thread From: Arun Menon @ 2026-03-24 7:18 UTC (permalink / raw) To: linux-kernel Cc: linux-integrity, Jason Gunthorpe, Jarkko Sakkinen, Peter Huewe, Arun Menon - In tpm_common_write() the size of the command is checked against TPM_BUFSIZE. We therefore need to increase the TPM_BUFSIZE to allow support for larger commands. Signed-off-by: Arun Menon <armenon@redhat.com> --- drivers/char/tpm/tpm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 87d68ddf270a7..a6933eb075296 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -33,7 +33,7 @@ #endif #define TPM_MINOR 224 /* officially assigned */ -#define TPM_BUFSIZE 4096 +#define TPM_BUFSIZE 65536 #define TPM_NUM_DEVICES 65536 #define TPM_RETRY 50 -- 2.53.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [RFC 0/4] tpm_crb: Add command and response buffer chunking support 2026-03-24 7:17 [RFC 0/4] tpm_crb: Add command and response buffer chunking support Arun Menon ` (3 preceding siblings ...) 2026-03-24 7:18 ` [RFC 4/4] tpm: Increase TPM_BUFSIZE to 64kB for chunking support Arun Menon @ 2026-03-24 10:41 ` Jarkko Sakkinen 2026-03-24 12:41 ` Arun Menon 4 siblings, 1 reply; 11+ messages in thread From: Jarkko Sakkinen @ 2026-03-24 10:41 UTC (permalink / raw) To: Arun Menon; +Cc: linux-kernel, linux-integrity, Jason Gunthorpe, Peter Huewe On Tue, Mar 24, 2026 at 12:47:59PM +0530, Arun Menon wrote: > The new version of TCG TPM v185 (currently under review [1]) supports > sending data/commands in chunks for the CRB (Command Response Buffer) > interface. This is in line with the initiative to support PQC algorithms. > > This series implements the logic to send and receive larger TPM > cmd/rsp between the linux guest and the TPM backend in chunks. > Currently, the TPM CRB driver is limited by the physical size of the > MMIO window. When userspace attempts to send a payload that exceeds this > size, the driver rejects it. > > This series introduces chunking support. The driver now checks the CRB > interface capability for CRB_INTF_CAP_CRB_CHUNK. If supported by the > backend, the driver will slice oversized commands into MMIO-sized > chunks, signalling the backend via CRB_START_NEXT_CHUNK, and finalizing > with CRB_START_INVOKE. Responses are also read back in a similar chunked > manner. > > If the backend does not support chunking, the driver retains its legacy > behaviour and enforces the standard size limits. > > This feature also requires the QEMU to interpret the data in chunks and > forward it to the TPM backend and subsequently dispatch the TPM response > in chunks back to the linux guest. This is implemented in [2] > > [1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_rc1_121225.pdf > [2] https://lore.kernel.org/qemu-devel/20260319135316.37412-1-armenon@redhat.com/ > > Arun Menon (4): > tpm_crb: Add definition of TPM CRB chunking fields > tpm_crb: Add new wrapper function to invoke start method > tpm_crb: Implement command and response chunking logic > tpm: Increase TPM_BUFSIZE to 64kB for chunking support > > drivers/char/tpm/tpm.h | 2 +- > drivers/char/tpm/tpm_crb.c | 194 ++++++++++++++++++++++++++----------- > 2 files changed, 137 insertions(+), 59 deletions(-) > > -- > 2.53.0 > When QEMU has the feature available? BR, Jarkko ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC 0/4] tpm_crb: Add command and response buffer chunking support 2026-03-24 10:41 ` [RFC 0/4] tpm_crb: Add command and response buffer " Jarkko Sakkinen @ 2026-03-24 12:41 ` Arun Menon 0 siblings, 0 replies; 11+ messages in thread From: Arun Menon @ 2026-03-24 12:41 UTC (permalink / raw) To: Jarkko Sakkinen Cc: linux-kernel, linux-integrity, Jason Gunthorpe, Peter Huewe Hi Jarkko, On Tue, Mar 24, 2026 at 12:41:26PM +0200, Jarkko Sakkinen wrote: > On Tue, Mar 24, 2026 at 12:47:59PM +0530, Arun Menon wrote: > > The new version of TCG TPM v185 (currently under review [1]) supports > > sending data/commands in chunks for the CRB (Command Response Buffer) > > interface. This is in line with the initiative to support PQC algorithms. > > > > This series implements the logic to send and receive larger TPM > > cmd/rsp between the linux guest and the TPM backend in chunks. > > Currently, the TPM CRB driver is limited by the physical size of the > > MMIO window. When userspace attempts to send a payload that exceeds this > > size, the driver rejects it. > > > > This series introduces chunking support. The driver now checks the CRB > > interface capability for CRB_INTF_CAP_CRB_CHUNK. If supported by the > > backend, the driver will slice oversized commands into MMIO-sized > > chunks, signalling the backend via CRB_START_NEXT_CHUNK, and finalizing > > with CRB_START_INVOKE. Responses are also read back in a similar chunked > > manner. > > > > If the backend does not support chunking, the driver retains its legacy > > behaviour and enforces the standard size limits. > > > > This feature also requires the QEMU to interpret the data in chunks and > > forward it to the TPM backend and subsequently dispatch the TPM response > > in chunks back to the linux guest. This is implemented in [2] > > > > [1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_rc1_121225.pdf > > [2] https://lore.kernel.org/qemu-devel/20260319135316.37412-1-armenon@redhat.com/ > > > > Arun Menon (4): > > tpm_crb: Add definition of TPM CRB chunking fields > > tpm_crb: Add new wrapper function to invoke start method > > tpm_crb: Implement command and response chunking logic > > tpm: Increase TPM_BUFSIZE to 64kB for chunking support > > > > drivers/char/tpm/tpm.h | 2 +- > > drivers/char/tpm/tpm_crb.c | 194 ++++++++++++++++++++++++++----------- > > 2 files changed, 137 insertions(+), 59 deletions(-) > > > > -- > > 2.53.0 > > > > When QEMU has the feature available? The QEMU patches are in review at the moment, here is the link: https://lore.kernel.org/qemu-devel/20260319135316.37412-1-armenon@redhat.com/ Hoping to have them merged soon. > > BR, Jarkko > Regards, Arun Menon ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-03-24 12:47 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-24 7:17 [RFC 0/4] tpm_crb: Add command and response buffer chunking support Arun Menon 2026-03-24 7:18 ` [RFC 1/4] tpm_crb: Add definition of TPM CRB chunking fields Arun Menon 2026-03-24 7:18 ` [RFC 2/4] tpm_crb: Add new wrapper function to invoke start method Arun Menon 2026-03-24 10:42 ` Jarkko Sakkinen 2026-03-24 12:43 ` Arun Menon 2026-03-24 7:18 ` [RFC 3/4] tpm_crb: Implement command and response chunking logic Arun Menon 2026-03-24 10:45 ` Jarkko Sakkinen 2026-03-24 12:46 ` Arun Menon 2026-03-24 7:18 ` [RFC 4/4] tpm: Increase TPM_BUFSIZE to 64kB for chunking support Arun Menon 2026-03-24 10:41 ` [RFC 0/4] tpm_crb: Add command and response buffer " Jarkko Sakkinen 2026-03-24 12:41 ` Arun Menon
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox