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:
parent
ea10c98c08
commit
b0b7756756
19 changed files with 142 additions and 222 deletions
|
@ -591,7 +591,7 @@ config KERNEL_VM_OFFSET
|
|||
|
||||
config KERNEL_VM_SIZE
|
||||
hex "Size of kernel address space in bytes"
|
||||
default 0xC0000000
|
||||
default 0x800000
|
||||
help
|
||||
Size of the kernel's address space. Constraining this helps control
|
||||
how much total memory can be used for page tables.
|
||||
|
|
|
@ -189,29 +189,6 @@ config X86_MMU
|
|||
and creates a set of page tables at boot time that is runtime-
|
||||
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
|
||||
bool "Use a single page table for all threads"
|
||||
default n
|
||||
|
@ -224,6 +201,18 @@ config X86_COMMON_PAGE_TABLE
|
|||
page tables in place. This is much slower, but uses much less RAM
|
||||
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
|
||||
bool
|
||||
help
|
||||
|
|
|
@ -195,24 +195,25 @@ static const struct paging_level paging_levels[] = {
|
|||
#define NUM_PD_ENTRIES 1024U
|
||||
#define NUM_PT_ENTRIES 1024U
|
||||
#endif /* !CONFIG_X86_64 && !CONFIG_X86_PAE */
|
||||
|
||||
/* 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)
|
||||
#ifdef CONFIG_X86_64
|
||||
#define PDPT_AREA (PD_AREA * NUM_PDPT_ENTRIES)
|
||||
#endif
|
||||
|
||||
#define VM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_sram))
|
||||
#define VM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_sram))
|
||||
#define VM_ADDR CONFIG_KERNEL_VM_BASE
|
||||
#define VM_SIZE CONFIG_KERNEL_VM_SIZE
|
||||
|
||||
/* 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_END ((uintptr_t)ROUND_UP(VM_ADDR + VM_SIZE, PT_AREA))
|
||||
|
||||
/* Number of page tables needed to cover system RAM. Depends on the specific
|
||||
* bounds of system RAM, but roughly 1 page table per 2MB of RAM
|
||||
/* Number of page tables needed to cover address space. Depends on the specific
|
||||
* bounds, but roughly 1 page table per 2MB of RAM
|
||||
*/
|
||||
#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_END ((uintptr_t)ROUND_UP(VM_ADDR + VM_SIZE, PD_AREA))
|
||||
/* Number of page directories needed to cover system RAM. Depends on the
|
||||
* specific bounds of system RAM, but roughly 1 page directory per 1GB of RAM
|
||||
/* Number of page directories needed to cover the address space. Depends on the
|
||||
* specific bounds, but roughly 1 page directory per 1GB of RAM
|
||||
*/
|
||||
#define NUM_PD ((PD_END - PD_START) / PD_AREA)
|
||||
#else
|
||||
|
@ -233,13 +234,11 @@ static const struct paging_level paging_levels[] = {
|
|||
|
||||
#ifdef CONFIG_X86_64
|
||||
/* 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_END ((uintptr_t)ROUND_UP(VM_ADDR + VM_SIZE, PDPT_AREA))
|
||||
/* Number of PDPTs needed to cover system RAM. Depends on the
|
||||
* specific bounds of system RAM, but roughly 1 PDPT per 512GB of RAM
|
||||
*/
|
||||
/* Number of PDPTs needed to cover the address space. 1 PDPT per 512GB of VM */
|
||||
#define NUM_PDPT ((PDPT_END - PDPT_START) / PDPT_AREA)
|
||||
|
||||
/* 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 */
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
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)
|
||||
|
||||
/* 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
|
||||
*
|
||||
|
@ -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
|
||||
* 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:
|
||||
* MASK_ALL - Update all PTE bits. Exitsing state totally discarded.
|
||||
* 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 mask What bits to update in the PTE (ignored if OPTION_RESET)
|
||||
* @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,
|
||||
pentry_t *old_val_ptr, pentry_t mask, uint32_t options)
|
||||
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 *table = ptables;
|
||||
bool flush = (options & OPTION_FLUSH) != 0U;
|
||||
|
||||
assert_virt_addr_aligned(virt);
|
||||
|
||||
for (int level = 0; level < NUM_LEVELS; level++) {
|
||||
int index;
|
||||
pentry_t *entryp;
|
||||
|
@ -966,42 +910,20 @@ static int page_map_set(pentry_t *ptables, void *virt, pentry_t entry_val,
|
|||
break;
|
||||
}
|
||||
|
||||
/* This is a non-leaf entry */
|
||||
if ((*entryp & MMU_P) == 0U) {
|
||||
/* Not present. Never done a mapping here yet, need
|
||||
* some RAM for linked tables
|
||||
*/
|
||||
void *new_table;
|
||||
|
||||
__ASSERT((options & OPTION_ALLOC) != 0,
|
||||
"missing page table and allocations disabled");
|
||||
|
||||
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);
|
||||
}
|
||||
/* 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);
|
||||
__ASSERT(table != NULL,
|
||||
"missing page table level %d when trying to map %p",
|
||||
level + 1, virt);
|
||||
}
|
||||
|
||||
if (flush) {
|
||||
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
|
||||
* 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
|
||||
* the same with respect to supervisor mode regardless of what thread is
|
||||
* 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
|
||||
* modified. Ignored if OPTION_RESET.
|
||||
* @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,
|
||||
size_t size, pentry_t entry_flags, pentry_t mask,
|
||||
uint32_t options)
|
||||
static void range_map_ptables(pentry_t *ptables, void *virt, uintptr_t phys,
|
||||
size_t size, pentry_t entry_flags, pentry_t mask,
|
||||
uint32_t options)
|
||||
{
|
||||
int ret;
|
||||
bool reset = (options & OPTION_RESET) != 0U;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ret = page_map_set(ptables, dest_virt, entry_val, NULL, mask,
|
||||
options);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
page_map_set(ptables, dest_virt, entry_val, NULL, mask,
|
||||
options);
|
||||
}
|
||||
|
||||
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.
|
||||
* @param options Control options. Do not set OPTION_USER here. OPTION_FLUSH
|
||||
* 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,
|
||||
pentry_t entry_flags, pentry_t mask, uint32_t options)
|
||||
static void range_map(void *virt, uintptr_t phys, size_t size,
|
||||
pentry_t entry_flags, pentry_t mask, uint32_t options)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
LOG_DBG("%s: %p -> %p (%zu) flags " PRI_ENTRY " mask "
|
||||
PRI_ENTRY " opt 0x%x", __func__, (void *)phys, virt, size,
|
||||
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 =
|
||||
CONTAINER_OF(node, struct arch_mem_domain, node);
|
||||
|
||||
ret = range_map_ptables(domain->ptables, virt, phys, size,
|
||||
entry_flags, mask,
|
||||
options | OPTION_USER);
|
||||
if (ret != 0) {
|
||||
/* NOTE: Currently we do not un-map a partially
|
||||
* completed mapping.
|
||||
*/
|
||||
goto out_unlock;
|
||||
}
|
||||
range_map_ptables(domain->ptables, virt, phys, size,
|
||||
entry_flags, mask, options | OPTION_USER);
|
||||
}
|
||||
#endif /* CONFIG_USERSPACE */
|
||||
ret = range_map_ptables(z_x86_kernel_ptables, virt, phys, size,
|
||||
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);
|
||||
}
|
||||
range_map_ptables(z_x86_kernel_ptables, virt, phys, size, entry_flags,
|
||||
mask, options);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
if ((options & OPTION_FLUSH) != 0U) {
|
||||
tlb_shootdown();
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int range_map_unlocked(void *virt, uintptr_t phys, size_t size,
|
||||
pentry_t entry_flags, pentry_t mask,
|
||||
uint32_t options)
|
||||
static inline void range_map_unlocked(void *virt, uintptr_t phys, size_t size,
|
||||
pentry_t entry_flags, pentry_t mask,
|
||||
uint32_t options)
|
||||
{
|
||||
int ret;
|
||||
k_spinlock_key_t key;
|
||||
|
||||
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);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 */
|
||||
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),
|
||||
MASK_ALL, OPTION_ALLOC);
|
||||
range_map_unlocked(virt, phys, size, flags_to_entry(flags),
|
||||
MASK_ALL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#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
|
||||
* kernel and thread stacks.
|
||||
*/
|
||||
(void)range_map_unlocked(stack, 0, CONFIG_MMU_PAGE_SIZE,
|
||||
MMU_P | ENTRY_XD, MASK_PERM, OPTION_FLUSH);
|
||||
range_map_unlocked(stack, 0, CONFIG_MMU_PAGE_SIZE,
|
||||
MMU_P | ENTRY_XD, MASK_PERM, OPTION_FLUSH);
|
||||
}
|
||||
#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)
|
||||
{
|
||||
(void)range_map_unlocked((void *)start, 0, size, 0, 0,
|
||||
OPTION_FLUSH | OPTION_RESET);
|
||||
range_map_unlocked((void *)start, 0, size, 0, 0,
|
||||
OPTION_FLUSH | OPTION_RESET);
|
||||
}
|
||||
|
||||
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,
|
||||
OPTION_FLUSH);
|
||||
range_map_unlocked((void *)start, 0, size, attr, MASK_PERM,
|
||||
OPTION_FLUSH);
|
||||
}
|
||||
|
||||
/* 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
|
||||
/* 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
|
||||
*
|
||||
|
@ -1636,9 +1566,6 @@ int arch_mem_domain_init(struct k_mem_domain *domain)
|
|||
if (ret == 0) {
|
||||
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);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -296,7 +296,17 @@ class PtableSet(object):
|
|||
some kind of leaf page table class (Pt or PtXd)"""
|
||||
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,
|
||||
with provided access flags"""
|
||||
table = self.toplevel
|
||||
|
@ -305,18 +315,29 @@ class PtableSet(object):
|
|||
for depth in range(1, len(self.levels)):
|
||||
# Create child table if needed
|
||||
if not table.has_entry(virt_addr):
|
||||
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
|
||||
table = self.new_child_table(table, virt_addr, depth)
|
||||
else:
|
||||
table = self.tables[table.lookup(virt_addr)]
|
||||
|
||||
# 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):
|
||||
"""Identity map an address range in the page tables, with provided
|
||||
|
@ -331,7 +352,7 @@ class PtableSet(object):
|
|||
# Never map the NULL page
|
||||
continue
|
||||
|
||||
self.map_page(addr, addr, flags)
|
||||
self.map_page(addr, addr, flags, False)
|
||||
|
||||
def set_region_perms(self, name, flags):
|
||||
"""Set access permissions for a named region that is already mapped
|
||||
|
@ -435,12 +456,18 @@ def main():
|
|||
|
||||
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_size = syms["z_mapped_size"]
|
||||
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")
|
||||
|
||||
|
@ -452,6 +479,9 @@ def main():
|
|||
map_flags = FLAG_P
|
||||
|
||||
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)
|
||||
|
||||
if isdef("CONFIG_X86_64"):
|
||||
|
|
|
@ -13,4 +13,3 @@ CONFIG_UART_CONSOLE=y
|
|||
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000
|
||||
CONFIG_BUILD_OUTPUT_BIN=y
|
||||
CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN=n
|
||||
CONFIG_X86_MMU_PAGE_POOL_PAGES=29
|
||||
|
|
|
@ -13,4 +13,3 @@ CONFIG_UART_CONSOLE=y
|
|||
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1900000000
|
||||
CONFIG_BUILD_OUTPUT_BIN=y
|
||||
CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN=n
|
||||
CONFIG_X86_MMU_PAGE_POOL_PAGES=29
|
||||
|
|
|
@ -12,9 +12,6 @@ config BUILD_OUTPUT_STRIPPED
|
|||
config MP_NUM_CPUS
|
||||
default 2
|
||||
|
||||
config X86_MMU_PAGE_POOL_PAGES
|
||||
default 3072 if X86_MMU
|
||||
|
||||
endif # BOARD_EHL_CRB
|
||||
|
||||
if BOARD_EHL_CRB_SBL
|
||||
|
@ -28,9 +25,6 @@ config BUILD_OUTPUT_STRIPPED
|
|||
config MP_NUM_CPUS
|
||||
default 2
|
||||
|
||||
config X86_MMU_PAGE_POOL_PAGES
|
||||
default 3072 if X86_MMU
|
||||
|
||||
config SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN
|
||||
depends on SHELL_BACKEND_SERIAL
|
||||
default n
|
||||
|
|
|
@ -10,4 +10,3 @@ CONFIG_UART_NS16550=y
|
|||
CONFIG_UART_CONSOLE=y
|
||||
CONFIG_X2APIC=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_X86_MMU_PAGE_POOL_PAGES=3092
|
||||
|
|
|
@ -10,4 +10,3 @@ CONFIG_UART_NS16550=y
|
|||
CONFIG_UART_CONSOLE=y
|
||||
CONFIG_X2APIC=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_X86_MMU_PAGE_POOL_PAGES=3092
|
||||
|
|
|
@ -8,7 +8,4 @@ config BOARD
|
|||
config BUILD_OUTPUT_STRIPPED
|
||||
default y
|
||||
|
||||
config X86_MMU_PAGE_POOL_PAGES
|
||||
default 3086 if X86_MMU
|
||||
|
||||
endif # BOARD_MINNOWBOARD
|
||||
|
|
|
@ -17,4 +17,3 @@ CONFIG_MP_NUM_CPUS=2
|
|||
CONFIG_X86_MMU=y
|
||||
CONFIG_X86_VERY_EARLY_CONSOLE=y
|
||||
CONFIG_QEMU_ICOUNT=n
|
||||
CONFIG_X86_MMU_PAGE_POOL_PAGES=23
|
||||
|
|
|
@ -18,4 +18,3 @@ CONFIG_X86_MMU=y
|
|||
CONFIG_X86_VERY_EARLY_CONSOLE=y
|
||||
CONFIG_QEMU_ICOUNT=n
|
||||
CONFIG_X86_KPTI=n
|
||||
CONFIG_X86_MMU_PAGE_POOL_PAGES=16
|
||||
|
|
|
@ -12,7 +12,6 @@ CONFIG_UART_CONSOLE=y
|
|||
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
CONFIG_X86_MMU=y
|
||||
CONFIG_X86_MMU_PAGE_POOL_PAGES=17
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_SCHED_SCALABLE=y
|
||||
CONFIG_WAITQ_SCALABLE=y
|
||||
|
|
|
@ -12,7 +12,6 @@ CONFIG_UART_CONSOLE=y
|
|||
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
CONFIG_X86_MMU=y
|
||||
CONFIG_X86_MMU_PAGE_POOL_PAGES=17
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_SCHED_SCALABLE=y
|
||||
CONFIG_WAITQ_SCALABLE=y
|
||||
|
|
|
@ -12,7 +12,6 @@ CONFIG_UART_CONSOLE=y
|
|||
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
CONFIG_X86_MMU=y
|
||||
CONFIG_X86_MMU_PAGE_POOL_PAGES=12
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_SCHED_SCALABLE=y
|
||||
CONFIG_WAITQ_SCALABLE=y
|
||||
|
|
|
@ -12,7 +12,6 @@ CONFIG_UART_CONSOLE=y
|
|||
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
CONFIG_X86_MMU=y
|
||||
CONFIG_X86_MMU_PAGE_POOL_PAGES=10
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_SCHED_SCALABLE=y
|
||||
CONFIG_WAITQ_SCALABLE=y
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
*/
|
||||
|
||||
#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"
|
||||
|
|
|
@ -23,6 +23,5 @@ CONFIG_X86_COMMON_PAGE_TABLE=y
|
|||
CONFIG_X86_KPTI=n
|
||||
CONFIG_KERNEL_VM_SIZE=0x400000
|
||||
CONFIG_KERNEL_VM_BASE=0x0
|
||||
CONFIG_X86_MMU_PAGE_POOL_PAGES=0
|
||||
CONFIG_KERNEL_VM_OFFSET=0x100000
|
||||
CONFIG_X86_KERNEL_OFFSET=0
|
|
@ -11,9 +11,6 @@ config BUILD_OUTPUT_STRIPPED
|
|||
config MP_NUM_CPUS
|
||||
default 2
|
||||
|
||||
config X86_MMU_PAGE_POOL_PAGES
|
||||
default 3092 if X86_MMU
|
||||
|
||||
endif # BOARD_UP_SQUARED
|
||||
|
||||
|
||||
|
@ -25,7 +22,4 @@ config BOARD
|
|||
config BUILD_OUTPUT_STRIPPED
|
||||
default y
|
||||
|
||||
config X86_MMU_PAGE_POOL_PAGES
|
||||
default 3086 if X86_MMU
|
||||
|
||||
endif # BOARD_UP_SQUARED_32
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue