Revert "x86: pre-allocate address space"

This reverts commit 64f05d443a.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
Anas Nashif 2021-01-22 07:37:33 -05:00
commit e980848ba7
19 changed files with 222 additions and 142 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 0x800000 default 0xC0000000
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,6 +189,29 @@ 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
@ -201,18 +224,6 @@ 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,25 +195,24 @@ 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 CONFIG_KERNEL_VM_BASE #define VM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_sram))
#define VM_SIZE CONFIG_KERNEL_VM_SIZE #define VM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_sram))
/* 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 the address space * covered by all the page tables needed for system RAM
*/ */
#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 address space. Depends on the specific /* Number of page tables needed to cover system RAM. Depends on the specific
* bounds, but roughly 1 page table per 2MB of RAM * bounds of system RAM, 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)
@ -223,8 +222,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 the address space. Depends on the /* Number of page directories needed to cover system RAM. Depends on the
* specific bounds, but roughly 1 page directory per 1GB of RAM * specific bounds of system RAM, 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
@ -234,11 +233,13 @@ 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 the address space. On 32-bit there is just one 4-entry PDPT. * to cover system RAM. 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 the address space. 1 PDPT per 512GB of VM */ /* Number of PDPTs needed to cover system RAM. Depends on the
* 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
@ -699,6 +700,47 @@ 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)
{ {
@ -807,6 +849,12 @@ 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
* *
@ -875,6 +923,10 @@ 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
@ -886,13 +938,17 @@ 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 void page_map_set(pentry_t *ptables, void *virt, pentry_t entry_val, static int 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;
@ -910,20 +966,42 @@ static void page_map_set(pentry_t *ptables, void *virt, pentry_t entry_val,
break; break;
} }
/* We fail an assertion here due to no support for /* This is a non-leaf entry */
* splitting existing bigpage mappings. if ((*entryp & MMU_P) == 0U) {
* If the PS bit is not supported at some level (like /* Not present. Never done a mapping here yet, need
* in a PML4 entry) it is always reserved and must be 0 * some RAM for linked tables
*/ */
__ASSERT((*entryp & MMU_PS) == 0U, "large page encountered"); void *new_table;
table = next_table(*entryp, level);
__ASSERT(table != NULL, __ASSERT((options & OPTION_ALLOC) != 0,
"missing page table level %d when trying to map %p", "missing page table and allocations disabled");
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;
} }
/** /**
@ -932,6 +1010,8 @@ static void 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
@ -951,11 +1031,14 @@ static void 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 void range_map_ptables(pentry_t *ptables, void *virt, uintptr_t phys, static int 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);
@ -979,9 +1062,14 @@ static void range_map_ptables(pentry_t *ptables, void *virt, uintptr_t phys,
entry_val = (phys + offset) | entry_flags; entry_val = (phys + offset) | entry_flags;
} }
page_map_set(ptables, dest_virt, entry_val, NULL, mask, ret = page_map_set(ptables, dest_virt, entry_val, NULL, mask,
options); options);
if (ret != 0) {
return ret;
}
} }
return 0;
} }
/** /**
@ -1005,10 +1093,14 @@ static void 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 void range_map(void *virt, uintptr_t phys, size_t size, static int 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);
@ -1039,29 +1131,47 @@ static void 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);
range_map_ptables(domain->ptables, virt, phys, size, ret = range_map_ptables(domain->ptables, virt, phys, size,
entry_flags, mask, options | OPTION_USER); entry_flags, mask,
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 */
range_map_ptables(z_x86_kernel_ptables, virt, phys, size, entry_flags, ret = range_map_ptables(z_x86_kernel_ptables, virt, phys, size,
mask, options); entry_flags, 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 void range_map_unlocked(void *virt, uintptr_t phys, size_t size, static inline int 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);
range_map(virt, phys, size, entry_flags, mask, options); ret = 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)
@ -1105,10 +1215,8 @@ 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)
{ {
range_map_unlocked(virt, phys, size, flags_to_entry(flags), return range_map_unlocked(virt, phys, size, flags_to_entry(flags),
MASK_ALL, 0); MASK_ALL, OPTION_ALLOC);
return 0;
} }
#if CONFIG_X86_STACK_PROTECTION #if CONFIG_X86_STACK_PROTECTION
@ -1122,8 +1230,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.
*/ */
range_map_unlocked(stack, 0, CONFIG_MMU_PAGE_SIZE, (void)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 */
@ -1225,14 +1333,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)
{ {
range_map_unlocked((void *)start, 0, size, 0, 0, (void)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)
{ {
range_map_unlocked((void *)start, 0, size, attr, MASK_PERM, (void)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
@ -1358,44 +1466,6 @@ 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
* *
@ -1566,6 +1636,9 @@ 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,17 +296,7 @@ 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 new_child_table(self, table, virt_addr, depth): def map_page(self, virt_addr, phys_addr, flags):
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
@ -315,29 +305,18 @@ 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):
table = self.new_child_table(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)
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
if not reserve: table.map(virt_addr, phys_addr, flags)
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
@ -352,7 +331,7 @@ class PtableSet(object):
# Never map the NULL page # Never map the NULL page
continue continue
self.map_page(addr, addr, flags, False) self.map_page(addr, addr, flags)
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
@ -456,18 +435,12 @@ def main():
debug("building %s" % pclass.__name__) debug("building %s" % pclass.__name__)
vm_base = syms["CONFIG_KERNEL_VM_BASE"] # Identity-mapped Zephyr image in RAM
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("Address space: 0x%x - 0x%x size %x" % debug("Base addresses: physical 0x%x size %d" % (image_base, image_size))
(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")
@ -479,9 +452,6 @@ 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,3 +13,4 @@ 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,3 +13,4 @@ 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,6 +12,9 @@ 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
@ -25,6 +28,9 @@ 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,3 +10,4 @@ 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,3 +10,4 @@ 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,4 +8,7 @@ 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,3 +17,4 @@ 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,3 +18,4 @@ 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,6 +12,7 @@ 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,6 +12,7 @@ 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,6 +12,7 @@ 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,6 +12,7 @@ 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(256) #define DT_DRAM_SIZE DT_SIZE_K(128)
#include "qemu_x86.dts" #include "qemu_x86.dts"

View file

@ -23,5 +23,6 @@ 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,6 +11,9 @@ 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
@ -22,4 +25,7 @@ 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