Attention is currently required from: Christian Walter, Johnny Lin, Jonathan Zhang, Jérémy Compostella, Shuo Liu, Tim Chu.
Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/85806?usp=email )
Change subject: cpu/x86/64bit: Install extended page tables in BSS ......................................................................
cpu/x86/64bit: Install extended page tables in BSS
On Intel 14nm Xeon-SP every processor support 1TiB of DRAM. Since MMIO is mapped above usable DRAM, the default page tables in RODATA are not sufficient to cover the high MMIO space.
This prevents the use of coreboot's ramstage drivers as they cannot access the PCI BARs residing in high MMIO.
Introduce a simple page table generator that installs extended page tables in BSS to access up to 48bit of the virtual address space.
TEST: Booted on ibm/sbp1 and accessed a PCI BAR above 512GiB without crash.
Change-Id: Ifab50975e0382a1f5c27b55bca1dbbb66b37ba3a Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/cpu/x86/64bit/Makefile.mk A src/cpu/x86/64bit/mmu.c M src/cpu/x86/Kconfig M src/soc/intel/xeon_sp/Kconfig 4 files changed, 212 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/06/85806/1
diff --git a/src/cpu/x86/64bit/Makefile.mk b/src/cpu/x86/64bit/Makefile.mk index 8ce3665..8ce9757 100644 --- a/src/cpu/x86/64bit/Makefile.mk +++ b/src/cpu/x86/64bit/Makefile.mk @@ -11,6 +11,8 @@
all_x86-y += $(PAGETABLE_SRC)
+ramstage-$(CONFIG_CPU_USE_EXTENDED_PAGE_TABLES_IN_BSS) += mmu.c + # Add --defsym=_start=0 to suppress a linker warning. $(objcbfs)/pt: $(dir)/$(PAGETABLE_SRC) $(obj)/config.h $(CC_bootblock) $(CFLAGS_bootblock) $(CPPFLAGS_bootblock) -o $@.tmp $< -Wl,--section-start=.rodata=$(CONFIG_ARCH_X86_64_PGTBL_LOC),--defsym=_start=0 -fuse-ld=bfd diff --git a/src/cpu/x86/64bit/mmu.c b/src/cpu/x86/64bit/mmu.c new file mode 100644 index 0000000..1dd89dd --- /dev/null +++ b/src/cpu/x86/64bit/mmu.c @@ -0,0 +1,199 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <bootstate.h> +#include <cpu/cpu.h> +#include <cpu/x86/cr.h> +#include <console/console.h> +#include <device/device.h> +#include <device/resource.h> +#include <stdint.h> +#include <stdio.h> + +#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 + (uintptr_t)(a)) +#define _GEN_PAGE(a) (_PRES + _RW + _US + _PS + _A + _D + (uintptr_t)(a)) +#define BITS_PER_VA 48 + +/* Page table to map the whole address space. See Note below. */ +#define PTE_ENTRIES (1 + 1 + 512) +static uint8_t __aligned(4096) page_tables[PTE_ENTRIES * 4096]; + +static inline bool cpu_supports_1gb_hugepage(void) +{ + static bool checked, supports; + if (checked) + return supports; + + /* check if CPU supports 1GB hugepages */ + if (cpu_cpuid_extended_level() >= 0x80000001) + supports = !!(cpuid_edx(0x80000001) & (1 << 26)); + checked = true; + + return supports; +} + +/** + * @brief Identity map more of the address space. + * + * The assumption is that on old platforms (that do not support 1GB + * PT), only mobile and client platforms are supported, and that those platforms + * used DDR3 or older DRAM, thus 512GiB of memory are sufficient for + * coreboot's ramstage. + * + * When 1GB PT are supported it maps 48 bits (the maximum 4-LVL paging supports), + * when 1GB PT aren't supported it maps 40 bits of the address space (512GiB). + * + * Runtime generated to keep ramstage size at minimum. + */ +static void mmu_enable(void) +{ + uint64_t *const p4mle = (uint64_t *const)&page_tables[0]; + uint64_t *const pdpt = (uint64_t *const)&page_tables[4096]; + uint64_t *const pdt = (uint64_t *const)&page_tables[4096 * 2]; + + if (cpu_supports_1gb_hugepage()) { + const uintptr_t max_addr = 1ULL * GiB * 512ULL * 512ULL; + const uint64_t incr = 1ULL * GiB; + + /* Build P4MLE */ + for (int i = 0; i < 512; i++) + p4mle[i] = _GEN_DIR(&pdpt[i * 512]); + + /* Build PDPT */ + uint64_t *page_table_ptr = pdpt; + for (uintptr_t addr = 0; addr < max_addr; addr+=incr, page_table_ptr++) + *page_table_ptr = _GEN_PAGE(addr); + } else { + const uintptr_t max_addr = 2ULL * MiB * 512ULL * 512ULL; + const uint64_t incr = 2ULL * MiB; + + /* Build P4MLE */ + p4mle[0] = _GEN_DIR(&pdpt[0]); + + /* Build PDPT */ + for (int i = 0; i < 512; i++) + pdpt[i] = _GEN_DIR(&pdt[i * 512]); + + /* Build PDT */ + uint64_t *page_table_ptr = pdt; + for (uintptr_t addr = 0; addr < max_addr; addr+=incr, page_table_ptr++) + *page_table_ptr = _GEN_PAGE(addr); + } + + /* Load the new page table address */ + write_cr3((uintptr_t)page_tables); +} + +/* + * Reports resources above the given limit. + */ +static void mmu_report_limit(void *gp, struct device *dev, struct resource *res) +{ + unsigned long long base, end; + char buf[16]; + + if (!res->size) + return; + const uint64_t *max_addr = (uint64_t *)gp; + + assert(((res->base + res->size) < *max_addr) && + (res->base < *max_addr) && + (res->size < *max_addr)); + + if (((res->base + res->size) < *max_addr) && + (res->base < *max_addr) && + (res->size < *max_addr)) + return; + + base = res->base; + end = resource_end(res); + buf[0] = '\0'; + + if (dev->downstream && (res->flags & IORESOURCE_PCI_BRIDGE)) { + snprintf(buf, sizeof(buf), + "seg %02x bus %02x ", dev->downstream->segment_group, + dev->downstream->secondary); + } + + printk(BIOS_ERR, "%s %02lx <- [0x%016llx - 0x%016llx] size 0x%08llx " + "gran 0x%02x %s%s\n", dev_path(dev), res->index, + base, end, res->size, res->gran, buf, + resource_type(res)); +} + +/* + * Find the upper limit of assigned memory resources. + */ +static void mmu_find_limit(void *gp, struct device *dev, struct resource *res) +{ + if (!res->size) + return; + uint64_t *limit = (uint64_t *)gp; + + if (*limit < (res->base + res->size)) + *limit = (res->base + res->size); +} + +/* + * Returns the (virtual) size of the currently mapped address space when using + * page tables in RODATA. + */ +static inline uint64_t mmu_default_map_size(void) +{ + if (CONFIG(NEED_SMALL_2MB_PAGE_TABLES)) + return 4ULL * GiB; + else + return 512ULL * GiB; +} + +/* + * Returns the (virtual) size of the mapped address space when using + * new page tables in BSS. + */ +static inline int mmu_max_virt_address_bits(void) +{ + /* Using 512 4K pages limits the usable address space */ + if (cpu_supports_1gb_hugepage()) + return BITS_PER_VA; + else + return 40; +} + +/* + * Installs new page tables in BSS. + */ +static void mmu_setup_all_resources(void *unused) +{ + uint64_t limit = 0; + + /* Get upper limit of active memory address space (DRAM / MMIO) */ + search_global_resources(IORESOURCE_MEM | IORESOURCE_ASSIGNED, + IORESOURCE_MEM | IORESOURCE_ASSIGNED, + mmu_find_limit, &limit); + limit = ALIGN_UP(limit, GiB); + + printk(BIOS_DEBUG, "MMU: Upper MEM limit is 0x%llx\n", limit); + printk(BIOS_DEBUG, "MMU: New page tables are%s required\n", + (limit > mmu_default_map_size()) ? "" : "n't"); + + uint64_t addr_limit = 1ULL << mmu_max_virt_address_bits(); + + /* Report conflicts when active address space is too big */ + assert(limit <= addr_limit); + if (limit > addr_limit) { + printk(BIOS_ERR, "MMU: New page tables in BSS won't cover active address space!\n"); + printk(BIOS_ERR, "MMU: Conflicting resources:\n"); + search_global_resources(IORESOURCE_MEM | IORESOURCE_ASSIGNED, + IORESOURCE_MEM | IORESOURCE_ASSIGNED, + mmu_report_limit, &addr_limit); + } + + mmu_enable(); +} + +BOOT_STATE_INIT_ENTRY(BS_DEV_RESOURCES, BS_ON_EXIT, mmu_setup_all_resources, NULL); \ No newline at end of file diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig index 828c0f9..9c2678b 100644 --- a/src/cpu/x86/Kconfig +++ b/src/cpu/x86/Kconfig @@ -152,6 +152,16 @@ bool default n
+config CPU_USE_EXTENDED_PAGE_TABLES_IN_BSS + bool + default n + depends on ARCH_RAMSTAGE_X86_64 + help + Set up extended pages tables in BSS that cover a bigger address space + than the default page tables in RODATA, installed after BS_DEV_RESOURCES + to make all memory resources reachable by the CPU. + Increases BSS by additional 2.1MiB. + config NEED_SMALL_2MB_PAGE_TABLES bool default n diff --git a/src/soc/intel/xeon_sp/Kconfig b/src/soc/intel/xeon_sp/Kconfig index f61de56..883015e 100644 --- a/src/soc/intel/xeon_sp/Kconfig +++ b/src/soc/intel/xeon_sp/Kconfig @@ -13,6 +13,7 @@ select BOOT_DEVICE_SUPPORTS_WRITES select CPU_INTEL_COMMON select CPU_INTEL_FIRMWARE_INTERFACE_TABLE + select CPU_USE_EXTENDED_PAGE_TABLES_IN_BSS select FSP_CAR select FSP_M_XIP select FSP_COMPRESS_FSP_S_LZ4