1 // SPDX-License-Identifier: GPL-2.0-or-later !! 1 // SPDX-License-Identifier: GPL-2.0 2 /* 2 /* 3 * Copyright (C) 2009 Sunplus Core Technology !! 3 * linux/arch/m68k/kernel/process.c 4 * Chen Liqin <liqin.chen@sunplusct.com> !! 4 * 5 * Lennox Wu <lennox.wu@sunplusct.com> !! 5 * Copyright (C) 1995 Hamish Macdonald 6 * Copyright (C) 2012 Regents of the Universit !! 6 * 7 * Copyright (C) 2017 SiFive !! 7 * 68060 fixes by Jesper Skov 8 */ 8 */ 9 9 10 #include <linux/cpu.h> !! 10 /* 11 #include <linux/kernel.h> !! 11 * This file handles the architecture-dependent parts of process handling.. >> 12 */ >> 13 >> 14 #include <linux/errno.h> >> 15 #include <linux/module.h> 12 #include <linux/sched.h> 16 #include <linux/sched.h> 13 #include <linux/sched/debug.h> 17 #include <linux/sched/debug.h> >> 18 #include <linux/sched/task.h> 14 #include <linux/sched/task_stack.h> 19 #include <linux/sched/task_stack.h> 15 #include <linux/tick.h> !! 20 #include <linux/kernel.h> >> 21 #include <linux/mm.h> >> 22 #include <linux/slab.h> >> 23 #include <linux/fs.h> >> 24 #include <linux/smp.h> >> 25 #include <linux/stddef.h> >> 26 #include <linux/unistd.h> 16 #include <linux/ptrace.h> 27 #include <linux/ptrace.h> >> 28 #include <linux/user.h> >> 29 #include <linux/reboot.h> >> 30 #include <linux/init_task.h> >> 31 #include <linux/mqueue.h> >> 32 #include <linux/rcupdate.h> >> 33 #include <linux/syscalls.h> 17 #include <linux/uaccess.h> 34 #include <linux/uaccess.h> 18 #include <linux/personality.h> !! 35 #include <linux/elfcore.h> 19 36 20 #include <asm/unistd.h> !! 37 #include <asm/traps.h> 21 #include <asm/processor.h> !! 38 #include <asm/machdep.h> 22 #include <asm/csr.h> !! 39 #include <asm/setup.h> 23 #include <asm/stacktrace.h> !! 40 24 #include <asm/string.h> !! 41 #include "process.h" 25 #include <asm/switch_to.h> << 26 #include <asm/thread_info.h> << 27 #include <asm/cpuidle.h> << 28 #include <asm/vector.h> << 29 #include <asm/cpufeature.h> << 30 #include <asm/exec.h> << 31 << 32 #if defined(CONFIG_STACKPROTECTOR) && !defined << 33 #include <linux/stackprotector.h> << 34 unsigned long __stack_chk_guard __read_mostly; << 35 EXPORT_SYMBOL(__stack_chk_guard); << 36 #endif << 37 42 38 extern asmlinkage void ret_from_fork(void); !! 43 asmlinkage void ret_from_fork(void); >> 44 asmlinkage void ret_from_kernel_thread(void); 39 45 40 void noinstr arch_cpu_idle(void) !! 46 void arch_cpu_idle(void) 41 { 47 { 42 cpu_do_idle(); !! 48 #if defined(MACH_ATARI_ONLY) >> 49 /* block out HSYNC on the atari (falcon) */ >> 50 __asm__("stop #0x2200" : : : "cc"); >> 51 #else >> 52 __asm__("stop #0x2000" : : : "cc"); >> 53 #endif 43 } 54 } 44 55 45 int set_unalign_ctl(struct task_struct *tsk, u !! 56 void machine_restart(char * __unused) 46 { 57 { 47 if (!unaligned_ctl_available()) !! 58 if (mach_reset) 48 return -EINVAL; !! 59 mach_reset(); 49 !! 60 for (;;); 50 tsk->thread.align_ctl = val; << 51 return 0; << 52 } 61 } 53 62 54 int get_unalign_ctl(struct task_struct *tsk, u !! 63 void machine_halt(void) 55 { 64 { 56 if (!unaligned_ctl_available()) !! 65 if (mach_halt) 57 return -EINVAL; !! 66 mach_halt(); 58 !! 67 for (;;); 59 return put_user(tsk->thread.align_ctl, << 60 } 68 } 61 69 62 void __show_regs(struct pt_regs *regs) !! 70 void machine_power_off(void) 63 { 71 { 64 show_regs_print_info(KERN_DEFAULT); !! 72 do_kernel_power_off(); 65 !! 73 for (;;); 66 if (!user_mode(regs)) { !! 74 } 67 pr_cont("epc : %pS\n", (void * << 68 pr_cont(" ra : %pS\n", (void * << 69 } << 70 75 71 pr_cont("epc : " REG_FMT " ra : " REG_ !! 76 void (*pm_power_off)(void); 72 regs->epc, regs->ra, regs->sp) !! 77 EXPORT_SYMBOL(pm_power_off); 73 pr_cont(" gp : " REG_FMT " tp : " REG_ << 74 regs->gp, regs->tp, regs->t0); << 75 pr_cont(" t1 : " REG_FMT " t2 : " REG_ << 76 regs->t1, regs->t2, regs->s0); << 77 pr_cont(" s1 : " REG_FMT " a0 : " REG_ << 78 regs->s1, regs->a0, regs->a1); << 79 pr_cont(" a2 : " REG_FMT " a3 : " REG_ << 80 regs->a2, regs->a3, regs->a4); << 81 pr_cont(" a5 : " REG_FMT " a6 : " REG_ << 82 regs->a5, regs->a6, regs->a7); << 83 pr_cont(" s2 : " REG_FMT " s3 : " REG_ << 84 regs->s2, regs->s3, regs->s4); << 85 pr_cont(" s5 : " REG_FMT " s6 : " REG_ << 86 regs->s5, regs->s6, regs->s7); << 87 pr_cont(" s8 : " REG_FMT " s9 : " REG_ << 88 regs->s8, regs->s9, regs->s10) << 89 pr_cont(" s11: " REG_FMT " t3 : " REG_ << 90 regs->s11, regs->t3, regs->t4) << 91 pr_cont(" t5 : " REG_FMT " t6 : " REG_ << 92 regs->t5, regs->t6); << 93 78 94 pr_cont("status: " REG_FMT " badaddr: !! 79 void show_regs(struct pt_regs * regs) 95 regs->status, regs->badaddr, r << 96 } << 97 void show_regs(struct pt_regs *regs) << 98 { 80 { 99 __show_regs(regs); !! 81 pr_info("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", 100 if (!user_mode(regs)) !! 82 regs->format, regs->vector, regs->pc, regs->sr, 101 dump_backtrace(regs, NULL, KER !! 83 print_tainted()); >> 84 pr_info("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", >> 85 regs->orig_d0, regs->d0, regs->a2, regs->a1); >> 86 pr_info("A0: %08lx D5: %08lx D4: %08lx\n", regs->a0, regs->d5, >> 87 regs->d4); >> 88 pr_info("D3: %08lx D2: %08lx D1: %08lx\n", regs->d3, regs->d2, >> 89 regs->d1); >> 90 if (!(regs->sr & PS_S)) >> 91 pr_info("USP: %08lx\n", rdusp()); 102 } 92 } 103 93 104 unsigned long arch_align_stack(unsigned long s !! 94 void flush_thread(void) 105 { 95 { 106 if (!(current->personality & ADDR_NO_R !! 96 current->thread.fc = USER_DATA; 107 sp -= get_random_u32_below(PAG !! 97 #ifdef CONFIG_FPU 108 return sp & ~0xf; !! 98 if (!FPU_IS_EMU) { >> 99 unsigned long zero = 0; >> 100 asm volatile("frestore %0": :"m" (zero)); >> 101 } >> 102 #endif 109 } 103 } 110 104 111 #ifdef CONFIG_COMPAT !! 105 /* 112 static bool compat_mode_supported __read_mostl !! 106 * Why not generic sys_clone, you ask? m68k passes all arguments on stack. 113 !! 107 * And we need all registers saved, which means a bunch of stuff pushed 114 bool compat_elf_check_arch(Elf32_Ehdr *hdr) !! 108 * on top of pt_regs, which means that sys_clone() arguments would be >> 109 * buried. We could, of course, copy them, but it's too costly for no >> 110 * good reason - generic clone() would have to copy them *again* for >> 111 * kernel_clone() anyway. So in this case it's actually better to pass pt_regs * >> 112 * and extract arguments for kernel_clone() from there. Eventually we might >> 113 * go for calling kernel_clone() directly from the wrapper, but only after we >> 114 * are finished with kernel_clone() prototype conversion. >> 115 */ >> 116 asmlinkage int m68k_clone(struct pt_regs *regs) 115 { 117 { 116 return compat_mode_supported && !! 118 /* regs will be equal to current_pt_regs() */ 117 hdr->e_machine == EM_RISCV && !! 119 struct kernel_clone_args args = { 118 hdr->e_ident[EI_CLASS] == ELFCL !! 120 .flags = (u32)(regs->d1) & ~CSIGNAL, >> 121 .pidfd = (int __user *)regs->d3, >> 122 .child_tid = (int __user *)regs->d4, >> 123 .parent_tid = (int __user *)regs->d3, >> 124 .exit_signal = regs->d1 & CSIGNAL, >> 125 .stack = regs->d2, >> 126 .tls = regs->d5, >> 127 }; >> 128 >> 129 return kernel_clone(&args); 119 } 130 } 120 131 121 static int __init compat_mode_detect(void) !! 132 /* >> 133 * Because extra registers are saved on the stack after the sys_clone3() >> 134 * arguments, this C wrapper extracts them from pt_regs * and then calls the >> 135 * generic sys_clone3() implementation. >> 136 */ >> 137 asmlinkage int m68k_clone3(struct pt_regs *regs) 122 { 138 { 123 unsigned long tmp = csr_read(CSR_STATU !! 139 return sys_clone3((struct clone_args __user *)regs->d1, regs->d2); 124 << 125 csr_write(CSR_STATUS, (tmp & ~SR_UXL) << 126 compat_mode_supported = << 127 (csr_read(CSR_STATUS) << 128 << 129 csr_write(CSR_STATUS, tmp); << 130 << 131 pr_info("riscv: ELF compat mode %s", << 132 compat_mode_supported << 133 << 134 return 0; << 135 } 140 } 136 early_initcall(compat_mode_detect); << 137 #endif << 138 141 139 void start_thread(struct pt_regs *regs, unsign !! 142 int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) 140 unsigned long sp) << 141 { 143 { 142 regs->status = SR_PIE; !! 144 unsigned long clone_flags = args->flags; 143 if (has_fpu()) { !! 145 unsigned long usp = args->stack; 144 regs->status |= SR_FS_INITIAL; !! 146 unsigned long tls = args->tls; 145 /* !! 147 struct fork_frame { 146 * Restore the initial value t !! 148 struct switch_stack sw; 147 * before starting the user pr !! 149 struct pt_regs regs; 148 */ !! 150 } *frame; 149 fstate_restore(current, regs); << 150 } << 151 regs->epc = pc; << 152 regs->sp = sp; << 153 151 154 #ifdef CONFIG_64BIT !! 152 frame = (struct fork_frame *) (task_stack_page(p) + THREAD_SIZE) - 1; 155 regs->status &= ~SR_UXL; << 156 153 157 if (is_compat_task()) !! 154 p->thread.ksp = (unsigned long)frame; 158 regs->status |= SR_UXL_32; !! 155 p->thread.esp0 = (unsigned long)&frame->regs; 159 else << 160 regs->status |= SR_UXL_64; << 161 #endif << 162 } << 163 156 164 void flush_thread(void) << 165 { << 166 #ifdef CONFIG_FPU << 167 /* 157 /* 168 * Reset FPU state and context !! 158 * Must save the current SFC/DFC value, NOT the value when 169 * frm: round to nearest, ties to !! 159 * the parent was last descheduled - RGH 10-08-96 170 * fflags: accrued exceptions cle << 171 */ 160 */ 172 fstate_off(current, task_pt_regs(curre !! 161 p->thread.fc = USER_DATA; 173 memset(¤t->thread.fstate, 0, siz << 174 #endif << 175 #ifdef CONFIG_RISCV_ISA_V << 176 /* Reset vector state */ << 177 riscv_v_vstate_ctrl_init(current); << 178 riscv_v_vstate_off(task_pt_regs(curren << 179 kfree(current->thread.vstate.datap); << 180 memset(¤t->thread.vstate, 0, siz << 181 clear_tsk_thread_flag(current, TIF_RIS << 182 #endif << 183 } << 184 162 185 void arch_release_task_struct(struct task_stru !! 163 if (unlikely(args->fn)) { 186 { !! 164 /* kernel thread */ 187 /* Free the vector context of datap. * !! 165 memset(frame, 0, sizeof(struct fork_frame)); 188 if (has_vector()) !! 166 frame->regs.sr = PS_S; 189 riscv_v_thread_free(tsk); !! 167 frame->sw.a3 = (unsigned long)args->fn; 190 } !! 168 frame->sw.d7 = (unsigned long)args->fn_arg; >> 169 frame->sw.retpc = (unsigned long)ret_from_kernel_thread; >> 170 p->thread.usp = 0; >> 171 return 0; >> 172 } >> 173 memcpy(frame, container_of(current_pt_regs(), struct fork_frame, regs), >> 174 sizeof(struct fork_frame)); >> 175 frame->regs.d0 = 0; >> 176 frame->sw.retpc = (unsigned long)ret_from_fork; >> 177 p->thread.usp = usp ?: rdusp(); 191 178 192 int arch_dup_task_struct(struct task_struct *d !! 179 if (clone_flags & CLONE_SETTLS) 193 { !! 180 task_thread_info(p)->tp_value = tls; 194 fstate_save(src, task_pt_regs(src)); !! 181 195 *dst = *src; !! 182 #ifdef CONFIG_FPU 196 /* clear entire V context, including d !! 183 if (!FPU_IS_EMU) { 197 memset(&dst->thread.vstate, 0, sizeof( !! 184 /* Copy the current fpu state */ 198 memset(&dst->thread.kernel_vstate, 0, !! 185 asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); 199 clear_tsk_thread_flag(dst, TIF_RISCV_V !! 186 >> 187 if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) { >> 188 if (CPU_IS_COLDFIRE) { >> 189 asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t" >> 190 "fmovel %/fpiar,%1\n\t" >> 191 "fmovel %/fpcr,%2\n\t" >> 192 "fmovel %/fpsr,%3" >> 193 : >> 194 : "m" (p->thread.fp[0]), >> 195 "m" (p->thread.fpcntl[0]), >> 196 "m" (p->thread.fpcntl[1]), >> 197 "m" (p->thread.fpcntl[2]) >> 198 : "memory"); >> 199 } else { >> 200 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" >> 201 "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" >> 202 : >> 203 : "m" (p->thread.fp[0]), >> 204 "m" (p->thread.fpcntl[0]) >> 205 : "memory"); >> 206 } >> 207 } >> 208 >> 209 /* Restore the state in case the fpu was busy */ >> 210 asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); >> 211 } >> 212 #endif /* CONFIG_FPU */ 200 213 201 return 0; 214 return 0; 202 } 215 } 203 216 204 int copy_thread(struct task_struct *p, const s !! 217 /* Fill in the fpu structure for a core dump. */ >> 218 int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu) 205 { 219 { 206 unsigned long clone_flags = args->flag !! 220 if (FPU_IS_EMU) { 207 unsigned long usp = args->stack; !! 221 int i; 208 unsigned long tls = args->tls; << 209 struct pt_regs *childregs = task_pt_re << 210 222 211 memset(&p->thread.s, 0, sizeof(p->thre !! 223 memcpy(fpu->fpcntl, current->thread.fpcntl, 12); >> 224 memcpy(fpu->fpregs, current->thread.fp, 96); >> 225 /* Convert internal fpu reg representation >> 226 * into long double format >> 227 */ >> 228 for (i = 0; i < 24; i += 3) >> 229 fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | >> 230 ((fpu->fpregs[i] & 0x0000ffff) << 16); >> 231 return 1; >> 232 } 212 233 213 /* p->thread holds context to be resto !! 234 if (IS_ENABLED(CONFIG_FPU)) { 214 if (unlikely(args->fn)) { !! 235 char fpustate[216]; 215 /* Kernel thread */ !! 236 216 memset(childregs, 0, sizeof(st !! 237 /* First dump the fpu context to avoid protocol violation. */ 217 /* Supervisor/Machine, irqs on !! 238 asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); 218 childregs->status = SR_PP | SR !! 239 if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) 219 !! 240 return 0; 220 p->thread.s[0] = (unsigned lon !! 241 221 p->thread.s[1] = (unsigned lon !! 242 if (CPU_IS_COLDFIRE) { 222 } else { !! 243 asm volatile ("fmovel %/fpiar,%0\n\t" 223 *childregs = *(current_pt_regs !! 244 "fmovel %/fpcr,%1\n\t" 224 /* Turn off status.VS */ !! 245 "fmovel %/fpsr,%2\n\t" 225 riscv_v_vstate_off(childregs); !! 246 "fmovemd %/fp0-%/fp7,%3" 226 if (usp) /* User fork */ !! 247 : 227 childregs->sp = usp; !! 248 : "m" (fpu->fpcntl[0]), 228 if (clone_flags & CLONE_SETTLS !! 249 "m" (fpu->fpcntl[1]), 229 childregs->tp = tls; !! 250 "m" (fpu->fpcntl[2]), 230 childregs->a0 = 0; /* Return v !! 251 "m" (fpu->fpregs[0]) 231 p->thread.s[0] = 0; !! 252 : "memory"); >> 253 } else { >> 254 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" >> 255 : >> 256 : "m" (fpu->fpcntl[0]) >> 257 : "memory"); >> 258 asm volatile ("fmovemx %/fp0-%/fp7,%0" >> 259 : >> 260 : "m" (fpu->fpregs[0]) >> 261 : "memory"); >> 262 } 232 } 263 } 233 p->thread.riscv_v_flags = 0; !! 264 234 if (has_vector()) !! 265 return 1; 235 riscv_v_thread_alloc(p); << 236 p->thread.ra = (unsigned long)ret_from << 237 p->thread.sp = (unsigned long)childreg << 238 return 0; << 239 } 266 } 240 267 241 void __init arch_task_cache_init(void) !! 268 unsigned long __get_wchan(struct task_struct *p) 242 { 269 { 243 riscv_v_setup_ctx_cache(); !! 270 unsigned long fp, pc; >> 271 unsigned long stack_page; >> 272 int count = 0; >> 273 >> 274 stack_page = (unsigned long)task_stack_page(p); >> 275 fp = ((struct switch_stack *)p->thread.ksp)->a6; >> 276 do { >> 277 if (fp < stack_page+sizeof(struct thread_info) || >> 278 fp >= 8184+stack_page) >> 279 return 0; >> 280 pc = ((unsigned long *)fp)[1]; >> 281 if (!in_sched_functions(pc)) >> 282 return pc; >> 283 fp = *(unsigned long *) fp; >> 284 } while (count++ < 16); >> 285 return 0; 244 } 286 } 245 287
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.