Attention is currently required from: Jérémy Compostella.
Benjamin Doron has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/79865?usp=email )
Change subject: [DNM] {arch,cpu}/x86: Support runtime page tables for SMM ......................................................................
[DNM] {arch,cpu}/x86: Support runtime page tables for SMM
ramstage generates page tables for SMM during MP init, so that they're available to smm_stub. However, this causes complications: the `page_tables` variable now points to SMM page tables.
TODO: - It would be optimal to only map SMRAM and known resources. However, this causes a triple-fault. Will investigate. - Must confirm if SMM_DEFAULT_BASE is available, and if placing page tables there is optimal. - Finalise page table size.
Change-Id: Ie9f4f9834da0e115758918f80f93264c8c487ec5 Signed-off-by: Benjamin Doron benjamin.doron@9elements.com --- M src/arch/x86/Makefile.inc M src/arch/x86/include/arch/mmu.h A src/arch/x86/mmu-smm.c M src/cpu/x86/smm/smm_module_loader.c M src/cpu/x86/smm/smm_stub.S M src/include/cpu/x86/smm.h 6 files changed, 111 insertions(+), 4 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/65/79865/1
diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc index bdd89bd..e7406a4 100644 --- a/src/arch/x86/Makefile.inc +++ b/src/arch/x86/Makefile.inc @@ -281,6 +281,7 @@ ramstage-$(CONFIG_HAVE_CF9_RESET) += cf9_reset.c all-$(CONFIG_ARCH_X86_MMU_PAGE_TABLES) += mmu.c ramstage-$(CONFIG_ARCH_RAMSTAGE_X86_64) += mmu-ramstage.c +ramstage-$(CONFIG_ARCH_RAMSTAGE_X86_64) += mmu-smm.c
rmodules_x86_32-y += memcpy.c rmodules_x86_32-y += memmove_32.c diff --git a/src/arch/x86/include/arch/mmu.h b/src/arch/x86/include/arch/mmu.h index 6df16aa..7ed19ea 100644 --- a/src/arch/x86/include/arch/mmu.h +++ b/src/arch/x86/include/arch/mmu.h @@ -88,6 +88,7 @@ #define PAT_UC_MINUS 7
void mmu_init_pre_cbmem(void); +void mmu_setup_smm_resources(uintptr_t page_tables, size_t page_tables_size, bool permanent);
struct region; void mmu_init_region(struct region *r); diff --git a/src/arch/x86/mmu-smm.c b/src/arch/x86/mmu-smm.c new file mode 100644 index 0000000..6595580 --- /dev/null +++ b/src/arch/x86/mmu-smm.c @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/mmu.h> +#include <console/console.h> +#include <cpu/cpu.h> +#include <cpu/x86/smm.h> +#include <device/resource.h> +#include <stdint.h> + +static void mmu_init_ranges(void *gp, struct device *dev, struct resource *res) +{ + uintptr_t smm_base; + size_t smm_size; + + if (!res->size || !IS_ALIGNED(res->size, 4 * KiB)) + return; + + smm_region(&smm_base, &smm_size); + if (res->base == smm_base) + return; + + const int addr_bits = MIN(cpu_phys_address_size(), BITS_PER_VA); + const uint64_t limit = 1ULL << addr_bits; + + if (res->size >= limit || res->base >= limit || (res->size + res->size) >= limit) + return; + + if (res->flags & IORESOURCE_CACHEABLE) + mmu_config_range(res->base, res->size, PAT_WB); + else if (res->flags & IORESOURCE_PREFETCH) + mmu_config_range(res->base, res->size, PAT_WT); + else if (res->flags & IORESOURCE_READONLY) + mmu_config_range(res->base, res->size, PAT_WP); + + /* Default mapping is UC, skip it */ +} + +void mmu_setup_smm_resources(uintptr_t page_tables, size_t page_tables_size, bool permanent) +{ + struct region r; + uintptr_t smm_base; + size_t smm_size; + + printk(BIOS_DEBUG, "MMU: Setup\n"); + + r.offset = page_tables; + r.size = page_tables_size; + mmu_init_region(&r); + + if (!permanent) { + /* smm_stub calls into ramstage:smm_do_relocation() */ + smm_base = 0; + smm_size = 4ULL * GiB; + } else { + /* BUGBUG: Broken! */ + smm_region(&smm_base, &smm_size); + + search_global_resources(IORESOURCE_MEM | IORESOURCE_ASSIGNED, + IORESOURCE_MEM | IORESOURCE_ASSIGNED, + mmu_init_ranges, 0); + } + + mmu_config_range(smm_base, smm_size, PAT_WB); + + printk(BIOS_DEBUG, "MMU: Setup done\n"); +} diff --git a/src/cpu/x86/smm/smm_module_loader.c b/src/cpu/x86/smm/smm_module_loader.c index f827e7b..3f27986 100644 --- a/src/cpu/x86/smm/smm_module_loader.c +++ b/src/cpu/x86/smm/smm_module_loader.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */
#include <acpi/acpi_gnvs.h> +#include <arch/mmu.h> #include <cbmem.h> #include <commonlib/helpers.h> #include <commonlib/region.h> @@ -13,7 +14,12 @@ #include <string.h> #include <types.h>
-#define SMM_CODE_SEGMENT_SIZE 0x10000 +#define SMM_CODE_SEGMENT_SIZE 0x10000 +#define RELOC_PAGE_TABLE_SIZE (6 * (4 * KiB)) +#define PERMANENT_PAGE_TABLE_SIZE (8 * (4 * KiB)) +_Static_assert(RELOC_PAGE_TABLE_SIZE <= (SMM_DEFAULT_BASE + SMM_DEFAULT_SIZE) \ + - (SMM_DEFAULT_BASE + SMM_ENTRY_OFFSET), \ + "page tables are too large");
/* * Components that make up the SMRAM: @@ -259,6 +265,7 @@ stub_params->stack_top = stack_top; stub_params->stack_size = g_stack_size; stub_params->c_handler = (uintptr_t)params->handler; + stub_params->smm_page_tables = params->smm_page_tables;
/* This runs on the BSP. All the APs are its siblings */ struct cpu_info *info = cpu_info(); @@ -312,6 +319,13 @@ if (params->num_cpus == 0) params->num_cpus = CONFIG_MAX_CPUS;
+ // TODO/TEST: 0x30000 is available; SMM_DEFAULT_BASE is page-aligned + params->smm_page_tables = 0; + if (CONFIG(ARCH_RAMSTAGE_X86_64)) { + mmu_setup_smm_resources(smram, RELOC_PAGE_TABLE_SIZE, false); + params->smm_page_tables = smram; + } + printk(BIOS_SPEW, "%s: exit\n", __func__); return smm_module_setup_stub(smram, SMM_DEFAULT_SIZE, params); } @@ -353,8 +367,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 + page tables + stacks */ +#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, @@ -398,6 +412,8 @@ * +-----------------+ * | smi handler | * | ... | + * +-----------------+ + * | page tables | * +-----------------+ <- cpu0 * | stub code | <- cpu1 * | stub code | <- cpu2 @@ -455,6 +471,24 @@
uintptr_t stub_segment_base = handler_base - SMM_CODE_SEGMENT_SIZE;
+ params->smm_page_tables = 0; + if (CONFIG(ARCH_RAMSTAGE_X86_64)) { + const size_t page_tables_size = PERMANENT_PAGE_TABLE_SIZE; + const uintptr_t page_tables_base = + ALIGN_DOWN(smram_top - stm_size - handler_size - page_tables_size, + 4 * KiB); + struct region page_tables = { + .offset = page_tables_base, + .size = page_tables_size + }; + if (append_and_check_region(smram, page_tables, region_list, "page tables")) + return -1; + mmu_setup_smm_resources(page_tables_base, page_tables_size, true); + params->smm_page_tables = page_tables_base; + + stub_segment_base -= ALIGN_DOWN(page_tables_size, 4 * KiB); + } + if (!smm_create_map(stub_segment_base, params->num_concurrent_save_states, params)) { printk(BIOS_ERR, "%s: Error creating CPU map\n", __func__); return -1; diff --git a/src/cpu/x86/smm/smm_stub.S b/src/cpu/x86/smm/smm_stub.S index 802dd92..26d3a2f 100644 --- a/src/cpu/x86/smm/smm_stub.S +++ b/src/cpu/x86/smm/smm_stub.S @@ -27,6 +27,8 @@ * into the table. */ apic_to_cpu_num: .fill CONFIG_MAX_CPUS,2,0xffff +smm_page_tables: +.long 0
.data /* Provide fallback stack to use when a valid CPU number cannot be found. */ @@ -196,7 +198,7 @@ mov %ecx, %edi
/* Get page table address */ - movl $(CONFIG_ARCH_X86_64_PGTBL_LOC), %eax + movl smm_page_tables, %eax
/* entry64.inc preserves ebx, esi, edi, ebp */ #include <cpu/x86/64bit/entry64.inc> diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h index a240ac2..2cea625 100644 --- a/src/include/cpu/x86/smm.h +++ b/src/include/cpu/x86/smm.h @@ -114,6 +114,7 @@ * contiguous like the 1:1 mapping it is up to the caller of the stub * loader to adjust this mapping. */ u16 apic_id_to_cpu[CONFIG_MAX_CPUS]; + u32 smm_page_tables; } __packed;
/* smm_handler_t is called with arg of smm_module_params pointer. */ @@ -162,6 +163,8 @@ size_t cpu_save_state_size; size_t num_concurrent_save_states;
+ uint32_t smm_page_tables; + smm_handler_t handler; };