xref: /openbmc/linux/include/linux/sched/task_stack.h (revision f3ac6067)
168db0cf1SIngo Molnar #ifndef _LINUX_SCHED_TASK_STACK_H
268db0cf1SIngo Molnar #define _LINUX_SCHED_TASK_STACK_H
368db0cf1SIngo Molnar 
4f3ac6067SIngo Molnar /*
5f3ac6067SIngo Molnar  * task->stack (kernel stack) handling interfaces:
6f3ac6067SIngo Molnar  */
7f3ac6067SIngo Molnar 
868db0cf1SIngo Molnar #include <linux/sched.h>
950d34394SIngo Molnar #include <linux/magic.h>
1068db0cf1SIngo Molnar 
11f3ac6067SIngo Molnar #ifdef CONFIG_THREAD_INFO_IN_TASK
12f3ac6067SIngo Molnar 
13f3ac6067SIngo Molnar /*
14f3ac6067SIngo Molnar  * When accessing the stack of a non-current task that might exit, use
15f3ac6067SIngo Molnar  * try_get_task_stack() instead.  task_stack_page will return a pointer
16f3ac6067SIngo Molnar  * that could get freed out from under you.
17f3ac6067SIngo Molnar  */
18f3ac6067SIngo Molnar static inline void *task_stack_page(const struct task_struct *task)
19f3ac6067SIngo Molnar {
20f3ac6067SIngo Molnar 	return task->stack;
21f3ac6067SIngo Molnar }
22f3ac6067SIngo Molnar 
23f3ac6067SIngo Molnar #define setup_thread_stack(new,old)	do { } while(0)
24f3ac6067SIngo Molnar 
25f3ac6067SIngo Molnar static inline unsigned long *end_of_stack(const struct task_struct *task)
26f3ac6067SIngo Molnar {
27f3ac6067SIngo Molnar 	return task->stack;
28f3ac6067SIngo Molnar }
29f3ac6067SIngo Molnar 
30f3ac6067SIngo Molnar #elif !defined(__HAVE_THREAD_FUNCTIONS)
31f3ac6067SIngo Molnar 
32f3ac6067SIngo Molnar #define task_stack_page(task)	((void *)(task)->stack)
33f3ac6067SIngo Molnar 
34f3ac6067SIngo Molnar static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
35f3ac6067SIngo Molnar {
36f3ac6067SIngo Molnar 	*task_thread_info(p) = *task_thread_info(org);
37f3ac6067SIngo Molnar 	task_thread_info(p)->task = p;
38f3ac6067SIngo Molnar }
39f3ac6067SIngo Molnar 
40f3ac6067SIngo Molnar /*
41f3ac6067SIngo Molnar  * Return the address of the last usable long on the stack.
42f3ac6067SIngo Molnar  *
43f3ac6067SIngo Molnar  * When the stack grows down, this is just above the thread
44f3ac6067SIngo Molnar  * info struct. Going any lower will corrupt the threadinfo.
45f3ac6067SIngo Molnar  *
46f3ac6067SIngo Molnar  * When the stack grows up, this is the highest address.
47f3ac6067SIngo Molnar  * Beyond that position, we corrupt data on the next page.
48f3ac6067SIngo Molnar  */
49f3ac6067SIngo Molnar static inline unsigned long *end_of_stack(struct task_struct *p)
50f3ac6067SIngo Molnar {
51f3ac6067SIngo Molnar #ifdef CONFIG_STACK_GROWSUP
52f3ac6067SIngo Molnar 	return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1;
53f3ac6067SIngo Molnar #else
54f3ac6067SIngo Molnar 	return (unsigned long *)(task_thread_info(p) + 1);
55f3ac6067SIngo Molnar #endif
56f3ac6067SIngo Molnar }
57f3ac6067SIngo Molnar 
58f3ac6067SIngo Molnar #endif
59f3ac6067SIngo Molnar 
60f3ac6067SIngo Molnar #ifdef CONFIG_THREAD_INFO_IN_TASK
61f3ac6067SIngo Molnar static inline void *try_get_task_stack(struct task_struct *tsk)
62f3ac6067SIngo Molnar {
63f3ac6067SIngo Molnar 	return atomic_inc_not_zero(&tsk->stack_refcount) ?
64f3ac6067SIngo Molnar 		task_stack_page(tsk) : NULL;
65f3ac6067SIngo Molnar }
66f3ac6067SIngo Molnar 
67f3ac6067SIngo Molnar extern void put_task_stack(struct task_struct *tsk);
68f3ac6067SIngo Molnar #else
69f3ac6067SIngo Molnar static inline void *try_get_task_stack(struct task_struct *tsk)
70f3ac6067SIngo Molnar {
71f3ac6067SIngo Molnar 	return task_stack_page(tsk);
72f3ac6067SIngo Molnar }
73f3ac6067SIngo Molnar 
74f3ac6067SIngo Molnar static inline void put_task_stack(struct task_struct *tsk) {}
75f3ac6067SIngo Molnar #endif
76f3ac6067SIngo Molnar 
77f3ac6067SIngo Molnar #define task_stack_end_corrupted(task) \
78f3ac6067SIngo Molnar 		(*(end_of_stack(task)) != STACK_END_MAGIC)
79f3ac6067SIngo Molnar 
80f3ac6067SIngo Molnar static inline int object_is_on_stack(void *obj)
81f3ac6067SIngo Molnar {
82f3ac6067SIngo Molnar 	void *stack = task_stack_page(current);
83f3ac6067SIngo Molnar 
84f3ac6067SIngo Molnar 	return (obj >= stack) && (obj < (stack + THREAD_SIZE));
85f3ac6067SIngo Molnar }
86f3ac6067SIngo Molnar 
87f3ac6067SIngo Molnar extern void thread_stack_cache_init(void);
88f3ac6067SIngo Molnar 
89f3ac6067SIngo Molnar #ifdef CONFIG_DEBUG_STACK_USAGE
90f3ac6067SIngo Molnar static inline unsigned long stack_not_used(struct task_struct *p)
91f3ac6067SIngo Molnar {
92f3ac6067SIngo Molnar 	unsigned long *n = end_of_stack(p);
93f3ac6067SIngo Molnar 
94f3ac6067SIngo Molnar 	do { 	/* Skip over canary */
95f3ac6067SIngo Molnar # ifdef CONFIG_STACK_GROWSUP
96f3ac6067SIngo Molnar 		n--;
97f3ac6067SIngo Molnar # else
98f3ac6067SIngo Molnar 		n++;
99f3ac6067SIngo Molnar # endif
100f3ac6067SIngo Molnar 	} while (!*n);
101f3ac6067SIngo Molnar 
102f3ac6067SIngo Molnar # ifdef CONFIG_STACK_GROWSUP
103f3ac6067SIngo Molnar 	return (unsigned long)end_of_stack(p) - (unsigned long)n;
104f3ac6067SIngo Molnar # else
105f3ac6067SIngo Molnar 	return (unsigned long)n - (unsigned long)end_of_stack(p);
106f3ac6067SIngo Molnar # endif
107f3ac6067SIngo Molnar }
108f3ac6067SIngo Molnar #endif
109f3ac6067SIngo Molnar extern void set_task_stack_end_magic(struct task_struct *tsk);
110f3ac6067SIngo Molnar 
11168db0cf1SIngo Molnar #endif /* _LINUX_SCHED_TASK_STACK_H */
112