[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 4/4] libxl: Add emulated TPM support on ARM


  • To: <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Jason Andryuk <jason.andryuk@xxxxxxx>
  • Date: Fri, 6 Nov 2026 18:15:26 -0500
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=lists.xenproject.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0)
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=CvB52JWQG6bRO1jPkIW77vtkV0moRZM3AN5DW/h+kik=; b=HHhCykoyUKPTNguUDSU9NRr5kWPuqJF/eXEgiCgys7lLyfJ623/3B5KH4BOvCVFRYbFcjR2qvM+zjX6hw65tb3TpYSMomfOPgCbX2hQIe0q9SIiH4RPbb3mM2hEMwllQWO8DlC2YTSCjth2xYaE/pFQexbKq4A9fmBYUMm9O//p5O4x4Daj1925PcNJZvpPPm//pTw2AUfcEERfCid8QL6EMNe6VmGeID+98t2d5Kon30x1qH+u8QD7JqSiJagYW71vxq+VM8QhyvR3S1BgX1UvwMrLZveCuJXFmvp3iTXEtqO1MR7e2bI5lAK4SQApFTWth6zW5kfkNRtJuVsZ0OA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=bkX/oxY+rN7V6xkprNHd96Wxpg8G6JhW3dUgQMRmQWddXYFDWI6Rsz5VIUKlgRLktW2NomjE3r32Ino2/e66BqMO3pSLeE+oimh3lGDp9COKDftju6oNe3nAtpJEHXLlZZ8aoiTxb2ipH+HyTDLdlq/Yh7fgGuakpktUGDYtgoOP14CIMsvQy0QEZptuQO2rzHqsun/sB7my8CC/6wWI4X7QIqdjgmvPTdouemsju8frxBWqOVHK+OySdC03ifRALVxcZNAS6e35LkNInsyp8PvfpIKvQ/eSwv9ZtOUiAgvtRBUavruKaiZHoatHt1PIGlJSN+pTVV1cRa+5DZ4E7Q==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=amd.com header.i="@amd.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Cc: Stefano Stabellini <stefano.stabellini@xxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Juergen Gross <jgross@xxxxxxxx>, "Stefano Stabellini" <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Stefano Stabellini <stefano.stabellini@xxxxxxxxxx>, Jason Andryuk <jason.andryuk@xxxxxxx>
  • Delivery-date: Fri, 06 Nov 2026 23:15:55 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

From: Stefano Stabellini <stefano.stabellini@xxxxxxx>

QEMU's ARM "xenpvh" machine runs as an IOREQ server and, when given a
"tpm-base-addr" machine property, instantiates a TPM TIS sysbus device
at that address connected to the "tpm0" TPM backend.  Hook the existing
tpm_* configuration up to it so ARM guests can use an swtpm-backed TPM.

Reserve GUEST_TPM_BASE/GUEST_TPM_SIZE in the ARM guest memory map and
add a "tcg,tpm-tis-mmio" node to the guest device tree when a TPM
version is configured.  The xenpvh machine has no CRB device, so TIS is
the default and only interface allowed for both TPM 1.2 and 2.0.

Add libxl__arch_pv_pvh_machinearg() returning the QEMU -machine argument
for a PV/PVH guest.  x86 returns plain "xenpv", while ARM uses "xenpvh"
and appends tpm-base-addr when a TPM is configured.  uint64_t tpm_base
in ARM's libxl__arch_pvh_machinearg() is to allow PRIx64 to print the
value.  Otherwise the ull argument mismatches PRIx64's %lx format.

libxl__arch_pv_pvh_machinearg() also handles PV guests.  This keeps the
extra_pv handling identical between PV and PVH guests.

Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxx>
[ Merge ARM parts with new libxl_dm implementation. ]
Signed-off-by: Jason Andryuk <jason.andryuk@xxxxxxx>
---
 docs/man/xl.cfg.5.pod.in      | 14 ++++++++---
 tools/include/libxl.h         |  5 ++--
 tools/libs/light/libxl_arch.h |  6 +++++
 tools/libs/light/libxl_arm.c  | 47 +++++++++++++++++++++++++++++++++++
 tools/libs/light/libxl_dm.c   | 14 ++++++++++-
 tools/libs/light/libxl_x86.c  |  6 +++++
 xen/include/public/arch-arm.h |  4 +++
 7 files changed, 89 insertions(+), 7 deletions(-)

diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in
index c12d2dc4db..e5952d7e27 100644
--- a/docs/man/xl.cfg.5.pod.in
+++ b/docs/man/xl.cfg.5.pod.in
@@ -823,11 +823,16 @@ value is optional if this is a guest domain.
 
 =item B<tpm_version=NUMBER>
 
-Provides an emulated TPM to a QEMU-based HVM guest, backed by B<swtpm(8)>.
-The TPM version to emulate is either B<1> for TPM 1.2 or B<2> for TPM 2.0.
+Provides an emulated TPM to a QEMU-based HVM guest, or to an Arm guest,
+backed by B<swtpm(8)>.  The TPM version to emulate is either B<1> for
+TPM 1.2 or B<2> for TPM 2.0.
 When this option is not specified, no TPM is provided and the other
 B<tpm_*> options are ignored.
 
+On Arm, QEMU's B<xenpvh> machine is started as an IOREQ server to emulate
+a TPM TIS interface, and the guest device tree gains a
+C<tcg,tpm-tis-mmio> node describing it.
+
 One of B<tpm_statefile> or B<tpm_statedir> is required, but not both.
 
 =item B<tpm_statefile="PATH">
@@ -844,8 +849,9 @@ Path to a directory in which B<swtpm> stores the persistent 
TPM state.
 
 The TPM interface presented to the guest.  B<tis> is the TPM Interface
 Specification (FIFO) interface and B<crb> is the Command Response Buffer
-interface.  B<tpm_version=1> only supports B<tis>, while B<tpm_version=2>
-supports either and defaults to B<crb>.
+interface.  On x86, B<tpm_version=1> only supports B<tis>, while
+B<tpm_version=2> supports either and defaults to B<crb>.  On Arm, only
+B<tis> is supported, for both TPM versions.
 
 =item B<tpm_swtpm_override="PATH">
 
diff --git a/tools/include/libxl.h b/tools/include/libxl.h
index 8b431b708d..8d19cf41bc 100644
--- a/tools/include/libxl.h
+++ b/tools/include/libxl.h
@@ -1568,8 +1568,9 @@ void libxl_mac_copy(libxl_ctx *ctx, libxl_mac *dst, const 
libxl_mac *src);
  *
  * If this is defined the tpm member of struct domain_build_info is
  * available.  When its version is non-zero, libxl starts swtpm to
- * provide an emulated TPM to a QEMU-based HVM guest.  Its interface
- * member selects the TPM interface (TIS or CRB) presented to the guest.
+ * provide an emulated TPM to a QEMU-based HVM guest, or to an Arm guest
+ * via QEMU's xenpvh machine.  Its interface member selects the TPM
+ * interface (TIS or CRB) presented to the guest.
  */
 #define LIBXL_HAVE_TPM
 
diff --git a/tools/libs/light/libxl_arch.h b/tools/libs/light/libxl_arch.h
index c8ef52ddbe..b3355d1e82 100644
--- a/tools/libs/light/libxl_arch.h
+++ b/tools/libs/light/libxl_arch.h
@@ -97,6 +97,12 @@ _hidden
 int libxl__arch_hvm_unmap_gsi(libxl__gc *gc, uint32_t sbdf, uint32_t domid);
 _hidden
 bool libxl__arch_local_domain_has_pirq_notion(libxl__gc *gc);
+
+/* QEMU -machine argument for a PVH guest. */
+_hidden
+char *libxl__arch_pv_pvh_machinearg(libxl__gc *gc,
+                                    const libxl_domain_build_info *b_info);
+
 #if defined(__i386__) || defined(__x86_64__)
 
 #define LAPIC_BASE_ADDRESS  0xfee00000
diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c
index 47b662ea5c..6325b19766 100644
--- a/tools/libs/light/libxl_arm.c
+++ b/tools/libs/light/libxl_arm.c
@@ -978,6 +978,29 @@ static int make_xen_iommu_node(libxl__gc *gc, void *fdt)
     return 0;
 }
 
+static int make_tpm_node(libxl__gc *gc, void *fdt)
+{
+    int res;
+    const uint64_t base = GUEST_TPM_BASE;
+    const char *name = GCSPRINTF("tpm@%"PRIx64, base);
+
+    res = fdt_begin_node(fdt, name);
+    if (res) return res;
+
+    res = fdt_property_compat(gc, fdt, 1, "tcg,tpm-tis-mmio");
+    if (res) return res;
+
+    res = fdt_property_regs(gc, fdt, GUEST_ROOT_ADDRESS_CELLS,
+                            GUEST_ROOT_SIZE_CELLS, 1,
+                            base, GUEST_TPM_SIZE);
+    if (res) return res;
+
+    res = fdt_end_node(fdt);
+    if (res) return res;
+
+    return 0;
+}
+
 /* The caller is responsible to complete / close the fdt node */
 static int make_virtio_mmio_node_common(libxl__gc *gc, void *fdt, uint64_t 
base,
                                         uint32_t irq, uint32_t backend_domid,
@@ -1450,6 +1473,9 @@ next_resize:
         if (iommu_needed)
             FDT( make_xen_iommu_node(gc, fdt) );
 
+        if (info->tpm.version)
+            FDT( make_tpm_node(gc, fdt) );
+
         if (pfdt)
             FDT( copy_partial_fdt(gc, fdt, pfdt) );
 
@@ -1860,6 +1886,16 @@ int libxl__arch_domain_build_info_setdefault(libxl__gc 
*gc,
         return ERROR_FAIL;
     }
 
+    /* The xenpvh machine only provides a TIS TPM interface. */
+    if (b_info->tpm.version) {
+        if (b_info->tpm.interface == LIBXL_TPM_INTERFACE_DEFAULT)
+            b_info->tpm.interface = LIBXL_TPM_INTERFACE_TIS;
+        if (b_info->tpm.interface != LIBXL_TPM_INTERFACE_TIS) {
+            LOG(ERROR, "Only the tis TPM interface is supported on Arm.");
+            return ERROR_INVAL;
+        }
+    }
+
     /* Sanitise SVE parameter */
     if (b_info->arch_arm.sve_vl) {
         unsigned int max_sve_vl =
@@ -1949,6 +1985,17 @@ bool libxl__arch_local_domain_has_pirq_notion(libxl__gc 
*gc)
     return true;
 }
 
+char *libxl__arch_pv_pvh_machinearg(libxl__gc *gc,
+                                    const libxl_domain_build_info *b_info)
+{
+    uint64_t tpm_base = GUEST_TPM_BASE;
+
+    if (b_info->tpm.version)
+        return GCSPRINTF("xenpvh,tpm-base-addr=0x%"PRIx64, tpm_base);
+
+    return libxl__strdup(gc, "xenpvh");
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libs/light/libxl_dm.c b/tools/libs/light/libxl_dm.c
index 843b8e29eb..ebdd05586e 100644
--- a/tools/libs/light/libxl_dm.c
+++ b/tools/libs/light/libxl_dm.c
@@ -18,6 +18,7 @@
 #include "libxl_osdeps.h" /* must come before any other headers */
 
 #include "libxl_internal.h"
+#include "libxl_arch.h"
 
 #include <xen/hvm/e820.h>
 #include <sys/types.h>
@@ -1573,7 +1574,12 @@ static int libxl__build_device_model_args_new(libxl__gc 
*gc,
     switch (b_info->type) {
     case LIBXL_DOMAIN_TYPE_PVH:
     case LIBXL_DOMAIN_TYPE_PV:
-        flexarray_append(dm_args, "xenpv");
+        machinearg = libxl__arch_pv_pvh_machinearg(gc, b_info);
+        flexarray_append(dm_args, machinearg);
+
+        if (b_info->tpm.version)
+            libxl__dm_add_tpm_args(gc, dm_args, guest_domid);
+
         for (i = 0; b_info->extra_pv && b_info->extra_pv[i] != NULL; i++)
             flexarray_append(dm_args, b_info->extra_pv[i]);
         break;
@@ -3892,6 +3898,12 @@ int libxl__need_xenpv_qemu(libxl__gc *gc, 
libxl_domain_config *d_config)
         goto out;
     }
 
+    /* QEMU provides the emulated TPM, e.g. via the ARM xenpvh machine. */
+    if (d_config->b_info.tpm.version) {
+        ret = 1;
+        goto out;
+    }
+
     for (idx = 0;; idx++) {
         dt = device_type_tbl[idx];
         if (!dt)
diff --git a/tools/libs/light/libxl_x86.c b/tools/libs/light/libxl_x86.c
index 3182cfc9df..a6e9ad777e 100644
--- a/tools/libs/light/libxl_x86.c
+++ b/tools/libs/light/libxl_x86.c
@@ -937,6 +937,12 @@ bool libxl__arch_local_domain_has_pirq_notion(libxl__gc 
*gc)
     return false;
 }
 
+char *libxl__arch_pv_pvh_machinearg(libxl__gc *gc,
+                                    const libxl_domain_build_info *b_info)
+{
+    return libxl__strdup(gc, "xenpv");
+}
+
 int libxl__arch_hvm_map_gsi(libxl__gc *gc, uint32_t sbdf, uint32_t domid)
 {
     int pirq = -1, gsi, r;
diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
index 5d15f572c7..efb45eb33c 100644
--- a/xen/include/public/arch-arm.h
+++ b/xen/include/public/arch-arm.h
@@ -452,6 +452,10 @@ typedef uint64_t xen_callback_t;
 #define GUEST_VPCI_ECAM_BASE    xen_mk_ullong(0x10000000)
 #define GUEST_VPCI_ECAM_SIZE    xen_mk_ullong(0x10000000)
 
+/* Emulated TPM (TIS over MMIO) */
+#define GUEST_TPM_BASE    xen_mk_ullong(0x0c000000)
+#define GUEST_TPM_SIZE    xen_mk_ullong(0x00005000)
+
 /* ACPI tables physical address */
 #define GUEST_ACPI_BASE xen_mk_ullong(0x20000000)
 #define GUEST_ACPI_SIZE xen_mk_ullong(0x02000000)
-- 
2.34.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.