1 /*
2  * Copyright (c) 2019 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #ifndef ZEPHYR_INCLUDE_ARCH_X86_THREAD_STACK_H
7 #define ZEPHYR_INCLUDE_ARCH_X86_THREAD_STACK_H
8 
9 #include <zephyr/arch/x86/mmustructs.h>
10 
11 #ifdef CONFIG_X86_64
12 #define ARCH_STACK_PTR_ALIGN 16UL
13 #else
14 #define ARCH_STACK_PTR_ALIGN 4UL
15 #endif
16 
17 #if defined(CONFIG_HW_STACK_PROTECTION) || defined(CONFIG_USERSPACE)
18 #define Z_X86_STACK_BASE_ALIGN	CONFIG_MMU_PAGE_SIZE
19 #else
20 #define Z_X86_STACK_BASE_ALIGN	ARCH_STACK_PTR_ALIGN
21 #endif
22 
23 #ifdef CONFIG_USERSPACE
24 /* If user mode enabled, expand any stack size to fill a page since that is
25  * the access control granularity and we don't want other kernel data to
26  * unintentionally fall in the latter part of the page
27  */
28 #define Z_X86_STACK_SIZE_ALIGN	CONFIG_MMU_PAGE_SIZE
29 #else
30 #define Z_X86_STACK_SIZE_ALIGN	ARCH_STACK_PTR_ALIGN
31 #endif
32 
33 #ifndef _ASMLANGUAGE
34 /* With both hardware stack protection and userspace enabled, stacks are
35  * arranged as follows:
36  *
37  * High memory addresses
38  * +-----------------------------------------+
39  * | Thread stack (varies)                   |
40  * +-----------------------------------------+
41  * | Privilege elevation stack               |
42  * |      (4096 bytes)                       |
43  * +-----------------------------------------+
44  * | Guard page (4096 bytes)                 |
45  * +-----------------------------------------+
46  * Low Memory addresses
47  *
48  * Privilege elevation stacks are fixed-size. All the pages containing the
49  * thread stack are marked as user-accessible. The guard page is marked
50  * read-only to catch stack overflows in supervisor mode.
51  *
52  * If a thread starts in supervisor mode, the page containing the
53  * privilege elevation stack is also marked read-only.
54  *
55  * If a thread starts in, or drops down to user mode, the privilege stack page
56  * will be marked as present, supervisor-only.
57  *
58  * If KPTI is not enabled, the _main_tss.esp0 field will always be updated
59  * updated to point to the top of the privilege elevation stack. Otherwise
60  * _main_tss.esp0 always points to the trampoline stack, which handles the
61  * page table switch to the kernel PDPT and transplants context to the
62  * privileged mode stack.
63  */
64 struct z_x86_thread_stack_header {
65 #ifdef CONFIG_HW_STACK_PROTECTION
66 	char guard_page[CONFIG_MMU_PAGE_SIZE];
67 #endif
68 #ifdef CONFIG_USERSPACE
69 	char privilege_stack[CONFIG_MMU_PAGE_SIZE];
70 #endif /* CONFIG_USERSPACE */
71 } __packed __aligned(Z_X86_STACK_BASE_ALIGN);
72 
73 #define ARCH_THREAD_STACK_OBJ_ALIGN(size)	Z_X86_STACK_BASE_ALIGN
74 
75 #define ARCH_THREAD_STACK_SIZE_ADJUST(size) \
76 	ROUND_UP((size), Z_X86_STACK_SIZE_ALIGN)
77 
78 #define ARCH_THREAD_STACK_RESERVED \
79 	sizeof(struct z_x86_thread_stack_header)
80 
81 #ifdef CONFIG_HW_STACK_PROTECTION
82 #define ARCH_KERNEL_STACK_RESERVED	CONFIG_MMU_PAGE_SIZE
83 #define ARCH_KERNEL_STACK_OBJ_ALIGN	CONFIG_MMU_PAGE_SIZE
84 #else
85 #define ARCH_KERNEL_STACK_RESERVED	0
86 #define ARCH_KERNEL_STACK_OBJ_ALIGN	ARCH_STACK_PTR_ALIGN
87 #endif
88 
89 #endif /* !_ASMLANGUAGE */
90 #endif /* ZEPHYR_INCLUDE_ARCH_X86_THREAD_STACK_H */
91