summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/Kconfig16
-rw-r--r--src/arch/x86/car.ld20
-rw-r--r--src/cpu/x86/pae/pgtbl.c47
-rw-r--r--src/include/cpu/x86/pae.h5
-rw-r--r--src/include/symbols.h4
5 files changed, 92 insertions, 0 deletions
diff --git a/src/arch/x86/Kconfig b/src/arch/x86/Kconfig
index f5bbd7827e..d7f144e179 100644
--- a/src/arch/x86/Kconfig
+++ b/src/arch/x86/Kconfig
@@ -286,3 +286,19 @@ config COLLECT_TIMESTAMPS_TSC
depends on COLLECT_TIMESTAMPS
help
Use the TSC as the timestamp source.
+
+config PAGING_IN_CACHE_AS_RAM
+ bool
+ default n
+ depends on ARCH_X86
+ help
+ Chipsets scan select this option to preallocate area in cache-as-ram
+ for storing paging data structures. PAE paging is currently the
+ only thing being supported.
+
+config NUM_CAR_PAGE_TABLE_PAGES
+ int
+ default 5
+ depends on PAGING_IN_CACHE_AS_RAM
+ help
+ The number of 4KiB pages that should be pre-allocated for page tables.
diff --git a/src/arch/x86/car.ld b/src/arch/x86/car.ld
index bfc1b03bd3..2acd3f673f 100644
--- a/src/arch/x86/car.ld
+++ b/src/arch/x86/car.ld
@@ -19,6 +19,13 @@
. = CONFIG_DCACHE_RAM_BASE;
.car.data . (NOLOAD) : {
_car_region_start = . ;
+#if IS_ENABLED(CONFIG_PAGING_IN_CACHE_AS_RAM)
+ /* Page table pre-allocation. CONFIG_DCACHE_RAM_BASE should be 4KiB
+ * aligned when using this option. */
+ _pagetables = . ;
+ . += 4096 * CONFIG_NUM_CAR_PAGE_TABLE_PAGES;
+ _epagetables = . ;
+#endif
/* Vboot work buffer is completely volatile outside of verstage and
* romstage. Appropriate code needs to handle the transition. */
#if IS_ENABLED(CONFIG_VBOOT_SEPARATE_VERSTAGE)
@@ -37,6 +44,16 @@
* so that multiple stages (romstage and verstage) have a consistent
* link address of these shared objects. */
PRERAM_CBMEM_CONSOLE(., (CONFIG_LATE_CBMEM_INIT ? 0 : CONFIG_PRERAM_CBMEM_CONSOLE_SIZE))
+#if IS_ENABLED(CONFIG_PAGING_IN_CACHE_AS_RAM)
+ . = ALIGN(32);
+ /* Page directory pointer table resides here. There are 4 8-byte entries
+ * totalling 32 bytes that need to be 32-byte aligned. The reason the
+ * pdpt are not colocated with the rest of the page tables is to reduce
+ * fragmentation of the CAR space that persists across stages. */
+ _pdpt = .;
+ . += 32;
+ _epdpt = .;
+#endif
_car_relocatable_data_start = .;
/* The timestamp implementation relies on this storage to be around
* after migration. One of the fields indicates not to use it as the
@@ -78,3 +95,6 @@
}
_bogus = ASSERT((CONFIG_DCACHE_RAM_SIZE == 0) || (SIZEOF(.car.data) <= CONFIG_DCACHE_RAM_SIZE), "Cache as RAM area is too full");
+#if IS_ENABLED(CONFIG_PAGING_IN_CACHE_AS_RAM)
+_bogus2 = ASSERT(_pagetables == ALIGN(_pagetables, 4096), "_pagetables aren't 4KiB aligned");
+#endif
diff --git a/src/cpu/x86/pae/pgtbl.c b/src/cpu/x86/pae/pgtbl.c
index cd03547ef8..c272b2da1c 100644
--- a/src/cpu/x86/pae/pgtbl.c
+++ b/src/cpu/x86/pae/pgtbl.c
@@ -13,6 +13,7 @@
* GNU General Public License for more details.
*/
+#include <cbfs.h>
#include <compiler.h>
#include <console/console.h>
#include <cpu/cpu.h>
@@ -22,6 +23,7 @@
#include <cpu/x86/pae.h>
#include <rules.h>
#include <string.h>
+#include <symbols.h>
void paging_enable_pae_cr3(uintptr_t cr3)
{
@@ -169,3 +171,48 @@ void paging_set_default_pat(void)
PAT_ENCODE(UC_MINUS, 6) | PAT_ENCODE(WT, 7);
paging_set_pat(pat);
}
+
+static int read_from_cbfs(const char *name, void *buf, size_t size)
+{
+ struct cbfsf fh;
+ struct region_device rdev;
+ size_t rdev_sz;
+
+ if (cbfs_boot_locate(&fh, name, NULL))
+ return -1;
+
+ cbfs_file_data(&rdev, &fh);
+
+ rdev_sz = region_device_sz(&rdev);
+
+ if (size < rdev_sz) {
+ printk(BIOS_ERR, "%s region too small to load: %zx < %zx\n",
+ name, size, rdev_sz);
+ return -1;
+ }
+
+ if (rdev_readat(&rdev, buf, 0, rdev_sz) != rdev_sz)
+ return -1;
+
+ return 0;
+}
+
+int paging_enable_for_car(const char *pdpt_name, const char *pt_name)
+{
+ if (!ENV_CACHE_AS_RAM)
+ return -1;
+
+ if (read_from_cbfs(pdpt_name, _pdpt, _pdpt_size)) {
+ printk(BIOS_ERR, "Couldn't load pdpt\n");
+ return -1;
+ }
+
+ if (read_from_cbfs(pt_name, _pagetables, _pagetables_size)) {
+ printk(BIOS_ERR, "Couldn't load page tables\n");
+ return -1;
+ }
+
+ paging_enable_pae_cr3((uintptr_t)_pdpt);
+
+ return 0;
+}
diff --git a/src/include/cpu/x86/pae.h b/src/include/cpu/x86/pae.h
index 96999bb0a8..a8b5e893fc 100644
--- a/src/include/cpu/x86/pae.h
+++ b/src/include/cpu/x86/pae.h
@@ -27,6 +27,11 @@ void paging_set_pat(uint64_t pat);
/* Set coreboot default PAT value. */
void paging_set_default_pat(void);
+/* Load page directory pointer table and page tables from cbfs identified by
+ * the provided the names then enable paging. Return 0 on success, < 0 on
+ * failure. */
+int paging_enable_for_car(const char *pdpt_name, const char *pt_name);
+
#define MAPPING_ERROR ((void *)0xffffffffUL)
void *map_2M_page(unsigned long page);
diff --git a/src/include/symbols.h b/src/include/symbols.h
index ada7fa70df..5b92899cee 100644
--- a/src/include/symbols.h
+++ b/src/include/symbols.h
@@ -106,6 +106,10 @@ extern u8 _framebuffer[];
extern u8 _eframebuffer[];
#define _framebuffer_size (_eframebuffer - _framebuffer)
+extern u8 _pdpt[];
+extern u8 _epdpt[];
+#define _pdpt_size (_epdpt - _pdpt)
+
/* Put this into a .c file accessing a linker script region to mark that region
* as "optional". If it is defined in memlayout.ld (or anywhere else), the
* values from that definition will be used. If not, start, end and size will