Attention is currently required from: Jérémy Compostella.
Arthur Heymans has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/80336?usp=email )
Change subject: cpu/x86/smm: Set up page tables in safe SMRAM ......................................................................
cpu/x86/smm: Set up page tables in safe SMRAM
Relying on page tables being in RO flash is not safe in every setup, therefore set up some page tables in SMRAM that the permanent smihandler can use.
Tested on QEMU.
Signed-off-by: Arthur Heymans arthur@aheymans.xyz Change-Id: Icb3086abd577b9abb9966dd910a264a873ace4ed --- M src/cpu/x86/mp_init.c M src/cpu/x86/smm/smm_module_loader.c M src/include/cpu/x86/smm.h 3 files changed, 54 insertions(+), 4 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/36/80336/1
diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c index 5a0d8a7..8f18de1 100644 --- a/src/cpu/x86/mp_init.c +++ b/src/cpu/x86/mp_init.c @@ -791,7 +791,6 @@ .num_cpus = num_cpus, .cpu_save_state_size = save_state_size, .num_concurrent_save_states = num_cpus, - .cr3 = read_cr3(), };
printk(BIOS_DEBUG, "Installing permanent SMM handler to 0x%08lx\n", smbase); diff --git a/src/cpu/x86/smm/smm_module_loader.c b/src/cpu/x86/smm/smm_module_loader.c index d965593..ca8c75d 100644 --- a/src/cpu/x86/smm/smm_module_loader.c +++ b/src/cpu/x86/smm/smm_module_loader.c @@ -8,6 +8,7 @@ #include <cpu/cpu.h> #include <cpu/x86/smm.h> #include <device/device.h> +#include <device/mmio.h> #include <rmodule.h> #include <stdio.h> #include <string.h> @@ -259,6 +260,7 @@ stub_params->stack_top = stack_top; stub_params->stack_size = g_stack_size; stub_params->c_handler = (uintptr_t)params->handler; + stub_params->cr3 = params->cr3;
/* This runs on the BSP. All the APs are its siblings */ struct cpu_info *info = cpu_info(); @@ -353,8 +355,8 @@ region_end(®ion)); }
-/* STM + Handler + (Stub + Save state) * CONFIG_MAX_CPUS + stacks */ -#define SMM_REGIONS_ARRAY_SIZE (1 + 1 + CONFIG_MAX_CPUS * 2 + 1) +/* STM + Handler + (Stub + Save state) * CONFIG_MAX_CPUS + stacks + page tables*/ +#define SMM_REGIONS_ARRAY_SIZE (1 + 1 + CONFIG_MAX_CPUS * 2 + 1 + 1)
static int append_and_check_region(const struct region smram, const struct region region, @@ -389,6 +391,39 @@ return 0; }
+#define _PRES (1ULL << 0) +#define _RW (1ULL << 1) +#define _US (1ULL << 2) +#define _A (1ULL << 5) +#define _D (1ULL << 6) +#define _PS (1ULL << 7) +#define _GEN_DIR(a) (_PRES + _RW + _US + _A + (a)) +#define _GEN_PAGE(a) (_PRES + _RW + _US + _PS + _A + _D + (a)) +#define PAGE_SIZE 8 + +/* Return the PM4LE */ +static uintptr_t install_page_table(const uintptr_t handler_base) +{ + const bool one_g_pages = !!(cpuid_edx(0x80000001) & (1 << 26)); + /* 4 1G pages or 4 PDPE entries with 512 * 2M pages */ + const size_t pages_needed = one_g_pages ? 4 : 2048 + 4; + const uintptr_t pages_base = ALIGN_DOWN(handler_base - pages_needed * PAGE_SIZE, 4096); + const uintptr_t pm4le = ALIGN_DOWN(pages_base - 8, 4096); + + if (one_g_pages) { + for (int i = 0; i < 4; i++) + write64p(pages_base + i * PAGE_SIZE, _GEN_PAGE(1 * GiB * i)); + write64p(pm4le, _GEN_DIR(pages_base)); + } else { + for (int i = 0; i < 2048; i++) + write64p(pages_base + i * PAGE_SIZE, _GEN_PAGE(2 * MiB * i)); + write64p(pm4le, _GEN_DIR(pages_base + 2048 * PAGE_SIZE)); + for (int i = 0; i < 4; i++) + write64p(pages_base + (2048 + i) * PAGE_SIZE, _GEN_DIR(pages_base + 4096 * i)); + } + return pm4le; +} + /* *The SMM module is placed within the provided region in the following * manner: @@ -398,6 +433,8 @@ * +-----------------+ * | smi handler | * | ... | + * +-----------------+ + * | page tables | * +-----------------+ <- cpu0 * | stub code | <- cpu1 * | stub code | <- cpu2 @@ -453,7 +490,20 @@ if (append_and_check_region(smram, handler, region_list, "HANDLER")) return -1;
- uintptr_t stub_segment_base = handler_base - SMM_CODE_SEGMENT_SIZE; + uintptr_t stub_segment_base; + if (ENV_X86_64) { + uintptr_t pt_base = install_page_table(handler_base); + struct region page_tables = { + .offset = pt_base, + .size = handler_base - pt_base, + }; + if (append_and_check_region(smram, page_tables, region_list, "PAGE TABLES")) + return -1; + params->cr3 = pt_base; + stub_segment_base = pt_base - SMM_CODE_SEGMENT_SIZE; + } else { + stub_segment_base = handler_base - SMM_CODE_SEGMENT_SIZE; + }
if (!smm_create_map(stub_segment_base, params->num_concurrent_save_states, params)) { printk(BIOS_ERR, "%s: Error creating CPU map\n", __func__); diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h index 6a0ec3f..a12065b 100644 --- a/src/include/cpu/x86/smm.h +++ b/src/include/cpu/x86/smm.h @@ -109,6 +109,7 @@ u32 stack_size; u32 stack_top; u32 c_handler; + u32 cr3; /* The apic_id_to_cpu provides a mapping from APIC id to CPU number. * The CPU number is indicated by the index into the array by matching * the default APIC id and value at the index. The stub loader