From 64c7d93604f3209e6a5e985edd4d1cb553ffe827 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sat, 22 Mar 2025 15:58:07 +0200 Subject: [PATCH 1/8] Extract grub_get_max_phy_addr_bits () to grub/i386/cpuid.h Out of grub_vbe_enable_mtrr() in video/i386/pc/vbe.c Signed-off-by: Sergii Dmytruk --- grub-core/video/i386/pc/vbe.c | 11 +---------- include/grub/i386/cpuid.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/grub-core/video/i386/pc/vbe.c b/grub-core/video/i386/pc/vbe.c index a0bb9af09..70952009f 100644 --- a/grub-core/video/i386/pc/vbe.c +++ b/grub-core/video/i386/pc/vbe.c @@ -93,7 +93,6 @@ grub_vbe_enable_mtrr (grub_uint8_t *base, grub_size_t size) grub_uint32_t features; grub_uint32_t mtrrcap; int var_mtrrs; - grub_uint32_t max_extended_cpuid; grub_uint32_t maxphyaddr; grub_uint64_t fb_base, fb_size; grub_uint64_t size_bits, fb_mask; @@ -142,15 +141,7 @@ grub_vbe_enable_mtrr (grub_uint8_t *base, grub_size_t size) return; var_mtrrs = (mtrrcap & 0xFF); - grub_cpuid (0x80000000, eax, ebx, ecx, edx); - max_extended_cpuid = eax; - if (max_extended_cpuid >= 0x80000008) - { - grub_cpuid (0x80000008, eax, ebx, ecx, edx); - maxphyaddr = (eax & 0xFF); - } - else - maxphyaddr = 36; + maxphyaddr = grub_get_max_phy_addr_bits (); bits_lo = 0xFFFFF000; /* assume maxphyaddr >= 36 */ bits_hi = (1 << (maxphyaddr - 32)) - 1; bits = bits_lo | ((grub_uint64_t) bits_hi << 32); diff --git a/include/grub/i386/cpuid.h b/include/grub/i386/cpuid.h index 36e4ee05e..023ab9431 100644 --- a/include/grub/i386/cpuid.h +++ b/include/grub/i386/cpuid.h @@ -96,4 +96,18 @@ grub_cpu_is_cpuid_supported (void) : "0" (num)) #endif +static inline grub_uint8_t grub_get_max_phy_addr_bits (void) +{ + grub_uint32_t eax, ebx, ecx, edx; + grub_uint32_t max_extended_cpuid; + + grub_cpuid (0x80000000, eax, ebx, ecx, edx); + max_extended_cpuid = eax; + if (max_extended_cpuid < 0x80000008) + return 36; + + grub_cpuid (0x80000008, eax, ebx, ecx, edx); + return eax & 0xFF; +} + #endif From 52bbc8ec93c18d218e9a73f9f87ad8c749a31f0c Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sat, 22 Mar 2025 16:13:00 +0200 Subject: [PATCH 2/8] grub-core/loader/slaunch/txt.c: pass ACM header to set_mtrr_mem_type Instead of an abstract memory range. Signed-off-by: Sergii Dmytruk --- grub-core/loader/slaunch/txt.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/grub-core/loader/slaunch/txt.c b/grub-core/loader/slaunch/txt.c index 5336f72ad..950e92e01 100644 --- a/grub-core/loader/slaunch/txt.c +++ b/grub-core/loader/slaunch/txt.c @@ -351,12 +351,11 @@ fls (int mask) } /* - * set the memory type for specified range (base to base+size) - * to mem_type and everything else to UC + * Set the memory type for ACM's memory range 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) +set_mtrr_mem_type (struct grub_txt_acm_header *sinit, grub_uint32_t mem_type) { grub_uint64_t mtrr_def_type; grub_uint64_t mtrr_cap; @@ -366,6 +365,9 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size, unsigned long ndx, base_v; int i = 0, j, num_pages, mtrr_s; + const grub_uint8_t *base = (const grub_uint8_t *)sinit; + grub_uint32_t size = sinit->size*4; + /* 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); @@ -390,7 +392,7 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size, base, size, num_pages); /* Each VAR MTRR base must be a multiple of that MTRR's Size */ - base_v = (unsigned long)base; + base_v = (grub_addr_t)base; /* MTRR size in pages */ mtrr_s = 1; @@ -410,7 +412,7 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size, while ( num_pages >= mtrr_s ) { mtrr_physbase.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2); - mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) & + mtrr_physbase.base = ((grub_addr_t)base >> GRUB_PAGE_SHIFT) & SINIT_MTRR_MASK; mtrr_physbase.type = mem_type; grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2, mtrr_physbase.raw); @@ -432,7 +434,7 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size, { /* Set the base of the current MTRR */ mtrr_physbase.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2); - mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) & + mtrr_physbase.base = ((grub_addr_t)base >> GRUB_PAGE_SHIFT) & SINIT_MTRR_MASK; mtrr_physbase.type = mem_type; grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2, mtrr_physbase.raw); @@ -505,8 +507,7 @@ grub_set_mtrrs_for_acmod (struct grub_txt_acm_header *hdr) 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); + err = set_mtrr_mem_type (hdr, GRUB_MTRR_MEMORY_TYPE_WB); /* Undo some of earlier changes and enable our new settings */ From 54e58c2dd7f2a8d47067f96d7de33753ce4fbfd5 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sat, 22 Mar 2025 16:15:52 +0200 Subject: [PATCH 3/8] slaunch: txt: obey ACM's MAXPHYSADDR capability In this case MTRRs masks should be limited to MAXPHYSADDR bits as reported by CPUID instead of to a fixed width of 36 bits. Signed-off-by: Sergii Dmytruk --- grub-core/loader/slaunch/txt.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/grub-core/loader/slaunch/txt.c b/grub-core/loader/slaunch/txt.c index 950e92e01..3f9cb5411 100644 --- a/grub-core/loader/slaunch/txt.c +++ b/grub-core/loader/slaunch/txt.c @@ -302,8 +302,6 @@ set_all_mtrrs (int 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 @@ -362,6 +360,8 @@ set_mtrr_mem_type (struct grub_txt_acm_header *sinit, grub_uint32_t mem_type) union mtrr_physbase_t mtrr_physbase; union mtrr_physmask_t mtrr_physmask; grub_uint32_t vcnt, pages_in_range; + grub_uint32_t max_phy_addr_bits; + grub_uint64_t mtrr_shifted_mask; unsigned long ndx, base_v; int i = 0, j, num_pages, mtrr_s; @@ -409,16 +409,22 @@ set_mtrr_mem_type (struct grub_txt_acm_header *sinit, grub_uint32_t mem_type) ndx = 0; + if (grub_txt_get_sinit_capabilities (sinit) & GRUB_TXT_CAPS_MAXPHYSADDR_SUPPORT) + max_phy_addr_bits = grub_get_max_phy_addr_bits (); + else + max_phy_addr_bits = 36; + mtrr_shifted_mask = (1ULL << (max_phy_addr_bits - GRUB_PAGE_SHIFT)) - 1; + while ( num_pages >= mtrr_s ) { mtrr_physbase.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2); mtrr_physbase.base = ((grub_addr_t)base >> GRUB_PAGE_SHIFT) & - SINIT_MTRR_MASK; + mtrr_shifted_mask; mtrr_physbase.type = mem_type; grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2, mtrr_physbase.raw); mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK0 + ndx*2); - mtrr_physmask.mask = ~(mtrr_s - 1) & SINIT_MTRR_MASK; + mtrr_physmask.mask = ~(mtrr_s - 1) & mtrr_shifted_mask; mtrr_physmask.v = 1; grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK0 + ndx*2, mtrr_physmask.raw); @@ -435,7 +441,7 @@ set_mtrr_mem_type (struct grub_txt_acm_header *sinit, grub_uint32_t mem_type) /* Set the base of the current MTRR */ mtrr_physbase.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2); mtrr_physbase.base = ((grub_addr_t)base >> GRUB_PAGE_SHIFT) & - SINIT_MTRR_MASK; + mtrr_shifted_mask; mtrr_physbase.type = mem_type; grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE0 + ndx*2, mtrr_physbase.raw); @@ -447,7 +453,7 @@ set_mtrr_mem_type (struct grub_txt_acm_header *sinit, grub_uint32_t mem_type) pages_in_range = 1 << (fls (num_pages) - 1); mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK0 + ndx*2); - mtrr_physmask.mask = ~(pages_in_range - 1) & SINIT_MTRR_MASK; + mtrr_physmask.mask = ~(pages_in_range - 1) & mtrr_shifted_mask; mtrr_physmask.v = 1; grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK0 + ndx*2, mtrr_physmask.raw); From fc6fe8e5f44a18d8fc91116d37f891c7a038dd8b Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sat, 22 Mar 2025 16:19:34 +0200 Subject: [PATCH 4/8] slaunch: efi: don't add Linux policy entries unconditionally Boot params are set only for Linux boot process and it being NULL won't stop the code from adding policy entries that can confuse DLME. Signed-off-by: Sergii Dmytruk --- grub-core/loader/slaunch/slrt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/grub-core/loader/slaunch/slrt.c b/grub-core/loader/slaunch/slrt.c index de5c32cf1..80f62fe0d 100644 --- a/grub-core/loader/slaunch/slrt.c +++ b/grub-core/loader/slaunch/slrt.c @@ -249,6 +249,12 @@ grub_update_slrt_policy (struct grub_slaunch_params *slparams) grub_uint64_t hi_val; int i, next = 0; + if (boot_params == NULL) + { + /* Nothing to update if Linux boot params aren't supplied */ + return; + } + policy = grub_slr_next_entry_by_tag ((struct grub_slr_table *)(grub_addr_t)slparams->slr_table_base, NULL, GRUB_SLR_ENTRY_ENTRY_POLICY); From 0727266682c09416ecc96260ac3f445ac6785eb2 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sat, 22 Mar 2025 17:04:28 +0200 Subject: [PATCH 5/8] slaunch: efi: always validate UUID in MLE header Just in case. Signed-off-by: Sergii Dmytruk --- grub-core/loader/slaunch/x86_efi_linux.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/grub-core/loader/slaunch/x86_efi_linux.c b/grub-core/loader/slaunch/x86_efi_linux.c index c88ec42f6..6c66fcb35 100644 --- a/grub-core/loader/slaunch/x86_efi_linux.c +++ b/grub-core/loader/slaunch/x86_efi_linux.c @@ -80,6 +80,13 @@ sl_efi_load_mle_data (struct grub_slaunch_params *slparams, mle_hdr_offset = grub_le_to_cpu32 (kernel_info.mle_header_offset); mle_hdr = (struct grub_txt_mle_header *)((grub_addr_t)kernel_addr + slparams->mle_header_offset); + + if (!grub_memcmp (mle_hdr->uuid, GRUB_TXT_MLE_UUID, 16)) + { + grub_dprintf ("slaunch", "Not an MLE header at %llu\n", + (unsigned long long)((grub_addr_t)kernel_addr + mle_hdr_offset)); + return GRUB_ERR_BAD_OS; + } } else { From ea7473d6e28a4998334a247f4e26c7e6a9cb8a2a Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sat, 22 Mar 2025 17:05:48 +0200 Subject: [PATCH 6/8] slaunch: efi: map MLE header's file offset into image offset The correct offset is a requirement for TXT and layout of sections in memory can be very different from the layout in a file. Signed-off-by: Sergii Dmytruk --- grub-core/loader/slaunch/x86_efi_linux.c | 48 ++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/grub-core/loader/slaunch/x86_efi_linux.c b/grub-core/loader/slaunch/x86_efi_linux.c index 6c66fcb35..ed693d48f 100644 --- a/grub-core/loader/slaunch/x86_efi_linux.c +++ b/grub-core/loader/slaunch/x86_efi_linux.c @@ -58,15 +58,53 @@ sl_efi_install_slr_table (struct grub_slaunch_params *slparams) return GRUB_ERR_NONE; } +/* Traverses sections of a loaded EFI image to map an offset within a file to + * an offset within the image. Returns appropriately casted -1 on error. */ +static grub_efi_uint64_t +foffset_to_voffset(grub_efi_loaded_image_t *image, grub_uint32_t foffset) +{ + struct grub_msdos_image_header *header; + struct grub_pe_image_header *pe_image_header; + struct grub_pe32_coff_header *coff_header; + struct grub_pe32_section_table *sections; + struct grub_pe32_section_table *section; + grub_uint16_t i; + grub_uint32_t loaded_section; + + header = image->image_base; + pe_image_header = (struct grub_pe_image_header *) + ((char *) header + header->pe_image_header_offset); + coff_header = &pe_image_header->coff_header; + sections = (struct grub_pe32_section_table *) + ((char *) coff_header + sizeof (*coff_header) + + coff_header->optional_header_size); + + loaded_section = GRUB_PE32_SCN_CNT_CODE | GRUB_PE32_SCN_CNT_INITIALIZED_DATA; + for (i = 0, section = sections; i < coff_header->num_sections; i++, section++) + { + grub_uint32_t fstart = section->raw_data_offset; + grub_uint32_t fend = fstart + section->raw_data_size; + + if ((section->characteristics & loaded_section) != 0 && + foffset >= fstart && foffset < fend) + { + return section->virtual_address + (foffset - fstart); + } + } + + return ~(grub_efi_uint64_t)0; +} + static grub_err_t sl_efi_load_mle_data (struct grub_slaunch_params *slparams, void *kernel_addr, grub_ssize_t kernel_start, + grub_efi_loaded_image_t *loaded_image, bool is_linux) { struct linux_kernel_params *lh = (struct linux_kernel_params *)kernel_addr; struct linux_kernel_info kernel_info; struct grub_txt_mle_header *mle_hdr; - grub_uint32_t mle_hdr_offset; + grub_uint64_t mle_hdr_offset; if (is_linux) { @@ -101,6 +139,10 @@ sl_efi_load_mle_data (struct grub_slaunch_params *slparams, { return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("not an slaunch kernel: no MLE header found")); } + + mle_hdr_offset = foffset_to_voffset (loaded_image, mle_hdr_offset); + if (mle_hdr_offset >= (1ULL << 32)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("failed to map MLE header")); } slparams->mle_header_offset = mle_hdr_offset; @@ -291,7 +333,7 @@ grub_sl_efi_txt_setup (struct grub_slaunch_params *slparams, void *kernel_addr, goto fail; } - err = sl_efi_load_mle_data (slparams, kernel_addr, start, is_linux); + err = sl_efi_load_mle_data (slparams, kernel_addr, start, loaded_image, is_linux); if (err != GRUB_ERR_NONE) { grub_dprintf ("slaunch", N_("failed to load MLE data")); @@ -371,7 +413,7 @@ grub_sl_efi_skinit_setup (struct grub_slaunch_params *slparams, void *kernel_add /* It's OK to call this for AMD SKINIT because SKL erases the log before use. */ grub_txt_init_tpm_event_log (logmem, slparams->tpm_evt_log_size); - err = sl_efi_load_mle_data (slparams, kernel_addr, start, is_linux); + err = sl_efi_load_mle_data (slparams, kernel_addr, start, loaded_image, is_linux); if (err != GRUB_ERR_NONE) goto fail; From a3f2b026a94fe46ce081aba093e00497fed242b1 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sat, 22 Mar 2025 17:07:12 +0200 Subject: [PATCH 7/8] grub-core/loader/slaunch/x86_efi_linux.c: improve a comment Signed-off-by: Sergii Dmytruk --- grub-core/loader/slaunch/x86_efi_linux.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/grub-core/loader/slaunch/x86_efi_linux.c b/grub-core/loader/slaunch/x86_efi_linux.c index ed693d48f..2696a9803 100644 --- a/grub-core/loader/slaunch/x86_efi_linux.c +++ b/grub-core/loader/slaunch/x86_efi_linux.c @@ -148,15 +148,16 @@ sl_efi_load_mle_data (struct grub_slaunch_params *slparams, slparams->mle_header_offset = mle_hdr_offset; slparams->mle_entry = mle_hdr->entry_point; - if (!is_linux) { - /* - * The previous value of the field is covering the whole EFI image which - * can include a lot of useless padding. Limit the size used for measuring - * MLE to that reported by the header. Don't change the behaviour for - * Linux. - */ - slparams->mle_size = mle_hdr->mle_end - mle_hdr->mle_start; - } + if (!is_linux) + { + /* + * The current value of the field covers the whole EFI image which can + * include a lot of useless padding. Limit the size used for measuring + * MLE to that reported by the header. Don't change the behaviour for + * Linux in case it causes trouble (needs testing). + */ + slparams->mle_size = mle_hdr->mle_end - mle_hdr->mle_start; + } return GRUB_ERR_NONE; } From b5517787efc2359908c268e7bad5eb0bd1043525 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 23 Mar 2025 21:36:42 +0200 Subject: [PATCH 8/8] slaunch: txt: improve error output * Add missing newlines. * Use grub_dprintf() to provide more context, each next grub_error() discards the message of the previous one unless error stack is pushed. Signed-off-by: Sergii Dmytruk --- grub-core/loader/slaunch/x86_efi_linux.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/grub-core/loader/slaunch/x86_efi_linux.c b/grub-core/loader/slaunch/x86_efi_linux.c index 2696a9803..f1c2c1d3f 100644 --- a/grub-core/loader/slaunch/x86_efi_linux.c +++ b/grub-core/loader/slaunch/x86_efi_linux.c @@ -114,7 +114,10 @@ sl_efi_load_mle_data (struct grub_slaunch_params *slparams, sizeof (struct linux_kernel_info)); if (OFFSET_OF (mle_header_offset, &kernel_info) >= grub_le_to_cpu32 (kernel_info.size)) - return grub_error (GRUB_ERR_BAD_OS, N_("not an slaunch kernel: lack of mle_header_offset")); + { + grub_dprintf ("slaunch", "not an slaunch kernel: lack of mle_header_offset\n"); + return GRUB_ERR_BAD_OS; + } mle_hdr_offset = grub_le_to_cpu32 (kernel_info.mle_header_offset); mle_hdr = (struct grub_txt_mle_header *)((grub_addr_t)kernel_addr + slparams->mle_header_offset); @@ -137,12 +140,16 @@ sl_efi_load_mle_data (struct grub_slaunch_params *slparams, if (mle_hdr_offset >= 0x1000) { - return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("not an slaunch kernel: no MLE header found")); + grub_dprintf ("slaunch", "not an slaunch kernel: no MLE header found\n"); + return GRUB_ERR_BAD_ARGUMENT; } mle_hdr_offset = foffset_to_voffset (loaded_image, mle_hdr_offset); if (mle_hdr_offset >= (1ULL << 32)) - return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("failed to map MLE header")); + { + grub_dprintf ("slaunch", "failed to map MLE header\n"); + return GRUB_ERR_BAD_ARGUMENT; + } } slparams->mle_header_offset = mle_hdr_offset; @@ -337,7 +344,7 @@ grub_sl_efi_txt_setup (struct grub_slaunch_params *slparams, void *kernel_addr, err = sl_efi_load_mle_data (slparams, kernel_addr, start, loaded_image, is_linux); if (err != GRUB_ERR_NONE) { - grub_dprintf ("slaunch", N_("failed to load MLE data")); + grub_dprintf ("slaunch", N_("failed to load MLE data\n")); goto fail; } @@ -345,14 +352,14 @@ grub_sl_efi_txt_setup (struct grub_slaunch_params *slparams, void *kernel_addr, err = grub_txt_boot_prepare (slparams); if (err != GRUB_ERR_NONE) { - grub_dprintf ("slaunch", N_("failed to prepare TXT")); + grub_dprintf ("slaunch", N_("failed to prepare TXT\n")); goto fail; } err = sl_efi_install_slr_table (slparams); if (err != GRUB_ERR_NONE) { - grub_dprintf ("slaunch", N_("failed to register SLRT with UEFI")); + grub_dprintf ("slaunch", N_("failed to register SLRT with UEFI\n")); goto fail; } @@ -416,7 +423,10 @@ grub_sl_efi_skinit_setup (struct grub_slaunch_params *slparams, void *kernel_add err = sl_efi_load_mle_data (slparams, kernel_addr, start, loaded_image, is_linux); if (err != GRUB_ERR_NONE) - goto fail; + { + grub_dprintf ("slaunch", N_("failed to load MLE data\n")); + goto fail; + } /* * AMD SKL final setup may relocate the SKL module. It is also what sets the SLRT and DCE