x86: abstract toplevel page table pointer

This patch is a preparatory step in enabling the MMU in
long mode; no steps are taken to implement long mode support.

We introduce struct x86_page_tables, which represents the
top-level data structure for page tables:

- For 32-bit, this will contain a four-entry page directory
  pointer table (PDPT)
- For 64-bit, this will (eventually) contain a page map level 4
  table (PML4)

In either case, this pointer value is what gets programmed into
CR3 to activate a set of page tables. There are extra bits in
CR3 to set for long mode, we'll get around to that later.

This abstraction will allow us to use the same APIs that work
with page tables in either mode, rather than hard-coding that
the top level data structure is a PDPT.

z_x86_mmu_validate() has been re-written to make it easier to
add another level of paging for long mode, to support 2MB
PDPT entries, and correctly validate regions which span PDPTE
entries.

Some MMU-related APIs moved out of 32-bit x86's arch.h into
mmustructs.h.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2019-10-01 13:42:35 -07:00 committed by Andrew Boie
commit f0ddbd7eee
11 changed files with 309 additions and 267 deletions

View file

@ -486,7 +486,10 @@ extern struct task_state_segment _main_tss;
#endif
struct z_x86_kernel_stack_data {
struct x86_mmu_pdpt pdpt;
/* For 32-bit, a single four-entry page directory pointer table, that
* needs to be aligned to 32 bytes.
*/
struct x86_page_tables ptables;
} __aligned(0x20);
/* With both hardware stack protection and userspace enabled, stacks are
@ -582,64 +585,6 @@ struct z_x86_thread_stack_header {
} while (false)
#endif
#ifdef CONFIG_X86_MMU
/* Kernel's page table. Always active when threads are running in supervisor
* mode, or handling an interrupt.
*
* If KPTI is not enabled, this is used as a template to create per-thread
* page tables for when threads run in user mode.
*/
extern struct x86_mmu_pdpt z_x86_kernel_pdpt;
#ifdef CONFIG_X86_KPTI
/* Separate page tables for user mode threads. The top-level PDPT is never
* installed into the CPU; instead used as a template for creating per-thread
* page tables.
*/
extern struct x86_mmu_pdpt z_x86_user_pdpt;
#define USER_PDPT z_x86_user_pdpt
#else
#define USER_PDPT z_x86_kernel_pdpt
#endif
/**
* @brief Fetch page table flags for a particular page
*
* Given a memory address, return the flags for the containing page's
* PDE and PTE entries. Intended for debugging.
*
* @param pdpt Which page table to use
* @param addr Memory address to example
* @param pde_flags Output parameter for page directory entry flags
* @param pte_flags Output parameter for page table entry flags
*/
void z_x86_mmu_get_flags(struct x86_mmu_pdpt *pdpt, void *addr,
x86_page_entry_data_t *pde_flags,
x86_page_entry_data_t *pte_flags);
/**
* @brief set flags in the MMU page tables
*
* Modify bits in the existing page tables for a particular memory
* range, which must be page-aligned
*
* @param pdpt Which page table to use
* @param ptr Starting memory address which must be page-aligned
* @param size Size of the region, must be page size multiple
* @param flags Value of bits to set in the page table entries
* @param mask Mask indicating which particular bits in the page table entries to
* modify
* @param flush Whether to flush the TLB for the modified pages, only needed
* when modifying the active page tables
*/
void z_x86_mmu_set_flags(struct x86_mmu_pdpt *pdpt, void *ptr,
size_t size,
x86_page_entry_data_t flags,
x86_page_entry_data_t mask, bool flush);
int z_x86_mmu_validate(struct x86_mmu_pdpt *pdpt, void *addr, size_t size,
int write);
#endif /* CONFIG_X86_MMU */
#ifdef __cplusplus
}
#endif