* [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC
@ 2026-04-14 8:29 Arun Menon
2026-04-14 8:29 ` [PATCH v4 01/10] hw/tpm: Add TPM CRB chunking fields Arun Menon
` (9 more replies)
0 siblings, 10 replies; 15+ messages in thread
From: Arun Menon @ 2026-04-14 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, marcandre.lureau, Igor Mammedov,
Laurent Vivier, Fabiano Rosas, Arun Menon
The move to Post Quantum Cryptography (PQC) changes how we manage
memory buffers. Unlike classic crypto algorithms like RSA or ECC which
used small keys and signatures, PQC algorithms require larger buffers.
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 data from the
linux guest to the TPM backend in chunks, thereby allowing the
guest to send larger data buffers. We introduce 2 new control registers
called nextChunk and crbRspRetry that will control the START. We also
add the CRB Interface Identifier called CapCRBChunk that is set to 1
indicating that the device supports chunking. The default maximum
chunk/buffer size is 3968 (4096 - 128) bytes.
During a send operation, the guest driver places data in the CRB buffer
and signals nextChunk for each segment until the final chunk is reached.
Upon receiving the START signal, QEMU appends the final chunk to its
internal buffer and dispatches the complete command to the TPM backend.
For responses, the backend's output is buffered. The guest consumes the
first chunk once the START bit is cleared. Subsequent chunks are
retrieved by the guest toggling the nextChunk bit, which advances the
internal buffer offset and populates the CRB data window.
For this to work, the linux guest tpm driver will also have to
a) probe if CRB chunking is supported
b) send data in chunks if the command length exceeds the chunk size.
c) receive data in chunks by sending a nextChunk signal and accumulate.
These patches are posted upstream:
https://lore.kernel.org/lkml/20260324181244.17741-1-armenon@redhat.com/
Dependencies:
This series has a hard dependency on the following patches currently on
the mailing list. They must be applied first for this series to function
correctly:
1. [PATCH 1/2] migration/vmstate: Add VMState support for GByteArray
Link: https://lore.kernel.org/all/20260406115247.4879-2-armenon@redhat.com/
2. [PATCH for-11.1] hw: add compat machines for 11.1
Link: https://lore.kernel.org/all/20260331140347.653404-1-cohuck@redhat.com/
[1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_rc1_121225.pdf
v4
--
- Add migration blocker to prevent data loss and new hw_compat property
called cap_chunk. The chunking feature is now only visible to machine
type 11.1 and higher.
- Rename invoke to Start, to comply with the TCG TPM specification.
- Use g_clear_pointer for safety.
v3
--
Patches 1-6
- Fix the issue with subsequent nextChunk signal from the guest while
the TPM backend is not done processing the previous request.
- Add tpm_crb_unrealize() to clear buffers
- Update hw_compat to 11.1.
- Use newly introduced GByteArray VMStateInfo for migration.
Patches 7-10
- Add Stefan Berger's patches for swtpm profile support, TPM TIS
migration support with extended buffer and related tests.
NOTE: I have removed the "WIP" prefix and the "TODO" regarding dynamic
allocation from Stefan's final patch, as the static 8192-byte limit is
sufficient for the current requirements and passes all local testing.
v2
--
- Add the VM migration support.
- Increase the TIS TPM interface max buffer size to 8192.
Based-on: <20260331140347.653404-1-cohuck@redhat.com>
Based-on: <20260406115247.4879-2-armenon@redhat.com>
Arun Menon (6):
hw/tpm: Add TPM CRB chunking fields
hw/tpm: Refactor CRB_CTRL_START register access
hw/tpm: Add internal buffer state for chunking
hw/tpm: Implement TPM CRB chunking logic
test/qtest: Add test for tpm crb chunking
hw/tpm: Add support for VM migration with TPM CRB chunking
Stefan Berger (4):
qtests: Enable starting swtpm with a given profile
tests: Use ML-DSA-87 operations to caused large TPM transfers with CRB
tpm: Extend TPM TIS buffer size to 8192 bytes
tests: Use ML-DSA-87 operations to caused large TPM transfers with TIS
hw/core/machine.c | 5 +-
hw/tpm/tpm_crb.c | 237 ++++++++++++++++++++++++++++---
hw/tpm/tpm_tis.h | 2 +
hw/tpm/tpm_tis_common.c | 23 +++
hw/tpm/tpm_tis_i2c.c | 24 +++-
hw/tpm/tpm_tis_isa.c | 24 +++-
hw/tpm/tpm_tis_sysbus.c | 24 +++-
include/hw/acpi/tpm.h | 5 +-
tests/qtest/tpm-crb-swtpm-test.c | 11 ++
tests/qtest/tpm-tests.c | 102 ++++++++++++-
tests/qtest/tpm-tests.h | 4 +
tests/qtest/tpm-tis-swtpm-test.c | 11 ++
tests/qtest/tpm-util.c | 156 +++++++++++++++++---
tests/qtest/tpm-util.h | 10 +-
14 files changed, 591 insertions(+), 47 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 01/10] hw/tpm: Add TPM CRB chunking fields
2026-04-14 8:29 [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC Arun Menon
@ 2026-04-14 8:29 ` Arun Menon
2026-04-17 10:05 ` Marc-André Lureau
2026-04-14 8:29 ` [PATCH v4 02/10] hw/tpm: Refactor CRB_CTRL_START register access Arun Menon
` (8 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Arun Menon @ 2026-04-14 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, marcandre.lureau, Igor Mammedov,
Laurent Vivier, Fabiano Rosas, Arun Menon, Stefan Berger
From: Arun Menon <armenon@redhat.com>
- Add new fields to the CRB Interface Identifier and the CRB
Control Start registers.
- CRB_CTRL_START now has 2 new settings, that can be toggled using the
nextChunk and crbRspRetry bits.
- CapCRBChunk bit (10) was Reserved1 previously. The field is reused in
this revision of the specification.
- Refer to section 6.4.2.2 of [1]
[1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_Pub.pdf
Signed-off-by: Arun Menon <armenon@redhat.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/tpm/tpm_crb.c | 3 +++
include/hw/acpi/tpm.h | 5 ++++-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
index 8723536f93..0a1c7ecdc6 100644
--- a/hw/tpm/tpm_crb.c
+++ b/hw/tpm/tpm_crb.c
@@ -59,6 +59,7 @@ DECLARE_INSTANCE_CHECKER(CRBState, CRB,
#define CRB_INTF_CAP_FIFO_NOT_SUPPORTED 0b0
#define CRB_INTF_CAP_CRB_SUPPORTED 0b1
#define CRB_INTF_IF_SELECTOR_CRB 0b1
+#define CRB_INTF_CAP_CRB_CHUNK 0b1
#define CRB_CTRL_CMD_SIZE (TPM_CRB_ADDR_SIZE - A_CRB_DATA_BUFFER)
@@ -262,6 +263,8 @@ static void tpm_crb_reset(void *dev)
CapCRB, CRB_INTF_CAP_CRB_SUPPORTED);
ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
InterfaceSelector, CRB_INTF_IF_SELECTOR_CRB);
+ ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
+ CapCRBChunk, CRB_INTF_CAP_CRB_CHUNK);
ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
RID, 0b0000);
ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID2,
diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
index d2bf6637c5..6eece21397 100644
--- a/include/hw/acpi/tpm.h
+++ b/include/hw/acpi/tpm.h
@@ -149,7 +149,7 @@ REG32(CRB_INTF_ID, 0x30)
FIELD(CRB_INTF_ID, InterfaceVersion, 4, 4)
FIELD(CRB_INTF_ID, CapLocality, 8, 1)
FIELD(CRB_INTF_ID, CapCRBIdleBypass, 9, 1)
- FIELD(CRB_INTF_ID, Reserved1, 10, 1)
+ FIELD(CRB_INTF_ID, CapCRBChunk, 10, 1)
FIELD(CRB_INTF_ID, CapDataXferSizeSupport, 11, 2)
FIELD(CRB_INTF_ID, CapFIFO, 13, 1)
FIELD(CRB_INTF_ID, CapCRB, 14, 1)
@@ -168,6 +168,9 @@ REG32(CRB_CTRL_STS, 0x44)
FIELD(CRB_CTRL_STS, tpmIdle, 1, 1)
REG32(CRB_CTRL_CANCEL, 0x48)
REG32(CRB_CTRL_START, 0x4C)
+ FIELD(CRB_CTRL_START, Start, 0, 1)
+ FIELD(CRB_CTRL_START, crbRspRetry, 1, 1)
+ FIELD(CRB_CTRL_START, nextChunk, 2, 1)
REG32(CRB_INT_ENABLED, 0x50)
REG32(CRB_INT_STS, 0x54)
REG32(CRB_CTRL_CMD_SIZE, 0x58)
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 02/10] hw/tpm: Refactor CRB_CTRL_START register access
2026-04-14 8:29 [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC Arun Menon
2026-04-14 8:29 ` [PATCH v4 01/10] hw/tpm: Add TPM CRB chunking fields Arun Menon
@ 2026-04-14 8:29 ` Arun Menon
2026-04-14 8:29 ` [PATCH v4 03/10] hw/tpm: Add internal buffer state for chunking Arun Menon
` (7 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Arun Menon @ 2026-04-14 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, marcandre.lureau, Igor Mammedov,
Laurent Vivier, Fabiano Rosas, Arun Menon, Stefan Berger
From: Arun Menon <armenon@redhat.com>
Replace manual bitwise operations with ARRAY_FIELD_DP32 macros
No functional changes.
Signed-off-by: Arun Menon <armenon@redhat.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/tpm/tpm_crb.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
index 0a1c7ecdc6..8e6ec44711 100644
--- a/hw/tpm/tpm_crb.c
+++ b/hw/tpm/tpm_crb.c
@@ -145,7 +145,7 @@ static void tpm_crb_mmio_write(void *opaque, hwaddr addr,
tpm_crb_get_active_locty(s) == locty) {
void *mem = memory_region_get_ram_ptr(&s->cmdmem);
- s->regs[R_CRB_CTRL_START] |= CRB_START_INVOKE;
+ ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, Start, 1);
s->cmd = (TPMBackendCmd) {
.in = mem,
.in_len = MIN(tpm_cmd_get_size(mem), s->be_buffer_size),
@@ -194,7 +194,7 @@ static void tpm_crb_request_completed(TPMIf *ti, int ret)
{
CRBState *s = CRB(ti);
- s->regs[R_CRB_CTRL_START] &= ~CRB_START_INVOKE;
+ ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, Start, 0);
if (ret != 0) {
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
tpmSts, 1); /* fatal error */
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 03/10] hw/tpm: Add internal buffer state for chunking
2026-04-14 8:29 [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC Arun Menon
2026-04-14 8:29 ` [PATCH v4 01/10] hw/tpm: Add TPM CRB chunking fields Arun Menon
2026-04-14 8:29 ` [PATCH v4 02/10] hw/tpm: Refactor CRB_CTRL_START register access Arun Menon
@ 2026-04-14 8:29 ` Arun Menon
2026-04-14 8:29 ` [PATCH v4 04/10] hw/tpm: Implement TPM CRB chunking logic Arun Menon
` (6 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Arun Menon @ 2026-04-14 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, marcandre.lureau, Igor Mammedov,
Laurent Vivier, Fabiano Rosas, Arun Menon
From: Arun Menon <armenon@redhat.com>
- Introduce GByteArray buffers to hold the command request and response
data during chunked TPM CRB transactions.
- Add helper function to clean them.
Signed-off-by: Arun Menon <armenon@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/tpm/tpm_crb.c | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
index 8e6ec44711..89f4113c97 100644
--- a/hw/tpm/tpm_crb.c
+++ b/hw/tpm/tpm_crb.c
@@ -38,10 +38,13 @@ struct CRBState {
TPMBackend *tpmbe;
TPMBackendCmd cmd;
uint32_t regs[TPM_CRB_R_MAX];
+ size_t be_buffer_size;
MemoryRegion mmio;
MemoryRegion cmdmem;
- size_t be_buffer_size;
+ GByteArray *command_buffer;
+ GByteArray *response_buffer;
+ uint32_t response_offset;
bool ppi_enabled;
TPMPPI ppi;
@@ -85,6 +88,13 @@ enum crb_cancel {
#define TPM_CRB_NO_LOCALITY 0xff
+static void tpm_crb_clear_internal_buffers(CRBState *s)
+{
+ g_byte_array_set_size(s->response_buffer, 0);
+ g_byte_array_set_size(s->command_buffer, 0);
+ s->response_offset = 0;
+}
+
static uint64_t tpm_crb_mmio_read(void *opaque, hwaddr addr,
unsigned size)
{
@@ -134,9 +144,11 @@ static void tpm_crb_mmio_write(void *opaque, hwaddr addr,
}
break;
case A_CRB_CTRL_CANCEL:
- if (val == CRB_CANCEL_INVOKE &&
- s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) {
- tpm_backend_cancel_cmd(s->tpmbe);
+ if (val == CRB_CANCEL_INVOKE) {
+ if (s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) {
+ tpm_backend_cancel_cmd(s->tpmbe);
+ }
+ tpm_crb_clear_internal_buffers(s);
}
break;
case A_CRB_CTRL_START:
@@ -240,6 +252,7 @@ static void tpm_crb_reset(void *dev)
tpm_ppi_reset(&s->ppi);
}
tpm_backend_reset(s->tpmbe);
+ tpm_crb_clear_internal_buffers(s);
memset(s->regs, 0, sizeof(s->regs));
@@ -306,6 +319,9 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(get_system_memory(),
TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem);
+ s->command_buffer = g_byte_array_new();
+ s->response_buffer = g_byte_array_new();
+
if (s->ppi_enabled) {
tpm_ppi_init(&s->ppi, get_system_memory(),
TPM_PPI_ADDR_BASE, OBJECT(s));
@@ -318,12 +334,21 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
}
}
+static void tpm_crb_unrealize(DeviceState *dev)
+{
+ CRBState *s = CRB(dev);
+
+ g_clear_pointer(&s->command_buffer, g_byte_array_unref);
+ g_clear_pointer(&s->response_buffer, g_byte_array_unref);
+}
+
static void tpm_crb_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
TPMIfClass *tc = TPM_IF_CLASS(klass);
dc->realize = tpm_crb_realize;
+ dc->unrealize = tpm_crb_unrealize;
device_class_set_props(dc, tpm_crb_properties);
dc->vmsd = &vmstate_tpm_crb;
dc->user_creatable = true;
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 04/10] hw/tpm: Implement TPM CRB chunking logic
2026-04-14 8:29 [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC Arun Menon
` (2 preceding siblings ...)
2026-04-14 8:29 ` [PATCH v4 03/10] hw/tpm: Add internal buffer state for chunking Arun Menon
@ 2026-04-14 8:29 ` Arun Menon
2026-04-14 8:29 ` [PATCH v4 05/10] test/qtest: Add test for tpm crb chunking Arun Menon
` (5 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Arun Menon @ 2026-04-14 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, marcandre.lureau, Igor Mammedov,
Laurent Vivier, Fabiano Rosas, Arun Menon, Stefan Berger
From: Arun Menon <armenon@redhat.com>
- Add logic to populate internal TPM command request and response
buffers and to toggle the control registers after each operation.
- The chunk size is limited to CRB_CTRL_CMD_SIZE which is
(TPM_CRB_ADDR_SIZE - A_CRB_DATA_BUFFER). This comes out as 3968 bytes
(4096 - 128 or 0x1000 - 0x80), because 128 bytes are reserved for
control and status registers. In other words, only 3968 bytes are
available for the TPM data.
- With this feature, guests can send commands larger than 3968 bytes.
- Refer section 6.5.3.9 of [1] for implementation details.
[1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_Pub.pdf
Signed-off-by: Arun Menon <armenon@redhat.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/tpm/tpm_crb.c | 148 +++++++++++++++++++++++++++++++++++++++++------
1 file changed, 131 insertions(+), 17 deletions(-)
diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
index 89f4113c97..8e44df1aed 100644
--- a/hw/tpm/tpm_crb.c
+++ b/hw/tpm/tpm_crb.c
@@ -17,6 +17,7 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
+#include "qemu/error-report.h"
#include "qapi/error.h"
#include "system/address-spaces.h"
#include "hw/core/qdev-properties.h"
@@ -65,6 +66,7 @@ DECLARE_INSTANCE_CHECKER(CRBState, CRB,
#define CRB_INTF_CAP_CRB_CHUNK 0b1
#define CRB_CTRL_CMD_SIZE (TPM_CRB_ADDR_SIZE - A_CRB_DATA_BUFFER)
+#define TPM_HEADER_SIZE 10
enum crb_loc_ctrl {
CRB_LOC_CTRL_REQUEST_ACCESS = BIT(0),
@@ -80,6 +82,8 @@ enum crb_ctrl_req {
enum crb_start {
CRB_START_INVOKE = BIT(0),
+ CRB_START_RSP_RETRY = BIT(1),
+ CRB_START_NEXT_CHUNK = BIT(2),
};
enum crb_cancel {
@@ -122,6 +126,69 @@ static uint8_t tpm_crb_get_active_locty(CRBState *s)
return ARRAY_FIELD_EX32(s->regs, CRB_LOC_STATE, activeLocality);
}
+static bool tpm_crb_append_command_request(CRBState *s)
+{
+ /*
+ * The linux guest writes the TPM command to the MMIO region in chunks.
+ * This function appends a chunk from the MMIO region to internal
+ * command_buffer.
+ */
+ void *mem = memory_region_get_ram_ptr(&s->cmdmem);
+ uint32_t to_copy = 0;
+ uint32_t total_request_size = 0;
+
+ /*
+ * The initial call extracts the total TPM command size
+ * from its header. For the subsequent calls, the data already
+ * appended in the command_buffer is used to calculate the total
+ * size, as its header stays the same.
+ */
+ if (s->command_buffer->len == 0) {
+ total_request_size = tpm_cmd_get_size(mem);
+ if (total_request_size < TPM_HEADER_SIZE) {
+ ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS, tpmSts, 1);
+ ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, Start, 0);
+ ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
+ tpm_crb_clear_internal_buffers(s);
+ error_report("Command size %" PRIu32 " less than "
+ "TPM header size %" PRIu32,
+ total_request_size, (uint32_t)TPM_HEADER_SIZE);
+ return false;
+ }
+ } else {
+ total_request_size = tpm_cmd_get_size(s->command_buffer->data);
+ }
+ total_request_size = MIN(total_request_size, s->be_buffer_size);
+
+ if (total_request_size > s->command_buffer->len) {
+ uint32_t remaining = total_request_size - s->command_buffer->len;
+ to_copy = MIN(remaining, CRB_CTRL_CMD_SIZE);
+ g_byte_array_append(s->command_buffer, (guint8 *)mem, to_copy);
+ }
+ return true;
+}
+
+static void tpm_crb_fill_command_response(CRBState *s)
+{
+ /*
+ * Response from the tpm backend will be stored in the internal
+ * response_buffer. This function will serve that accumulated response
+ * to the linux guest in chunks by writing it back to MMIO region.
+ */
+ void *mem = memory_region_get_ram_ptr(&s->cmdmem);
+ uint32_t remaining = s->response_buffer->len - s->response_offset;
+ uint32_t to_copy = MIN(CRB_CTRL_CMD_SIZE, remaining);
+
+ memcpy(mem, s->response_buffer->data + s->response_offset, to_copy);
+
+ if (to_copy < CRB_CTRL_CMD_SIZE) {
+ memset((guint8 *)mem + to_copy, 0, CRB_CTRL_CMD_SIZE - to_copy);
+ }
+
+ s->response_offset += to_copy;
+ memory_region_set_dirty(&s->cmdmem, 0, CRB_CTRL_CMD_SIZE);
+}
+
static void tpm_crb_mmio_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
@@ -152,20 +219,55 @@ static void tpm_crb_mmio_write(void *opaque, hwaddr addr,
}
break;
case A_CRB_CTRL_START:
- if (val == CRB_START_INVOKE &&
- !(s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) &&
- tpm_crb_get_active_locty(s) == locty) {
- void *mem = memory_region_get_ram_ptr(&s->cmdmem);
-
- ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, Start, 1);
- s->cmd = (TPMBackendCmd) {
- .in = mem,
- .in_len = MIN(tpm_cmd_get_size(mem), s->be_buffer_size),
- .out = mem,
- .out_len = s->be_buffer_size,
- };
-
- tpm_backend_deliver_request(s->tpmbe, &s->cmd);
+ if (tpm_crb_get_active_locty(s) != locty) {
+ break;
+ }
+ if (s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) {
+ /*
+ * Backend TPM is busy processing a request.
+ */
+ break;
+ }
+ if (val & CRB_START_INVOKE) {
+ if (!(s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE)) {
+ if (!tpm_crb_append_command_request(s)) {
+ break;
+ }
+ ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, Start, 1);
+ g_byte_array_set_size(s->response_buffer, s->be_buffer_size);
+ s->cmd = (TPMBackendCmd) {
+ .in = s->command_buffer->data,
+ .in_len = s->command_buffer->len,
+ .out = s->response_buffer->data,
+ .out_len = s->response_buffer->len,
+ };
+ tpm_backend_deliver_request(s->tpmbe, &s->cmd);
+ }
+ } else if (val & CRB_START_NEXT_CHUNK) {
+ /*
+ * nextChunk is used both while sending and receiving data.
+ * To distinguish between the two, response_buffer is checked.
+ * If it does not have data, then that means we have not yet
+ * sent the command to the tpm backend, and therefore call
+ * tpm_crb_append_command_request().
+ */
+ if (s->response_buffer->len > 0 &&
+ s->response_offset < s->response_buffer->len) {
+ tpm_crb_fill_command_response(s);
+ } else {
+ if (!tpm_crb_append_command_request(s)) {
+ break;
+ }
+ }
+ ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
+ } else if (val & CRB_START_RSP_RETRY) {
+ if (s->response_buffer->len > 0) {
+ trace_tpm_crb_mmio_write(addr, size, val);
+ s->response_offset = 0;
+ tpm_crb_fill_command_response(s);
+ }
+ ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, crbRspRetry, 0);
+ ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
}
break;
case A_CRB_LOC_CTRL:
@@ -210,8 +312,21 @@ static void tpm_crb_request_completed(TPMIf *ti, int ret)
if (ret != 0) {
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
tpmSts, 1); /* fatal error */
+ tpm_crb_clear_internal_buffers(s);
+ } else {
+ uint32_t actual_resp_size = tpm_cmd_get_size(s->response_buffer->data);
+ uint32_t total_resp_size = MIN(actual_resp_size, s->be_buffer_size);
+ g_byte_array_set_size(s->response_buffer, total_resp_size);
+ s->response_offset = 0;
}
- memory_region_set_dirty(&s->cmdmem, 0, CRB_CTRL_CMD_SIZE);
+ /*
+ * Send the first chunk. Subsequent chunks will be sent
+ * on receiving nextChunk from the guest
+ */
+ tpm_crb_fill_command_response(s);
+ ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
+ ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, crbRspRetry, 0);
+ g_byte_array_set_size(s->command_buffer, 0);
}
static enum TPMVersion tpm_crb_get_version(TPMIf *ti)
@@ -288,8 +403,7 @@ static void tpm_crb_reset(void *dev)
s->regs[R_CRB_CTRL_RSP_SIZE] = CRB_CTRL_CMD_SIZE;
s->regs[R_CRB_CTRL_RSP_ADDR] = TPM_CRB_ADDR_BASE + A_CRB_DATA_BUFFER;
- s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->tpmbe),
- CRB_CTRL_CMD_SIZE);
+ s->be_buffer_size = tpm_backend_get_buffer_size(s->tpmbe);
if (tpm_backend_startup_tpm(s->tpmbe, s->be_buffer_size) < 0) {
exit(1);
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 05/10] test/qtest: Add test for tpm crb chunking
2026-04-14 8:29 [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC Arun Menon
` (3 preceding siblings ...)
2026-04-14 8:29 ` [PATCH v4 04/10] hw/tpm: Implement TPM CRB chunking logic Arun Menon
@ 2026-04-14 8:29 ` Arun Menon
2026-04-14 8:29 ` [PATCH v4 06/10] hw/tpm: Add support for VM migration with TPM CRB chunking Arun Menon
` (4 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Arun Menon @ 2026-04-14 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, marcandre.lureau, Igor Mammedov,
Laurent Vivier, Fabiano Rosas, Arun Menon
From: Arun Menon <armenon@redhat.com>
- New test case added to the swtpm test. Data is written and read from
the buffer in chunks.
- The chunk size is dynamically calculated by reading the
CRB_CTRL_CMD_SIZE address. This can be changed manually to test.
- Add a helper function tpm_wait_till_bit_clear()
- Note that this commit does not yet exercise the chunked read/write
logic, as current transfer sizes remain small. Testing for large
transfers is introduced in a subsequent patch: 'tests: Use ML-DSA-87
operations to cause large TPM transfers with CRB'
Signed-off-by: Arun Menon <armenon@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
tests/qtest/tpm-crb-swtpm-test.c | 10 +++
tests/qtest/tpm-util.c | 110 ++++++++++++++++++++++++++-----
tests/qtest/tpm-util.h | 5 ++
3 files changed, 110 insertions(+), 15 deletions(-)
diff --git a/tests/qtest/tpm-crb-swtpm-test.c b/tests/qtest/tpm-crb-swtpm-test.c
index ffeb1c396b..050c7b0c1f 100644
--- a/tests/qtest/tpm-crb-swtpm-test.c
+++ b/tests/qtest/tpm-crb-swtpm-test.c
@@ -33,6 +33,14 @@ static void tpm_crb_swtpm_test(const void *data)
"tpm-crb", NULL);
}
+static void tpm_crb_chunk_swtpm_test(const void *data)
+{
+ const TestState *ts = data;
+
+ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_chunk_transfer,
+ "tpm-crb", NULL);
+}
+
static void tpm_crb_swtpm_migration_test(const void *data)
{
const TestState *ts = data;
@@ -54,6 +62,8 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
qtest_add_data_func("/tpm/crb-swtpm/test", &ts, tpm_crb_swtpm_test);
+ qtest_add_data_func("/tpm/crb-chunk-swtpm/test", &ts,
+ tpm_crb_chunk_swtpm_test);
qtest_add_data_func("/tpm/crb-swtpm-migration/test", &ts,
tpm_crb_swtpm_migration_test);
ret = g_test_run();
diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c
index 2cb2dd4796..744592763f 100644
--- a/tests/qtest/tpm-util.c
+++ b/tests/qtest/tpm-util.c
@@ -14,16 +14,44 @@
#include "qemu/osdep.h"
#include <glib/gstdio.h>
+#include "qemu/bswap.h"
#include "hw/acpi/tpm.h"
#include "libqtest.h"
#include "tpm-util.h"
#include "qobject/qdict.h"
+#define CRB_ADDR_START (TPM_CRB_ADDR_BASE + A_CRB_CTRL_START)
+#define CRB_ADDR_CTRL_STS (TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS)
+#define CRB_ADDR_CTRL_CMD_SIZE \
+ (TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_SIZE)
+
+#define CRB_START_INVOKE (1 << 0)
+#define CRB_START_RSP_RETRY (1 << 1)
+#define CRB_START_NEXT_CHUNK (1 << 2)
+
+void tpm_wait_till_bit_clear(QTestState *s, uint64_t addr, uint32_t mask)
+{
+ uint32_t sts;
+ uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+
+ while (true) {
+ sts = qtest_readl(s, addr);
+ if ((sts & mask) == 0) {
+ break;
+ }
+ if (g_get_monotonic_time() >= end_time) {
+ g_assert_cmphex(sts & mask, ==, 0);
+ break;
+ }
+ }
+}
+
void tpm_util_crb_transfer(QTestState *s,
const unsigned char *req, size_t req_size,
unsigned char *rsp, size_t rsp_size)
{
+ uint32_t tpm_sts;
uint64_t caddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
uint64_t raddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
@@ -31,24 +59,76 @@ void tpm_util_crb_transfer(QTestState *s,
qtest_memwrite(s, caddr, req, req_size);
- uint32_t sts, start = 1;
- uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
- qtest_writel(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start);
- while (true) {
- start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
- if ((start & 1) == 0) {
- break;
+ qtest_writel(s, CRB_ADDR_START, CRB_START_INVOKE);
+ tpm_wait_till_bit_clear(s, CRB_ADDR_START, CRB_START_INVOKE);
+
+ tpm_sts = qtest_readl(s, CRB_ADDR_CTRL_STS);
+ g_assert_cmpint(tpm_sts & 1, ==, 0);
+
+ qtest_memread(s, raddr, rsp, rsp_size);
+}
+
+void tpm_util_crb_chunk_transfer(QTestState *s,
+ const unsigned char *req, size_t req_size,
+ unsigned char *rsp, size_t rsp_size)
+{
+ uint32_t tpm_sts;
+ size_t chunk_size;
+
+ uint64_t caddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
+ uint64_t raddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
+ uint32_t crb_ctrl_cmd_size = qtest_readl(s, CRB_ADDR_CTRL_CMD_SIZE);
+
+ chunk_size = crb_ctrl_cmd_size;
+
+ qtest_writeb(s, TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1);
+
+ for (size_t i = 0; i < req_size; i += chunk_size) {
+ bool last_chunk = false;
+ size_t current_chunk_size = chunk_size;
+
+ if (i + chunk_size > req_size) {
+ last_chunk = true;
+ current_chunk_size = req_size - i;
}
- if (g_get_monotonic_time() >= end_time) {
- break;
+
+ qtest_memwrite(s, caddr, req + i, current_chunk_size);
+
+ if (last_chunk) {
+ qtest_writel(s, CRB_ADDR_START, CRB_START_INVOKE);
+ tpm_wait_till_bit_clear(s, CRB_ADDR_START, CRB_START_INVOKE);
+ } else {
+ qtest_writel(s, CRB_ADDR_START, CRB_START_NEXT_CHUNK);
+ tpm_wait_till_bit_clear(s, CRB_ADDR_START, CRB_START_NEXT_CHUNK);
}
- };
- start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
- g_assert_cmpint(start & 1, ==, 0);
- sts = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
- g_assert_cmpint(sts & 1, ==, 0);
+ }
+ tpm_sts = qtest_readl(s, CRB_ADDR_CTRL_STS);
+ g_assert_cmpint(tpm_sts & 1, ==, 0);
- qtest_memread(s, raddr, rsp, rsp_size);
+ /*
+ * Read response in chunks
+ */
+
+ unsigned char header[10];
+ uint32_t actual_response_size = 0;
+
+ qtest_memread(s, raddr, header, sizeof(header));
+ actual_response_size = ldl_be_p(&header[2]);
+
+ if (actual_response_size > rsp_size) {
+ actual_response_size = rsp_size;
+ }
+
+ for (size_t i = 0; i < actual_response_size; i += chunk_size) {
+ size_t to_read = i + chunk_size > actual_response_size
+ ? actual_response_size - i
+ : chunk_size;
+ if (i > 0) {
+ qtest_writel(s, CRB_ADDR_START, CRB_START_NEXT_CHUNK);
+ tpm_wait_till_bit_clear(s, CRB_ADDR_START, CRB_START_NEXT_CHUNK);
+ }
+ qtest_memread(s, raddr, rsp + i, to_read);
+ }
}
void tpm_util_startup(QTestState *s, tx_func *tx)
diff --git a/tests/qtest/tpm-util.h b/tests/qtest/tpm-util.h
index 0cb28dd6e5..681544e7d8 100644
--- a/tests/qtest/tpm-util.h
+++ b/tests/qtest/tpm-util.h
@@ -24,10 +24,15 @@ typedef void (tx_func)(QTestState *s,
const unsigned char *req, size_t req_size,
unsigned char *rsp, size_t rsp_size);
+void tpm_wait_till_bit_clear(QTestState *s, uint64_t addr, uint32_t mask);
void tpm_util_crb_transfer(QTestState *s,
const unsigned char *req, size_t req_size,
unsigned char *rsp, size_t rsp_size);
+void tpm_util_crb_chunk_transfer(QTestState *s,
+ const unsigned char *req, size_t req_size,
+ unsigned char *rsp, size_t rsp_size);
+
void tpm_util_startup(QTestState *s, tx_func *tx);
void tpm_util_pcrextend(QTestState *s, tx_func *tx);
void tpm_util_pcrread(QTestState *s, tx_func *tx,
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 06/10] hw/tpm: Add support for VM migration with TPM CRB chunking
2026-04-14 8:29 [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC Arun Menon
` (4 preceding siblings ...)
2026-04-14 8:29 ` [PATCH v4 05/10] test/qtest: Add test for tpm crb chunking Arun Menon
@ 2026-04-14 8:29 ` Arun Menon
2026-04-14 8:29 ` [PATCH v4 07/10] qtests: Enable starting swtpm with a given profile Arun Menon
` (3 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Arun Menon @ 2026-04-14 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, marcandre.lureau, Igor Mammedov,
Laurent Vivier, Fabiano Rosas, Arun Menon
From: Arun Menon <armenon@redhat.com>
- Add subsection in VMState for TPM CRB with the newly introduced
command and response buffer GByteArrays, along with a needed callback,
so that newer QEMU only sends the buffers if it is necessary.
- Add hw_compat global properties for both migrate-buffers and cap-chunk
because the chunking feature is only supported for machine type 11.1
and higher.
- Implement a migration blocker to prevent migration of the VM if the
user manually enables chunking capability but disables buffer
migration. This avoids state data loss.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
hw/core/machine.c | 5 ++++-
hw/tpm/tpm_crb.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 56 insertions(+), 2 deletions(-)
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 1abc8ae737..6d6b0fc9d1 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -38,7 +38,10 @@
#include "hw/acpi/generic_event_device.h"
#include "qemu/audio.h"
-GlobalProperty hw_compat_11_0[] = {};
+GlobalProperty hw_compat_11_0[] = {
+ { "tpm-crb", "x-migrate-buffers", "off"},
+ { "tpm-crb", "x-cap-chunk", "off"},
+};
const size_t hw_compat_11_0_len = G_N_ELEMENTS(hw_compat_11_0);
GlobalProperty hw_compat_10_2[] = {
diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
index 8e44df1aed..0f1eced977 100644
--- a/hw/tpm/tpm_crb.c
+++ b/hw/tpm/tpm_crb.c
@@ -24,6 +24,7 @@
#include "hw/pci/pci_ids.h"
#include "hw/acpi/tpm.h"
#include "migration/vmstate.h"
+#include "migration/blocker.h"
#include "system/tpm_backend.h"
#include "system/tpm_util.h"
#include "system/reset.h"
@@ -49,6 +50,10 @@ struct CRBState {
bool ppi_enabled;
TPMPPI ppi;
+
+ bool migrate_buffers;
+ bool cap_chunk;
+ Error *migration_blocker;
};
typedef struct CRBState CRBState;
@@ -345,18 +350,48 @@ static int tpm_crb_pre_save(void *opaque)
return 0;
}
+static bool tpm_crb_chunk_needed(void *opaque)
+{
+ CRBState *s = opaque;
+
+ if (!s->migrate_buffers) {
+ return false;
+ }
+
+ return ((s->command_buffer && s->command_buffer->len > 0) ||
+ (s->response_buffer && s->response_buffer->len > 0));
+}
+
+static const VMStateDescription vmstate_tpm_crb_chunk = {
+ .name = "tpm-crb/chunk",
+ .version_id = 0,
+ .needed = tpm_crb_chunk_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_GBYTEARRAY(command_buffer, CRBState, 0),
+ VMSTATE_GBYTEARRAY(response_buffer, CRBState, 0),
+ VMSTATE_UINT32(response_offset, CRBState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_tpm_crb = {
.name = "tpm-crb",
.pre_save = tpm_crb_pre_save,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, CRBState, TPM_CRB_R_MAX),
VMSTATE_END_OF_LIST(),
+ },
+ .subsections = (const VMStateDescription * const []) {
+ &vmstate_tpm_crb_chunk,
+ NULL,
}
};
static const Property tpm_crb_properties[] = {
DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe),
DEFINE_PROP_BOOL("ppi", CRBState, ppi_enabled, true),
+ DEFINE_PROP_BOOL("x-migrate-buffers", CRBState, migrate_buffers, true),
+ DEFINE_PROP_BOOL("x-cap-chunk", CRBState, cap_chunk, true),
};
static void tpm_crb_reset(void *dev)
@@ -392,7 +427,7 @@ static void tpm_crb_reset(void *dev)
ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
InterfaceSelector, CRB_INTF_IF_SELECTOR_CRB);
ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
- CapCRBChunk, CRB_INTF_CAP_CRB_CHUNK);
+ CapCRBChunk, s->cap_chunk ? CRB_INTF_CAP_CRB_CHUNK : 0);
ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
RID, 0b0000);
ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID2,
@@ -413,6 +448,7 @@ static void tpm_crb_reset(void *dev)
static void tpm_crb_realize(DeviceState *dev, Error **errp)
{
CRBState *s = CRB(dev);
+ int ret;
if (!tpm_find()) {
error_setg(errp, "at most one TPM device is permitted");
@@ -422,6 +458,16 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
error_setg(errp, "'tpmdev' property is required");
return;
}
+ if (s->cap_chunk && !s->migrate_buffers) {
+ error_setg(&s->migration_blocker, "TPM chunking is enabled but "
+ "buffer migration is disabled. Migration is blocked to prevent "
+ "data loss");
+
+ ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
+ if (ret < 0) {
+ return;
+ }
+ }
memory_region_init_io(&s->mmio, OBJECT(s), &tpm_crb_memory_ops, s,
"tpm-crb-mmio", sizeof(s->regs));
@@ -454,6 +500,11 @@ static void tpm_crb_unrealize(DeviceState *dev)
g_clear_pointer(&s->command_buffer, g_byte_array_unref);
g_clear_pointer(&s->response_buffer, g_byte_array_unref);
+
+ if (s->migration_blocker) {
+ migrate_del_blocker(&s->migration_blocker);
+ error_free(s->migration_blocker);
+ }
}
static void tpm_crb_class_init(ObjectClass *klass, const void *data)
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 07/10] qtests: Enable starting swtpm with a given profile
2026-04-14 8:29 [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC Arun Menon
` (5 preceding siblings ...)
2026-04-14 8:29 ` [PATCH v4 06/10] hw/tpm: Add support for VM migration with TPM CRB chunking Arun Menon
@ 2026-04-14 8:29 ` Arun Menon
2026-04-14 8:29 ` [PATCH v4 08/10] tests: Use ML-DSA-87 operations to caused large TPM transfers with CRB Arun Menon
` (2 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Arun Menon @ 2026-04-14 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, marcandre.lureau, Igor Mammedov,
Laurent Vivier, Fabiano Rosas, Arun Menon, Stefan Berger
From: Stefan Berger <stefanb@linux.ibm.com>
Enable swtpm to start with a given profile by passing it to swtpm on the
command line using
--profile name=<profile name>
Remove any existing TPM 2 state file since applying a new profile to
existing state would be refused by swtpm.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
tests/qtest/tpm-tests.c | 6 +++---
tests/qtest/tpm-util.c | 9 ++++++++-
tests/qtest/tpm-util.h | 3 ++-
3 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/tests/qtest/tpm-tests.c b/tests/qtest/tpm-tests.c
index 197714f8d9..f71d882990 100644
--- a/tests/qtest/tpm-tests.c
+++ b/tests/qtest/tpm-tests.c
@@ -43,7 +43,7 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
return;
}
- succ = tpm_util_swtpm_start(src_tpm_path, &swtpm_pid, &addr, &error);
+ succ = tpm_util_swtpm_start(src_tpm_path, &swtpm_pid, &addr, NULL, &error);
g_assert_true(succ);
args = g_strdup_printf(
@@ -91,11 +91,11 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path,
}
succ = tpm_util_swtpm_start(src_tpm_path, &src_tpm_pid,
- &src_tpm_addr, &error);
+ &src_tpm_addr, NULL, &error);
g_assert_true(succ);
succ = tpm_util_swtpm_start(dst_tpm_path, &dst_tpm_pid,
- &dst_tpm_addr, &error);
+ &dst_tpm_addr, NULL, &error);
g_assert_true(succ);
tpm_util_migration_start_qemu(&src_qemu, &dst_qemu,
diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c
index 744592763f..cbba5b1c1f 100644
--- a/tests/qtest/tpm-util.c
+++ b/tests/qtest/tpm-util.c
@@ -212,7 +212,8 @@ bool tpm_util_swtpm_has_tpm2(void)
}
gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
- SocketAddress **addr, GError **error)
+ SocketAddress **addr, const char *profilename,
+ GError **error)
{
char *swtpm_argv_tpmstate = g_strdup_printf("dir=%s", path);
char *swtpm_argv_ctrl = g_strdup_printf("type=unixio,path=%s/sock",
@@ -222,11 +223,17 @@ gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
g_strdup("--tpmstate"), swtpm_argv_tpmstate,
g_strdup("--ctrl"), swtpm_argv_ctrl,
g_strdup("--tpm2"),
+ profilename ? g_strdup("--profile") : NULL,
+ profilename ? g_strdup_printf("name=%s", profilename) : NULL,
NULL
};
+ g_autofree char *swtpm_state_file;
gboolean succ;
unsigned i;
+ swtpm_state_file = g_strdup_printf("%s/tpm2-00.permall", path);
+ g_unlink(swtpm_state_file);
+
*addr = g_new0(SocketAddress, 1);
(*addr)->type = SOCKET_ADDRESS_TYPE_UNIX;
(*addr)->u.q_unix.path = g_build_filename(path, "sock", NULL);
diff --git a/tests/qtest/tpm-util.h b/tests/qtest/tpm-util.h
index 681544e7d8..ca2d7d173f 100644
--- a/tests/qtest/tpm-util.h
+++ b/tests/qtest/tpm-util.h
@@ -41,7 +41,8 @@ void tpm_util_pcrread(QTestState *s, tx_func *tx,
bool tpm_util_swtpm_has_tpm2(void);
gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
- SocketAddress **addr, GError **error);
+ SocketAddress **addr, const char *profilename,
+ GError **error);
void tpm_util_swtpm_kill(GPid pid);
void tpm_util_migrate(QTestState *who, const char *uri);
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 08/10] tests: Use ML-DSA-87 operations to caused large TPM transfers with CRB
2026-04-14 8:29 [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC Arun Menon
` (6 preceding siblings ...)
2026-04-14 8:29 ` [PATCH v4 07/10] qtests: Enable starting swtpm with a given profile Arun Menon
@ 2026-04-14 8:29 ` Arun Menon
2026-04-14 8:29 ` [PATCH v4 09/10] tpm: Extend TPM TIS buffer size to 8192 bytes Arun Menon
2026-04-14 8:29 ` [PATCH v4 10/10] tests: Use ML-DSA-87 operations to caused large TPM transfers with TIS Arun Menon
9 siblings, 0 replies; 15+ messages in thread
From: Arun Menon @ 2026-04-14 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, marcandre.lureau, Igor Mammedov,
Laurent Vivier, Fabiano Rosas, Arun Menon, Stefan Berger
From: Stefan Berger <stefanb@linux.ibm.com>
To test large data transfers (receiving and sending) that make use of a CRB
chunked transfer, create an ML-DSA-87 key and sign some data with it and
receive the 4627 bytes signature. After this send the signature back to the
TPM to have the TPM verify the signature.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
tests/qtest/tpm-crb-swtpm-test.c | 5 +-
tests/qtest/tpm-tests.c | 96 ++++++++++++++++++++++++++++++++
tests/qtest/tpm-tests.h | 4 ++
tests/qtest/tpm-util.c | 37 ++++++++++++
tests/qtest/tpm-util.h | 2 +
5 files changed, 142 insertions(+), 2 deletions(-)
diff --git a/tests/qtest/tpm-crb-swtpm-test.c b/tests/qtest/tpm-crb-swtpm-test.c
index 050c7b0c1f..541fd58133 100644
--- a/tests/qtest/tpm-crb-swtpm-test.c
+++ b/tests/qtest/tpm-crb-swtpm-test.c
@@ -37,8 +37,9 @@ static void tpm_crb_chunk_swtpm_test(const void *data)
{
const TestState *ts = data;
- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_chunk_transfer,
- "tpm-crb", NULL);
+ tpm_test_swtpm_large_tx_test(ts->src_tpm_path,
+ tpm_util_crb_chunk_transfer,
+ "tpm-crb", NULL);
}
static void tpm_crb_swtpm_migration_test(const void *data)
diff --git a/tests/qtest/tpm-tests.c b/tests/qtest/tpm-tests.c
index f71d882990..21811f3a2e 100644
--- a/tests/qtest/tpm-tests.c
+++ b/tests/qtest/tpm-tests.c
@@ -13,6 +13,7 @@
*/
#include "qemu/osdep.h"
+#include "system/tpm_util.h"
#include <glib/gstdio.h>
#include "libqtest-single.h"
@@ -130,3 +131,98 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path,
g_unlink(src_tpm_addr->u.q_unix.path);
qapi_free_SocketAddress(src_tpm_addr);
}
+
+void tpm_test_swtpm_large_tx_test(const char *src_tpm_path, tx_func *tx,
+ const char *ifmodel,
+ const char *machine_options)
+{
+ unsigned char signature[2 + 2 + 4627]; /* TPMT_SIGNATURE */
+ unsigned char response[8192];
+ unsigned char request[8192];
+ SocketAddress *addr = NULL;
+ GError *error = NULL;
+ char *args = NULL;
+ GPid swtpm_pid;
+ QTestState *s;
+ gboolean succ;
+
+ if (tpm_test_swtpm_skip()) {
+ return;
+ }
+
+ /* Large transfers based on ML-DSA operations required default-v2 profile */
+ if (!tpm_util_swtpm_has_profile("default-v2", "ml-dsa")) {
+ return;
+ }
+
+ succ = tpm_util_swtpm_start(src_tpm_path, &swtpm_pid, &addr, "default-v2",
+ &error);
+ g_assert_true(succ);
+
+ args = g_strdup_printf(
+ "%s "
+ "-chardev socket,id=chr,path=%s "
+ "-tpmdev emulator,id=dev,chardev=chr "
+ "-device %s,tpmdev=dev",
+ machine_options ? : "", addr->u.q_unix.path, ifmodel);
+
+ s = qtest_start(args);
+ g_free(args);
+
+ tpm_util_startup(s, tx);
+
+ static const unsigned char tpm_createprimary_mldsa[] =
+ "\x80\x02\x00\x00\x00\x38\x00\x00\x01\x31\x40\x00\x00\x07\x00\x00"
+ "\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00"
+ "\x00\x00\x0f\x00\xa1\x00\x0b\x00\x04\x04\x72\x00\x00\x00\x03\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00";
+ tx(s, tpm_createprimary_mldsa, sizeof(tpm_createprimary_mldsa),
+ response, sizeof(response));
+ g_assert_cmpint(tpm_cmd_get_errcode(response), ==, 0);
+ g_assert_cmpint(tpm_cmd_get_size(response), ==, 2831);
+
+ static const unsigned char tpm_signsequencestart[] =
+ "\x80\x01\x00\x00\x00\x12\x00\x00\x01\xaa\x80\x00\x00\x00\x00\x00"
+ "\x00\x00";
+ tx(s, tpm_signsequencestart, sizeof(tpm_signsequencestart),
+ response, sizeof(response));
+ g_assert_cmpint(tpm_cmd_get_errcode(response), ==, 0);
+ g_assert_cmpint(tpm_cmd_get_size(response), ==, 14);
+
+ /* Complete sequence and get signature */
+ static const unsigned char tpm_signsequencecomplete[] =
+ "\x80\x02\x00\x00\x00\x2a\x00\x00\x01\xa4\x80\x00\x00\x01\x80\x00"
+ "\x00\x00\x00\x00\x00\x12\x40\x00\x00\x09\x00\x00\x00\x00\x00\x40"
+ "\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00";
+ tx(s, tpm_signsequencecomplete, sizeof(tpm_signsequencecomplete),
+ response, sizeof(response));
+ g_assert_cmpint(tpm_cmd_get_errcode(response), ==, 0);
+ g_assert_cmpint(tpm_cmd_get_size(response), ==, 4655);
+
+ /* TPMT_SIGNATURE found at offset 14 */
+ memcpy(signature, &response[14], sizeof(signature));
+
+ static const unsigned char tpm_verifysequencestart[] =
+ "\x80\x01\x00\x00\x00\x14\x00\x00\x01\xa9\x80\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00";
+ tx(s, tpm_verifysequencestart, sizeof(tpm_verifysequencestart),
+ response, sizeof(response));
+ g_assert_cmpint(tpm_cmd_get_errcode(response), ==, 0);
+ g_assert_cmpint(tpm_cmd_get_size(response), ==, 14);
+
+ /* TPM2_VerifySequenceComplete */
+ memcpy(request,
+ "\x80\x02\x00\x00\x12\x36\x00\x00\x01\xa3\x80\x00\x00\x01\x80\x00"
+ "\x00\x00\x00\x00\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00",
+ 31);
+ memcpy(&request[31], signature, sizeof(signature));
+ tx(s, request, 31 + sizeof(signature), response, sizeof(response));
+ g_assert_cmpint(tpm_cmd_get_errcode(response), ==, 0);
+ g_assert_cmpint(tpm_cmd_get_size(response), ==, 27);
+
+ qtest_end();
+ tpm_util_swtpm_kill(swtpm_pid);
+
+ g_unlink(addr->u.q_unix.path);
+ qapi_free_SocketAddress(addr);
+}
diff --git a/tests/qtest/tpm-tests.h b/tests/qtest/tpm-tests.h
index 07ba60d26e..6993ce40dc 100644
--- a/tests/qtest/tpm-tests.h
+++ b/tests/qtest/tpm-tests.h
@@ -24,4 +24,8 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path,
const char *ifmodel,
const char *machine_options);
+void tpm_test_swtpm_large_tx_test(const char *src_tpm_path, tx_func *tx,
+ const char *ifmodel,
+ const char *machine_options);
+
#endif /* TESTS_TPM_TESTS_H */
diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c
index cbba5b1c1f..ad4325aade 100644
--- a/tests/qtest/tpm-util.c
+++ b/tests/qtest/tpm-util.c
@@ -211,6 +211,43 @@ bool tpm_util_swtpm_has_tpm2(void)
return has_tpm2;
}
+bool tpm_util_swtpm_has_profile(const char *profilename,
+ const char *content)
+{
+ bool has_profile = false;
+ char *out = NULL;
+ static const char *argv[] = {
+ "swtpm", "socket", "--tpm2", "--print-profiles", NULL
+ };
+
+ if (!tpm_util_swtpm_has_tpm2()) {
+ return false;
+ }
+
+ if (!g_spawn_sync(NULL /* working_dir */,
+ (char **)argv,
+ NULL /* envp */,
+ G_SPAWN_SEARCH_PATH,
+ NULL /* child_setup */,
+ NULL /* user_data */,
+ &out,
+ NULL /* err */,
+ NULL /* exit_status */,
+ NULL)) {
+ return false;
+ }
+
+ if (strstr(out, profilename)) {
+ has_profile = true;
+ }
+ if (has_profile && content && strstr(out, content) == NULL) {
+ has_profile = false;
+ }
+
+ g_free(out);
+ return has_profile;
+}
+
gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
SocketAddress **addr, const char *profilename,
GError **error)
diff --git a/tests/qtest/tpm-util.h b/tests/qtest/tpm-util.h
index ca2d7d173f..90790f30db 100644
--- a/tests/qtest/tpm-util.h
+++ b/tests/qtest/tpm-util.h
@@ -39,6 +39,8 @@ void tpm_util_pcrread(QTestState *s, tx_func *tx,
const unsigned char *exp_resp, size_t exp_resp_size);
bool tpm_util_swtpm_has_tpm2(void);
+bool tpm_util_swtpm_has_profile(const char *profilename,
+ const char *content);
gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
SocketAddress **addr, const char *profilename,
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 09/10] tpm: Extend TPM TIS buffer size to 8192 bytes
2026-04-14 8:29 [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC Arun Menon
` (7 preceding siblings ...)
2026-04-14 8:29 ` [PATCH v4 08/10] tests: Use ML-DSA-87 operations to caused large TPM transfers with CRB Arun Menon
@ 2026-04-14 8:29 ` Arun Menon
2026-04-14 8:29 ` [PATCH v4 10/10] tests: Use ML-DSA-87 operations to caused large TPM transfers with TIS Arun Menon
9 siblings, 0 replies; 15+ messages in thread
From: Arun Menon @ 2026-04-14 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, marcandre.lureau, Igor Mammedov,
Laurent Vivier, Fabiano Rosas, Arun Menon, Stefan Berger
From: Stefan Berger <stefanb@linux.ibm.com>
Extend the TIS buffer size to 8192 bytes and store the first 4096 bytes
using VMSTATE_PARTIAL_BUFFER and the rest using VMSTATE_BUFFER_START_MIDDLE
when necessary. It is necessary to store the buffer beyond original 4096
bytes when:
- the user has written more than 4096 bytes to the buffer
- the TPM 2 response is larger than 4096 bytes
Use the .needed function of the VMStateDescription interface to check
whether the bytes in the buffer beyond 4096 bytes needed to be saved.
The .pre_save function is called before the .needed function so that we
can be sure to have received any response packet from the TPM.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
[ Arun Menon - Removed WIP tag and TODO for submission ]
Signed-off-by: Arun Menon <armenon@redhat.com>
---
hw/tpm/tpm_tis.h | 2 ++
hw/tpm/tpm_tis_common.c | 23 +++++++++++++++++++++++
hw/tpm/tpm_tis_i2c.c | 24 +++++++++++++++++++++++-
hw/tpm/tpm_tis_isa.c | 24 +++++++++++++++++++++++-
hw/tpm/tpm_tis_sysbus.c | 24 +++++++++++++++++++++++-
5 files changed, 94 insertions(+), 3 deletions(-)
diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h
index 184632ff66..d35c332287 100644
--- a/hw/tpm/tpm_tis.h
+++ b/hw/tpm/tpm_tis.h
@@ -90,4 +90,6 @@ uint32_t tpm_tis_read_data(TPMState *s, hwaddr addr, unsigned size);
void tpm_tis_write_data(TPMState *s, hwaddr addr, uint64_t val, uint32_t size);
uint16_t tpm_tis_get_checksum(TPMState *s);
+bool tpm_tis_ext_buffer_migration_needed(struct TPMState *s);
+
#endif /* TPM_TPM_TIS_H */
diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c
index f594b15b8a..dffb0a411e 100644
--- a/hw/tpm/tpm_tis_common.c
+++ b/hw/tpm/tpm_tis_common.c
@@ -890,3 +890,26 @@ const VMStateDescription vmstate_locty = {
}
};
+bool tpm_tis_ext_buffer_migration_needed(struct TPMState *s)
+{
+ if (!TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
+ return false;
+ }
+
+ switch (s->loc[s->active_locty].state) {
+ case TPM_TIS_STATE_IDLE:
+ case TPM_TIS_STATE_READY:
+ return false;
+ case TPM_TIS_STATE_RECEPTION:
+ return s->rw_offset >= 4096;
+ case TPM_TIS_STATE_EXECUTION:
+ /*
+ * TPM is executing: we cannot know the size of TPM response.
+ * .pre_save must have been called before (should never get here).
+ */
+ return false;
+ case TPM_TIS_STATE_COMPLETION:
+ return (tpm_cmd_get_size(&s->buffer) >= 4096);
+ }
+ return false;
+}
diff --git a/hw/tpm/tpm_tis_i2c.c b/hw/tpm/tpm_tis_i2c.c
index 9f13e0ec12..a01df7e5a0 100644
--- a/hw/tpm/tpm_tis_i2c.c
+++ b/hw/tpm/tpm_tis_i2c.c
@@ -110,13 +110,31 @@ static int tpm_tis_i2c_post_load(void *opaque, int version_id)
return 0;
}
+static bool tpm_tis_ext_buffer_migration_needed_i2c(void *opaque)
+{
+ TPMStateI2C *i2cst = opaque;
+
+ return tpm_tis_ext_buffer_migration_needed(&i2cst->state);
+}
+
+static const VMStateDescription vmstate_tpm_tis_ext_buffer_i2c = {
+ .name = "tpm-tis/ext_buffer",
+ .version_id = 0,
+ .needed = tpm_tis_ext_buffer_migration_needed_i2c,
+ .pre_save = tpm_tis_i2c_pre_save,
+ .fields = (const VMStateField[]) {
+ VMSTATE_BUFFER_START_MIDDLE(state.buffer, TPMStateI2C, 4096),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_tpm_tis_i2c = {
.name = "tpm-tis-i2c",
.version_id = 0,
.pre_save = tpm_tis_i2c_pre_save,
.post_load = tpm_tis_i2c_post_load,
.fields = (const VMStateField[]) {
- VMSTATE_BUFFER(state.buffer, TPMStateI2C),
+ VMSTATE_PARTIAL_BUFFER(state.buffer, TPMStateI2C, 4096),
VMSTATE_UINT16(state.rw_offset, TPMStateI2C),
VMSTATE_UINT8(state.active_locty, TPMStateI2C),
VMSTATE_UINT8(state.aborting_locty, TPMStateI2C),
@@ -133,6 +151,10 @@ static const VMStateDescription vmstate_tpm_tis_i2c = {
VMSTATE_UINT8(csum_enable, TPMStateI2C),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription *const[]) {
+ &vmstate_tpm_tis_ext_buffer_i2c,
+ NULL,
}
};
diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c
index 61e95434f5..73038f1a10 100644
--- a/hw/tpm/tpm_tis_isa.c
+++ b/hw/tpm/tpm_tis_isa.c
@@ -49,12 +49,30 @@ static int tpm_tis_pre_save_isa(void *opaque)
return tpm_tis_pre_save(&isadev->state);
}
+static bool tpm_tis_ext_buffer_migration_needed_isa(void *opaque)
+{
+ TPMStateISA *isadev = opaque;
+
+ return tpm_tis_ext_buffer_migration_needed(&isadev->state);
+}
+
+static const VMStateDescription vmstate_tpm_tis_ext_buffer_isa = {
+ .name = "tpm-tis/ext_buffer",
+ .version_id = 0,
+ .needed = tpm_tis_ext_buffer_migration_needed_isa,
+ .pre_save = tpm_tis_pre_save_isa,
+ .fields = (const VMStateField[]) {
+ VMSTATE_BUFFER_START_MIDDLE(state.buffer, TPMStateISA, 4096),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_tpm_tis_isa = {
.name = "tpm-tis",
.version_id = 0,
.pre_save = tpm_tis_pre_save_isa,
.fields = (const VMStateField[]) {
- VMSTATE_BUFFER(state.buffer, TPMStateISA),
+ VMSTATE_PARTIAL_BUFFER(state.buffer, TPMStateISA, 4096),
VMSTATE_UINT16(state.rw_offset, TPMStateISA),
VMSTATE_UINT8(state.active_locty, TPMStateISA),
VMSTATE_UINT8(state.aborting_locty, TPMStateISA),
@@ -64,6 +82,10 @@ static const VMStateDescription vmstate_tpm_tis_isa = {
vmstate_locty, TPMLocality),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription *const[]) {
+ &vmstate_tpm_tis_ext_buffer_isa,
+ NULL,
}
};
diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c
index e9372e7316..86fc5a592c 100644
--- a/hw/tpm/tpm_tis_sysbus.c
+++ b/hw/tpm/tpm_tis_sysbus.c
@@ -48,12 +48,30 @@ static int tpm_tis_pre_save_sysbus(void *opaque)
return tpm_tis_pre_save(&sbdev->state);
}
+static bool tpm_tis_ext_buffer_migration_needed_sysbus(void *opaque)
+{
+ TPMStateSysBus *sbdev = opaque;
+
+ return tpm_tis_ext_buffer_migration_needed(&sbdev->state);
+}
+
+static const VMStateDescription vmstate_tpm_tis_ext_buffer_sysbus = {
+ .name = "tpm-tis/ext_buffer",
+ .version_id = 0,
+ .needed = tpm_tis_ext_buffer_migration_needed_sysbus,
+ .pre_save = tpm_tis_pre_save_sysbus,
+ .fields = (const VMStateField[]) {
+ VMSTATE_BUFFER_START_MIDDLE(state.buffer, TPMStateSysBus, 4096),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_tpm_tis_sysbus = {
.name = "tpm-tis",
.version_id = 0,
.pre_save = tpm_tis_pre_save_sysbus,
.fields = (const VMStateField[]) {
- VMSTATE_BUFFER(state.buffer, TPMStateSysBus),
+ VMSTATE_PARTIAL_BUFFER(state.buffer, TPMStateSysBus, 4096),
VMSTATE_UINT16(state.rw_offset, TPMStateSysBus),
VMSTATE_UINT8(state.active_locty, TPMStateSysBus),
VMSTATE_UINT8(state.aborting_locty, TPMStateSysBus),
@@ -63,6 +81,10 @@ static const VMStateDescription vmstate_tpm_tis_sysbus = {
0, vmstate_locty, TPMLocality),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription *const[]) {
+ &vmstate_tpm_tis_ext_buffer_sysbus,
+ NULL,
}
};
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4 10/10] tests: Use ML-DSA-87 operations to caused large TPM transfers with TIS
2026-04-14 8:29 [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC Arun Menon
` (8 preceding siblings ...)
2026-04-14 8:29 ` [PATCH v4 09/10] tpm: Extend TPM TIS buffer size to 8192 bytes Arun Menon
@ 2026-04-14 8:29 ` Arun Menon
9 siblings, 0 replies; 15+ messages in thread
From: Arun Menon @ 2026-04-14 8:29 UTC (permalink / raw)
To: qemu-devel
Cc: Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, marcandre.lureau, Igor Mammedov,
Laurent Vivier, Fabiano Rosas, Arun Menon, Stefan Berger
From: Stefan Berger <stefanb@linux.ibm.com>
Test a large data transfer with the TIS. To do this, first create an
ML-DSA-87 key and sign some data with it. Then receive the 4627 bytes
signature and then send the signature back to have the TPM verify it.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
tests/qtest/tpm-tis-swtpm-test.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/tests/qtest/tpm-tis-swtpm-test.c b/tests/qtest/tpm-tis-swtpm-test.c
index 105e42e21d..56d2a340c9 100644
--- a/tests/qtest/tpm-tis-swtpm-test.c
+++ b/tests/qtest/tpm-tis-swtpm-test.c
@@ -36,6 +36,15 @@ static void tpm_tis_swtpm_test(const void *data)
"tpm-tis", NULL);
}
+static void tpm_tis_large_tx_swtpm_test(const void *data)
+{
+ const TestState *ts = data;
+
+ tpm_test_swtpm_large_tx_test(ts->src_tpm_path,
+ tpm_tis_transfer,
+ "tpm-tis", NULL);
+}
+
static void tpm_tis_swtpm_migration_test(const void *data)
{
const TestState *ts = data;
@@ -57,6 +66,8 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test);
+ qtest_add_data_func("/tpm/tis-larget-tx-swtpm/test", &ts,
+ tpm_tis_large_tx_swtpm_test);
qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts,
tpm_tis_swtpm_migration_test);
ret = g_test_run();
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v4 01/10] hw/tpm: Add TPM CRB chunking fields
2026-04-14 8:29 ` [PATCH v4 01/10] hw/tpm: Add TPM CRB chunking fields Arun Menon
@ 2026-04-17 10:05 ` Marc-André Lureau
2026-04-17 14:34 ` Stefan Berger
0 siblings, 1 reply; 15+ messages in thread
From: Marc-André Lureau @ 2026-04-17 10:05 UTC (permalink / raw)
To: Arun Menon
Cc: qemu-devel, Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, Igor Mammedov, Laurent Vivier,
Fabiano Rosas, Stefan Berger
Hi
On Tue, Apr 14, 2026 at 12:30 PM Arun Menon <armenon@redhat.com> wrote:
>
> From: Arun Menon <armenon@redhat.com>
>
> - Add new fields to the CRB Interface Identifier and the CRB
> Control Start registers.
> - CRB_CTRL_START now has 2 new settings, that can be toggled using the
> nextChunk and crbRspRetry bits.
> - CapCRBChunk bit (10) was Reserved1 previously. The field is reused in
> this revision of the specification.
> - Refer to section 6.4.2.2 of [1]
>
> [1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_Pub.pdf
>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> hw/tpm/tpm_crb.c | 3 +++
> include/hw/acpi/tpm.h | 5 ++++-
> 2 files changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
> index 8723536f93..0a1c7ecdc6 100644
> --- a/hw/tpm/tpm_crb.c
> +++ b/hw/tpm/tpm_crb.c
> @@ -59,6 +59,7 @@ DECLARE_INSTANCE_CHECKER(CRBState, CRB,
> #define CRB_INTF_CAP_FIFO_NOT_SUPPORTED 0b0
> #define CRB_INTF_CAP_CRB_SUPPORTED 0b1
> #define CRB_INTF_IF_SELECTOR_CRB 0b1
> +#define CRB_INTF_CAP_CRB_CHUNK 0b1
>
> #define CRB_CTRL_CMD_SIZE (TPM_CRB_ADDR_SIZE - A_CRB_DATA_BUFFER)
>
> @@ -262,6 +263,8 @@ static void tpm_crb_reset(void *dev)
> CapCRB, CRB_INTF_CAP_CRB_SUPPORTED);
> ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
> InterfaceSelector, CRB_INTF_IF_SELECTOR_CRB);
> + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
> + CapCRBChunk, CRB_INTF_CAP_CRB_CHUNK);
We should not expose that new capability to guests without an explicit
"cap-chunk=on".
It should reject if any chunk request is made when cap-chunk=off in
later patches.
I don't think x-migrate-buffers is necessary. If cap-chunk=on, it can
be migrated with 11.1, with older machine version just add a migration
blocker.
> ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
> RID, 0b0000);
> ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID2,
> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> index d2bf6637c5..6eece21397 100644
> --- a/include/hw/acpi/tpm.h
> +++ b/include/hw/acpi/tpm.h
> @@ -149,7 +149,7 @@ REG32(CRB_INTF_ID, 0x30)
> FIELD(CRB_INTF_ID, InterfaceVersion, 4, 4)
> FIELD(CRB_INTF_ID, CapLocality, 8, 1)
> FIELD(CRB_INTF_ID, CapCRBIdleBypass, 9, 1)
> - FIELD(CRB_INTF_ID, Reserved1, 10, 1)
> + FIELD(CRB_INTF_ID, CapCRBChunk, 10, 1)
> FIELD(CRB_INTF_ID, CapDataXferSizeSupport, 11, 2)
> FIELD(CRB_INTF_ID, CapFIFO, 13, 1)
> FIELD(CRB_INTF_ID, CapCRB, 14, 1)
> @@ -168,6 +168,9 @@ REG32(CRB_CTRL_STS, 0x44)
> FIELD(CRB_CTRL_STS, tpmIdle, 1, 1)
> REG32(CRB_CTRL_CANCEL, 0x48)
> REG32(CRB_CTRL_START, 0x4C)
> + FIELD(CRB_CTRL_START, Start, 0, 1)
> + FIELD(CRB_CTRL_START, crbRspRetry, 1, 1)
> + FIELD(CRB_CTRL_START, nextChunk, 2, 1)
> REG32(CRB_INT_ENABLED, 0x50)
> REG32(CRB_INT_STS, 0x54)
> REG32(CRB_CTRL_CMD_SIZE, 0x58)
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 01/10] hw/tpm: Add TPM CRB chunking fields
2026-04-17 10:05 ` Marc-André Lureau
@ 2026-04-17 14:34 ` Stefan Berger
2026-04-17 14:51 ` Marc-André Lureau
0 siblings, 1 reply; 15+ messages in thread
From: Stefan Berger @ 2026-04-17 14:34 UTC (permalink / raw)
To: Marc-André Lureau, Arun Menon
Cc: qemu-devel, Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, Igor Mammedov, Laurent Vivier,
Fabiano Rosas
On 4/17/26 6:05 AM, Marc-André Lureau wrote:
> Hi
>
> On Tue, Apr 14, 2026 at 12:30 PM Arun Menon <armenon@redhat.com> wrote:
>>
>> From: Arun Menon <armenon@redhat.com>
>>
>> - Add new fields to the CRB Interface Identifier and the CRB
>> Control Start registers.
>> - CRB_CTRL_START now has 2 new settings, that can be toggled using the
>> nextChunk and crbRspRetry bits.
>> - CapCRBChunk bit (10) was Reserved1 previously. The field is reused in
>> this revision of the specification.
>> - Refer to section 6.4.2.2 of [1]
>>
>> [1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_Pub.pdf
>>
>> Signed-off-by: Arun Menon <armenon@redhat.com>
>> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
>> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>> hw/tpm/tpm_crb.c | 3 +++
>> include/hw/acpi/tpm.h | 5 ++++-
>> 2 files changed, 7 insertions(+), 1 deletion(-)
>>
>> diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
>> index 8723536f93..0a1c7ecdc6 100644
>> --- a/hw/tpm/tpm_crb.c
>> +++ b/hw/tpm/tpm_crb.c
>> @@ -59,6 +59,7 @@ DECLARE_INSTANCE_CHECKER(CRBState, CRB,
>> #define CRB_INTF_CAP_FIFO_NOT_SUPPORTED 0b0
>> #define CRB_INTF_CAP_CRB_SUPPORTED 0b1
>> #define CRB_INTF_IF_SELECTOR_CRB 0b1
>> +#define CRB_INTF_CAP_CRB_CHUNK 0b1
>>
>> #define CRB_CTRL_CMD_SIZE (TPM_CRB_ADDR_SIZE - A_CRB_DATA_BUFFER)
>>
>> @@ -262,6 +263,8 @@ static void tpm_crb_reset(void *dev)
>> CapCRB, CRB_INTF_CAP_CRB_SUPPORTED);
>> ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
>> InterfaceSelector, CRB_INTF_IF_SELECTOR_CRB);
>> + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
>> + CapCRBChunk, CRB_INTF_CAP_CRB_CHUNK);
>
> We should not expose that new capability to guests without an explicit
> "cap-chunk=on".
You mean put this on the QEMU command line? This new capability is
really only needed if the user chooses PQC algorithm support (but then I
was also going to allow for 7kb writes to NVRAM spaces rather than 1kb
writes so far) and if the user chooses a swtpm profile with such support
but then fails to set this flag, some transmissions won't work. What
would be the problem if we exposed this new feature all the time and if
we can avoid state backwards-incompatibilities, which IMO is the most
important aspect, if we detect that chunking was not used by the driver
and only write additional state if found absolutely necessary? I would
prefer to untangle the user's choice of enabled algorithm from the
choice of such a flag. But then there's the aspect of OS drivers that
could use chunking even when not absolutely necessary (?).
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 01/10] hw/tpm: Add TPM CRB chunking fields
2026-04-17 14:34 ` Stefan Berger
@ 2026-04-17 14:51 ` Marc-André Lureau
2026-04-20 11:50 ` Arun Menon
0 siblings, 1 reply; 15+ messages in thread
From: Marc-André Lureau @ 2026-04-17 14:51 UTC (permalink / raw)
To: Stefan Berger
Cc: Arun Menon, qemu-devel, Yanan Wang, Ani Sinha, Michael S. Tsirkin,
Philippe Mathieu-Daudé, Stefan Berger, Paolo Bonzini,
Marcel Apfelbaum, Zhao Liu, Igor Mammedov, Laurent Vivier,
Fabiano Rosas
Hi
On Fri, Apr 17, 2026 at 6:36 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
>
>
>
> On 4/17/26 6:05 AM, Marc-André Lureau wrote:
> > Hi
> >
> > On Tue, Apr 14, 2026 at 12:30 PM Arun Menon <armenon@redhat.com> wrote:
> >>
> >> From: Arun Menon <armenon@redhat.com>
> >>
> >> - Add new fields to the CRB Interface Identifier and the CRB
> >> Control Start registers.
> >> - CRB_CTRL_START now has 2 new settings, that can be toggled using the
> >> nextChunk and crbRspRetry bits.
> >> - CapCRBChunk bit (10) was Reserved1 previously. The field is reused in
> >> this revision of the specification.
> >> - Refer to section 6.4.2.2 of [1]
> >>
> >> [1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_Pub.pdf
> >>
> >> Signed-off-by: Arun Menon <armenon@redhat.com>
> >> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> >> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> >> ---
> >> hw/tpm/tpm_crb.c | 3 +++
> >> include/hw/acpi/tpm.h | 5 ++++-
> >> 2 files changed, 7 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
> >> index 8723536f93..0a1c7ecdc6 100644
> >> --- a/hw/tpm/tpm_crb.c
> >> +++ b/hw/tpm/tpm_crb.c
> >> @@ -59,6 +59,7 @@ DECLARE_INSTANCE_CHECKER(CRBState, CRB,
> >> #define CRB_INTF_CAP_FIFO_NOT_SUPPORTED 0b0
> >> #define CRB_INTF_CAP_CRB_SUPPORTED 0b1
> >> #define CRB_INTF_IF_SELECTOR_CRB 0b1
> >> +#define CRB_INTF_CAP_CRB_CHUNK 0b1
> >>
> >> #define CRB_CTRL_CMD_SIZE (TPM_CRB_ADDR_SIZE - A_CRB_DATA_BUFFER)
> >>
> >> @@ -262,6 +263,8 @@ static void tpm_crb_reset(void *dev)
> >> CapCRB, CRB_INTF_CAP_CRB_SUPPORTED);
> >> ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
> >> InterfaceSelector, CRB_INTF_IF_SELECTOR_CRB);
> >> + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
> >> + CapCRBChunk, CRB_INTF_CAP_CRB_CHUNK);
> >
> > We should not expose that new capability to guests without an explicit
> > "cap-chunk=on".
>
> You mean put this on the QEMU command line? This new capability is
> really only needed if the user chooses PQC algorithm support (but then I
> was also going to allow for 7kb writes to NVRAM spaces rather than 1kb
> writes so far) and if the user chooses a swtpm profile with such support
> but then fails to set this flag, some transmissions won't work. What
> would be the problem if we exposed this new feature all the time and if
> we can avoid state backwards-incompatibilities, which IMO is the most
> important aspect, if we detect that chunking was not used by the driver
In general, we shouldn't suddenly expose device capabilities to
guests. Starting with 11.1 machine, the cap-chunk feature can be
enabled by default though.
> and only write additional state if found absolutely necessary? I would
> prefer to untangle the user's choice of enabled algorithm from the
> choice of such a flag. But then there's the aspect of OS drivers that
> could use chunking even when not absolutely necessary (?).
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v4 01/10] hw/tpm: Add TPM CRB chunking fields
2026-04-17 14:51 ` Marc-André Lureau
@ 2026-04-20 11:50 ` Arun Menon
0 siblings, 0 replies; 15+ messages in thread
From: Arun Menon @ 2026-04-20 11:50 UTC (permalink / raw)
To: Marc-André Lureau
Cc: Stefan Berger, qemu-devel, Yanan Wang, Ani Sinha,
Michael S. Tsirkin, Philippe Mathieu-Daudé, Stefan Berger,
Paolo Bonzini, Marcel Apfelbaum, Zhao Liu, Igor Mammedov,
Laurent Vivier, Fabiano Rosas
Hi Marc-André,
Thanks for the review.
On Fri, Apr 17, 2026 at 06:51:14PM +0400, Marc-André Lureau wrote:
> Hi
>
> On Fri, Apr 17, 2026 at 6:36 PM Stefan Berger <stefanb@linux.ibm.com> wrote:
> >
> >
> >
> > On 4/17/26 6:05 AM, Marc-André Lureau wrote:
> > > Hi
> > >
> > > On Tue, Apr 14, 2026 at 12:30 PM Arun Menon <armenon@redhat.com> wrote:
> > >>
> > >> From: Arun Menon <armenon@redhat.com>
> > >>
> > >> - Add new fields to the CRB Interface Identifier and the CRB
> > >> Control Start registers.
> > >> - CRB_CTRL_START now has 2 new settings, that can be toggled using the
> > >> nextChunk and crbRspRetry bits.
> > >> - CapCRBChunk bit (10) was Reserved1 previously. The field is reused in
> > >> this revision of the specification.
> > >> - Refer to section 6.4.2.2 of [1]
> > >>
> > >> [1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_Pub.pdf
> > >>
> > >> Signed-off-by: Arun Menon <armenon@redhat.com>
> > >> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> > >> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > >> ---
> > >> hw/tpm/tpm_crb.c | 3 +++
> > >> include/hw/acpi/tpm.h | 5 ++++-
> > >> 2 files changed, 7 insertions(+), 1 deletion(-)
> > >>
> > >> diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
> > >> index 8723536f93..0a1c7ecdc6 100644
> > >> --- a/hw/tpm/tpm_crb.c
> > >> +++ b/hw/tpm/tpm_crb.c
> > >> @@ -59,6 +59,7 @@ DECLARE_INSTANCE_CHECKER(CRBState, CRB,
> > >> #define CRB_INTF_CAP_FIFO_NOT_SUPPORTED 0b0
> > >> #define CRB_INTF_CAP_CRB_SUPPORTED 0b1
> > >> #define CRB_INTF_IF_SELECTOR_CRB 0b1
> > >> +#define CRB_INTF_CAP_CRB_CHUNK 0b1
> > >>
> > >> #define CRB_CTRL_CMD_SIZE (TPM_CRB_ADDR_SIZE - A_CRB_DATA_BUFFER)
> > >>
> > >> @@ -262,6 +263,8 @@ static void tpm_crb_reset(void *dev)
> > >> CapCRB, CRB_INTF_CAP_CRB_SUPPORTED);
> > >> ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
> > >> InterfaceSelector, CRB_INTF_IF_SELECTOR_CRB);
> > >> + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
> > >> + CapCRBChunk, CRB_INTF_CAP_CRB_CHUNK);
> > >
> > > We should not expose that new capability to guests without an explicit
> > > "cap-chunk=on".
> >
> > You mean put this on the QEMU command line? This new capability is
> > really only needed if the user chooses PQC algorithm support (but then I
> > was also going to allow for 7kb writes to NVRAM spaces rather than 1kb
> > writes so far) and if the user chooses a swtpm profile with such support
> > but then fails to set this flag, some transmissions won't work. What
> > would be the problem if we exposed this new feature all the time and if
> > we can avoid state backwards-incompatibilities, which IMO is the most
> > important aspect, if we detect that chunking was not used by the driver
>
> In general, we shouldn't suddenly expose device capabilities to
> guests. Starting with 11.1 machine, the cap-chunk feature can be
> enabled by default though.
You are right, we do not need to keep track of 2 properties. I will
remove migrate_buffers hw_compat property.
IIUC, you meant we need to expose cap-chunk i.e. remove "x-".
And the whole logic of exposing it based on machine type should also be
moved to earlier i.e. [PATCH v4 01/10] hw/tpm: Add TPM CRB chunking fields
instead of [PATCH v4 06/10] hw/tpm: Add support for VM migration with TPM CRB chunking.
>
> > and only write additional state if found absolutely necessary? I would
> > prefer to untangle the user's choice of enabled algorithm from the
> > choice of such a flag. But then there's the aspect of OS drivers that
> > could use chunking even when not absolutely necessary (?).
>
Reards,
Arun Menon
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-04-20 11:51 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-14 8:29 [PATCH v4 00/10] hw/tpm: CRB chunking capability to handle PQC Arun Menon
2026-04-14 8:29 ` [PATCH v4 01/10] hw/tpm: Add TPM CRB chunking fields Arun Menon
2026-04-17 10:05 ` Marc-André Lureau
2026-04-17 14:34 ` Stefan Berger
2026-04-17 14:51 ` Marc-André Lureau
2026-04-20 11:50 ` Arun Menon
2026-04-14 8:29 ` [PATCH v4 02/10] hw/tpm: Refactor CRB_CTRL_START register access Arun Menon
2026-04-14 8:29 ` [PATCH v4 03/10] hw/tpm: Add internal buffer state for chunking Arun Menon
2026-04-14 8:29 ` [PATCH v4 04/10] hw/tpm: Implement TPM CRB chunking logic Arun Menon
2026-04-14 8:29 ` [PATCH v4 05/10] test/qtest: Add test for tpm crb chunking Arun Menon
2026-04-14 8:29 ` [PATCH v4 06/10] hw/tpm: Add support for VM migration with TPM CRB chunking Arun Menon
2026-04-14 8:29 ` [PATCH v4 07/10] qtests: Enable starting swtpm with a given profile Arun Menon
2026-04-14 8:29 ` [PATCH v4 08/10] tests: Use ML-DSA-87 operations to caused large TPM transfers with CRB Arun Menon
2026-04-14 8:29 ` [PATCH v4 09/10] tpm: Extend TPM TIS buffer size to 8192 bytes Arun Menon
2026-04-14 8:29 ` [PATCH v4 10/10] tests: Use ML-DSA-87 operations to caused large TPM transfers with TIS Arun Menon
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.