Commit a94f1c2eff for qemu.org

commit a94f1c2eff993a5cafd666eed89e59775cde28b0
Author: Stefan Berger <stefanb@linux.vnet.ibm.com>
Date:   Wed Apr 29 12:17:43 2026 +0000

    tests: Add a TPM TIS I2C swtpm test

    Add a test case testing the TPM TIS over I2C with swtpm.

    Reviewed-by: Arun Menon <armenon@redhat.com>
    Link: https://lore.kernel.org/qemu-devel/20260429121743.1346635-7-stefanb@linux.ibm.com
    Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>

diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 57512c6e56..45ea497fa5 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -244,7 +244,7 @@ qtests_arm = \
   (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed : []) + \
   (config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
   (config_all_devices.has_key('CONFIG_GENERIC_LOADER') ? ['hexloader-test'] : []) + \
-  (config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
+  (config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test', 'tpm-tis-i2c-swtpm-test'] : []) + \
   (config_all_devices.has_key('CONFIG_VEXPRESS') ? ['test-arm-mptimer'] : []) + \
   (config_all_devices.has_key('CONFIG_MICROBIT') ? ['microbit-test'] : []) + \
   (config_all_devices.has_key('CONFIG_STM32L4X5_SOC') ? qtests_stm32l4x5 : []) + \
@@ -263,7 +263,7 @@ qtests_aarch64 = \
   (config_all_devices.has_key('CONFIG_XLNX_VERSAL') ? ['xlnx-canfd-test', 'xlnx-versal-trng-test'] : []) + \
   (config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test', 'bcm2835-i2c-test'] : []) +  \
   (config_all_accel.has_key('CONFIG_TCG') and                                            \
-   config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
+   config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test', 'tpm-tis-i2c-swtpm-test'] : []) + \
   (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \
   (config_all_devices.has_key('CONFIG_NPCM8XX') ? qtests_npcm8xx : []) + \
   (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and
@@ -402,6 +402,7 @@ qtests = {
   'tpm-tis-swtpm-test': [io, tpmemu_files, 'tpm-tis-util.c'],
   'tpm-tis-test': [io, tpmemu_files, 'tpm-tis-util.c'],
   'tpm-tis-i2c-test': [io, tpmemu_files, 'tpm-tis-i2c-util.c', 'qtest_aspeed.c'],
+  'tpm-tis-i2c-swtpm-test': [io, tpmemu_files, 'tpm-tis-i2c-util.c', 'qtest_aspeed.c'],
   'tpm-tis-device-swtpm-test': [io, tpmemu_files, 'tpm-tis-util.c'],
   'tpm-tis-device-test': [io, tpmemu_files, 'tpm-tis-util.c'],
   'virtio-net-failover': test_migration_files,
diff --git a/tests/qtest/tpm-tis-i2c-swtpm-test.c b/tests/qtest/tpm-tis-i2c-swtpm-test.c
new file mode 100644
index 0000000000..50d32a960b
--- /dev/null
+++ b/tests/qtest/tpm-tis-i2c-swtpm-test.c
@@ -0,0 +1,82 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * QTest testcase for TPM TIS over I2C talking to external swtpm
+ *
+ * Copyright (c) 2018, 2026 IBM Corporation
+ *  with parts borrowed from migration-test.c that is:
+ *     Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *   Stefan Berger <stefanb@linux.ibm.com>
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "tpm-tests.h"
+#include "tpm-tis-i2c-util.h"
+#include "qtest_aspeed.h"
+
+typedef struct TestState {
+    char *src_tpm_path;
+    char *dst_tpm_path;
+    char *uri;
+    const char *machine_options;
+    char *ifmodel;
+} TestState;
+
+static void tpm_tis_i2c_swtpm_test(const void *data)
+{
+    const TestState *ts = data;
+
+    tpm_test_swtpm_test(ts->src_tpm_path, tpm_tis_i2c_transfer,
+                        ts->ifmodel, ts->machine_options);
+}
+
+static void tpm_tis_swtpm_migration_test(const void *data)
+{
+    const TestState *ts = data;
+
+    tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path,
+                                  ts->uri, tpm_tis_i2c_transfer,
+                                  ts->ifmodel, ts->machine_options);
+}
+
+
+int main(int argc, char **argv)
+{
+    int ret;
+    TestState ts;
+
+    ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-tis-i2c-swtpm-test.XXXXXX",
+                                     NULL);
+    ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-tis-i2c-swtpm-test.XXXXXX",
+                                     NULL);
+    ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path);
+    ts.machine_options = "-machine rainier-bmc -accel tcg";
+    ts.ifmodel = g_strdup_printf(
+                            "tpm-tis-i2c,bus=aspeed.i2c.bus.%d,address=0x%x",
+                            I2C_DEV_BUS_NUM, I2C_SLAVE_ADDR);
+
+    module_call_init(MODULE_INIT_QOM);
+    g_test_init(&argc, &argv, NULL);
+
+    aspeed_bus_addr = ast2600_i2c_calc_bus_addr(I2C_DEV_BUS_NUM);
+
+    qtest_add_data_func("/tpm/tis-i2c-swtpm/test", &ts, tpm_tis_i2c_swtpm_test);
+    qtest_add_data_func("/tpm/tis-i2c-swtpm-migration/test", &ts,
+                        tpm_tis_swtpm_migration_test);
+    ret = g_test_run();
+
+    tpm_util_rmdir(ts.dst_tpm_path);
+    g_free(ts.dst_tpm_path);
+    tpm_util_rmdir(ts.src_tpm_path);
+    g_free(ts.src_tpm_path);
+    g_free(ts.uri);
+    g_free(ts.ifmodel);
+
+    return ret;
+}
diff --git a/tests/qtest/tpm-tis-i2c-util.c b/tests/qtest/tpm-tis-i2c-util.c
index 6e724a4a47..c73420ec5b 100644
--- a/tests/qtest/tpm-tis-i2c-util.c
+++ b/tests/qtest/tpm-tis-i2c-util.c
@@ -15,6 +15,7 @@
 #include "libqtest-single.h"
 #include "qtest_aspeed.h"
 #include "tpm-tis-i2c-util.h"
+#include "tpm-emu.h"

 uint32_t aspeed_bus_addr;

@@ -62,3 +63,40 @@ void tpm_tis_i2c_writel(QTestState *s, uint8_t locty, uint8_t reg, uint32_t v)
     }
     aspeed_i2c_writel(s, aspeed_bus_addr, I2C_SLAVE_ADDR, reg, v);
 }
+
+void tpm_tis_i2c_transfer(QTestState *s,
+                          const unsigned char *req, size_t req_size,
+                          unsigned char *rsp, size_t rsp_size)
+{
+    uint32_t sts;
+    size_t i;
+
+    /* request use of locality 0 */
+    tpm_tis_i2c_writeb(s, 0, TPM_I2C_REG_ACCESS, TPM_TIS_ACCESS_REQUEST_USE);
+
+    tpm_tis_i2c_writel(s, 0, TPM_I2C_REG_STS, TPM_TIS_STS_COMMAND_READY);
+
+    /* transmit command */
+    for (i = 0; i < req_size; i++) {
+        tpm_tis_i2c_writeb(s, 0, TPM_I2C_REG_DATA_FIFO, req[i]);
+    }
+
+    /* start processing */
+    tpm_tis_i2c_writeb(s, 0, TPM_I2C_REG_STS, TPM_TIS_STS_TPM_GO);
+
+    uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
+    do {
+        sts = tpm_tis_i2c_readl(s, 0, TPM_I2C_REG_STS);
+        if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
+            break;
+        }
+    } while (g_get_monotonic_time() < end_time);
+
+    /* read response */
+    for (i = 0; i < rsp_size; i++) {
+        rsp[i] = tpm_tis_i2c_readb(s, 0, TPM_I2C_REG_DATA_FIFO);
+    }
+    /* relinquish use of locality 0 */
+    tpm_tis_i2c_writeb(s, 0,
+                       TPM_I2C_REG_ACCESS, TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+}
diff --git a/tests/qtest/tpm-tis-i2c-util.h b/tests/qtest/tpm-tis-i2c-util.h
index 3289545f61..499bf4964a 100644
--- a/tests/qtest/tpm-tis-i2c-util.h
+++ b/tests/qtest/tpm-tis-i2c-util.h
@@ -27,4 +27,8 @@ uint32_t tpm_tis_i2c_readl(QTestState *s, uint8_t locty, uint8_t reg);
 void tpm_tis_i2c_writeb(QTestState *s, uint8_t locty, uint8_t reg, uint8_t v);
 void tpm_tis_i2c_writel(QTestState *s, uint8_t locty, uint8_t reg, uint32_t v);

+void tpm_tis_i2c_transfer(QTestState *s,
+                          const unsigned char *req, size_t req_size,
+                          unsigned char *rsp, size_t rsp_size);
+
 #endif /* TESTS_TPM_TIS_I2C_UTIL_H */