1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _LINUX_SCHED_TASK_STACK_H |
3 | #define _LINUX_SCHED_TASK_STACK_H |
4 | |
5 | /* |
6 | * task->stack (kernel stack) handling interfaces: |
7 | */ |
8 | |
9 | #include <linux/sched.h> |
10 | #include <linux/magic.h> |
11 | |
12 | #ifdef CONFIG_THREAD_INFO_IN_TASK |
13 | |
14 | /* |
15 | * When accessing the stack of a non-current task that might exit, use |
16 | * try_get_task_stack() instead. task_stack_page will return a pointer |
17 | * that could get freed out from under you. |
18 | */ |
19 | static __always_inline void *task_stack_page(const struct task_struct *task) |
20 | { |
21 | return task->stack; |
22 | } |
23 | |
24 | #define setup_thread_stack(new,old) do { } while(0) |
25 | |
26 | static __always_inline unsigned long *end_of_stack(const struct task_struct *task) |
27 | { |
28 | #ifdef CONFIG_STACK_GROWSUP |
29 | return (unsigned long *)((unsigned long)task->stack + THREAD_SIZE) - 1; |
30 | #else |
31 | return task->stack; |
32 | #endif |
33 | } |
34 | |
35 | #elif !defined(__HAVE_THREAD_FUNCTIONS) |
36 | |
37 | #define task_stack_page(task) ((void *)(task)->stack) |
38 | |
39 | static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org) |
40 | { |
41 | *task_thread_info(p) = *task_thread_info(org); |
42 | task_thread_info(p)->task = p; |
43 | } |
44 | |
45 | /* |
46 | * Return the address of the last usable long on the stack. |
47 | * |
48 | * When the stack grows down, this is just above the thread |
49 | * info struct. Going any lower will corrupt the threadinfo. |
50 | * |
51 | * When the stack grows up, this is the highest address. |
52 | * Beyond that position, we corrupt data on the next page. |
53 | */ |
54 | static inline unsigned long *end_of_stack(struct task_struct *p) |
55 | { |
56 | #ifdef CONFIG_STACK_GROWSUP |
57 | return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1; |
58 | #else |
59 | return (unsigned long *)(task_thread_info(p) + 1); |
60 | #endif |
61 | } |
62 | |
63 | #endif |
64 | |
65 | #ifdef CONFIG_THREAD_INFO_IN_TASK |
66 | static inline void *try_get_task_stack(struct task_struct *tsk) |
67 | { |
68 | return refcount_inc_not_zero(r: &tsk->stack_refcount) ? |
69 | task_stack_page(task: tsk) : NULL; |
70 | } |
71 | |
72 | extern void put_task_stack(struct task_struct *tsk); |
73 | #else |
74 | static inline void *try_get_task_stack(struct task_struct *tsk) |
75 | { |
76 | return task_stack_page(tsk); |
77 | } |
78 | |
79 | static inline void put_task_stack(struct task_struct *tsk) {} |
80 | #endif |
81 | |
82 | void exit_task_stack_account(struct task_struct *tsk); |
83 | |
84 | #define task_stack_end_corrupted(task) \ |
85 | (*(end_of_stack(task)) != STACK_END_MAGIC) |
86 | |
87 | static inline int object_is_on_stack(const void *obj) |
88 | { |
89 | void *stack = task_stack_page(current); |
90 | |
91 | return (obj >= stack) && (obj < (stack + THREAD_SIZE)); |
92 | } |
93 | |
94 | extern void thread_stack_cache_init(void); |
95 | |
96 | #ifdef CONFIG_DEBUG_STACK_USAGE |
97 | static inline unsigned long stack_not_used(struct task_struct *p) |
98 | { |
99 | unsigned long *n = end_of_stack(task: p); |
100 | |
101 | do { /* Skip over canary */ |
102 | # ifdef CONFIG_STACK_GROWSUP |
103 | n--; |
104 | # else |
105 | n++; |
106 | # endif |
107 | } while (!*n); |
108 | |
109 | # ifdef CONFIG_STACK_GROWSUP |
110 | return (unsigned long)end_of_stack(p) - (unsigned long)n; |
111 | # else |
112 | return (unsigned long)n - (unsigned long)end_of_stack(task: p); |
113 | # endif |
114 | } |
115 | #endif |
116 | extern void set_task_stack_end_magic(struct task_struct *tsk); |
117 | |
118 | #ifndef __HAVE_ARCH_KSTACK_END |
119 | static inline int kstack_end(void *addr) |
120 | { |
121 | /* Reliable end of stack detection: |
122 | * Some APM bios versions misalign the stack |
123 | */ |
124 | return !(((unsigned long)addr+sizeof(void*)-1) & (THREAD_SIZE-sizeof(void*))); |
125 | } |
126 | #endif |
127 | |
128 | #endif /* _LINUX_SCHED_TASK_STACK_H */ |
129 | |