1e9564df7SGuo Ren // SPDX-License-Identifier: GPL-2.0 2e9564df7SGuo Ren // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 3e9564df7SGuo Ren 4e9564df7SGuo Ren #include <linux/module.h> 5e9564df7SGuo Ren #include <linux/version.h> 6e9564df7SGuo Ren #include <linux/sched.h> 7e9564df7SGuo Ren #include <linux/sched/task_stack.h> 8e9564df7SGuo Ren #include <linux/sched/debug.h> 9e9564df7SGuo Ren #include <linux/delay.h> 10e9564df7SGuo Ren #include <linux/kallsyms.h> 11e9564df7SGuo Ren #include <linux/uaccess.h> 12e9564df7SGuo Ren #include <linux/ptrace.h> 13e9564df7SGuo Ren 14e9564df7SGuo Ren #include <asm/elf.h> 15e9564df7SGuo Ren #include <abi/reg_ops.h> 16e9564df7SGuo Ren 17e9564df7SGuo Ren struct cpuinfo_csky cpu_data[NR_CPUS]; 18e9564df7SGuo Ren 19*2f78c73fSMao Han #ifdef CONFIG_STACKPROTECTOR 20*2f78c73fSMao Han #include <linux/stackprotector.h> 21*2f78c73fSMao Han unsigned long __stack_chk_guard __read_mostly; 22*2f78c73fSMao Han EXPORT_SYMBOL(__stack_chk_guard); 23*2f78c73fSMao Han #endif 24*2f78c73fSMao Han 25e9564df7SGuo Ren asmlinkage void ret_from_fork(void); 26e9564df7SGuo Ren asmlinkage void ret_from_kernel_thread(void); 27e9564df7SGuo Ren 28e9564df7SGuo Ren /* 29e9564df7SGuo Ren * Some archs flush debug and FPU info here 30e9564df7SGuo Ren */ 31e9564df7SGuo Ren void flush_thread(void){} 32e9564df7SGuo Ren 33e9564df7SGuo Ren /* 34e9564df7SGuo Ren * Return saved PC from a blocked thread 35e9564df7SGuo Ren */ 36e9564df7SGuo Ren unsigned long thread_saved_pc(struct task_struct *tsk) 37e9564df7SGuo Ren { 38e9564df7SGuo Ren struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; 39e9564df7SGuo Ren 40e9564df7SGuo Ren return sw->r15; 41e9564df7SGuo Ren } 42e9564df7SGuo Ren 43e9564df7SGuo Ren int copy_thread(unsigned long clone_flags, 44e9564df7SGuo Ren unsigned long usp, 45e9564df7SGuo Ren unsigned long kthread_arg, 46e9564df7SGuo Ren struct task_struct *p) 47e9564df7SGuo Ren { 48e9564df7SGuo Ren struct switch_stack *childstack; 49e9564df7SGuo Ren struct pt_regs *childregs = task_pt_regs(p); 50e9564df7SGuo Ren 51e9564df7SGuo Ren #ifdef CONFIG_CPU_HAS_FPU 52e9564df7SGuo Ren save_to_user_fp(&p->thread.user_fp); 53e9564df7SGuo Ren #endif 54e9564df7SGuo Ren 55e9564df7SGuo Ren childstack = ((struct switch_stack *) childregs) - 1; 56e9564df7SGuo Ren memset(childstack, 0, sizeof(struct switch_stack)); 57e9564df7SGuo Ren 58e9564df7SGuo Ren /* setup ksp for switch_to !!! */ 59e9564df7SGuo Ren p->thread.ksp = (unsigned long)childstack; 60e9564df7SGuo Ren 61e9564df7SGuo Ren if (unlikely(p->flags & PF_KTHREAD)) { 62e9564df7SGuo Ren memset(childregs, 0, sizeof(struct pt_regs)); 63e9564df7SGuo Ren childstack->r15 = (unsigned long) ret_from_kernel_thread; 6448ede51fSGuo Ren childstack->r10 = kthread_arg; 65e9564df7SGuo Ren childstack->r9 = usp; 66e9564df7SGuo Ren childregs->sr = mfcr("psr"); 67e9564df7SGuo Ren } else { 68e9564df7SGuo Ren *childregs = *(current_pt_regs()); 69e9564df7SGuo Ren if (usp) 70e9564df7SGuo Ren childregs->usp = usp; 71e9564df7SGuo Ren if (clone_flags & CLONE_SETTLS) 72e9564df7SGuo Ren task_thread_info(p)->tp_value = childregs->tls 73e9564df7SGuo Ren = childregs->regs[0]; 74e9564df7SGuo Ren 75e9564df7SGuo Ren childregs->a0 = 0; 76e9564df7SGuo Ren childstack->r15 = (unsigned long) ret_from_fork; 77e9564df7SGuo Ren } 78e9564df7SGuo Ren 79e9564df7SGuo Ren return 0; 80e9564df7SGuo Ren } 81e9564df7SGuo Ren 82e9564df7SGuo Ren /* Fill in the fpu structure for a core dump. */ 83e9564df7SGuo Ren int dump_fpu(struct pt_regs *regs, struct user_fp *fpu) 84e9564df7SGuo Ren { 85e9564df7SGuo Ren memcpy(fpu, ¤t->thread.user_fp, sizeof(*fpu)); 86e9564df7SGuo Ren return 1; 87e9564df7SGuo Ren } 88e9564df7SGuo Ren EXPORT_SYMBOL(dump_fpu); 89e9564df7SGuo Ren 90e9564df7SGuo Ren int dump_task_regs(struct task_struct *tsk, elf_gregset_t *pr_regs) 91e9564df7SGuo Ren { 92e9564df7SGuo Ren struct pt_regs *regs = task_pt_regs(tsk); 93e9564df7SGuo Ren 94e9564df7SGuo Ren /* NOTE: usp is error value. */ 95e9564df7SGuo Ren ELF_CORE_COPY_REGS((*pr_regs), regs) 96e9564df7SGuo Ren 97e9564df7SGuo Ren return 1; 98e9564df7SGuo Ren } 99e9564df7SGuo Ren 100e9564df7SGuo Ren unsigned long get_wchan(struct task_struct *p) 101e9564df7SGuo Ren { 1020ea2dc7cSGuo Ren unsigned long lr; 1030ea2dc7cSGuo Ren unsigned long *fp, *stack_start, *stack_end; 104e9564df7SGuo Ren int count = 0; 105e9564df7SGuo Ren 106e9564df7SGuo Ren if (!p || p == current || p->state == TASK_RUNNING) 107e9564df7SGuo Ren return 0; 108e9564df7SGuo Ren 1090ea2dc7cSGuo Ren stack_start = (unsigned long *)end_of_stack(p); 1100ea2dc7cSGuo Ren stack_end = (unsigned long *)(task_stack_page(p) + THREAD_SIZE); 1110ea2dc7cSGuo Ren 1120ea2dc7cSGuo Ren fp = (unsigned long *) thread_saved_fp(p); 113e9564df7SGuo Ren do { 1140ea2dc7cSGuo Ren if (fp < stack_start || fp > stack_end) 115e9564df7SGuo Ren return 0; 1160ea2dc7cSGuo Ren #ifdef CONFIG_STACKTRACE 1170ea2dc7cSGuo Ren lr = fp[1]; 1180ea2dc7cSGuo Ren fp = (unsigned long *)fp[0]; 1190ea2dc7cSGuo Ren #else 1200ea2dc7cSGuo Ren lr = *fp++; 1210ea2dc7cSGuo Ren #endif 1220ea2dc7cSGuo Ren if (!in_sched_functions(lr) && 1230ea2dc7cSGuo Ren __kernel_text_address(lr)) 1240ea2dc7cSGuo Ren return lr; 125e9564df7SGuo Ren } while (count++ < 16); 1260ea2dc7cSGuo Ren 127e9564df7SGuo Ren return 0; 128e9564df7SGuo Ren } 129e9564df7SGuo Ren EXPORT_SYMBOL(get_wchan); 130e9564df7SGuo Ren 131e9564df7SGuo Ren #ifndef CONFIG_CPU_PM_NONE 132e9564df7SGuo Ren void arch_cpu_idle(void) 133e9564df7SGuo Ren { 134e9564df7SGuo Ren #ifdef CONFIG_CPU_PM_WAIT 135e9564df7SGuo Ren asm volatile("wait\n"); 136e9564df7SGuo Ren #endif 137e9564df7SGuo Ren 138e9564df7SGuo Ren #ifdef CONFIG_CPU_PM_DOZE 139e9564df7SGuo Ren asm volatile("doze\n"); 140e9564df7SGuo Ren #endif 141e9564df7SGuo Ren 142e9564df7SGuo Ren #ifdef CONFIG_CPU_PM_STOP 143e9564df7SGuo Ren asm volatile("stop\n"); 144e9564df7SGuo Ren #endif 145e9564df7SGuo Ren local_irq_enable(); 146e9564df7SGuo Ren } 147e9564df7SGuo Ren #endif 148