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_X86_STACK_PROTECTION) || defined(CONFIG_USERSPACE) \
18 	|| defined(CONFIG_THREAD_STACK_MEM_MAPPED)
19 #define Z_X86_STACK_BASE_ALIGN	CONFIG_MMU_PAGE_SIZE
20 #else
21 #define Z_X86_STACK_BASE_ALIGN	ARCH_STACK_PTR_ALIGN
22 #endif
23 
24 #if defined(CONFIG_USERSPACE) || defined(CONFIG_THREAD_STACK_MEM_MAPPED)
25 /* If user mode enabled, expand any stack size to fill a page since that is
26  * the access control granularity and we don't want other kernel data to
27  * unintentionally fall in the latter part of the page
28  *
29  * This is also true when memory mapped stacks are used with since
30  * access control applies to one page at a time.
31  */
32 #define Z_X86_STACK_SIZE_ALIGN	CONFIG_MMU_PAGE_SIZE
33 #else
34 #define Z_X86_STACK_SIZE_ALIGN	ARCH_STACK_PTR_ALIGN
35 #endif
36 
37 #ifndef _ASMLANGUAGE
38 /* With both hardware stack protection and userspace enabled, stacks are
39  * arranged as follows:
40  *
41  * --- Without stack being memory mapped:
42  * High memory addresses
43  * +-----------------------------------------+
44  * | Thread stack (varies)                   |
45  * +-----------------------------------------+
46  * | Privilege elevation stack               |
47  * |   (CONFIG_PRIVILEGED_STACK_SIZE)        |
48  * +-----------------------------------------+
49  * | Guard page (4096 bytes)                 |
50  * |   - 'guard_page' in struct              |
51  * |     z_x86_thread_stack_header           |
52  * +-----------------------------------------+
53  * Low Memory addresses
54  *
55  * --- With stack being memory mapped:
56  * High memory addresses
57  * +-----------------------------------------+
58  * | Guard page (empty page)                 |
59  * +-----------------------------------------+
60  * | Thread stack (varies)                   |
61  * +-----------------------------------------+
62  * | Privilege elevation stack               |
63  * |   (CONFIG_PRIVILEGED_STACK_SIZE)        |
64  * +-----------------------------------------+
65  * | Guard page (empty page)                 |
66  * +-----------------------------------------+
67  * Low Memory addresses
68  *
69  * Without memory mapped stacks, the guard page is actually allocated
70  * as part of the stack struct, which takes up physical memory during
71  * linking.
72  *
73  * Privilege elevation stacks are fixed-size. All the pages containing the
74  * thread stack are marked as user-accessible. The guard page is marked
75  * read-only to catch stack overflows in supervisor mode.
76  *
77  * If a thread starts in supervisor mode, the page containing the
78  * privilege elevation stack is also marked read-only.
79  *
80  * If a thread starts in, or drops down to user mode, the privilege stack page
81  * will be marked as present, supervisor-only.
82  *
83  * If KPTI is not enabled, the _main_tss.esp0 field will always be updated
84  * updated to point to the top of the privilege elevation stack. Otherwise
85  * _main_tss.esp0 always points to the trampoline stack, which handles the
86  * page table switch to the kernel PDPT and transplants context to the
87  * privileged mode stack.
88  */
89 struct z_x86_thread_stack_header {
90 #if defined(CONFIG_X86_STACK_PROTECTION) && !defined(CONFIG_THREAD_STACK_MEM_MAPPED)
91 	char guard_page[CONFIG_MMU_PAGE_SIZE];
92 #endif
93 #ifdef CONFIG_USERSPACE
94 	char privilege_stack[CONFIG_PRIVILEGED_STACK_SIZE];
95 #endif /* CONFIG_USERSPACE */
96 } __packed __aligned(Z_X86_STACK_BASE_ALIGN);
97 
98 #define ARCH_THREAD_STACK_OBJ_ALIGN(size)	Z_X86_STACK_BASE_ALIGN
99 
100 #define ARCH_THREAD_STACK_SIZE_ADJUST(size) \
101 	ROUND_UP((size), Z_X86_STACK_SIZE_ALIGN)
102 
103 #define ARCH_THREAD_STACK_RESERVED \
104 	sizeof(struct z_x86_thread_stack_header)
105 
106 #ifdef CONFIG_X86_STACK_PROTECTION
107 #define ARCH_KERNEL_STACK_RESERVED	CONFIG_MMU_PAGE_SIZE
108 #define ARCH_KERNEL_STACK_OBJ_ALIGN	CONFIG_MMU_PAGE_SIZE
109 #else
110 #define ARCH_KERNEL_STACK_RESERVED	0
111 #define ARCH_KERNEL_STACK_OBJ_ALIGN	ARCH_STACK_PTR_ALIGN
112 #endif
113 
114 #endif /* !_ASMLANGUAGE */
115 #endif /* ZEPHYR_INCLUDE_ARCH_X86_THREAD_STACK_H */
116