[PATCH v3 00/19] x86: Trenchboot Secure Launch DRTM for Intel TXT (GRUB)

6 views
Skip to first unread message

Sergii Dmytruk

unread,
Dec 12, 2024, 8:41:52 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
Hello,

Continuing upstreaming [TrenchBoot] code changes. More context can be found in
the cover letter for [v1]. This set targets v11 of Linux patches [linux-v11].

How the patches look now:

1. [01-02] Various additions in preparation for later commits
2. [03-05] TPM-related part (`tpm` module rename, addition of a simple TPM
driver)
3. [06-08] SecureLaunch with its SLRT
4. [09-12] Support for Intel TXT D-RTM
5. [13-15] Implementation of SecureLaunch commands
6. [16] Support for TPM 1
7. [17-19] Multiboot2 support for Intel TXT

This set of changes can also be viewed on GitHub at [TrenchBoot/grub].

Best regards,
Sergii

-----

Changes in v3:
- rebase on latest master
- overhaul that changes how SLRT is built, adds UEFI support and a common DL
entry
- AMD changes were removed from this series to be submitted separately

Changes in [v2]:
- 5 patches landed as a separate [generic-x86] series
- 3 patches were in [generic-x86] as well, got Reviewed-Bys and returned here;
one of them was extracted out of a different patch
- patches related to modules received some documentation additions
- several commit messages became more verbose
- some commits have seen cosmetic changes with no impact on functionality
- a leak fix got dropped to be sent separately (it's not really related to the
rest of changes)

-----

[TrenchBoot]: https://trenchboot.org/
[v1]: https://lists.gnu.org/archive/html/grub-devel/2024-08/msg00088.html
[v2]: https://lists.gnu.org/archive/html/grub-devel/2024-11/msg00000.html
[TrenchBoot/grub]: https://github.com/TrenchBoot/grub/compare/f6e2ef2...tb-2.12-139-v3
[generic-x86]: https://lists.gnu.org/archive/html/grub-devel/2024-10/msg00055.html
[linux-v11]: https://lkml.org/lkml/2024/9/13/1396

-----

Aleksandr Burmashev (1):
commands/tpm: Rename tpm module to tpm_verifier

Daniel Kiper (2):
mmap: Add grub_mmap_get_lowest() and grub_mmap_get_highest()
commands/i386/tpm: Add TPM TIS and CRB driver

Fedora Ninjas (1):
slaunch: Add Secure Launch framework and commands

Michał Żygowski (2):
i386/txt: Initialize TPM 1.2 event log in TXT heap
multiboot2: Support TXT Secure Launch

Ross Philipson (11):
i386: Add CRx, MMIO, MSR and extend CPUID definitions
efi/tpm: Replace tpm command
slaunch: Add Secure Launch Resource Table (SLRT) header file
slaunch: Add main Secure Launch definitions header
slaunch: Add SLR table setup support module
i386/txt: Add Intel TXT definitions header file
slaunch/txt: Add Intel TXT core implementation
slaunch/txt: Add Intel TXT ACM module support
slaunch/txt: Add Intel TXT verification routines
i386/efi: Add DL stub as common DL event module
efi: Add Secure Launch support for efi/linux boot through EFI stub

Sergii Dmytruk (2):
multiboot: Make GRUB_MULTIBOOT(make_mbi) return MBI's size
slaunch: Introduce a hook for filling SLRT policy

docs/grub.texi | 32 +-
grub-core/Makefile.am | 6 +
grub-core/Makefile.core.def | 23 +-
grub-core/commands/efi/tpm.c | 2 +-
grub-core/commands/i386/tpm.c | 151 +++
grub-core/commands/{tpm.c => tpm_verifier.c} | 57 +-
grub-core/lib/i386/relocator32.S | 8 +
grub-core/loader/efi/dltrampoline.S | 94 ++
grub-core/loader/efi/linux.c | 16 +
grub-core/loader/i386/bsd.c | 3 +
grub-core/loader/i386/linux.c | 87 +-
grub-core/loader/i386/multiboot_mbi.c | 4 +-
grub-core/loader/i386/xnu.c | 2 +
grub-core/loader/multiboot.c | 16 +-
grub-core/loader/multiboot_elfxx.c | 90 +-
grub-core/loader/multiboot_mbi2.c | 138 ++-
grub-core/loader/slaunch/acmod.c | 575 ++++++++++
grub-core/loader/slaunch/dlstub.c | 93 ++
grub-core/loader/slaunch/i386_linux.c | 220 ++++
grub-core/loader/slaunch/slaunch.c | 204 ++++
grub-core/loader/slaunch/slrt.c | 320 ++++++
grub-core/loader/slaunch/txt.c | 1001 ++++++++++++++++++
grub-core/loader/slaunch/verify.c | 297 ++++++
grub-core/loader/slaunch/x86_efi_linux.c | 212 ++++
grub-core/mmap/mmap.c | 83 ++
include/grub/file.h | 3 +
include/grub/i386/cpuid.h | 13 +
include/grub/i386/crfr.h | 190 ++++
include/grub/i386/linux.h | 19 +-
include/grub/i386/memory.h | 5 +
include/grub/i386/mmio.h | 74 ++
include/grub/i386/msr.h | 61 ++
include/grub/i386/tpm.h | 35 +
include/grub/i386/txt.h | 708 +++++++++++++
include/grub/memory.h | 3 +
include/grub/multiboot.h | 2 +-
include/grub/multiboot2.h | 6 +-
include/grub/slaunch.h | 129 +++
include/grub/slr_table.h | 298 ++++++
include/grub/tpm.h | 2 +
40 files changed, 5217 insertions(+), 65 deletions(-)
create mode 100644 grub-core/commands/i386/tpm.c
rename grub-core/commands/{tpm.c => tpm_verifier.c} (60%)
create mode 100644 grub-core/loader/efi/dltrampoline.S
create mode 100644 grub-core/loader/slaunch/acmod.c
create mode 100644 grub-core/loader/slaunch/dlstub.c
create mode 100644 grub-core/loader/slaunch/i386_linux.c
create mode 100644 grub-core/loader/slaunch/slaunch.c
create mode 100644 grub-core/loader/slaunch/slrt.c
create mode 100644 grub-core/loader/slaunch/txt.c
create mode 100644 grub-core/loader/slaunch/verify.c
create mode 100644 grub-core/loader/slaunch/x86_efi_linux.c
create mode 100644 include/grub/i386/crfr.h
create mode 100644 include/grub/i386/mmio.h
create mode 100644 include/grub/i386/tpm.h
create mode 100644 include/grub/i386/txt.h
create mode 100644 include/grub/slaunch.h
create mode 100644 include/grub/slr_table.h


base-commit: 3b8b9e330a3ef211c334a6a6f53ece883d94f8be
prerequisite-patch-id: 450e6ee179d407f3718821303500f65cb955b5db
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:41:55 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Daniel Kiper <daniel...@oracle.com>

The functions find the lowest and highest values with regard to the
passed in limit. Passing a low limit of 0 or a high limit of ~0
calculates lowest and highest available RAM addresses respectively.

Signed-off-by: Daniel Kiper <daniel...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
Reviewed-by: Ross Philipson <ross.ph...@oracle.com>
---
grub-core/mmap/mmap.c | 83 +++++++++++++++++++++++++++++++++++++++++++
include/grub/memory.h | 3 ++
2 files changed, 86 insertions(+)

diff --git a/grub-core/mmap/mmap.c b/grub-core/mmap/mmap.c
index c8c8312c5..80d6c60b8 100644
--- a/grub-core/mmap/mmap.c
+++ b/grub-core/mmap/mmap.c
@@ -26,6 +26,7 @@
#include <grub/command.h>
#include <grub/dl.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>

GRUB_MOD_LICENSE ("GPLv3+");

@@ -343,6 +344,88 @@ grub_mmap_unregister (int handle)

#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */

+typedef struct
+{
+ grub_uint64_t addr;
+ grub_uint64_t limit;
+} addr_limit_t;
+
+/* Helper for grub_mmap_get_lowest(). */
+static int
+lowest_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
+ void *data)
+{
+ addr_limit_t *al = data;
+ grub_uint64_t end;
+
+ if (type != GRUB_MEMORY_AVAILABLE)
+ return 0;
+
+ if (grub_add (addr, size, &end))
+ return 0;
+
+ if (addr >= al->limit)
+ al->addr = grub_min (al->addr, addr);
+
+ if ((addr < al->limit) && (end > al->limit))
+ al->addr = al->limit;
+
+ return 0;
+}
+
+/*
+ * This function calculates lowest available RAM address that is at or above
+ * the passed limit. If no RAM exists above the limit, ~0 is returned.
+ */
+grub_uint64_t
+grub_mmap_get_lowest (grub_uint64_t limit)
+{
+ addr_limit_t al = {~0, limit};
+
+ grub_mmap_iterate (lowest_hook, &al);
+
+ return al.addr;
+}
+
+/* Helper for grub_mmap_get_highest(). */
+static int
+highest_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
+ void *data)
+{
+ addr_limit_t *al = data;
+ grub_uint64_t end;
+
+ if (type != GRUB_MEMORY_AVAILABLE)
+ return 0;
+
+ if (grub_add (addr, size, &end))
+ return 0;
+
+ if (end < al->limit)
+ al->addr = grub_max (al->addr, end);
+
+ if ((addr < al->limit) && (end >= al->limit))
+ al->addr = al->limit;
+
+ return 0;
+}
+
+/*
+ * This function calculates highest available RAM address that is below the
+ * passed limit. Returned address is either one byte after last byte of RAM or
+ * equal to limit, whichever is lower. If no RAM exists below limit, 0 is
+ * returned.
+ */
+grub_uint64_t
+grub_mmap_get_highest (grub_uint64_t limit)
+{
+ addr_limit_t al = {0, limit};
+
+ grub_mmap_iterate (highest_hook, &al);
+
+ return al.addr;
+}
+
#define CHUNK_SIZE 0x400

struct badram_entry {
diff --git a/include/grub/memory.h b/include/grub/memory.h
index 6da114a1b..8f22f7525 100644
--- a/include/grub/memory.h
+++ b/include/grub/memory.h
@@ -69,6 +69,9 @@ void *grub_mmap_malign_and_register (grub_uint64_t align, grub_uint64_t size,

void grub_mmap_free_and_unregister (int handle);

+extern grub_uint64_t grub_mmap_get_lowest (grub_uint64_t limit);
+extern grub_uint64_t grub_mmap_get_highest (grub_uint64_t limit);
+
#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE

struct grub_mmap_region
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:41:58 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

The definitions are going to be used by new Secure Launch feature and a
TPM driver.

Control registers and flags:
- CR0 read/write and flags (PE, MP, EM, TS, PG, NE, WP, AM, NW, CD)
- CR4 read/write and flags (VME, PVI, TSD, DE, PSE, PAE, MCE, PGE, PCE,
FXSR, XMM, VMXE, SMXE, PCIDE)
- EFLAGS read/write and flags (CF, PF, AF, ZF, SF, TF, IF, DF, OF,
IOPL, NT, RF, VM, AC, VIF, VIP, ID)

MMIO:
- read/write 8bit values
- read/write 32bit values
- read/write 64bit values

MSRs:
- platform ID
- APIC base
- feature control
- MTRR (capability, bases, masks, types)
- MCG (global machine check; capability, status)
- MISC_ENABLE
- MC0 (machine check error reporting status)
- EFER (LME, LMA, SVEM (AMD-V))
- AMD: SVM control

CPUID:
- flags for availability of vendor, features
- Intel: VMX, SMX
- AMD: SVM

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Daniel Kiper <daniel...@oracle.com>
Signed-off-by: Krystian Hebel <krystia...@3mdeb.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
Reviewed-by: Alec Brown <alec.r...@oracle.com>
---
include/grub/i386/cpuid.h | 13 +++
include/grub/i386/crfr.h | 190 ++++++++++++++++++++++++++++++++++++++
include/grub/i386/mmio.h | 74 +++++++++++++++
include/grub/i386/msr.h | 61 ++++++++++++
4 files changed, 338 insertions(+)
create mode 100644 include/grub/i386/crfr.h
create mode 100644 include/grub/i386/mmio.h

diff --git a/include/grub/i386/cpuid.h b/include/grub/i386/cpuid.h
index f7ae4b0a4..e1c45dfc2 100644
--- a/include/grub/i386/cpuid.h
+++ b/include/grub/i386/cpuid.h
@@ -19,6 +19,19 @@
#ifndef GRUB_CPU_CPUID_HEADER
#define GRUB_CPU_CPUID_HEADER 1

+/* General */
+#define GRUB_X86_CPUID_VENDOR 0x00000000
+#define GRUB_X86_CPUID_FEATURES 0x00000001
+
+/* Intel */
+#define GRUB_VMX_CPUID_FEATURE (1<<5)
+#define GRUB_SMX_CPUID_FEATURE (1<<6)
+
+/* AMD */
+#define GRUB_AMD_CPUID_FEATURES 0x80000001
+#define GRUB_SVM_CPUID_FEATURE (1<<2)
+#define GRUB_AMD_CPUID_FUNC 0x8000000a
+
extern unsigned char grub_cpuid_has_longmode;
extern unsigned char grub_cpuid_has_pae;

diff --git a/include/grub/i386/crfr.h b/include/grub/i386/crfr.h
new file mode 100644
index 000000000..8e0725b7a
--- /dev/null
+++ b/include/grub/i386/crfr.h
@@ -0,0 +1,190 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_CRFR_H
+#define GRUB_CRFR_H 1
+
+/* Routines for R/W of control and flags registers */
+
+#define GRUB_CR0_X86_PE 0x00000001 /* Enable Protected Mode */
+#define GRUB_CR0_X86_MP 0x00000002 /* "Math" (FPU) Present */
+#define GRUB_CR0_X86_EM 0x00000004 /* EMulate FPU */
+#define GRUB_CR0_X86_TS 0x00000008 /* Task Switched */
+#define GRUB_CR0_X86_PG 0x80000000 /* Enable PaGing */
+
+#define GRUB_CR0_X86_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */
+#define GRUB_CR0_X86_WP 0x00010000 /* Write Protect */
+#define GRUB_CR0_X86_AM 0x00040000 /* Alignment Mask */
+#define GRUB_CR0_X86_NW 0x20000000 /* Not Write-through */
+#define GRUB_CR0_X86_CD 0x40000000 /* Cache Disable */
+
+#define GRUB_CR4_X86_VME 0x00000001 /* Virtual 8086 mode extensions */
+#define GRUB_CR4_X86_PVI 0x00000002 /* Protected-mode virtual interrupts */
+#define GRUB_CR4_X86_TSD 0x00000004 /* Time stamp disable */
+#define GRUB_CR4_X86_DE 0x00000008 /* Debugging extensions */
+#define GRUB_CR4_X86_PSE 0x00000010 /* Page size extensions */
+#define GRUB_CR4_X86_PAE 0x00000020 /* Physical address extension */
+#define GRUB_CR4_X86_MCE 0x00000040 /* Enable Machine check enable */
+#define GRUB_CR4_X86_PGE 0x00000080 /* Enable Page global */
+#define GRUB_CR4_X86_PCE 0x00000100 /* Enable Performance monitoring counter */
+#define GRUB_CR4_X86_FXSR 0x00000200 /* Fast FPU save/restore */
+#define GRUB_CR4_X86_XMM 0x00000400 /* Enable SIMD/MMX2 to use except 16 */
+#define GRUB_CR4_X86_VMXE 0x00002000 /* Enable VMX */
+#define GRUB_CR4_X86_SMXE 0x00004000 /* Enable SMX */
+#define GRUB_CR4_X86_PCIDE 0x00020000 /* Enable PCID */
+
+#define GRUB_EFLAGS_X86_CF 0x00000001 /* Carry Flag */
+#define GRUB_EFLAGS_X86_PF 0x00000004 /* Parity Flag */
+#define GRUB_EFLAGS_X86_AF 0x00000010 /* Auxillary carry Flag */
+#define GRUB_EFLAGS_X86_ZF 0x00000040 /* Zero Flag */
+#define GRUB_EFLAGS_X86_SF 0x00000080 /* Sign Flag */
+#define GRUB_EFLAGS_X86_TF 0x00000100 /* Trap Flag */
+#define GRUB_EFLAGS_X86_IF 0x00000200 /* Interrupt Flag */
+#define GRUB_EFLAGS_X86_DF 0x00000400 /* Direction Flag */
+#define GRUB_EFLAGS_X86_OF 0x00000800 /* Overflow Flag */
+#define GRUB_EFLAGS_X86_IOPL 0x00003000 /* IOPL mask */
+#define GRUB_EFLAGS_X86_NT 0x00004000 /* Nested Task */
+#define GRUB_EFLAGS_X86_RF 0x00010000 /* Resume Flag */
+#define GRUB_EFLAGS_X86_VM 0x00020000 /* Virtual Mode */
+#define GRUB_EFLAGS_X86_AC 0x00040000 /* Alignment Check */
+#define GRUB_EFLAGS_X86_VIF 0x00080000 /* Virtual Interrupt Flag */
+#define GRUB_EFLAGS_X86_VIP 0x00100000 /* Virtual Interrupt Pending */
+#define GRUB_EFLAGS_X86_ID 0x00200000 /* CPUID detection flag */
+
+#ifndef ASM_FILE
+
+#include <grub/types.h>
+
+static inline unsigned long
+grub_read_cr4 (void)
+{
+ unsigned long val;
+
+ asm volatile ("mov %%cr4, %0" : "=r" (val) : : "memory");
+
+ return val;
+}
+
+static inline void
+grub_write_cr4 (unsigned long val)
+{
+ asm volatile ("mov %0, %%cr4" : : "r" (val) : "memory");
+}
+
+#define GRUB_CR0 0
+#define GRUB_CR1 1
+#define GRUB_CR2 2
+#define GRUB_CR3 3
+#define GRUB_CR4 4
+
+#ifdef __x86_64__
+#define read_cr(r, d) asm volatile ("movq %%cr" r ", %0" : "=r" (d))
+#else
+#define read_cr(r, d) asm volatile ("movl %%cr" r ", %0" : "=r" (d))
+#endif
+
+static inline unsigned long
+grub_read_control_register(grub_uint8_t reg)
+{
+ unsigned long data;
+
+ switch (reg)
+ {
+ case GRUB_CR0:
+ read_cr("0", data);
+ break;
+ case GRUB_CR1:
+ read_cr("1", data);
+ break;
+ case GRUB_CR2:
+ read_cr("2", data);
+ break;
+ case GRUB_CR3:
+ read_cr("3", data);
+ break;
+ case GRUB_CR4:
+ read_cr("4", data);
+ break;
+ default:
+ /* TODO: Loudly complain if this is called. Even some kind of BUG() */
+ data = ~0UL;
+ break;
+ }
+
+ return data;
+}
+
+#ifdef __x86_64__
+#define write_cr(r, d) asm volatile ("movq %0, %%cr" r : : "r" (d))
+#else
+#define write_cr(r, d) asm volatile ("movl %0, %%cr" r : : "r" (d))
+#endif
+
+static inline void
+grub_write_control_register(grub_uint8_t reg, unsigned long data)
+{
+ switch (reg)
+ {
+ case GRUB_CR0:
+ write_cr("0", data);
+ break;
+ case GRUB_CR1:
+ write_cr("1", data);
+ break;
+ case GRUB_CR2:
+ write_cr("2", data);
+ break;
+ case GRUB_CR3:
+ write_cr("3", data);
+ break;
+ case GRUB_CR4:
+ write_cr("4", data);
+ break;
+ default:
+ /* TODO: Loudly complain if this is called. Even some kind of BUG() */
+ ;
+ }
+}
+
+static inline unsigned long
+grub_read_flags_register(void)
+{
+ unsigned long flags;
+
+#ifdef __x86_64__
+ asm volatile ("pushfq; popq %0" : "=r" (flags));
+#else
+ asm volatile ("pushfl; popl %0" : "=r" (flags));
+#endif
+
+ return flags;
+}
+
+static inline void
+grub_write_flags_register (unsigned long flags)
+{
+#ifdef __x86_64__
+ asm volatile ("pushq %0; popfq" : : "r" (flags));
+#else
+ asm volatile ("pushl %0; popfl" : : "r" (flags));
+#endif
+}
+
+#endif /* ASM_FILE */
+
+#endif /* GRUB_CRFR_H */
diff --git a/include/grub/i386/mmio.h b/include/grub/i386/mmio.h
new file mode 100644
index 000000000..2b9eb1212
--- /dev/null
+++ b/include/grub/i386/mmio.h
@@ -0,0 +1,74 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_I386_MMIO_H
+#define GRUB_I386_MMIO_H 1
+
+#include <grub/types.h>
+
+#define grub_mb() asm volatile ("mfence" : : : "memory")
+
+static inline grub_uint8_t
+grub_read8 (const grub_addr_t addr)
+{
+ grub_uint8_t val;
+
+ val = (*(volatile grub_uint8_t *) (addr));
+
+ return val;
+}
+
+static inline grub_uint32_t
+grub_read32 (const grub_addr_t addr)
+{
+ grub_uint32_t val;
+
+ val = (*(volatile grub_uint32_t *) (addr));
+
+ return val;
+}
+
+static inline grub_uint64_t
+grub_read64 (const grub_addr_t addr)
+{
+ grub_uint64_t val;
+
+ val = (*(volatile grub_uint64_t *) (addr));
+
+ return val;
+}
+
+static inline void
+grub_write8 (grub_uint8_t val, grub_addr_t addr)
+{
+ (*(volatile grub_uint8_t *) (addr)) = val;
+}
+
+static inline void
+grub_write32 (grub_uint32_t val, grub_addr_t addr)
+{
+ (*(volatile grub_uint32_t *) (addr)) = val;
+}
+
+static inline void
+grub_write64 (grub_uint64_t val, grub_addr_t addr)
+{
+ (*(volatile grub_uint64_t *) (addr)) = val;
+}
+
+#endif /* GRUB_I386_MMIO_H */
diff --git a/include/grub/i386/msr.h b/include/grub/i386/msr.h
index 1e838c022..9f29c6eb2 100644
--- a/include/grub/i386/msr.h
+++ b/include/grub/i386/msr.h
@@ -2,6 +2,9 @@
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2019 Free Software Foundation, Inc.
*
+ * Some definitions in this header are extracted from the Trusted Computing
+ * Group's "TPM Main Specification", Parts 1-3.
+ *
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@@ -19,6 +22,62 @@
#ifndef GRUB_I386_MSR_H
#define GRUB_I386_MSR_H 1

+/* General */
+#define GRUB_MSR_X86_PLATFORM_ID 0x00000017
+
+#define GRUB_MSR_X86_APICBASE 0x0000001b
+#define GRUB_MSR_X86_APICBASE_BSP (1<<8)
+#define GRUB_MSR_X86_APICBASE_ENABLE (1<<11)
+#define GRUB_MSR_X86_APICBASE_BASE (0xfffff<<12) /* Mask for APIC base address */
+
+#define GRUB_MSR_X86_FEATURE_CONTROL 0x0000003a
+#define GRUB_MSR_X86_ENABLE_VMX_IN_SMX (1<<1) /* Enable VMX inside SMX */
+#define GRUB_MSR_X86_SENTER_FUNCTIONS (0x7f<<8) /* Bitmap of SENTER function enables */
+#define GRUB_MSR_X86_SENTER_ENABLE (1<<15) /* SENTER global enable */
+
+#define GRUB_MSR_X86_MTRRCAP 0x000000fe
+#define GRUB_MSR_X86_VCNT_MASK 0xff /* Number of variable MTRRs */
+
+#define GRUB_MSR_X86_MCG_CAP 0x00000179
+#define GRUB_MSR_MCG_BANKCNT_MASK 0xff /* Number of banks */
+#define GRUB_MSR_X86_MCG_STATUS 0x0000017a
+#define GRUB_MSR_MCG_STATUS_MCIP (1ULL<<2) /* MC in progress */
+
+#define GRUB_MSR_X86_MISC_ENABLE 0x000001a0
+#define GRUB_MSR_X86_ENABLE_MONITOR_FSM (1<<18)
+
+#define GRUB_MSR_X86_MTRR_PHYSBASE0 0x00000200
+#define GRUB_MSR_X86_MTRR_PHYSMASK0 0x00000201
+#define GRUB_MSR_X86_BASE_DEF_TYPE_MASK 0xff
+#define GRUB_MSR_X86_MASK_VALID (1<<11)
+
+#define GRUB_MSR_X86_MTRR_DEF_TYPE 0x000002ff
+#define GRUB_MSR_X86_DEF_TYPE_MASK 0xff
+#define GRUB_MSR_X86_MTRR_ENABLE_FIXED (1<<10)
+#define GRUB_MSR_X86_MTRR_ENABLE (1<<11)
+
+#define GRUB_MSR_X86_MC0_STATUS 0x00000401
+
+#define GRUB_MSR_X86_EFER 0xc0000080 /* Extended features */
+#define GRUB_MSR_EFER_LME (1<<8) /* Enable Long Mode/IA-32e */
+#define GRUB_MSR_EFER_LMA (1<<10) /* Long Mode/IA-32e Active */
+#define GRUB_MSR_EFER_SVME (1<<12) /* Enable SVM (AMD-V) */
+
+/* AMD Specific */
+#define GRUB_MSR_AMD64_PATCH_LEVEL 0x0000008b
+#define GRUB_MSR_AMD64_PATCH_CLEAR 0xc0010021 /* AMD-specific microcode patch clear */
+#define GRUB_MSR_AMD64_VM_CR 0xc0010114 /* SVM control register */
+#define GRUB_MSR_SVM_VM_CR_SVM_DISABLE (1<<4) /* Disable writes to EFER.SVME */
+
+/* MTRR Specific */
+#define GRUB_MTRR_MEMORY_TYPE_UC 0
+#define GRUB_MTRR_MEMORY_TYPE_WC 1
+#define GRUB_MTRR_MEMORY_TYPE_WT 4
+#define GRUB_MTRR_MEMORY_TYPE_WP 5
+#define GRUB_MTRR_MEMORY_TYPE_WB 6
+
+#ifndef ASM_FILE
+
#include <grub/err.h>
#include <grub/i386/cpuid.h>
#include <grub/types.h>
@@ -71,4 +130,6 @@ grub_wrmsr (grub_uint32_t msr_id, grub_uint64_t msr_value)
asm volatile ("wrmsr" : : "c" (msr_id), "a" (low), "d" (high));
}

+#endif /* ASM_FILE */
+
#endif /* GRUB_I386_MSR_H */
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:02 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Replace UEFI tpm measuring command with TPM logging function, allowing the
removal of the tpm command file.

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/Makefile.core.def | 1 -
grub-core/commands/efi/tpm.c | 2 +-
grub-core/commands/tpm.c | 125 -----------------------------------
include/grub/tpm.h | 2 +
4 files changed, 3 insertions(+), 127 deletions(-)
delete mode 100644 grub-core/commands/tpm.c

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index f70e02e69..adadd1365 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1153,7 +1153,6 @@ module = {

module = {
name = tpm;
- common = commands/tpm.c;
ieee1275 = commands/ieee1275/ibmvtpm.c;
enable = powerpc_ieee1275;
};
diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c
index cbac69866..ca7d9bf5d 100644
--- a/grub-core/commands/efi/tpm.c
+++ b/grub-core/commands/efi/tpm.c
@@ -267,7 +267,7 @@ grub_cc_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
}

grub_err_t
-grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
+grub_tpm_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
const char *description)
{
grub_efi_handle_t tpm_handle;
diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c
deleted file mode 100644
index dde74ab83..000000000
--- a/grub-core/commands/tpm.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2018 Free Software Foundation, Inc.
- *
- * GRUB is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GRUB is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
- *
- * Core TPM support code.
- */
-
-#include <grub/err.h>
-#include <grub/i18n.h>
-#include <grub/misc.h>
-#include <grub/mm.h>
-#include <grub/tpm.h>
-#include <grub/term.h>
-#include <grub/verify.h>
-#include <grub/dl.h>
-
-GRUB_MOD_LICENSE ("GPLv3+");
-
-static grub_err_t
-grub_tpm_verify_init (grub_file_t io,
- enum grub_file_type type __attribute__ ((unused)),
- void **context, enum grub_verify_flags *flags)
-{
- *context = io->name;
- *flags |= GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
-
- /*
- * The loopback image is mapped as a disk allowing it to function like
- * a block device. However, we measure files read from the block device
- * not the device itself. For example, we don't measure block devices like
- * hd0 disk directly. This process is crucial to prevent out-of-memory
- * errors as loopback images are inherently large.
- */
- if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_LOOPBACK)
- *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_tpm_verify_write (void *context, void *buf, grub_size_t size)
-{
- grub_err_t status = grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context);
-
- if (status == GRUB_ERR_NONE)
- return GRUB_ERR_NONE;
-
- grub_dprintf ("tpm", "Measuring buffer failed: %d\n", status);
- return grub_is_tpm_fail_fatal () ? status : GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_tpm_verify_string (char *str, enum grub_verify_string_type type)
-{
- const char *prefix = NULL;
- char *description;
- grub_err_t status;
-
- switch (type)
- {
- case GRUB_VERIFY_KERNEL_CMDLINE:
- prefix = "kernel_cmdline: ";
- break;
- case GRUB_VERIFY_MODULE_CMDLINE:
- prefix = "module_cmdline: ";
- break;
- case GRUB_VERIFY_COMMAND:
- prefix = "grub_cmd: ";
- break;
- }
- description = grub_malloc (grub_strlen (str) + grub_strlen (prefix) + 1);
- if (!description)
- return grub_errno;
- grub_memcpy (description, prefix, grub_strlen (prefix));
- grub_memcpy (description + grub_strlen (prefix), str,
- grub_strlen (str) + 1);
- status =
- grub_tpm_measure ((unsigned char *) str, grub_strlen (str),
- GRUB_STRING_PCR, description);
- grub_free (description);
- if (status == GRUB_ERR_NONE)
- return GRUB_ERR_NONE;
-
- grub_dprintf ("tpm", "Measuring string %s failed: %d\n", str, status);
- return grub_is_tpm_fail_fatal () ? status : GRUB_ERR_NONE;
-}
-
-struct grub_file_verifier grub_tpm_verifier = {
- .name = "tpm",
- .init = grub_tpm_verify_init,
- .write = grub_tpm_verify_write,
- .verify_string = grub_tpm_verify_string,
-};
-
-GRUB_MOD_INIT (tpm)
-{
- /*
- * Even though this now calls ibmvtpm's grub_tpm_present() from GRUB_MOD_INIT(),
- * it does seem to call it late enough in the initialization sequence so
- * that whatever discovered "device nodes" before this GRUB_MOD_INIT() is
- * called, enables the ibmvtpm driver to see the device nodes.
- */
- if (!grub_tpm_present())
- return;
- grub_verifier_register (&grub_tpm_verifier);
-}
-
-GRUB_MOD_FINI (tpm)
-{
- if (!grub_tpm_present())
- return;
- grub_verifier_unregister (&grub_tpm_verifier);
-}
diff --git a/include/grub/tpm.h b/include/grub/tpm.h
index d09783dac..c9dfbfb21 100644
--- a/include/grub/tpm.h
+++ b/include/grub/tpm.h
@@ -38,6 +38,8 @@

grub_err_t grub_tpm_measure (unsigned char *buf, grub_size_t size,
grub_uint8_t pcr, const char *description);
+grub_err_t grub_tpm_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
+ const char *description);
int grub_tpm_present (void);

static inline bool
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:05 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Aleksandr Burmashev <alexander...@oracle.com>

This avoids naming collision with TPM TIS and CRB driver introduced
by subsequent patch and characterizes the functionality of the module
better.

Signed-off-by: Daniel Kiper <daniel...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
docs/grub.texi | 21 +++---
grub-core/Makefile.core.def | 4 +-
grub-core/commands/tpm_verifier.c | 102 ++++++++++++++++++++++++++++++
3 files changed, 115 insertions(+), 12 deletions(-)
create mode 100644 grub-core/commands/tpm_verifier.c

diff --git a/docs/grub.texi b/docs/grub.texi
index 200e747af..5355ca356 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4136,7 +4136,7 @@ Modules can be loaded via the @command{insmod} (@pxref{insmod}) command.
* tftp_module::
* tga_module::
* time_module::
-* tpm_module::
+* tpm_verifier_module::
* tr_module::
* trig_module::
* true_module::
@@ -5702,8 +5702,8 @@ image files in GRUB.
This module provides support for the @command{time} command to measure the
time taken by a given command and output it to the terminal.

-@node tpm_module
-@section tpm
+@node tpm_verifier_module
+@section tpm_verifier
This module provides support for interacting with a Trusted Platform Module
(TPM) with GRUB to perform Measured Boot. @xref{Measured Boot} for more
information.
@@ -8770,10 +8770,10 @@ grub-mkimage -O x86_64-efi -o grubx64.efi -p '(tftp)/grub' --sbat sbat.csv efine
@node Measured Boot
@section Measuring boot components

-If the tpm module is loaded and the platform has a Trusted Platform Module
-installed, GRUB will log each command executed and each file loaded into the
-TPM event log and extend the PCR values in the TPM correspondingly. All events
-will be logged into the PCR described below with a type of EV_IPL and an
+If the tpm_verifier module is loaded and the platform has a Trusted Platform
+Module installed, GRUB will log each command executed and each file loaded into
+the TPM event log and extend the PCR values in the TPM correspondingly. All
+events will be logged into the PCR described below with a type of EV_IPL and an
event description as described below.

@multitable @columnfractions 0.3 0.1 0.6
@@ -8798,9 +8798,10 @@ corresponding to the filename.

GRUB will not measure its own @file{core.img} - it is expected that firmware
will carry this out. GRUB will also not perform any measurements until the
-tpm module is loaded. As such it is recommended that the tpm module be built
-into @file{core.img} in order to avoid a potential gap in measurement between
-@file{core.img} being loaded and the tpm module being loaded.
+tpm_verifier module is loaded. As such it is recommended that the tpm_verifier
+module be built into @file{core.img} in order to avoid a potential gap in
+measurement between @file{core.img} being loaded and the tpm_verifier module
+being loaded.

Measured boot is currently only supported on EFI and IBM IEEE1275 PowerPC
platforms.
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index adadd1365..363b3ff12 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2560,8 +2560,8 @@ module = {
};

module = {
- name = tpm;
- common = commands/tpm.c;
+ name = tpm_verifier;
+ common = commands/tpm_verifier.c;
efi = commands/efi/tpm.c;
enable = efi;
};
diff --git a/grub-core/commands/tpm_verifier.c b/grub-core/commands/tpm_verifier.c
new file mode 100644
index 000000000..f72ce6730
--- /dev/null
+++ b/grub-core/commands/tpm_verifier.c
@@ -0,0 +1,102 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2018 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Core TPM support code.
+ */
+
+#include <grub/err.h>
+#include <grub/i18n.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/tpm.h>
+#include <grub/term.h>
+#include <grub/verify.h>
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+grub_err_t
+grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
+ const char *description)
+{
+ return grub_tpm_log_event (buf, size, pcr, description);
+}
+
+static grub_err_t
+grub_tpm_verify_init (grub_file_t io,
+ enum grub_file_type type __attribute__ ((unused)),
+ void **context, enum grub_verify_flags *flags)
+{
+ *context = io->name;
+ *flags |= GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm_verify_write (void *context, void *buf, grub_size_t size)
+{
+ grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm_verify_string (char *str, enum grub_verify_string_type type)
+{
+ const char *prefix = NULL;
+ char *description;
+
+ switch (type)
+ {
+ case GRUB_VERIFY_KERNEL_CMDLINE:
+ prefix = "kernel_cmdline: ";
+ break;
+ case GRUB_VERIFY_MODULE_CMDLINE:
+ prefix = "module_cmdline: ";
+ break;
+ case GRUB_VERIFY_COMMAND:
+ prefix = "grub_cmd: ";
+ break;
+ }
+ description = grub_malloc (grub_strlen (str) + grub_strlen (prefix) + 1);
+ if (!description)
+ return GRUB_ERR_NONE;
+ grub_memcpy (description, prefix, grub_strlen (prefix));
+ grub_memcpy (description + grub_strlen (prefix), str,
+ grub_strlen (str) + 1);
+
+ grub_tpm_measure ((unsigned char *) str, grub_strlen (str), GRUB_STRING_PCR,
+ description);
+ grub_free (description);
+ return GRUB_ERR_NONE;
+}
+
+struct grub_file_verifier grub_tpm_verifier = {
+ .name = "tpm_verifier",
+ .init = grub_tpm_verify_init,
+ .write = grub_tpm_verify_write,
+ .verify_string = grub_tpm_verify_string,
+};
+
+GRUB_MOD_INIT (tpm_verifier)
+{
+ grub_verifier_register (&grub_tpm_verifier);
+}
+
+GRUB_MOD_FINI (tpm_verifier)
+{
+ grub_verifier_unregister (&grub_tpm_verifier);
+}
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:09 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Daniel Kiper <daniel...@oracle.com>

It will be used by Intel TXT secure launcher introduced
by subsequent patches to query TPM version and relinquish a locality.

It also provides `tpm_type` command that prints TPM version and
interface.

Signed-off-by: Daniel Kiper <daniel...@oracle.com>
Signed-off-by: Krystian Hebel <krystia...@3mdeb.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
docs/grub.texi | 8 ++
grub-core/Makefile.core.def | 6 ++
grub-core/commands/i386/tpm.c | 151 ++++++++++++++++++++++++++++++++++
include/grub/i386/tpm.h | 35 ++++++++
4 files changed, 200 insertions(+)
create mode 100644 grub-core/commands/i386/tpm.c
create mode 100644 include/grub/i386/tpm.h

diff --git a/docs/grub.texi b/docs/grub.texi
index 5355ca356..c0984e585 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4136,6 +4136,7 @@ Modules can be loaded via the @command{insmod} (@pxref{insmod}) command.
* tftp_module::
* tga_module::
* time_module::
+* tpm_module::
* tpm_verifier_module::
* tr_module::
* trig_module::
@@ -5702,6 +5703,12 @@ image files in GRUB.
This module provides support for the @command{time} command to measure the
time taken by a given command and output it to the terminal.

+@node tpm_module
+@section tpm
+This module provides support for interacting with a Trusted Platform Module
+(TPM) on x86 systems through TIS and CRB. It also provides @command{tpm_type}
+command which shows TPM version and interface type.
+
@node tpm_verifier_module
@section tpm_verifier
This module provides support for interacting with a Trusted Platform Module
@@ -8427,6 +8434,7 @@ GRUB shell may provide more information on parameters and usage.
@item @command{testspeed} - Test file read speed.
@item @command{tgatest} - Tests loading of TGA bitmap.
@item @command{time} - Measure time used by COMMAND
+@item @command{tpm_type} - Show TPM version and interface type.
@item @command{tr} - Translate SET1 characters to SET2 in STRING.
@item @command{usb} - Test USB support.
@item @command{vbeinfo} - List available video modes. If resolution is given show only modes matching it.
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 363b3ff12..4bc2df614 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2559,6 +2559,12 @@ module = {
common = commands/testspeed.c;
};

+module = {
+ name = tpm;
+ x86 = commands/i386/tpm.c;
+ enable = x86;
+};
+
module = {
name = tpm_verifier;
common = commands/tpm_verifier.c;
diff --git a/grub-core/commands/i386/tpm.c b/grub-core/commands/i386/tpm.c
new file mode 100644
index 000000000..f19cd0bc1
--- /dev/null
+++ b/grub-core/commands/i386/tpm.c
@@ -0,0 +1,151 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (c) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * TPM TIS and CRB driver.
+ *
+ * Note: It is suggested to not use this driver together with UEFI TPM driver.
+ */
+
+#include <grub/command.h>
+#include <grub/dl.h>
+#include <grub/err.h>
+#include <grub/i386/memory.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/tpm.h>
+#include <grub/mm.h>
+#include <grub/types.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/*
+ * The code is based on TCG PC Client Platform TPM Profile Specification for
+ * TPM 2.0, Version 1.05 Revision 14 released September 4, 2020.
+ */
+
+#define TPM_MMIO_BASE 0xfed40000
+
+/* 6.3.2 Register Space Addresses */
+/* TIS registers. */
+#define TPM_ACCESS 0x0000
+#define TPM_INTF_CAPABILITY 0x0014
+#define INTF_CAP_INTERFACE_VERSION_SHIFT 28
+#define INTF_CAP_INTERFACE_VERSION_MASK 0x7
+#define TPM_INTERFACE_ID 0x0030
+#define INTERFACE_ID_INTERFACE_TYPE_SHIFT 0
+#define INTERFACE_ID_INTERFACE_TYPE_MASK 0xF
+
+/* CRB registers. */
+#define TPM_LOC_CTRL 0x0008
+
+
+#define TIS_RELINQUISH_LCL 0x20
+#define CRB_RELINQUISH_LCL 0x0002
+
+/* 6.4.2 Interface Identifier Register */
+#define TPM_CRB_INTF_ACTIVE 0x1
+
+/* 6.5.2.7 Interface Capability */
+#define TPM_12_TIS_INTF_12 0x0
+#define TPM_12_TIS_INTF_13 0x2
+#define TPM_20_TIS_INTF_13 0x3
+
+typedef enum
+ {
+ TPM_INTF_NONE = 0,
+ TPM_INTF_TIS,
+ TPM_INTF_CRB
+ }
+tpm_intf_t;
+
+static grub_tpm_ver_t tpm_ver = GRUB_TPM_NONE;
+static tpm_intf_t tpm_intf = TPM_INTF_NONE;
+
+grub_tpm_ver_t
+grub_get_tpm_ver (void)
+{
+ return tpm_ver;
+}
+
+/* Only localities 0-4 are supported. */
+void
+grub_tpm_relinquish_locality (grub_uint8_t lcl)
+{
+ grub_addr_t addr = TPM_MMIO_BASE + lcl * GRUB_PAGE_SIZE;
+
+ if (tpm_intf == TPM_INTF_TIS)
+ grub_write8 (TIS_RELINQUISH_LCL, addr + TPM_ACCESS);
+ else if (tpm_intf == TPM_INTF_CRB)
+ grub_write32 (CRB_RELINQUISH_LCL, addr + TPM_LOC_CTRL);
+}
+
+static grub_err_t
+grub_cmd_tpm_type (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ const char *tpm_ver_s = "NONE";
+ const char *tpm_intf_s = "NONE";
+
+ if (tpm_ver == GRUB_TPM_12)
+ tpm_ver_s = "1.2";
+ else if (tpm_ver == GRUB_TPM_20)
+ tpm_ver_s = "2.0";
+
+ if (tpm_intf == TPM_INTF_TIS)
+ tpm_intf_s = "TIS";
+ else if (tpm_intf == TPM_INTF_CRB)
+ tpm_intf_s = "CRB";
+
+ grub_printf ("TPM family: %s\nTPM interface: %s\n", tpm_ver_s, tpm_intf_s);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd_tpm_type;
+
+GRUB_MOD_INIT (tpm)
+{
+ grub_uint32_t intf_id;
+ grub_uint32_t intf_cap;
+
+ cmd_tpm_type = grub_register_command ("tpm_type", grub_cmd_tpm_type,
+ NULL, N_("Show TPM version and interface type."));
+
+ tpm_ver = GRUB_TPM_20;
+
+ intf_id = grub_read32 (TPM_MMIO_BASE + TPM_INTERFACE_ID);
+ intf_id >>= INTERFACE_ID_INTERFACE_TYPE_SHIFT;
+ intf_id &= INTERFACE_ID_INTERFACE_TYPE_MASK;
+
+ tpm_intf = (intf_id == TPM_CRB_INTF_ACTIVE) ? TPM_INTF_CRB : TPM_INTF_TIS;
+
+ /* CRB exists only in TPM 2.0 */
+ if (tpm_intf == TPM_INTF_CRB)
+ return;
+
+ intf_cap = grub_read32 (TPM_MMIO_BASE + TPM_INTF_CAPABILITY);
+ intf_cap >>= INTF_CAP_INTERFACE_VERSION_SHIFT;
+ intf_cap &= INTF_CAP_INTERFACE_VERSION_MASK;
+
+ if (intf_cap == TPM_12_TIS_INTF_12 || intf_cap == TPM_12_TIS_INTF_13)
+ tpm_ver = GRUB_TPM_12;
+}
+
+GRUB_MOD_FINI (tpm)
+{
+ grub_unregister_command (cmd_tpm_type);
+}
diff --git a/include/grub/i386/tpm.h b/include/grub/i386/tpm.h
new file mode 100644
index 000000000..64d93a96e
--- /dev/null
+++ b/include/grub/i386/tpm.h
@@ -0,0 +1,35 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (c) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_I386_TPM_H
+#define GRUB_I386_TPM_H 1
+
+#include <grub/types.h>
+
+typedef enum
+ {
+ GRUB_TPM_NONE = 0,
+ GRUB_TPM_12,
+ GRUB_TPM_20
+ }
+grub_tpm_ver_t;
+
+extern grub_tpm_ver_t grub_get_tpm_ver (void);
+extern void grub_tpm_relinquish_locality (grub_uint8_t lcl);
+
+#endif /* GRUB_I386_TPM_H */
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:12 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Introduce the Secure Launch Resource Table which forms the formal
interface between the pre and post launch code.

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/Makefile.am | 3 +
include/grub/slr_table.h | 296 +++++++++++++++++++++++++++++++++++++++
2 files changed, 299 insertions(+)
create mode 100644 include/grub/slr_table.h

diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index e50db8106..2a7be10ee 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -104,6 +104,7 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slr_table.h
endif

if COND_i386_xen_pvh
@@ -123,6 +124,7 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slr_table.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pmtimer.h
@@ -185,6 +187,7 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slr_table.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pmtimer.h
diff --git a/include/grub/slr_table.h b/include/grub/slr_table.h
new file mode 100644
index 000000000..9dff3d0d5
--- /dev/null
+++ b/include/grub/slr_table.h
@@ -0,0 +1,296 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Secure Launch Resource Table definitions
+ */
+
+#ifndef GRUB_SLR_TABLE_H
+#define GRUB_SLR_TABLE_H 1
+
+#define GRUB_UEFI_SLR_TABLE_GUID \
+ { 0x877a9b2a, 0x0385, 0x45d1, { 0xa0, 0x34, 0x9d, 0xac, 0x9c, 0x9e, 0x56, 0x5f }}
+
+/* SLR table header values */
+#define GRUB_SLR_TABLE_MAGIC 0x4452544d
+#define GRUB_SLR_TABLE_REVISION 1
+
+/* Current revisions for the policy and UEFI config */
+#define GRUB_SLR_POLICY_REVISION 1
+#define GRUB_SLR_UEFI_CONFIG_REVISION 1
+
+/* SLR defined architectures */
+#define GRUB_SLR_INTEL_TXT 1
+#define GRUB_SLR_AMD_SKINIT 2
+
+/* SLR defined bootloaders */
+#define GRUB_SLR_BOOTLOADER_INVALID 0
+#define GRUB_SLR_BOOTLOADER_GRUB 1
+
+/* Log formats */
+#define GRUB_SLR_DRTM_TPM12_LOG 1
+#define GRUB_SLR_DRTM_TPM20_LOG 2
+
+/* DRTM Policy Entry Flags */
+#define GRUB_SLR_POLICY_FLAG_MEASURED 0x1
+#define GRUB_SLR_POLICY_IMPLICIT_SIZE 0x2
+
+/* Array Lengths */
+#define GRUB_TPM_EVENT_INFO_LENGTH 32
+#define GRUB_TXT_VARIABLE_MTRRS_LENGTH 32
+
+/* Tags */
+#define GRUB_SLR_ENTRY_INVALID 0x0000
+#define GRUB_SLR_ENTRY_DL_INFO 0x0001
+#define GRUB_SLR_ENTRY_LOG_INFO 0x0002
+#define GRUB_SLR_ENTRY_ENTRY_POLICY 0x0003
+#define GRUB_SLR_ENTRY_INTEL_INFO 0x0004
+#define GRUB_SLR_ENTRY_AMD_INFO 0x0005
+#define GRUB_SLR_ENTRY_ARM_INFO 0x0006
+#define GRUB_SLR_ENTRY_UEFI_INFO 0x0007
+#define GRUB_SLR_ENTRY_UEFI_CONFIG 0x0008
+#define GRUB_SLR_ENTRY_END 0xffff
+
+/* Entity Types */
+#define GRUB_SLR_ET_UNSPECIFIED 0x0000
+#define GRUB_SLR_ET_SLRT 0x0001
+#define GRUB_SLR_ET_BOOT_PARAMS 0x0002
+#define GRUB_SLR_ET_SETUP_DATA 0x0003
+#define GRUB_SLR_ET_CMDLINE 0x0004
+#define GRUB_SLR_ET_UEFI_MEMMAP 0x0005
+#define GRUB_SLR_ET_RAMDISK 0x0006
+#define GRUB_SLR_ET_TXT_OS2MLE 0x0010
+#define GRUB_SLR_ET_UNUSED 0xffff
+
+/*
+ * Primary Secure Launch Resource Table Header
+ */
+struct grub_slr_table
+{
+ grub_uint32_t magic;
+ grub_uint16_t revision;
+ grub_uint16_t architecture;
+ grub_uint32_t size;
+ grub_uint32_t max_size;
+ /* table entries */
+} GRUB_PACKED;
+
+/*
+ * Common SLRT Table Header
+ */
+struct grub_slr_entry_hdr
+{
+ grub_uint32_t tag;
+ grub_uint32_t size;
+} GRUB_PACKED;
+
+/*
+ * Boot loader context
+ */
+struct grub_slr_bl_context
+{
+ grub_uint16_t bootloader;
+ grub_uint16_t reserved[3];
+ grub_uint64_t context;
+} GRUB_PACKED;
+
+/*
+ * Dynamic Launch Callback Function type
+ */
+typedef void (*grub_dl_handler_func)(struct grub_slr_bl_context *bl_context);
+
+/*
+ * DRTM Dynamic Launch Configuration
+ */
+struct grub_slr_entry_dl_info
+{
+ struct grub_slr_entry_hdr hdr;
+ grub_uint64_t dce_size;
+ grub_uint64_t dce_base;
+ grub_uint64_t dlme_size;
+ grub_uint64_t dlme_base;
+ grub_uint64_t dlme_entry;
+ struct grub_slr_bl_context bl_context;
+ grub_uint64_t dl_handler;
+} GRUB_PACKED;
+
+/*
+ * TPM Log Information
+ */
+struct grub_slr_entry_log_info
+{
+ struct grub_slr_entry_hdr hdr;
+ grub_uint16_t format;
+ grub_uint16_t reserved;
+ grub_uint32_t size;
+ grub_uint64_t addr;
+} GRUB_PACKED;
+
+/*
+ * DRTM Measurement Entry
+ */
+struct grub_slr_policy_entry
+{
+ grub_uint16_t pcr;
+ grub_uint16_t entity_type;
+ grub_uint16_t flags;
+ grub_uint16_t reserved;
+ grub_uint64_t size;
+ grub_uint64_t entity;
+ char evt_info[GRUB_TPM_EVENT_INFO_LENGTH];
+} GRUB_PACKED;
+
+/*
+ * DRTM Measurement Policy
+ */
+struct grub_slr_entry_policy
+{
+ struct grub_slr_entry_hdr hdr;
+ grub_uint16_t reserved[2];
+ grub_uint16_t revision;
+ grub_uint16_t nr_entries;
+ struct grub_slr_policy_entry policy_entries[];
+} GRUB_PACKED;
+
+/*
+ * Secure Launch defined MTRR saving structures
+ */
+struct grub_slr_txt_mtrr_pair
+{
+ grub_uint64_t mtrr_physbase;
+ grub_uint64_t mtrr_physmask;
+} GRUB_PACKED;
+
+struct grub_slr_txt_mtrr_state
+{
+ grub_uint64_t default_mem_type;
+ grub_uint64_t mtrr_vcnt;
+ struct grub_slr_txt_mtrr_pair mtrr_pair[GRUB_TXT_VARIABLE_MTRRS_LENGTH];
+} GRUB_PACKED;
+
+/*
+ * Intel TXT Info table
+ */
+struct grub_slr_entry_intel_info
+{
+ struct grub_slr_entry_hdr hdr;
+ grub_uint64_t txt_heap;
+ grub_uint64_t saved_misc_enable_msr;
+ struct grub_slr_txt_mtrr_state saved_bsp_mtrrs;
+} GRUB_PACKED;
+
+/*
+ * UEFI config measurement entry
+ */
+struct grub_slr_uefi_cfg_entry
+{
+ grub_uint16_t pcr;
+ grub_uint16_t reserved;
+ grub_uint32_t size;
+ grub_uint64_t cfg; /* address or value */
+ char evt_info[GRUB_TPM_EVENT_INFO_LENGTH];
+} GRUB_PACKED;
+
+/*
+ * UEFI config measurements
+ */
+struct grub_slr_entry_uefi_config
+{
+ struct grub_slr_entry_hdr hdr;
+ grub_uint16_t reserved[2];
+ grub_uint16_t revision;
+ grub_uint16_t nr_entries;
+ struct grub_slr_uefi_cfg_entry uefi_cfg_entries[];
+} GRUB_PACKED;
+
+static inline void *
+grub_slr_end_of_entries (struct grub_slr_table *table)
+{
+ return (void *)((grub_uint8_t *)table + table->size);
+}
+
+static inline void *
+grub_slr_next_entry (struct grub_slr_table *table,
+ struct grub_slr_entry_hdr *curr)
+{
+ struct grub_slr_entry_hdr *next = (struct grub_slr_entry_hdr *)
+ ((grub_uint8_t *)curr + curr->size);
+
+ if ((void *)next >= grub_slr_end_of_entries(table))
+ return NULL;
+ if (next->tag == GRUB_SLR_ENTRY_END)
+ return NULL;
+
+ return next;
+}
+
+static inline void *
+grub_slr_next_entry_by_tag (struct grub_slr_table *table,
+ struct grub_slr_entry_hdr *entry,
+ grub_uint16_t tag)
+{
+ if (!entry) /* Start from the beginning */
+ entry = (struct grub_slr_entry_hdr *)(((grub_uint8_t *)table) + sizeof(*table));
+
+ for ( ; ; )
+ {
+ if (entry->tag == tag)
+ return entry;
+
+ entry = grub_slr_next_entry (table, entry);
+ if (!entry)
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static inline int
+grub_slr_add_entry (struct grub_slr_table *table,
+ struct grub_slr_entry_hdr *entry)
+{
+ struct grub_slr_entry_hdr *end;
+
+ if ((table->size + entry->size) > table->max_size)
+ return -1;
+
+ grub_memcpy((grub_uint8_t *)table + table->size - sizeof(*end), entry, entry->size);
+ table->size += entry->size;
+
+ end = (struct grub_slr_entry_hdr *)((grub_uint8_t *)table + table->size - sizeof(*end));
+ end->tag = GRUB_SLR_ENTRY_END;
+ end->size = sizeof(*end);
+
+ return 0;
+}
+
+static inline void
+grub_slr_init_table(struct grub_slr_table *slrt, grub_uint16_t architecture,
+ grub_uint32_t max_size)
+{
+ struct grub_slr_entry_hdr *end;
+
+ slrt->magic = GRUB_SLR_TABLE_MAGIC;
+ slrt->revision = GRUB_SLR_TABLE_REVISION;
+ slrt->architecture = architecture;
+ slrt->size = sizeof(*slrt) + sizeof(*end);
+ slrt->max_size = max_size;
+ end = (struct grub_slr_entry_hdr *)((grub_uint8_t *)slrt + sizeof(*slrt));
+ end->tag = GRUB_SLR_ENTRY_END;
+ end->size = sizeof(*end);
+}
+
+#endif /* GRUB_SLR_TABLE_H */
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:14 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/Makefile.am | 3 ++
include/grub/slaunch.h | 96 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+)
create mode 100644 include/grub/slaunch.h

diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index 2a7be10ee..9a6daf22c 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -105,6 +105,7 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slr_table.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slaunch.h
endif

if COND_i386_xen_pvh
@@ -125,6 +126,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slr_table.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slaunch.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pmtimer.h
@@ -188,6 +190,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slr_table.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slaunch.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pmtimer.h
diff --git a/include/grub/slaunch.h b/include/grub/slaunch.h
new file mode 100644
index 000000000..ba6516981
--- /dev/null
+++ b/include/grub/slaunch.h
@@ -0,0 +1,96 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Main secure launch definitions header file.
+ */
+
+#ifndef GRUB_I386_SLAUNCH_H
+#define GRUB_I386_SLAUNCH_H 1
+
+/* Secure launch platform types. */
+#define SLP_NONE 0
+#define SLP_INTEL_TXT 1
+
+#define GRUB_SLAUNCH_TPM_EVT_LOG_SIZE (8 * GRUB_PAGE_SIZE)
+
+#ifndef ASM_FILE
+
+#define GRUB_SL_BOOT_TYPE_INVALID 0
+#define GRUB_SL_BOOT_TYPE_LINUX 1
+#define GRUB_SL_BOOT_TYPE_EFI 2
+
+struct linux_kernel_params;
+struct linux_i386_kernel_header;
+struct grub_relocator;
+struct grub_slr_entry_hdr;
+struct grub_slr_policy_entry;
+
+struct grub_slaunch_params
+{
+ grub_uint32_t boot_type;
+ grub_uint32_t platform_type;
+ struct linux_kernel_params *boot_params;
+ grub_uint64_t boot_params_base;
+ struct grub_relocator *relocator;
+ grub_uint64_t slr_table_base;
+ grub_uint32_t slr_table_size;
+ void *slr_table_mem;
+ void *mle_mem;
+ grub_uint32_t mle_start;
+ grub_uint32_t mle_size;
+ grub_uint64_t mle_ptab_target;
+ grub_uint32_t mle_ptab_size;
+ void *mle_ptab_mem;
+ grub_uint32_t mle_header_offset;
+ grub_uint32_t ap_wake_block;
+ grub_uint32_t ap_wake_block_size;
+ grub_uint64_t dce_base;
+ grub_uint32_t dce_size;
+ grub_uint64_t tpm_evt_log_base;
+ grub_uint32_t tpm_evt_log_size;
+};
+
+struct grub_efi_info
+{
+ grub_uint32_t efi_signature;
+ grub_uint32_t efi_system_table;
+ grub_uint32_t efi_mem_desc_size;
+ grub_uint32_t efi_mem_desc_version;
+ grub_uint32_t efi_mmap;
+ grub_uint32_t efi_mmap_size;
+ grub_uint32_t efi_system_table_hi;
+ grub_uint32_t efi_mmap_hi;
+};
+
+extern grub_uint32_t grub_slaunch_platform_type (void);
+extern void *grub_slaunch_module (void);
+
+void dl_entry(grub_uint64_t dl_ctx);
+
+/* SLRT setup functions */
+void grub_init_slrt_storage (void);
+grub_err_t grub_setup_slrt_policy (struct grub_slaunch_params *slparams,
+ struct grub_slr_policy_entry *platform_entry);
+void grub_setup_slrt_dl_info (struct grub_slaunch_params *slparams);
+void grub_setup_slrt_log_info (struct grub_slaunch_params *slparams);
+void grub_setup_slr_table (struct grub_slaunch_params *slparams,
+ struct grub_slr_entry_hdr *platform_info);
+void grub_update_slrt_policy (struct grub_slaunch_params *slparams);
+
+#endif /* ASM_FILE */
+
+#endif /* GRUB_I386_SLAUNCH_H */
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:19 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/slaunch/slrt.c | 285 ++++++++++++++++++++++++++++++++
1 file changed, 285 insertions(+)
create mode 100644 grub-core/loader/slaunch/slrt.c

diff --git a/grub-core/loader/slaunch/slrt.c b/grub-core/loader/slaunch/slrt.c
new file mode 100644
index 000000000..b5213bcaa
--- /dev/null
+++ b/grub-core/loader/slaunch/slrt.c
@@ -0,0 +1,285 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/loader.h>
+#include <grub/normal.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/slr_table.h>
+#include <grub/slaunch.h>
+#include <grub/i386/linux.h>
+#include <grub/i386/memory.h>
+#include <grub/i386/tpm.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/txt.h>
+
+#define SLR_MAX_POLICY_ENTRIES 7
+
+/* Area to collect and build SLR Table information */
+static grub_uint8_t slr_policy_buf[GRUB_PAGE_SIZE] = {0};
+static struct grub_slr_entry_dl_info slr_dl_info_staging = {0};
+static struct grub_slr_entry_log_info slr_log_info_staging = {0};
+static struct grub_slr_entry_policy *slr_policy_staging =
+ (struct grub_slr_entry_policy *)slr_policy_buf;
+
+extern void dl_entry_trampoline(void);
+
+void
+grub_init_slrt_storage (void)
+{
+ slr_dl_info_staging.hdr.tag = GRUB_SLR_ENTRY_DL_INFO;
+ slr_dl_info_staging.hdr.size = sizeof(struct grub_slr_entry_dl_info);
+
+ slr_log_info_staging.hdr.tag = GRUB_SLR_ENTRY_LOG_INFO;
+ slr_log_info_staging.hdr.size = sizeof(struct grub_slr_entry_log_info);
+
+ slr_policy_staging->hdr.tag = GRUB_SLR_ENTRY_ENTRY_POLICY;
+ slr_policy_staging->hdr.size = sizeof(struct grub_slr_entry_policy) +
+ SLR_MAX_POLICY_ENTRIES*sizeof(struct grub_slr_policy_entry);
+ slr_policy_staging->revision = GRUB_SLR_POLICY_REVISION;
+ slr_policy_staging->nr_entries = SLR_MAX_POLICY_ENTRIES;
+}
+
+grub_err_t
+grub_setup_slrt_policy (struct grub_slaunch_params *slparams,
+ struct grub_slr_policy_entry *platform_entry)
+{
+ struct linux_kernel_params *boot_params = slparams->boot_params;
+ struct grub_efi_info *efi_info = NULL;
+ grub_uint64_t hi_val;
+ int i = 0;
+
+ /* A bit of work to extract the v2.08 EFI info from the linux params */
+ if (boot_params != NULL)
+ efi_info = (struct grub_efi_info *)((grub_uint8_t *)&(boot_params->v0208)
+ + 2*sizeof(grub_uint32_t));
+
+ /* the SLR table should be measured too, at least parts of it */
+ slr_policy_staging->policy_entries[i].pcr = 18;
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_SLRT;
+ slr_policy_staging->policy_entries[i].entity = slparams->slr_table_base;
+ slr_policy_staging->policy_entries[i].flags |= GRUB_SLR_POLICY_IMPLICIT_SIZE;
+ grub_strcpy (slr_policy_staging->policy_entries[i].evt_info, "Measured SLR Table");
+ i++;
+
+ if (boot_params != NULL)
+ {
+ /* boot params have everything needed to setup policy except OS2MLE data */
+ slr_policy_staging->policy_entries[i].pcr = 18;
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_BOOT_PARAMS;
+ slr_policy_staging->policy_entries[i].entity = (grub_uint64_t)(grub_addr_t)boot_params;
+ slr_policy_staging->policy_entries[i].size = GRUB_PAGE_SIZE;
+ grub_strcpy (slr_policy_staging->policy_entries[i].evt_info, "Measured boot parameters");
+ }
+ else
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_UNUSED;
+ i++;
+
+ if (boot_params != NULL && boot_params->setup_data)
+ {
+ slr_policy_staging->policy_entries[i].pcr = 18;
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_SETUP_DATA;
+ slr_policy_staging->policy_entries[i].entity = boot_params->setup_data;
+ slr_policy_staging->policy_entries[i].flags |= GRUB_SLR_POLICY_IMPLICIT_SIZE;
+ grub_strcpy (slr_policy_staging->policy_entries[i].evt_info, "Measured Kernel setup_data");
+ }
+ else
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_UNUSED;
+ i++;
+
+ if (boot_params != NULL && boot_params->cmd_line_ptr)
+ {
+ slr_policy_staging->policy_entries[i].pcr = 18;
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_CMDLINE;
+ slr_policy_staging->policy_entries[i].entity = boot_params->cmd_line_ptr;
+ hi_val = boot_params->ext_cmd_line_ptr;
+ slr_policy_staging->policy_entries[i].entity |= hi_val << 32;;
+ slr_policy_staging->policy_entries[i].size = boot_params->cmdline_size;
+ grub_strcpy (slr_policy_staging->policy_entries[i].evt_info, "Measured Kernel command line");
+ }
+ else
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_UNUSED;
+ i++;
+
+ if (efi_info != NULL && !grub_memcmp(&efi_info->efi_signature, "EL64", sizeof(grub_uint32_t)))
+ {
+ slr_policy_staging->policy_entries[i].pcr = 18;
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_UEFI_MEMMAP;
+ slr_policy_staging->policy_entries[i].entity = efi_info->efi_mmap;
+ hi_val = efi_info->efi_mmap_hi;
+ slr_policy_staging->policy_entries[i].entity |= hi_val << 32;
+ slr_policy_staging->policy_entries[i].size = efi_info->efi_mmap_size;
+ grub_strcpy (slr_policy_staging->policy_entries[i].evt_info, "Measured EFI memory map");
+ }
+ else
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_UNUSED;
+ i++;
+
+ if (boot_params != NULL && boot_params->ramdisk_image)
+ {
+ slr_policy_staging->policy_entries[i].pcr = 17;
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_RAMDISK;
+ slr_policy_staging->policy_entries[i].entity = boot_params->ramdisk_image;
+ hi_val = boot_params->ext_ramdisk_image;
+ slr_policy_staging->policy_entries[i].entity |= hi_val << 32;
+ slr_policy_staging->policy_entries[i].size = boot_params->ramdisk_size;
+ hi_val = boot_params->ext_ramdisk_size;
+ slr_policy_staging->policy_entries[i].size |= hi_val << 32;
+ grub_strcpy (slr_policy_staging->policy_entries[i].evt_info, "Measured Kernel initrd");
+ }
+ else
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_UNUSED;
+ i++;
+
+ if (platform_entry)
+ {
+ slr_policy_staging->policy_entries[i].pcr = platform_entry->pcr;
+ slr_policy_staging->policy_entries[i].entity_type = platform_entry->entity_type;
+ slr_policy_staging->policy_entries[i].flags = platform_entry->flags;
+ slr_policy_staging->policy_entries[i].entity = platform_entry->entity;
+ slr_policy_staging->policy_entries[i].size = platform_entry->size;
+ grub_strcpy (slr_policy_staging->policy_entries[i].evt_info, platform_entry->evt_info);
+ }
+ else
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_UNUSED;
+
+ return GRUB_ERR_NONE;
+}
+
+void
+grub_setup_slrt_dl_info (struct grub_slaunch_params *slparams)
+{
+ struct grub_txt_mle_header *mle_header;
+
+ mle_header = (struct grub_txt_mle_header *)((grub_addr_t) slparams->mle_mem + slparams->mle_header_offset);
+
+ /* Setup DL entry point, DCE and DLME information */
+ slr_dl_info_staging.bl_context.bootloader = GRUB_SLR_BOOTLOADER_GRUB;
+ slr_dl_info_staging.bl_context.context = (grub_addr_t)slparams;
+ slr_dl_info_staging.dl_handler = (grub_addr_t)dl_entry_trampoline;
+ slr_dl_info_staging.dlme_size = slparams->mle_size;
+ slr_dl_info_staging.dlme_base = slparams->mle_start;
+ slr_dl_info_staging.dlme_entry = mle_header->entry_point;
+ slr_dl_info_staging.dce_base = slparams->dce_base;
+ slr_dl_info_staging.dce_size = slparams->dce_size;
+}
+
+void
+grub_setup_slrt_log_info (struct grub_slaunch_params *slparams)
+{
+ slr_log_info_staging.addr = slparams->tpm_evt_log_base;
+ slr_log_info_staging.size = slparams->tpm_evt_log_size;
+ slr_log_info_staging.format =
+ (grub_get_tpm_ver () == GRUB_TPM_20) ?
+ GRUB_SLR_DRTM_TPM20_LOG : GRUB_SLR_DRTM_TPM20_LOG;
+}
+
+void
+grub_setup_slr_table (struct grub_slaunch_params *slparams,
+ struct grub_slr_entry_hdr *platform_info)
+{
+ struct grub_slr_table *slrt =
+ (struct grub_slr_table *)(grub_addr_t)slparams->slr_table_base;
+
+ grub_slr_add_entry (slrt, &slr_dl_info_staging.hdr);
+ grub_slr_add_entry (slrt, &slr_log_info_staging.hdr);
+ grub_slr_add_entry (slrt, &slr_policy_staging->hdr);
+
+ /* Add in any platform specific info if present */
+ if (platform_info)
+ grub_slr_add_entry (slrt, platform_info);
+}
+
+void
+grub_update_slrt_policy (struct grub_slaunch_params *slparams)
+{
+ struct linux_kernel_params *boot_params = slparams->boot_params;
+ struct grub_slr_entry_policy *policy;
+ struct grub_efi_info *efi_info;
+ grub_uint64_t hi_val;
+ int i, next = 0;
+
+ policy = grub_slr_next_entry_by_tag ((struct grub_slr_table *)(grub_addr_t)slparams->slr_table_base,
+ NULL,
+ GRUB_SLR_ENTRY_ENTRY_POLICY);
+
+ /* First find the updated boot params */
+ for (i = 0; i < policy->nr_entries; i++)
+ {
+ if (policy->policy_entries[i].entity_type == GRUB_SLR_ET_BOOT_PARAMS)
+ {
+ boot_params = (struct linux_kernel_params *)(grub_addr_t)policy->policy_entries[i].entity;
+ slparams->boot_params = boot_params;
+ break;
+ }
+ }
+
+ /* A bit of work to extract the v2.08 EFI info from the linux params */
+ efi_info = (struct grub_efi_info *)((grub_uint8_t *)&(boot_params->v0208)
+ + 2*sizeof(grub_uint32_t));
+
+ for (i = 0; i < policy->nr_entries; i++)
+ {
+ if (policy->policy_entries[i].entity_type == GRUB_SLR_ET_UNUSED)
+ {
+ if (next == 0 && boot_params->setup_data)
+ {
+ policy->policy_entries[i].pcr = 18;
+ policy->policy_entries[i].entity_type = GRUB_SLR_ET_SETUP_DATA;
+ policy->policy_entries[i].entity = boot_params->setup_data;
+ policy->policy_entries[i].flags |= GRUB_SLR_POLICY_IMPLICIT_SIZE;
+ grub_strcpy (policy->policy_entries[i].evt_info, "Measured Kernel setup_data");
+ }
+ else if (next == 1 && boot_params->cmd_line_ptr)
+ {
+ policy->policy_entries[i].pcr = 18;
+ policy->policy_entries[i].entity_type = GRUB_SLR_ET_CMDLINE;
+ policy->policy_entries[i].entity = boot_params->cmd_line_ptr;
+ hi_val = boot_params->ext_cmd_line_ptr;
+ policy->policy_entries[i].entity |= hi_val << 32;;
+ policy->policy_entries[i].size = boot_params->cmdline_size;
+ grub_strcpy (policy->policy_entries[i].evt_info, "Measured Kernel command line");
+ }
+ else if (next == 2 && !grub_memcmp(&efi_info->efi_signature, "EL64", sizeof(grub_uint32_t)))
+ {
+ policy->policy_entries[i].pcr = 18;
+ policy->policy_entries[i].entity_type = GRUB_SLR_ET_UEFI_MEMMAP;
+ policy->policy_entries[i].entity = efi_info->efi_mmap;
+ hi_val = efi_info->efi_mmap_hi;
+ policy->policy_entries[i].entity |= hi_val << 32;
+ policy->policy_entries[i].size = efi_info->efi_mmap_size;
+ grub_strcpy (policy->policy_entries[i].evt_info, "Measured EFI memory map");
+ }
+ else if (next == 3 && boot_params->ramdisk_image)
+ {
+ policy->policy_entries[i].pcr = 17;
+ policy->policy_entries[i].entity_type = GRUB_SLR_ET_RAMDISK;
+ policy->policy_entries[i].entity = boot_params->ramdisk_image;
+ hi_val = boot_params->ext_ramdisk_image;
+ policy->policy_entries[i].entity |= hi_val << 32;
+ policy->policy_entries[i].size = boot_params->ramdisk_size;
+ hi_val = boot_params->ext_ramdisk_size;
+ policy->policy_entries[i].entity |= hi_val << 32;
+ grub_strcpy (policy->policy_entries[i].evt_info, "Measured Kernel initrd");
+ }
+ next++;
+ }
+ }
+}
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:21 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Daniel Kiper <daniel...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
include/grub/i386/txt.h | 673 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 673 insertions(+)
create mode 100644 include/grub/i386/txt.h

diff --git a/include/grub/i386/txt.h b/include/grub/i386/txt.h
new file mode 100644
index 000000000..01668045f
--- /dev/null
+++ b/include/grub/i386/txt.h
@@ -0,0 +1,673 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Intel TXT definitions header file.
+ */
+
+#ifndef GRUB_TXT_H
+#define GRUB_TXT_H 1
+
+#include <grub/i386/mmio.h>
+
+/* Intel TXT Software Developers Guide */
+
+/* Chapter 2, Table 2 MLE/SINIT Capabilities Field Bit Definitions */
+
+#define GRUB_TXT_PCR_EXT_MAX_AGILITY_POLICY 0
+#define GRUB_TXT_PCR_EXT_MAX_PERF_POLICY 1
+
+#define GRUB_TXT_PLATFORM_TYPE_LEGACY 0
+#define GRUB_TXT_PLATFORM_TYPE_CLIENT 1
+#define GRUB_TXT_PLATFORM_TYPE_SERVER 2
+#define GRUB_TXT_PLATFORM_TYPE_RESERVED 3
+
+#define GRUB_TXT_CAPS_GETSEC_WAKE_SUPPORT (1<<0)
+#define GRUB_TXT_CAPS_MONITOR_SUPPORT (1<<1)
+#define GRUB_TXT_CAPS_ECX_PT_SUPPORT (1<<2)
+#define GRUB_TXT_CAPS_STM_SUPPORT (1<<3)
+#define GRUB_TXT_CAPS_TPM_12_NO_LEGACY_PCR_USAGE (1<<4)
+#define GRUB_TXT_CAPS_TPM_12_AUTH_PCR_USAGE (1<<5)
+#define GRUB_TXT_CAPS_PLATFORM_TYPE (3<<6)
+#define GRUB_TXT_CAPS_MAXPHYSADDR_SUPPORT (1<<8)
+#define GRUB_TXT_CAPS_TPM_20_EVTLOG_SUPPORT (1<<9)
+#define GRUB_TXT_CAPS_CBNT_SUPPORT (1<<10)
+/* Rest is reserved */
+
+/* Appendix A TXT Execution Technology Authenticated Code Modules */
+/* A.1 Authenticated Code Module Format */
+
+#define GRUB_TXT_ACM_MODULE_TYPE 2
+
+#define GRUB_TXT_ACM_MODULE_SUB_TYPE_TXT_ACM 0
+#define GRUB_TXT_ACM_MODULE_SUB_TYPE_S_ACM 1
+
+#define GRUB_TXT_ACM_HEADER_LEN_0_0 161
+#define GRUB_TXT_ACM_HEADER_LEN_3_0 224
+
+#define GRUB_TXT_ACM_HEADER_VERSION_0_0 0x0000
+#define GRUB_TXT_ACM_HEADER_VERSION_3_0 0x0300
+
+#define GRUB_TXT_ACM_FLAG_PREPRODUCTION (1<<14)
+#define GRUB_TXT_ACM_FLAG_DEBUG_SIGNED (1<<15)
+
+#define GRUB_TXT_ACM_MODULE_VENDOR_INTEL 0x00008086
+
+#define GRUB_TXT_MLE_MAX_SIZE 0x40000000
+
+#define GRUB_MLE_AP_WAKE_BLOCK_SIZE (20 * GRUB_PAGE_SIZE)
+
+struct grub_txt_acm_header
+{
+ grub_uint16_t module_type;
+ grub_uint16_t module_sub_type;
+ grub_uint32_t header_len;
+ grub_uint32_t header_version;
+ grub_uint16_t chipset_id;
+ grub_uint16_t flags;
+ grub_uint32_t module_vendor;
+ grub_uint32_t date; /* e.g 20131231H == December 31, 2013 */
+ grub_uint32_t size; /* multiples of 4 bytes */
+ grub_uint16_t txt_svn;
+ grub_uint16_t se_svn;
+ grub_uint32_t code_control;
+ grub_uint32_t error_entry_point;
+ grub_uint32_t gdt_limit;
+ grub_uint32_t gdt_base;
+ grub_uint32_t seg_sel;
+ grub_uint32_t entry_point;
+ grub_uint8_t reserved2[64];
+ grub_uint32_t key_size;
+ grub_uint32_t scratch_size;
+ /* RSA Pub Key and Signature */
+} GRUB_PACKED;
+
+#define GRUB_TXT_ACM_UUID "\xaa\x3a\xc0\x7f\xa7\x46\xdb\x18\x2e\xac\x69\x8f\x8d\x41\x7f\x5a"
+
+#define GRUB_TXT_ACM_CHIPSET_TYPE_BIOS 0
+#define GRUB_TXT_ACM_CHIPSET_TYPE_SINIT 1
+#define GRUB_TXT_ACM_CHIPSET_TYPE_BIOS_RACM 8
+#define GRUB_TXT_ACM_CHIPSET_TYPE_SINIT_RACM 9
+
+struct grub_txt_acm_info_table
+{
+ grub_uint8_t uuid[16];
+ grub_uint8_t chipset_acm_type;
+ grub_uint8_t version;
+ grub_uint16_t length;
+ grub_uint32_t chipset_id_list;
+ grub_uint32_t os_sinit_data_ver;
+ grub_uint32_t min_mle_header_ver;
+ grub_uint32_t capabilities;
+ grub_uint32_t acm_version_revision;
+ grub_uint32_t processor_id_list;
+ /* Version >= 5 */
+ grub_uint32_t tpm_info_list;
+} GRUB_PACKED;
+
+struct grub_txt_acm_chipset_id_list
+{
+ grub_uint32_t count;
+ /* Array of chipset ID structs */
+} GRUB_PACKED;
+
+#define GRUB_TXT_ACM_REVISION_ID_MASK (1<<0)
+
+struct grub_txt_acm_chipset_id
+{
+ grub_uint32_t flags;
+ grub_uint16_t vendor_id;
+ grub_uint16_t device_id;
+ grub_uint16_t revision_id;
+ grub_uint16_t reserved;
+ grub_uint32_t extended_id;
+} GRUB_PACKED;
+
+struct grub_txt_acm_processor_id_list
+{
+ grub_uint32_t count;
+ /* Array of processor ID structs */
+} GRUB_PACKED;
+
+struct grub_txt_acm_processor_id
+{
+ grub_uint32_t fms;
+ grub_uint32_t fms_mask;
+ grub_uint64_t platform_id;
+ grub_uint64_t platform_mask;
+} GRUB_PACKED;
+
+#define GRUB_TXT_TPM_CAPS_EXTPOL_NONE 0 /* TPM 1.2 */
+#define GRUB_TXT_TPM_CAPS_EXTPOL_MA 1
+#define GRUB_TXT_TPM_CAPS_EXTPOL_MP 2
+#define GRUB_TXT_TPM_CAPS_EXTPOL_BOTH 3
+
+#define GRUB_TXT_TPM_CAPS_FAMILY_DISCRETE_12 1
+#define GRUB_TXT_TPM_CAPS_FAMILY_DISCRETE_20 2
+#define GRUB_TXT_TPM_CAPS_FAMILY_FIRMWARE_20 8
+
+#define GRUB_TXT_TPM_CAPS_INITIAL_NV_INDICES 0
+#define GRUB_TXT_TPM_CAPS_TCP_NV_INDICES 1
+
+struct grub_txt_acm_tpm_info
+{
+ grub_uint32_t capabilities;
+ grub_uint16_t count;
+ /* List of supported hash algorithm per TPM2 spec */
+} GRUB_PACKED;
+
+/* Appendix B SMX Interaction with Platform */
+/* B.1 Intel Trusted Execution Technology Configuration Registers */
+
+#ifdef __x86_64__
+#define GRUB_TXT_CFG_REGS_PUB 0xfed30000ULL
+#else
+#define GRUB_TXT_CFG_REGS_PUB 0xfed30000
+#endif
+
+#define GRUB_TXT_STS 0x0000
+#define GRUB_TXT_ESTS 0x0008
+#define GRUB_TXT_ERRORCODE 0x0030
+#define GRUB_TXT_CMD_RESET 0x0038
+#define GRUB_TXT_CMD_CLOSE_PRIVATE 0x0048
+#define GRUB_TXT_VER_FSBIF 0x0100
+#define GRUB_TXT_DIDVID 0x0110
+#define GRUB_TXT_VER_QPIIF 0x0200
+#define GRUB_TXT_CMD_UNLOCK_MEM_CONFIG 0x0218
+#define GRUB_TXT_SINIT_BASE 0x0270
+#define GRUB_TXT_SINIT_SIZE 0x0278
+#define GRUB_TXT_MLE_JOIN 0x0290
+#define GRUB_TXT_HEAP_BASE 0x0300
+#define GRUB_TXT_HEAP_SIZE 0x0308
+#define GRUB_TXT_MSEG_BASE 0x0310
+#define GRUB_TXT_MSEG_SIZE 0x0318
+#define GRUB_TXT_DPR 0x0330
+#define GRUB_TXT_CMD_OPEN_LOCALITY1 0x0380
+#define GRUB_TXT_CMD_CLOSE_LOCALITY1 0x0388
+#define GRUB_TXT_CMD_OPEN_LOCALITY2 0x0390
+#define GRUB_TXT_CMD_CLOSE_LOCALITY2 0x0398
+#define GRUB_TXT_PUBLIC_KEY 0x0400
+#define GRUB_TXT_CMD_SECRETS 0x08e0
+#define GRUB_TXT_CMD_NO_SECRETS 0x08e8
+#define GRUB_TXT_E2STS 0x08f0
+
+#define GRUB_TXT_STS_SENTER_DONE (1 << 0)
+#define GRUB_TXT_STS_SEXIT_DONE (1 << 1)
+#define GRUB_TXT_STS_MEM_CONFIG_LOCK (1 << 6)
+#define GRUB_TXT_STS_PRIVATE_OPEN (1 << 7)
+#define GRUB_TXT_STS_LOCALITY1_OPEN (1 << 15)
+#define GRUB_TXT_STS_LOCALITY2_OPEN (1 << 16)
+
+#define GRUB_TXT_ESTS_TXT_RESET (1 << 0)
+
+#define GRUB_TXT_VER_FSBIF_DEBUG_FUSE (1 << 31)
+
+#define GRUB_TXT_VER_QPIIF_DEBUG_FUSE (1 << 31)
+
+#define GRUB_TXT_E2STS_SECRETS (1 << 1)
+
+union grub_txt_didvid
+{
+ grub_uint64_t value;
+ struct
+ {
+ grub_uint16_t vid;
+ grub_uint16_t did;
+ grub_uint16_t rid;
+ grub_uint16_t id_ext;
+ };
+} GRUB_PACKED;
+
+#define GRUB_TXT_VERSION_DEBUG_FUSED (1<<31)
+
+/* Appendix C Intel TXT Heap Memory */
+
+/* Ext Data Structs */
+
+struct grub_txt_heap_uuid
+{
+ grub_uint32_t data1;
+ grub_uint16_t data2;
+ grub_uint16_t data3;
+ grub_uint16_t data4;
+ grub_uint8_t data5[6];
+} GRUB_PACKED;
+
+struct grub_txt_heap_ext_data_element
+{
+ grub_uint32_t type;
+ grub_uint32_t size;
+ grub_uint8_t data[];
+} GRUB_PACKED;
+
+#define GRUB_TXT_HEAP_EXTDATA_TYPE_END 0
+
+struct grub_txt_heap_end_element
+{
+ grub_uint32_t type;
+ grub_uint32_t size;
+} GRUB_PACKED;
+
+#define GRUB_TXT_HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1
+
+struct grub_txt_heap_bios_spec_ver_element
+{
+ grub_uint16_t spec_ver_major;
+ grub_uint16_t spec_ver_minor;
+ grub_uint16_t spec_ver_revision;
+} GRUB_PACKED;
+
+#define GRUB_TXT_HEAP_EXTDATA_TYPE_ACM 2
+
+struct grub_txt_heap_acm_element
+{
+ grub_uint32_t num_acms;
+ /* Array of num_acms grub_uint64_t addresses */
+} GRUB_PACKED;
+
+#define GRUB_TXT_HEAP_EXTDATA_TYPE_STM 3
+
+struct grub_txt_heap_stm_element
+{
+ /* STM specific BIOS properties */
+} GRUB_PACKED;
+
+#define GRUB_TXT_HEAP_EXTDATA_TYPE_CUSTOM 4
+
+struct grub_txt_heap_custom_element
+{
+ struct grub_txt_heap_uuid uuid;
+ /* Vendor Data */
+} GRUB_PACKED;
+
+#define GRUB_TXT_HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR 5
+
+struct grub_txt_heap_tpm_event_log_element
+{
+ grub_uint32_t type;
+ grub_uint32_t size;
+ grub_uint64_t event_log_phys_addr;
+} GRUB_PACKED;
+
+#define GRUB_TXT_HEAP_EXTDATA_TYPE_MADT 6
+
+struct grub_txt_heap_madt_element
+{
+ /* Copy of ACPI MADT table */
+} GRUB_PACKED;
+
+#define GRUB_TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 8
+
+struct grub_txt_heap_event_log_pointer2_1_element
+{
+ grub_uint32_t type;
+ grub_uint32_t size;
+ grub_uint64_t phys_addr;
+ grub_uint32_t allocated_event_container_size;
+ grub_uint32_t first_record_offset;
+ grub_uint32_t next_record_offset;
+} GRUB_PACKED;
+
+#define GRUB_TXT_HEAP_EXTDATA_TYPE_MCFG 9
+
+struct grub_txt_heap_mcfg_element
+{
+ /* Copy of ACPI MCFG table */
+} GRUB_PACKED;
+
+/* TXT Heap Tables */
+
+struct grub_txt_bios_data
+{
+ grub_uint32_t version; /* Currently 5 for TPM 1.2 and 6 for TPM 2.0 */
+ grub_uint32_t bios_sinit_size;
+ grub_uint64_t reserved1;
+ grub_uint64_t reserved22;
+ grub_uint32_t num_logical_procs;
+ /* Versions >= 5 with updates in version 6 */
+ grub_uint32_t sinit_flags;
+ grub_uint32_t mle_flags;
+ /* Versions >= 4 */
+ /* Ext Data Elements */
+} GRUB_PACKED;
+
+/* GRUB SLAUNCH specific definitions OS-MLE data */
+#define GRUB_SL_BOOTPARAMS_OFFSET 0x12c
+#define GRUB_SL_MAX_EVENT_LOG_SIZE (5*4*1024) /* 4k*5 */
+#define GRUB_SL_OS_MLE_STRUCT_VERSION 1
+
+struct grub_txt_os_mle_data
+{
+ grub_uint32_t version;
+ grub_uint32_t reserved;
+ grub_uint64_t boot_params_addr;
+ grub_uint64_t slrt;
+ grub_uint64_t txt_info;
+ grub_uint32_t ap_wake_block;
+ grub_uint32_t ap_wake_block_size;
+ grub_uint8_t mle_scratch[64];
+} GRUB_PACKED;
+
+struct grub_txt_os_sinit_data
+{
+ grub_uint32_t version; /* Currently 6 for TPM 1.2 and 7 for TPM 2.0 */
+ grub_uint32_t flags;
+ grub_uint64_t mle_ptab;
+ grub_uint64_t mle_size;
+ grub_uint64_t mle_hdr_base;
+ grub_uint64_t vtd_pmr_lo_base;
+ grub_uint64_t vtd_pmr_lo_size;
+ grub_uint64_t vtd_pmr_hi_base;
+ grub_uint64_t vtd_pmr_hi_size;
+ grub_uint64_t lcp_po_base;
+ grub_uint64_t lcp_po_size;
+ grub_uint32_t capabilities;
+ /* Version = 5 */
+ grub_uint64_t efi_rsdt_ptr;
+ /* Versions >= 6 */
+ /* Ext Data Elements */
+ grub_uint8_t ext_data_elts[];
+} GRUB_PACKED;
+
+struct grub_txt_sinit_mle_data
+{
+ grub_uint32_t version; /* Current values are 6 through 9 */
+ /* Versions <= 8 */
+ grub_uint8_t bios_acm_id[20];
+ grub_uint32_t edx_senter_flags;
+ grub_uint64_t mseg_valid;
+ grub_uint8_t sinit_hash[20];
+ grub_uint8_t mle_hash[20];
+ grub_uint8_t stm_hash[20];
+ grub_uint8_t lcp_policy_hash[20];
+ grub_uint32_t lcp_policy_control;
+ /* Versions >= 7 */
+ grub_uint32_t rlp_wakeup_addr;
+ grub_uint32_t reserved;
+ grub_uint32_t num_of_sinit_mdrs;
+ grub_uint32_t sinit_mdrs_table_offset;
+ grub_uint32_t sinit_vtd_dmar_table_size;
+ grub_uint32_t sinit_vtd_dmar_table_offset;
+ /* Versions >= 8 */
+ grub_uint32_t processor_scrtm_status;
+ /* Versions >= 9 */
+ /* Ext Data Elements */
+} GRUB_PACKED;
+
+struct grub_txt_sinit_memory_descriptor_records
+{
+ grub_uint64_t address;
+ grub_uint64_t length;
+ grub_uint8_t type;
+ grub_uint8_t reserved[7];
+} GRUB_PACKED;
+
+/* Section 2 Measured Launch Environment */
+/* 2.1 MLE Architecture Overview */
+/* Table 1. MLE Header structure */
+
+struct grub_txt_mle_header
+{
+ grub_uint8_t uuid[16];
+ grub_uint32_t header_len;
+ grub_uint32_t version;
+ grub_uint32_t entry_point;
+ grub_uint32_t first_valid_page;
+ grub_uint32_t mle_start;
+ grub_uint32_t mle_end;
+ grub_uint32_t capabilities;
+ grub_uint32_t cmdline_start;
+ grub_uint32_t cmdline_end;
+} GRUB_PACKED;
+
+struct grub_txt_heap_event_log_ptr_elt
+{
+ grub_uint64_t event_log_phys_addr;
+} GRUB_PACKED;
+
+struct grub_txt_heap_event_log_ptr_elt2_1
+{
+ grub_uint64_t phys_addr;
+ grub_uint32_t allcoated_event_container_size;
+ grub_uint32_t first_record_offset;
+ grub_uint32_t next_record_offset;
+} GRUB_PACKED;
+
+/* TXT register and heap access */
+
+static inline grub_uint64_t
+grub_txt_reg_pub_readq (grub_uint32_t reg)
+{
+ return grub_read64 (GRUB_TXT_CFG_REGS_PUB + reg);
+}
+
+static inline grub_uint8_t *
+grub_txt_get_heap (void)
+{
+ return (grub_uint8_t *)(grub_addr_t) grub_txt_reg_pub_readq (GRUB_TXT_HEAP_BASE);
+}
+
+static inline grub_uint64_t
+grub_txt_bios_data_size (grub_uint8_t *heap)
+{
+ return *(grub_uint64_t *)heap;
+}
+
+static inline struct grub_txt_bios_data*
+grub_txt_bios_data_start (grub_uint8_t *heap)
+{
+ return (struct grub_txt_bios_data*)(heap + sizeof (grub_uint64_t));
+}
+
+static inline grub_uint64_t
+grub_txt_os_mle_data_size (grub_uint8_t *heap)
+{
+ return *(grub_uint64_t *)(heap + grub_txt_bios_data_size (heap));
+}
+
+static inline struct grub_txt_os_mle_data*
+grub_txt_os_mle_data_start (grub_uint8_t *heap)
+{
+ return (struct grub_txt_os_mle_data*)(heap + grub_txt_bios_data_size (heap) +
+ sizeof (grub_uint64_t));
+}
+
+static inline grub_uint64_t
+grub_txt_os_sinit_data_size (grub_uint8_t *heap)
+{
+ return *(grub_uint64_t *)(heap + grub_txt_bios_data_size (heap) +
+ grub_txt_os_mle_data_size (heap));
+}
+
+static inline struct grub_txt_os_sinit_data *
+grub_txt_os_sinit_data_start (grub_uint8_t *heap)
+{
+ return (struct grub_txt_os_sinit_data*)(heap +
+ grub_txt_bios_data_size (heap) +
+ grub_txt_os_mle_data_size (heap) + sizeof (grub_uint64_t));
+}
+
+static inline grub_uint64_t
+grub_txt_sinit_mle_data_size (grub_uint8_t *heap)
+{
+ return *(grub_uint64_t *)(heap + grub_txt_bios_data_size (heap) +
+ grub_txt_os_mle_data_size (heap) +
+ grub_txt_os_sinit_data_size (heap));
+}
+
+static inline struct grub_txt_sinit_mle_data*
+grub_txt_sinit_mle_data_start (grub_uint8_t *heap)
+{
+ return (struct grub_txt_sinit_mle_data*)(heap +
+ grub_txt_bios_data_size (heap) +
+ grub_txt_os_mle_data_size (heap) +
+ grub_txt_os_sinit_data_size (heap) +
+ sizeof (grub_uint64_t));
+}
+
+/* Intel 64 and IA-32 Architectures Software Developer’s Manual */
+/* Volume 2 (2A, 2B, 2C & 2D): Instruction Set Reference, A-Z */
+
+/* CHAPTER 6 SAFER MODE EXTENSIONS REFERENCE */
+
+#define GRUB_SMX_LEAF_CAPABILITIES 0
+#define GRUB_SMX_LEAF_UNDEFINED 1
+#define GRUB_SMX_LEAF_ENTERACCS 2
+#define GRUB_SMX_LEAF_EXITAC 3
+#define GRUB_SMX_LEAF_SENTER 4
+#define GRUB_SMX_LEAF_SEXIT 5
+#define GRUB_SMX_LEAF_PARAMETERS 6
+#define GRUB_SMX_LEAF_SMCTRL 7
+#define GRUB_SMX_LEAF_WAKEUP 8
+
+#define GRUB_SMX_CAPABILITY_CHIPSET_PRESENT (1<<0)
+#define GRUB_SMX_CAPABILITY_UNDEFINED (1<<1)
+#define GRUB_SMX_CAPABILITY_ENTERACCS (1<<2)
+#define GRUB_SMX_CAPABILITY_EXITAC (1<<3)
+#define GRUB_SMX_CAPABILITY_SENTER (1<<4)
+#define GRUB_SMX_CAPABILITY_SEXIT (1<<5)
+#define GRUB_SMX_CAPABILITY_PARAMETERS (1<<6)
+#define GRUB_SMX_CAPABILITY_SMCTRL (1<<7)
+#define GRUB_SMX_CAPABILITY_WAKEUP (1<<8)
+#define GRUB_SMX_CAPABILITY_EXTENDED_LEAFS (1<<31)
+
+static inline grub_uint32_t
+grub_txt_getsec_capabilities (grub_uint32_t index)
+{
+ grub_uint32_t caps;
+
+ asm volatile (".byte 0x0f,0x37\n"
+ : "=a" (caps)
+ : "a" (GRUB_SMX_LEAF_CAPABILITIES), "b" (index));
+ return caps;
+}
+
+static inline void
+grub_txt_getsec_enteraccs (grub_uint32_t acm_phys_addr, grub_uint32_t acm_size)
+{
+ asm volatile (".byte 0x0f,0x37\n" :
+ : "a" (GRUB_SMX_LEAF_ENTERACCS),
+ "b" (acm_phys_addr), "c" (acm_size));
+}
+
+static inline void
+grub_txt_getsec_exitac (grub_uint32_t near_jump)
+{
+ asm volatile (".byte 0x0f,0x37\n" :
+ : "a" (GRUB_SMX_LEAF_EXITAC), "b" (near_jump));
+}
+
+static inline void
+grub_txt_getsec_senter (grub_uint32_t acm_phys_addr, grub_uint32_t acm_size)
+{
+ asm volatile (".byte 0x0f,0x37\n" :
+ : "a" (GRUB_SMX_LEAF_SENTER),
+ "b" (acm_phys_addr), "c" (acm_size));
+}
+
+static inline void
+grub_txt_getsec_sexit (void)
+{
+ asm volatile (".byte 0x0f,0x37\n" : : "a" (GRUB_SMX_LEAF_SEXIT));
+}
+
+#define GRUB_SMX_PARAMETER_TYPE_MASK 0x1f
+#define GRUB_SMX_PARAMETER_NULL 0
+#define GRUB_SMX_PARAMETER_ACM_VERSIONS 1
+#define GRUB_SMX_PARAMETER_MAX_ACM_SIZE 2
+#define GRUB_SMX_PARAMETER_ACM_MEMORY_TYPES 3
+#define GRUB_SMX_PARAMETER_SENTER_CONTROLS 4
+#define GRUB_SMX_PARAMETER_TXT_EXTENSIONS 5
+
+
+#define GRUB_SMX_PARAMETER_MAX_VERSIONS 0x20
+
+#define GRUB_SMX_GET_MAX_ACM_SIZE(v) ((v & ~GRUB_SMX_PARAMETER_TYPE_MASK)*0x20)
+
+#define GRUB_SMX_ACM_MEMORY_TYPE_UC 0x00000100
+#define GRUB_SMX_ACM_MEMORY_TYPE_WC 0x00000200
+#define GRUB_SMX_ACM_MEMORY_TYPE_WT 0x00001000
+#define GRUB_SMX_ACM_MEMORY_TYPE_WP 0x00002000
+#define GRUB_SMX_ACM_MEMORY_TYPE_WB 0x00004000
+
+#define GRUB_SMX_GET_ACM_MEMORY_TYPES(v) (v & ~GRUB_SMX_PARAMETER_TYPE_MASK)
+
+#define GRUB_SMX_GET_SENTER_CONTROLS(v) ((v & 0x7f00) >> 8)
+
+#define GRUB_SMX_PROCESSOR_BASE_SCRTM 0x00000020
+#define GRUB_SMX_MACHINE_CHECK_HANLDING 0x00000040
+#define GRUB_SMX_GET_TXT_EXT_FEATURES(v) (v & (GRUB_SMX_PROCESSOR_BASE_SCRTM|GRUB_SMX_MACHINE_CHECK_HANLDING))
+
+#define GRUB_SMX_DEFAULT_VERSION 0x0
+#define GRUB_SMX_DEFAULT_VERSION_MASK 0xffffffff
+#define GRUB_SMX_DEFAULT_MAX_ACM_SIZE 0x8000 /* 32K */
+#define GRUB_SMX_DEFAULT_ACM_MEMORY_TYPE GRUB_SMX_ACM_MEMORY_TYPE_UC
+#define GRUB_SMX_DEFAULT_SENTER_CONTROLS 0x0
+
+#define GRUB_TXT_PMR_ALIGN_SHIFT 21
+#define GRUB_TXT_PMR_ALIGN (1 << GRUB_TXT_PMR_ALIGN_SHIFT)
+
+struct grub_smx_supported_versions
+{
+ grub_uint32_t mask;
+ grub_uint32_t version;
+} GRUB_PACKED;
+
+struct grub_smx_parameters
+{
+ struct grub_smx_supported_versions versions[GRUB_SMX_PARAMETER_MAX_VERSIONS];
+ grub_uint32_t version_count;
+ grub_uint32_t max_acm_size;
+ grub_uint32_t acm_memory_types;
+ grub_uint32_t senter_controls;
+ grub_uint32_t txt_feature_ext_flags;
+} GRUB_PACKED;
+
+static inline void
+grub_txt_getsec_parameters (grub_uint32_t index, grub_uint32_t *eax_out,
+ grub_uint32_t *ebx_out, grub_uint32_t *ecx_out)
+{
+ if (!eax_out || !ebx_out || !ecx_out)
+ return;
+
+ asm volatile (".byte 0x0f,0x37\n"
+ : "=a" (*eax_out), "=b" (*ebx_out), "=c" (*ecx_out)
+ : "0" (GRUB_SMX_LEAF_PARAMETERS), "1" (index));
+}
+
+extern grub_uint32_t grub_txt_supported_os_sinit_data_ver (struct grub_txt_acm_header* hdr);
+
+extern grub_uint32_t grub_txt_get_sinit_capabilities (struct grub_txt_acm_header* hdr);
+
+extern int grub_txt_is_sinit_acmod (const void *acmod_base, grub_uint32_t acmod_size);
+
+extern int grub_txt_acmod_match_platform (struct grub_txt_acm_header *hdr);
+
+extern struct grub_txt_acm_header* grub_txt_sinit_select (struct grub_txt_acm_header *sinit);
+
+extern grub_err_t grub_txt_verify_platform (void);
+extern grub_err_t grub_txt_prepare_cpu (void);
+extern grub_err_t grub_set_mtrrs_for_acmod (struct grub_txt_acm_header *hdr);
+
+extern grub_uint32_t grub_txt_get_mle_ptab_size (grub_uint32_t mle_size);
+extern void grub_txt_setup_mle_ptab (struct grub_slaunch_params *slparams);
+
+extern grub_err_t grub_txt_init (void);
+extern void grub_txt_shutdown (void);
+extern void grub_txt_state_show (void);
+extern grub_err_t grub_txt_boot_prepare (struct grub_slaunch_params *slparams);
+
+#endif
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:24 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Daniel Kiper <daniel...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/slaunch/txt.c | 935 +++++++++++++++++++++++++++++++++
include/grub/i386/linux.h | 5 +-
include/grub/i386/memory.h | 5 +
3 files changed, 944 insertions(+), 1 deletion(-)
create mode 100644 grub-core/loader/slaunch/txt.c

diff --git a/grub-core/loader/slaunch/txt.c b/grub-core/loader/slaunch/txt.c
new file mode 100644
index 000000000..7040c4159
--- /dev/null
+++ b/grub-core/loader/slaunch/txt.c
@@ -0,0 +1,935 @@
+/*
+ * txt.c: Intel(r) TXT support functions, including initiating measured
+ * launch, post-launch, AP wakeup, etc.
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/loader.h>
+#include <grub/memory.h>
+#include <grub/normal.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/acpi.h>
+#include <grub/slr_table.h>
+#include <grub/slaunch.h>
+#include <grub/i386/cpuid.h>
+#include <grub/i386/msr.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/crfr.h>
+#include <grub/i386/memory.h>
+#include <grub/i386/tpm.h>
+#include <grub/i386/txt.h>
+
+#define OS_SINIT_DATA_TPM_12_VER 6
+#define OS_SINIT_DATA_TPM_20_VER 7
+
+#define OS_SINIT_DATA_MIN_VER OS_SINIT_DATA_TPM_12_VER
+
+/* Area to collect and build TXT SLR Table information and policy entry */
+static struct grub_slr_entry_intel_info slr_intel_info_staging = {0};
+static struct grub_slr_policy_entry slr_intel_policy_staging = {0};
+
+static grub_err_t
+enable_smx_mode (void)
+{
+ grub_uint32_t caps;
+
+ /* Enable SMX mode. */
+ grub_write_cr4 (grub_read_cr4 () | GRUB_CR4_X86_SMXE);
+
+ caps = grub_txt_getsec_capabilities (0);
+
+ if (!(caps & GRUB_SMX_CAPABILITY_CHIPSET_PRESENT))
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("TXT-capable chipset is not present"));
+ goto fail;
+ }
+
+ if (!(caps & GRUB_SMX_CAPABILITY_SENTER))
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("GETSEC[SENTER] is not available"));
+ goto fail;
+ }
+
+ if (!(caps & GRUB_SMX_CAPABILITY_PARAMETERS))
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("GETSEC[PARAMETERS] is not available"));
+ goto fail;
+ }
+
+ return GRUB_ERR_NONE;
+
+ fail:
+ /* Disable SMX mode on failure. */
+ grub_write_cr4 (grub_read_cr4 () & ~GRUB_CR4_X86_SMXE);
+
+ return grub_errno;
+}
+
+static void
+grub_txt_smx_parameters (struct grub_smx_parameters *params)
+{
+ grub_uint32_t index = 0, eax, ebx, ecx, param_type;
+
+ grub_memset (params, 0, sizeof(struct grub_smx_supported_versions));
+
+ params->max_acm_size = GRUB_SMX_DEFAULT_MAX_ACM_SIZE;
+ params->acm_memory_types = GRUB_SMX_DEFAULT_ACM_MEMORY_TYPE;
+ params->senter_controls = GRUB_SMX_DEFAULT_SENTER_CONTROLS;
+
+ do
+ {
+ grub_txt_getsec_parameters (index, &eax, &ebx, &ecx);
+ param_type = eax & GRUB_SMX_PARAMETER_TYPE_MASK;
+
+ switch (param_type)
+ {
+ case GRUB_SMX_PARAMETER_NULL:
+ break; /* This means done. */
+
+ case GRUB_SMX_PARAMETER_ACM_VERSIONS:
+ if (params->version_count == GRUB_SMX_PARAMETER_MAX_VERSIONS)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Too many ACM versions"));
+ break;
+ }
+ params->versions[params->version_count].mask = ebx;
+ params->versions[params->version_count++].version = ecx;
+ break;
+
+ case GRUB_SMX_PARAMETER_MAX_ACM_SIZE:
+ params->max_acm_size = GRUB_SMX_GET_MAX_ACM_SIZE (eax);
+ break;
+
+ case GRUB_SMX_PARAMETER_ACM_MEMORY_TYPES:
+ params->acm_memory_types = GRUB_SMX_GET_ACM_MEMORY_TYPES (eax);
+ break;
+
+ case GRUB_SMX_PARAMETER_SENTER_CONTROLS:
+ params->senter_controls = GRUB_SMX_GET_SENTER_CONTROLS (eax);
+ break;
+
+ case GRUB_SMX_PARAMETER_TXT_EXTENSIONS:
+ params->txt_feature_ext_flags = GRUB_SMX_GET_TXT_EXT_FEATURES (eax);
+ break;
+
+ default:
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown SMX parameter"));
+ param_type = GRUB_SMX_PARAMETER_NULL;
+ }
+
+ ++index;
+
+ } while (param_type != GRUB_SMX_PARAMETER_NULL);
+
+ /* If no ACM versions were found, set the default one. */
+ if (!params->version_count)
+ {
+ params->versions[0].mask = GRUB_SMX_DEFAULT_VERSION_MASK;
+ params->versions[0].version = GRUB_SMX_DEFAULT_VERSION;
+ params->version_count++;
+ }
+}
+
+grub_err_t
+grub_txt_prepare_cpu (void)
+{
+ struct grub_smx_parameters params;
+ grub_uint32_t i;
+ grub_uint64_t mcg_cap, mcg_stat;
+ unsigned long cr0;
+
+ cr0 = grub_read_control_register (GRUB_CR0);
+
+ /* Cache must be enabled (CR0.CD = CR0.NW = 0). */
+ cr0 &= ~(GRUB_CR0_X86_CD | GRUB_CR0_X86_NW);
+
+ /* Native FPU error reporting must be enabled for proper interaction behavior. */
+ cr0 |= GRUB_CR0_X86_NE;
+
+ grub_write_control_register (GRUB_CR0, cr0);
+
+ /* Disable virtual-8086 mode (EFLAGS.VM = 0). */
+ grub_write_flags_register (grub_read_flags_register () & ~GRUB_EFLAGS_X86_VM);
+
+ /*
+ * Verify all machine check status registers are clear (unless
+ * support preserving them).
+ */
+
+ /* Is machine check in progress? */
+ if ( grub_rdmsr (GRUB_MSR_X86_MCG_STATUS) & GRUB_MSR_MCG_STATUS_MCIP )
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("machine check in progress during secure launch"));
+
+ grub_txt_smx_parameters (&params);
+
+ if (params.txt_feature_ext_flags & GRUB_SMX_PROCESSOR_BASE_SCRTM)
+ grub_dprintf ("slaunch", "CPU supports processor-based S-CRTM\n");
+
+ if (params.txt_feature_ext_flags & GRUB_SMX_MACHINE_CHECK_HANLDING)
+ grub_dprintf ("slaunch", "CPU supports preserving machine check errors\n");
+ else
+ {
+ grub_dprintf ("slaunch", "CPU does not support preserving machine check errors\n");
+
+ /* Check if all machine check registers are clear. */
+ mcg_cap = grub_rdmsr (GRUB_MSR_X86_MCG_CAP);
+ for (i = 0; i < (mcg_cap & GRUB_MSR_MCG_BANKCNT_MASK); ++i)
+ {
+ mcg_stat = grub_rdmsr (GRUB_MSR_X86_MC0_STATUS + i * 4);
+ if (mcg_stat & (1ULL << 63))
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("secure launch MCG[%u] = %llx ERROR"), i, (unsigned long long)mcg_stat);
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static void
+save_mtrrs (struct grub_slr_txt_mtrr_state *saved_bsp_mtrrs)
+{
+ grub_uint64_t i;
+
+ saved_bsp_mtrrs->default_mem_type =
+ grub_rdmsr (GRUB_MSR_X86_MTRR_DEF_TYPE);
+
+ saved_bsp_mtrrs->mtrr_vcnt =
+ grub_rdmsr (GRUB_MSR_X86_MTRRCAP) & GRUB_MSR_X86_VCNT_MASK;
+
+ if (saved_bsp_mtrrs->mtrr_vcnt > GRUB_TXT_VARIABLE_MTRRS_LENGTH)
+ {
+ /* Print warning but continue saving what we can... */
+ grub_printf ("WARNING: Actual number of variable MTRRs (%" PRIuGRUB_UINT64_T
+ ") > GRUB_SL_MAX_VARIABLE_MTRRS (%d)\n",
+ saved_bsp_mtrrs->mtrr_vcnt,
+ GRUB_TXT_VARIABLE_MTRRS_LENGTH);
+ saved_bsp_mtrrs->mtrr_vcnt = GRUB_TXT_VARIABLE_MTRRS_LENGTH;
+ }
+
+ for (i = 0; i < saved_bsp_mtrrs->mtrr_vcnt; ++i)
+ {
+ saved_bsp_mtrrs->mtrr_pair[i].mtrr_physmask =
+ grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK0 + i * 2);
+ saved_bsp_mtrrs->mtrr_pair[i].mtrr_physbase =
+ grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + i * 2);
+ }
+}
+
+static void
+set_all_mtrrs (int enable)
+{
+ grub_uint64_t mtrr_def_type;
+
+ mtrr_def_type = grub_rdmsr (GRUB_MSR_X86_MTRR_DEF_TYPE);
+
+ if ( enable )
+ mtrr_def_type |= GRUB_MSR_X86_MTRR_ENABLE;
+ else
+ mtrr_def_type &= ~GRUB_MSR_X86_MTRR_ENABLE;
+
+ grub_wrmsr (GRUB_MSR_X86_MTRR_DEF_TYPE, mtrr_def_type);
+}
+
+#define SINIT_MTRR_MASK 0xFFFFFF /* SINIT requires 36b mask */
+
+union mtrr_physbase_t
+{
+ grub_uint64_t raw;
+ struct
+ {
+ grub_uint64_t type : 8;
+ grub_uint64_t reserved1 : 4;
+ grub_uint64_t base : 52; /* Define as max width and mask w/ */
+ /* MAXPHYADDR when using */
+ };
+} GRUB_PACKED;
+
+union mtrr_physmask_t
+{
+ grub_uint64_t raw;
+ struct
+ {
+ grub_uint64_t reserved1 : 11;
+ grub_uint64_t v : 1; /* valid */
+ grub_uint64_t mask : 52; /* define as max width and mask w/ */
+ /* MAXPHYADDR when using */
+ };
+} GRUB_PACKED;
+
+static inline grub_uint32_t
+bsrl (grub_uint32_t mask)
+{
+ grub_uint32_t result;
+
+ asm ("bsrl %1,%0" : "=r" (result) : "rm" (mask) : "cc");
+
+ return result;
+}
+
+static inline int
+fls (int mask)
+{
+ return (mask == 0 ? mask : (int)bsrl ((grub_uint32_t)mask) + 1);
+}
+
+/*
+ * set the memory type for specified range (base to base+size)
+ * to mem_type and everything else to UC
+ */
+static grub_err_t
+set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size,
+ grub_uint32_t mem_type)
+{
+ grub_uint64_t mtrr_def_type;
+ grub_uint64_t mtrr_cap;
+ union mtrr_physbase_t mtrr_physbase;
+ union mtrr_physmask_t mtrr_physmask;
+ grub_uint32_t vcnt, pages_in_range;
+ unsigned long ndx, base_v;
+ int i = 0, j, num_pages, mtrr_s;
+
+ /* Disable all fixed MTRRs, set default type to UC */
+ mtrr_def_type = grub_rdmsr (GRUB_MSR_X86_MTRR_DEF_TYPE);
+ mtrr_def_type &= ~(GRUB_MSR_X86_MTRR_ENABLE_FIXED | GRUB_MSR_X86_DEF_TYPE_MASK);
+ mtrr_def_type |= GRUB_MTRR_MEMORY_TYPE_UC;
+ grub_wrmsr (GRUB_MSR_X86_MTRR_DEF_TYPE, mtrr_def_type);
+
+ /* Initially disable all variable MTRRs (we'll enable the ones we use) */
+ mtrr_cap = grub_rdmsr (GRUB_MSR_X86_MTRRCAP);
+ vcnt = (mtrr_cap & GRUB_MSR_X86_VCNT_MASK);
+
+ for ( ndx = 0; ndx < vcnt; ndx++ )
+ {
+ mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK0 + ndx*2);
+ mtrr_physmask.v = 0;
+ grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK0 + ndx*2, mtrr_physmask.raw);
+ }
+
+ /* Map all AC module pages as mem_type */
+ num_pages = GRUB_PAGE_UP(size) >> GRUB_PAGE_SHIFT;
+
+ grub_dprintf ("slaunch", "setting MTRRs for acmod: base=%p, size=%x, num_pages=%d\n",
+ base, size, num_pages);
+
+ /* Each VAR MTRR base must be a multiple if that MTRR's Size */
+ base_v = (unsigned long)base;
+ /* MTRR size in pages */
+ mtrr_s = 1;
+
+ while ( (base_v & 0x01) == 0 )
+ {
+ i++;
+ base_v = base_v >> 1;
+ }
+
+ for (j = i - 12; j > 0; j--)
+ mtrr_s = mtrr_s*2; /* mtrr_s = mtrr_s << 1 */
+
+ grub_dprintf ("slaunch", "The maximum allowed MTRR range size=%d Pages \n", mtrr_s);
+
+ ndx = 0;
+
+ while ( num_pages >= mtrr_s )
+ {
+ mtrr_physbase.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2);
+ mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) &
+ SINIT_MTRR_MASK;
+ mtrr_physbase.type = mem_type;
+ grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2, mtrr_physbase.raw);
+
+ mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK0 + ndx*2);
+ mtrr_physmask.mask = ~(mtrr_s - 1) & SINIT_MTRR_MASK;
+ mtrr_physmask.v = 1;
+ grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK0 + ndx*2, mtrr_physmask.raw);
+
+ base += (mtrr_s * GRUB_PAGE_SIZE);
+ num_pages -= mtrr_s;
+ ndx++;
+ if ( ndx == vcnt )
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("exceeded number of var MTRRs when mapping range"));
+ }
+
+ while ( num_pages > 0 )
+ {
+ /* Set the base of the current MTRR */
+ mtrr_physbase.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2);
+ mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) &
+ SINIT_MTRR_MASK;
+ mtrr_physbase.type = mem_type;
+ grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2, mtrr_physbase.raw);
+
+ /*
+ * Calculate MTRR mask
+ * MTRRs can map pages in power of 2
+ * may need to use multiple MTRRS to map all of region
+ */
+ pages_in_range = 1 << (fls (num_pages) - 1);
+
+ mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK0 + ndx*2);
+ mtrr_physmask.mask = ~(pages_in_range - 1) & SINIT_MTRR_MASK;
+ mtrr_physmask.v = 1;
+ grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK0 + ndx*2, mtrr_physmask.raw);
+
+ /*
+ * Prepare for the next loop depending on number of pages
+ * We figure out from the above how many pages could be used in this
+ * mtrr. Then we decrement the count, increment the base,
+ * increment the mtrr we are dealing with, and if num_pages is
+ * still not zero, we do it again.
+ */
+ base += (pages_in_range * GRUB_PAGE_SIZE);
+ num_pages -= pages_in_range;
+ ndx++;
+ if ( ndx == vcnt )
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("exceeded number of var MTRRs when mapping range"));
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * this must be done for each processor so that all have the same
+ * memory types
+ */
+grub_err_t
+grub_set_mtrrs_for_acmod (struct grub_txt_acm_header *hdr)
+{
+ unsigned long eflags;
+ unsigned long cr0, cr4;
+ grub_err_t err;
+
+ /*
+ * need to do some things before we start changing MTRRs
+ *
+ * since this will modify some of the MTRRs, they should be saved first
+ * so that they can be restored once the AC mod is done
+ */
+
+ /* Disable interrupts */
+ eflags = grub_read_flags_register ();
+ grub_write_flags_register (eflags & ~GRUB_EFLAGS_X86_IF);
+
+ /* Save CR0 then disable cache (CRO.CD=1, CR0.NW=0) */
+ cr0 = grub_read_control_register (GRUB_CR0);
+ grub_write_control_register (GRUB_CR0,
+ (cr0 & ~GRUB_CR0_X86_NW) | GRUB_CR0_X86_CD);
+
+ /* Flush caches */
+ asm volatile ("wbinvd");
+
+ /* Save CR4 and disable global pages (CR4.PGE=0) */
+ cr4 = grub_read_control_register (GRUB_CR4);
+ grub_write_control_register (GRUB_CR4, cr4 & ~GRUB_CR4_X86_PGE);
+
+ /* Disable MTRRs */
+ set_all_mtrrs (0);
+
+ /* Set MTRRs for AC mod and rest of memory */
+ err = set_mtrr_mem_type ((grub_uint8_t*)hdr, hdr->size*4,
+ GRUB_MTRR_MEMORY_TYPE_WB);
+ if ( err )
+ return err;
+
+ /* Undo some of earlier changes and enable our new settings */
+
+ /* Flush caches */
+ asm volatile ("wbinvd");
+
+ /* Enable MTRRs */
+ set_all_mtrrs (1);
+
+ /* Restore CR0 (cacheing) */
+ grub_write_control_register (GRUB_CR0, cr0);
+
+ /* Restore CR4 (global pages) */
+ grub_write_control_register (GRUB_CR4, cr4);
+
+ /* Restore flags */
+ grub_write_flags_register (eflags);
+
+ return GRUB_ERR_NONE;
+}
+
+static void
+set_txt_info_ptr (struct grub_slaunch_params *slparams,
+ struct grub_txt_os_mle_data *os_mle_data)
+{
+ struct grub_slr_entry_hdr *txt_info;
+
+ txt_info = grub_slr_next_entry_by_tag ((struct grub_slr_table *)(grub_addr_t)slparams->slr_table_base,
+ NULL,
+ GRUB_SLR_ENTRY_INTEL_INFO);
+ os_mle_data->txt_info = (grub_addr_t)txt_info;
+}
+
+static grub_err_t
+init_txt_heap (struct grub_slaunch_params *slparams, struct grub_txt_acm_header *sinit)
+{
+ grub_uint8_t *txt_heap;
+ grub_uint32_t os_sinit_data_ver, sinit_caps;
+ grub_uint64_t *size;
+ struct grub_txt_os_mle_data *os_mle_data;
+ struct grub_txt_os_sinit_data *os_sinit_data;
+ struct grub_txt_heap_end_element *heap_end_element;
+ struct grub_txt_heap_event_log_pointer2_1_element *heap_event_log_pointer2_1_element;
+#ifdef GRUB_MACHINE_EFI
+ struct grub_acpi_rsdp_v20 *rsdp;
+#endif
+ struct grub_slr_txt_mtrr_state saved_mtrrs_state = {0};
+ grub_err_t err;
+
+ /* BIOS data already verified in grub_txt_verify_platform(). */
+
+ txt_heap = grub_txt_get_heap ();
+
+ /* Prepare SLR table staging area */
+ grub_init_slrt_storage ();
+
+ /* OS/loader to MLE data. */
+
+ os_mle_data = grub_txt_os_mle_data_start (txt_heap);
+ size = (grub_uint64_t *) ((grub_addr_t) os_mle_data - sizeof (grub_uint64_t));
+ *size = sizeof (*os_mle_data) + sizeof (grub_uint64_t);
+
+ grub_memset (os_mle_data, 0, sizeof (*os_mle_data));
+
+ os_mle_data->version = GRUB_SL_OS_MLE_STRUCT_VERSION;
+ os_mle_data->boot_params_addr = slparams->boot_params_base;
+ os_mle_data->slrt = slparams->slr_table_base;
+
+ os_mle_data->ap_wake_block = slparams->ap_wake_block;
+ os_mle_data->ap_wake_block_size = slparams->ap_wake_block_size;
+
+ grub_setup_slrt_log_info (slparams);
+
+ /* Save the BSPs MTRR state so post launch can restore itt */
+ save_mtrrs (&saved_mtrrs_state);
+
+ /* Setup the TXT specific SLR information and policy entry */
+ slr_intel_info_staging.hdr.tag = GRUB_SLR_ENTRY_INTEL_INFO;
+ slr_intel_info_staging.hdr.size = sizeof(struct grub_slr_entry_intel_info);
+ slr_intel_info_staging.txt_heap = (grub_addr_t)txt_heap;
+ slr_intel_info_staging.saved_misc_enable_msr =
+ grub_rdmsr (GRUB_MSR_X86_MISC_ENABLE);
+ grub_memcpy (&(slr_intel_info_staging.saved_bsp_mtrrs), &saved_mtrrs_state,
+ sizeof(struct grub_slr_txt_mtrr_state));
+
+ slr_intel_policy_staging.pcr = 18;
+ slr_intel_policy_staging.entity_type = GRUB_SLR_ET_TXT_OS2MLE;
+ slr_intel_policy_staging.entity = (grub_addr_t)os_mle_data;
+ slr_intel_policy_staging.size = sizeof(struct grub_txt_os_mle_data);
+ grub_strcpy (slr_intel_policy_staging.evt_info, "Measured TXT OS-MLE data");
+
+ /* Create the SLR security policy */
+ err = grub_setup_slrt_policy (slparams, &slr_intel_policy_staging);
+ if (err != GRUB_ERR_NONE)
+ return grub_error (err, N_("failed to build SLR policy"));
+
+ /* OS/loader to SINIT data. */
+
+ os_sinit_data_ver = grub_txt_supported_os_sinit_data_ver (sinit);
+
+ if (os_sinit_data_ver < OS_SINIT_DATA_MIN_VER)
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("unsupported OS to SINIT data version in SINIT ACM: %d"
+ " expected >= %d"), os_sinit_data_ver, OS_SINIT_DATA_MIN_VER);
+
+ os_sinit_data = grub_txt_os_sinit_data_start (txt_heap);
+ size = (grub_uint64_t *) ((grub_addr_t) os_sinit_data - sizeof (grub_uint64_t));
+
+ *size = sizeof(grub_uint64_t) + sizeof (struct grub_txt_os_sinit_data) +
+ sizeof (struct grub_txt_heap_end_element);
+
+ if (grub_get_tpm_ver () == GRUB_TPM_12)
+ *size += sizeof (struct grub_txt_heap_tpm_event_log_element);
+ else if (grub_get_tpm_ver () == GRUB_TPM_20)
+ *size += sizeof (struct grub_txt_heap_event_log_pointer2_1_element);
+ else
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("unsupported TPM version"));
+
+ grub_memset (os_sinit_data, 0, *size);
+
+#ifdef GRUB_MACHINE_EFI
+ rsdp = grub_acpi_get_rsdpv2 ();
+
+ if (rsdp == NULL)
+ return grub_printf ("WARNING: ACPI RSDP 2.0 missing\n");
+
+ os_sinit_data->efi_rsdt_ptr = (grub_uint64_t)(grub_addr_t) rsdp;
+#endif
+
+ os_sinit_data->mle_ptab = slparams->mle_ptab_target;
+ os_sinit_data->mle_size = slparams->mle_size;
+
+ os_sinit_data->mle_hdr_base = slparams->mle_header_offset;
+
+ /* TODO: Check low PMR with RMRR. Look at relevant tboot code too. */
+ /* TODO: Kernel should not allocate any memory outside of PMRs regions!!! */
+ os_sinit_data->vtd_pmr_lo_base = 0;
+ os_sinit_data->vtd_pmr_lo_size = ALIGN_DOWN (grub_mmap_get_highest (0x100000000),
+ GRUB_TXT_PMR_ALIGN);
+
+ os_sinit_data->vtd_pmr_hi_base = ALIGN_UP (grub_mmap_get_lowest (0x100000000),
+ GRUB_TXT_PMR_ALIGN);
+ os_sinit_data->vtd_pmr_hi_size = ALIGN_DOWN (grub_mmap_get_highest (0xffffffffffffffff),
+ GRUB_TXT_PMR_ALIGN);
+ os_sinit_data->vtd_pmr_hi_size -= os_sinit_data->vtd_pmr_hi_base;
+
+ grub_dprintf ("slaunch",
+ "vtd_pmr_lo_base: 0x%" PRIxGRUB_UINT64_T " vtd_pmr_lo_size: 0x%"
+ PRIxGRUB_UINT64_T " vtd_pmr_hi_base: 0x%" PRIxGRUB_UINT64_T
+ " vtd_pmr_hi_size: 0x%" PRIxGRUB_UINT64_T "\n",
+ os_sinit_data->vtd_pmr_lo_base, os_sinit_data->vtd_pmr_lo_size,
+ os_sinit_data->vtd_pmr_hi_base, os_sinit_data->vtd_pmr_hi_size);
+
+ sinit_caps = grub_txt_get_sinit_capabilities (sinit);
+
+ /* CBnT bits 5:4 must be 11b, since D/A mapping is the only one supported. */
+ os_sinit_data->capabilities = GRUB_TXT_CAPS_TPM_12_NO_LEGACY_PCR_USAGE |
+ GRUB_TXT_CAPS_TPM_12_AUTH_PCR_USAGE;
+
+ /* Choose monitor RLP wakeup mechanism first. */
+ if (sinit_caps & GRUB_TXT_CAPS_MONITOR_SUPPORT)
+ os_sinit_data->capabilities |= GRUB_TXT_CAPS_MONITOR_SUPPORT;
+ else if (sinit_caps & GRUB_TXT_CAPS_GETSEC_WAKE_SUPPORT)
+ os_sinit_data->capabilities |= GRUB_TXT_CAPS_GETSEC_WAKE_SUPPORT;
+ else
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("lack of RLP wakeup mechanism"));
+
+ if (sinit_caps & GRUB_TXT_CAPS_ECX_PT_SUPPORT)
+ os_sinit_data->capabilities |= GRUB_TXT_CAPS_ECX_PT_SUPPORT;
+
+ if (grub_get_tpm_ver () == GRUB_TPM_12)
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("TPM 1.2 is not supported"));
+ else
+ {
+ if (!(sinit_caps & GRUB_TXT_CAPS_TPM_20_EVTLOG_SUPPORT))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("original TXT TPM 2.0 event log format is not supported"));
+
+ os_sinit_data->capabilities |= GRUB_TXT_CAPS_TPM_20_EVTLOG_SUPPORT;
+
+ os_sinit_data->flags = GRUB_TXT_PCR_EXT_MAX_PERF_POLICY;
+
+ os_sinit_data->version = OS_SINIT_DATA_TPM_20_VER;
+
+ heap_event_log_pointer2_1_element =
+ (struct grub_txt_heap_event_log_pointer2_1_element *) os_sinit_data->ext_data_elts;
+ heap_event_log_pointer2_1_element->type = GRUB_TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1;
+ heap_event_log_pointer2_1_element->size = sizeof (*heap_event_log_pointer2_1_element);
+
+ heap_event_log_pointer2_1_element->phys_addr = slparams->tpm_evt_log_base;
+ heap_event_log_pointer2_1_element->allocated_event_container_size = slparams->tpm_evt_log_size;
+
+ heap_end_element = (struct grub_txt_heap_end_element *)
+ ((grub_addr_t) heap_event_log_pointer2_1_element + heap_event_log_pointer2_1_element->size);
+ heap_end_element->type = GRUB_TXT_HEAP_EXTDATA_TYPE_END;
+ heap_end_element->size = sizeof (*heap_end_element);
+ }
+
+ /*
+ * TODO: TXT spec: Note: BiosDataSize + OsMleDataSize + OsSinitDataSize + SinitMleDataSize
+ * must be less than or equal to TXT.HEAP.SIZE, TXT spec, p. 102.
+ */
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * TODO: Why 1 GiB limit? It does not seem that it is required by TXT spec.
+ * If there is a limit then it should be checked before allocation and image load.
+ *
+ * If enough room is available in front of the MLE, the maximum size of an
+ * MLE that can be covered is 1G. This is due to having 512 PDEs pointing
+ * to 512 page tables with 512 PTEs each.
+ */
+grub_uint32_t
+grub_txt_get_mle_ptab_size (grub_uint32_t mle_size)
+{
+ /*
+ * #PT + 1 PT + #PD + 1 PD + 1 PDT
+ *
+ * Why do we need 2 extra PTEs and PDEs? Yes, because MLE image may not
+ * start and end at PTE (page) and PDE (2 MiB) boundary...
+ */
+ return ((((mle_size / GRUB_PAGE_SIZE) + 2) / 512) + 1 +
+ (((mle_size / (512 * GRUB_PAGE_SIZE)) + 2) / 512) + 1 + 1) * GRUB_PAGE_SIZE;
+}
+
+/* Page directory and table entries only need Present set */
+#define MAKE_PT_MLE_ENTRY(addr) (((grub_uint64_t)(grub_addr_t)(addr) & GRUB_PAGE_MASK) | 0x01)
+
+/*
+ * The MLE page tables have to be below the MLE and have no special regions in
+ * between them and the MLE (this is a bit of an unwritten rule).
+ * 20 pages are carved out of memory below the MLE. That leave 18 page table
+ * pages that can cover up to 36M .
+ * can only contain 4k pages
+ *
+ * TODO: TXT Spec p.32; List section name and number with PT MLE requirments here.
+ *
+ * TODO: This function is not able to cover MLEs larger than 1 GiB. Fix it!!!
+ * After fixing inrease GRUB_TXT_MLE_MAX_SIZE too.
+ */
+void
+grub_txt_setup_mle_ptab (struct grub_slaunch_params *slparams)
+{
+ grub_uint8_t *pg_dir, *pg_dir_ptr_tab = slparams->mle_ptab_mem, *pg_tab;
+ grub_uint32_t mle_off = 0, pd_off = 0;
+ grub_uint64_t *pde, *pte;
+
+ grub_memset (pg_dir_ptr_tab, 0, slparams->mle_ptab_size);
+
+ pg_dir = pg_dir_ptr_tab + GRUB_PAGE_SIZE;
+ pg_tab = pg_dir + GRUB_PAGE_SIZE;
+
+ /* Only use first entry in page dir ptr table */
+ *(grub_uint64_t *)pg_dir_ptr_tab = MAKE_PT_MLE_ENTRY(pg_dir);
+
+ /* Start with first entry in page dir */
+ *(grub_uint64_t *)pg_dir = MAKE_PT_MLE_ENTRY(pg_tab);
+
+ pte = (grub_uint64_t *)pg_tab;
+ pde = (grub_uint64_t *)pg_dir;
+
+ do
+ {
+ *pte = MAKE_PT_MLE_ENTRY(slparams->mle_start + mle_off);
+
+ pte++;
+ mle_off += GRUB_PAGE_SIZE;
+
+ if (!(++pd_off % 512))
+ {
+ /* Break if we don't need any additional page entries */
+ if (mle_off >= slparams->mle_size)
+ break;
+ pde++;
+ *pde = MAKE_PT_MLE_ENTRY(pte);
+ }
+ } while (mle_off < slparams->mle_size);
+}
+
+grub_err_t
+grub_txt_init (void)
+{
+ grub_err_t err;
+
+ err = grub_txt_verify_platform ();
+
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ err = enable_smx_mode ();
+
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ return GRUB_ERR_NONE;
+}
+
+void
+grub_txt_shutdown (void)
+{
+ /* Disable SMX mode. */
+ grub_write_cr4 (grub_read_cr4 () & ~GRUB_CR4_X86_SMXE);
+}
+
+void
+grub_txt_state_show (void)
+{
+ grub_uint64_t data;
+ grub_uint8_t *data8 = (grub_uint8_t *) &data;
+ int i;
+
+ data = grub_txt_reg_pub_readq (GRUB_TXT_STS);
+ grub_printf (" TXT.STS: 0x%016" PRIxGRUB_UINT64_T "\n"
+ " SENTER.DONE.STS: %d\n"
+ " SEXIT.DONE.STS: %d\n"
+ " MEM-CONFIGLOCK.STS: %d\n"
+ " PRIVATEOPEN.STS: %d\n"
+ " TXT.LOCALITY1.OPEN.STS: %d\n"
+ " TXT.LOCALITY2.OPEN.STS: %d\n",
+ data, !!(data & GRUB_TXT_STS_SENTER_DONE),
+ !!(data & GRUB_TXT_STS_SEXIT_DONE),
+ !!(data & GRUB_TXT_STS_MEM_CONFIG_LOCK),
+ !!(data & GRUB_TXT_STS_PRIVATE_OPEN),
+ !!(data & GRUB_TXT_STS_LOCALITY1_OPEN),
+ !!(data & GRUB_TXT_STS_LOCALITY2_OPEN));
+
+ /* Only least significant byte has a meaning. */
+ data = grub_txt_reg_pub_readq (GRUB_TXT_ESTS) & 0x00000000000000ff;
+ grub_printf (" TXT.ESTS: 0x%02" PRIxGRUB_UINT64_T "\n"
+ " TXT_RESET.STS: %d\n", data,
+ !!(data & GRUB_TXT_ESTS_TXT_RESET));
+
+ data = grub_txt_reg_pub_readq (GRUB_TXT_E2STS);
+ grub_printf (" TXT.E2STS: 0x%016" PRIxGRUB_UINT64_T "\n"
+ " SECRETS.STS: %d\n", data,
+ !!(data & GRUB_TXT_E2STS_SECRETS));
+
+ /* Only least significant 4 bytes have a meaning. */
+ data = grub_txt_reg_pub_readq (GRUB_TXT_ERRORCODE) & 0x00000000ffffffff;
+ grub_printf (" TXT.ERRORCODE: 0x%08" PRIxGRUB_UINT64_T "\n", data);
+
+ data = grub_txt_reg_pub_readq (GRUB_TXT_DIDVID);
+ grub_printf (" TXT.DIDVID: 0x%016" PRIxGRUB_UINT64_T "\n"
+ " VID: 0x%04" PRIxGRUB_UINT64_T "\n"
+ " DID: 0x%04" PRIxGRUB_UINT64_T "\n"
+ " RID: 0x%04" PRIxGRUB_UINT64_T "\n"
+ " ID-EXT: 0x%04" PRIxGRUB_UINT64_T "\n",
+ data, data & 0x000000000000ffff,
+ (data & 0x00000000ffff0000) >> 16,
+ (data & 0x0000ffff00000000) >> 32, data >> 48);
+
+ /* Only least significant 4 bytes have a meaning. */
+ data = grub_txt_reg_pub_readq (GRUB_TXT_VER_FSBIF) & 0x00000000ffffffff;
+ grub_printf (" TXT.VER.FSBIF: 0x%08" PRIxGRUB_UINT64_T "\n", data);
+
+ if ((data != 0x00000000) && (data != 0xffffffff))
+ grub_printf (" DEBUG.FUSE: %d\n", !!(data & GRUB_TXT_VER_FSBIF_DEBUG_FUSE));
+ else
+ {
+ /* Only least significant 4 bytes have a meaning. */
+ data = grub_txt_reg_pub_readq (GRUB_TXT_VER_QPIIF) & 0x00000000ffffffff;
+ grub_printf (" TXT.VER.QPIIF: 0x%08" PRIxGRUB_UINT64_T "\n"
+ " DEBUG.FUSE: %d\n", data,
+ !!(data & GRUB_TXT_VER_QPIIF_DEBUG_FUSE));
+ }
+
+ /* Only least significant 4 bytes have a meaning. */
+ data = grub_txt_reg_pub_readq (GRUB_TXT_SINIT_BASE) & 0x00000000ffffffff;
+ grub_printf (" TXT.SINIT.BASE: 0x%08" PRIxGRUB_UINT64_T "\n", data);
+
+ /* Only least significant 4 bytes have a meaning. */
+ data = grub_txt_reg_pub_readq (GRUB_TXT_SINIT_SIZE) & 0x00000000ffffffff;
+ grub_printf (" TXT.SINIT.SIZE: %" PRIuGRUB_UINT64_T
+ " B (0x%" PRIxGRUB_UINT64_T ")\n", data, data);
+
+ /* Only least significant 4 bytes have a meaning. */
+ data = grub_txt_reg_pub_readq (GRUB_TXT_HEAP_BASE) & 0x00000000ffffffff;
+ grub_printf (" TXT.HEAP.BASE: 0x%08" PRIxGRUB_UINT64_T "\n", data);
+
+ /* Only least significant 4 bytes have a meaning. */
+ data = grub_txt_reg_pub_readq (GRUB_TXT_HEAP_SIZE) & 0x00000000ffffffff;
+ grub_printf (" TXT.HEAP.SIZE: %" PRIuGRUB_UINT64_T
+ " B (0x%" PRIxGRUB_UINT64_T ")\n", data, data);
+
+ /* Only least significant 4 bytes have a meaning. */
+ data = grub_txt_reg_pub_readq (GRUB_TXT_DPR) & 0x00000000ffffffff;
+ grub_printf (" TXT.DPR: 0x%08" PRIxGRUB_UINT64_T "\n"
+ " LOCK: %d\n"
+ " TOP: 0x%08" PRIxGRUB_UINT64_T "\n"
+ " SIZE: %" PRIuGRUB_UINT64_T " MiB\n",
+ data, !!(data & (1 << 0)), (data & 0xfff00000),
+ (data & 0x00000ff0) >> 4);
+
+ grub_printf (" TXT.PUBLIC.KEY:\n");
+
+ for (i = 0; i < 4; ++i)
+ {
+ /* TODO: Check relevant MSRs on SGX platforms. */
+ data = grub_txt_reg_pub_readq (GRUB_TXT_PUBLIC_KEY + i * sizeof (grub_uint64_t));
+ grub_printf (" %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x%s", data8[0], data8[1],
+ data8[2], data8[3], data8[4], data8[5], data8[6], data8[7],
+ (i < 3) ? ":\n" : "\n");
+ }
+}
+
+grub_err_t
+grub_txt_boot_prepare (struct grub_slaunch_params *slparams)
+{
+ grub_err_t err;
+ grub_uint8_t *txt_heap;
+ struct grub_txt_os_mle_data *os_mle_data;
+ struct grub_txt_mle_header *mle_header;
+ struct grub_txt_acm_header *sinit_base;
+ struct grub_slr_table *slrt = slparams->slr_table_mem;
+
+ /* Setup the generic bits of the SLRT */
+ grub_slr_init_table(slrt, GRUB_SLR_INTEL_TXT, slparams->slr_table_size);
+
+ sinit_base = grub_txt_sinit_select (grub_slaunch_module ());
+
+ if (sinit_base == NULL)
+ return grub_errno;
+
+ err = init_txt_heap (slparams, sinit_base);
+
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ /* Update the MLE header. */
+ mle_header = (struct grub_txt_mle_header *)(grub_addr_t) (slparams->mle_start + slparams->mle_header_offset);
+ mle_header->first_valid_page = 0;
+ mle_header->mle_end = slparams->mle_size;
+
+ slparams->dce_base = (grub_uint32_t)(grub_addr_t) sinit_base;
+ slparams->dce_size = sinit_base->size * 4;
+
+ /* Setup DL entry point, DCE and DLME information */
+ grub_setup_slrt_dl_info (slparams);
+
+ /* Final setup of SLR table */
+ txt_heap = grub_txt_get_heap ();
+ os_mle_data = grub_txt_os_mle_data_start (txt_heap);
+ grub_setup_slr_table (slparams, (struct grub_slr_entry_hdr *)&slr_intel_info_staging);
+ set_txt_info_ptr (slparams, os_mle_data);
+
+ grub_tpm_relinquish_locality (0);
+
+ return GRUB_ERR_NONE;
+}
diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h
index d4b550869..ace28f8c2 100644
--- a/include/grub/i386/linux.h
+++ b/include/grub/i386/linux.h
@@ -240,8 +240,11 @@ struct linux_kernel_params
grub_uint32_t ofw_num_items; /* b4 */
grub_uint32_t ofw_cif_handler; /* b8 */
grub_uint32_t ofw_idt; /* bc */
+ grub_uint32_t ext_ramdisk_image; /* c0 */
+ grub_uint32_t ext_ramdisk_size; /* c4 */
+ grub_uint32_t ext_cmd_line_ptr; /* c8 */

- grub_uint8_t padding7[0x1b8 - 0xc0];
+ grub_uint8_t padding7[0x1b8 - 0xcc];

union
{
diff --git a/include/grub/i386/memory.h b/include/grub/i386/memory.h
index c64529630..56f64855b 100644
--- a/include/grub/i386/memory.h
+++ b/include/grub/i386/memory.h
@@ -22,6 +22,7 @@

#define GRUB_PAGE_SHIFT 12
#define GRUB_PAGE_SIZE (1UL << GRUB_PAGE_SHIFT)
+#define GRUB_PAGE_MASK (~(GRUB_PAGE_SIZE - 1))

/* The flag for protected mode. */
#define GRUB_MEMORY_CPU_CR0_PE_ON 0x1
@@ -43,8 +44,12 @@

#define GRUB_MMAP_MALLOC_LOW 1

+#include <grub/misc.h>
#include <grub/types.h>

+#define GRUB_PAGE_UP(p) ALIGN_UP (p, GRUB_PAGE_SIZE)
+#define GRUB_PAGE_DOWN(p) ALIGN_DOWN (p, GRUB_PAGE_SIZE)
+
struct grub_e820_mmap_entry
{
grub_uint64_t addr;
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:26 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Daniel Kiper <daniel...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/slaunch/acmod.c | 575 +++++++++++++++++++++++++++++++
1 file changed, 575 insertions(+)
create mode 100644 grub-core/loader/slaunch/acmod.c

diff --git a/grub-core/loader/slaunch/acmod.c b/grub-core/loader/slaunch/acmod.c
new file mode 100644
index 000000000..9c3daebe3
--- /dev/null
+++ b/grub-core/loader/slaunch/acmod.c
@@ -0,0 +1,575 @@
+/*
+ * acmod.c: support functions for use of Intel(r) TXT Authenticated
+ * Code (AC) Modules
+#include <grub/normal.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/slr_table.h>
+#include <grub/slaunch.h>
+#include <grub/i386/msr.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/txt.h>
+
+/*
+ * This checks to see if two numbers multiplied together are larger
+ * than the type that they are. Returns TRUE if OVERFLOWING.
+ * If the first parameter "x" is greater than zero and
+ * if that is true, that the largest possible value 0xFFFFFFFF / "x"
+ * is less than the second parameter "y". If "y" is zero then
+ * it will also fail because no unsigned number is less than zero.
+ */
+static inline int
+multiply_overflow_u32 (grub_uint32_t x, grub_uint32_t y)
+{
+ /* Use x instead of (x > 0)? */
+ return (x > 0) ? ((((grub_uint32_t)(~0))/x) < y) : 0;
+}
+
+/*
+ * These three "plus overflow" functions take a "x" value
+ * and add the "y" value to it and if the two values are
+ * greater than the size of the variable type, they will
+ * overflow the type and end up with a smaller value and
+ * return TRUE - that they did overflow. i.e.
+ */
+static inline int plus_overflow_u32 (grub_uint32_t x, grub_uint32_t y)
+{
+ return ((((grub_uint32_t)(~0)) - x) < y);
+}
+
+static struct grub_txt_acm_info_table*
+get_acmod_info_table (struct grub_txt_acm_header* hdr)
+{
+ grub_uint32_t user_area_off;
+
+ /* Overflow? */
+ if ( plus_overflow_u32 (hdr->header_len, hdr->scratch_size) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM header length plus scratch size overflows"));
+ return NULL;
+ }
+
+ if ( multiply_overflow_u32 ((hdr->header_len + hdr->scratch_size), 4) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM header length and scratch size in bytes overflows"));
+ return NULL;
+ }
+
+ /*
+ * This fn assumes that the ACM has already passed at least the initial
+ * is_acmod() checks.
+ */
+
+ user_area_off = (hdr->header_len + hdr->scratch_size) * 4;
+
+ /* Overflow? */
+ if ( plus_overflow_u32 (user_area_off, sizeof(struct grub_txt_acm_info_table)) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("user_area_off plus acm_info_table_t size overflows"));
+ return NULL;
+ }
+
+ /* Check that table is within module. */
+ if ( user_area_off + sizeof(struct grub_txt_acm_info_table) > hdr->size * 4 )
+ {
+ /* TODO: Is (grub_uint32_t) correct??? */
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM info table size too large: %x > %x"),
+ user_area_off + (grub_uint32_t)sizeof(struct grub_txt_acm_info_table), hdr->size * 4);
+ return NULL;
+ }
+
+ /* Overflow? */
+ if ( plus_overflow_u32 ((grub_uint32_t)(unsigned long)hdr, user_area_off) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("hdr plus user_area_off overflows"));
+ return NULL;
+ }
+
+ return (struct grub_txt_acm_info_table *)((unsigned long)hdr + user_area_off);
+}
+
+static struct grub_txt_acm_chipset_id_list*
+get_acmod_chipset_list (struct grub_txt_acm_header *hdr)
+{
+ struct grub_txt_acm_info_table *info_table;
+ grub_uint32_t size, id_list_off;
+ struct grub_txt_acm_chipset_id_list *chipset_id_list;
+
+ /* This fn assumes that the ACM has already passed the is_acmod() checks */
+
+ info_table = get_acmod_info_table (hdr);
+ if ( !info_table )
+ return NULL;
+ id_list_off = info_table->chipset_id_list;
+
+ size = hdr->size * 4;
+
+ /* Overflow? */
+ if ( plus_overflow_u32 (id_list_off, sizeof(struct grub_txt_acm_chipset_id)) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("id_list_off plus acm_chipset_id_t size overflows"));
+ return NULL;
+ }
+
+ /* Check that chipset id table is w/in ACM */
+ if ( id_list_off + sizeof(struct grub_txt_acm_chipset_id) > size )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("chipset id list is too big: %x"), id_list_off);
+ return NULL;
+ }
+
+ /* Overflow? */
+ if ( plus_overflow_u32 ((grub_uint32_t)(unsigned long)hdr, id_list_off) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("hdr plus id_list_off overflows"));
+ return NULL;
+ }
+
+ chipset_id_list = (struct grub_txt_acm_chipset_id_list*)
+ ((unsigned long)hdr + id_list_off);
+
+ /* Overflows? */
+ if ( multiply_overflow_u32 (chipset_id_list->count,
+ sizeof(struct grub_txt_acm_chipset_id)) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("size of acm_chipset_id_list overflows"));
+ return NULL;
+ }
+
+ if ( plus_overflow_u32 (id_list_off + sizeof(struct grub_txt_acm_chipset_id),
+ chipset_id_list->count * sizeof(struct grub_txt_acm_chipset_id)) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("size of all entries overflows"));
+ return NULL;
+ }
+
+ /* Check that all entries are w/in ACM */
+ if ( id_list_off + sizeof(struct grub_txt_acm_chipset_id) +
+ chipset_id_list->count * sizeof(struct grub_txt_acm_chipset_id) > size )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM chipset id entries are too big: %x"),
+ chipset_id_list->count);
+ return NULL;
+ }
+
+ return chipset_id_list;
+}
+
+static struct grub_txt_acm_processor_id_list*
+get_acmod_processor_list (struct grub_txt_acm_header* hdr)
+{
+ struct grub_txt_acm_info_table *info_table;
+ grub_uint32_t size, id_list_off;
+ struct grub_txt_acm_processor_id_list *proc_id_list;
+
+ /* This fn assumes that the ACM has already passed the is_acmod() checks */
+
+ info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL )
+ return NULL;
+ id_list_off = info_table->processor_id_list;
+
+ size = hdr->size * 4;
+
+ /* Overflow? */
+ if ( plus_overflow_u32 (id_list_off, sizeof(struct grub_txt_acm_processor_id)) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("id_list_off plus acm_processor_id_t size overflows"));
+ return NULL;
+ }
+
+ /* Check that processor id table is w/in ACM */
+ if ( id_list_off + sizeof(struct grub_txt_acm_processor_id) > size )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM processor id list is too big: %x"), id_list_off);
+ return NULL;
+ }
+
+ /* Overflow? */
+ if ( plus_overflow_u32 ((unsigned long)hdr, id_list_off) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("hdr plus id_list_off overflows"));
+ return NULL;
+ }
+
+ proc_id_list = (struct grub_txt_acm_processor_id_list *)
+ ((unsigned long)hdr + id_list_off);
+
+ /* Overflows? */
+ if ( multiply_overflow_u32 (proc_id_list->count,
+ sizeof(struct grub_txt_acm_processor_id)) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("size of acm_processor_id_list overflows"));
+ return NULL;
+ }
+
+ if ( plus_overflow_u32 (id_list_off + sizeof(struct grub_txt_acm_processor_id),
+ proc_id_list->count * sizeof(struct grub_txt_acm_processor_id)) )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("size of all entries overflows"));
+ return NULL;
+ }
+
+ /* Check that all entries are w/in ACM */
+ if ( id_list_off + sizeof(struct grub_txt_acm_processor_id) +
+ proc_id_list->count * sizeof(struct grub_txt_acm_processor_id) > size )
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM processor id entries are too big: %x"),
+ proc_id_list->count);
+ return NULL;
+ }
+
+ return proc_id_list;
+}
+
+static int
+is_acmod (const void *acmod_base, grub_uint32_t acmod_size,
+ grub_uint8_t *type_out)
+{
+ struct grub_txt_acm_header *acm_hdr = (struct grub_txt_acm_header *)acmod_base;
+ struct grub_txt_acm_info_table *info_table;
+
+ /* First check size */
+ if ( acmod_size < sizeof (struct grub_txt_acm_header) )
+ return 0;
+
+ /* Then check overflow */
+ if ( multiply_overflow_u32 (acm_hdr->size, 4) )
+ return 0;
+
+ /* Then check size equivalency */
+ if ( acmod_size != acm_hdr->size * 4 )
+ return 0;
+
+ /* Then check type and vendor */
+ if ( (acm_hdr->module_type != GRUB_TXT_ACM_MODULE_TYPE) ||
+ (acm_hdr->module_vendor != GRUB_TXT_ACM_MODULE_VENDOR_INTEL) )
+ return 0;
+
+ info_table = get_acmod_info_table (acm_hdr);
+ if ( !info_table )
+ return 0;
+
+ /* Check if ACM UUID is present */
+ if ( grub_memcmp (&(info_table->uuid), GRUB_TXT_ACM_UUID, 16) )
+ return 0;
+
+ if ( type_out )
+ *type_out = info_table->chipset_acm_type;
+
+ return 1;
+}
+
+static struct grub_txt_acm_header*
+get_bios_sinit (void *sinit_region_base)
+{
+ grub_uint8_t *txt_heap = grub_txt_get_heap ();
+ struct grub_txt_bios_data *bios_data = grub_txt_bios_data_start (txt_heap);
+ struct grub_txt_acm_header *bios_sinit;
+
+ if ( !sinit_region_base )
+ return NULL;
+
+ if ( bios_data->bios_sinit_size == 0 )
+ return NULL;
+
+ /* BIOS has loaded an SINIT module, so verify that it is valid */
+ grub_dprintf ("slaunch", "BIOS has already loaded an SINIT module\n");
+
+ bios_sinit = (struct grub_txt_acm_header *)sinit_region_base;
+
+ /* Is it a valid SINIT module? */
+ if ( !grub_txt_is_sinit_acmod (sinit_region_base, bios_data->bios_sinit_size) ||
+ !grub_txt_acmod_match_platform (bios_sinit) )
+ return NULL;
+
+ return bios_sinit;
+}
+
+grub_uint32_t
+grub_txt_supported_os_sinit_data_ver (struct grub_txt_acm_header* hdr)
+{
+ static struct grub_txt_acm_info_table *info_table;
+
+ /* Assumes that it passed is_sinit_acmod() */
+ info_table = get_acmod_info_table (hdr);
+
+ if ( info_table == NULL )
+ return 0;
+
+ return info_table->os_sinit_data_ver;
+}
+
+grub_uint32_t
+grub_txt_get_sinit_capabilities (struct grub_txt_acm_header* hdr)
+{
+ static struct grub_txt_acm_info_table *info_table;
+
+ /* Assumes that it passed is_sinit_acmod() */
+ info_table = get_acmod_info_table (hdr);
+
+ if ( info_table == NULL || info_table->version < 3 )
+ return 0;
+
+ return info_table->capabilities;
+}
+
+int
+grub_txt_is_sinit_acmod (const void *acmod_base, grub_uint32_t acmod_size)
+{
+ grub_uint8_t type;
+
+ if ( !is_acmod (acmod_base, acmod_size, &type) )
+ return 0;
+
+ if ( type != GRUB_TXT_ACM_CHIPSET_TYPE_SINIT )
+ return 0;
+
+ return 1;
+}
+
+/* Format of VER.FSBIF and VER.QPIIF registers. */
+typedef union {
+ grub_uint64_t _raw;
+ struct {
+ grub_uint64_t reserved : 31;
+ grub_uint64_t prod_fused : 1;
+ };
+} grub_txt_ver_fsbif_qpiif_t;
+
+int
+grub_txt_acmod_match_platform (struct grub_txt_acm_header *hdr)
+{
+ union grub_txt_didvid didvid;
+ grub_uint32_t fms, ign, i;
+ grub_uint64_t platform_id;
+ grub_txt_ver_fsbif_qpiif_t ver;
+ struct grub_txt_acm_chipset_id_list *chipset_id_list;
+ struct grub_txt_acm_chipset_id *chipset_id;
+ struct grub_txt_acm_processor_id_list *proc_id_list;
+ struct grub_txt_acm_processor_id *proc_id;
+ struct grub_txt_acm_info_table *info_table;
+
+ /* This fn assumes that the ACM has already passed the is_acmod() checks */
+
+ /* Get chipset fusing, device, and vendor id info */
+ didvid.value = grub_txt_reg_pub_readq (GRUB_TXT_DIDVID);
+
+ ver._raw = grub_txt_reg_pub_readq (GRUB_TXT_VER_FSBIF);
+ if ( (ver._raw & 0xffffffff) == 0xffffffff ||
+ (ver._raw & 0xffffffff) == 0x00 ) /* Need to use VER.QPIIF */
+ ver._raw = grub_txt_reg_pub_readq (GRUB_TXT_VER_QPIIF);
+
+ grub_dprintf ("slaunch", "chipset production fused: %x, "
+ "chipset vendor: 0x%x, device: 0x%x, revision: 0x%x\n",
+ ver.prod_fused, didvid.vid, didvid.did, didvid.rid);
+
+ grub_cpuid (1, fms, ign, ign, ign);
+ platform_id = grub_rdmsr (GRUB_MSR_X86_PLATFORM_ID);
+
+ grub_dprintf ("slaunch", "processor family/model/stepping: 0x%x, "
+ "platform id: 0x%" PRIxGRUB_UINT64_T "\n", fms, platform_id);
+
+ /*
+ * Check if chipset fusing is same. Note the DEBUG.FUSE bit in the version
+ * is 0 when debug fused so the logic below checking a mismatch is valid.
+ */
+ if ( (ver._raw & GRUB_TXT_VERSION_DEBUG_FUSED) &&
+ (hdr->flags & GRUB_TXT_ACM_FLAG_DEBUG_SIGNED) )
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("production/debug mismatch between chipset and ACM"));
+ return 0;
+ }
+
+ /* Check if chipset vendor/device/revision IDs match */
+ chipset_id_list = get_acmod_chipset_list (hdr);
+ if ( !chipset_id_list )
+ return 0;
+
+ grub_dprintf ("slaunch", "%d SINIT ACM chipset id entries:\n", chipset_id_list->count);
+
+ chipset_id = (struct grub_txt_acm_chipset_id *) ((grub_addr_t)chipset_id_list + sizeof (chipset_id_list->count));
+ for (i = 0; i < chipset_id_list->count; i++, chipset_id++)
+ {
+ grub_dprintf ("slaunch", " vendor: 0x%x, device: 0x%x, flags: 0x%x, "
+ "revision: 0x%x, extended: 0x%x\n", chipset_id->vendor_id,
+ chipset_id->device_id, chipset_id->flags,
+ chipset_id->revision_id, chipset_id->extended_id);
+
+ if ( (didvid.vid == chipset_id->vendor_id ) &&
+ (didvid.did == chipset_id->device_id ) &&
+ ( ( ( (chipset_id->flags & GRUB_TXT_ACM_REVISION_ID_MASK) == 0) &&
+ (didvid.rid == chipset_id->revision_id) ) ||
+ ( ( (chipset_id->flags & GRUB_TXT_ACM_REVISION_ID_MASK) == 1) &&
+ ( (didvid.rid & chipset_id->revision_id) != 0 ) ) ) )
+ break;
+ }
+
+ if ( i >= chipset_id_list->count )
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("chipset id mismatch"));
+ return 0;
+ }
+
+ /* Check if processor family/model/stepping and platform IDs match */
+ info_table = get_acmod_info_table (hdr);
+ if ( !info_table )
+ return 0;
+
+ /*
+ * Logic inverted from oringal to avoid the if block. Not sure what drives
+ * the logic of not checking processor infrmation for version 4 or less.
+ */
+ if ( info_table->version < 4 )
+ return 1;
+
+ proc_id_list = get_acmod_processor_list(hdr);
+ if ( !proc_id_list )
+ return 1;
+
+ grub_dprintf ("slaunch", "%d SINIT ACM processor id entries:\n", proc_id_list->count);
+
+ proc_id = (struct grub_txt_acm_processor_id *) ((grub_addr_t)proc_id_list + sizeof (proc_id_list->count));
+ for (i = 0; i < proc_id_list->count; i++, proc_id++)
+ {
+ grub_dprintf ("slaunch", " fms: 0x%x, fms_mask: 0x%x, platform_id: 0x%" PRIxGRUB_UINT64_T
+ ", platform_mask: 0x%" PRIxGRUB_UINT64_T "\n", proc_id->fms, proc_id->fms_mask,
+ proc_id->platform_id, proc_id->platform_mask);
+
+ if ( (proc_id->fms == (fms & proc_id->fms_mask)) &&
+ (proc_id->platform_id == (platform_id & proc_id->platform_mask)) )
+ break;
+ }
+
+ if ( i >= proc_id_list->count )
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("chipset id mismatch"));
+ return 0;
+ }
+
+ return 1;
+}
+
+struct grub_txt_acm_header *
+grub_txt_sinit_select (struct grub_txt_acm_header *sinit)
+{
+ struct grub_txt_acm_header *bios_sinit;
+ void *sinit_region_base;
+ grub_uint32_t sinit_region_size;
+
+ sinit_region_base = (void *)(grub_addr_t) grub_txt_reg_pub_readq (GRUB_TXT_SINIT_BASE);
+ sinit_region_size = (grub_uint32_t) grub_txt_reg_pub_readq (GRUB_TXT_SINIT_SIZE);
+
+ grub_dprintf ("slaunch", "TXT.SINIT.BASE: %p\nTXT.SINIT.SIZE: 0x%"
+ PRIxGRUB_UINT32_T "\n", sinit_region_base, sinit_region_size);
+
+ if (sinit_region_base == NULL)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("no SINIT ACM final resting place"));
+ return NULL;
+ }
+
+ if (sinit != NULL)
+ grub_dprintf ("slaunch", "SINIT ACM date: %" PRIxGRUB_UINT32_T "\n", sinit->date);
+
+ bios_sinit = get_bios_sinit (sinit_region_base);
+
+ /* Does BIOS provide SINIT ACM? */
+ if (bios_sinit != NULL)
+ {
+ grub_dprintf ("slaunch", "BIOS SINIT ACM date: %" PRIxGRUB_UINT32_T "\n",
+ bios_sinit->date);
+
+ if (sinit == NULL)
+ {
+ grub_dprintf ("slaunch", "no SINIT ACM provided. Using BIOS SINIT ACM\n");
+ return bios_sinit;
+ }
+
+ if (bios_sinit->date >= sinit->date)
+ {
+ grub_dprintf ("slaunch", "BIOS provides newer or same SINIT ACM, so, using BIOS one\n");
+ return bios_sinit;
+ }
+
+ grub_dprintf ("slaunch", "BIOS provides older SINIT ACM, so, ignoring BIOS one\n");
+ }
+
+ /* Fail if there is no SINIT ACM. */
+ if (sinit == NULL)
+ return NULL;
+
+ /* Our SINIT ACM is newer than BIOS one or BIOS does not have one. */
+
+ if (multiply_overflow_u32 (sinit->size, 4))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("SINIT ACM size in bytes overflows"));
+ return NULL;
+ }
+
+ if ((sinit->size * 4) > sinit_region_size)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ N_("SINIT ACM does not fit into final resting place: 0x%"
+ PRIxGRUB_UINT32_T "\n"), sinit->size * 4);
+ return NULL;
+ }
+
+ grub_memcpy (sinit_region_base, sinit, sinit->size * 4);
+
+ return sinit_region_base;
+}
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:31 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Daniel Kiper <daniel...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/slaunch/verify.c | 297 ++++++++++++++++++++++++++++++
1 file changed, 297 insertions(+)
create mode 100644 grub-core/loader/slaunch/verify.c

diff --git a/grub-core/loader/slaunch/verify.c b/grub-core/loader/slaunch/verify.c
new file mode 100644
index 000000000..9f488355f
--- /dev/null
+++ b/grub-core/loader/slaunch/verify.c
@@ -0,0 +1,297 @@
+/*
+ * verify.c: verify that platform and processor supports Intel(r) TXT
+ *
+ * Copyright (c) 2003-2010, Intel Corporation
+/* Current max that the secure launch can handle */
+#define TXT_MAX_CPUS 512
+
+static grub_err_t
+verify_bios_spec_ver_elt (struct grub_txt_heap_ext_data_element *elt)
+{
+ grub_uint8_t *ptr = (grub_uint8_t *)elt;
+ struct grub_txt_heap_bios_spec_ver_element *bios_spec_ver_elt =
+ (struct grub_txt_heap_bios_spec_ver_element *)ptr;
+
+ if ( elt->size != sizeof(*elt) + sizeof(*bios_spec_ver_elt) )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_BIOS_SPEC_VER element has wrong size (%d)"),
+ elt->size);
+
+ /* Any values are allowed */
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+verify_acm_elt (struct grub_txt_heap_ext_data_element *elt)
+{
+ grub_uint8_t *ptr = ((grub_uint8_t *)elt + sizeof(*elt));
+ struct grub_txt_heap_acm_element *acm_elt =
+ (struct grub_txt_heap_acm_element *)ptr;
+ grub_uint64_t *acm_addrs;
+ grub_uint32_t i;
+
+ if ( elt->size != sizeof(*elt) + sizeof(*acm_elt) +
+ acm_elt->num_acms*sizeof(grub_uint64_t) )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_ACM element has wrong size (%d)"),
+ elt->size);
+
+ /* No addrs is not error, but print warning. */
+ if ( acm_elt->num_acms == 0 )
+ grub_printf ("WARNING: HEAP_ACM element has no ACM addrs\n");
+
+ acm_addrs = (grub_uint64_t *)(ptr + sizeof(*acm_elt));
+ for ( i = 0; i < acm_elt->num_acms; i++ )
+ {
+ if ( acm_addrs[i] == 0 )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_ACM element ACM addr (%d) is NULL"), i);
+
+ if ( acm_addrs[i] >= 0x100000000UL )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_ACM element ACM addr (%d) is >4GB"), i);
+
+ /* Not going to check if ACM addrs are valid ACMs */
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+verify_custom_elt (struct grub_txt_heap_ext_data_element *elt)
+{
+ grub_uint8_t *ptr = (grub_uint8_t *)elt;
+ struct grub_txt_heap_custom_element *custom_elt =
+ (struct grub_txt_heap_custom_element *)ptr;
+
+ if ( elt->size < sizeof(*elt) + sizeof(*custom_elt) )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_CUSTOM element has wrong size (%d)"),
+ elt->size);
+
+ /* Any values are allowed */
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+verify_evt_log_ptr_elt (struct grub_txt_heap_ext_data_element *elt)
+{
+ grub_uint8_t *ptr = (grub_uint8_t *)elt;
+ struct grub_txt_heap_tpm_event_log_element *elog_elt =
+ (struct grub_txt_heap_tpm_event_log_element *)ptr;
+
+ if ( elt->size != sizeof(*elt) + sizeof(*elog_elt) )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("HEAP_EVENT_LOG_POINTER element has wrong size (%d)"),
+ elt->size);
+
+ /* TODO: Sort out how to do this verifier once the event log handling is in place
+ *
+ * return verify_evt_log((event_log_container_t *)(unsigned long)
+ * elog_elt->event_log_phys_addr);
+ */
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+verify_ext_data_elts(struct grub_txt_heap_ext_data_element *elts,
+ grub_uint64_t elts_size)
+{
+ struct grub_txt_heap_ext_data_element *elt = elts;
+ grub_err_t err;
+
+ if ( elts_size < sizeof(*elt) )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("TXT heap ext data elements too small"));
+
+ for ( ; ; )
+ {
+ if ( elts_size < elt->size || elt->size == 0 )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("TXT heap invalid element size: type: %d, size: %d"),
+ elt->type, elt->size);
+
+ switch ( elt->type )
+ {
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_END:
+ return GRUB_ERR_NONE;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_BIOS_SPEC_VER:
+ err = verify_bios_spec_ver_elt (elt);
+ if ( err )
+ return err;
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_ACM:
+ err = verify_acm_elt (elt);
+ if ( err )
+ return err;
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_STM:
+ /* Nothing to check, platform specific */
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_CUSTOM:
+ err = verify_custom_elt (elt);
+ if ( err )
+ return err;
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR:
+ err = verify_evt_log_ptr_elt (elt);
+ if ( err )
+ return err;
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_MADT:
+ /* Copy of ACPI MADT, not validating */
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1:
+ /* TODO TBOOT did not verify this, not sure why or how to do it */
+ break;
+ case GRUB_TXT_HEAP_EXTDATA_TYPE_MCFG:
+ /* Copy of ACPI MCFG, not validating */
+ break;
+ default:
+ /* TODO: What kind of element??? Improve the message. */
+ grub_printf ("WARNING: unknown element: type: %u, size: %u\n", elt->type, elt->size);
+ break;
+ }
+
+ elts_size -= elt->size;
+ elt = (struct grub_txt_heap_ext_data_element *)((grub_uint8_t *)elt + elt->size);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_txt_verify_platform (void)
+{
+ grub_uint8_t *txt_heap;
+ grub_uint32_t eax, ebx, ecx, edx;
+ grub_uint64_t bios_size, heap_base, heap_size, msr;
+ grub_err_t err = GRUB_ERR_NONE;
+ struct grub_txt_bios_data *bios_data;
+ struct grub_txt_heap_ext_data_element *elts;
+
+ grub_cpuid (GRUB_X86_CPUID_FEATURES, eax, ebx, ecx, edx);
+
+ if (!(ecx & GRUB_SMX_CPUID_FEATURE))
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("CPU does not support SMX"));
+
+ msr = grub_rdmsr (GRUB_MSR_X86_FEATURE_CONTROL);
+
+ if ((msr & (GRUB_MSR_X86_SENTER_FUNCTIONS | GRUB_MSR_X86_SENTER_ENABLE)) !=
+ (GRUB_MSR_X86_SENTER_FUNCTIONS | GRUB_MSR_X86_SENTER_ENABLE))
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("GETSEC[SENTER] is not enabled"));
+
+ /*
+ * TODO
+ * TXT Specification
+ * 4.5 SGX Requirement for TXT Platform
+ * Secure Launch currently does not support interop with SGX since it does
+ * not have TPM support to write the SE NVRAM index.
+ * Eventually need the verify_IA32_se_svn_status routine to be called here.
+ */
+
+ if (grub_txt_reg_pub_readq (GRUB_TXT_ESTS) & GRUB_TXT_ESTS_TXT_RESET)
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("TXT_RESET.STS is set and GETSEC[SENTER] is disabled"));
+
+ /*
+ * Verify that the BIOS information in the TXT heap that was setup by the
+ * BIOS ACM is sane.
+ */
+
+ txt_heap = grub_txt_get_heap ();
+ heap_base = grub_txt_reg_pub_readq (GRUB_TXT_HEAP_BASE);
+ heap_size = grub_txt_reg_pub_readq (GRUB_TXT_HEAP_SIZE);
+
+ if ( txt_heap == NULL || heap_base == 0 || heap_size == 0 )
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("TXT heap is not configured correctly"));
+
+ bios_size = grub_txt_bios_data_size (txt_heap);
+ if ( bios_size == 0 || bios_size > heap_size )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("invalid size of the TXT heap BIOS data table"));
+
+ bios_data = grub_txt_bios_data_start (txt_heap);
+
+ /* Check version */
+ if ( bios_data->version < 3 )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("unsupported BIOS data version (%d)"), bios_data->version);
+
+ if ( bios_data->num_logical_procs > TXT_MAX_CPUS )
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("BIOS reports too many CPUs for secure launch (%d)"),
+ bios_data->num_logical_procs);
+
+ if ( bios_data->version >= 4 && bios_size > sizeof(*bios_data) + sizeof(bios_size) )
+ {
+ elts = (struct grub_txt_heap_ext_data_element *) ((grub_uint8_t *)bios_data + sizeof(*bios_data));
+ err = verify_ext_data_elts(elts, bios_size - sizeof(*bios_data));
+ }
+
+ return err;
+}
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:33 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/efi/dltrampoline.S | 94 +++++++++++++++++++++++++++++
grub-core/loader/slaunch/dlstub.c | 93 ++++++++++++++++++++++++++++
2 files changed, 187 insertions(+)
create mode 100644 grub-core/loader/efi/dltrampoline.S
create mode 100644 grub-core/loader/slaunch/dlstub.c

diff --git a/grub-core/loader/efi/dltrampoline.S b/grub-core/loader/efi/dltrampoline.S
new file mode 100644
index 000000000..461e14271
--- /dev/null
+++ b/grub-core/loader/efi/dltrampoline.S
@@ -0,0 +1,94 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <grub/symbol.h>
+
+#define GRUB_SMX_LEAF_SENTER 4
+#define CS_SEL32 0x0008
+#define DS_SEL 0x0010
+
+#define CR0_PE 0x00000001
+#define CR0_MP 0x00000002
+#define CR0_TS 0x00000008
+#define CR0_NE 0x00000020
+
+ .file "dltrampoline.S"
+ .text
+
+ .code64
+ .globl dl_entry_trampoline
+dl_entry_trampoline:
+ /* %edi should contain dl_context pointer */
+ call EXT_C(dl_entry)
+ ud2
+
+ .globl dl_trampoline
+dl_trampoline:
+ cli
+ leaq dl_gdt_base(%rip), %rax
+ leaq dl_gdt(%rip), %rbx
+ movl %ebx, (%eax)
+ lgdt dl_gdtr(%rip)
+
+ /* Setup target to ret to compat mode */
+ leal 1f(%rip), %ecx
+ pushq $CS_SEL32
+ pushq %rcx
+ lretq
+
+ .code32
+1: /* Now in IA-32e compatibility mode load data segments and do senter */
+ movw $DS_SEL, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+ movl $GRUB_SMX_LEAF_SENTER, %eax
+ movl %edi, %ebx
+ movl %esi, %ecx
+ xorl %edx, %edx
+ getsec
+
+ .align 8
+dl_gdt:
+ /* Null Segment */
+ .quad 0
+ /* 32b Code Segment */
+ .word 0xffff /* Limit 1 */
+ .word 0x0000 /* Base 1 */
+ .byte 0x00 /* Base 2 */
+ .byte 0x9b /* P=1 DPL=0 S=1 Type=0010 C=0 W=1 A=1 */
+ .byte 0xcf /* G=1 D=1 L=0 AVL=0 Limit 2 */
+ .byte 0x00 /* Base 3 */
+ /* Data Segment, can be used both in 32b and 64b */
+ .word 0xffff /* Limit 1 */
+ .word 0x0000 /* Base 1 */
+ .byte 0x00 /* Base 2 */
+ .byte 0x93 /* P=1 DPL=0 S=1 Type=0010 C=0 W=1 A=1 */
+ .byte 0xcf /* G=1 D=1 L=0 AVL=0 Limit 2 */
+ .byte 0x00 /* Base 3 */
+
+ .word 0
+dl_gdtr:
+ .word 23 /* Limit */
+dl_gdt_base:
+ .long 0 /* Base */
+ .long 0
diff --git a/grub-core/loader/slaunch/dlstub.c b/grub-core/loader/slaunch/dlstub.c
new file mode 100644
index 000000000..d3c28645e
--- /dev/null
+++ b/grub-core/loader/slaunch/dlstub.c
@@ -0,0 +1,93 @@
+#include <grub/cpu/relocator.h>
+#include <grub/i386/msr.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/txt.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+extern void dl_trampoline(grub_uint32_t dce_base, grub_uint32_t dce_size);
+
+void dl_entry (grub_uint64_t dl_ctx)
+{
+ struct grub_slr_bl_context *bl_ctx = (struct grub_slr_bl_context *)(grub_addr_t)dl_ctx;
+ struct grub_slaunch_params *slparams = (struct grub_slaunch_params *)(grub_addr_t)bl_ctx->context;
+ struct grub_relocator32_state state = {0};
+ grub_err_t err;
+
+ state.edi = slparams->platform_type;
+
+ if (slparams->platform_type == SLP_INTEL_TXT)
+ {
+ if (slparams->boot_type == GRUB_SL_BOOT_TYPE_EFI)
+ grub_update_slrt_policy (slparams);
+
+ err = grub_set_mtrrs_for_acmod ((void *)(grub_addr_t)slparams->dce_base);
+ if (err)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("setting MTRRs for TXT SINIT failed"));
+ return;
+ }
+
+ err = grub_txt_prepare_cpu ();
+ if ( err )
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("prepare CPU for TXT SENTER failed"));
+ return;
+ }
+ }
+ else
+ {
+ grub_error (GRUB_ERR_BUG, N_("unknown dynamic launch platform: %d"), slparams->platform_type);
+ return;
+ }
+
+ if (!(grub_rdmsr (GRUB_MSR_X86_APICBASE) & GRUB_MSR_X86_APICBASE_BSP))
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("x86 dynamic launch event must be performed on the BSP"));
+ return;
+ }
+
+ if (slparams->boot_type == GRUB_SL_BOOT_TYPE_LINUX)
+ {
+ /* Configure relocator GETSEC[SENTER] call. */
+ state.eax = GRUB_SMX_LEAF_SENTER;
+ state.ebx = slparams->dce_base;
+ state.ecx = slparams->dce_size;
+ state.edx = 0;
+ grub_relocator32_boot (slparams->relocator, state, 0);
+ }
+ else if (slparams->boot_type == GRUB_SL_BOOT_TYPE_EFI)
+ {
+ dl_trampoline (slparams->dce_base, slparams->dce_size);
+ }
+ else
+ {
+ grub_error (GRUB_ERR_BUG, N_("unknown dynamic launch boot type: %d"), slparams->boot_type);
+ }
+}
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:37 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Fedora Ninjas <grub2...@fedoraproject.org>

The usage looks as follows:

# Enable secure launch (required and must come before other slaunch
# commands).
slaunch

# Specify the startup binary for DRTM. This is optional on Intel if
# BIOS has already loaded ACM. There can be multiple such commands
# with the last valid one taking effect (the invalid files print an
# error message but are otherwise ignored).
slaunch_module /some/file

# Prints current status of ACM for debugging purposes.
slaunch_state

# Specify kernel/initrd and boot as usual.

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Daniel Kiper <daniel...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
docs/grub.texi | 9 ++
grub-core/Makefile.core.def | 13 ++
grub-core/lib/i386/relocator32.S | 8 +
grub-core/loader/i386/bsd.c | 3 +
grub-core/loader/i386/linux.c | 87 +++++++++-
grub-core/loader/i386/xnu.c | 2 +
grub-core/loader/multiboot.c | 2 +
grub-core/loader/slaunch/i386_linux.c | 220 ++++++++++++++++++++++++++
grub-core/loader/slaunch/slaunch.c | 204 ++++++++++++++++++++++++
include/grub/file.h | 3 +
include/grub/i386/linux.h | 14 +-
include/grub/slaunch.h | 15 ++
12 files changed, 573 insertions(+), 7 deletions(-)
create mode 100644 grub-core/loader/slaunch/i386_linux.c
create mode 100644 grub-core/loader/slaunch/slaunch.c

diff --git a/docs/grub.texi b/docs/grub.texi
index c0984e585..a2ae57cea 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4118,6 +4118,7 @@ Modules can be loaded via the @command{insmod} (@pxref{insmod}) command.
* sfs_module::
* shift_test_module::
* signature_test_module::
+* slaunch_module::
* sleep_module::
* sleep_test_module::
* smbios_module::
@@ -5603,6 +5604,11 @@ operations in GRUB.
This module is intended for performing a functional test of the digital
signature verification functions in GRUB.

+@node slaunch_module
+@section slaunch
+This module provides support for Secure Launch boot in a form of three commands:
+@command{slaunch}, @command{slaunch_module} and @command{slaunch_state}.
+
@node sleep_module
@section sleep
This module provides support for the @command{sleep} command to wait a specified
@@ -8426,6 +8432,9 @@ GRUB shell may provide more information on parameters and usage.
@item @command{read_dword} - Read 32-bit value from ADDR.
@item @command{read_word} - Read 16-bit value from ADDR.
@item @command{setpci} - Manipulate PCI devices.
+@item @command{slaunch} - Enable secure launcher.
+@item @command{slaunch_module} - Load secure launcher module from file.
+@item @command{slaunch_state} - Display secure launcher state.
@item @command{suspend} - Return to IEEE1275 prompt.
@item @command{syslinux_configfile} - Execute syslinux config in new context
@item @command{syslinux_source} - Execute syslinux config in same context
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 4bc2df614..327a8391b 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1875,6 +1875,19 @@ module = {
common = lib/cmdline.c;
};

+module = {
+ name = slaunch;
+ x86 = loader/slaunch/slaunch.c;
+ x86 = loader/slaunch/slrt.c;
+ x86 = loader/slaunch/txt.c;
+ x86 = loader/slaunch/acmod.c;
+ x86 = loader/slaunch/verify.c;
+ x86 = loader/slaunch/i386_linux.c;
+ x86 = loader/slaunch/dlstub.c;
+ x86 = loader/efi/dltrampoline.S;
+ enable = x86;
+};
+
module = {
name = fdt;
efi = loader/efi/fdt.c;
diff --git a/grub-core/lib/i386/relocator32.S b/grub-core/lib/i386/relocator32.S
index 09ce56ad0..25f162b0e 100644
--- a/grub-core/lib/i386/relocator32.S
+++ b/grub-core/lib/i386/relocator32.S
@@ -24,6 +24,8 @@

#include "relocator_common.S"

+#include <grub/slaunch.h>
+
.p2align 4 /* force 16-byte alignment */

VARIABLE(grub_relocator32_start)
@@ -110,11 +112,17 @@ VARIABLE(grub_relocator32_edx)
payload and makes this implementation easier. */
cld

+ cmpl $SLP_INTEL_TXT, %edi
+ je LOCAL(intel_txt)
+
.byte 0xea
VARIABLE(grub_relocator32_eip)
.long 0
.word CODE_SEGMENT

+LOCAL(intel_txt):
+ getsec
+
/* GDT. Copied from loader/i386/linux.c. */
.p2align 4
LOCAL(gdt):
diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c
index 1f9128f6f..41d768418 100644
--- a/grub-core/loader/i386/bsd.c
+++ b/grub-core/loader/i386/bsd.c
@@ -792,6 +792,7 @@ grub_freebsd_boot (void)
#endif

grub_memcpy (&stack[9], &bi, sizeof (bi));
+ state.edi = 0; /* Secure Launch not in progress */
state.eip = entry;
state.esp = stack_target;
state.ebp = stack_target;
@@ -907,6 +908,7 @@ grub_openbsd_boot (void)
return err;
#endif

+ state.edi = 0; /* Secure Launch not in progress */
state.eip = entry;
state.ebp = state.esp
= ((grub_uint8_t *) stack - (grub_uint8_t *) buf0) + buf_target;
@@ -1229,6 +1231,7 @@ grub_netbsd_boot (void)
return err;
#endif

+ state.edi = 0; /* Secure Launch not in progress */
state.eip = entry;
state.esp = stack_target;
state.ebp = stack_target;
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
index 26ed25427..2a74881fb 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -31,9 +31,13 @@
#include <grub/video.h>
#include <grub/video_fb.h>
#include <grub/command.h>
+#include <grub/slr_table.h>
+#include <grub/slaunch.h>
#include <grub/i386/relocator.h>
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/txt.h>
#include <grub/linux.h>
#include <grub/machine/kernel.h>
#include <grub/safemath.h>
@@ -69,6 +73,7 @@ static grub_size_t linux_mem_size;
static int loaded;
static void *prot_mode_mem;
static grub_addr_t prot_mode_target;
+static grub_size_t prot_file_size;
static void *initrd_mem;
static grub_addr_t initrd_mem_target;
static grub_size_t prot_init_space;
@@ -82,6 +87,7 @@ static grub_efi_uintn_t efi_mmap_size;
#else
static const grub_size_t efi_mmap_size = 0;
#endif
+static struct grub_slaunch_params slparams = {0};

/* FIXME */
#if 0
@@ -150,11 +156,25 @@ allocate_pages (grub_size_t prot_size, grub_size_t *align,
grub_uint64_t preferred_address)
{
grub_err_t err;
+ grub_size_t total_size;

if (prot_size == 0)
prot_size = 1;

- prot_size = page_align (prot_size);
+ if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+ {
+ err = grub_sl_txt_prepare_mle_ptab (&slparams, &prot_size, &preferred_address);
+ if (err)
+ goto fail;
+ }
+ else
+ {
+ prot_size = page_align (prot_size);
+ slparams.mle_ptab_size = 0;
+ }
+
+ total_size = prot_size + slparams.mle_ptab_size;
+

/* Initialize the memory pointers with NULL for convenience. */
free_pages ();
@@ -176,15 +196,15 @@ allocate_pages (grub_size_t prot_size, grub_size_t *align,
err = grub_relocator_alloc_chunk_align (relocator, &ch,
preferred_address,
preferred_address,
- prot_size, 1,
+ total_size, 1,
GRUB_RELOCATOR_PREFERENCE_LOW,
1);
for (; err && *align + 1 > min_align; (*align)--)
{
grub_errno = GRUB_ERR_NONE;
err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000,
- UP_TO_TOP32 (prot_size),
- prot_size, 1 << *align,
+ UP_TO_TOP32 (total_size),
+ total_size, 1 << *align,
GRUB_RELOCATOR_PREFERENCE_LOW,
1);
}
@@ -194,13 +214,21 @@ allocate_pages (grub_size_t prot_size, grub_size_t *align,
else
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
preferred_address,
- prot_size);
+ total_size);
if (err)
goto fail;
prot_mode_mem = get_virtual_current_address (ch);
prot_mode_target = get_physical_target_address (ch);
}

+ if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+ {
+ err = grub_sl_txt_setup_linux (&slparams, relocator, total_size, prot_size,
+ &prot_mode_mem, &prot_mode_target);
+ if (err)
+ goto fail;
+ }
+
grub_dprintf ("linux", "prot_mode_mem = %p, prot_mode_target = %lx, prot_size = %x\n",
prot_mode_mem, (unsigned long) prot_mode_target,
(unsigned) prot_size);
@@ -558,6 +586,12 @@ grub_linux_boot (void)
if (err)
return err;
real_mode_mem = get_virtual_current_address (ch);
+
+ if (grub_slaunch_platform_type () != SLP_NONE)
+ {
+ slparams.boot_params = real_mode_mem;
+ slparams.boot_params_base = get_physical_target_address (ch);
+ }
}
efi_mmap_buf = (grub_uint8_t *) real_mode_mem + ctx.real_size;

@@ -587,6 +621,8 @@ grub_linux_boot (void)

ctx.params->secure_boot = grub_efi_get_secureboot ();

+ grub_dprintf ("linux", "EFI exit boot services\n");
+
err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL,
&efi_desc_size, &efi_desc_version);
if (err)
@@ -624,6 +660,24 @@ grub_linux_boot (void)
}
#endif

+ if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+ {
+ struct grub_slr_table *slrt = (struct grub_slr_table *)slparams.slr_table_mem;
+ struct grub_slr_entry_dl_info *dlinfo;
+
+ slparams.platform_type = grub_slaunch_platform_type();
+
+ err = grub_txt_boot_prepare (&slparams);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ dlinfo = grub_slr_next_entry_by_tag (slrt, NULL, GRUB_SLR_ENTRY_DL_INFO);
+ dl_entry ((grub_uint64_t)(grub_addr_t)&dlinfo->bl_context);
+
+ /* If this returns, something failed miserably */
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
#if defined (__x86_64__) && defined (GRUB_MACHINE_EFI)
if (grub_le_to_cpu16 (ctx.params->version) >= 0x020c &&
(linux_params.xloadflags & LINUX_X86_XLF_KERNEL_64) != 0)
@@ -642,6 +696,7 @@ grub_linux_boot (void)
state.esi = ctx.real_mode_target;
state.esp = ctx.real_mode_target;
state.eip = ctx.params->code32_start;
+
return grub_relocator32_boot (relocator, state, 0);
}

@@ -662,7 +717,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_file_t file = 0;
struct linux_i386_kernel_header lh;
grub_uint8_t setup_sects;
- grub_size_t real_size, prot_size, prot_file_size;
+ grub_size_t real_size, prot_size;
grub_ssize_t len;
int i;
grub_size_t align, min_align;
@@ -772,6 +827,19 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
prot_init_space = page_align (prot_size) * 3;
}

+ grub_dprintf ("linux", "before align=%d, min_align=%d\n",
+ (int)align, (int)min_align);
+
+ if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+ {
+ /* PMRs require GRUB_TXT_PMR_ALIGN_SHIFT aligments. */
+ min_align = grub_max (min_align, GRUB_TXT_PMR_ALIGN_SHIFT);
+ align = grub_max (align, GRUB_TXT_PMR_ALIGN_SHIFT);
+ }
+
+ grub_dprintf ("linux", "after align=%d, min_align=%d\n",
+ (int)align, (int)min_align);
+
if (allocate_pages (prot_size, &align,
min_align, relocatable,
preferred_address))
@@ -779,6 +847,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),

grub_memset (&linux_params, 0, sizeof (linux_params));

+ if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+ grub_txt_setup_mle_ptab (&slparams);
+
/*
* The Linux 32-bit boot protocol defines the setup header end
* to be at 0x202 + the byte value at 0x201.
@@ -805,6 +876,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}

+ /* Read the kernel_info struct. */
+ if (grub_sl_find_kernel_info (&slparams, file, &lh, real_size))
+ goto fail;
+
linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
linux_params.kernel_alignment = (1 << align);
linux_params.ps_mouse = linux_params.padding11 = 0;
diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c
index b91e2f840..b04c1931d 100644
--- a/grub-core/loader/i386/xnu.c
+++ b/grub-core/loader/i386/xnu.c
@@ -802,6 +802,7 @@ grub_xnu_boot_resume (void)
{
struct grub_relocator32_state state = {0};

+ state.edi = 0; /* Secure Launch not in progress */
state.esp = grub_xnu_stack;
state.ebp = grub_xnu_stack;
state.eip = grub_xnu_entry_point;
@@ -1129,6 +1130,7 @@ grub_xnu_boot (void)
grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size,
descriptor_version, memory_map);

+ state.edi = 0; /* Secure Launch not in progress */
state.eip = grub_xnu_entry_point;
state.eax = grub_xnu_arg1;
state.esp = grub_xnu_stack;
diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c
index 36b27a906..ec29f1b58 100644
--- a/grub-core/loader/multiboot.c
+++ b/grub-core/loader/multiboot.c
@@ -161,6 +161,8 @@ efi_boot (struct grub_relocator *rel __attribute__ ((unused)),
static void
normal_boot (struct grub_relocator *rel, struct grub_relocator32_state state)
{
+ state.edi = 0; /* Secure Launch not in progress */
+
grub_relocator32_boot (rel, state, 0);
}
#else
diff --git a/grub-core/loader/slaunch/i386_linux.c b/grub-core/loader/slaunch/i386_linux.c
new file mode 100644
index 000000000..770888f63
--- /dev/null
+++ b/grub-core/loader/slaunch/i386_linux.c
@@ -0,0 +1,220 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/loader.h>
+#include <grub/memory.h>
+#include <grub/normal.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/slr_table.h>
+#include <grub/slaunch.h>
+#include <grub/cpu/relocator.h>
+#include <grub/i386/msr.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/linux.h>
+#include <grub/i386/txt.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define OFFSET_OF(x, y) ((grub_size_t)((grub_uint8_t *)(&(y)->x) - (grub_uint8_t *)(y)))
+
+grub_err_t
+grub_sl_find_kernel_info (struct grub_slaunch_params *slparams, grub_file_t kernel_file,
+ struct linux_i386_kernel_header *lh, grub_size_t real_size)
+
+{
+ struct linux_kernel_info *linux_info;
+
+ /* Not a Secure Launch, do nothing */
+ if (grub_slaunch_platform_type () == SLP_NONE)
+ return GRUB_ERR_NONE;
+
+ if (grub_le_to_cpu16 (lh->version) < 0x020f)
+ {
+ grub_error (GRUB_ERR_BAD_OS, N_("not slaunch kernel: boot protocol too old"));
+ goto fail;
+ }
+
+
+ if (grub_file_seek (kernel_file, grub_le_to_cpu32 (lh->kernel_info_offset) +
+ real_size + GRUB_DISK_SECTOR_SIZE) == ((grub_off_t) -1))
+ goto fail;
+
+ linux_info = grub_malloc (GRUB_KERNEL_INFO_MIN_SIZE_TOTAL);
+
+ if (!linux_info)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate memory for kernel_info"));
+ goto fail;
+ }
+
+ /* Load minimal kernel_info struct. */
+ if (grub_file_read (kernel_file, linux_info,
+ GRUB_KERNEL_INFO_MIN_SIZE_TOTAL) != GRUB_KERNEL_INFO_MIN_SIZE_TOTAL)
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of kernel file"));
+ goto fail;
+ }
+
+ if (grub_memcmp (&linux_info->header, GRUB_KERNEL_INFO_HEADER, sizeof (linux_info->header)))
+ {
+ grub_error (GRUB_ERR_BAD_OS, N_("incorrect kernel_info header"));
+ goto fail;
+ }
+
+ linux_info->size_total = grub_le_to_cpu32 (linux_info->size_total);
+
+ linux_info = grub_realloc (linux_info, linux_info->size_total);
+
+ if (!linux_info)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot reallocate memory for kernel_info"));
+ goto fail;
+ }
+
+ /* Load the rest of kernel_info struct. */
+ if (grub_file_read (kernel_file, &linux_info->setup_type_max,
+ linux_info->size_total - GRUB_KERNEL_INFO_MIN_SIZE_TOTAL) !=
+ (grub_ssize_t)(linux_info->size_total - GRUB_KERNEL_INFO_MIN_SIZE_TOTAL))
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of kernel file"));
+ goto fail;
+ }
+
+ /* Fetch the MLE header offset so Secure Launch can locate it */
+ if (OFFSET_OF (mle_header_offset, linux_info) >= grub_le_to_cpu32 (linux_info->size))
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("not slaunch kernel: lack of mle_header_offset"));
+ goto fail;
+ }
+
+ slparams->mle_header_offset = grub_le_to_cpu32 (linux_info->mle_header_offset);
+
+ return GRUB_ERR_NONE;
+
+fail:
+ return grub_errno;
+}
+
+grub_err_t
+grub_sl_txt_prepare_mle_ptab (struct grub_slaunch_params *slparams, grub_size_t *prot_size,
+ grub_uint64_t *preferred_address)
+{
+ *prot_size = ALIGN_UP (*prot_size, GRUB_TXT_PMR_ALIGN);
+
+ if (*prot_size > GRUB_TXT_MLE_MAX_SIZE)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("slaunch kernel: protected size out of range"));
+ return GRUB_ERR_OUT_OF_RANGE;
+ }
+
+ slparams->mle_ptab_size = grub_txt_get_mle_ptab_size (*prot_size);
+ slparams->mle_ptab_size = ALIGN_UP (slparams->mle_ptab_size, GRUB_TXT_PMR_ALIGN);
+
+ /* Do not go below GRUB_TXT_PMR_ALIGN */
+ *preferred_address = (*preferred_address > slparams->mle_ptab_size) ?
+ (*preferred_address - slparams->mle_ptab_size) : GRUB_TXT_PMR_ALIGN;
+ *preferred_address = ALIGN_UP (*preferred_address, GRUB_TXT_PMR_ALIGN);
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_sl_txt_setup_linux (struct grub_slaunch_params *slparams, struct grub_relocator *relocator,
+ grub_size_t total_size, grub_size_t prot_size,
+ void **prot_mode_mem, grub_addr_t *prot_mode_target)
+{
+ grub_relocator_chunk_t ch;
+
+ slparams->boot_type = GRUB_SL_BOOT_TYPE_LINUX;
+ slparams->relocator = relocator;
+
+ /* Zero out memory to get stable MLE measurements. */
+ grub_memset (*prot_mode_mem, 0, total_size);
+
+ slparams->mle_ptab_mem = *prot_mode_mem;
+ slparams->mle_ptab_target = *prot_mode_target;
+
+ *prot_mode_mem = (char *)*prot_mode_mem + slparams->mle_ptab_size;
+ *prot_mode_target += slparams->mle_ptab_size;
+
+ slparams->mle_mem = *prot_mode_mem;
+ slparams->mle_start = *prot_mode_target;
+ slparams->mle_size = prot_size;
+
+ grub_dprintf ("linux", "mle_ptab_mem = %p, mle_ptab_target = %lx, mle_ptab_size = %x\n",
+ slparams->mle_ptab_mem, (unsigned long) slparams->mle_ptab_target,
+ (unsigned) slparams->mle_ptab_size);
+
+ if (grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000,
+ 0xffffffff - GRUB_PAGE_SIZE,
+ GRUB_PAGE_SIZE, GRUB_PAGE_SIZE,
+ GRUB_RELOCATOR_PREFERENCE_NONE, 1))
+ goto fail;
+
+ slparams->slr_table_base = get_physical_target_address (ch);
+ slparams->slr_table_size = GRUB_PAGE_SIZE;
+ slparams->slr_table_mem = get_virtual_current_address (ch);
+
+ grub_memset (slparams->slr_table_mem, 0, slparams->slr_table_size);
+
+ grub_dprintf ("linux", "slr_table_base = %lx, slr_table_size = %x\n",
+ (unsigned long) slparams->slr_table_base,
+ (unsigned) slparams->slr_table_size);
+
+ if (grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000,
+ 0xffffffff - GRUB_SLAUNCH_TPM_EVT_LOG_SIZE,
+ GRUB_SLAUNCH_TPM_EVT_LOG_SIZE, GRUB_PAGE_SIZE,
+ GRUB_RELOCATOR_PREFERENCE_NONE, 1))
+ goto fail;
+
+ slparams->tpm_evt_log_base = get_physical_target_address (ch);
+ slparams->tpm_evt_log_size = GRUB_SLAUNCH_TPM_EVT_LOG_SIZE;
+
+ grub_memset (get_virtual_current_address (ch), 0, slparams->tpm_evt_log_size);
+
+ grub_dprintf ("linux", "tpm_evt_log_base = %lx, tpm_evt_log_size = %x\n",
+ (unsigned long) slparams->tpm_evt_log_base,
+ (unsigned) slparams->tpm_evt_log_size);
+
+ if (grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000,
+ 0xffffffff - GRUB_MLE_AP_WAKE_BLOCK_SIZE,
+ GRUB_MLE_AP_WAKE_BLOCK_SIZE, GRUB_PAGE_SIZE,
+ GRUB_RELOCATOR_PREFERENCE_NONE, 1))
+ goto fail;
+
+ slparams->ap_wake_block = get_physical_target_address (ch);
+ slparams->ap_wake_block_size = GRUB_MLE_AP_WAKE_BLOCK_SIZE;
+
+ grub_memset (get_virtual_current_address (ch), 0, slparams->ap_wake_block_size);
+
+ grub_dprintf ("linux", "ap_wake_block = %lx, ap_wake_block_size = %lx\n",
+ (unsigned long) slparams->ap_wake_block,
+ (unsigned long) slparams->ap_wake_block_size);
+
+ return GRUB_ERR_NONE;
+
+fail:
+ return grub_errno;
+}
diff --git a/grub-core/loader/slaunch/slaunch.c b/grub-core/loader/slaunch/slaunch.c
new file mode 100644
index 000000000..8079bae7a
--- /dev/null
+++ b/grub-core/loader/slaunch/slaunch.c
@@ -0,0 +1,204 @@
+#include <grub/i386/cpuid.h>
+#include <grub/i386/msr.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/txt.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_uint32_t slp = SLP_NONE;
+
+static void *slaunch_module = NULL;
+
+grub_uint32_t
+grub_slaunch_platform_type (void)
+{
+ return slp;
+}
+
+void *
+grub_slaunch_module (void)
+{
+ return slaunch_module;
+}
+
+static grub_err_t
+grub_cmd_slaunch (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ grub_uint32_t manufacturer[3];
+ grub_uint32_t eax;
+ grub_err_t err;
+
+ if (!grub_cpu_is_cpuid_supported ())
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("CPUID is unsupported"));
+
+ err = grub_cpu_is_msr_supported ();
+
+ if (err != GRUB_ERR_NONE)
+ return grub_error (err, N_("MSRs are unsupported"));
+
+ grub_cpuid (0, eax, manufacturer[0], manufacturer[2], manufacturer[1]);
+
+ if (!grub_memcmp (manufacturer, "GenuineIntel", 12))
+ {
+ err = grub_txt_init ();
+
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ slp = SLP_INTEL_TXT;
+ }
+ else
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("CPU is unsupported"));
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_slaunch_module (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_file_t file;
+ grub_ssize_t size;
+ void *new_module = NULL;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected: filename"));
+
+ if (slp == SLP_NONE)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("secure launch not enabled"));
+
+ if (slp > SLP_INTEL_TXT)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("unknown secure launch platform type: %d"), slp);
+
+ grub_errno = GRUB_ERR_NONE;
+
+ file = grub_file_open (argv[0], GRUB_FILE_TYPE_SLAUNCH_MODULE);
+
+ if (file == NULL)
+ return grub_errno;
+
+ size = grub_file_size (file);
+
+ if (!size)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("file size is zero"));
+ goto fail;
+ }
+
+ new_module = grub_malloc (size);
+
+ if (new_module == NULL)
+ goto fail;
+
+ if (grub_file_read (file, new_module, size) != size)
+ {
+ if (grub_errno == GRUB_ERR_NONE)
+ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file: %s"),
+ argv[0]);
+ goto fail;
+ }
+
+ if (slp == SLP_INTEL_TXT)
+ {
+ if (!grub_txt_is_sinit_acmod (new_module, size))
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("it does not look like SINIT ACM"));
+ goto fail;
+ }
+
+ if (!grub_txt_acmod_match_platform (new_module))
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("SINIT ACM does not match platform"));
+ goto fail;
+ }
+ }
+
+ grub_file_close (file);
+
+ grub_free (slaunch_module);
+ slaunch_module = new_module;
+
+ return GRUB_ERR_NONE;
+
+ fail:
+ grub_error_push ();
+
+ grub_free (new_module);
+ grub_file_close (file);
+
+ grub_error_pop ();
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_slaunch_state (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ if (slp == SLP_NONE)
+ grub_printf ("Secure launcher: Disabled\n");
+ else if (slp == SLP_INTEL_TXT)
+ {
+ grub_printf ("Secure launcher: Intel TXT\n");
+ grub_txt_state_show ();
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd_slaunch, cmd_slaunch_module, cmd_slaunch_state;
+
+GRUB_MOD_INIT (slaunch)
+{
+ cmd_slaunch = grub_register_command ("slaunch", grub_cmd_slaunch,
+ NULL, N_("Enable secure launcher"));
+ cmd_slaunch_module = grub_register_command ("slaunch_module", grub_cmd_slaunch_module,
+ NULL, N_("Load secure launcher module from file"));
+ cmd_slaunch_state = grub_register_command ("slaunch_state", grub_cmd_slaunch_state,
+ NULL, N_("Display secure launcher state"));
+}
+
+GRUB_MOD_FINI (slaunch)
+{
+ if (cmd_slaunch_state)
+ grub_unregister_command (cmd_slaunch_state);
+
+ if (cmd_slaunch_module)
+ grub_unregister_command (cmd_slaunch_module);
+
+ if (cmd_slaunch)
+ grub_unregister_command (cmd_slaunch);
+
+ if (slp == SLP_INTEL_TXT)
+ grub_txt_shutdown ();
+}
diff --git a/include/grub/file.h b/include/grub/file.h
index a5bf3a792..47b638a43 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -132,6 +132,9 @@ enum grub_file_type

GRUB_FILE_TYPE_VERIFY_SIGNATURE,

+ /* Secure Launch module. */
+ GRUB_FILE_TYPE_SLAUNCH_MODULE,
+
GRUB_FILE_TYPE_MASK = 0xffff,

/* --skip-sig is specified. */
diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h
index ace28f8c2..0de9eccfc 100644
--- a/include/grub/i386/linux.h
+++ b/include/grub/i386/linux.h
@@ -158,6 +158,17 @@ struct linux_i386_kernel_header
grub_uint64_t pref_address;
grub_uint32_t init_size;
grub_uint32_t handover_offset;
+ grub_uint32_t kernel_info_offset;
+} GRUB_PACKED;
+
+struct linux_kernel_info
+{
+ grub_uint32_t header;
+ grub_uint32_t size;
+ grub_uint32_t size_total;
+ grub_uint32_t setup_type_max;
+ grub_uint32_t mle_header_offset;
+ grub_uint8_t var_len_data[0];
} GRUB_PACKED;

/* Boot parameters for Linux based on 2.6.12. This is used by the setup
@@ -339,9 +350,10 @@ struct linux_kernel_params
grub_uint64_t pref_address;
grub_uint32_t init_size;
grub_uint32_t handover_offset;
+ grub_uint32_t kernel_info_offset;
/* Linux setup header copy - END. */

- grub_uint8_t _pad7[40];
+ grub_uint8_t _pad7[36];
grub_uint32_t edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]; /* 290 */
struct grub_e820_mmap e820_map[(0x400 - 0x2d0) / 20]; /* 2d0 */
} GRUB_PACKED;
diff --git a/include/grub/slaunch.h b/include/grub/slaunch.h
index ba6516981..061d8e439 100644
--- a/include/grub/slaunch.h
+++ b/include/grub/slaunch.h
@@ -33,6 +33,9 @@
#define GRUB_SL_BOOT_TYPE_LINUX 1
#define GRUB_SL_BOOT_TYPE_EFI 2

+#define GRUB_KERNEL_INFO_HEADER "LToP"
+#define GRUB_KERNEL_INFO_MIN_SIZE_TOTAL 12
+
struct linux_kernel_params;
struct linux_i386_kernel_header;
struct grub_relocator;
@@ -91,6 +94,18 @@ void grub_setup_slr_table (struct grub_slaunch_params *slparams,
struct grub_slr_entry_hdr *platform_info);
void grub_update_slrt_policy (struct grub_slaunch_params *slparams);

+/* Linux i386 functions */
+grub_err_t grub_sl_find_kernel_info (struct grub_slaunch_params *slparams,
+ grub_file_t kernel_file,
+ struct linux_i386_kernel_header *lh,
+ grub_size_t real_size);
+grub_err_t grub_sl_txt_prepare_mle_ptab (struct grub_slaunch_params *slparams,
+ grub_size_t *prot_size,
+ grub_uint64_t *preferred_address);
+grub_err_t grub_sl_txt_setup_linux (struct grub_slaunch_params *slparams,
+ struct grub_relocator *relocator,
+ grub_size_t total_size, grub_size_t prot_size,
+ void **prot_mode_mem, grub_addr_t *prot_mode_target);
#endif /* ASM_FILE */

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:39 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/Makefile.core.def | 1 +
grub-core/loader/efi/linux.c | 16 ++
grub-core/loader/slaunch/x86_efi_linux.c | 212 +++++++++++++++++++++++
include/grub/slaunch.h | 7 +
4 files changed, 236 insertions(+)
create mode 100644 grub-core/loader/slaunch/x86_efi_linux.c

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 327a8391b..aba480842 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1885,6 +1885,7 @@ module = {
x86 = loader/slaunch/i386_linux.c;
x86 = loader/slaunch/dlstub.c;
x86 = loader/efi/dltrampoline.S;
+ x86_64_efi = loader/slaunch/x86_efi_linux.c;
enable = x86;
};

diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index 78ea07ca8..da13b4f62 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -25,11 +25,14 @@
#include <grub/loader.h>
#include <grub/mm.h>
#include <grub/types.h>
+#include <grub/slr_table.h>
+#include <grub/slaunch.h>
#include <grub/efi/efi.h>
#include <grub/efi/fdtload.h>
#include <grub/efi/memory.h>
#include <grub/efi/pe32.h>
#include <grub/efi/sb.h>
+#include <grub/x86_64/efi/memory.h>
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
#include <grub/verify.h>
@@ -55,6 +58,8 @@ static bool initrd_use_loadfile2 = false;
static grub_guid_t load_file2_guid = GRUB_EFI_LOAD_FILE2_PROTOCOL_GUID;
static grub_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;

+static struct grub_slaunch_params slparams = {0};
+
static initrd_media_device_path_t initrd_lf2_device_path = {
{
{
@@ -190,6 +195,7 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args)
grub_efi_boot_services_t *b;
grub_efi_status_t status;
grub_efi_loaded_image_t *loaded_image;
+ grub_err_t err;
int len;

mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t));
@@ -234,6 +240,16 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args)
2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
(grub_uint8_t *) args, len, NULL);

+ if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+ {
+ err = grub_sl_efi_txt_setup (&slparams, kernel_addr, loaded_image);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_error (err, "Secure Launch setup TXT failed");
+ goto unload;
+ }
+ }
+
grub_dprintf ("linux", "starting image %p\n", image_handle);
status = b->start_image (image_handle, 0, NULL);

diff --git a/grub-core/loader/slaunch/x86_efi_linux.c b/grub-core/loader/slaunch/x86_efi_linux.c
new file mode 100644
index 000000000..1a237b42c
--- /dev/null
+++ b/grub-core/loader/slaunch/x86_efi_linux.c
@@ -0,0 +1,212 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024, Oracle and/or its affiliates.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/charset.h>
+#include <grub/command.h>
+#include <grub/err.h>
+#include <grub/linux.h>
+#include <grub/loader.h>
+#include <grub/mm.h>
+#include <grub/types.h>
+#include <grub/slr_table.h>
+#include <grub/slaunch.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/memory.h>
+#include <grub/x86_64/efi/memory.h>
+#include <grub/i386/msr.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/memory.h>
+#include <grub/i386/linux.h>
+#include <grub/i386/txt.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define GRUB_EFI_SLAUNCH_TPM_EVT_LOG_SIZE 0x8000
+#define GRUB_EFI_MLE_AP_WAKE_BLOCK_SIZE 0x14000
+#define OFFSET_OF(x, y) ((grub_size_t)((grub_uint8_t *)(&(y)->x) - (grub_uint8_t *)(y)))
+
+static struct linux_kernel_params boot_params = {0};
+
+static grub_err_t
+sl_efi_install_slr_table (struct grub_slaunch_params *slparams)
+{
+ grub_guid_t slrt_guid = GRUB_UEFI_SLR_TABLE_GUID;
+ grub_efi_boot_services_t *b;
+ grub_efi_status_t status;
+
+ b = grub_efi_system_table->boot_services;
+ status = b->install_configuration_table (&slrt_guid, (void *)slparams->slr_table_base);
+ if (status != GRUB_EFI_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_OS, "cannot load image");
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+sl_efi_locate_mle_offset (struct grub_slaunch_params *slparams,
+ void *kernel_addr, grub_ssize_t kernel_start)
+{
+ struct linux_kernel_params *lh = (struct linux_kernel_params *)kernel_addr;
+ struct linux_kernel_info kernel_info;
+
+ /* Locate the MLE header offset in kernel_info section */
+ grub_memcpy ((void *)&kernel_info,
+ (char *)kernel_addr + kernel_start + grub_le_to_cpu32 (lh->kernel_info_offset),
+ sizeof (struct linux_kernel_info));
+
+ if (OFFSET_OF (mle_header_offset, &kernel_info) >= grub_le_to_cpu32 (kernel_info.size))
+ return grub_error (GRUB_ERR_BAD_OS, N_("not slaunch kernel: lack of mle_header_offset"));
+
+ slparams->mle_header_offset = grub_le_to_cpu32 (kernel_info.mle_header_offset);
+
+ return GRUB_ERR_NONE;
+}
+
+static void *
+sl_efi_txt_setup_slmem (struct grub_slaunch_params *slparams,
+ grub_efi_physical_address_t max_addr,
+ grub_uint32_t *slmem_size_out)
+{
+ grub_uint8_t *slmem;
+ grub_uint32_t slmem_size =
+ GRUB_EFI_PAGE_SIZE + GRUB_EFI_SLAUNCH_TPM_EVT_LOG_SIZE + GRUB_EFI_MLE_AP_WAKE_BLOCK_SIZE;
+
+ slmem = grub_efi_allocate_pages_real (max_addr,
+ GRUB_EFI_BYTES_TO_PAGES(slmem_size),
+ GRUB_EFI_ALLOCATE_MAX_ADDRESS,
+ GRUB_EFI_LOADER_DATA);
+ if (!slmem)
+ return NULL;
+
+ grub_memset (slmem, 0, slmem_size);
+
+ slparams->slr_table_base = (grub_uint64_t)slmem;
+ slparams->slr_table_size = GRUB_EFI_PAGE_SIZE;
+ slparams->slr_table_mem = slmem;
+
+ slparams->tpm_evt_log_base = (grub_uint64_t)(slmem + GRUB_EFI_PAGE_SIZE);
+ slparams->tpm_evt_log_size = GRUB_EFI_SLAUNCH_TPM_EVT_LOG_SIZE;
+
+ slparams->ap_wake_block = (grub_uint32_t)(grub_uint64_t)(slmem + GRUB_EFI_PAGE_SIZE + GRUB_EFI_SLAUNCH_TPM_EVT_LOG_SIZE);
+ slparams->ap_wake_block_size = GRUB_EFI_MLE_AP_WAKE_BLOCK_SIZE;
+
+ *slmem_size_out = slmem_size;
+ return slmem;
+}
+
+grub_err_t
+grub_sl_efi_txt_setup (struct grub_slaunch_params *slparams, void *kernel_addr,
+ grub_efi_loaded_image_t *loaded_image)
+{
+ struct linux_kernel_params *lh = (struct linux_kernel_params *)kernel_addr;
+ grub_uint64_t image_base = (grub_uint64_t)loaded_image->image_base;
+ grub_efi_uint64_t image_size = loaded_image->image_size;
+ grub_efi_physical_address_t requested;
+ grub_ssize_t start;
+ grub_err_t err;
+ void *addr;
+ void *slmem = NULL;
+ grub_uint32_t slmem_size = 0;
+
+ slparams->boot_type = GRUB_SL_BOOT_TYPE_EFI;
+ slparams->platform_type = grub_slaunch_platform_type ();
+
+ /*
+ * Dummy empty boot params structure for now. EFI stub will create a boot params
+ * and populate it. The SL code in EFI stub will update the boot params structure
+ * in the OSMLE data and SLRT.
+ */
+ slparams->boot_params = &boot_params;
+ slparams->boot_params_base = (grub_uint64_t)&boot_params;
+
+ /*
+ * Note that while the boot params on the zero page are not used or updated during a Linux
+ * UEFI boot through the PE header, the values placed there in the bzImage during the build
+ * are still valid and can be treated as boot params for certain things.
+ */
+ start = (lh->setup_sects + 1) * 512;
+
+ /* Allocate page tables for TXT just in front of the kernel image */
+ slparams->mle_ptab_size = grub_txt_get_mle_ptab_size (image_size);
+ slparams->mle_ptab_size = ALIGN_UP (slparams->mle_ptab_size, GRUB_TXT_PMR_ALIGN);
+ requested = ALIGN_DOWN ((image_base - slparams->mle_ptab_size),
+ GRUB_TXT_PMR_ALIGN);
+
+ addr = grub_efi_allocate_pages_real (requested,
+ GRUB_EFI_BYTES_TO_PAGES(slparams->mle_ptab_size),
+ GRUB_EFI_ALLOCATE_ADDRESS,
+ GRUB_EFI_LOADER_DATA);
+ if (!addr)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ return GRUB_ERR_OUT_OF_MEMORY;
+ }
+
+ slparams->mle_ptab_mem = addr;
+ slparams->mle_ptab_target = (grub_uint64_t)addr;
+
+ /*
+ * For the MLE, skip the zero page and startup section of the binary. The MLE
+ * begins with the protected mode .text section which follows. The MLE header
+ * and MLE entry point are RVA's from the beginning of .text where startup_32
+ * begins.
+ *
+ * Note, to do the EFI boot, the entire bzImage binary is loaded since the PE
+ * header is in the startup section before the protected mode piece begins.
+ * In legacy world this part of the image would have been stripped off.
+ */
+ slparams->mle_mem = image_base + start;
+ slparams->mle_start = image_base + start;
+ slparams->mle_size = image_size - start;
+
+ /* Setup the TXT ACM page tables */
+ grub_txt_setup_mle_ptab (slparams);
+
+ /* Allocate a block of memory for Secure Launch entities */
+ slmem = sl_efi_txt_setup_slmem (slparams, (grub_efi_physical_address_t)addr,
+ &slmem_size);
+ if (!slmem)
+ {
+ err = GRUB_ERR_OUT_OF_MEMORY;
+ goto fail;
+ }
+
+ err = sl_efi_locate_mle_offset (slparams, kernel_addr, start);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ /* Final stage for secure launch, setup TXT and install the SLR table */
+ err = grub_txt_boot_prepare (slparams);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ err = sl_efi_install_slr_table (slparams);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ return GRUB_ERR_NONE;
+
+fail:
+
+ if (slmem && slmem_size)
+ grub_efi_free_pages ((grub_addr_t)slmem, slmem_size);
+
+ grub_efi_free_pages ((grub_addr_t)addr, slparams->mle_ptab_size);
+
+ return err;
+}
diff --git a/include/grub/slaunch.h b/include/grub/slaunch.h
index 061d8e439..e0b51f12c 100644
--- a/include/grub/slaunch.h
+++ b/include/grub/slaunch.h
@@ -36,11 +36,14 @@
#define GRUB_KERNEL_INFO_HEADER "LToP"
#define GRUB_KERNEL_INFO_MIN_SIZE_TOTAL 12

+/* Forward declarations */
struct linux_kernel_params;
struct linux_i386_kernel_header;
struct grub_relocator;
struct grub_slr_entry_hdr;
struct grub_slr_policy_entry;
+struct grub_efi_loaded_image;
+typedef struct grub_efi_loaded_image grub_efi_loaded_image_t;

struct grub_slaunch_params
{
@@ -106,6 +109,10 @@ grub_err_t grub_sl_txt_setup_linux (struct grub_slaunch_params *slparams,
struct grub_relocator *relocator,
grub_size_t total_size, grub_size_t prot_size,
void **prot_mode_mem, grub_addr_t *prot_mode_target);
+
+/* Linux EFI functions */
+grub_err_t grub_sl_efi_txt_setup (struct grub_slaunch_params *slparams, void *kernel_addr,
+ grub_efi_loaded_image_t *loaded_image);

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:42 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Michał Żygowski <michal....@3mdeb.com>

Signed-off-by: Michał Żygowski <michal....@3mdeb.com>
Signed-off-by: Krystian Hebel <krystia...@3mdeb.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/slaunch/txt.c | 68 +++++++++++++++++++++++++++++++++-
include/grub/i386/txt.h | 33 +++++++++++++++++
2 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/grub-core/loader/slaunch/txt.c b/grub-core/loader/slaunch/txt.c
index 7040c4159..3b36e0ca4 100644
--- a/grub-core/loader/slaunch/txt.c
+++ b/grub-core/loader/slaunch/txt.c
@@ -503,6 +503,32 @@ grub_set_mtrrs_for_acmod (struct grub_txt_acm_header *hdr)
return GRUB_ERR_NONE;
}

+void
+grub_txt_init_tpm_event_log (void *buf, grub_size_t size)
+{
+ struct grub_txt_event_log_container *elog;
+
+ if (buf == NULL || size < sizeof (*elog))
+ return;
+
+ /* For TPM 2.0 just clear the area, only TPM 1.2 requires initialization. */
+ grub_memset (buf, 0, size);
+
+ if (grub_get_tpm_ver () != GRUB_TPM_12)
+ return;
+
+ elog = (struct grub_txt_event_log_container *) buf;
+
+ grub_memcpy ((void *) elog->signature, EVTLOG_SIGNATURE, sizeof (elog->signature));
+ elog->container_ver_major = EVTLOG_CNTNR_MAJOR_VER;
+ elog->container_ver_minor = EVTLOG_CNTNR_MINOR_VER;
+ elog->pcr_event_ver_major = EVTLOG_EVT_MAJOR_VER;
+ elog->pcr_event_ver_minor = EVTLOG_EVT_MINOR_VER;
+ elog->size = size;
+ elog->pcr_events_offset = sizeof (*elog);
+ elog->next_event_offset = sizeof (*elog);
+}
+
static void
set_txt_info_ptr (struct grub_slaunch_params *slparams,
struct grub_txt_os_mle_data *os_mle_data)
@@ -524,6 +550,7 @@ init_txt_heap (struct grub_slaunch_params *slparams, struct grub_txt_acm_header
struct grub_txt_os_mle_data *os_mle_data;
struct grub_txt_os_sinit_data *os_sinit_data;
struct grub_txt_heap_end_element *heap_end_element;
+ struct grub_txt_heap_tpm_event_log_element *heap_tpm_event_log_element;
struct grub_txt_heap_event_log_pointer2_1_element *heap_event_log_pointer2_1_element;
#ifdef GRUB_MACHINE_EFI
struct grub_acpi_rsdp_v20 *rsdp;
@@ -637,10 +664,31 @@ init_txt_heap (struct grub_slaunch_params *slparams, struct grub_txt_acm_header

sinit_caps = grub_txt_get_sinit_capabilities (sinit);

+ grub_dprintf ("slaunch", "SINIT capabilities 0x%08x\n", sinit_caps);
+
/* CBnT bits 5:4 must be 11b, since D/A mapping is the only one supported. */
os_sinit_data->capabilities = GRUB_TXT_CAPS_TPM_12_NO_LEGACY_PCR_USAGE |
GRUB_TXT_CAPS_TPM_12_AUTH_PCR_USAGE;

+ if (grub_get_tpm_ver () == GRUB_TPM_20)
+ {
+ if ((sinit_caps & os_sinit_data->capabilities) != os_sinit_data->capabilities)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("Details/authorities PCR usage is not supported"));
+ }
+ else
+ {
+ if (!(sinit_caps & GRUB_TXT_CAPS_TPM_12_AUTH_PCR_USAGE))
+ {
+ grub_dprintf ("slaunch", "Details/authorities PCR usage is not supported. Trying legacy");
+ if (sinit_caps & GRUB_TXT_CAPS_TPM_12_NO_LEGACY_PCR_USAGE)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("Not a single PCR usage available in SINIT capabilities"));
+
+ os_sinit_data->capabilities = 0;
+ }
+ }
+
/* Choose monitor RLP wakeup mechanism first. */
if (sinit_caps & GRUB_TXT_CAPS_MONITOR_SUPPORT)
os_sinit_data->capabilities |= GRUB_TXT_CAPS_MONITOR_SUPPORT;
@@ -653,9 +701,27 @@ init_txt_heap (struct grub_slaunch_params *slparams, struct grub_txt_acm_header
os_sinit_data->capabilities |= GRUB_TXT_CAPS_ECX_PT_SUPPORT;

if (grub_get_tpm_ver () == GRUB_TPM_12)
- return grub_error (GRUB_ERR_BAD_DEVICE, N_("TPM 1.2 is not supported"));
+ {
+ grub_dprintf ("slaunch", "TPM 1.2 detected\n");
+ grub_dprintf ("slaunch", "Setting up TXT HEAP TPM event log element\n");
+ os_sinit_data->flags = GRUB_TXT_PCR_EXT_MAX_PERF_POLICY;
+ os_sinit_data->version = OS_SINIT_DATA_TPM_12_VER;
+
+ heap_tpm_event_log_element =
+ (struct grub_txt_heap_tpm_event_log_element *) os_sinit_data->ext_data_elts;
+ heap_tpm_event_log_element->type = GRUB_TXT_HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR;
+ heap_tpm_event_log_element->size = sizeof (*heap_tpm_event_log_element);
+ heap_tpm_event_log_element->event_log_phys_addr = slparams->tpm_evt_log_base;
+
+ heap_end_element = (struct grub_txt_heap_end_element *)
+ ((grub_addr_t) heap_tpm_event_log_element + heap_tpm_event_log_element->size);
+ heap_end_element->type = GRUB_TXT_HEAP_EXTDATA_TYPE_END;
+ heap_end_element->size = sizeof (*heap_end_element);
+ }
else
{
+ grub_dprintf ("slaunch", "TPM 2.0 detected\n");
+ grub_dprintf ("slaunch", "Setting up TXT HEAP TPM event log element\n");
if (!(sinit_caps & GRUB_TXT_CAPS_TPM_20_EVTLOG_SUPPORT))
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("original TXT TPM 2.0 event log format is not supported"));
diff --git a/include/grub/i386/txt.h b/include/grub/i386/txt.h
index 01668045f..d4a6d1cd1 100644
--- a/include/grub/i386/txt.h
+++ b/include/grub/i386/txt.h
@@ -22,6 +22,7 @@
#define GRUB_TXT_H 1

#include <grub/i386/mmio.h>
+#include <grub/tpm.h>

/* Intel TXT Software Developers Guide */

@@ -636,6 +637,36 @@ struct grub_smx_parameters
grub_uint32_t txt_feature_ext_flags;
} GRUB_PACKED;

+/* Structures and constants used for TPM 1.2 event log initialization */
+struct grub_tpm12_pcr_event
+{
+ grub_uint32_t pcr_index;
+ grub_uint32_t type;
+ grub_uint8_t digest[SHA1_DIGEST_SIZE];
+ grub_uint32_t data_size;
+ grub_uint8_t data[];
+} GRUB_PACKED;
+
+#define EVTLOG_SIGNATURE "TXT Event Container"
+#define EVTLOG_CNTNR_MAJOR_VER 1
+#define EVTLOG_CNTNR_MINOR_VER 0
+#define EVTLOG_EVT_MAJOR_VER 1
+#define EVTLOG_EVT_MINOR_VER 0
+
+struct grub_txt_event_log_container
+{
+ grub_uint8_t signature[20];
+ grub_uint8_t reserved[12];
+ grub_uint8_t container_ver_major;
+ grub_uint8_t container_ver_minor;
+ grub_uint8_t pcr_event_ver_major;
+ grub_uint8_t pcr_event_ver_minor;
+ grub_uint32_t size;
+ grub_uint32_t pcr_events_offset;
+ grub_uint32_t next_event_offset;
+ struct grub_tpm12_pcr_event pcr_events[];
+} GRUB_PACKED;
+
static inline void
grub_txt_getsec_parameters (grub_uint32_t index, grub_uint32_t *eax_out,
grub_uint32_t *ebx_out, grub_uint32_t *ecx_out)
@@ -662,6 +693,8 @@ extern grub_err_t grub_txt_verify_platform (void);
extern grub_err_t grub_txt_prepare_cpu (void);
extern grub_err_t grub_set_mtrrs_for_acmod (struct grub_txt_acm_header *hdr);

+extern void grub_txt_init_tpm_event_log (void *buf, grub_size_t size);
+
extern grub_uint32_t grub_txt_get_mle_ptab_size (grub_uint32_t mle_size);
extern void grub_txt_setup_mle_ptab (struct grub_slaunch_params *slparams);

--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:45 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
GRUB_MULTIBOOT(get_mbi_size) returns an upper bound on MBI's size
instead of the actual size. It could also be used for measurements
after zeroing unused parts of the buffer, but using an actual size seems
like a better option as the same MBI will always have the same hash
regardless of the amount of extra memory that follows it.

Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/i386/multiboot_mbi.c | 4 +++-
grub-core/loader/multiboot.c | 3 ++-
grub-core/loader/multiboot_mbi2.c | 6 ++++--
include/grub/multiboot.h | 2 +-
include/grub/multiboot2.h | 3 ++-
5 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c
index bdaf67ad0..f058f4645 100644
--- a/grub-core/loader/i386/multiboot_mbi.c
+++ b/grub-core/loader/i386/multiboot_mbi.c
@@ -453,7 +453,7 @@ retrieve_video_parameters (struct multiboot_info *mbi,
}

grub_err_t
-grub_multiboot_make_mbi (grub_uint32_t *target)
+grub_multiboot_make_mbi (grub_uint32_t *target, grub_uint32_t *size)
{
struct multiboot_info *mbi;
struct multiboot_mod_list *modlist;
@@ -621,6 +621,8 @@ grub_multiboot_make_mbi (grub_uint32_t *target)
return err;
#endif

+ *size = (char *) ptrorig - (char *) mbi;
+
return GRUB_ERR_NONE;
}

diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c
index ec29f1b58..98c1d5e99 100644
--- a/grub-core/loader/multiboot.c
+++ b/grub-core/loader/multiboot.c
@@ -177,6 +177,7 @@ static grub_err_t
grub_multiboot_boot (void)
{
grub_err_t err;
+ grub_uint32_t mbi_size;

#ifdef GRUB_USE_MULTIBOOT2
struct grub_relocator32_state state = MULTIBOOT2_INITIAL_STATE;
@@ -185,7 +186,7 @@ grub_multiboot_boot (void)
#endif
state.MULTIBOOT_ENTRY_REGISTER = GRUB_MULTIBOOT (payload_eip);

- err = GRUB_MULTIBOOT (make_mbi) (&state.MULTIBOOT_MBI_REGISTER);
+ err = GRUB_MULTIBOOT (make_mbi) (&state.MULTIBOOT_MBI_REGISTER, &mbi_size);

if (err)
return err;
diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c
index 00a48413c..1945b3ac6 100644
--- a/grub-core/loader/multiboot_mbi2.c
+++ b/grub-core/loader/multiboot_mbi2.c
@@ -701,7 +701,7 @@ retrieve_video_parameters (grub_properly_aligned_t **ptrorig)
}

grub_err_t
-grub_multiboot2_make_mbi (grub_uint32_t *target)
+grub_multiboot2_make_mbi (grub_uint32_t *target, grub_uint32_t *size)
{
grub_properly_aligned_t *ptrorig;
grub_properly_aligned_t *mbistart;
@@ -1002,7 +1002,9 @@ grub_multiboot2_make_mbi (grub_uint32_t *target)
/ sizeof (grub_properly_aligned_t);
}

- ((grub_uint32_t *) mbistart)[0] = (char *) ptrorig - (char *) mbistart;
+ *size = (char *) ptrorig - (char *) mbistart;
+
+ ((grub_uint32_t *) mbistart)[0] = *size;
((grub_uint32_t *) mbistart)[1] = 0;

return GRUB_ERR_NONE;
diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h
index d8847f753..020c54847 100644
--- a/include/grub/multiboot.h
+++ b/include/grub/multiboot.h
@@ -41,7 +41,7 @@ void grub_multiboot (int argc, char *argv[]);
void grub_module (int argc, char *argv[]);

void grub_multiboot_set_accepts_video (int val);
-grub_err_t grub_multiboot_make_mbi (grub_uint32_t *target);
+grub_err_t grub_multiboot_make_mbi (grub_uint32_t *target, grub_uint32_t *size);
void grub_multiboot_free_mbi (void);
grub_err_t grub_multiboot_init_mbi (int argc, char *argv[]);
grub_err_t grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
diff --git a/include/grub/multiboot2.h b/include/grub/multiboot2.h
index b90aa6989..3417a1447 100644
--- a/include/grub/multiboot2.h
+++ b/include/grub/multiboot2.h
@@ -33,7 +33,8 @@ void grub_multiboot2 (int argc, char *argv[]);
void grub_module2 (int argc, char *argv[]);

void grub_multiboot2_set_accepts_video (int val);
-grub_err_t grub_multiboot2_make_mbi (grub_uint32_t *target);
+grub_err_t grub_multiboot2_make_mbi (grub_uint32_t *target,
+ grub_uint32_t *size);
void grub_multiboot2_free_mbi (void);
grub_err_t grub_multiboot2_init_mbi (int argc, char *argv[]);
grub_err_t grub_multiboot2_add_module (grub_addr_t start, grub_size_t size,
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:48 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/slaunch/slrt.c | 37 ++++++++++++++++++++++++++++++++-
include/grub/slaunch.h | 10 +++++++++
2 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/grub-core/loader/slaunch/slrt.c b/grub-core/loader/slaunch/slrt.c
index b5213bcaa..0fe10041f 100644
--- a/grub-core/loader/slaunch/slrt.c
+++ b/grub-core/loader/slaunch/slrt.c
@@ -30,7 +30,7 @@
#include <grub/i386/mmio.h>
#include <grub/i386/txt.h>

-#define SLR_MAX_POLICY_ENTRIES 7
+#define SLR_MAX_POLICY_ENTRIES 16

/* Area to collect and build SLR Table information */
static grub_uint8_t slr_policy_buf[GRUB_PAGE_SIZE] = {0};
@@ -65,12 +65,30 @@ grub_setup_slrt_policy (struct grub_slaunch_params *slparams,
struct grub_efi_info *efi_info = NULL;
grub_uint64_t hi_val;
int i = 0;
+ int added;

/* A bit of work to extract the v2.08 EFI info from the linux params */
if (boot_params != NULL)
efi_info = (struct grub_efi_info *)((grub_uint8_t *)&(boot_params->v0208)
+ 2*sizeof(grub_uint32_t));

+ if (slparams->fill_policy_hook)
+ {
+ added = slparams->fill_policy_hook (1, SLR_MAX_POLICY_ENTRIES - i,
+ &slr_policy_staging->policy_entries[i],
+ slparams->fill_policy_hook_data);
+ if (added < 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("failed to prepend policy entries"));
+
+ i += added;
+ }
+
+ /* The code below always adds 7 entries. */
+ if (SLR_MAX_POLICY_ENTRIES - i < 7)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("not enough policy entry slots"));
+
/* the SLR table should be measured too, at least parts of it */
slr_policy_staging->policy_entries[i].pcr = 18;
slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_SLRT;
@@ -159,6 +177,23 @@ grub_setup_slrt_policy (struct grub_slaunch_params *slparams,
}
else
slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_UNUSED;
+ i++;
+
+ if (slparams->fill_policy_hook)
+ {
+ added = slparams->fill_policy_hook (0, SLR_MAX_POLICY_ENTRIES - i,
+ &slr_policy_staging->policy_entries[i],
+ slparams->fill_policy_hook_data);
+ if (added < 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("failed to append policy entries"));
+
+ i += added;
+ }
+
+ /* Mark any unused entries with the appropriate type */
+ for (; i < SLR_MAX_POLICY_ENTRIES; ++i)
+ slr_policy_staging->policy_entries[i].entity_type = GRUB_SLR_ET_UNUSED;

return GRUB_ERR_NONE;
}
diff --git a/include/grub/slaunch.h b/include/grub/slaunch.h
index e0b51f12c..f7bea641e 100644
--- a/include/grub/slaunch.h
+++ b/include/grub/slaunch.h
@@ -68,6 +68,16 @@ struct grub_slaunch_params
grub_uint32_t dce_size;
grub_uint64_t tpm_evt_log_base;
grub_uint32_t tpm_evt_log_size;
+
+ /*
+ * Can be NULL. Called twice: when starting to add standard SLRT entries and
+ * after adding them. Should return the number of entries added by the hook
+ * or a negative value on failure.
+ */
+ int (*fill_policy_hook)(int is_start, int available_entries,
+ struct grub_slr_policy_entry *next_entry, void *data);
+ /* Data passed to fill_policy_hook. */
+ void *fill_policy_hook_data;
};

struct grub_efi_info
--
2.47.1

Sergii Dmytruk

unread,
Dec 12, 2024, 8:42:50 AM12/12/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Michał Żygowski <michal....@3mdeb.com>

The code makes sure the order of policy entries is correct:
- MBI entry goes first, so the payload can measure it first on launch
- then goes SLRT and other typical entries
- MB2 modules are appended last

Signed-off-by: Michał Żygowski <michal....@3mdeb.com>
Signed-off-by: Tomasz Żyjewski <tomasz....@3mdeb.com>
Signed-off-by: Krystian Hebel <krystia...@3mdeb.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/multiboot.c | 11 +++
grub-core/loader/multiboot_elfxx.c | 90 +++++++++++++++++++-
grub-core/loader/multiboot_mbi2.c | 132 +++++++++++++++++++++++++++++
grub-core/loader/slaunch/dlstub.c | 2 +-
include/grub/i386/txt.h | 2 +
include/grub/multiboot2.h | 3 +
include/grub/slaunch.h | 1 +
include/grub/slr_table.h | 2 +
8 files changed, 241 insertions(+), 2 deletions(-)

diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c
index 98c1d5e99..07163739b 100644
--- a/grub-core/loader/multiboot.c
+++ b/grub-core/loader/multiboot.c
@@ -50,6 +50,7 @@
#include <grub/video.h>
#include <grub/memory.h>
#include <grub/i18n.h>
+#include <grub/slaunch.h>

GRUB_MOD_LICENSE ("GPLv3+");

@@ -191,6 +192,16 @@ grub_multiboot_boot (void)
if (err)
return err;

+#ifdef GRUB_USE_MULTIBOOT2
+ if (grub_slaunch_platform_type () != SLP_NONE)
+ {
+ err = grub_multiboot2_perform_slaunch (state.MULTIBOOT_MBI_REGISTER,
+ mbi_size);
+ if (err)
+ return grub_error (err, N_("failed to perform Multiboot2 slaunch"));
+ }
+#endif
+
if (grub_efi_is_finished)
normal_boot (GRUB_MULTIBOOT (relocator), state);
else
diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c
index 1edad0594..ee05a4d99 100644
--- a/grub-core/loader/multiboot_elfxx.c
+++ b/grub-core/loader/multiboot_elfxx.c
@@ -44,7 +44,9 @@
#error "I'm confused"
#endif

+#include <grub/i386/txt.h>
#include <grub/i386/relocator.h>
+#include <grub/slaunch.h>

#define CONCAT(a,b) CONCAT_(a, b)
#define CONCAT_(a,b) a ## b
@@ -73,6 +75,11 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
grub_off_t phlimit;
unsigned int i;
void *source = NULL;
+#ifdef GRUB_USE_MULTIBOOT2
+ struct grub_slaunch_params *slparams = &grub_multiboot2_slparams;
+ grub_uint32_t mle_hdr_offset;
+ struct grub_txt_mle_header *mle_hdr;
+#endif

if (ehdr->e_ident[EI_MAG0] != ELFMAG0
|| ehdr->e_ident[EI_MAG1] != ELFMAG1
@@ -127,6 +134,18 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
{
load_size = highest_load - mld->link_base_addr;

+#ifndef GRUB_USE_MULTIBOOT2
+ if (grub_slaunch_platform_type () != SLP_NONE)
+ return grub_error (GRUB_ERR_BAD_OS, "Only multiboot2 supported for slaunch");
+#else
+ if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+ {
+ /* Do not go below GRUB_TXT_PMR_ALIGN. */
+ if (mld->align < GRUB_TXT_PMR_ALIGN)
+ mld->align = GRUB_TXT_PMR_ALIGN;
+ }
+#endif
+
grub_dprintf ("multiboot_loader", "align=0x%lx, preference=0x%x, "
"load_size=0x%x, avoid_efi_boot_services=%d\n",
(long) mld->align, mld->preference, load_size,
@@ -148,9 +167,57 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)

mld->load_base_addr = get_physical_target_address (ch);
source = get_virtual_current_address (ch);
+
+#ifdef GRUB_USE_MULTIBOOT2
+ grub_memset (source, 0, load_size);
+ grub_dprintf ("multiboot_loader", "load_base_addr=0x%lx, source=0x%lx\n",
+ (long) mld->load_base_addr, (long) source);
+
+ if (grub_slaunch_platform_type () != SLP_NONE)
+ {
+ slparams->mle_start = mld->load_base_addr;
+ slparams->mle_mem = source;
+ slparams->mle_ptab_size = 0;
+ }
+
+ if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+ {
+ /*
+ * Allocate the binary together with the page tables to make one
+ * contiguous block for MLE.
+ */
+ slparams->mle_ptab_size = grub_txt_get_mle_ptab_size (load_size);
+ slparams->mle_ptab_size = ALIGN_UP (slparams->mle_ptab_size, GRUB_TXT_PMR_ALIGN);
+
+ err = grub_relocator_alloc_chunk_align_safe (GRUB_MULTIBOOT (relocator), &ch,
+ GRUB_MEMORY_MACHINE_UPPER_START,
+ mld->load_base_addr - slparams->mle_ptab_size,
+ slparams->mle_ptab_size, GRUB_TXT_PMR_ALIGN,
+ GRUB_RELOCATOR_PREFERENCE_NONE, 1);
+ if (err)
+ {
+ grub_dprintf ("multiboot_loader", "Cannot allocate memory for MLE page tables\n");
+ return err;
+ }
+
+ slparams->mle_ptab_mem = get_virtual_current_address (ch);
+ slparams->mle_ptab_target = (grub_uint64_t) get_physical_target_address (ch);
+ grub_dprintf ("multiboot_loader", "mle_ptab_mem = %p, mle_ptab_target = %lx, mle_ptab_size = %x\n",
+ slparams->mle_ptab_mem, (unsigned long) slparams->mle_ptab_target,
+ (unsigned) slparams->mle_ptab_size);
+ }
+#endif
}
else
- mld->load_base_addr = mld->link_base_addr;
+ {
+#ifdef GRUB_USE_MULTIBOOT2
+ /* TODO: support non-relocatable */
+ if (grub_slaunch_platform_type () != SLP_NONE)
+ return grub_error (GRUB_ERR_BAD_OS, "Non-relocatable ELF not supported with slaunch");
+#endif
+
+ mld->load_base_addr = mld->link_base_addr;
+ }

grub_dprintf ("multiboot_loader", "relocatable=%d, link_base_addr=0x%x, "
"load_base_addr=0x%x\n", mld->relocatable,
@@ -213,6 +280,27 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
}
}

+#ifdef GRUB_USE_MULTIBOOT2
+ if (grub_slaunch_platform_type () != SLP_NONE)
+ {
+ /* TODO: decide on universal way of conveying location of MLE header */
+ for (mle_hdr_offset = 0; mle_hdr_offset < 0x1000; mle_hdr_offset += 16)
+ {
+ mle_hdr = (struct grub_txt_mle_header *)((grub_addr_t)source + mle_hdr_offset);
+ if (!grub_memcmp (mle_hdr->uuid, GRUB_TXT_MLE_UUID, 16))
+ {
+ break;
+ }
+ }
+
+ if (mle_hdr_offset >= 0x1000)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "MLE header not found");
+
+ slparams->mle_header_offset = mle_hdr_offset;
+ slparams->mle_size = mle_hdr->mle_end - mle_hdr->mle_start;
+ }
+#endif
+
for (i = 0; i < phnum; i++)
if (phdr(i)->p_vaddr <= ehdr->e_entry
&& phdr(i)->p_vaddr + phdr(i)->p_memsz > ehdr->e_entry)
diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c
index 1945b3ac6..dcbfbed1f 100644
--- a/grub-core/loader/multiboot_mbi2.c
+++ b/grub-core/loader/multiboot_mbi2.c
@@ -36,6 +36,10 @@
#include <grub/i18n.h>
#include <grub/net.h>
#include <grub/lib/cmdline.h>
+#include <grub/i386/memory.h>
+#include <grub/i386/txt.h>
+#include <grub/slaunch.h>
+#include <grub/slr_table.h>

#if defined (GRUB_MACHINE_EFI)
#include <grub/efi/efi.h>
@@ -63,6 +67,12 @@ struct module
int cmdline_size;
};

+struct fill_policy_hook_data
+{
+ grub_uint32_t mbi_target;
+ grub_uint32_t mbi_size;
+};
+
static struct module *modules, *modules_last;
static grub_size_t cmdline_size;
static grub_size_t total_modcmd;
@@ -76,6 +86,8 @@ static void *elf_sections;
static int keep_bs = 0;
static grub_uint32_t load_base_addr;

+struct grub_slaunch_params grub_multiboot2_slparams = {0};
+
void
grub_multiboot2_add_elfsyms (grub_size_t num, grub_size_t entsize,
unsigned shndx, void *data)
@@ -119,6 +131,7 @@ grub_multiboot2_load (grub_file_t file, const char *filename)
grub_uint32_t console_required = 0;
struct multiboot_header_tag_framebuffer *fbtag = NULL;
int accepted_consoles = GRUB_MULTIBOOT2_CONSOLE_EGA_TEXT;
+ struct grub_slaunch_params *slparams = &grub_multiboot2_slparams;
mbi_load_data_t mld;

mld.mbi_ver = 2;
@@ -275,8 +288,18 @@ grub_multiboot2_load (grub_file_t file, const char *filename)
"load address tag without entry address tag");
}

+ if (grub_slaunch_platform_type () != SLP_NONE)
+ {
+ slparams->relocator = grub_multiboot2_relocator;
+ slparams->boot_type = GRUB_SL_BOOT_TYPE_MB2;
+ slparams->platform_type = grub_slaunch_platform_type ();
+ }
+
if (addr_tag)
{
+ if (slparams->platform_type != SLP_NONE)
+ return grub_error (GRUB_ERR_BAD_OS, "Slaunch not supported with multiboot addr tag");
+
grub_uint64_t load_addr = (addr_tag->load_addr + 1)
? addr_tag->load_addr : (addr_tag->header_addr
- ((char *) header - (char *) mld.buffer));
@@ -390,6 +413,35 @@ grub_multiboot2_load (grub_file_t file, const char *filename)
err = grub_multiboot2_set_console (GRUB_MULTIBOOT2_CONSOLE_EGA_TEXT,
accepted_consoles,
0, 0, 0, console_required);
+
+ if (slparams->platform_type != SLP_NONE)
+ {
+ grub_relocator_chunk_t ch;
+
+ if (grub_relocator_alloc_chunk_align_safe (grub_multiboot2_relocator, &ch, 0x1000000,
+ UP_TO_TOP32 (GRUB_SLAUNCH_TPM_EVT_LOG_SIZE),
+ GRUB_SLAUNCH_TPM_EVT_LOG_SIZE, GRUB_PAGE_SIZE,
+ GRUB_RELOCATOR_PREFERENCE_HIGH, 1))
+ {
+ grub_free (mld.buffer);
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate TPM event log area");
+ }
+
+ slparams->tpm_evt_log_base = get_physical_target_address (ch);
+ slparams->tpm_evt_log_size = GRUB_SLAUNCH_TPM_EVT_LOG_SIZE;
+
+ if (slparams->platform_type == SLP_INTEL_TXT)
+ grub_txt_init_tpm_event_log (get_virtual_current_address (ch),
+ slparams->tpm_evt_log_size);
+
+ grub_dprintf ("multiboot_loader", "tpm_evt_log_base = 0x%lx, tpm_evt_log_size = 0x%x\n",
+ (unsigned long) slparams->tpm_evt_log_base,
+ (unsigned) slparams->tpm_evt_log_size);
+
+ if (slparams->platform_type == SLP_INTEL_TXT)
+ grub_txt_setup_mle_ptab (slparams);
+ }
+
return err;
}

@@ -1128,3 +1180,83 @@ grub_multiboot2_set_bootdev (void)

bootdev_set = 1;
}
+
+static int
+fill_policy_hook(int is_start, int available_entries,
+ struct grub_slr_policy_entry *next_entry, void *data)
+{
+ int i = 0;
+ unsigned m;
+ struct module *cur;
+ struct fill_policy_hook_data *hook_data = data;
+
+ if (is_start)
+ {
+ if (available_entries < 1)
+ return -1;
+
+ next_entry->pcr = 18;
+ next_entry->entity_type = GRUB_SLR_ET_MULTIBOOT2_INFO;
+ next_entry->entity = hook_data->mbi_target;
+ next_entry->size = hook_data->mbi_size;
+ next_entry->flags = 0;
+ grub_strcpy (next_entry->evt_info, "Measured MB2 information");
+ i = 1;
+ }
+ else
+ {
+ if (available_entries < (int)modcnt)
+ return -1;
+
+ for (m = 0, cur = modules; m < modcnt; m++, cur = cur->next)
+ {
+ next_entry[i].pcr = 17;
+ next_entry[i].entity_type = GRUB_SLR_ET_MULTIBOOT2_MODULE;
+ next_entry[i].entity = cur->start;
+ next_entry[i].size = cur->size;
+ next_entry[i].flags = 0;
+ grub_strcpy (next_entry[i].evt_info, "Measured MB2 module");
+ i++;
+ }
+ }
+
+ return i;
+}
+
+grub_err_t
+grub_multiboot2_perform_slaunch (grub_uint32_t mbi_target,
+ grub_uint32_t mbi_size)
+{
+ grub_err_t err;
+ struct grub_slaunch_params *slparams = &grub_multiboot2_slparams;
+ struct grub_slr_entry_dl_info *dlinfo;
+ struct fill_policy_hook_data hook_data = {
+ .mbi_target = mbi_target,
+ .mbi_size = mbi_size,
+ };
+
+ slparams->boot_params_base = mbi_target;
+
+ slparams->fill_policy_hook = &fill_policy_hook;
+ slparams->fill_policy_hook_data = &hook_data;
+
+ if (slparams->platform_type == SLP_INTEL_TXT)
+ {
+ err = grub_txt_boot_prepare (slparams);
+ if (err != GRUB_ERR_NONE)
+ return grub_error (err, "TXT boot preparation failed");
+ }
+ else
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("Unknown secure launcher platform type: %d\n"), slparams->platform_type);
+
+ grub_dprintf ("multiboot_loader", "slr_table_base = 0x%lx, slr_table_size = 0x%x\n",
+ (unsigned long) slparams->slr_table_base,
+ (unsigned) slparams->slr_table_size);
+
+ dlinfo = grub_slr_next_entry_by_tag (slparams->slr_table_mem, NULL, GRUB_SLR_ENTRY_DL_INFO);
+ dl_entry ((grub_uint64_t)(grub_addr_t) &dlinfo->bl_context);
+
+ /* If this returns, something failed miserably */
+ return GRUB_ERR_BAD_DEVICE;
+}
diff --git a/grub-core/loader/slaunch/dlstub.c b/grub-core/loader/slaunch/dlstub.c
index d3c28645e..2cdbdd886 100644
--- a/grub-core/loader/slaunch/dlstub.c
+++ b/grub-core/loader/slaunch/dlstub.c
@@ -73,7 +73,7 @@ void dl_entry (grub_uint64_t dl_ctx)
return;
}

- if (slparams->boot_type == GRUB_SL_BOOT_TYPE_LINUX)
+ if (slparams->boot_type == GRUB_SL_BOOT_TYPE_LINUX || slparams->boot_type == GRUB_SL_BOOT_TYPE_MB2)
{
/* Configure relocator GETSEC[SENTER] call. */
state.eax = GRUB_SMX_LEAF_SENTER;
diff --git a/include/grub/i386/txt.h b/include/grub/i386/txt.h
index d4a6d1cd1..d2ae7b21e 100644
--- a/include/grub/i386/txt.h
+++ b/include/grub/i386/txt.h
@@ -420,6 +420,8 @@ struct grub_txt_sinit_memory_descriptor_records
/* 2.1 MLE Architecture Overview */
/* Table 1. MLE Header structure */

+#define GRUB_TXT_MLE_UUID "\x5a\xac\x82\x90\x6f\x47\xa7\x74\x0f\x5c\x55\xa2\xcb\x51\xb6\x42"
+
struct grub_txt_mle_header
{
grub_uint8_t uuid[16];
diff --git a/include/grub/multiboot2.h b/include/grub/multiboot2.h
index 3417a1447..1a3be5f48 100644
--- a/include/grub/multiboot2.h
+++ b/include/grub/multiboot2.h
@@ -28,6 +28,7 @@
#include <grub/err.h>

extern struct grub_relocator *grub_multiboot2_relocator;
+extern struct grub_slaunch_params grub_multiboot2_slparams;

void grub_multiboot2 (int argc, char *argv[]);
void grub_module2 (int argc, char *argv[]);
@@ -43,6 +44,8 @@ void grub_multiboot2_set_bootdev (void);
void
grub_multiboot2_add_elfsyms (grub_size_t num, grub_size_t entsize,
unsigned shndx, void *data);
+grub_err_t grub_multiboot2_perform_slaunch (grub_uint32_t mbi_target,
+ grub_uint32_t mbi_size);

grub_uint32_t grub_multiboot2_get_mmap_count (void);
grub_err_t grub_multiboot2_set_video_mode (void);
diff --git a/include/grub/slaunch.h b/include/grub/slaunch.h
index f7bea641e..f63b8b379 100644
--- a/include/grub/slaunch.h
+++ b/include/grub/slaunch.h
@@ -32,6 +32,7 @@
#define GRUB_SL_BOOT_TYPE_INVALID 0
#define GRUB_SL_BOOT_TYPE_LINUX 1
#define GRUB_SL_BOOT_TYPE_EFI 2
+#define GRUB_SL_BOOT_TYPE_MB2 3

#define GRUB_KERNEL_INFO_HEADER "LToP"
#define GRUB_KERNEL_INFO_MIN_SIZE_TOTAL 12
diff --git a/include/grub/slr_table.h b/include/grub/slr_table.h
index 9dff3d0d5..b9302472b 100644
--- a/include/grub/slr_table.h
+++ b/include/grub/slr_table.h
@@ -72,6 +72,8 @@
#define GRUB_SLR_ET_CMDLINE 0x0004
#define GRUB_SLR_ET_UEFI_MEMMAP 0x0005
#define GRUB_SLR_ET_RAMDISK 0x0006
+#define GRUB_SLR_ET_MULTIBOOT2_INFO 0x0007
+#define GRUB_SLR_ET_MULTIBOOT2_MODULE 0x0008
#define GRUB_SLR_ET_TXT_OS2MLE 0x0010
#define GRUB_SLR_ET_UNUSED 0xffff

--
2.47.1

Reply all
Reply to author
Forward
0 new messages