18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _LINUX_SCHED_TASK_STACK_H 38c2ecf20Sopenharmony_ci#define _LINUX_SCHED_TASK_STACK_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci/* 68c2ecf20Sopenharmony_ci * task->stack (kernel stack) handling interfaces: 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/sched.h> 108c2ecf20Sopenharmony_ci#include <linux/magic.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#ifdef CONFIG_THREAD_INFO_IN_TASK 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * When accessing the stack of a non-current task that might exit, use 168c2ecf20Sopenharmony_ci * try_get_task_stack() instead. task_stack_page will return a pointer 178c2ecf20Sopenharmony_ci * that could get freed out from under you. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_cistatic inline void *task_stack_page(const struct task_struct *task) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci return task->stack; 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define setup_thread_stack(new,old) do { } while(0) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic __always_inline unsigned long *end_of_stack(const struct task_struct *task) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci#ifdef CONFIG_STACK_GROWSUP 298c2ecf20Sopenharmony_ci return (unsigned long *)((unsigned long)task->stack + THREAD_SIZE) - 1; 308c2ecf20Sopenharmony_ci#else 318c2ecf20Sopenharmony_ci return task->stack; 328c2ecf20Sopenharmony_ci#endif 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#elif !defined(__HAVE_THREAD_FUNCTIONS) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define task_stack_page(task) ((void *)(task)->stack) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic inline void setup_thread_stack(struct task_struct *p, struct task_struct *org) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci *task_thread_info(p) = *task_thread_info(org); 428c2ecf20Sopenharmony_ci task_thread_info(p)->task = p; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * Return the address of the last usable long on the stack. 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * When the stack grows down, this is just above the thread 498c2ecf20Sopenharmony_ci * info struct. Going any lower will corrupt the threadinfo. 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * When the stack grows up, this is the highest address. 528c2ecf20Sopenharmony_ci * Beyond that position, we corrupt data on the next page. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_cistatic inline unsigned long *end_of_stack(struct task_struct *p) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci#ifdef CONFIG_STACK_GROWSUP 578c2ecf20Sopenharmony_ci return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1; 588c2ecf20Sopenharmony_ci#else 598c2ecf20Sopenharmony_ci return (unsigned long *)(task_thread_info(p) + 1); 608c2ecf20Sopenharmony_ci#endif 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#endif 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#ifdef CONFIG_THREAD_INFO_IN_TASK 668c2ecf20Sopenharmony_cistatic inline void *try_get_task_stack(struct task_struct *tsk) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci return refcount_inc_not_zero(&tsk->stack_refcount) ? 698c2ecf20Sopenharmony_ci task_stack_page(tsk) : NULL; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ciextern void put_task_stack(struct task_struct *tsk); 738c2ecf20Sopenharmony_ci#else 748c2ecf20Sopenharmony_cistatic inline void *try_get_task_stack(struct task_struct *tsk) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci return task_stack_page(tsk); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic inline void put_task_stack(struct task_struct *tsk) {} 808c2ecf20Sopenharmony_ci#endif 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define task_stack_end_corrupted(task) \ 838c2ecf20Sopenharmony_ci (*(end_of_stack(task)) != STACK_END_MAGIC) 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic inline int object_is_on_stack(const void *obj) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci void *stack = task_stack_page(current); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return (obj >= stack) && (obj < (stack + THREAD_SIZE)); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ciextern void thread_stack_cache_init(void); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_STACK_USAGE 958c2ecf20Sopenharmony_cistatic inline unsigned long stack_not_used(struct task_struct *p) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci unsigned long *n = end_of_stack(p); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci do { /* Skip over canary */ 1008c2ecf20Sopenharmony_ci# ifdef CONFIG_STACK_GROWSUP 1018c2ecf20Sopenharmony_ci n--; 1028c2ecf20Sopenharmony_ci# else 1038c2ecf20Sopenharmony_ci n++; 1048c2ecf20Sopenharmony_ci# endif 1058c2ecf20Sopenharmony_ci } while (!*n); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci# ifdef CONFIG_STACK_GROWSUP 1088c2ecf20Sopenharmony_ci return (unsigned long)end_of_stack(p) - (unsigned long)n; 1098c2ecf20Sopenharmony_ci# else 1108c2ecf20Sopenharmony_ci return (unsigned long)n - (unsigned long)end_of_stack(p); 1118c2ecf20Sopenharmony_ci# endif 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci#endif 1148c2ecf20Sopenharmony_ciextern void set_task_stack_end_magic(struct task_struct *tsk); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_KSTACK_END 1178c2ecf20Sopenharmony_cistatic inline int kstack_end(void *addr) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci /* Reliable end of stack detection: 1208c2ecf20Sopenharmony_ci * Some APM bios versions misalign the stack 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci return !(((unsigned long)addr+sizeof(void*)-1) & (THREAD_SIZE-sizeof(void*))); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci#endif 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci#endif /* _LINUX_SCHED_TASK_STACK_H */ 127