x86: pre-allocate address space

We no longer use a page pool to draw memory pages when doing
memory map operations. We now preallocate the entire virtual
address space so no allocations are ever necessary when mapping
memory.

We still need memory to clone page tables, but this is now
expressed by a new Kconfig X86_MAX_ADDITIONAL_MEM_DOMAINS
which has much clearer semantics than specifying the number
of pages in the pool.

The default address space size is now 8MB, but this can be
tuned by the application.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2020-12-17 21:12:40 -08:00 committed by Anas Nashif
commit b0b7756756
19 changed files with 142 additions and 222 deletions

View file

@ -591,7 +591,7 @@ config KERNEL_VM_OFFSET
config KERNEL_VM_SIZE config KERNEL_VM_SIZE
hex "Size of kernel address space in bytes" hex "Size of kernel address space in bytes"
default 0xC0000000 default 0x800000
help help
Size of the kernel's address space. Constraining this helps control Size of the kernel's address space. Constraining this helps control
how much total memory can be used for page tables. how much total memory can be used for page tables.

View file

@ -189,29 +189,6 @@ config X86_MMU
and creates a set of page tables at boot time that is runtime- and creates a set of page tables at boot time that is runtime-
mutable. mutable.
config X86_MMU_PAGE_POOL_PAGES
int "Number of pages to reserve for building page tables"
default 0
depends on X86_MMU
help
Define the number of pages in the pool used to allocate page table
data structures at runtime.
Pages might need to be drawn from the pool during memory mapping
operations, unless the address space has been completely pre-allocated.
Pages will need to drawn from the pool to initialize memory domains.
This does not include the default memory domain if KPTI=n.
The specific value used here depends on the size of physical RAM,
how much additional virtual memory will be mapped at runtime, and
how many memory domains need to be initialized.
The current suite of Zephyr test cases may initialize at most two
additional memory domains besides the default domain.
Unused pages in this pool cannot be used for other purposes.
config X86_COMMON_PAGE_TABLE config X86_COMMON_PAGE_TABLE
bool "Use a single page table for all threads" bool "Use a single page table for all threads"
default n default n
@ -224,6 +201,18 @@ config X86_COMMON_PAGE_TABLE
page tables in place. This is much slower, but uses much less RAM page tables in place. This is much slower, but uses much less RAM
for page tables. for page tables.
config X86_MAX_ADDITIONAL_MEM_DOMAINS
int "Maximum number of memory domains"
default 3
depends on X86_MMU && USERSPACE && !X86_COMMON_PAGE_TABLE
help
The initial page tables at boot are pre-allocated, and used for the
default memory domain. Instantiation of additional memory domains
if common page tables are in use requires a pool of free pinned
memory pages for constructing page tables.
Zephyr test cases assume 3 additional domains can be instantiated.
config X86_NO_MELTDOWN config X86_NO_MELTDOWN
bool bool
help help

View file

@ -195,24 +195,25 @@ static const struct paging_level paging_levels[] = {
#define NUM_PD_ENTRIES 1024U #define NUM_PD_ENTRIES 1024U
#define NUM_PT_ENTRIES 1024U #define NUM_PT_ENTRIES 1024U
#endif /* !CONFIG_X86_64 && !CONFIG_X86_PAE */ #endif /* !CONFIG_X86_64 && !CONFIG_X86_PAE */
/* Memory range covered by an instance of various table types */ /* Memory range covered by an instance of various table types */
#define PT_AREA ((uintptr_t)(CONFIG_MMU_PAGE_SIZE * NUM_PT_ENTRIES)) #define PT_AREA ((uintptr_t)(CONFIG_MMU_PAGE_SIZE * NUM_PT_ENTRIES))
#define PD_AREA (PT_AREA * NUM_PD_ENTRIES) #define PD_AREA (PT_AREA * NUM_PD_ENTRIES)
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
#define PDPT_AREA (PD_AREA * NUM_PDPT_ENTRIES) #define PDPT_AREA (PD_AREA * NUM_PDPT_ENTRIES)
#endif #endif
#define VM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_sram)) #define VM_ADDR CONFIG_KERNEL_VM_BASE
#define VM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_sram)) #define VM_SIZE CONFIG_KERNEL_VM_SIZE
/* Define a range [PT_START, PT_END) which is the memory range /* Define a range [PT_START, PT_END) which is the memory range
* covered by all the page tables needed for system RAM * covered by all the page tables needed for the address space
*/ */
#define PT_START ((uintptr_t)ROUND_DOWN(VM_ADDR, PT_AREA)) #define PT_START ((uintptr_t)ROUND_DOWN(VM_ADDR, PT_AREA))
#define PT_END ((uintptr_t)ROUND_UP(VM_ADDR + VM_SIZE, PT_AREA)) #define PT_END ((uintptr_t)ROUND_UP(VM_ADDR + VM_SIZE, PT_AREA))
/* Number of page tables needed to cover system RAM. Depends on the specific /* Number of page tables needed to cover address space. Depends on the specific
* bounds of system RAM, but roughly 1 page table per 2MB of RAM * bounds, but roughly 1 page table per 2MB of RAM
*/ */
#define NUM_PT ((PT_END - PT_START) / PT_AREA) #define NUM_PT ((PT_END - PT_START) / PT_AREA)
@ -222,8 +223,8 @@ static const struct paging_level paging_levels[] = {
*/ */
#define PD_START ((uintptr_t)ROUND_DOWN(VM_ADDR, PD_AREA)) #define PD_START ((uintptr_t)ROUND_DOWN(VM_ADDR, PD_AREA))
#define PD_END ((uintptr_t)ROUND_UP(VM_ADDR + VM_SIZE, PD_AREA)) #define PD_END ((uintptr_t)ROUND_UP(VM_ADDR + VM_SIZE, PD_AREA))
/* Number of page directories needed to cover system RAM. Depends on the /* Number of page directories needed to cover the address space. Depends on the
* specific bounds of system RAM, but roughly 1 page directory per 1GB of RAM * specific bounds, but roughly 1 page directory per 1GB of RAM
*/ */
#define NUM_PD ((PD_END - PD_START) / PD_AREA) #define NUM_PD ((PD_END - PD_START) / PD_AREA)
#else #else
@ -233,13 +234,11 @@ static const struct paging_level paging_levels[] = {
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
/* Same semantics as above, but for the page directory pointer tables needed /* Same semantics as above, but for the page directory pointer tables needed
* to cover system RAM. On 32-bit there is just one 4-entry PDPT. * to cover the address space. On 32-bit there is just one 4-entry PDPT.
*/ */
#define PDPT_START ((uintptr_t)ROUND_DOWN(VM_ADDR, PDPT_AREA)) #define PDPT_START ((uintptr_t)ROUND_DOWN(VM_ADDR, PDPT_AREA))
#define PDPT_END ((uintptr_t)ROUND_UP(VM_ADDR + VM_SIZE, PDPT_AREA)) #define PDPT_END ((uintptr_t)ROUND_UP(VM_ADDR + VM_SIZE, PDPT_AREA))
/* Number of PDPTs needed to cover system RAM. Depends on the /* Number of PDPTs needed to cover the address space. 1 PDPT per 512GB of VM */
* specific bounds of system RAM, but roughly 1 PDPT per 512GB of RAM
*/
#define NUM_PDPT ((PDPT_END - PDPT_START) / PDPT_AREA) #define NUM_PDPT ((PDPT_END - PDPT_START) / PDPT_AREA)
/* All pages needed for page tables, using computed values plus one more for /* All pages needed for page tables, using computed values plus one more for
@ -700,47 +699,6 @@ void z_x86_dump_mmu_flags(pentry_t *ptables, void *virt)
} }
#endif /* CONFIG_EXCEPTION_DEBUG */ #endif /* CONFIG_EXCEPTION_DEBUG */
/*
* Pool of free memory pages for creating new page tables, as needed.
*
* XXX: This is very crude, once obtained, pages may not be returned. Tuning
* the optimal value of CONFIG_X86_MMU_PAGE_POOL_PAGES is not intuitive,
* Better to have a kernel managed page pool of unused RAM that can be used for
* this, sbrk(), and other anonymous mappings. See #29526
*/
static uint8_t __noinit
page_pool[CONFIG_MMU_PAGE_SIZE * CONFIG_X86_MMU_PAGE_POOL_PAGES]
__aligned(CONFIG_MMU_PAGE_SIZE);
static uint8_t *page_pos = page_pool + sizeof(page_pool);
/* Return a zeroed and suitably aligned memory page for page table data
* from the global page pool
*/
static void *page_pool_get(void)
{
void *ret;
if (page_pos == page_pool) {
ret = NULL;
} else {
page_pos -= CONFIG_MMU_PAGE_SIZE;
ret = page_pos;
}
if (ret != NULL) {
memset(ret, 0, CONFIG_MMU_PAGE_SIZE);
}
return ret;
}
/* Debugging function to show how many pages are free in the pool */
static inline unsigned int pages_free(void)
{
return (page_pos - page_pool) / CONFIG_MMU_PAGE_SIZE;
}
/* Reset permissions on a PTE to original state when the mapping was made */ /* Reset permissions on a PTE to original state when the mapping was made */
static inline pentry_t reset_pte(pentry_t old_val) static inline pentry_t reset_pte(pentry_t old_val)
{ {
@ -849,12 +807,6 @@ static inline bool atomic_pte_cas(pentry_t *target, pentry_t old_value,
*/ */
#define OPTION_RESET BIT(2) #define OPTION_RESET BIT(2)
/* Indicates that allocations from the page pool are allowed to instantiate
* new paging structures. Only necessary when establishing new mappings
* and the entire address space isn't pre-allocated.
*/
#define OPTION_ALLOC BIT(3)
/** /**
* Atomically update bits in a page table entry * Atomically update bits in a page table entry
* *
@ -923,10 +875,6 @@ static inline pentry_t pte_atomic_update(pentry_t *pte, pentry_t update_val,
* modified by another CPU, using atomic operations to update the requested * modified by another CPU, using atomic operations to update the requested
* bits and return the previous PTE value. * bits and return the previous PTE value.
* *
* This function is NOT atomic with respect to allocating intermediate
* paging structures, and this must be called with x86_mmu_lock held if
* OPTION_ALLOC is used.
*
* Common mask values: * Common mask values:
* MASK_ALL - Update all PTE bits. Exitsing state totally discarded. * MASK_ALL - Update all PTE bits. Exitsing state totally discarded.
* MASK_PERM - Only update permission bits. All other bits and physical * MASK_PERM - Only update permission bits. All other bits and physical
@ -938,17 +886,13 @@ static inline pentry_t pte_atomic_update(pentry_t *pte, pentry_t update_val,
* @param [out] old_val_ptr Filled in with previous PTE value. May be NULL. * @param [out] old_val_ptr Filled in with previous PTE value. May be NULL.
* @param mask What bits to update in the PTE (ignored if OPTION_RESET) * @param mask What bits to update in the PTE (ignored if OPTION_RESET)
* @param options Control options, described above * @param options Control options, described above
* @retval 0 Success
* @retval -ENOMEM allocation required and no free pages (only if OPTION_ALLOC)
*/ */
static int page_map_set(pentry_t *ptables, void *virt, pentry_t entry_val, static void page_map_set(pentry_t *ptables, void *virt, pentry_t entry_val,
pentry_t *old_val_ptr, pentry_t mask, uint32_t options) pentry_t *old_val_ptr, pentry_t mask, uint32_t options)
{ {
pentry_t *table = ptables; pentry_t *table = ptables;
bool flush = (options & OPTION_FLUSH) != 0U; bool flush = (options & OPTION_FLUSH) != 0U;
assert_virt_addr_aligned(virt);
for (int level = 0; level < NUM_LEVELS; level++) { for (int level = 0; level < NUM_LEVELS; level++) {
int index; int index;
pentry_t *entryp; pentry_t *entryp;
@ -966,42 +910,20 @@ static int page_map_set(pentry_t *ptables, void *virt, pentry_t entry_val,
break; break;
} }
/* This is a non-leaf entry */ /* We fail an assertion here due to no support for
if ((*entryp & MMU_P) == 0U) { * splitting existing bigpage mappings.
/* Not present. Never done a mapping here yet, need * If the PS bit is not supported at some level (like
* some RAM for linked tables * in a PML4 entry) it is always reserved and must be 0
*/ */
void *new_table; __ASSERT((*entryp & MMU_PS) == 0U, "large page encountered");
table = next_table(*entryp, level);
__ASSERT((options & OPTION_ALLOC) != 0, __ASSERT(table != NULL,
"missing page table and allocations disabled"); "missing page table level %d when trying to map %p",
level + 1, virt);
new_table = page_pool_get();
if (new_table == NULL) {
return -ENOMEM;
}
*entryp = ((pentry_t)z_x86_phys_addr(new_table) |
INT_FLAGS);
table = new_table;
} else {
/* We fail an assertion here due to no support for
* splitting existing bigpage mappings.
* If the PS bit is not supported at some level (like
* in a PML4 entry) it is always reserved and must be 0
*/
__ASSERT((*entryp & MMU_PS) == 0U,
"large page encountered");
table = next_table(*entryp, level);
}
} }
if (flush) { if (flush) {
tlb_flush_page(virt); tlb_flush_page(virt);
} }
return 0;
} }
/** /**
@ -1010,8 +932,6 @@ static int page_map_set(pentry_t *ptables, void *virt, pentry_t entry_val,
* See documentation for page_map_set() for additional notes about masks and * See documentation for page_map_set() for additional notes about masks and
* supported options. * supported options.
* *
* Must call this with x86_mmu_lock held if OPTION_ALLOC is used.
*
* It is vital to remember that all virtual-to-physical mappings must be * It is vital to remember that all virtual-to-physical mappings must be
* the same with respect to supervisor mode regardless of what thread is * the same with respect to supervisor mode regardless of what thread is
* scheduled (and therefore, if multiple sets of page tables exist, which one * scheduled (and therefore, if multiple sets of page tables exist, which one
@ -1031,14 +951,11 @@ static int page_map_set(pentry_t *ptables, void *virt, pentry_t entry_val,
* @param mask What bits to update in each PTE. Un-set bits will never be * @param mask What bits to update in each PTE. Un-set bits will never be
* modified. Ignored if OPTION_RESET. * modified. Ignored if OPTION_RESET.
* @param options Control options, described above * @param options Control options, described above
* @retval 0 Success
* @retval -ENOMEM allocation required and no free pages (only if OPTION_ALLOC)
*/ */
static int range_map_ptables(pentry_t *ptables, void *virt, uintptr_t phys, static void range_map_ptables(pentry_t *ptables, void *virt, uintptr_t phys,
size_t size, pentry_t entry_flags, pentry_t mask, size_t size, pentry_t entry_flags, pentry_t mask,
uint32_t options) uint32_t options)
{ {
int ret;
bool reset = (options & OPTION_RESET) != 0U; bool reset = (options & OPTION_RESET) != 0U;
assert_addr_aligned(phys); assert_addr_aligned(phys);
@ -1062,14 +979,9 @@ static int range_map_ptables(pentry_t *ptables, void *virt, uintptr_t phys,
entry_val = (phys + offset) | entry_flags; entry_val = (phys + offset) | entry_flags;
} }
ret = page_map_set(ptables, dest_virt, entry_val, NULL, mask, page_map_set(ptables, dest_virt, entry_val, NULL, mask,
options); options);
if (ret != 0) {
return ret;
}
} }
return 0;
} }
/** /**
@ -1093,14 +1005,10 @@ static int range_map_ptables(pentry_t *ptables, void *virt, uintptr_t phys,
* be preserved. Ignored if OPTION_RESET. * be preserved. Ignored if OPTION_RESET.
* @param options Control options. Do not set OPTION_USER here. OPTION_FLUSH * @param options Control options. Do not set OPTION_USER here. OPTION_FLUSH
* will trigger a TLB shootdown after all tables are updated. * will trigger a TLB shootdown after all tables are updated.
* @retval 0 Success
* @retval -ENOMEM page table allocation required, but no free pages
*/ */
static int range_map(void *virt, uintptr_t phys, size_t size, static void range_map(void *virt, uintptr_t phys, size_t size,
pentry_t entry_flags, pentry_t mask, uint32_t options) pentry_t entry_flags, pentry_t mask, uint32_t options)
{ {
int ret = 0;
LOG_DBG("%s: %p -> %p (%zu) flags " PRI_ENTRY " mask " LOG_DBG("%s: %p -> %p (%zu) flags " PRI_ENTRY " mask "
PRI_ENTRY " opt 0x%x", __func__, (void *)phys, virt, size, PRI_ENTRY " opt 0x%x", __func__, (void *)phys, virt, size,
entry_flags, mask, options); entry_flags, mask, options);
@ -1131,47 +1039,29 @@ static int range_map(void *virt, uintptr_t phys, size_t size,
struct arch_mem_domain *domain = struct arch_mem_domain *domain =
CONTAINER_OF(node, struct arch_mem_domain, node); CONTAINER_OF(node, struct arch_mem_domain, node);
ret = range_map_ptables(domain->ptables, virt, phys, size, range_map_ptables(domain->ptables, virt, phys, size,
entry_flags, mask, entry_flags, mask, options | OPTION_USER);
options | OPTION_USER);
if (ret != 0) {
/* NOTE: Currently we do not un-map a partially
* completed mapping.
*/
goto out_unlock;
}
} }
#endif /* CONFIG_USERSPACE */ #endif /* CONFIG_USERSPACE */
ret = range_map_ptables(z_x86_kernel_ptables, virt, phys, size, range_map_ptables(z_x86_kernel_ptables, virt, phys, size, entry_flags,
entry_flags, mask, options); mask, options);
#if defined(CONFIG_USERSPACE) && !defined(CONFIG_X86_COMMON_PAGE_TABLE)
out_unlock:
#endif /* CONFIG_USERSPACE */
if (ret == 0 && (options & OPTION_ALLOC) != 0) {
LOG_DBG("page pool pages free: %u / %u", pages_free(),
CONFIG_X86_MMU_PAGE_POOL_PAGES);
}
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
if ((options & OPTION_FLUSH) != 0U) { if ((options & OPTION_FLUSH) != 0U) {
tlb_shootdown(); tlb_shootdown();
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
return ret;
} }
static inline int range_map_unlocked(void *virt, uintptr_t phys, size_t size, static inline void range_map_unlocked(void *virt, uintptr_t phys, size_t size,
pentry_t entry_flags, pentry_t mask, pentry_t entry_flags, pentry_t mask,
uint32_t options) uint32_t options)
{ {
int ret;
k_spinlock_key_t key; k_spinlock_key_t key;
key = k_spin_lock(&x86_mmu_lock); key = k_spin_lock(&x86_mmu_lock);
ret = range_map(virt, phys, size, entry_flags, mask, options); range_map(virt, phys, size, entry_flags, mask, options);
k_spin_unlock(&x86_mmu_lock, key); k_spin_unlock(&x86_mmu_lock, key);
return ret;
} }
static pentry_t flags_to_entry(uint32_t flags) static pentry_t flags_to_entry(uint32_t flags)
@ -1215,8 +1105,10 @@ static pentry_t flags_to_entry(uint32_t flags)
/* map new region virt..virt+size to phys with provided arch-neutral flags */ /* map new region virt..virt+size to phys with provided arch-neutral flags */
int arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) int arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags)
{ {
return range_map_unlocked(virt, phys, size, flags_to_entry(flags), range_map_unlocked(virt, phys, size, flags_to_entry(flags),
MASK_ALL, OPTION_ALLOC); MASK_ALL, 0);
return 0;
} }
#if CONFIG_X86_STACK_PROTECTION #if CONFIG_X86_STACK_PROTECTION
@ -1230,8 +1122,8 @@ void z_x86_set_stack_guard(k_thread_stack_t *stack)
* Guard page is always the first page of the stack object for both * Guard page is always the first page of the stack object for both
* kernel and thread stacks. * kernel and thread stacks.
*/ */
(void)range_map_unlocked(stack, 0, CONFIG_MMU_PAGE_SIZE, range_map_unlocked(stack, 0, CONFIG_MMU_PAGE_SIZE,
MMU_P | ENTRY_XD, MASK_PERM, OPTION_FLUSH); MMU_P | ENTRY_XD, MASK_PERM, OPTION_FLUSH);
} }
#endif /* CONFIG_X86_STACK_PROTECTION */ #endif /* CONFIG_X86_STACK_PROTECTION */
@ -1333,14 +1225,14 @@ int arch_buffer_validate(void *addr, size_t size, int write)
static inline void reset_region(uintptr_t start, size_t size) static inline void reset_region(uintptr_t start, size_t size)
{ {
(void)range_map_unlocked((void *)start, 0, size, 0, 0, range_map_unlocked((void *)start, 0, size, 0, 0,
OPTION_FLUSH | OPTION_RESET); OPTION_FLUSH | OPTION_RESET);
} }
static inline void apply_region(uintptr_t start, size_t size, pentry_t attr) static inline void apply_region(uintptr_t start, size_t size, pentry_t attr)
{ {
(void)range_map_unlocked((void *)start, 0, size, attr, MASK_PERM, range_map_unlocked((void *)start, 0, size, attr, MASK_PERM,
OPTION_FLUSH); OPTION_FLUSH);
} }
/* Cache of the current memory domain applied to the common page tables and /* Cache of the current memory domain applied to the common page tables and
@ -1466,6 +1358,44 @@ void arch_mem_domain_destroy(struct k_mem_domain *domain)
#else #else
/* Memory domains each have a set of page tables assigned to them */ /* Memory domains each have a set of page tables assigned to them */
/*
* Pool of free memory pages for copying page tables, as needed.
*/
#define PTABLE_COPY_SIZE (NUM_TABLE_PAGES * CONFIG_MMU_PAGE_SIZE)
static uint8_t __noinit
page_pool[PTABLE_COPY_SIZE * CONFIG_X86_MAX_ADDITIONAL_MEM_DOMAINS]
__aligned(CONFIG_MMU_PAGE_SIZE);
static uint8_t *page_pos = page_pool + sizeof(page_pool);
/* Return a zeroed and suitably aligned memory page for page table data
* from the global page pool
*/
static void *page_pool_get(void)
{
void *ret;
if (page_pos == page_pool) {
ret = NULL;
} else {
page_pos -= CONFIG_MMU_PAGE_SIZE;
ret = page_pos;
}
if (ret != NULL) {
memset(ret, 0, CONFIG_MMU_PAGE_SIZE);
}
return ret;
}
/* Debugging function to show how many pages are free in the pool */
static inline unsigned int pages_free(void)
{
return (page_pos - page_pool) / CONFIG_MMU_PAGE_SIZE;
}
/** /**
* Duplicate an entire set of page tables * Duplicate an entire set of page tables
* *
@ -1636,9 +1566,6 @@ int arch_mem_domain_init(struct k_mem_domain *domain)
if (ret == 0) { if (ret == 0) {
sys_slist_append(&x86_domain_list, &domain->arch.node); sys_slist_append(&x86_domain_list, &domain->arch.node);
} }
LOG_DBG("page pool pages free: %u / %u\n", pages_free(),
CONFIG_X86_MMU_PAGE_POOL_PAGES);
k_spin_unlock(&x86_mmu_lock, key); k_spin_unlock(&x86_mmu_lock, key);
return ret; return ret;

View file

@ -296,7 +296,17 @@ class PtableSet(object):
some kind of leaf page table class (Pt or PtXd)""" some kind of leaf page table class (Pt or PtXd)"""
raise NotImplementedError() raise NotImplementedError()
def map_page(self, virt_addr, phys_addr, flags): def new_child_table(self, table, virt_addr, depth):
new_table_addr = self.get_new_mmutable_addr()
new_table = self.levels[depth]()
debug("new %s at physical addr 0x%x"
% (self.levels[depth].__name__, new_table_addr))
self.tables[new_table_addr] = new_table
table.map(virt_addr, new_table_addr, INT_FLAGS)
return new_table
def map_page(self, virt_addr, phys_addr, flags, reserve):
"""Map a virtual address to a physical address in the page tables, """Map a virtual address to a physical address in the page tables,
with provided access flags""" with provided access flags"""
table = self.toplevel table = self.toplevel
@ -305,18 +315,29 @@ class PtableSet(object):
for depth in range(1, len(self.levels)): for depth in range(1, len(self.levels)):
# Create child table if needed # Create child table if needed
if not table.has_entry(virt_addr): if not table.has_entry(virt_addr):
new_table_addr = self.get_new_mmutable_addr() table = self.new_child_table(table, virt_addr, depth)
new_table = self.levels[depth]()
debug("new %s at physical addr 0x%x"
% (self.levels[depth].__name__, new_table_addr))
self.tables[new_table_addr] = new_table
table.map(virt_addr, new_table_addr, INT_FLAGS)
table = new_table
else: else:
table = self.tables[table.lookup(virt_addr)] table = self.tables[table.lookup(virt_addr)]
# Set up entry in leaf page table # Set up entry in leaf page table
table.map(virt_addr, phys_addr, flags) if not reserve:
table.map(virt_addr, phys_addr, flags)
def reserve(self, virt_base, size):
debug("Reserving paging structures 0x%x (%d)" %
(virt_base, size))
align_check(virt_base, size)
# How much memory is covered by leaf page table
scope = 1 << self.levels[-2].addr_shift
if virt_base % scope != 0:
error("misaligned virtual address space, 0x%x not a multiple of 0x%x" %
(virt_base, scope))
for addr in range(virt_base, virt_base + size, scope):
self.map_page(addr, 0, 0, True)
def map(self, phys_base, size, flags): def map(self, phys_base, size, flags):
"""Identity map an address range in the page tables, with provided """Identity map an address range in the page tables, with provided
@ -331,7 +352,7 @@ class PtableSet(object):
# Never map the NULL page # Never map the NULL page
continue continue
self.map_page(addr, addr, flags) self.map_page(addr, addr, flags, False)
def set_region_perms(self, name, flags): def set_region_perms(self, name, flags):
"""Set access permissions for a named region that is already mapped """Set access permissions for a named region that is already mapped
@ -435,12 +456,18 @@ def main():
debug("building %s" % pclass.__name__) debug("building %s" % pclass.__name__)
# Identity-mapped Zephyr image in RAM vm_base = syms["CONFIG_KERNEL_VM_BASE"]
vm_size = syms["CONFIG_KERNEL_VM_SIZE"]
image_base = syms["z_mapped_start"] image_base = syms["z_mapped_start"]
image_size = syms["z_mapped_size"] image_size = syms["z_mapped_size"]
ptables_phys = syms["z_x86_pagetables_start"] ptables_phys = syms["z_x86_pagetables_start"]
debug("Base addresses: physical 0x%x size %d" % (image_base, image_size)) debug("Address space: 0x%x - 0x%x size %x" %
(vm_base, vm_base + vm_size, vm_size))
debug("Zephyr image: 0x%x - 0x%x size %x" %
(image_base, image_base + image_size, image_size))
is_perm_regions = isdef("CONFIG_SRAM_REGION_PERMISSIONS") is_perm_regions = isdef("CONFIG_SRAM_REGION_PERMISSIONS")
@ -452,6 +479,9 @@ def main():
map_flags = FLAG_P map_flags = FLAG_P
pt = pclass(ptables_phys) pt = pclass(ptables_phys)
# Instantiate all the paging structures for the address space
pt.reserve(vm_base, vm_size)
# Map the zephyr image
pt.map(image_base, image_size, map_flags | ENTRY_RW) pt.map(image_base, image_size, map_flags | ENTRY_RW)
if isdef("CONFIG_X86_64"): if isdef("CONFIG_X86_64"):

View file

@ -13,4 +13,3 @@ CONFIG_UART_CONSOLE=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000
CONFIG_BUILD_OUTPUT_BIN=y CONFIG_BUILD_OUTPUT_BIN=y
CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN=n CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN=n
CONFIG_X86_MMU_PAGE_POOL_PAGES=29

View file

@ -13,4 +13,3 @@ CONFIG_UART_CONSOLE=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1900000000 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1900000000
CONFIG_BUILD_OUTPUT_BIN=y CONFIG_BUILD_OUTPUT_BIN=y
CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN=n CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN=n
CONFIG_X86_MMU_PAGE_POOL_PAGES=29

View file

@ -12,9 +12,6 @@ config BUILD_OUTPUT_STRIPPED
config MP_NUM_CPUS config MP_NUM_CPUS
default 2 default 2
config X86_MMU_PAGE_POOL_PAGES
default 3072 if X86_MMU
endif # BOARD_EHL_CRB endif # BOARD_EHL_CRB
if BOARD_EHL_CRB_SBL if BOARD_EHL_CRB_SBL
@ -28,9 +25,6 @@ config BUILD_OUTPUT_STRIPPED
config MP_NUM_CPUS config MP_NUM_CPUS
default 2 default 2
config X86_MMU_PAGE_POOL_PAGES
default 3072 if X86_MMU
config SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN config SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN
depends on SHELL_BACKEND_SERIAL depends on SHELL_BACKEND_SERIAL
default n default n

View file

@ -10,4 +10,3 @@ CONFIG_UART_NS16550=y
CONFIG_UART_CONSOLE=y CONFIG_UART_CONSOLE=y
CONFIG_X2APIC=y CONFIG_X2APIC=y
CONFIG_SMP=y CONFIG_SMP=y
CONFIG_X86_MMU_PAGE_POOL_PAGES=3092

View file

@ -10,4 +10,3 @@ CONFIG_UART_NS16550=y
CONFIG_UART_CONSOLE=y CONFIG_UART_CONSOLE=y
CONFIG_X2APIC=y CONFIG_X2APIC=y
CONFIG_SMP=y CONFIG_SMP=y
CONFIG_X86_MMU_PAGE_POOL_PAGES=3092

View file

@ -8,7 +8,4 @@ config BOARD
config BUILD_OUTPUT_STRIPPED config BUILD_OUTPUT_STRIPPED
default y default y
config X86_MMU_PAGE_POOL_PAGES
default 3086 if X86_MMU
endif # BOARD_MINNOWBOARD endif # BOARD_MINNOWBOARD

View file

@ -17,4 +17,3 @@ CONFIG_MP_NUM_CPUS=2
CONFIG_X86_MMU=y CONFIG_X86_MMU=y
CONFIG_X86_VERY_EARLY_CONSOLE=y CONFIG_X86_VERY_EARLY_CONSOLE=y
CONFIG_QEMU_ICOUNT=n CONFIG_QEMU_ICOUNT=n
CONFIG_X86_MMU_PAGE_POOL_PAGES=23

View file

@ -18,4 +18,3 @@ CONFIG_X86_MMU=y
CONFIG_X86_VERY_EARLY_CONSOLE=y CONFIG_X86_VERY_EARLY_CONSOLE=y
CONFIG_QEMU_ICOUNT=n CONFIG_QEMU_ICOUNT=n
CONFIG_X86_KPTI=n CONFIG_X86_KPTI=n
CONFIG_X86_MMU_PAGE_POOL_PAGES=16

View file

@ -12,7 +12,6 @@ CONFIG_UART_CONSOLE=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000
CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_X86_MMU=y CONFIG_X86_MMU=y
CONFIG_X86_MMU_PAGE_POOL_PAGES=17
CONFIG_DEBUG_INFO=y CONFIG_DEBUG_INFO=y
CONFIG_SCHED_SCALABLE=y CONFIG_SCHED_SCALABLE=y
CONFIG_WAITQ_SCALABLE=y CONFIG_WAITQ_SCALABLE=y

View file

@ -12,7 +12,6 @@ CONFIG_UART_CONSOLE=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000
CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_X86_MMU=y CONFIG_X86_MMU=y
CONFIG_X86_MMU_PAGE_POOL_PAGES=17
CONFIG_DEBUG_INFO=y CONFIG_DEBUG_INFO=y
CONFIG_SCHED_SCALABLE=y CONFIG_SCHED_SCALABLE=y
CONFIG_WAITQ_SCALABLE=y CONFIG_WAITQ_SCALABLE=y

View file

@ -12,7 +12,6 @@ CONFIG_UART_CONSOLE=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000
CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_X86_MMU=y CONFIG_X86_MMU=y
CONFIG_X86_MMU_PAGE_POOL_PAGES=12
CONFIG_DEBUG_INFO=y CONFIG_DEBUG_INFO=y
CONFIG_SCHED_SCALABLE=y CONFIG_SCHED_SCALABLE=y
CONFIG_WAITQ_SCALABLE=y CONFIG_WAITQ_SCALABLE=y

View file

@ -12,7 +12,6 @@ CONFIG_UART_CONSOLE=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000
CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_X86_MMU=y CONFIG_X86_MMU=y
CONFIG_X86_MMU_PAGE_POOL_PAGES=10
CONFIG_DEBUG_INFO=y CONFIG_DEBUG_INFO=y
CONFIG_SCHED_SCALABLE=y CONFIG_SCHED_SCALABLE=y
CONFIG_WAITQ_SCALABLE=y CONFIG_WAITQ_SCALABLE=y

View file

@ -5,5 +5,5 @@
*/ */
#define DT_DRAM_BASE 0x100000 #define DT_DRAM_BASE 0x100000
#define DT_DRAM_SIZE DT_SIZE_K(128) #define DT_DRAM_SIZE DT_SIZE_K(256)
#include "qemu_x86.dts" #include "qemu_x86.dts"

View file

@ -23,6 +23,5 @@ CONFIG_X86_COMMON_PAGE_TABLE=y
CONFIG_X86_KPTI=n CONFIG_X86_KPTI=n
CONFIG_KERNEL_VM_SIZE=0x400000 CONFIG_KERNEL_VM_SIZE=0x400000
CONFIG_KERNEL_VM_BASE=0x0 CONFIG_KERNEL_VM_BASE=0x0
CONFIG_X86_MMU_PAGE_POOL_PAGES=0
CONFIG_KERNEL_VM_OFFSET=0x100000 CONFIG_KERNEL_VM_OFFSET=0x100000
CONFIG_X86_KERNEL_OFFSET=0 CONFIG_X86_KERNEL_OFFSET=0

View file

@ -11,9 +11,6 @@ config BUILD_OUTPUT_STRIPPED
config MP_NUM_CPUS config MP_NUM_CPUS
default 2 default 2
config X86_MMU_PAGE_POOL_PAGES
default 3092 if X86_MMU
endif # BOARD_UP_SQUARED endif # BOARD_UP_SQUARED
@ -25,7 +22,4 @@ config BOARD
config BUILD_OUTPUT_STRIPPED config BUILD_OUTPUT_STRIPPED
default y default y
config X86_MMU_PAGE_POOL_PAGES
default 3086 if X86_MMU
endif # BOARD_UP_SQUARED_32 endif # BOARD_UP_SQUARED_32