mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-07 15:02:40 +00:00
The x86 paging code has been rewritten to support another paging mode and non-identity virtual mappings. - Paging code now uses an array of paging level characteristics and walks tables using for loops. This is opposed to having different functions for every paging level and lots of #ifdefs. The code is now more concise and adding new paging modes should be trivial. - We now support 32-bit, PAE, and IA-32e page tables. - The page tables created by gen_mmu.py are now installed at early boot. There are no longer separate "flat" page tables. These tables are mutable at any time. - The x86_mmu code now has a private header. Many definitions that did not need to be in public scope have been moved out of mmustructs.h and either placed in the C file or in the private header. - Improvements to dumping page table information, with the physical mapping and flags all shown - arch_mem_map() implemented - x86 userspace/memory domain code ported to use the new infrastructure. - add logic for physical -> virtual instruction pointer transition, including cleaning up identity mappings after this takes place. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
167 lines
5.6 KiB
C
167 lines
5.6 KiB
C
/*
|
|
* Copyright (c) 2019 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#ifndef ZEPHYR_INCLUDE_ARCH_X86_THREAD_STACK_H
|
|
#define ZEPHYR_INCLUDE_ARCH_X86_THREAD_STACK_H
|
|
|
|
#include <arch/x86/mmustructs.h>
|
|
|
|
#ifdef CONFIG_X86_64
|
|
#define ARCH_STACK_PTR_ALIGN 16UL
|
|
#else
|
|
#define ARCH_STACK_PTR_ALIGN 4UL
|
|
#endif
|
|
|
|
#ifdef CONFIG_USERSPACE
|
|
/* We need a set of page tables for each thread in the system which runs in
|
|
* user mode. For each thread, we have:
|
|
*
|
|
* - On 32-bit
|
|
* - a toplevel PD
|
|
* - On 32-bit (PAE)
|
|
* - a toplevel PDPT
|
|
* - a set of PDs for the memory range covered by system RAM
|
|
* - On 64-bit
|
|
* - a toplevel PML4
|
|
* - a set of PDPTs for the memory range covered by system RAM
|
|
* - a set of PDs for the memory range covered by system RAM
|
|
* - On all modes:
|
|
* - a set of PTs for the memory range covered by system RAM
|
|
*
|
|
* Directories and tables for memory ranges outside of system RAM will be
|
|
* shared and not thread-specific.
|
|
*
|
|
* NOTE: We are operating under the assumption that memory domain partitions
|
|
* will not be configured which grant permission to address ranges outside
|
|
* of system RAM.
|
|
*
|
|
* Each of these page tables will be programmed to reflect the memory
|
|
* permission policy for that thread, which will be the union of:
|
|
*
|
|
* - The boot time memory regions (text, rodata, and so forth)
|
|
* - The thread's stack buffer
|
|
* - Partitions in the memory domain configuration (if a member of a
|
|
* memory domain)
|
|
*
|
|
* The PDPT is fairly small singleton on x86 PAE (32 bytes) and also must
|
|
* be aligned to 32 bytes, so we place it at the highest addresses of the
|
|
* page reserved for the privilege elevation stack. On 64-bit or legacy 32-bit
|
|
* all table entities up to and including the PML4 are page-sized.
|
|
*
|
|
* The page directories and tables require page alignment so we put them as
|
|
* additional fields in the stack object, using the below macros to compute how
|
|
* many pages we need.
|
|
*/
|
|
#define Z_X86_THREAD_PT_AREA (Z_X86_NUM_TABLE_PAGES * \
|
|
(uintptr_t)CONFIG_MMU_PAGE_SIZE)
|
|
#else
|
|
#define Z_X86_THREAD_PT_AREA 0UL
|
|
#endif
|
|
|
|
#if defined(CONFIG_HW_STACK_PROTECTION) || defined(CONFIG_USERSPACE)
|
|
#define Z_X86_STACK_BASE_ALIGN CONFIG_MMU_PAGE_SIZE
|
|
#else
|
|
#define Z_X86_STACK_BASE_ALIGN ARCH_STACK_PTR_ALIGN
|
|
#endif
|
|
|
|
#ifdef CONFIG_USERSPACE
|
|
/* If user mode enabled, expand any stack size to fill a page since that is
|
|
* the access control granularity and we don't want other kernel data to
|
|
* unintentionally fall in the latter part of the page
|
|
*/
|
|
#define Z_X86_STACK_SIZE_ALIGN CONFIG_MMU_PAGE_SIZE
|
|
#else
|
|
#define Z_X86_STACK_SIZE_ALIGN ARCH_STACK_PTR_ALIGN
|
|
#endif
|
|
|
|
#ifndef _ASMLANGUAGE
|
|
|
|
#ifndef CONFIG_X86_64
|
|
struct z_x86_kernel_stack_data {
|
|
/* For 32-bit, a single four-entry page directory pointer table, that
|
|
* needs to be aligned to 32 bytes.
|
|
*
|
|
* 64-bit all the page table entities up to and including the PML4
|
|
* are page-aligned and we just reserve room for them in
|
|
* Z_X86_THREAD_PT_AREA.
|
|
*/
|
|
uint8_t ptables[0x20];
|
|
} __aligned(0x20);
|
|
#endif /* !CONFIG_X86_64 */
|
|
|
|
/* With both hardware stack protection and userspace enabled, stacks are
|
|
* arranged as follows:
|
|
*
|
|
* High memory addresses
|
|
* +-----------------------------------------+
|
|
* | Thread stack (varies) |
|
|
* +-----------------------------------------+
|
|
* | PDPT (32 bytes, 32-bit only) |
|
|
* | Privilege elevation stack |
|
|
* | (4064 or 4096 bytes) |
|
|
* +-----------------------------------------+
|
|
* | Guard page (4096 bytes) |
|
|
* +-----------------------------------------+
|
|
* | User page tables (Z_X86_THREAD_PT_AREA) |
|
|
* +-----------------------------------------+
|
|
* Low Memory addresses
|
|
*
|
|
* Privilege elevation stacks are fixed-size. All the pages containing the
|
|
* thread stack are marked as user-accessible. The guard page is marked
|
|
* read-only to catch stack overflows in supervisor mode.
|
|
*
|
|
* If a thread starts in supervisor mode, the page containing the PDPT and/or
|
|
* privilege elevation stack is also marked read-only.
|
|
*
|
|
* If a thread starts in, or drops down to user mode, the privilege stack page
|
|
* will be marked as present, supervior-only. The page tables will be
|
|
* initialized and used as the active page tables when that thread is active.
|
|
*
|
|
* If KPTI is not enabled, the _main_tss.esp0 field will always be updated
|
|
* updated to point to the top of the privilege elevation stack. Otherwise
|
|
* _main_tss.esp0 always points to the trampoline stack, which handles the
|
|
* page table switch to the kernel PDPT and transplants context to the
|
|
* privileged mode stack.
|
|
*/
|
|
struct z_x86_thread_stack_header {
|
|
#ifdef CONFIG_USERSPACE
|
|
char page_tables[Z_X86_THREAD_PT_AREA];
|
|
#endif
|
|
|
|
#ifdef CONFIG_HW_STACK_PROTECTION
|
|
char guard_page[CONFIG_MMU_PAGE_SIZE];
|
|
#endif
|
|
|
|
#ifdef CONFIG_USERSPACE
|
|
#ifdef CONFIG_X86_64
|
|
char privilege_stack[CONFIG_MMU_PAGE_SIZE];
|
|
#else
|
|
char privilege_stack[CONFIG_MMU_PAGE_SIZE -
|
|
sizeof(struct z_x86_kernel_stack_data)];
|
|
|
|
struct z_x86_kernel_stack_data kernel_data;
|
|
#endif /* CONFIG_X86_64 */
|
|
#endif /* CONFIG_USERSPACE */
|
|
} __packed __aligned(Z_X86_STACK_BASE_ALIGN);
|
|
|
|
#define ARCH_THREAD_STACK_OBJ_ALIGN(size) Z_X86_STACK_BASE_ALIGN
|
|
|
|
#define ARCH_THREAD_STACK_SIZE_ADJUST(size) \
|
|
ROUND_UP((size), Z_X86_STACK_SIZE_ALIGN)
|
|
|
|
#define ARCH_THREAD_STACK_RESERVED \
|
|
sizeof(struct z_x86_thread_stack_header)
|
|
|
|
#ifdef CONFIG_HW_STACK_PROTECTION
|
|
#define ARCH_KERNEL_STACK_RESERVED CONFIG_MMU_PAGE_SIZE
|
|
#define ARCH_KERNEL_STACK_OBJ_ALIGN CONFIG_MMU_PAGE_SIZE
|
|
#else
|
|
#define ARCH_KERNEL_STACK_RESERVED 0
|
|
#define ARCH_KERNEL_STACK_OBJ_ALIGN ARCH_STACK_PTR_ALIGN
|
|
#endif
|
|
|
|
#endif /* !_ASMLANGUAGE */
|
|
#endif /* ZEPHYR_INCLUDE_ARCH_X86_THREAD_STACK_H */
|