Attention is currently required from: Jérémy Compostella.

Benjamin Doron has uploaded this change for review.

View Change

[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(&region));
}

-/* 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;
};


To view, visit change 79865. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: main
Gerrit-Change-Id: Ie9f4f9834da0e115758918f80f93264c8c487ec5
Gerrit-Change-Number: 79865
Gerrit-PatchSet: 1
Gerrit-Owner: Benjamin Doron <benjamin.doron00@gmail.com>
Gerrit-Reviewer: Jérémy Compostella <jeremy.compostella@intel.com>
Gerrit-Attention: Jérémy Compostella <jeremy.compostella@intel.com>
Gerrit-MessageType: newchange