[PATCH v4 13/23] x86/slaunch: measure MBI into TPM

Sergii Dmytruk <[email protected]> Sun, 2 Aug 2026 16:09:29 +0300
Newsgroups gmane.comp.emulators.xen.devel
Message-ID <8e971b5b87d6b5dd7aebba55a40ddaeed7b97616.1785668458.git.sergii.dmytruk@3mdeb.com>
From: Krystian Hebel <[email protected]>

Make slaunch-tpm.c compile in early boot environment use it to measure
MBI in early 32b code without paging (gets triggered from head.S).

The fact of the measurement is not yet stored anywhere as there is no
code for TPM event log discovery and modification.

Signed-off-by: Krystian Hebel <[email protected]>
Signed-off-by: Sergii Dmytruk <[email protected]>
---

Notes:
    v4: was part of "x86/tpm.c: code for early hashing and extending PCRs (for TPM1.2)"
    v4: tpm_extend_mbi => slaunch_measure_mbi
    v4: doesn't touch tpm.c, uses slaunch-tpm.c instead
    v4: use `const multiboot2_fixed_t *` instead of `uint32_t *` for MBI

 xen/arch/x86/boot/Makefile             |   7 +-
 xen/arch/x86/boot/head.S               |   5 ++
 xen/arch/x86/include/asm/slaunch-tpm.h |   7 ++
 xen/arch/x86/include/asm/slaunch.h     |  14 ++++
 xen/arch/x86/slaunch-tpm.c             | 112 +++++++++++++++++++++++++
 xen/arch/x86/slaunch.c                 |   4 +
 6 files changed, 148 insertions(+), 1 deletion(-)

diff --git a/xen/arch/x86/boot/Makefile b/xen/arch/x86/boot/Makefile
index 02f690d34a..b31c96be18 100644
--- a/xen/arch/x86/boot/Makefile
+++ b/xen/arch/x86/boot/Makefile
@@ -7,6 +7,7 @@ obj32 += reloc.32.o
 obj32 += reloc-trampoline.32.o
 ifeq ($(CONFIG_SLAUNCH),y)
 obj32 += slaunch-early.32.o
+obj32 += slaunch-tpm-early.32.o
 endif
 obj32 += tpm-early.32.o
 
@@ -14,7 +15,7 @@ obj64 := reloc-trampoline.o
 
 exports := cmdline_parse_early,reloc,reloc_trampoline32
 ifeq ($(CONFIG_SLAUNCH),y)
-exports := $(exports),slaunch_early_init
+exports := $(exports),slaunch_early_init,slaunch_measure_mbi
 endif
 
 nocov-y   += $(obj32) $(obj64)
@@ -39,6 +40,10 @@ $(obj)/%.32.o: $(src)/%.c FORCE
 
 $(obj)/slaunch-early.32.o: XEN_CFLAGS += -D__EARLY_SLAUNCH__
 
+$(obj)/slaunch-tpm-early.32.o: XEN_CFLAGS += -D__EARLY_SLAUNCH__
+$(obj)/slaunch-tpm-early.32.o: $(src)/../slaunch-tpm.c FORCE
+	$(call if_changed_rule,cc_o_c)
+
 $(obj)/tpm-early.32.o: XEN_CFLAGS += -D__EARLY_TPM__
 $(obj)/tpm-early.32.o: $(src)/../tpm.c FORCE
 	$(call if_changed_rule,cc_o_c)
diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S
index 700d1d850e..2c1a0f6306 100644
--- a/xen/arch/x86/boot/head.S
+++ b/xen/arch/x86/boot/head.S
@@ -539,6 +539,11 @@ __start:
         pop     sym_esi(slaunch_slrt) /* save physical address of SLRT for C
                                          code */
 
+        mov     sym_esi(slaunch_slrt), %edx /* physical SLRT address */
+        mov     %ebx, %eax                  /* physical MBI address */
+        /* slaunch_measure_mbi(mbi/eax, slrt/edx) using fastcall. */
+        call    slaunch_measure_mbi
+
         /* Move magic number expected by Multiboot 2 to EAX and fall through. */
         movl    $MULTIBOOT2_BOOTLOADER_MAGIC, %eax
 #endif
diff --git a/xen/arch/x86/include/asm/slaunch-tpm.h b/xen/arch/x86/include/asm/slaunch-tpm.h
index 68e9c8358a..79154f505b 100644
--- a/xen/arch/x86/include/asm/slaunch-tpm.h
+++ b/xen/arch/x86/include/asm/slaunch-tpm.h
@@ -16,4 +16,11 @@ struct slr_table;
 void slaunch_find_log(const struct slr_table *slrt, paddr_t *evt_log,
                       uint32_t *evt_log_size);
 
+/*
+ * Log data is optional (pass in NULL and/or zero size to indicate its absence).
+ */
+void slaunch_hash_extend(unsigned int loc, unsigned int pcr, const uint8_t *buf,
+                         unsigned int size, uint32_t type,
+                         const uint8_t *log_data, unsigned int log_data_size);
+
 #endif /* X86_SLAUNCH_TPM_H */
diff --git a/xen/arch/x86/include/asm/slaunch.h b/xen/arch/x86/include/asm/slaunch.h
index 459fc83388..65aab01f04 100644
--- a/xen/arch/x86/include/asm/slaunch.h
+++ b/xen/arch/x86/include/asm/slaunch.h
@@ -17,6 +17,20 @@
 #include <xen/slr-table.h>
 #include <xen/types.h>
 
+#define DRTM_LOC                   2
+#define DRTM_CODE_PCR              17
+#define DRTM_DATA_PCR              18
+
+/*
+ * Secure Launch event log entry types. The TXT specification defines the base
+ * event value as 0x400 for DRTM values, use it regardless of the DRTM for
+ * consistency.
+ */
+#define DLE_EVTYPE_BASE            0x400
+#define DLE_EVTYPE_SLAUNCH         (DLE_EVTYPE_BASE + 0x102)
+#define DLE_EVTYPE_SLAUNCH_START   (DLE_EVTYPE_BASE + 0x103)
+#define DLE_EVTYPE_SLAUNCH_END     (DLE_EVTYPE_BASE + 0x104)
+
 struct slaunch_early_init_results
 {
     uint32_t mbi_pa;
diff --git a/xen/arch/x86/slaunch-tpm.c b/xen/arch/x86/slaunch-tpm.c
index f59170594d..21dec67dca 100644
--- a/xen/arch/x86/slaunch-tpm.c
+++ b/xen/arch/x86/slaunch-tpm.c
@@ -2,13 +2,71 @@
 /*
  * Slaunch functions related to TPM.
  *
+ * This file is built twice:
+ *  1. For early 32b mode without paging when it also provides
+ *     slaunch_measure_mbi() to be called from assembly.
+ *  2. For 64b code.
+ *
  * Copyright (c) 2022-2026 3mdeb Sp. z o.o.  All rights reserved.
  */
 
+#include <xen/compiler.h>
+#include <xen/lib.h>
 #include <xen/macros.h>
+#include <xen/multiboot2.h>
+#include <xen/sha1.h>
+#include <xen/sha2.h>
 #include <xen/slr-table.h>
 #include <xen/types.h>
 
+#include <asm/intel-txt.h>
+#include <asm/slaunch.h>
+#include <asm/slaunch-tpm.h>
+#include <asm/tpm.h>
+#include <asm/tpm2.h>
+
+#ifdef __EARLY_SLAUNCH__
+
+#ifdef __va
+#error "__va defined in non-paged mode!"
+#endif
+
+#define __va(x)  _p(x)
+
+static uint32_t slrt_location;
+
+/*
+ * The code is being compiled as a standalone binary without linking to any
+ * other part of Xen.  Providing implementation of builtin functions in this
+ * case is necessary if compiler chooses to not use an inline builtin.
+ */
+void *(memset)(void *s, int c, size_t n)
+{
+    uint8_t *d = s;
+
+    while ( n-- )
+        *d++ = c;
+
+    return s;
+}
+
+struct slr_table *slaunch_get_slrt(void)
+{
+    return _p(slrt_location);
+}
+
+void asmlinkage slaunch_measure_mbi(const multiboot2_fixed_t *mbi,
+                                    uint32_t slrt_pa)
+{
+    /* Need this to implement slaunch_get_slrt() for early TPM code. */
+    slrt_location = slrt_pa;
+
+    slaunch_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (const uint8_t *)mbi,
+                        mbi->total_size, DLE_EVTYPE_SLAUNCH, NULL, 0);
+}
+
+#endif  /* __EARLY_SLAUNCH__ */
+
 void slaunch_find_log(const struct slr_table *slrt, paddr_t *evt_log,
                       uint32_t *evt_log_size)
 {
@@ -34,3 +92,57 @@ void slaunch_find_log(const struct slr_table *slrt, paddr_t *evt_log,
         *evt_log_size = 0;
     }
 }
+
+void slaunch_hash_extend(unsigned int loc, unsigned int pcr, const uint8_t *buf,
+                         unsigned int size, uint32_t type,
+                         const uint8_t *log_data, unsigned int log_data_size)
+{
+    paddr_t evt_log_paddr;
+    uint32_t evt_log_size;
+    struct tpm_log_hashes log_hashes;
+    uint8_t discarded_digests[SHA2_256_DIGEST_SIZE];
+    uint32_t rc;
+
+    slaunch_find_log(slaunch_get_slrt(), &evt_log_paddr, &evt_log_size);
+
+    if ( tpm_is_tpm1() )
+    {
+        log_hashes = (struct tpm_log_hashes) {
+            .count = 1,
+            .hashes = {
+                {
+                    .alg = TPM_ALG_SHA1,
+                    .size = SHA1_DIGEST_SIZE,
+                    .data = discarded_digests,
+                },
+            },
+        };
+    }
+    else
+    {
+        log_hashes = (struct tpm_log_hashes) {
+            .count = 2,
+            .hashes = {
+                {
+                    .alg = TPM_ALG_SHA1,
+                    .size = SHA1_DIGEST_SIZE,
+                    .data = discarded_digests,
+                },
+                {
+                    .alg = TPM_ALG_SHA256,
+                    .size = SHA2_256_DIGEST_SIZE,
+                    .data = discarded_digests,
+                },
+            },
+        };
+    }
+
+    rc = tpm_hash_extend(loc, pcr, buf, size, &log_hashes);
+    if (rc != 0)
+    {
+#ifndef __EARLY_SLAUNCH__
+        printk(XENLOG_ERR "Extending PCR-%u failed with an error: 0x%08x\n",
+               pcr, rc);
+#endif
+    }
+}
diff --git a/xen/arch/x86/slaunch.c b/xen/arch/x86/slaunch.c
index ba1ba61c47..83dce3d57d 100644
--- a/xen/arch/x86/slaunch.c
+++ b/xen/arch/x86/slaunch.c
@@ -18,6 +18,7 @@
 #include <asm/setup.h>
 #include <asm/slaunch.h>
 #include <asm/slaunch-tpm.h>
+#include <asm/tpm.h>
 
 /*
  * These variables are assigned to by the code near Xen's entry point.
@@ -78,6 +79,9 @@ void __init slaunch_map_mem_regions(void)
     paddr_t evt_log_addr;
     uint32_t evt_log_size;
 
+    rc = slaunch_map_l2(TPM_MMIO_BASE, TPM_MMIO_SIZE);
+    BUG_ON(rc != 0);
+
     /* Vendor-specific part. */
     txt_map_mem_regions();
 
-- 
2.55.0