diff --git a/1100-i386-msr-Merge-rdmsr.h-and-wrmsr.h-into-msr.h.patch b/1100-i386-msr-Merge-rdmsr.h-and-wrmsr.h-into-msr.h.patch new file mode 100644 index 0000000..a2ae71c --- /dev/null +++ b/1100-i386-msr-Merge-rdmsr.h-and-wrmsr.h-into-msr.h.patch @@ -0,0 +1,133 @@ +From b965e567652ec8eb8bde2cd6f79b4ef02fdb0fa4 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Tue, 17 Dec 2019 17:51:29 +0100 +Subject: [PATCH] i386/msr: Merge rdmsr.h and wrmsr.h into msr.h + +It does not make sense to have separate headers for separate static +functions. Additionally, we have to add some constants with MSR addresses +in subsequent patches. So, make one common place to store them. + +Signed-off-by: Daniel Kiper +--- + grub-core/commands/i386/rdmsr.c | 2 +- + grub-core/commands/i386/wrmsr.c | 2 +- + include/grub/i386/{wrmsr.h => msr.h} | 16 +++++++++--- + include/grub/i386/rdmsr.h | 37 ---------------------------- + 4 files changed, 15 insertions(+), 42 deletions(-) + rename include/grub/i386/{wrmsr.h => msr.h} (78%) + delete mode 100644 include/grub/i386/rdmsr.h + +diff --git a/grub-core/commands/i386/rdmsr.c b/grub-core/commands/i386/rdmsr.c +index 46c4346da1b6..fa4622f9e8a1 100644 +--- a/grub-core/commands/i386/rdmsr.c ++++ b/grub-core/commands/i386/rdmsr.c +@@ -26,7 +26,7 @@ + #include + #include + #include +-#include ++#include + + GRUB_MOD_LICENSE("GPLv3+"); + +diff --git a/grub-core/commands/i386/wrmsr.c b/grub-core/commands/i386/wrmsr.c +index 1b143b8882a4..8f352f205ffd 100644 +--- a/grub-core/commands/i386/wrmsr.c ++++ b/grub-core/commands/i386/wrmsr.c +@@ -27,7 +27,7 @@ + #include + #include + #include +-#include ++#include + + GRUB_MOD_LICENSE("GPLv3+"); + +diff --git a/include/grub/i386/wrmsr.h b/include/grub/i386/msr.h +similarity index 78% +rename from include/grub/i386/wrmsr.h +rename to include/grub/i386/msr.h +index dea60aed1fc0..7b52b5d61229 100644 +--- a/include/grub/i386/wrmsr.h ++++ b/include/grub/i386/msr.h +@@ -16,14 +16,24 @@ + * along with GRUB. If not, see . + */ + +-#ifndef GRUB_WRMSR_H +-#define GRUB_WRMSR_H 1 ++#ifndef GRUB_I386_MSR_H ++#define GRUB_I386_MSR_H 1 + + /* + * TODO: Add a general protection exception handler. + * Accessing a reserved or unimplemented MSR address results in a GP#. + */ + ++static inline grub_uint64_t ++grub_msr_read (grub_uint32_t msr_id) ++{ ++ grub_uint32_t low, high; ++ ++ asm volatile ("rdmsr" : "=a" (low), "=d" (high) : "c" (msr_id)); ++ ++ return ((grub_uint64_t) high << 32) | low; ++} ++ + static inline void + grub_msr_write(grub_uint32_t msr_id, grub_uint64_t msr_value) + { +@@ -32,4 +42,4 @@ grub_msr_write(grub_uint32_t msr_id, grub_uint64_t msr_value) + asm volatile ("wrmsr" : : "c" (msr_id), "a" (low), "d" (high)); + } + +-#endif /* GRUB_WRMSR_H */ ++#endif /* GRUB_I386_MSR_H */ +diff --git a/include/grub/i386/rdmsr.h b/include/grub/i386/rdmsr.h +deleted file mode 100644 +index c0a0c717a0e9..000000000000 +--- a/include/grub/i386/rdmsr.h ++++ /dev/null +@@ -1,37 +0,0 @@ +-/* +- * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2019 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 . +- */ +- +-#ifndef GRUB_RDMSR_H +-#define GRUB_RDMSR_H 1 +- +-/* +- * TODO: Add a general protection exception handler. +- * Accessing a reserved or unimplemented MSR address results in a GP#. +- */ +- +-static inline grub_uint64_t +-grub_msr_read (grub_uint32_t msr_id) +-{ +- grub_uint32_t low, high; +- +- asm volatile ("rdmsr" : "=a" (low), "=d" (high) : "c" (msr_id)); +- +- return ((grub_uint64_t)high << 32) | low; +-} +- +-#endif /* GRUB_RDMSR_H */ + +base-commit: ae94b97be2b81b625d6af6654d3ed79078b50ff6 +-- +2.41.0 + diff --git a/1101-i386-msr-Rename-grub_msr_read-and-grub_msr_write.patch b/1101-i386-msr-Rename-grub_msr_read-and-grub_msr_write.patch new file mode 100644 index 0000000..0bf4178 --- /dev/null +++ b/1101-i386-msr-Rename-grub_msr_read-and-grub_msr_write.patch @@ -0,0 +1,66 @@ +From 462af28050122f87412237abd8000f3667a5d3be Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Tue, 17 Dec 2019 20:02:37 +0100 +Subject: [PATCH] i386/msr: Rename grub_msr_read() and grub_msr_write() + +... to grub_rdmsr() and grub_wrmsr() respectively. New names are more +obvious than older ones. + +Signed-off-by: Daniel Kiper +--- + grub-core/commands/i386/rdmsr.c | 2 +- + grub-core/commands/i386/wrmsr.c | 2 +- + include/grub/i386/msr.h | 4 ++-- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/i386/rdmsr.c b/grub-core/commands/i386/rdmsr.c +index fa4622f9e8a1..89ece7657f27 100644 +--- a/grub-core/commands/i386/rdmsr.c ++++ b/grub-core/commands/i386/rdmsr.c +@@ -76,7 +76,7 @@ grub_cmd_msr_read (grub_extcmd_context_t ctxt, int argc, char **argv) + if (*ptr != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument")); + +- value = grub_msr_read (addr); ++ value = grub_rdmsr (addr); + + if (ctxt->state[0].set) + { +diff --git a/grub-core/commands/i386/wrmsr.c b/grub-core/commands/i386/wrmsr.c +index 8f352f205ffd..cf6bf6c8fe43 100644 +--- a/grub-core/commands/i386/wrmsr.c ++++ b/grub-core/commands/i386/wrmsr.c +@@ -77,7 +77,7 @@ grub_cmd_msr_write (grub_command_t cmd __attribute__ ((unused)), int argc, char + if (*ptr != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument")); + +- grub_msr_write (addr, value); ++ grub_wrmsr (addr, value); + + return GRUB_ERR_NONE; + } +diff --git a/include/grub/i386/msr.h b/include/grub/i386/msr.h +index 7b52b5d61229..4fba1b8e0d04 100644 +--- a/include/grub/i386/msr.h ++++ b/include/grub/i386/msr.h +@@ -25,7 +25,7 @@ + */ + + static inline grub_uint64_t +-grub_msr_read (grub_uint32_t msr_id) ++grub_rdmsr (grub_uint32_t msr_id) + { + grub_uint32_t low, high; + +@@ -35,7 +35,7 @@ grub_msr_read (grub_uint32_t msr_id) + } + + static inline void +-grub_msr_write(grub_uint32_t msr_id, grub_uint64_t msr_value) ++grub_wrmsr (grub_uint32_t msr_id, grub_uint64_t msr_value) + { + grub_uint32_t low = msr_value, high = msr_value >> 32; + +-- +2.41.0 + diff --git a/1102-i386-msr-Extract-and-improve-MSR-support-detection-c.patch b/1102-i386-msr-Extract-and-improve-MSR-support-detection-c.patch new file mode 100644 index 0000000..73efb6a --- /dev/null +++ b/1102-i386-msr-Extract-and-improve-MSR-support-detection-c.patch @@ -0,0 +1,136 @@ +From 52d63e5e45eaf8df9a81a453459fd89fbf898969 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Sat, 25 Apr 2020 16:43:52 +0200 +Subject: [PATCH] i386/msr: Extract and improve MSR support detection code + +Currently rdmsr and wrmsr commands have own MSR support detection code. +This code is the same. So, it is duplicated. Additionally, this code +cannot be reused by others. Hence, extract this code to a function and +make it public. By the way, improve a code a bit. + +Additionally, use GRUB_ERR_BAD_DEVICE instead of GRUB_ERR_BUG to signal +an error because errors encountered by this new routine are not bugs. + +Signed-off-by: Daniel Kiper +--- + grub-core/commands/i386/rdmsr.c | 21 +++++---------------- + grub-core/commands/i386/wrmsr.c | 21 +++++---------------- + include/grub/i386/msr.h | 29 +++++++++++++++++++++++++++++ + 3 files changed, 39 insertions(+), 32 deletions(-) + +diff --git a/grub-core/commands/i386/rdmsr.c b/grub-core/commands/i386/rdmsr.c +index 89ece7657f27..2e42f6197648 100644 +--- a/grub-core/commands/i386/rdmsr.c ++++ b/grub-core/commands/i386/rdmsr.c +@@ -42,27 +42,16 @@ static const struct grub_arg_option options[] = + static grub_err_t + grub_cmd_msr_read (grub_extcmd_context_t ctxt, int argc, char **argv) + { +- grub_uint32_t manufacturer[3], max_cpuid, a, b, c, features, addr; ++ grub_err_t err; ++ grub_uint32_t addr; + grub_uint64_t value; + const char *ptr; + char buf[sizeof("1122334455667788")]; + +- /* +- * The CPUID instruction should be used to determine whether MSRs +- * are supported. (CPUID.01H:EDX[5] = 1) +- */ +- if (! grub_cpu_is_cpuid_supported ()) +- return grub_error (GRUB_ERR_BUG, N_("unsupported instruction")); ++ err = grub_cpu_is_msr_supported (); + +- grub_cpuid (0, max_cpuid, manufacturer[0], manufacturer[2], manufacturer[1]); +- +- if (max_cpuid < 1) +- return grub_error (GRUB_ERR_BUG, N_("unsupported instruction")); +- +- grub_cpuid (1, a, b, c, features); +- +- if (!(features & (1 << 5))) +- return grub_error (GRUB_ERR_BUG, N_("unsupported instruction")); ++ if (err != GRUB_ERR_NONE) ++ return grub_error (err, N_("RDMSR is unsupported")); + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); +diff --git a/grub-core/commands/i386/wrmsr.c b/grub-core/commands/i386/wrmsr.c +index cf6bf6c8fe43..7fbedaed95ba 100644 +--- a/grub-core/commands/i386/wrmsr.c ++++ b/grub-core/commands/i386/wrmsr.c +@@ -36,26 +36,15 @@ static grub_command_t cmd_write; + static grub_err_t + grub_cmd_msr_write (grub_command_t cmd __attribute__ ((unused)), int argc, char **argv) + { +- grub_uint32_t manufacturer[3], max_cpuid, a, b, c, features, addr; ++ grub_err_t err; ++ grub_uint32_t addr; + grub_uint64_t value; + const char *ptr; + +- /* +- * The CPUID instruction should be used to determine whether MSRs +- * are supported. (CPUID.01H:EDX[5] = 1) +- */ +- if (!grub_cpu_is_cpuid_supported ()) +- return grub_error (GRUB_ERR_BUG, N_("unsupported instruction")); ++ err = grub_cpu_is_msr_supported (); + +- grub_cpuid (0, max_cpuid, manufacturer[0], manufacturer[2], manufacturer[1]); +- +- if (max_cpuid < 1) +- return grub_error (GRUB_ERR_BUG, N_("unsupported instruction")); +- +- grub_cpuid (1, a, b, c, features); +- +- if (!(features & (1 << 5))) +- return grub_error (GRUB_ERR_BUG, N_("unsupported instruction")); ++ if (err != GRUB_ERR_NONE) ++ return grub_error (err, N_("WRMSR is unsupported")); + + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected")); +diff --git a/include/grub/i386/msr.h b/include/grub/i386/msr.h +index 4fba1b8e0d04..1e838c022f41 100644 +--- a/include/grub/i386/msr.h ++++ b/include/grub/i386/msr.h +@@ -19,6 +19,35 @@ + #ifndef GRUB_I386_MSR_H + #define GRUB_I386_MSR_H 1 + ++#include ++#include ++#include ++ ++static inline grub_err_t ++grub_cpu_is_msr_supported (void) ++{ ++ grub_uint32_t eax, ebx, ecx, edx; ++ ++ /* ++ * The CPUID instruction should be used to determine whether MSRs ++ * are supported, CPUID.01H:EDX[5] = 1. ++ */ ++ if (!grub_cpu_is_cpuid_supported ()) ++ return GRUB_ERR_BAD_DEVICE; ++ ++ grub_cpuid (0, eax, ebx, ecx, edx); ++ ++ if (eax < 1) ++ return GRUB_ERR_BAD_DEVICE; ++ ++ grub_cpuid (1, eax, ebx, ecx, edx); ++ ++ if (!(edx & (1 << 5))) ++ return GRUB_ERR_BAD_DEVICE; ++ ++ return GRUB_ERR_NONE; ++} ++ + /* + * TODO: Add a general protection exception handler. + * Accessing a reserved or unimplemented MSR address results in a GP#. +-- +2.41.0 + diff --git a/1103-i386-memory-Rename-PAGE_SHIFT-to-GRUB_PAGE_SHIFT.patch b/1103-i386-memory-Rename-PAGE_SHIFT-to-GRUB_PAGE_SHIFT.patch new file mode 100644 index 0000000..0f0a500 --- /dev/null +++ b/1103-i386-memory-Rename-PAGE_SHIFT-to-GRUB_PAGE_SHIFT.patch @@ -0,0 +1,176 @@ +From 7d5c059815a34eb170f4e8912cb742a9e69b6e45 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Wed, 20 Nov 2019 12:40:42 +0100 +Subject: [PATCH] i386/memory: Rename PAGE_SHIFT to GRUB_PAGE_SHIFT + +...to avoid potential conflicts and confusion. + +Signed-off-by: Daniel Kiper +--- + grub-core/lib/i386/xen/relocator.S | 6 +++--- + grub-core/lib/x86_64/xen/relocator.S | 4 ++-- + grub-core/loader/i386/xen.c | 28 ++++++++++++++-------------- + include/grub/i386/memory.h | 2 +- + 4 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/grub-core/lib/i386/xen/relocator.S b/grub-core/lib/i386/xen/relocator.S +index 96e51b59adfb..dab4d8aceb74 100644 +--- a/grub-core/lib/i386/xen/relocator.S ++++ b/grub-core/lib/i386/xen/relocator.S +@@ -75,10 +75,10 @@ VARIABLE(grub_relocator_xen_mfn_list) + .long 0 + movl 0(%eax, %ebp, 4), %ecx /* mfn */ + movl %ebp, %ebx +- shll $PAGE_SHIFT, %ebx /* virtual address (1:1 mapping) */ ++ shll $GRUB_PAGE_SHIFT, %ebx /* virtual address (1:1 mapping) */ + movl %ecx, %edx +- shll $PAGE_SHIFT, %ecx /* prepare pte low part */ +- shrl $(32 - PAGE_SHIFT), %edx /* pte high part */ ++ shll $GRUB_PAGE_SHIFT, %ecx /* prepare pte low part */ ++ shrl $(32 - GRUB_PAGE_SHIFT), %edx /* pte high part */ + orl $(GRUB_PAGE_PRESENT | GRUB_PAGE_USER), %ecx /* pte low */ + movl $UVMF_INVLPG, %esi + movl $__HYPERVISOR_update_va_mapping, %eax +diff --git a/grub-core/lib/x86_64/xen/relocator.S b/grub-core/lib/x86_64/xen/relocator.S +index f5364ed0f4c8..852cd40aa08b 100644 +--- a/grub-core/lib/x86_64/xen/relocator.S ++++ b/grub-core/lib/x86_64/xen/relocator.S +@@ -60,9 +60,9 @@ LOCAL(cont): + jz 3f + 2: + movq %r12, %rdi +- shlq $PAGE_SHIFT, %rdi /* virtual address (1:1 mapping) */ ++ shlq $GRUB_PAGE_SHIFT, %rdi /* virtual address (1:1 mapping) */ + movq (%rbx, %r12, 8), %rsi /* mfn */ +- shlq $PAGE_SHIFT, %rsi ++ shlq $GRUB_PAGE_SHIFT, %rsi + orq $(GRUB_PAGE_PRESENT | GRUB_PAGE_USER), %rsi /* Build pte */ + movq $UVMF_INVLPG, %rdx + movq %rcx, %r9 /* %rcx clobbered by hypercall */ +diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c +index cd24874ca324..1810c1dbc8b0 100644 +--- a/grub-core/loader/i386/xen.c ++++ b/grub-core/loader/i386/xen.c +@@ -92,7 +92,7 @@ static struct xen_loader_state xen_state; + + static grub_dl_t my_mod; + +-#define PAGE_SIZE (1UL << PAGE_SHIFT) ++#define PAGE_SIZE (1UL << GRUB_PAGE_SHIFT) + #define MAX_MODULES (PAGE_SIZE / sizeof (struct xen_multiboot_mod_list)) + #define STACK_SIZE 1048576 + #define ADDITIONAL_SIZE (1 << 19) +@@ -103,7 +103,7 @@ static grub_dl_t my_mod; + static grub_uint64_t + page2offset (grub_uint64_t page) + { +- return page << PAGE_SHIFT; ++ return page << GRUB_PAGE_SHIFT; + } + + static grub_err_t +@@ -142,7 +142,7 @@ get_pgtable_size (grub_uint64_t from, grub_uint64_t to, grub_uint64_t pfn) + continue; + } + +- bits = PAGE_SHIFT + (i + 1) * LOG_POINTERS_PER_PAGE; ++ bits = GRUB_PAGE_SHIFT + (i + 1) * LOG_POINTERS_PER_PAGE; + mask = (1ULL << bits) - 1; + map->lvls[i].virt_start = map->area.virt_start & ~mask; + map->lvls[i].virt_end = map->area.virt_end | mask; +@@ -247,11 +247,11 @@ generate_page_table (grub_xen_mfn_t *mfn_list) + if (lvl->virt_start >= end || lvl->virt_end <= start) + continue; + p_s = (grub_max (start, lvl->virt_start) - start) >> +- (PAGE_SHIFT + l * LOG_POINTERS_PER_PAGE); ++ (GRUB_PAGE_SHIFT + l * LOG_POINTERS_PER_PAGE); + p_e = (grub_min (end, lvl->virt_end) - start) >> +- (PAGE_SHIFT + l * LOG_POINTERS_PER_PAGE); ++ (GRUB_PAGE_SHIFT + l * LOG_POINTERS_PER_PAGE); + pfn = ((grub_max (start, lvl->virt_start) - lvl->virt_start) >> +- (PAGE_SHIFT + l * LOG_POINTERS_PER_PAGE)) + lvl->pfn_start; ++ (GRUB_PAGE_SHIFT + l * LOG_POINTERS_PER_PAGE)) + lvl->pfn_start; + grub_dprintf ("xen", "write page table entries level %d pg %p " + "mapping %d/%d index %lx-%lx pfn %llx\n", + l, pg, m1, m2, p_s, p_e, (unsigned long long) pfn); +@@ -329,16 +329,16 @@ grub_xen_p2m_alloc (void) + { + err = get_pgtable_size (xen_state.xen_inf.p2m_base, + xen_state.xen_inf.p2m_base + p2msize, +- (xen_state.max_addr + p2msize) >> PAGE_SHIFT); ++ (xen_state.max_addr + p2msize) >> GRUB_PAGE_SHIFT); + if (err) + return err; + +- map->area.pfn_start = xen_state.max_addr >> PAGE_SHIFT; ++ map->area.pfn_start = xen_state.max_addr >> GRUB_PAGE_SHIFT; + p2malloc = p2msize + page2offset (map->area.n_pt_pages); + xen_state.n_mappings++; + xen_state.next_start.mfn_list = xen_state.xen_inf.p2m_base; + xen_state.next_start.first_p2m_pfn = map->area.pfn_start; +- xen_state.next_start.nr_p2m_frames = p2malloc >> PAGE_SHIFT; ++ xen_state.next_start.nr_p2m_frames = p2malloc >> GRUB_PAGE_SHIFT; + } + else + { +@@ -381,7 +381,7 @@ grub_xen_special_alloc (void) + xen_state.virt_start_info = get_virtual_current_address (ch); + xen_state.max_addr = + ALIGN_UP (xen_state.max_addr + sizeof (xen_state.next_start), PAGE_SIZE); +- xen_state.console_pfn = xen_state.max_addr >> PAGE_SHIFT; ++ xen_state.console_pfn = xen_state.max_addr >> GRUB_PAGE_SHIFT; + xen_state.max_addr += 2 * PAGE_SIZE; + + xen_state.next_start.nr_pages = grub_xen_start_page_addr->nr_pages; +@@ -413,7 +413,7 @@ grub_xen_pt_alloc (void) + + xen_state.next_start.pt_base = + xen_state.max_addr + xen_state.xen_inf.virt_base; +- nr_info_pages = xen_state.max_addr >> PAGE_SHIFT; ++ nr_info_pages = xen_state.max_addr >> GRUB_PAGE_SHIFT; + nr_need_pages = nr_info_pages; + + while (1) +@@ -461,7 +461,7 @@ grub_xen_pt_alloc (void) + xen_state.max_addr + STACK_SIZE + xen_state.xen_inf.virt_base; + xen_state.next_start.nr_pt_frames = nr_need_pages; + xen_state.max_addr = try_virt_end - xen_state.xen_inf.virt_base; +- xen_state.pgtbl_end = xen_state.max_addr >> PAGE_SHIFT; ++ xen_state.pgtbl_end = xen_state.max_addr >> GRUB_PAGE_SHIFT; + xen_state.map_reloc->where = (grub_uint64_t *) ((char *) map->where + + page2offset (map->area.n_pt_pages)); + +@@ -515,7 +515,7 @@ grub_xen_boot (void) + if (err) + return err; + +- nr_pages = xen_state.max_addr >> PAGE_SHIFT; ++ nr_pages = xen_state.max_addr >> GRUB_PAGE_SHIFT; + + grub_dprintf ("xen", "bootstrap domain %llx+%llx\n", + (unsigned long long) xen_state.xen_inf.virt_base, +@@ -819,7 +819,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + if (xen_state.xen_inf.unmapped_initrd) + { + xen_state.next_start.flags |= SIF_MOD_START_PFN; +- xen_state.next_start.mod_start = xen_state.max_addr >> PAGE_SHIFT; ++ xen_state.next_start.mod_start = xen_state.max_addr >> GRUB_PAGE_SHIFT; + } + else + xen_state.next_start.mod_start = +diff --git a/include/grub/i386/memory.h b/include/grub/i386/memory.h +index 5cb607fb4667..7be57d6d7ecc 100644 +--- a/include/grub/i386/memory.h ++++ b/include/grub/i386/memory.h +@@ -20,7 +20,7 @@ + #ifndef GRUB_MEMORY_CPU_HEADER + #define GRUB_MEMORY_CPU_HEADER 1 + +-#define PAGE_SHIFT 12 ++#define GRUB_PAGE_SHIFT 12 + + /* The flag for protected mode. */ + #define GRUB_MEMORY_CPU_CR0_PE_ON 0x1 +-- +2.41.0 + diff --git a/1104-i386-memory-Rename-PAGE_SIZE-to-GRUB_PAGE_SIZE-and-m.patch b/1104-i386-memory-Rename-PAGE_SIZE-to-GRUB_PAGE_SIZE-and-m.patch new file mode 100644 index 0000000..1db0aab --- /dev/null +++ b/1104-i386-memory-Rename-PAGE_SIZE-to-GRUB_PAGE_SIZE-and-m.patch @@ -0,0 +1,170 @@ +From 881d5870cbf72f7b35282de1addb107ac3b8100b Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Wed, 20 Nov 2019 12:52:16 +0100 +Subject: [PATCH] i386/memory: Rename PAGE_SIZE to GRUB_PAGE_SIZE and make it + global + +Subsequent patches will use that constant. + +Signed-off-by: Daniel Kiper +--- + grub-core/loader/i386/xen.c | 35 +++++++++++++++++------------------ + include/grub/i386/memory.h | 1 + + 2 files changed, 18 insertions(+), 18 deletions(-) + +diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c +index 1810c1dbc8b0..45c24c45f18d 100644 +--- a/grub-core/loader/i386/xen.c ++++ b/grub-core/loader/i386/xen.c +@@ -92,8 +92,7 @@ static struct xen_loader_state xen_state; + + static grub_dl_t my_mod; + +-#define PAGE_SIZE (1UL << GRUB_PAGE_SHIFT) +-#define MAX_MODULES (PAGE_SIZE / sizeof (struct xen_multiboot_mod_list)) ++#define MAX_MODULES (GRUB_PAGE_SIZE / sizeof (struct xen_multiboot_mod_list)) + #define STACK_SIZE 1048576 + #define ADDITIONAL_SIZE (1 << 19) + #define ALIGN_SIZE (1 << 22) +@@ -229,7 +228,7 @@ generate_page_table (grub_xen_mfn_t *mfn_list) + + for (m1 = 0; m1 < xen_state.n_mappings; m1++) + grub_memset (xen_state.mappings[m1].where, 0, +- xen_state.mappings[m1].area.n_pt_pages * PAGE_SIZE); ++ xen_state.mappings[m1].area.n_pt_pages * GRUB_PAGE_SIZE); + + for (l = NUMBER_OF_LEVELS - 1; l >= 0; l--) + { +@@ -324,7 +323,7 @@ grub_xen_p2m_alloc (void) + + map = xen_state.mappings + xen_state.n_mappings; + p2msize = ALIGN_UP (sizeof (grub_xen_mfn_t) * +- grub_xen_start_page_addr->nr_pages, PAGE_SIZE); ++ grub_xen_start_page_addr->nr_pages, GRUB_PAGE_SIZE); + if (xen_state.xen_inf.has_p2m_base) + { + err = get_pgtable_size (xen_state.xen_inf.p2m_base, +@@ -380,9 +379,9 @@ grub_xen_special_alloc (void) + xen_state.state.start_info = xen_state.max_addr + xen_state.xen_inf.virt_base; + xen_state.virt_start_info = get_virtual_current_address (ch); + xen_state.max_addr = +- ALIGN_UP (xen_state.max_addr + sizeof (xen_state.next_start), PAGE_SIZE); ++ ALIGN_UP (xen_state.max_addr + sizeof (xen_state.next_start), GRUB_PAGE_SIZE); + xen_state.console_pfn = xen_state.max_addr >> GRUB_PAGE_SHIFT; +- xen_state.max_addr += 2 * PAGE_SIZE; ++ xen_state.max_addr += 2 * GRUB_PAGE_SIZE; + + xen_state.next_start.nr_pages = grub_xen_start_page_addr->nr_pages; + grub_memcpy (xen_state.next_start.magic, grub_xen_start_page_addr->magic, +@@ -431,9 +430,9 @@ grub_xen_pt_alloc (void) + /* Map the relocator page either at virtual 0 or after end of area. */ + nr_need_pages = nr_info_pages + map->area.n_pt_pages; + if (xen_state.xen_inf.virt_base) +- err = get_pgtable_size (0, PAGE_SIZE, nr_need_pages); ++ err = get_pgtable_size (0, GRUB_PAGE_SIZE, nr_need_pages); + else +- err = get_pgtable_size (try_virt_end, try_virt_end + PAGE_SIZE, ++ err = get_pgtable_size (try_virt_end, try_virt_end + GRUB_PAGE_SIZE, + nr_need_pages); + if (err) + return err; +@@ -538,7 +537,7 @@ grub_xen_boot (void) + + return grub_relocator_xen_boot (xen_state.relocator, xen_state.state, nr_pages, + xen_state.xen_inf.virt_base < +- PAGE_SIZE ? page2offset (nr_pages) : 0, ++ GRUB_PAGE_SIZE ? page2offset (nr_pages) : 0, + xen_state.pgtbl_end - 1, + page2offset (xen_state.pgtbl_end - 1) + + xen_state.xen_inf.virt_base); +@@ -677,7 +676,7 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- if (xen_state.xen_inf.virt_base & (PAGE_SIZE - 1)) ++ if (xen_state.xen_inf.virt_base & (GRUB_PAGE_SIZE - 1)) + { + grub_error (GRUB_ERR_BAD_OS, "unaligned virt_base"); + goto fail; +@@ -700,10 +699,10 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)), + kern_start = grub_min (kern_start, xen_state.xen_inf.hypercall_page - + xen_state.xen_inf.virt_base); + kern_end = grub_max (kern_end, xen_state.xen_inf.hypercall_page - +- xen_state.xen_inf.virt_base + PAGE_SIZE); ++ xen_state.xen_inf.virt_base + GRUB_PAGE_SIZE); + } + +- xen_state.max_addr = ALIGN_UP (kern_end, PAGE_SIZE); ++ xen_state.max_addr = ALIGN_UP (kern_end, GRUB_PAGE_SIZE); + + + if (grub_sub (kern_end, kern_start, &sz)) +@@ -730,7 +729,7 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)), + if (xen_state.xen_inf.has_hypercall_page) + { + unsigned i; +- for (i = 0; i < PAGE_SIZE / HYPERCALL_INTERFACE_SIZE; i++) ++ for (i = 0; i < GRUB_PAGE_SIZE / HYPERCALL_INTERFACE_SIZE; i++) + set_hypercall_interface ((grub_uint8_t *) kern_chunk_src + + i * HYPERCALL_INTERFACE_SIZE + + xen_state.xen_inf.hypercall_page - +@@ -829,7 +828,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + (unsigned) (xen_state.max_addr + xen_state.xen_inf.virt_base), + (unsigned) size); + +- xen_state.max_addr = ALIGN_UP (xen_state.max_addr + size, PAGE_SIZE); ++ xen_state.max_addr = ALIGN_UP (xen_state.max_addr + size, GRUB_PAGE_SIZE); + + fail: + grub_initrd_close (&initrd_ctx); +@@ -883,7 +882,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), + { + xen_state.xen_inf.unmapped_initrd = 0; + xen_state.n_modules = 0; +- xen_state.max_addr = ALIGN_UP (xen_state.max_addr, PAGE_SIZE); ++ xen_state.max_addr = ALIGN_UP (xen_state.max_addr, GRUB_PAGE_SIZE); + xen_state.modules_target_start = xen_state.max_addr; + xen_state.next_start.mod_start = + xen_state.max_addr + xen_state.xen_inf.virt_base; +@@ -903,7 +902,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), + MAX_MODULES * sizeof (xen_state.module_info_page[0]); + } + +- xen_state.max_addr = ALIGN_UP (xen_state.max_addr, PAGE_SIZE); ++ xen_state.max_addr = ALIGN_UP (xen_state.max_addr, GRUB_PAGE_SIZE); + + file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_INITRD | + (nounzip ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE)); +@@ -926,7 +925,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), + + xen_state.module_info_page[xen_state.n_modules].cmdline = + xen_state.max_addr - xen_state.modules_target_start; +- xen_state.max_addr = ALIGN_UP (xen_state.max_addr + cmdline_len, PAGE_SIZE); ++ xen_state.max_addr = ALIGN_UP (xen_state.max_addr + cmdline_len, GRUB_PAGE_SIZE); + + if (size) + { +@@ -953,7 +952,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), + xen_state.n_modules++; + grub_dprintf ("xen", "module, addr=0x%x, size=0x%x\n", + (unsigned) xen_state.max_addr, (unsigned) size); +- xen_state.max_addr = ALIGN_UP (xen_state.max_addr + size, PAGE_SIZE); ++ xen_state.max_addr = ALIGN_UP (xen_state.max_addr + size, GRUB_PAGE_SIZE); + + + fail: +diff --git a/include/grub/i386/memory.h b/include/grub/i386/memory.h +index 7be57d6d7ecc..c64529630f19 100644 +--- a/include/grub/i386/memory.h ++++ b/include/grub/i386/memory.h +@@ -21,6 +21,7 @@ + #define GRUB_MEMORY_CPU_HEADER 1 + + #define GRUB_PAGE_SHIFT 12 ++#define GRUB_PAGE_SIZE (1UL << GRUB_PAGE_SHIFT) + + /* The flag for protected mode. */ + #define GRUB_MEMORY_CPU_CR0_PE_ON 0x1 +-- +2.41.0 + diff --git a/1105-i386-memory-Define-GRUB_PAGE_MASK-constant-and-GRUB_.patch b/1105-i386-memory-Define-GRUB_PAGE_MASK-constant-and-GRUB_.patch new file mode 100644 index 0000000..d00e9ec --- /dev/null +++ b/1105-i386-memory-Define-GRUB_PAGE_MASK-constant-and-GRUB_.patch @@ -0,0 +1,41 @@ +From d9f97aa57e7cb90a0ed3947daba727b2f619b17b Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Mon, 22 Jan 2024 13:14:39 +0100 +Subject: [PATCH] i386/memory: Define GRUB_PAGE_MASK constant and + GRUB_PAGE_{UP,DOWN} macros + +Subsequent patches will use those macros and constant. + +Signed-off-by: Krystian Hebel +--- + include/grub/i386/memory.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/grub/i386/memory.h b/include/grub/i386/memory.h +index c64529630f19..56f64855be7e 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 + #include + ++#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.41.0 + diff --git a/1106-mmap-Add-grub_mmap_get_lowest-and-grub_mmap_get_high.patch b/1106-mmap-Add-grub_mmap_get_lowest-and-grub_mmap_get_high.patch new file mode 100644 index 0000000..98ec1f6 --- /dev/null +++ b/1106-mmap-Add-grub_mmap_get_lowest-and-grub_mmap_get_high.patch @@ -0,0 +1,131 @@ +From d0570055a9451163220d28e79ba3cf89fb2c1dfa Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Mon, 4 May 2020 22:34:59 +0200 +Subject: [PATCH] mmap: Add grub_mmap_get_lowest() and grub_mmap_get_highest() + +The functions calculate lowest and highest available RAM +addresses respectively. + +Both functions are needed to calculate PMR boundaries for +Intel TXT secure launcher introduced by subsequent patches. + +Signed-off-by: Daniel Kiper +--- + grub-core/mmap/mmap.c | 79 +++++++++++++++++++++++++++++++++++++++++++ + include/grub/memory.h | 3 ++ + 2 files changed, 82 insertions(+) + +diff --git a/grub-core/mmap/mmap.c b/grub-core/mmap/mmap.c +index c8c8312c56f2..5b18b1a4c297 100644 +--- a/grub-core/mmap/mmap.c ++++ b/grub-core/mmap/mmap.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -343,6 +344,84 @@ 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 6da114a1bdc1..8f22f752502b 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.41.0 + diff --git a/1107-i386-tpm-Rename-tpm-module-to-tpm_verifier.patch b/1107-i386-tpm-Rename-tpm-module-to-tpm_verifier.patch new file mode 100644 index 0000000..06343dc --- /dev/null +++ b/1107-i386-tpm-Rename-tpm-module-to-tpm_verifier.patch @@ -0,0 +1,96 @@ +From 01e5b0008d4031ef8612cfc387c7a66d2d4331c6 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Wed, 22 Apr 2020 21:41:24 +0200 +Subject: [PATCH] i386/tpm: Rename tpm module to tpm_verifier + +...to avoid naming collision with TPM TIS and CRB driver introduced +by subsequent patch. + +Signed-off-by: Daniel Kiper +--- + docs/grub.texi | 15 ++++++++------- + grub-core/Makefile.core.def | 4 ++-- + grub-core/commands/{tpm.c => tpm_verifier.c} | 6 +++--- + 3 files changed, 13 insertions(+), 12 deletions(-) + rename grub-core/commands/{tpm.c => tpm_verifier.c} (96%) + +diff --git a/docs/grub.texi b/docs/grub.texi +index f8b4b3b21a7f..20cf82a813a7 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5991,10 +5991,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 +@@ -6019,9 +6019,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 platforms. + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 8022e1c0a794..f482cc01e36e 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2490,8 +2490,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.c b/grub-core/commands/tpm_verifier.c +similarity index 96% +rename from grub-core/commands/tpm.c +rename to grub-core/commands/tpm_verifier.c +index 2052c36eaba5..1d820a774b3b 100644 +--- a/grub-core/commands/tpm.c ++++ b/grub-core/commands/tpm_verifier.c +@@ -78,18 +78,18 @@ grub_tpm_verify_string (char *str, enum grub_verify_string_type type) + } + + struct grub_file_verifier grub_tpm_verifier = { +- .name = "tpm", ++ .name = "tpm_verifier", + .init = grub_tpm_verify_init, + .write = grub_tpm_verify_write, + .verify_string = grub_tpm_verify_string, + }; + +-GRUB_MOD_INIT (tpm) ++GRUB_MOD_INIT (tpm_verifier) + { + grub_verifier_register (&grub_tpm_verifier); + } + +-GRUB_MOD_FINI (tpm) ++GRUB_MOD_FINI (tpm_verifier) + { + grub_verifier_unregister (&grub_tpm_verifier); + } +-- +2.41.0 + diff --git a/1108-i386-tpm-Add-TPM-TIS-and-CRB-driver.patch b/1108-i386-tpm-Add-TPM-TIS-and-CRB-driver.patch new file mode 100644 index 0000000..37da1e2 --- /dev/null +++ b/1108-i386-tpm-Add-TPM-TIS-and-CRB-driver.patch @@ -0,0 +1,217 @@ +From c51d2529ed6bbddcc08edd74ca9e855b4ad397ff Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Mon, 4 May 2020 22:30:58 +0200 +Subject: [PATCH] i386/tpm: Add TPM TIS and CRB driver + +It will be used by Intel TXT secure launcher introduced +by subsequent patches. + +Signed-off-by: Daniel Kiper +Signed-off-by: Krystian Hebel +--- + grub-core/commands/i386/tpm.c | 149 ++++++++++++++++++++++++++++++++++ + include/grub/i386/tpm.h | 36 ++++++++ + 2 files changed, 185 insertions(+) + create mode 100644 grub-core/commands/i386/tpm.c + create mode 100644 include/grub/i386/tpm.h + +diff --git a/grub-core/commands/i386/tpm.c b/grub-core/commands/i386/tpm.c +new file mode 100644 +index 000000000000..f3b6f51ecd05 +--- /dev/null ++++ b/grub-core/commands/i386/tpm.c +@@ -0,0 +1,149 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 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 . ++ * ++ * TPM TIS and CRB driver. ++ * ++ * Note: It is suggested to not use this driver together with UEFI TPM driver. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++/* Code 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 7 ++#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; ++} ++ ++/* Localities 0-4 are supported only. */ ++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 000000000000..d22a2507efa1 +--- /dev/null ++++ b/include/grub/i386/tpm.h +@@ -0,0 +1,36 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 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 . ++ * ++ */ ++ ++#ifndef GRUB_I386_TPM_H ++#define GRUB_I386_TPM_H 1 ++ ++#include ++ ++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.41.0 + diff --git a/1109-i386-slaunch-Add-basic-platform-support-for-secure-l.patch b/1109-i386-slaunch-Add-basic-platform-support-for-secure-l.patch new file mode 100644 index 0000000..3a43540 --- /dev/null +++ b/1109-i386-slaunch-Add-basic-platform-support-for-secure-l.patch @@ -0,0 +1,413 @@ +From 615f29aac919a2fdaa6f9187569c8854ca1acf03 Mon Sep 17 00:00:00 2001 +From: Ross Philipson +Date: Wed, 7 Aug 2019 13:50:14 -0400 +Subject: [PATCH] i386/slaunch: Add basic platform support for secure launch + +Some of the commands declared in header files will be implemented in +the follow-up commits. + +Signed-off-by: Ross Philipson +Signed-off-by: Daniel Kiper +Signed-off-by: Krystian Hebel +--- + include/grub/i386/cpuid.h | 12 ++++ + include/grub/i386/crfr.h | 127 ++++++++++++++++++++++++++++++++++++ + include/grub/i386/mmio.h | 72 ++++++++++++++++++++ + include/grub/i386/msr.h | 63 ++++++++++++++++++ + include/grub/i386/slaunch.h | 62 ++++++++++++++++++ + 5 files changed, 336 insertions(+) + create mode 100644 include/grub/i386/crfr.h + create mode 100644 include/grub/i386/mmio.h + create mode 100644 include/grub/i386/slaunch.h + +diff --git a/include/grub/i386/cpuid.h b/include/grub/i386/cpuid.h +index f7ae4b0a4641..0ddd87b1544e 100644 +--- a/include/grub/i386/cpuid.h ++++ b/include/grub/i386/cpuid.h +@@ -19,6 +19,18 @@ + #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_X86_CPUID_FEATURES_ECX_VMX (1<<5) ++#define GRUB_X86_CPUID_FEATURES_ECX_SMX (1<<6) ++ ++/* AMD */ ++#define GRUB_AMD_CPUID_FEATURES 0x80000001 ++#define GRUB_AMD_CPUID_FEATURES_ECX_SVM (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 000000000000..2efd42a1767c +--- /dev/null ++++ b/include/grub/i386/crfr.h +@@ -0,0 +1,127 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 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 . ++ */ ++ ++#ifndef GRUB_CRFR_H ++#define GRUB_CRFR_H 1 ++ ++#include ++ ++/* 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 /* Generate #XM instead of #UD for SIMD */ ++#define GRUB_CR4_X86_VMXE 0x00002000 /* Enable VMX */ ++#define GRUB_CR4_X86_SMXE 0x00004000 /* Enable SMX */ ++#define GRUB_CR4_X86_PCIDE 0x00020000 /* Enable PCID */ ++ ++static inline unsigned long ++grub_read_cr0 (void) ++{ ++ unsigned long val; ++ ++ asm volatile ("mov %%cr0, %0" : "=r" (val) : : "memory"); ++ ++ return val; ++} ++ ++static inline void ++grub_write_cr0 (unsigned long val) ++{ ++ asm volatile ("mov %0, %%cr0" : : "r" (val) : "memory"); ++} ++ ++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_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 */ ++ ++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 +diff --git a/include/grub/i386/mmio.h b/include/grub/i386/mmio.h +new file mode 100644 +index 000000000000..97a30f7d8af6 +--- /dev/null ++++ b/include/grub/i386/mmio.h +@@ -0,0 +1,72 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 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 . ++ */ ++ ++#ifndef GRUB_I386_MMIO_H ++#define GRUB_I386_MMIO_H 1 ++ ++#include ++ ++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 1e838c022f41..52c923ab94ac 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,64 @@ + #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_FEATURE_CTRL_LOCK (1<<0) /* Lock writes to this register */ ++#define GRUB_MSR_X86_ENABLE_VMX_IN_SMX (1<<1) /* Enable VMX inside SMX */ ++#define GRUB_MSR_X86_ENABLE_VMX_OUT_SMX (1<<2) /* Enable VMX outside 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_MTRR_PHYSBASE(n) (GRUB_MSR_X86_MTRR_PHYSBASE0 + 2 * (n)) ++#define GRUB_MSR_X86_MTRR_PHYSMASK(n) (GRUB_MSR_X86_MTRR_PHYSMASK0 + 2 * (n)) ++#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_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 + #include + #include +@@ -71,4 +132,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 */ +diff --git a/include/grub/i386/slaunch.h b/include/grub/i386/slaunch.h +new file mode 100644 +index 000000000000..7f7709cda75e +--- /dev/null ++++ b/include/grub/i386/slaunch.h +@@ -0,0 +1,62 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 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 . ++ * ++ * 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 ++ ++/* PCRs used by Secure launch. */ ++#define GRUB_SLAUNCH_CODE_PCR 17 ++#define GRUB_SLAUNCH_DATA_PCR 18 ++ ++#define GRUB_SLAUNCH_TPM_EVT_LOG_SIZE (8 * GRUB_PAGE_SIZE) ++ ++#ifndef ASM_FILE ++ ++#include ++#include ++ ++struct grub_slaunch_params ++{ ++ grub_uint32_t boot_params_addr; ++ grub_uint32_t mle_start; ++ grub_uint32_t mle_size; ++ void *mle_ptab_mem; ++ grub_uint64_t mle_ptab_target; ++ grub_uint32_t mle_ptab_size; ++ grub_uint32_t mle_header_offset; ++ grub_uint32_t ap_wake_block; ++ grub_uint32_t ap_wake_block_size; ++ grub_uint32_t dce_base; ++ grub_uint32_t dce_size; ++ grub_uint64_t tpm_evt_log_base; ++ grub_uint32_t tpm_evt_log_size; ++}; ++ ++extern grub_uint32_t grub_slaunch_platform_type (void); ++extern void *grub_slaunch_module (void); ++extern struct grub_slaunch_params *grub_slaunch_params (void); ++ ++#endif /* ASM_FILE */ ++ ++#endif /* GRUB_I386_SLAUNCH_H */ +-- +2.41.0 + diff --git a/1110-i386-txt-Initial-commit-of-the-Secure-Launch-Resourc.patch b/1110-i386-txt-Initial-commit-of-the-Secure-Launch-Resourc.patch new file mode 100644 index 0000000..14480c8 --- /dev/null +++ b/1110-i386-txt-Initial-commit-of-the-Secure-Launch-Resourc.patch @@ -0,0 +1,355 @@ +From 6833012da36ed4017abfe483cd09db9418490860 Mon Sep 17 00:00:00 2001 +From: Ross Philipson +Date: Mon, 9 Jan 2023 12:55:42 -0500 +Subject: [PATCH] i386/txt: Initial commit of the Secure Launch Resource Table + (SLRT) + +Provide definitions of structures and basic functions for constructing +and parsing of SLRT. + +Signed-off-by: Ross Philipson +Signed-off-by: Sergii Dmytruk +--- + include/grub/slr_table.h | 330 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 330 insertions(+) + create mode 100644 include/grub/slr_table.h + +diff --git a/include/grub/slr_table.h b/include/grub/slr_table.h +new file mode 100644 +index 000000000000..b6bbb0d546ff +--- /dev/null ++++ b/include/grub/slr_table.h +@@ -0,0 +1,330 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2023 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 . ++ * ++ * Secure Launch Resource Table definitions ++ */ ++ ++#ifndef GRUB_SLR_TABLE_H ++#define GRUB_SLR_TABLE_H 1 ++ ++#include ++ ++#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_DRTM_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_MULTIBOOT2_INFO 0x0007 ++#define GRUB_SLR_ET_MULTIBOOT2_MODULE 0x0008 ++#define GRUB_SLR_ET_TXT_OS2MLE 0x0010 ++#define GRUB_SLR_ET_UNUSED 0xffff ++ ++/* ++ * Primary SLR 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; ++ /* entries[] */ ++} GRUB_PACKED; ++ ++/* ++ * Common SLRT Table Header ++ */ ++struct grub_slr_entry_hdr ++{ ++ grub_uint16_t tag; ++ grub_uint16_t size; ++} GRUB_PACKED; ++ ++/* ++ * Boot loader context ++ */ ++struct grub_slr_bl_context ++{ ++ grub_uint16_t bootloader; ++ grub_uint16_t reserved; ++ grub_uint64_t context; ++} GRUB_PACKED; ++ ++/* ++ * DRTM Dynamic Launch Configuration ++ */ ++struct grub_slr_entry_dl_info ++{ ++ struct grub_slr_entry_hdr hdr; ++ struct grub_slr_bl_context bl_context; ++ grub_uint64_t dl_handler; ++ grub_uint64_t dce_base; ++ grub_uint32_t dce_size; ++ grub_uint64_t dlme_entry; ++} 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_uint64_t addr; ++ grub_uint32_t size; ++} GRUB_PACKED; ++ ++/* ++ * DRTM Measurement Policy ++ */ ++struct grub_slr_entry_policy ++{ ++ struct grub_slr_entry_hdr hdr; ++ grub_uint16_t revision; ++ grub_uint16_t nr_entries; ++ /* policy_entries[] */ ++} 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 entity; ++ grub_uint64_t size; ++ char evt_info[GRUB_TPM_EVENT_INFO_LENGTH]; ++} 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 saved_misc_enable_msr; ++ struct grub_slr_txt_mtrr_state saved_bsp_mtrrs; ++} GRUB_PACKED; ++ ++/* ++ * AMD SKINIT Info table ++ */ ++struct grub_slr_entry_amd_info ++{ ++ struct grub_slr_entry_hdr hdr; ++ char reserved[]; /* Reserved for future use */ ++} GRUB_PACKED; ++ ++/* ++ * ARM DRTM Info table ++ */ ++struct grub_slr_entry_arm_info ++{ ++ struct grub_slr_entry_hdr hdr; ++ char reserved[]; /* Reserved for future use */ ++} GRUB_PACKED; ++ ++struct grub_slr_uefi_cfg_entry ++{ ++ grub_uint16_t pcr; ++ grub_uint16_t reserved; ++ grub_uint64_t cfg; /* address or value */ ++ grub_uint32_t size; ++ char evt_info[GRUB_TPM_EVENT_INFO_LENGTH]; ++} GRUB_PACKED; ++ ++struct grub_slr_entry_uefi_config ++{ ++ struct grub_slr_entry_hdr hdr; ++ grub_uint16_t revision; ++ grub_uint16_t nr_entries; ++ struct grub_slr_uefi_cfg_entry uefi_cfg_entries[]; ++} GRUB_PACKED; ++ ++static inline grub_addr_t ++grub_slr_end_of_entries (struct grub_slr_table *table) ++{ ++ return (grub_addr_t) table + table->size; ++} ++ ++static inline struct grub_slr_entry_hdr * ++grub_slr_next_entry (struct grub_slr_table *table, ++ struct grub_slr_entry_hdr *curr) ++{ ++ grub_addr_t addr; ++ struct grub_slr_entry_hdr *next; ++ ++ /* Can read the size field of current entry? */ ++ if ( grub_add ((grub_addr_t) curr, sizeof(*curr), &addr) ) ++ return NULL; ++ ++ /* Does current size overflow? */ ++ if ( grub_add ((grub_addr_t) curr, curr->size, &addr) ) ++ return NULL; ++ ++ /* Can read the size field of next entry? */ ++ if ( grub_add (addr, sizeof(*next), &addr) ) ++ return NULL; ++ ++ /* Does next element's header fit within the table? */ ++ if (addr >= grub_slr_end_of_entries (table)) ++ return NULL; ++ ++ next = (struct grub_slr_entry_hdr *) (addr - sizeof(*next)); ++ ++ /* Does next element fit within the table? */ ++ if (grub_slr_end_of_entries (table) - (addr - sizeof(*next)) < next->size) ++ return NULL; ++ ++ /* Is this the last element? */ ++ if (next->tag == GRUB_SLR_ENTRY_END) ++ return NULL; ++ ++ return next; ++} ++ ++static inline struct grub_slr_entry_hdr * ++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; ++ grub_uint32_t new_size; ++ ++ if (entry->size < sizeof(*end) || ++ grub_add (table->size, entry->size, &new_size) || ++ new_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; ++ ++ if (max_size < sizeof(*slrt) + sizeof(*end)) ++ grub_fatal ("Requested SLRT max size (%" PRIuGRUB_UINT32_T ++ " B) is too small\n", max_size); ++ ++ 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.41.0 + diff --git a/1111-i386-txt-Add-Intel-TXT-definitions-header-file.patch b/1111-i386-txt-Add-Intel-TXT-definitions-header-file.patch new file mode 100644 index 0000000..5946831 --- /dev/null +++ b/1111-i386-txt-Add-Intel-TXT-definitions-header-file.patch @@ -0,0 +1,724 @@ +From e49d73b3f8d95c341f591f1b0f08843ed14aa1e1 Mon Sep 17 00:00:00 2001 +From: Ross Philipson +Date: Wed, 7 Aug 2019 13:53:06 -0400 +Subject: [PATCH] i386/txt: Add Intel TXT definitions header file + +Signed-off-by: Ross Philipson +Signed-off-by: Daniel Kiper +--- + include/grub/i386/txt.h | 703 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 703 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 000000000000..a7ddd3a66702 +--- /dev/null ++++ b/include/grub/i386/txt.h +@@ -0,0 +1,703 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 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 . ++ * ++ * Intel TXT definitions header file. ++ */ ++ ++#ifndef GRUB_TXT_H ++#define GRUB_TXT_H 1 ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Intel TXT Software Developers Guide Revision 017.4 */ ++ ++/* Chapter 2, Table 4. MLE/SINIT Capabilities Field Bit Definitions */ ++#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) /* Must be 1 for TPM 2.0 */ ++#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) ++#define GRUB_TXT_CAPS_STARTUP_ACM_SUPPORT (7<<11) /* Reserved for MLE, must be 0 */ ++#define GRUB_TXT_CAPS_DMA_PROTECTION (1<<14) /* 0 = Legacy, 1 = TPR */ ++/* 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_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 (4 * 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; ++ ++/* A.1.2 ACM Information Table */ ++#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 ++/* Revocation ACMs */ ++#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; ++ ++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 ++/* VER_FSBIF is considered deprecated, but some CPUs still use it */ ++#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 ++/* DPR is considered deprecated, but some CPUs still use it */ ++#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_PROD_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; ++ ++#define GRUB_TXT_HEAP_EXTDATA_TYPE_END 0 ++ ++struct grub_txt_heap_end_element ++{ ++ /* Empty, just the common header with type and 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_uint64_t addr[]; ++} GRUB_PACKED; ++ ++#define GRUB_TXT_HEAP_EXTDATA_TYPE_STM 3 ++ ++struct grub_txt_heap_stm_element ++{ ++ /* STM specific BIOS properties */ ++ /* GNU extension used to counteract "error: flexible array member in a struct ++ * with no named members". */ ++ grub_uint8_t data[0]; ++} 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_uint8_t data[]; ++} GRUB_PACKED; ++ ++/* Deprecated, but still used for TPM 1.2 */ ++#define GRUB_TXT_HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR 5 ++ ++struct grub_txt_heap_tpm_event_log_element ++{ ++ 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 */ ++ /* GNU extension used to counteract "error: flexible array member in a struct ++ * with no named members". */ ++ grub_uint8_t madt[0]; ++} GRUB_PACKED; ++ ++#define GRUB_TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 8 ++ ++struct grub_txt_heap_event_log_pointer2_1_element ++{ ++ 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 */ ++ /* GNU extension used to counteract "error: flexible array member in a struct ++ * with no named members". */ ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++#define GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE (2 * sizeof(grub_uint32_t)) ++ ++struct grub_txt_heap_ext_data_element ++{ ++ grub_uint32_t type; ++ grub_uint32_t size; /* Must be at least 8 bytes, includes size of this struct */ ++ union { ++ struct grub_txt_heap_end_element end; ++ struct grub_txt_heap_bios_spec_ver_element bios_spec_ver; ++ struct grub_txt_heap_acm_element acm; ++ struct grub_txt_heap_stm_element stm; ++ struct grub_txt_heap_custom_element custom; ++ struct grub_txt_heap_tpm_event_log_element tpm_event_log; ++ struct grub_txt_heap_madt_element madt; ++ struct grub_txt_heap_event_log_pointer2_1_element event_log_pointer2_1; ++ struct grub_txt_heap_mcfg_element mcfg; ++ }; ++} 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 reserved2; ++ grub_uint32_t num_logical_procs; ++ /* Versions >= 3 */ ++ grub_uint32_t sinit_flags; ++ /* Versions >= 5 with updates in version 6 */ ++ grub_uint32_t mle_flags; ++ /* Versions >= 4 */ ++ /* Ext Data Elements */ ++} GRUB_PACKED; ++ ++/* GRUB SLAUNCH specific definitions OS-MLE data */ ++#define GRUB_SL_OS_MLE_STRUCT_VERSION 1 ++ ++struct grub_slaunch_mtrr_pair ++{ ++ grub_uint64_t mtrr_physbase; ++ grub_uint64_t mtrr_physmask; ++} GRUB_PACKED; ++ ++struct grub_slaunch_mtrr_state ++{ ++ grub_uint64_t default_mem_type; ++ grub_uint64_t mtrr_vcnt; ++ struct grub_slaunch_mtrr_pair mtrr_pair[GRUB_SL_MAX_VARIABLE_MTRRS]; ++} GRUB_PACKED; ++ ++struct grub_txt_os_mle_data ++{ ++ grub_uint32_t version; ++ grub_uint32_t boot_params_addr; ++ grub_uint64_t saved_misc_enable_msr; ++ struct grub_slaunch_mtrr_state saved_bsp_mtrrs; ++ grub_uint32_t ap_wake_block; ++ grub_uint32_t ap_wake_block_size; ++ grub_uint64_t evtlog_addr; ++ grub_uint32_t evtlog_size; ++ grub_uint8_t mle_scratch[64]; ++} GRUB_PACKED; ++ ++/* Table 29. OS to SINIT Data Table */ ++#define GRUB_TXT_PCR_EXT_MAX_AGILITY_POLICY 0 ++#define GRUB_TXT_PCR_EXT_MAX_PERF_POLICY 1 ++ ++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; /* Version 7+ only, otherwise reserved */ ++ 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; ++ /* Versions >= 5 */ ++ /* Warning: version 5 has pointer to RSDT here, not RSDP */ ++ grub_uint64_t efi_rsdp_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 */ ++ /* Reserved for versions >= 9, must be 0 */ ++ 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; /* Reserved for version 9 */ ++ /* 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 3. 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]; ++ 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_uint8_t ++grub_txt_reg_pub_read8 (grub_uint16_t reg) ++{ ++ return grub_read8 (GRUB_TXT_CFG_REGS_PUB + reg); ++} ++ ++static inline grub_uint32_t ++grub_txt_reg_pub_read32 (grub_uint16_t reg) ++{ ++ return grub_read32 (GRUB_TXT_CFG_REGS_PUB + reg); ++} ++ ++static inline grub_uint64_t ++grub_txt_reg_pub_read64 (grub_uint16_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_read32 (GRUB_TXT_HEAP_BASE); ++} ++ ++static inline grub_uint32_t ++grub_txt_get_heap_size (void) ++{ ++ return grub_txt_reg_pub_read32 (GRUB_TXT_HEAP_SIZE); ++} ++ ++/* ++ * Each block of data on heap begins with 64-bit size field, followed by proper ++ * data. Specified size includes size field, so the minimal value of that field ++ * is 8. TXT SDG mentions that all sizes must be multiples of 8 bytes, but even ++ * BiosData produced by code signed by Intel doesn't follow that requirement. ++ * This means that we can't just cast pointer to arbitrary location on TXT heap ++ * with (grub_uint64_t *), because unaligned pointer is UB. ++ */ ++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 */ ++/* Order Number: 325383-082US December 2023 */ ++ ++/* CHAPTER 7 SAFER MODE EXTENSIONS REFERENCE */ ++ ++/* Table 7-2. GETSEC Leaf Functions */ ++#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 ++ ++/* Table 7-3. GETSEC Capability Result Encoding */ ++#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 ("getsec" ++ : "=a" (caps) ++ : "a" (GRUB_SMX_LEAF_CAPABILITIES), "b" (index)); ++ return caps; ++} ++ ++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 ("getsec" ++ : "=a" (*eax_out), "=b" (*ebx_out), "=c" (*ecx_out) ++ : "a" (GRUB_SMX_LEAF_PARAMETERS), "b" (index)); ++} ++ ++#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) & ~(__typeof__(v))GRUB_SMX_PARAMETER_TYPE_MASK) ++ ++#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) & ~(__typeof__(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_HANDLING 0x00000040 ++#define GRUB_SMX_GET_TXT_EXT_FEATURES(v) (v & (__typeof__(v))(GRUB_SMX_PROCESSOR_BASE_SCRTM|GRUB_SMX_MACHINE_CHECK_HANDLING)) ++ ++#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 ++ ++/* ++ * Measured Launch Environment Developer’s Guide, ++ * Table 29. OS to SINIT Data Table ++ */ ++#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; ++ ++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_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.41.0 + diff --git a/1112-i386-txt-Add-Intel-TXT-core-implementation.patch b/1112-i386-txt-Add-Intel-TXT-core-implementation.patch new file mode 100644 index 0000000..b17be77 --- /dev/null +++ b/1112-i386-txt-Add-Intel-TXT-core-implementation.patch @@ -0,0 +1,1036 @@ +From 459766701425d1cab5bbd33071734424a95a2e3a Mon Sep 17 00:00:00 2001 +From: Ross Philipson +Date: Wed, 7 Aug 2019 13:57:33 -0400 +Subject: [PATCH] i386/txt: Add Intel TXT core implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Ross Philipson +Signed-off-by: Daniel Kiper +Signed-off-by: Michał Żygowski +Signed-off-by: Krystian Hebel +--- + grub-core/loader/i386/txt/txt.c | 997 ++++++++++++++++++++++++++++++++ + include/grub/i386/slaunch.h | 1 - + 2 files changed, 997 insertions(+), 1 deletion(-) + create mode 100644 grub-core/loader/i386/txt/txt.c + +diff --git a/grub-core/loader/i386/txt/txt.c b/grub-core/loader/i386/txt/txt.c +new file mode 100644 +index 000000000000..b92107d50ea3 +--- /dev/null ++++ b/grub-core/loader/i386/txt/txt.c +@@ -0,0 +1,997 @@ ++/* ++ * 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) 2020 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++ ++static grub_err_t ++enable_smx_mode (void) ++{ ++ grub_uint32_t caps; ++ grub_uint64_t feat_ctrl = grub_rdmsr (GRUB_MSR_X86_FEATURE_CONTROL); ++ ++ if (!(feat_ctrl & GRUB_MSR_X86_FEATURE_CTRL_LOCK)) ++ { ++ grub_dprintf ("slaunch", "Firmware didn't lock FEATURE_CONTROL MSR," ++ "locking it now\n"); ++ /* Not setting SENTER_FUNCTIONS and SENTER_ENABLE because they were tested ++ * in grub_txt_verify_platform() */ ++ feat_ctrl |= GRUB_MSR_X86_ENABLE_VMX_OUT_SMX | ++ GRUB_MSR_X86_ENABLE_VMX_IN_SMX | ++ GRUB_MSR_X86_FEATURE_CTRL_LOCK; ++ grub_wrmsr (GRUB_MSR_X86_FEATURE_CONTROL, feat_ctrl); ++ } ++ ++ /* 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 grub_err_t ++grub_txt_smx_parameters (struct grub_smx_parameters *params) ++{ ++ grub_uint32_t index = 0, eax, ebx, ecx, param_type; ++ ++ grub_memset (params, 0, sizeof(*params)); ++ ++ 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) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Too many ACM versions")); ++ 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: ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown SMX parameter")); ++ } ++ ++ ++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++; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++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; ++ grub_err_t err; ++ ++ cr0 = grub_read_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_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")); ++ ++ err = grub_txt_smx_parameters (¶ms); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ 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_HANDLING) ++ 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] = %" PRIxGRUB_UINT64_T " ERROR"), i, ++ mcg_stat); ++ } ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static void ++save_mtrrs (struct grub_txt_os_mle_data *os_mle_data) ++{ ++ grub_uint64_t i; ++ ++ os_mle_data->saved_bsp_mtrrs.default_mem_type = ++ grub_rdmsr (GRUB_MSR_X86_MTRR_DEF_TYPE); ++ ++ os_mle_data->saved_bsp_mtrrs.mtrr_vcnt = ++ grub_rdmsr (GRUB_MSR_X86_MTRRCAP) & GRUB_MSR_X86_VCNT_MASK; ++ ++ if (os_mle_data->saved_bsp_mtrrs.mtrr_vcnt > GRUB_SL_MAX_VARIABLE_MTRRS) ++ { ++ /* 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", ++ os_mle_data->saved_bsp_mtrrs.mtrr_vcnt, ++ GRUB_SL_MAX_VARIABLE_MTRRS); ++ os_mle_data->saved_bsp_mtrrs.mtrr_vcnt = GRUB_SL_MAX_VARIABLE_MTRRS; ++ } ++ ++ for (i = 0; i < os_mle_data->saved_bsp_mtrrs.mtrr_vcnt; ++i) ++ { ++ os_mle_data->saved_bsp_mtrrs.mtrr_pair[i].mtrr_physmask = ++ grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK (i)); ++ os_mle_data->saved_bsp_mtrrs.mtrr_pair[i].mtrr_physbase = ++ grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE (i)); ++ } ++} ++ ++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 */ ++ ++/* ++ * Note: bitfields in following structures are assumed to work on x86 and ++ * nothing else. All compilers supported by GRUB agree when it comes to layout ++ * of bits that is consistent with hardware implementation. It was decided to ++ * use bitfields for better readability instead of manual shifting and masking. ++ */ ++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_PHYSMASK (ndx)); ++ mtrr_physmask.v = 0; ++ grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx), 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 of that MTRR's Size */ ++ /* grub_txt_sinit_select() made sure that base is at least 4K-aligned */ ++ 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_PHYSBASE (ndx)); ++ mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) & ++ SINIT_MTRR_MASK; ++ mtrr_physbase.type = mem_type; ++ grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE (ndx), mtrr_physbase.raw); ++ ++ mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx)); ++ mtrr_physmask.mask = ~(mtrr_s - 1) & SINIT_MTRR_MASK; ++ mtrr_physmask.v = 1; ++ grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx), 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_PHYSBASE (ndx)); ++ mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) & ++ SINIT_MTRR_MASK; ++ mtrr_physbase.type = mem_type; ++ grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE (ndx), 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_PHYSMASK (ndx)); ++ mtrr_physmask.mask = ~(pages_in_range - 1) & SINIT_MTRR_MASK; ++ mtrr_physmask.v = 1; ++ grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx), 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 ++ */ ++static grub_err_t ++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_cr0 (); ++ grub_write_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_cr4 (); ++ grub_write_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); ++ ++ /* Undo some of earlier changes and enable our new settings */ ++ ++ /* Flush caches */ ++ asm volatile ("wbinvd"); ++ ++ /* Enable MTRRs */ ++ set_all_mtrrs (1); ++ ++ /* Restore CR0 (caching) */ ++ grub_write_cr0 (cr0); ++ ++ /* Restore CR4 (global pages) */ ++ grub_write_cr4 (cr4); ++ ++ /* Restore flags */ ++ grub_write_flags_register (eflags); ++ ++ return err; ++} ++ ++/* Adds new element to the end. `size` does not include common header. */ ++/* Assume that heap was cleared and there is enough space to add the element. */ ++static inline struct grub_txt_heap_ext_data_element * ++add_ext_data_elt (struct grub_txt_os_sinit_data *os_sinit_data, ++ grub_uint32_t type, grub_uint32_t size) ++{ ++ struct grub_txt_heap_ext_data_element *elt = ++ (struct grub_txt_heap_ext_data_element *) os_sinit_data->ext_data_elts; ++ ++ while (elt->type != GRUB_TXT_HEAP_EXTDATA_TYPE_END) ++ elt = (struct grub_txt_heap_ext_data_element *)((grub_uint8_t *)elt + elt->size); ++ ++ elt->type = type; ++ elt->size = size + GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE; ++ ++ return elt; ++} ++ ++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; ++ grub_uint64_t size_total; ++ struct grub_txt_os_mle_data *os_mle_data; ++ struct grub_txt_os_sinit_data *os_sinit_data; ++ struct grub_txt_heap_ext_data_element *elt; ++#ifdef GRUB_MACHINE_EFI ++ struct grub_acpi_rsdp_v20 *rsdp; ++#endif ++ ++ /* BIOS data already verified in grub_txt_verify_platform(). */ ++ ++ txt_heap = grub_txt_get_heap (); ++ ++ grub_dprintf ("slaunch", "TXT heap %p\n", txt_heap); ++ ++ /* OS/loader to MLE data. */ ++ ++ os_mle_data = grub_txt_os_mle_data_start (txt_heap); ++ grub_dprintf ("slaunch", "OS MLE data: %p\n", os_mle_data); ++ size = (grub_uint64_t *) ((grub_addr_t) os_mle_data - sizeof (grub_uint64_t)); ++ *size = sizeof (*os_mle_data) + sizeof (grub_uint64_t); ++ ++ if (grub_add (grub_txt_bios_data_size (txt_heap), *size, &size_total) || ++ (size_total > grub_txt_get_heap_size ())) ++ { ++ *size = 0; ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("not enough TXT HEAP space for OsMleData")); ++ } ++ ++ 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_addr; ++ os_mle_data->saved_misc_enable_msr = grub_rdmsr (GRUB_MSR_X86_MISC_ENABLE); ++ ++ os_mle_data->ap_wake_block = slparams->ap_wake_block; ++ os_mle_data->ap_wake_block_size = slparams->ap_wake_block_size; ++ ++ os_mle_data->evtlog_addr = slparams->tpm_evt_log_base; ++ os_mle_data->evtlog_size = slparams->tpm_evt_log_size; ++ ++ grub_dprintf ("slaunch", "Saving MTRRs to OS MLE data\n"); ++ save_mtrrs (os_mle_data); ++ ++ /* OS/loader to SINIT data. */ ++ grub_dprintf ("slaunch", "Get supported OS SINIT data version\n"); ++ 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); ++ grub_dprintf ("slaunch", "OS SINIT data: %p\n", os_sinit_data); ++ 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) + ++ GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE /* End element */; ++ ++ if (grub_get_tpm_ver () == GRUB_TPM_12) ++ *size += GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE + ++ sizeof (struct grub_txt_heap_tpm_event_log_element); ++ else if (grub_get_tpm_ver () == GRUB_TPM_20) ++ *size += GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE + ++ sizeof (struct grub_txt_heap_event_log_pointer2_1_element); ++ else ++ return grub_error (GRUB_ERR_BAD_DEVICE, N_("unsupported TPM version")); ++ ++ if (grub_add (size_total, *size, &size_total) || ++ (size_total > grub_txt_get_heap_size ())) ++ { ++ *size = 0; ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("not enough TXT HEAP space for OsSinitData")); ++ } ++ ++ grub_memset (os_sinit_data, 0, *size); ++ ++#ifdef GRUB_MACHINE_EFI ++ rsdp = grub_acpi_get_rsdpv2 (); ++ ++ if (rsdp == NULL) ++ return grub_error (GRUB_ERR_BAD_DEVICE, N_("ACPI RSDP 2.0 missing\n")); ++ ++ os_sinit_data->efi_rsdp_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); ++ ++ /* ++ * In the latest TXT Software Development Guide as of now (April 2023, ++ * Revision 017.4) bits 4 and 5 (used to be "no legacy PCR usage" and ++ * "auth PCR usage" respectively) of capabilities field bit are reserved. ++ * Bit 4 is ignored, but it is returned as 0 by SINIT[CAPABILITIES], ++ * while bit 5 is forced to 1 for compatibility reasons. This is related ++ * to support for TPM 1.2 devices, which always had this bit set. ++ * ++ * There are TPM 2.0 platforms that will have both bits set. TXT ++ * specification doesn't specify when this has changed, so we can't ++ * reliably test for those. ++ */ ++ os_sinit_data->capabilities = GRUB_TXT_CAPS_TPM_12_AUTH_PCR_USAGE; ++ ++ /* ++ * APs (application processors) can't be brought up by usual INIT-SIPI-SIPI ++ * sequence after Measured Launch, otherwise the MLE integrity is lost. ++ * Choose monitor RLP (responding logical processor, fancy name for AP) wakeup ++ * mechanism first, if that isn't supported fall back to GETSEC[WAKEUP]. */ ++ 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_NOT_IMPLEMENTED_YET, ++ N_("TPM 1.2 detected, but not implemented yet")); ++ 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; ++ ++ elt = add_ext_data_elt(os_sinit_data, ++ GRUB_TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1, ++ sizeof (struct grub_txt_heap_event_log_pointer2_1_element)); ++ elt->event_log_pointer2_1.phys_addr = slparams->tpm_evt_log_base; ++ elt->event_log_pointer2_1.allocated_event_container_size = slparams->tpm_evt_log_size; ++ } ++ ++ elt = add_ext_data_elt(os_sinit_data, GRUB_TXT_HEAP_EXTDATA_TYPE_END, 0); ++ ++ if ((grub_uint8_t *)elt + elt->size > ++ (grub_uint8_t *)grub_txt_sinit_mle_data_start (txt_heap) - sizeof(grub_uint64_t)) ++ return grub_error (GRUB_ERR_BUG, ++ N_("error in OsSinitData size requirements calculation")); ++ ++ /* SinitMleDataSize isn't known at this point, it is crafted by SINIT ACM. ++ * We can only test if size field fits and hope that ACM checks the rest. */ ++ if (grub_add (size_total, sizeof (grub_uint64_t), &size_total) || ++ (size_total > grub_txt_get_heap_size ())) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("not enough TXT HEAP space for SinitMleDataSize")); ++ ++ grub_dprintf ("slaunch", "TXT HEAP init done\n"); ++ ++ 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? Because MLE image may not ++ * start and end at PTE (page) and PDE (2 MiB) boundary... ++ */ ++ return ((((mle_size / GRUB_PAGE_SIZE) + 2) / 512) + /* Number of PTs */ ++// 1 + /* PT */ ++ (((mle_size / (512 * GRUB_PAGE_SIZE)) + 2) / 512) + /* Number of PDs */ ++// 1 + /* PD */ ++ 1) /* PDT */ ++ * 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 requirements here. ++ * ++ * TODO: This function is not able to cover MLEs larger than 1 GiB. Fix it!!! ++ * After fixing increase 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 ++ { ++ /* mle_start may be unaligned, handled by mask in MAKE_PT_MLE_ENTRY */ ++ *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); ++ } ++ /* Add one page in case mle_start isn't aligned */ ++ } while (mle_off - GRUB_PAGE_SIZE + 1 < 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) ++{ ++ union { ++ grub_uint64_t d64; ++ grub_uint32_t d32; ++ grub_uint8_t d8; ++ grub_uint8_t a8[8]; ++ } data; ++ int i; ++ union grub_txt_didvid didvid; ++ ++ data.d64 = grub_txt_reg_pub_read64 (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.d64, !!(data.d64 & GRUB_TXT_STS_SENTER_DONE), ++ !!(data.d64 & GRUB_TXT_STS_SEXIT_DONE), ++ !!(data.d64 & GRUB_TXT_STS_MEM_CONFIG_LOCK), ++ !!(data.d64 & GRUB_TXT_STS_PRIVATE_OPEN), ++ !!(data.d64 & GRUB_TXT_STS_LOCALITY1_OPEN), ++ !!(data.d64 & GRUB_TXT_STS_LOCALITY2_OPEN)); ++ ++ /* Only least significant byte has a meaning. */ ++ data.d8 = grub_txt_reg_pub_read8 (GRUB_TXT_ESTS); ++ grub_printf (" TXT.ESTS: 0x%02x\n" ++ " TXT_RESET.STS: %d\n", data.d8, ++ !!(data.d8 & GRUB_TXT_ESTS_TXT_RESET)); ++ ++ data.d64 = grub_txt_reg_pub_read64 (GRUB_TXT_E2STS); ++ grub_printf (" TXT.E2STS: 0x%016" PRIxGRUB_UINT64_T "\n" ++ " SECRETS.STS: %d\n", data.d64, ++ !!(data.d64 & GRUB_TXT_E2STS_SECRETS)); ++ ++ /* Only least significant 4 bytes have a meaning. */ ++ data.d32 = grub_txt_reg_pub_read32 (GRUB_TXT_ERRORCODE); ++ grub_printf (" TXT.ERRORCODE: 0x%08" PRIxGRUB_UINT32_T "\n", data.d32); ++ ++ didvid.value = grub_txt_reg_pub_read64 (GRUB_TXT_DIDVID); ++ grub_printf (" TXT.DIDVID: 0x%016" PRIxGRUB_UINT64_T "\n" ++ " VID: 0x%04x\n" ++ " DID: 0x%04x\n" ++ " RID: 0x%04x\n" ++ " ID-EXT: 0x%04x\n", ++ didvid.value, didvid.vid, didvid.did, didvid.rid, didvid.id_ext); ++ ++ /* Only least significant 4 bytes have a meaning. */ ++ data.d32 = grub_txt_reg_pub_read32 (GRUB_TXT_VER_FSBIF); ++ grub_printf (" TXT.VER.FSBIF: 0x%08" PRIxGRUB_UINT32_T "\n", data.d32); ++ ++ if ((data.d32 != 0x00000000) && (data.d32 != 0xffffffff)) ++ grub_printf (" DEBUG.FUSE: %d\n", !!(data.d32 & GRUB_TXT_VER_FSBIF_DEBUG_FUSE)); ++ else ++ { ++ /* Only least significant 4 bytes have a meaning. */ ++ data.d32 = grub_txt_reg_pub_read32 (GRUB_TXT_VER_QPIIF); ++ grub_printf (" TXT.VER.QPIIF: 0x%08" PRIxGRUB_UINT32_T "\n" ++ " DEBUG.FUSE: %d\n", data.d32, ++ !!(data.d32 & GRUB_TXT_VER_QPIIF_DEBUG_FUSE)); ++ } ++ ++ /* Only least significant 4 bytes have a meaning. */ ++ data.d32 = grub_txt_reg_pub_read32 (GRUB_TXT_SINIT_BASE); ++ grub_printf (" TXT.SINIT.BASE: 0x%08" PRIxGRUB_UINT32_T "\n", data.d32); ++ ++ /* Only least significant 4 bytes have a meaning. */ ++ data.d32 = grub_txt_reg_pub_read32 (GRUB_TXT_SINIT_SIZE); ++ grub_printf (" TXT.SINIT.SIZE: %" PRIuGRUB_UINT32_T ++ " B (0x%" PRIxGRUB_UINT32_T ")\n", data.d32, data.d32); ++ ++ /* Only least significant 4 bytes have a meaning. */ ++ data.d32 = grub_txt_reg_pub_read32 (GRUB_TXT_HEAP_BASE); ++ grub_printf (" TXT.HEAP.BASE: 0x%08" PRIxGRUB_UINT32_T "\n", data.d32); ++ ++ /* Only least significant 4 bytes have a meaning. */ ++ data.d32 = grub_txt_reg_pub_read32 (GRUB_TXT_HEAP_SIZE); ++ grub_printf (" TXT.HEAP.SIZE: %" PRIuGRUB_UINT32_T ++ " B (0x%" PRIxGRUB_UINT32_T ")\n", data.d32, data.d32); ++ ++ /* Only least significant 4 bytes have a meaning. */ ++ data.d32 = grub_txt_reg_pub_read32 (GRUB_TXT_DPR); ++ grub_printf (" TXT.DPR: 0x%08" PRIxGRUB_UINT32_T "\n" ++ " LOCK: %d\n" ++ " TOP: 0x%08" PRIxGRUB_UINT32_T "\n" ++ " SIZE: %" PRIuGRUB_UINT32_T " MiB\n", ++ data.d32, !!(data.d32 & (1 << 0)), (data.d32 & 0xfff00000), ++ (data.d32 & 0x00000ff0) >> 4); ++ ++ grub_printf (" TXT.PUBLIC.KEY:\n"); ++ ++ for (i = 0; i < 4; ++i) ++ { ++ /* TODO: Check relevant MSRs on SGX platforms. */ ++ data.d64 = grub_txt_reg_pub_read64 (GRUB_TXT_PUBLIC_KEY + i * sizeof (grub_uint64_t)); ++ grub_printf (" %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x%s", data.a8[0], data.a8[1], ++ data.a8[2], data.a8[3], data.a8[4], data.a8[5], data.a8[6], data.a8[7], ++ (i < 3) ? ":\n" : "\n"); ++ } ++} ++ ++grub_err_t ++grub_txt_boot_prepare (struct grub_slaunch_params *slparams) ++{ ++ grub_err_t err; ++ struct grub_txt_mle_header *mle_header; ++ struct grub_txt_acm_header *sinit_base; ++ int i; ++ ++ sinit_base = grub_txt_sinit_select (grub_slaunch_module ()); ++ ++ if (sinit_base == NULL) ++ return grub_errno; ++ ++ grub_dprintf ("slaunch", "Init TXT heap\n"); ++ err = init_txt_heap (slparams, sinit_base); ++ ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ grub_dprintf ("slaunch", "TXT heap successfully prepared\n"); ++ ++ /* 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; ++ ++ /* ++ * Access to locality 4 isn't available to software, skip it. Don't bother ++ * checking TPM status, we have no tools for recovering from bad state better ++ * than command abort, which is part of locality relinquish. Write performed ++ * by the following function is no-op if locality is neither active nor ++ * requested. ++ */ ++ for (i = 0; i < 4; ++i) ++ grub_tpm_relinquish_locality (i); ++ ++ grub_dprintf ("slaunch", "TPM localities relinquished\n"); ++ ++ err = set_mtrrs_for_acmod (sinit_base); ++ if (err) ++ return grub_error (err, N_("secure launch failed to set MTRRs for ACM")); ++ ++ grub_dprintf ("slaunch", "MTRRs set for ACMOD\n"); ++ ++ err = grub_txt_prepare_cpu (); ++ if ( err ) ++ return err; ++ ++ grub_dprintf ("slaunch", "CPU prepared for secure launch\n"); ++ ++ if (!(grub_rdmsr (GRUB_MSR_X86_APICBASE) & GRUB_MSR_X86_APICBASE_BSP)) ++ return grub_error (GRUB_ERR_BAD_DEVICE, N_("secure launch must run on BSP")); ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/include/grub/i386/slaunch.h b/include/grub/i386/slaunch.h +index 7f7709cda75e..93a491e4fc9e 100644 +--- a/include/grub/i386/slaunch.h ++++ b/include/grub/i386/slaunch.h +@@ -33,7 +33,6 @@ + + #ifndef ASM_FILE + +-#include + #include + + struct grub_slaunch_params +-- +2.41.0 + diff --git a/1113-i386-txt-Add-Intel-TXT-ACM-module-support.patch b/1113-i386-txt-Add-Intel-TXT-ACM-module-support.patch new file mode 100644 index 0000000..1725cef --- /dev/null +++ b/1113-i386-txt-Add-Intel-TXT-ACM-module-support.patch @@ -0,0 +1,622 @@ +From 0ce784f00a21af6b379ece3e2c681fa47b945a5d Mon Sep 17 00:00:00 2001 +From: Ross Philipson +Date: Wed, 7 Aug 2019 13:59:18 -0400 +Subject: [PATCH] i386/txt: Add Intel TXT ACM module support + +Signed-off-by: Ross Philipson +Signed-off-by: Daniel Kiper +Signed-off-by: Krystian Hebel +--- + grub-core/loader/i386/txt/acmod.c | 600 ++++++++++++++++++++++++++++++ + 1 file changed, 600 insertions(+) + create mode 100644 grub-core/loader/i386/txt/acmod.c + +diff --git a/grub-core/loader/i386/txt/acmod.c b/grub-core/loader/i386/txt/acmod.c +new file mode 100644 +index 000000000000..6a8338abfde5 +--- /dev/null ++++ b/grub-core/loader/i386/txt/acmod.c +@@ -0,0 +1,600 @@ ++/* ++ * acmod.c: support functions for use of Intel(r) TXT Authenticated ++ * Code (AC) Modules ++ * ++ * 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) 2020 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Macro that returns value of it->field if it's inside info table, 0 otherwise. ++ * Fields at or below 'length' ('uuid', 'chipset_acm_type', 'version') don't ++ * benefit from this macro, because it requires that 'length' (and by extension ++ * fields below that) is valid. ++ */ ++#define info_table_get(it, field) \ ++ (__builtin_offsetof(struct grub_txt_acm_info_table, field) + sizeof(it->field)\ ++ <= it->length ? it->field : 0) ++ ++/* ++ * Returns hdr + offset if [offset, offset + count * size) is within the bounds ++ * of the ACM, NULL otherwise. ++ */ ++static void* ++n_fit_in_acm (struct grub_txt_acm_header *hdr, grub_uint32_t offset, ++ grub_uint32_t size, grub_uint32_t count) ++{ ++ grub_uint32_t total_size, elem_end; ++ /* ACM size overflow was checked in is_acmod() */ ++ grub_uint32_t acm_len = hdr->size * 4; ++ ++ /* ++ * `offset` will often come from `info_table_get`, and this is the most ++ * convenient place to check for the macro returning zero. This is fine, since ++ * there is no legitimate reason to access the zero offset in this manner. ++ */ ++ if ( offset == 0 ) ++ return NULL; ++ ++ if ( grub_mul (size, count, &total_size) ) ++ return NULL; ++ ++ if ( grub_add (offset, total_size, &elem_end) ) ++ return NULL; ++ ++ if ( elem_end > acm_len ) ++ return NULL; ++ ++ /* Not checking if (hdr + elem_end) overflows. We know that (hdr + acm_len) ++ * doesn't, and that elem_end <= acm_len. For the same reason we don't have to ++ * check if (hdr + offset) overflows. */ ++ ++ return (void *)((unsigned long)hdr + offset); ++} ++ ++static void* ++fits_in_acm (struct grub_txt_acm_header *hdr, grub_uint32_t offset, ++ grub_uint32_t size) ++{ ++ return n_fit_in_acm(hdr, offset, size, 1); ++} ++ ++/* ++ * Returns pointer to ACM information table. If the table is located outside of ++ * ACM or its reported size is too small to cover at least 'length' field, ++ * NULL is returned instead. ++ */ ++static struct grub_txt_acm_info_table* ++get_acmod_info_table (struct grub_txt_acm_header* hdr) ++{ ++ grub_uint32_t user_area_off, info_table_size; ++ struct grub_txt_acm_info_table *ptr = NULL; ++ /* Minimum size required to read full size of table */ ++ info_table_size = __builtin_offsetof (struct grub_txt_acm_info_table, length) ++ + sizeof(ptr->length); ++ ++ /* Overflow? */ ++ if ( grub_add (hdr->header_len, hdr->scratch_size, &user_area_off) ) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM header length plus scratch size overflows")); ++ return NULL; ++ } ++ ++ if ( grub_mul (user_area_off, 4, &user_area_off) ) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM header length and scratch size in bytes overflows")); ++ return NULL; ++ } ++ ++ ptr = fits_in_acm(hdr, user_area_off, info_table_size); ++ ++ if ( ptr != NULL ) ++ { ++ if ( info_table_get (ptr, length) < info_table_size ) ++ return NULL; ++ ++ info_table_size = info_table_get (ptr, length); ++ ptr = fits_in_acm(hdr, user_area_off, info_table_size); ++ } ++ ++ return ptr; ++} ++ ++/* ++ * Function returns pointer to chipset ID list, after checking that ++ * grub_txt_acm_chipset_id_list and all grub_txt_acm_chipset_id structures are ++ * within ACM. Otherwise, NULL is returned. ++ */ ++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 id_entries_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 == NULL ) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM info table out of bounds")); ++ return NULL; ++ } ++ ++ chipset_id_list = fits_in_acm(hdr, info_table_get (info_table, chipset_id_list), ++ sizeof(struct grub_txt_acm_chipset_id_list)); ++ if ( chipset_id_list == NULL ) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM chipset ID list out of bounds")); ++ return NULL; ++ } ++ ++ /* Overflows were checked by fits_in_acm() */ ++ id_entries_off = info_table->chipset_id_list + sizeof(*chipset_id_list); ++ ++ if ( n_fit_in_acm( hdr, id_entries_off, sizeof(struct grub_txt_acm_chipset_id), ++ chipset_id_list->count ) == NULL ) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM chipset ID entries out of bounds")); ++ return NULL; ++ } ++ ++ return chipset_id_list; ++} ++ ++/* ++ * Function returns pointer to processor ID list, after checking that ++ * grub_txt_acm_processor_id_list and all grub_txt_acm_processor_id structures ++ * are within ACM. Otherwise, NULL is returned. ++ */ ++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 id_entries_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 ) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM info table out of bounds")); ++ return NULL; ++ } ++ ++ proc_id_list = fits_in_acm(hdr, info_table_get (info_table, processor_id_list), ++ sizeof(*proc_id_list)); ++ if ( proc_id_list == NULL ) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM processor ID list out of bounds")); ++ return NULL; ++ } ++ ++ /* Overflows were checked by fits_in_acm() */ ++ id_entries_off = info_table->processor_id_list + sizeof(*proc_id_list); ++ ++ if ( n_fit_in_acm ( hdr, id_entries_off, sizeof(*proc_id_list), ++ proc_id_list->count ) == NULL ) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("ACM processor ID entries out of bounds")); ++ 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; ++ grub_uint32_t size_from_hdr; ++ ++ /* First check size */ ++ if ( acmod_size < sizeof (*acm_hdr) ) ++ return 0; ++ ++ /* Then check overflow */ ++ if ( grub_mul (acm_hdr->size, 4, &size_from_hdr) ) ++ return 0; ++ ++ /* Then check size equivalency */ ++ if ( acmod_size != size_from_hdr ) ++ return 0; ++ ++ /* Then check type, sub-type and vendor */ ++ if ( (acm_hdr->module_type != GRUB_TXT_ACM_MODULE_TYPE) || ++ (acm_hdr->module_sub_type != GRUB_TXT_ACM_MODULE_SUB_TYPE_TXT_ACM) || ++ (acm_hdr->module_vendor != GRUB_TXT_ACM_MODULE_VENDOR_INTEL) ) ++ return 0; ++ ++ info_table = get_acmod_info_table (acm_hdr); ++ if ( info_table == NULL ) ++ return 0; ++ ++ /* Check if ACM UUID is present */ ++ if ( grub_memcmp (&(info_table->uuid), GRUB_TXT_ACM_UUID, 16) ) ++ return 0; ++ ++ /* ++ * TXT specification doesn't give clear mapping of info table size to version, ++ * so just warn if the size is different than expected but try to use it ++ * anyway. info_table_get() macro does enough testing to not read outside ++ * of info table. ++ */ ++ if ( info_table->length < sizeof(*info_table) ) ++ grub_dprintf ("slaunch", "Info table size (%x) smaller than expected (%" ++ PRIxGRUB_SIZE ")\n", ++ info_table->length, sizeof(*info_table)); ++ ++ if ( type_out ) ++ *type_out = info_table_get (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; ++ grub_uint32_t tmp; ++ ++ if ( sinit_region_base == NULL ) ++ return NULL; ++ ++ if ( bios_data->bios_sinit_size == 0 ) ++ return NULL; ++ ++ /* Check if ACM crosses 4G */ ++ if ( grub_add ( (unsigned long)sinit_region_base, bios_data->bios_sinit_size, ++ &tmp) ) ++ 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) ) ++ { ++ grub_dprintf("slaunch", "BIOS SINIT module did not pass reasonableness checks"); ++ 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 grub_txt_is_sinit_acmod() */ ++ info_table = get_acmod_info_table (hdr); ++ ++ if ( info_table == NULL ) ++ return 0; ++ ++ return info_table_get (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 grub_txt_is_sinit_acmod() */ ++ info_table = get_acmod_info_table (hdr); ++ ++ if ( info_table == NULL || info_table->version < 3 ) ++ return 0; ++ ++ return info_table_get (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; ++} ++ ++static int ++didvid_matches(union grub_txt_didvid didvid, ++ struct grub_txt_acm_chipset_id *chipset_id) ++{ ++ if ( didvid.vid != chipset_id->vendor_id ) ++ return 0; ++ ++ if ( didvid.did != chipset_id->device_id ) ++ return 0; ++ ++ /* If RevisionIdMask is 0, the RevisionId field must exactly match the ++ * TXT.DIDVID.RID field. */ ++ if ( (chipset_id->flags & GRUB_TXT_ACM_REVISION_ID_MASK) == 0 && ++ ( didvid.rid == chipset_id->revision_id ) ) ++ return 1; ++ ++ /* If RevisionIdMask is 1, the RevisionId field is a bitwise mask that can be ++ * used to test for any bits set in the TXT.DIDVID.RID field. If any bits are ++ * set, the RevisionId is a match. */ ++ if ( (chipset_id->flags & GRUB_TXT_ACM_REVISION_ID_MASK) != 0 && ++ ( didvid.rid & chipset_id->revision_id ) != 0 ) ++ return 1; ++ ++ return 0; ++} ++ ++int ++grub_txt_acmod_match_platform (struct grub_txt_acm_header *hdr) ++{ ++ union grub_txt_didvid didvid; ++ grub_uint32_t fms, ign, i, ver; ++ grub_uint64_t platform_id; ++ 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 */ ++ info_table = get_acmod_info_table (hdr); ++ if ( info_table == NULL ) ++ return 0; ++ ++ /* Get chipset fusing, device, and vendor id info */ ++ didvid.value = grub_txt_reg_pub_read64 (GRUB_TXT_DIDVID); ++ ++ ver = grub_txt_reg_pub_read32 (GRUB_TXT_VER_QPIIF); ++ if ( ver == 0xffffffff || ver == 0x00 ) /* Old CPU, need to use VER.FSBIF */ ++ ver = grub_txt_reg_pub_read32 (GRUB_TXT_VER_FSBIF); ++ ++ grub_dprintf ("slaunch", "chipset production fused: %s, " ++ "chipset vendor: 0x%x, device: 0x%x, revision: 0x%x\n", ++ (ver & GRUB_TXT_VERSION_PROD_FUSED) ? "yes" : "no" , 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 & GRUB_TXT_VERSION_PROD_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 == NULL ) ++ 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_matches ( didvid, chipset_id) ) ++ break; ++ } ++ ++ if ( i >= chipset_id_list->count ) ++ { ++ /* ++ * Version 9 introduces flexible ACM information table format, not yet ++ * supported by this code. ++ * ++ * TXT spec says that 9 will be the final version and further changes will ++ * be reflected elsewhere, but check for higher values too in case they ++ * change their mind. ++ */ ++ if ( info_table->version >= 9 ) ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ N_("chipset id mismatch, flexible ACM info list may contain" ++ " matching entry but it isn't yet supported by code")); ++ else ++ grub_error (GRUB_ERR_BAD_DEVICE, N_("chipset id mismatch")); ++ ++ return 0; ++ } ++ ++ /* ++ * Unfortunately the spec isn't too clear on what the changes to the info ++ * table were, across the different versions, but an old version of the entire ++ * spec document shows that the processor table field didn't exist when the ++ * latest version of the info table was 3. ++ */ ++ if ( info_table->version < 4 ) ++ return 1; ++ ++ /* Check if processor family/model/stepping and platform IDs match */ ++ proc_id_list = get_acmod_processor_list(hdr); ++ if ( proc_id_list == NULL ) ++ return 0; ++ ++ 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_("processor id mismatch")); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* ++ * Choose between the BIOS-provided and user-provided SINIT ACMs, and copy the ++ * chosen module to the SINIT memory. ++ */ ++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_size, sinit_region_size; ++ ++ sinit_region_base = (void *)(grub_addr_t) grub_txt_reg_pub_read32 (GRUB_TXT_SINIT_BASE); ++ sinit_region_size = (grub_uint32_t) grub_txt_reg_pub_read32 (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 ( ((grub_addr_t) sinit_region_base & ((1 << GRUB_PAGE_SHIFT) - 1)) != 0 ) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("SINIT ACM base not properly aligned")); ++ 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 (grub_mul (sinit->size, 4, &sinit_size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("SINIT ACM size in bytes overflows")); ++ return NULL; ++ } ++ ++ if (sinit_size > 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); ++ return NULL; ++ } ++ ++ grub_memcpy (sinit_region_base, sinit, sinit_size); ++ ++ return sinit_region_base; ++} +-- +2.41.0 + diff --git a/1114-i386-txt-Add-Intel-TXT-verification-routines.patch b/1114-i386-txt-Add-Intel-TXT-verification-routines.patch new file mode 100644 index 0000000..11d8698 --- /dev/null +++ b/1114-i386-txt-Add-Intel-TXT-verification-routines.patch @@ -0,0 +1,300 @@ +From b3a5c6f2f404ecd814a938fa643a114d71fdd752 Mon Sep 17 00:00:00 2001 +From: Ross Philipson +Date: Wed, 7 Aug 2019 14:46:17 -0400 +Subject: [PATCH] i386/txt: Add Intel TXT verification routines + +Signed-off-by: Ross Philipson +Signed-off-by: Daniel Kiper +Signed-off-by: Krystian Hebel +--- + grub-core/loader/i386/txt/verify.c | 278 +++++++++++++++++++++++++++++ + 1 file changed, 278 insertions(+) + create mode 100644 grub-core/loader/i386/txt/verify.c + +diff --git a/grub-core/loader/i386/txt/verify.c b/grub-core/loader/i386/txt/verify.c +new file mode 100644 +index 000000000000..5205c931c35b +--- /dev/null ++++ b/grub-core/loader/i386/txt/verify.c +@@ -0,0 +1,278 @@ ++/* ++ * verify.c: verify that platform and processor supports Intel(r) TXT ++ * ++ * Copyright (c) 2003-2010, 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) 2020 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* 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) ++{ ++ if ( elt->size != GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE + ++ sizeof(struct grub_txt_heap_bios_spec_ver_element) ) ++ 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_uint64_t acm_addrs_size; ++ grub_uint32_t i; ++ ++ if ( elt->size < GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE + ++ sizeof(struct grub_txt_heap_acm_element) || ++ grub_mul (elt->acm.num_acms, sizeof(grub_uint64_t), &acm_addrs_size) || ++ elt->size - (GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE + sizeof(elt->acm)) != ++ acm_addrs_size ) ++ 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 ( elt->acm.num_acms == 0 ) ++ grub_printf ("WARNING: HEAP_ACM element has no ACM addrs\n"); ++ ++ for ( i = 0; i < elt->acm.num_acms; i++ ) ++ { ++ if ( elt->acm.addr[i] == 0 ) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("HEAP_ACM element ACM addr (%d) is NULL"), i); ++ ++ if ( elt->acm.addr[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) ++{ ++ if ( elt->size < GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE + ++ sizeof(struct grub_txt_heap_custom_element) ) ++ 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_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 < GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE ) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("TXT heap ext data elements too small")); ++ ++ for ( ; ; ) ++ { ++ if ( elts_size < GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE || ++ elt->size < GRUB_TXT_HEAP_ELEMENT_HEADER_SIZE || ++ elts_size < elt->size ) ++ 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; ++ /* These shouldn't be present in BIOS data, treat them as errors */ ++ case GRUB_TXT_HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR: ++ case GRUB_TXT_HEAP_EXTDATA_TYPE_MADT: ++ case GRUB_TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1: ++ case GRUB_TXT_HEAP_EXTDATA_TYPE_MCFG: ++ default: ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("unknown element: type: %u, size: %u\n"), ++ elt->type, elt->size); ++ } ++ ++ 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, errorcode, heap_base, heap_size; ++ grub_uint64_t bios_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_X86_CPUID_FEATURES_ECX_SMX)) ++ 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. ++ */ ++ ++ errorcode = grub_txt_reg_pub_read32 (GRUB_TXT_ERRORCODE); ++ /* 0 - no previous SENTER, 0xC0000001 - previous SENTER succeeded */ ++ if ( errorcode != 0 && errorcode != 0xC0000001 ) ++ return grub_error (GRUB_ERR_BAD_DEVICE, ++ N_("TXT_ERRORCODE reports failure: 0x%08" PRIxGRUB_UINT32_T), ++ errorcode); ++ ++ if (grub_txt_reg_pub_read8 (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 reasonable. ++ */ ++ ++ txt_heap = grub_txt_get_heap (); ++ heap_base = grub_txt_reg_pub_read32 (GRUB_TXT_HEAP_BASE); ++ heap_size = grub_txt_reg_pub_read32 (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 < sizeof (grub_uint64_t) + sizeof (*bios_data) || ++ 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); ++ ++ /* ++ * grub_uint32_t mle_flags is supposed to be added in version 5, however, the ++ * only ACM in 630744_003 package that is version 4 (Sandy Bridge & Ivy Bridge ++ * SNB_IVB_SINIT_20190708_PW.bin) seems to also have this field, or at least ++ * a placeholder for it. ++ */ ++ 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.41.0 + diff --git a/1115-i386-txt-Initialize-TPM-1.2-event-log-in-TXT-heap.patch b/1115-i386-txt-Initialize-TPM-1.2-event-log-in-TXT-heap.patch new file mode 100644 index 0000000..9ed7463 --- /dev/null +++ b/1115-i386-txt-Initialize-TPM-1.2-event-log-in-TXT-heap.patch @@ -0,0 +1,170 @@ +From f13b0f94d0ffc26bd936d25233ecbd20d5e5b866 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= +Date: Wed, 31 Aug 2022 14:37:49 +0200 +Subject: [PATCH] i386/txt: Initialize TPM 1.2 event log in TXT heap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Michał Żygowski +Signed-off-by: Krystian Hebel +--- + grub-core/loader/i386/txt/txt.c | 62 +++++++++++++++++++++++++++++++-- + include/grub/i386/txt.h | 31 +++++++++++++++++ + 2 files changed, 91 insertions(+), 2 deletions(-) + +diff --git a/grub-core/loader/i386/txt/txt.c b/grub-core/loader/i386/txt/txt.c +index b92107d50ea3..44a0b5c01bf3 100644 +--- a/grub-core/loader/i386/txt/txt.c ++++ b/grub-core/loader/i386/txt/txt.c +@@ -519,6 +519,32 @@ set_mtrrs_for_acmod (struct grub_txt_acm_header *hdr) + return err; + } + ++void ++grub_txt_init_tpm_event_log (void *buf, grub_size_t size) ++{ ++ struct event_log_container *elog; ++ ++ if (buf == NULL || size == 0) ++ 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 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); ++} ++ + /* Adds new element to the end. `size` does not include common header. */ + /* Assume that heap was cleared and there is enough space to add the element. */ + static inline struct grub_txt_heap_ext_data_element * +@@ -657,6 +683,8 @@ 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 %08x\n", sinit_caps); ++ + /* + * In the latest TXT Software Development Guide as of now (April 2023, + * Revision 017.4) bits 4 and 5 (used to be "no legacy PCR usage" and +@@ -671,6 +699,25 @@ init_txt_heap (struct grub_slaunch_params *slparams, struct grub_txt_acm_header + */ + os_sinit_data->capabilities = 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; ++ } ++ } ++ + /* + * APs (application processors) can't be brought up by usual INIT-SIPI-SIPI + * sequence after Measured Launch, otherwise the MLE integrity is lost. +@@ -687,10 +734,21 @@ 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_NOT_IMPLEMENTED_YET, +- N_("TPM 1.2 detected, but not implemented yet")); ++ { ++ 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; ++ ++ elt = add_ext_data_elt(os_sinit_data, ++ GRUB_TXT_HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR, ++ sizeof (struct grub_txt_heap_tpm_event_log_element)); ++ elt->tpm_event_log.event_log_phys_addr = slparams->tpm_evt_log_base; ++ } + 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 a7ddd3a66702..155ebab0ff6a 100644 +--- a/include/grub/i386/txt.h ++++ b/include/grub/i386/txt.h +@@ -22,6 +22,7 @@ + #define GRUB_TXT_H 1 + + #include ++#include + #include + #include + #include +@@ -679,6 +680,34 @@ 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 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 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 tpm12_pcr_event pcr_events[]; ++} GRUB_PACKED; ++ + 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); +@@ -692,6 +721,8 @@ extern struct grub_txt_acm_header* grub_txt_sinit_select (struct grub_txt_acm_he + extern grub_err_t grub_txt_verify_platform (void); + extern grub_err_t grub_txt_prepare_cpu (void); + ++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.41.0 + diff --git a/1116-i386-txt-switch-to-using-Secure-Launch-Resource-Tabl.patch b/1116-i386-txt-switch-to-using-Secure-Launch-Resource-Tabl.patch new file mode 100644 index 0000000..c8699cf --- /dev/null +++ b/1116-i386-txt-switch-to-using-Secure-Launch-Resource-Tabl.patch @@ -0,0 +1,331 @@ +From f5ce8a71089c4cd2899e4f191aa0fc7ca3c79d79 Mon Sep 17 00:00:00 2001 +From: Ross Philipson +Date: Fri, 13 Jan 2023 15:11:26 -0500 +Subject: [PATCH] i386/txt: switch to using Secure Launch Resource Table + interface + +Signed-off-by: Ross Philipson +Signed-off-by: Sergii Dmytruk +--- + grub-core/loader/i386/txt/txt.c | 109 ++++++++++++++++++++++++-------- + include/grub/i386/slaunch.h | 30 ++++++++- + include/grub/i386/txt.h | 26 +++----- + 3 files changed, 121 insertions(+), 44 deletions(-) + +diff --git a/grub-core/loader/i386/txt/txt.c b/grub-core/loader/i386/txt/txt.c +index 44a0b5c01bf3..cc4db716d205 100644 +--- a/grub-core/loader/i386/txt/txt.c ++++ b/grub-core/loader/i386/txt/txt.c +@@ -60,6 +60,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -75,6 +76,8 @@ + + #define OS_SINIT_DATA_MIN_VER OS_SINIT_DATA_TPM_12_VER + ++static struct grub_slr_entry_intel_info slr_intel_info_staging = {0}; ++ + static grub_err_t + enable_smx_mode (void) + { +@@ -249,33 +252,39 @@ grub_txt_prepare_cpu (void) + } + + static void +-save_mtrrs (struct grub_txt_os_mle_data *os_mle_data) ++save_mtrrs (struct grub_slr_txt_mtrr_state *saved_bsp_mtrrs) + { + grub_uint64_t i; + +- os_mle_data->saved_bsp_mtrrs.default_mem_type = ++ saved_bsp_mtrrs->default_mem_type = + grub_rdmsr (GRUB_MSR_X86_MTRR_DEF_TYPE); + +- os_mle_data->saved_bsp_mtrrs.mtrr_vcnt = ++ saved_bsp_mtrrs->mtrr_vcnt = + grub_rdmsr (GRUB_MSR_X86_MTRRCAP) & GRUB_MSR_X86_VCNT_MASK; + +- if (os_mle_data->saved_bsp_mtrrs.mtrr_vcnt > GRUB_SL_MAX_VARIABLE_MTRRS) ++ 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", +- os_mle_data->saved_bsp_mtrrs.mtrr_vcnt, +- GRUB_SL_MAX_VARIABLE_MTRRS); +- os_mle_data->saved_bsp_mtrrs.mtrr_vcnt = GRUB_SL_MAX_VARIABLE_MTRRS; ++ saved_bsp_mtrrs->mtrr_vcnt, ++ GRUB_TXT_VARIABLE_MTRRS_LENGTH); ++ saved_bsp_mtrrs->mtrr_vcnt = GRUB_TXT_VARIABLE_MTRRS_LENGTH; + } + +- for (i = 0; i < os_mle_data->saved_bsp_mtrrs.mtrr_vcnt; ++i) ++ for (i = 0; i < saved_bsp_mtrrs->mtrr_vcnt; ++i) + { +- os_mle_data->saved_bsp_mtrrs.mtrr_pair[i].mtrr_physmask = ++ saved_bsp_mtrrs->mtrr_pair[i].mtrr_physmask = + grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK (i)); +- os_mle_data->saved_bsp_mtrrs.mtrr_pair[i].mtrr_physbase = ++ saved_bsp_mtrrs->mtrr_pair[i].mtrr_physbase = + grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE (i)); + } ++ /* Zero unused array items. */ ++ for ( ; i < GRUB_TXT_VARIABLE_MTRRS_LENGTH; ++i) ++ { ++ saved_bsp_mtrrs->mtrr_pair[i].mtrr_physmask = 0; ++ saved_bsp_mtrrs->mtrr_pair[i].mtrr_physbase = 0; ++ } + } + + static void +@@ -545,6 +554,20 @@ grub_txt_init_tpm_event_log (void *buf, grub_size_t size) + elog->next_event_offset = sizeof(*elog); + } + ++static void ++setup_txt_slrt_entry (struct grub_slaunch_params *slparams, ++ struct grub_txt_os_mle_data *os_mle_data) ++{ ++ struct grub_slr_table *slr_table = slparams->slr_table_mem; ++ struct grub_slr_entry_hdr *txt_info; ++ ++ grub_slr_add_entry (slr_table, &slr_intel_info_staging.hdr); ++ ++ txt_info = grub_slr_next_entry_by_tag (slr_table, NULL, GRUB_SLR_ENTRY_INTEL_INFO); ++ os_mle_data->txt_info = (grub_addr_t) slparams->slr_table_base ++ + ((grub_addr_t) txt_info - (grub_addr_t) slparams->slr_table_mem); ++} ++ + /* Adds new element to the end. `size` does not include common header. */ + /* Assume that heap was cleared and there is enough space to add the element. */ + static inline struct grub_txt_heap_ext_data_element * +@@ -590,6 +613,20 @@ init_txt_heap (struct grub_slaunch_params *slparams, struct grub_txt_acm_header + size = (grub_uint64_t *) ((grub_addr_t) os_mle_data - sizeof (grub_uint64_t)); + *size = sizeof (*os_mle_data) + sizeof (grub_uint64_t); + ++ if (slparams->slr_table_base == GRUB_SLAUNCH_STORE_IN_OS2MLE) ++ { ++ /* SLRT needs to be at least 4-byte aligned per specification. */ ++ slparams->slr_table_base = ++ ALIGN_UP ((grub_addr_t) os_mle_data + sizeof (*os_mle_data), 4); ++ ++ /* Recompute size including SLRT table in it. */ ++ *size = (slparams->slr_table_base + slparams->slr_table_size) ++ - ((grub_addr_t) os_mle_data - sizeof (grub_uint64_t)); ++ ++ /* Size of heap sections should be a multiple of 8. */ ++ *size = ALIGN_UP (*size, 8); ++ } ++ + if (grub_add (grub_txt_bios_data_size (txt_heap), *size, &size_total) || + (size_total > grub_txt_get_heap_size ())) + { +@@ -602,16 +639,20 @@ init_txt_heap (struct grub_slaunch_params *slparams, struct grub_txt_acm_header + + os_mle_data->version = GRUB_SL_OS_MLE_STRUCT_VERSION; + os_mle_data->boot_params_addr = slparams->boot_params_addr; +- os_mle_data->saved_misc_enable_msr = grub_rdmsr (GRUB_MSR_X86_MISC_ENABLE); ++ 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; + +- os_mle_data->evtlog_addr = slparams->tpm_evt_log_base; +- os_mle_data->evtlog_size = slparams->tpm_evt_log_size; ++ /* Setup the TXT specific SLR information */ ++ 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.saved_misc_enable_msr = ++ grub_rdmsr (GRUB_MSR_X86_MISC_ENABLE); + ++ /* Save the BSPs MTRR state so post launch can restore it. */ + grub_dprintf ("slaunch", "Saving MTRRs to OS MLE data\n"); +- save_mtrrs (os_mle_data); ++ save_mtrrs (&slr_intel_info_staging.saved_bsp_mtrrs); + + /* OS/loader to SINIT data. */ + grub_dprintf ("slaunch", "Get supported OS SINIT data version\n"); +@@ -999,9 +1040,10 @@ 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; +- int i; + + sinit_base = grub_txt_sinit_select (grub_slaunch_module ()); + +@@ -1017,24 +1059,22 @@ grub_txt_boot_prepare (struct grub_slaunch_params *slparams) + grub_dprintf ("slaunch", "TXT heap successfully prepared\n"); + + /* Update the MLE header. */ +- mle_header = (struct grub_txt_mle_header *)(grub_addr_t) (slparams->mle_start + slparams->mle_header_offset); ++ mle_header = ++ (struct grub_txt_mle_header *) ((grub_uint8_t *) slparams->mle_mem + 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; + +- /* +- * Access to locality 4 isn't available to software, skip it. Don't bother +- * checking TPM status, we have no tools for recovering from bad state better +- * than command abort, which is part of locality relinquish. Write performed +- * by the following function is no-op if locality is neither active nor +- * requested. +- */ +- for (i = 0; i < 4; ++i) +- grub_tpm_relinquish_locality (i); ++ /* Setup of SLR table. */ ++ grub_slaunch_init_slrt_storage (GRUB_SLR_INTEL_TXT); ++ txt_heap = grub_txt_get_heap (); ++ os_mle_data = grub_txt_os_mle_data_start (txt_heap); ++ setup_txt_slrt_entry (slparams, os_mle_data); + +- grub_dprintf ("slaunch", "TPM localities relinquished\n"); ++ grub_tpm_relinquish_locality (0); ++ grub_dprintf ("slaunch", "Relinquished TPM locality 0\n"); + + err = set_mtrrs_for_acmod (sinit_base); + if (err) +@@ -1053,3 +1093,20 @@ grub_txt_boot_prepare (struct grub_slaunch_params *slparams) + + return GRUB_ERR_NONE; + } ++ ++void ++grub_txt_add_slrt_policy_entries (void) ++{ ++ struct grub_txt_os_mle_data *os_mle_data; ++ grub_uint8_t *txt_heap; ++ ++ txt_heap = grub_txt_get_heap (); ++ os_mle_data = grub_txt_os_mle_data_start (txt_heap); ++ ++ grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_DATA_PCR, ++ GRUB_SLR_ET_TXT_OS2MLE, ++ /*flags=*/0, ++ (grub_addr_t) os_mle_data, ++ sizeof(*os_mle_data), ++ "Measured TXT OS-MLE data"); ++} +diff --git a/include/grub/i386/slaunch.h b/include/grub/i386/slaunch.h +index 93a491e4fc9e..a694260cbeea 100644 +--- a/include/grub/i386/slaunch.h ++++ b/include/grub/i386/slaunch.h +@@ -31,6 +31,19 @@ + + #define GRUB_SLAUNCH_TPM_EVT_LOG_SIZE (8 * GRUB_PAGE_SIZE) + ++/* ++ * Special value for slr_table_base of struct grub_slaunch_params that indicates ++ * that the table should be stored near OS2MLE data (right after it). ++ * ++ * In this case: ++ * 1. Platform-specific code (e.g., TXT-code) is responsible for setting ++ * slr_table_base to its final value ++ * 2. SLRT should be copied from slr_table_mem to slr_table_base after invoking ++ * grub_slaunch_finish_slr_table () by the code which used this special ++ * value. ++ */ ++#define GRUB_SLAUNCH_STORE_IN_OS2MLE ((grub_uint64_t) 0xFFFFFFFFFFFFFFFF) ++ + #ifndef ASM_FILE + + #include +@@ -38,11 +51,16 @@ + struct grub_slaunch_params + { + grub_uint32_t boot_params_addr; ++ grub_uint64_t slr_table_base; ++ /* This is size of SLRT buffer, so maximum size of the table. */ ++ grub_uint32_t slr_table_size; ++ void *slr_table_mem; + grub_uint32_t mle_start; + grub_uint32_t mle_size; +- void *mle_ptab_mem; ++ void *mle_mem; + 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; +@@ -56,6 +74,16 @@ extern grub_uint32_t grub_slaunch_platform_type (void); + extern void *grub_slaunch_module (void); + extern struct grub_slaunch_params *grub_slaunch_params (void); + ++extern void grub_slaunch_init_slrt_storage (int arch); ++extern void grub_slaunch_add_slrt_policy_entries (void); ++extern void grub_slaunch_add_slrt_policy_entry (grub_uint16_t pcr, ++ grub_uint16_t entity_type, ++ grub_uint16_t flags, ++ grub_uint64_t entity, ++ grub_uint64_t size, ++ const char *evt_info); ++extern void grub_slaunch_finish_slr_table (void); ++ + #endif /* ASM_FILE */ + + #endif /* GRUB_I386_SLAUNCH_H */ +diff --git a/include/grub/i386/txt.h b/include/grub/i386/txt.h +index 155ebab0ff6a..c3dde57ea849 100644 +--- a/include/grub/i386/txt.h ++++ b/include/grub/i386/txt.h +@@ -353,29 +353,14 @@ struct grub_txt_bios_data + /* GRUB SLAUNCH specific definitions OS-MLE data */ + #define GRUB_SL_OS_MLE_STRUCT_VERSION 1 + +-struct grub_slaunch_mtrr_pair +-{ +- grub_uint64_t mtrr_physbase; +- grub_uint64_t mtrr_physmask; +-} GRUB_PACKED; +- +-struct grub_slaunch_mtrr_state +-{ +- grub_uint64_t default_mem_type; +- grub_uint64_t mtrr_vcnt; +- struct grub_slaunch_mtrr_pair mtrr_pair[GRUB_SL_MAX_VARIABLE_MTRRS]; +-} GRUB_PACKED; +- + struct grub_txt_os_mle_data + { + grub_uint32_t version; + grub_uint32_t boot_params_addr; +- grub_uint64_t saved_misc_enable_msr; +- struct grub_slaunch_mtrr_state saved_bsp_mtrrs; ++ grub_uint32_t slrt; ++ grub_uint32_t txt_info; + grub_uint32_t ap_wake_block; + grub_uint32_t ap_wake_block_size; +- grub_uint64_t evtlog_addr; +- grub_uint32_t evtlog_size; + grub_uint8_t mle_scratch[64]; + } GRUB_PACKED; + +@@ -729,6 +714,13 @@ 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); ++/* ++ * This function doesn't finish building of SLRT. It's caller's responsibility ++ * to call grub_slaunch_finish_slr_table() after making any necessary ++ * grub_slr_add_entry() and grub_slaunch_add_slrt_policy_entry() calls including ++ * grub_txt_add_slrt_polic_entries() and grub_slaunch_add_slrt_policy_entries(). ++ */ + extern grub_err_t grub_txt_boot_prepare (struct grub_slaunch_params *slparams); ++extern void grub_txt_add_slrt_policy_entries (void); + + #endif +-- +2.41.0 + diff --git a/1117-i386-slaunch-Add-secure-launch-framework-and-command.patch b/1117-i386-slaunch-Add-secure-launch-framework-and-command.patch new file mode 100644 index 0000000..6b32e26 --- /dev/null +++ b/1117-i386-slaunch-Add-secure-launch-framework-and-command.patch @@ -0,0 +1,1098 @@ +From cf61e4e0ca2f76b6b306bf3e88faac028e427b12 Mon Sep 17 00:00:00 2001 +From: Ross Philipson +Date: Wed, 7 Aug 2019 15:01:00 -0400 +Subject: [PATCH] i386/slaunch: Add secure launch framework and commands + +Signed-off-by: Ross Philipson +Signed-off-by: Daniel Kiper +Signed-off-by: Krystian Hebel +--- + grub-core/Makefile.am | 6 + + grub-core/Makefile.core.def | 15 + + grub-core/lib/i386/relocator32.S | 8 + + grub-core/loader/i386/bsd.c | 4 + + grub-core/loader/i386/coreboot/chainloader.c | 2 + + grub-core/loader/i386/linux.c | 320 ++++++++++++++++++- + grub-core/loader/i386/pc/plan9.c | 3 +- + grub-core/loader/i386/slaunch.c | 304 ++++++++++++++++++ + grub-core/loader/i386/xnu.c | 3 + + grub-core/loader/multiboot.c | 5 + + include/grub/file.h | 3 + + include/grub/i386/linux.h | 14 +- + 12 files changed, 670 insertions(+), 17 deletions(-) + create mode 100644 grub-core/loader/i386/slaunch.c + +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index ee88e44e97a0..44ba9ac40538 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -103,6 +103,8 @@ 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/i386/slaunch.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/slr_table.h + endif + + if COND_i386_xen_pvh +@@ -122,6 +124,8 @@ 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/i386/slaunch.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 +@@ -183,6 +187,8 @@ 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/i386/slaunch.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/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index f482cc01e36e..7ebacaa3cefe 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1816,6 +1816,15 @@ module = { + enable = noemu; + }; + ++module = { ++ name = slaunch; ++ x86 = loader/i386/slaunch.c; ++ x86 = loader/i386/txt/txt.c; ++ x86 = loader/i386/txt/acmod.c; ++ x86 = loader/i386/txt/verify.c; ++ enable = x86; ++}; ++ + module = { + name = fdt; + efi = loader/efi/fdt.c; +@@ -2489,6 +2498,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/lib/i386/relocator32.S b/grub-core/lib/i386/relocator32.S +index 09ce56ad0ae6..a2b377197b16 100644 +--- a/grub-core/lib/i386/relocator32.S ++++ b/grub-core/lib/i386/relocator32.S +@@ -24,6 +24,8 @@ + + #include "relocator_common.S" + ++#include ++ + .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 5f3290ce17bc..d9832328d307 100644 +--- a/grub-core/loader/i386/bsd.c ++++ b/grub-core/loader/i386/bsd.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -792,6 +793,7 @@ grub_freebsd_boot (void) + #endif + + grub_memcpy (&stack[9], &bi, sizeof (bi)); ++ state.edi = SLP_NONE; + state.eip = entry; + state.esp = stack_target; + state.ebp = stack_target; +@@ -907,6 +909,7 @@ grub_openbsd_boot (void) + return err; + #endif + ++ state.edi = SLP_NONE; + state.eip = entry; + state.ebp = state.esp + = ((grub_uint8_t *) stack - (grub_uint8_t *) buf0) + buf_target; +@@ -1229,6 +1232,7 @@ grub_netbsd_boot (void) + return err; + #endif + ++ state.edi = SLP_NONE; + state.eip = entry; + state.esp = stack_target; + state.ebp = stack_target; +diff --git a/grub-core/loader/i386/coreboot/chainloader.c b/grub-core/loader/i386/coreboot/chainloader.c +index 0a19ebb9c3e5..dccd86b07bde 100644 +--- a/grub-core/loader/i386/coreboot/chainloader.c ++++ b/grub-core/loader/i386/coreboot/chainloader.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -47,6 +48,7 @@ grub_chain_boot (void) + grub_video_set_mode ("text", 0, 0); + + state.eip = entry; ++ state.edi = SLP_NONE; + return grub_relocator32_boot (relocator, state, 0); + } + +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index 9f74a96b19ae..bf3878ab91e2 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -34,9 +34,12 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -63,18 +66,36 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define ACCEPTS_PURE_TEXT 1 + #endif + ++/* See kernel_info in Documentation/arch/x86/boot.rst in the kernel tree */ ++#define KERNEL_INFO_HEADER "LToP" ++#define KERNEL_INFO_MIN_SIZE_TOTAL 12 ++ ++struct linux_params_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; ++}; ++ + static grub_dl_t my_mod; + + 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; + static struct grub_relocator *relocator = NULL; + static void *efi_mmap_buf; + static grub_size_t maximal_cmdline_size; ++static struct linux_kernel_info *linux_info; + static struct linux_kernel_params linux_params; + static char *linux_cmdline; + #ifdef GRUB_MACHINE_EFI +@@ -98,6 +119,8 @@ static struct idt_descriptor idt_desc = + }; + #endif + ++#define OFFSET_OF(x, y) ((grub_size_t)((grub_uint8_t *)(&(y)->x) - (grub_uint8_t *)(y))) ++ + static inline grub_size_t + page_align (grub_size_t size) + { +@@ -150,11 +173,37 @@ 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; ++ struct grub_slaunch_params *slparams = grub_slaunch_params(); + + if (prot_size == 0) + prot_size = 1; + +- prot_size = page_align (prot_size); ++ if (grub_slaunch_platform_type () == SLP_INTEL_TXT) ++ { ++ if (prot_size > GRUB_TXT_MLE_MAX_SIZE) ++ { ++ err = GRUB_ERR_OUT_OF_RANGE; ++ goto fail; ++ } ++ ++ /* Check performed above makes sure that this doesn't overflow. */ ++ prot_size = ALIGN_UP (prot_size, GRUB_TXT_PMR_ALIGN); ++ ++ 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); ++ } ++ 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,7 +225,7 @@ 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)--) +@@ -194,11 +243,65 @@ 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) ++ { ++ /* 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_start = prot_mode_target; ++ slparams->mle_size = prot_size; ++ slparams->mle_mem = prot_mode_mem; ++ ++ 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); ++ ++ err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000, ++ 0xffffffff - GRUB_PAGE_SIZE, ++ GRUB_PAGE_SIZE, GRUB_PAGE_SIZE, ++ GRUB_RELOCATOR_PREFERENCE_NONE, 1); ++ if (err) ++ 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); ++ ++ err = 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); ++ if (err) ++ goto fail; ++ ++ slparams->tpm_evt_log_base = get_physical_target_address (ch); ++ slparams->tpm_evt_log_size = GRUB_SLAUNCH_TPM_EVT_LOG_SIZE; ++ ++ grub_txt_init_tpm_event_log (get_virtual_current_address (ch), ++ 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); ++ } + } + + grub_dprintf ("linux", "prot_mode_mem = %p, prot_mode_target = %lx, prot_size = %x\n", +@@ -286,7 +389,7 @@ grub_linux_setup_video (struct linux_kernel_params *params) + params->lfb_size >>= 16; + params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA; + break; +- ++ + case GRUB_VIDEO_DRIVER_EFI_UGA: + case GRUB_VIDEO_DRIVER_EFI_GOP: + params->have_vga = GRUB_VIDEO_LINUX_TYPE_EFIFB; +@@ -398,6 +501,63 @@ grub_linux_boot_mmap_fill (grub_uint64_t addr, grub_uint64_t size, + return 0; + } + ++static void ++grub_linux_setup_slr_table (struct grub_slaunch_params *slparams) ++{ ++ struct linux_kernel_params *boot_params = (void *) (grub_addr_t) slparams->boot_params_addr; ++ struct linux_params_efi_info *efi_info; ++ ++ /* A bit of work to extract the v2.08 EFI info from the linux params */ ++ efi_info = (void *)((grub_uint8_t *)&boot_params->v0208 + 2*sizeof(grub_uint32_t)); ++ ++ grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_DATA_PCR, ++ GRUB_SLR_ET_BOOT_PARAMS, ++ /*flags=*/0, ++ (grub_addr_t) boot_params, ++ GRUB_PAGE_SIZE, ++ "Measured boot parameters"); ++ ++ if (boot_params->setup_data) ++ grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_DATA_PCR, ++ GRUB_SLR_ET_SETUP_DATA, ++ GRUB_SLR_POLICY_IMPLICIT_SIZE, ++ boot_params->setup_data, ++ /*size=*/0, ++ "Measured Kernel setup_data"); ++ ++ /* The cmdline ptr can have hi bits but GRUB puts it always < 4G */ ++ grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_DATA_PCR, ++ GRUB_SLR_ET_CMDLINE, ++ /*flags=*/0, ++ boot_params->cmd_line_ptr, ++ boot_params->cmdline_size, ++ "Measured Kernel command line"); ++ ++ if (!grub_memcmp(&efi_info->efi_signature, "EL64", sizeof(grub_uint32_t))) ++ { ++ grub_uint64_t mmap_addr = ++ ((grub_uint64_t) efi_info->efi_mmap_hi << 32) | efi_info->efi_mmap; ++ grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_DATA_PCR, ++ GRUB_SLR_ET_UEFI_MEMMAP, ++ /*flags=*/0, ++ mmap_addr, ++ efi_info->efi_mmap_size, ++ "Measured EFI memory map"); ++ } ++ ++ if (boot_params->ramdisk_image) ++ /* ++ * The initrd image and size can have hi bits but in GRUB it is always ++ * < 4G, see GRUB_LINUX_INITRD_MAX_ADDRESS in grub_cmd_initrd(). ++ */ ++ grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_CODE_PCR, ++ GRUB_SLR_ET_RAMDISK, ++ /*flags=*/0, ++ boot_params->ramdisk_image, ++ boot_params->ramdisk_size, ++ "Measured Kernel initrd"); ++} ++ + static grub_err_t + grub_linux_boot (void) + { +@@ -411,6 +571,8 @@ grub_linux_boot (void) + }; + grub_size_t mmap_size; + grub_size_t cl_offset; ++ grub_size_t ap_wake_block_size = 0; ++ struct grub_slaunch_params *slparams = grub_slaunch_params(); + + #ifdef GRUB_MACHINE_IEEE1275 + { +@@ -543,6 +705,9 @@ grub_linux_boot (void) + (unsigned) ctx.real_size, + (unsigned) efi_mmap_size); + ++ if (grub_slaunch_platform_type () == SLP_INTEL_TXT) ++ ap_wake_block_size = GRUB_MLE_AP_WAKE_BLOCK_SIZE; ++ + if (! ctx.real_mode_target) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); + +@@ -550,7 +715,8 @@ grub_linux_boot (void) + grub_relocator_chunk_t ch; + grub_size_t sz; + +- if (grub_add (ctx.real_size, efi_mmap_size, &sz)) ++ if (grub_add (efi_mmap_size, ap_wake_block_size, &sz) || ++ grub_add (ctx.real_size, sz, &sz)) + return GRUB_ERR_OUT_OF_RANGE; + + err = grub_relocator_alloc_chunk_addr (relocator, &ch, +@@ -561,6 +727,20 @@ grub_linux_boot (void) + } + efi_mmap_buf = (grub_uint8_t *) real_mode_mem + ctx.real_size; + ++ if (grub_slaunch_platform_type () == SLP_INTEL_TXT) ++ { ++ slparams->ap_wake_block = ctx.real_mode_target + ctx.real_size + efi_mmap_size; ++ slparams->ap_wake_block_size = ap_wake_block_size; ++ grub_memset ((void *) ((grub_addr_t) real_mode_mem + ctx.real_size + ++ efi_mmap_size), 0, 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) ap_wake_block_size); ++ ++ /* Grab the real mode target address, this is the boot params page. */ ++ slparams->boot_params_addr = ctx.real_mode_target; ++ } ++ + grub_dprintf ("linux", "real_mode_mem = %p\n", + real_mode_mem); + +@@ -587,13 +767,15 @@ 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) + return err; +- ++ + /* Note that no boot services are available from here. */ +- efi_mmap_target = ctx.real_mode_target ++ efi_mmap_target = ctx.real_mode_target + + ((grub_uint8_t *) efi_mmap_buf - (grub_uint8_t *) real_mode_mem); + /* Pass EFI parameters. */ + if (grub_le_to_cpu16 (ctx.params->version) >= 0x0208) +@@ -624,12 +806,36 @@ grub_linux_boot (void) + } + #endif + +- /* FIXME. */ +- /* asm volatile ("lidt %0" : : "m" (idt_desc)); */ +- state.ebp = state.edi = state.ebx = 0; +- state.esi = ctx.real_mode_target; +- state.esp = ctx.real_mode_target; +- state.eip = ctx.params->code32_start; ++ state.edi = grub_slaunch_platform_type (); ++ ++ if (state.edi == SLP_INTEL_TXT) ++ { ++ err = grub_txt_boot_prepare (slparams); ++ ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ grub_slaunch_add_slrt_policy_entries (); ++ grub_txt_add_slrt_policy_entries (); ++ grub_linux_setup_slr_table (slparams); ++ grub_slaunch_finish_slr_table (); ++ ++ /* Configure relocator GETSEC[SENTER] call. */ ++ state.eax = GRUB_SMX_LEAF_SENTER; ++ state.ebx = slparams->dce_base; ++ state.ecx = slparams->dce_size; ++ state.edx = 0; ++ } ++ else ++ { ++ /* FIXME. */ ++ /* asm volatile ("lidt %0" : : "m" (idt_desc)); */ ++ state.ebp = state.edi = state.ebx = 0; ++ 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); + } + +@@ -650,12 +856,13 @@ 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; + int relocatable; + grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR; ++ struct grub_slaunch_params *slparams = grub_slaunch_params(); + + grub_dl_ref (my_mod); + +@@ -743,7 +950,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + align = 0; + relocatable = 0; + } +- ++ + if (grub_le_to_cpu16 (lh.version) >= 0x020a) + { + min_align = lh.min_alignment; +@@ -760,6 +967,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + prot_init_space = page_align (prot_size) * 3; + } + ++ 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); ++ } ++ + if (allocate_pages (prot_size, &align, + min_align, relocatable, + preferred_address)) +@@ -767,6 +981,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 (grub_slaunch_params ()); ++ + /* + * The Linux 32-bit boot protocol defines the setup header end + * to be at 0x202 + the byte value at 0x201. +@@ -793,6 +1010,79 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ /* Read the kernel_info struct. */ ++ if (grub_le_to_cpu16 (lh.version) >= 0x020f) ++ { ++ if (grub_file_seek (file, (grub_off_t) grub_le_to_cpu32 (lh.kernel_info_offset) + ++ real_size + GRUB_DISK_SECTOR_SIZE) == ((grub_off_t) -1)) ++ goto fail; ++ ++ linux_info = grub_malloc (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 (file, linux_info, ++ KERNEL_INFO_MIN_SIZE_TOTAL) != KERNEL_INFO_MIN_SIZE_TOTAL) ++ { ++ if (!grub_errno) ++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); ++ goto fail; ++ } ++ ++ if (grub_memcmp (&linux_info->header, KERNEL_INFO_HEADER, sizeof (linux_info->header))) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("incorrect kernel_info header")); ++ goto fail; ++ } ++ ++ if (linux_info->size_total < KERNEL_INFO_MIN_SIZE_TOTAL) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("incorrect kernel_info size")); ++ goto fail; ++ } ++ ++ 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 (file, &linux_info->setup_type_max, ++ linux_info->size_total - KERNEL_INFO_MIN_SIZE_TOTAL) != ++ (grub_ssize_t)(linux_info->size_total - KERNEL_INFO_MIN_SIZE_TOTAL)) ++ { ++ if (!grub_errno) ++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); ++ goto fail; ++ } ++ ++ if (grub_slaunch_platform_type () != SLP_NONE) ++ { ++ 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); ++ } ++ } ++ else if (grub_slaunch_platform_type () != SLP_NONE) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("not slaunch kernel: boot protocol too old")); ++ 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/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c +index 37550155df78..cd8213a05d31 100644 +--- a/grub-core/loader/i386/pc/plan9.c ++++ b/grub-core/loader/i386/pc/plan9.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -84,7 +85,7 @@ grub_plan9_boot (void) + .ebx = 0, + .ecx = 0, + .edx = 0, +- .edi = 0, ++ .edi = SLP_NONE, + .esp = 0, + .ebp = 0, + .esi = 0 +diff --git a/grub-core/loader/i386/slaunch.c b/grub-core/loader/i386/slaunch.c +new file mode 100644 +index 000000000000..b15194c78b61 +--- /dev/null ++++ b/grub-core/loader/i386/slaunch.c +@@ -0,0 +1,304 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_uint32_t slp = SLP_NONE; ++ ++static void *slaunch_module = NULL; ++ ++static struct grub_slaunch_params slparams; ++ ++/* Area to collect and build SLR Table information. */ ++static struct grub_slr_entry_dl_info slr_dl_info_staging; ++static struct grub_slr_entry_log_info slr_log_info_staging; ++static grub_uint8_t slr_policy_buf[GRUB_PAGE_SIZE]; ++static struct grub_slr_entry_policy *slr_policy_staging = ++ (struct grub_slr_entry_policy *)slr_policy_buf; ++ ++grub_uint32_t ++grub_slaunch_platform_type (void) ++{ ++ return slp; ++} ++ ++void * ++grub_slaunch_module (void) ++{ ++ return slaunch_module; ++} ++ ++struct grub_slaunch_params * ++grub_slaunch_params (void) ++{ ++ return &slparams; ++} ++ ++void ++grub_slaunch_init_slrt_storage (int arch) ++{ ++ struct grub_txt_mle_header *mle_header = ++ (void *) ((grub_uint8_t *) slparams.mle_mem + slparams.mle_header_offset); ++ ++ /* Setup the generic bits of the SLRT. */ ++ grub_slr_init_table(slparams.slr_table_mem, arch, slparams.slr_table_size); ++ ++ /* Setup DCE and DLME information. */ ++ 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_dl_info_staging.dce_base = slparams.dce_base; ++ slr_dl_info_staging.dce_size = slparams.dce_size; ++ slr_dl_info_staging.dlme_entry = mle_header->entry_point; ++ ++ 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_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_TPM12_LOG; ++ ++ slr_policy_staging->hdr.tag = GRUB_SLR_ENTRY_DRTM_POLICY; ++ slr_policy_staging->hdr.size = sizeof(struct grub_slr_entry_policy); ++ slr_policy_staging->revision = GRUB_SLR_TABLE_REVISION; ++ slr_policy_staging->nr_entries = 0; ++} ++ ++void grub_slaunch_add_slrt_policy_entries (void) ++{ ++ /* The SLR table should be measured too, at least parts of it. */ ++ grub_slaunch_add_slrt_policy_entry (GRUB_SLAUNCH_DATA_PCR, ++ GRUB_SLR_ET_SLRT, ++ GRUB_SLR_POLICY_IMPLICIT_SIZE, ++ slparams.slr_table_base, ++ /*size=*/0, ++ "Measured SLR Table"); ++} ++ ++void ++grub_slaunch_add_slrt_policy_entry (grub_uint16_t pcr, ++ grub_uint16_t entity_type, ++ grub_uint16_t flags, ++ grub_uint64_t entity, ++ grub_uint64_t size, ++ const char *evt_info) ++{ ++ struct grub_slr_policy_entry *entry = ++ (void *)((grub_uint8_t *)slr_policy_staging + ++ sizeof(struct grub_slr_entry_policy) + ++ slr_policy_staging->nr_entries*sizeof(*entry)); ++ ++ if (slr_policy_staging->hdr.size > sizeof(slr_policy_buf) - sizeof(*entry)) ++ grub_fatal("Not enough space for adding policy entry: %s! The buffer is full.", ++ evt_info); ++ ++ entry->pcr = pcr; ++ entry->entity_type = entity_type; ++ entry->flags = flags; ++ entry->entity = entity; ++ entry->size = size; ++ ++ grub_strncpy(entry->evt_info, evt_info, sizeof(entry->evt_info) - 1); ++ entry->evt_info[sizeof(entry->evt_info) - 1] = '\0'; ++ ++ slr_policy_staging->hdr.size += sizeof(*entry); ++ ++slr_policy_staging->nr_entries; ++} ++ ++void ++grub_slaunch_finish_slr_table (void) ++{ ++ struct grub_slr_table *slr_table = slparams.slr_table_mem; ++ ++ grub_slr_add_entry (slr_table, &slr_dl_info_staging.hdr); ++ grub_slr_add_entry (slr_table, &slr_log_info_staging.hdr); ++ grub_slr_add_entry (slr_table, &slr_policy_staging->hdr); ++} ++ ++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; ++ ++ 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; ++ } ++ ++ slaunch_module = grub_malloc (size); ++ ++ if (slaunch_module == NULL) ++ goto fail; ++ ++ if (grub_file_read (file, slaunch_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 (slaunch_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 (slaunch_module)) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("SINIT ACM does not match platform")); ++ goto fail; ++ } ++ } ++ ++ grub_file_close (file); ++ ++ return GRUB_ERR_NONE; ++ ++fail: ++ grub_error_push (); ++ ++ grub_free (slaunch_module); ++ grub_file_close (file); ++ ++ slaunch_module = NULL; ++ ++ 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 (); ++ } ++ else ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Unknown secure launcher platform type: %d\n"), slp); ++ ++ 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/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c +index a7009360732a..4989227bdbf5 100644 +--- a/grub-core/loader/i386/xnu.c ++++ b/grub-core/loader/i386/xnu.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -807,6 +808,7 @@ grub_xnu_boot_resume (void) + { + struct grub_relocator32_state state; + ++ state.edi = SLP_NONE; + state.esp = grub_xnu_stack; + state.ebp = grub_xnu_stack; + state.eip = grub_xnu_entry_point; +@@ -1134,6 +1136,7 @@ grub_xnu_boot (void) + grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size, + descriptor_version, memory_map); + ++ state.edi = SLP_NONE; + 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 facb13f3d36e..3ab0c828c3ae 100644 +--- a/grub-core/loader/multiboot.c ++++ b/grub-core/loader/multiboot.c +@@ -50,6 +50,9 @@ + #include + #include + #include ++#if defined (__i386__) || defined (__x86_64__) ++#include ++#endif + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -161,6 +164,8 @@ efi_boot (struct grub_relocator *rel __attribute__ ((unused)), + static void + normal_boot (struct grub_relocator *rel, struct grub_relocator32_state state) + { ++ state.edi = SLP_NONE; ++ + grub_relocator32_boot (rel, state, 0); + } + #else +diff --git a/include/grub/file.h b/include/grub/file.h +index 31567483ccfc..f08fcda74115 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -128,6 +128,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 eddf9251d9a5..18c860e6b759 100644 +--- a/include/grub/i386/linux.h ++++ b/include/grub/i386/linux.h +@@ -148,6 +148,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; /* In bytes, excluding var_len_data[] */ ++ grub_uint32_t size_total; /* In bytes, including var_len_data[] */ ++ grub_uint32_t setup_type_max; ++ grub_uint32_t mle_header_offset; ++ grub_uint8_t var_len_data[]; + } GRUB_PACKED; + + /* Boot parameters for Linux based on 2.6.12. This is used by the setup +@@ -325,9 +336,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; +-- +2.41.0 + diff --git a/1118-multiboot-make-GRUB_MULTIBOOT-make_mbi-return-MBI-s-.patch b/1118-multiboot-make-GRUB_MULTIBOOT-make_mbi-return-MBI-s-.patch new file mode 100644 index 0000000..8b9b3eb --- /dev/null +++ b/1118-multiboot-make-GRUB_MULTIBOOT-make_mbi-return-MBI-s-.patch @@ -0,0 +1,114 @@ +From 4e6cb41ee5606159c9ec0f4b8239749645808901 Mon Sep 17 00:00:00 2001 +From: Sergii Dmytruk +Date: Wed, 22 Nov 2023 21:08:35 +0200 +Subject: [PATCH] multiboot: make GRUB_MULTIBOOT(make_mbi) return MBI's size + +GRUB_MULTIBOOT(get_mbi_size) doesn't look like an accurate source of the +final size, more like a minimal memory buffer size. + +Signed-off-by: Sergii Dmytruk +--- + 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 a67d9d0a8088..29dd9cbb7c25 100644 +--- a/grub-core/loader/i386/multiboot_mbi.c ++++ b/grub-core/loader/i386/multiboot_mbi.c +@@ -450,7 +450,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; +@@ -618,6 +618,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 3ab0c828c3ae..07173f60e7c4 100644 +--- a/grub-core/loader/multiboot.c ++++ b/grub-core/loader/multiboot.c +@@ -180,6 +180,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; +@@ -188,7 +189,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 9a943d7bdd7c..197afd1b1809 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 bd0a9873e6c1..f9fa74471326 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 502d34ef1804..d1e3b3a8b4f6 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.41.0 + diff --git a/1119-multiboot2-Implement-TXT-slaunch-support.patch b/1119-multiboot2-Implement-TXT-slaunch-support.patch new file mode 100644 index 0000000..a3c8751 --- /dev/null +++ b/1119-multiboot2-Implement-TXT-slaunch-support.patch @@ -0,0 +1,373 @@ +From 58c9a06983cb68f04548713208b25c0b579b4043 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= +Date: Thu, 1 Sep 2022 17:58:53 +0200 +Subject: [PATCH] multiboot2: Implement TXT slaunch support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The code makes sure that MBI entry goes first in DRTM, so the payload +can measure it first on launch. + +SLRT table is allocated on the heap first, size for it is reserved +inside TXT heap by TXT code and data is later copied into its final +place. + +Signed-off-by: Sergii Dmytruk +Signed-off-by: Michał Żygowski +Signed-off-by: Tomasz Żyjewski +Signed-off-by: Krystian Hebel +--- + grub-core/loader/multiboot.c | 23 ++++++- + grub-core/loader/multiboot_elfxx.c | 104 ++++++++++++++++++++++++++--- + grub-core/loader/multiboot_mbi2.c | 99 +++++++++++++++++++++++++++ + include/grub/multiboot2.h | 2 + + 4 files changed, 219 insertions(+), 9 deletions(-) + +diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c +index 07173f60e7c4..17a922be2a16 100644 +--- a/grub-core/loader/multiboot.c ++++ b/grub-core/loader/multiboot.c +@@ -52,6 +52,7 @@ + #include + #if defined (__i386__) || defined (__x86_64__) + #include ++#include + #endif + + GRUB_MOD_LICENSE ("GPLv3+"); +@@ -164,7 +165,17 @@ efi_boot (struct grub_relocator *rel __attribute__ ((unused)), + static void + normal_boot (struct grub_relocator *rel, struct grub_relocator32_state state) + { +- state.edi = SLP_NONE; ++ struct grub_slaunch_params *slparams = grub_slaunch_params(); ++ state.edi = grub_slaunch_platform_type (); ++ ++ if (state.edi == SLP_INTEL_TXT) ++ { ++ /* 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 (rel, state, 0); + } +@@ -194,6 +205,16 @@ grub_multiboot_boot (void) + if (err) + return err; + ++#ifdef GRUB_USE_MULTIBOOT2 ++ if (grub_slaunch_platform_type () == SLP_INTEL_TXT) ++ { ++ err = grub_multiboot2_prepare_slaunch_txt (state.MULTIBOOT_MBI_REGISTER, ++ mbi_size); ++ if (err) ++ return err; ++ } ++#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 f2318e0d165d..438cedc2c096 100644 +--- a/grub-core/loader/multiboot_elfxx.c ++++ b/grub-core/loader/multiboot_elfxx.c +@@ -34,6 +34,8 @@ + #error "I'm confused" + #endif + ++#include ++#include + #include + + #define CONCAT(a,b) CONCAT_(a, b) +@@ -60,6 +62,9 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) + grub_uint32_t load_offset = 0, load_size; + int i; + void *source = NULL; ++ struct grub_slaunch_params *slparams = grub_slaunch_params(); ++ grub_size_t total_size; ++ grub_uint32_t mle_hdr_offset; + + if (ehdr->e_ident[EI_MAG0] != ELFMAG0 + || ehdr->e_ident[EI_MAG1] != ELFMAG1 +@@ -106,25 +111,87 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) + (long) mld->align, mld->preference, load_size, + mld->avoid_efi_boot_services); + +- if (load_size > mld->max_addr || mld->min_addr > mld->max_addr - load_size) ++ if (grub_slaunch_platform_type () == SLP_INTEL_TXT) ++ { ++#ifndef GRUB_USE_MULTIBOOT2 ++ return grub_error (GRUB_ERR_BAD_OS, "Only multiboot2 supported for slaunch"); ++#else ++ /* ++ * We allocate the the binary together with page tables to make one ++ * contiguous block for MLE. We have to align up to PMR (2MB). ++ */ ++ total_size = ALIGN_UP(load_size, GRUB_TXT_PMR_ALIGN); ++ ++ slparams->mle_size = total_size; ++ ++ slparams->mle_ptab_size = grub_txt_get_mle_ptab_size (total_size); ++ slparams->mle_ptab_size = ALIGN_UP (slparams->mle_ptab_size, GRUB_TXT_PMR_ALIGN); ++ ++ /* Do not go below GRUB_TXT_PMR_ALIGN. */ ++ if (mld->align < GRUB_TXT_PMR_ALIGN) ++ mld->align = GRUB_TXT_PMR_ALIGN; ++#endif ++ } ++ else ++ { ++ total_size = load_size; ++ slparams->mle_ptab_size = 0; ++ } ++ ++ if (total_size > mld->max_addr || mld->min_addr > mld->max_addr - total_size) + return grub_error (GRUB_ERR_BAD_OS, "invalid min/max address and/or load size"); + + err = grub_relocator_alloc_chunk_align_safe (GRUB_MULTIBOOT (relocator), &ch, +- mld->min_addr, mld->max_addr, +- load_size, mld->align ? mld->align : 1, ++ mld->min_addr, mld->max_addr - total_size, ++ total_size, mld->align ? mld->align : 1, + mld->preference, mld->avoid_efi_boot_services); + + if (err) +- { +- grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS image\n"); +- return err; +- } ++ { ++ grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS image\n"); ++ return err; ++ } + + mld->load_base_addr = get_physical_target_address (ch); + source = get_virtual_current_address (ch); ++ grub_memset (get_virtual_current_address (ch), 0, total_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_INTEL_TXT) ++ { ++#ifndef GRUB_USE_MULTIBOOT2 ++ return grub_error (GRUB_ERR_BAD_OS, "Only multiboot2 supported for slaunch"); ++#else ++ slparams->mle_start = mld->load_base_addr; ++ slparams->mle_mem = source; ++ ++ 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; ++ { ++ mld->load_base_addr = mld->link_base_addr; ++ /* TODO: support non-relocatable */ ++ if (grub_slaunch_platform_type () == SLP_INTEL_TXT) ++ return grub_error (GRUB_ERR_BAD_OS, "Non-relocatable ELF not supported with slaunch"); ++ } + + grub_dprintf ("multiboot_loader", "relocatable=%d, link_base_addr=0x%x, " + "load_base_addr=0x%x\n", mld->relocatable, +@@ -180,6 +247,27 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) + } + } + ++ if (grub_slaunch_platform_type () == SLP_INTEL_TXT) ++ { ++ slparams->mle_header_offset = 0xffffffff; ++ ++ /* TODO: decide on universal way of conveying location of MLE header */ ++ for (mle_hdr_offset = 0; mle_hdr_offset < 0x1000; mle_hdr_offset += 16) ++ { ++ if ( !grub_memcmp ((void *)((grub_addr_t) source + mle_hdr_offset), GRUB_TXT_MLE_UUID, 16) ) ++ { ++ slparams->mle_header_offset = mle_hdr_offset; ++ break; ++ } ++ } ++ ++ if (slparams->mle_header_offset == 0xffffffff) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "MLE header not found"); ++ ++ grub_dprintf ("slaunch", "slparams->mle_header_offset: 0x%08x\n", ++ slparams->mle_header_offset); ++ } ++ + for (i = 0; i < ehdr->e_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 197afd1b1809..fd93bc0e4237 100644 +--- a/grub-core/loader/multiboot_mbi2.c ++++ b/grub-core/loader/multiboot_mbi2.c +@@ -36,6 +36,10 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + + #if defined (GRUB_MACHINE_EFI) + #include +@@ -277,6 +281,9 @@ grub_multiboot2_load (grub_file_t file, const char *filename) + + if (addr_tag) + { ++ if (grub_slaunch_platform_type () == SLP_INTEL_TXT) ++ 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 +397,34 @@ 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 (grub_slaunch_platform_type () == SLP_INTEL_TXT) ++ { ++ grub_relocator_chunk_t ch; ++ struct grub_slaunch_params *slparams = grub_slaunch_params(); ++ ++ 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; ++ ++ grub_txt_init_tpm_event_log(get_virtual_current_address (ch), ++ slparams->tpm_evt_log_size); ++ ++ grub_dprintf ("multiboot_loader", "tpm_evt_log_base = %lx, tpm_evt_log_size = %x\n", ++ (unsigned long) slparams->tpm_evt_log_base, ++ (unsigned) slparams->tpm_evt_log_size); ++ ++ grub_txt_setup_mle_ptab (slparams); ++ } ++ + return err; + } + +@@ -722,7 +757,12 @@ grub_multiboot2_make_mbi (grub_uint32_t *target, grub_uint32_t *size) + + ptrorig = get_virtual_current_address (ch); + #if defined (__i386__) || defined (__x86_64__) ++ struct grub_slaunch_params *slparams = grub_slaunch_params(); ++ + *target = get_physical_target_address (ch); ++ /* Save MBI pointer in the TXT heap area */ ++ if (grub_slaunch_platform_type () == SLP_INTEL_TXT) ++ slparams->boot_params_addr = *target; + #elif defined (__mips) + *target = get_physical_target_address (ch) | 0x80000000; + #else +@@ -1128,3 +1168,62 @@ grub_multiboot2_set_bootdev (void) + + bootdev_set = 1; + } ++ ++static void ++add_multiboot2_slrt_policy_entries (void) ++{ ++ unsigned i; ++ struct module *cur; ++ ++ for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) ++ { ++ grub_slaunch_add_slrt_policy_entry (17, ++ GRUB_SLR_ET_MULTIBOOT2_MODULE, ++ /*flags=*/0, ++ cur->start, ++ cur->size, ++ "Measured MB2 module"); ++ } ++} ++ ++grub_err_t ++grub_multiboot2_prepare_slaunch_txt (grub_uint32_t mbi_target, ++ grub_uint32_t mbi_size) ++{ ++ grub_err_t err; ++ struct grub_slaunch_params *slparams = grub_slaunch_params (); ++ ++ slparams->slr_table_base = GRUB_SLAUNCH_STORE_IN_OS2MLE; ++ slparams->slr_table_size = GRUB_PAGE_SIZE; ++ ++ slparams->slr_table_mem = grub_zalloc (slparams->slr_table_size); ++ if (slparams->slr_table_mem == NULL) ++ return GRUB_ERR_OUT_OF_MEMORY; ++ ++ err = grub_txt_boot_prepare (slparams); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_printf ("TXT boot preparation failed"); ++ return err; ++ } ++ ++ grub_slaunch_add_slrt_policy_entry (18, ++ GRUB_SLR_ET_MULTIBOOT2_INFO, ++ /*flags=*/0, ++ mbi_target, ++ mbi_size, ++ "Measured MB2 information"); ++ grub_slaunch_add_slrt_policy_entries (); ++ grub_txt_add_slrt_policy_entries (); ++ add_multiboot2_slrt_policy_entries (); ++ grub_slaunch_finish_slr_table (); ++ ++ grub_dprintf ("multiboot_loader", "slr_table_base = %lx, slr_table_size = %x\n", ++ (unsigned long) slparams->slr_table_base, ++ (unsigned) slparams->slr_table_size); ++ grub_memcpy ((void *)(grub_addr_t) slparams->slr_table_base, ++ slparams->slr_table_mem, ++ slparams->slr_table_size); ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/include/grub/multiboot2.h b/include/grub/multiboot2.h +index d1e3b3a8b4f6..0ca577e7395f 100644 +--- a/include/grub/multiboot2.h ++++ b/include/grub/multiboot2.h +@@ -43,6 +43,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_prepare_slaunch_txt (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); +-- +2.41.0 + diff --git a/grub2.spec.in b/grub2.spec.in index 9406d51..3e3ca99 100644 --- a/grub2.spec.in +++ b/grub2.spec.in @@ -773,6 +773,28 @@ Patch0215: 0215-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch Patch1000: 1000-templates-linux_xen-fix-detecting-xsm-policy.patch Patch1001: 1001-Hide-os-prober-disabled-warning.patch +# Intel TXT support patches +Patch1100: 1100-i386-msr-Merge-rdmsr.h-and-wrmsr.h-into-msr.h.patch +Patch1101: 1101-i386-msr-Rename-grub_msr_read-and-grub_msr_write.patch +Patch1102: 1102-i386-msr-Extract-and-improve-MSR-support-detection-c.patch +Patch1103: 1103-i386-memory-Rename-PAGE_SHIFT-to-GRUB_PAGE_SHIFT.patch +Patch1104: 1104-i386-memory-Rename-PAGE_SIZE-to-GRUB_PAGE_SIZE-and-m.patch +Patch1105: 1105-i386-memory-Define-GRUB_PAGE_MASK-constant-and-GRUB_.patch +Patch1106: 1106-mmap-Add-grub_mmap_get_lowest-and-grub_mmap_get_high.patch +Patch1107: 1107-i386-tpm-Rename-tpm-module-to-tpm_verifier.patch +Patch1108: 1108-i386-tpm-Add-TPM-TIS-and-CRB-driver.patch +Patch1109: 1109-i386-slaunch-Add-basic-platform-support-for-secure-l.patch +Patch1110: 1110-i386-txt-Initial-commit-of-the-Secure-Launch-Resourc.patch +Patch1111: 1111-i386-txt-Add-Intel-TXT-definitions-header-file.patch +Patch1112: 1112-i386-txt-Add-Intel-TXT-core-implementation.patch +Patch1113: 1113-i386-txt-Add-Intel-TXT-ACM-module-support.patch +Patch1114: 1114-i386-txt-Add-Intel-TXT-verification-routines.patch +Patch1115: 1115-i386-txt-Initialize-TPM-1.2-event-log-in-TXT-heap.patch +Patch1116: 1116-i386-txt-switch-to-using-Secure-Launch-Resource-Tabl.patch +Patch1117: 1117-i386-slaunch-Add-secure-launch-framework-and-command.patch +Patch1118: 1118-multiboot-make-GRUB_MULTIBOOT-make_mbi-return-MBI-s-.patch +Patch1119: 1119-multiboot2-Implement-TXT-slaunch-support.patch + BuildRequires: autoconf BuildRequires: automake BuildRequires: bison