^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Chen Liqin <liqin.chen@sunplusct.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Lennox Wu <lennox.wu@sunplusct.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2012 Regents of the University of California
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2017 SiFive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/sched/task_stack.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/tick.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/processor.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/csr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/switch_to.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/thread_info.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) register unsigned long gp_in_global __asm__("gp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #ifdef CONFIG_STACKPROTECTOR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/stackprotector.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) unsigned long __stack_chk_guard __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) EXPORT_SYMBOL(__stack_chk_guard);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) extern asmlinkage void ret_from_fork(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) extern asmlinkage void ret_from_kernel_thread(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) void arch_cpu_idle(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) wait_for_interrupt();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) raw_local_irq_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) void show_regs(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) show_regs_print_info(KERN_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) pr_cont("epc: " REG_FMT " ra : " REG_FMT " sp : " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) regs->epc, regs->ra, regs->sp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) pr_cont(" gp : " REG_FMT " tp : " REG_FMT " t0 : " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) regs->gp, regs->tp, regs->t0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) pr_cont(" t1 : " REG_FMT " t2 : " REG_FMT " s0 : " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) regs->t1, regs->t2, regs->s0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) pr_cont(" s1 : " REG_FMT " a0 : " REG_FMT " a1 : " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) regs->s1, regs->a0, regs->a1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) pr_cont(" a2 : " REG_FMT " a3 : " REG_FMT " a4 : " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) regs->a2, regs->a3, regs->a4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) pr_cont(" a5 : " REG_FMT " a6 : " REG_FMT " a7 : " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) regs->a5, regs->a6, regs->a7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) pr_cont(" s2 : " REG_FMT " s3 : " REG_FMT " s4 : " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) regs->s2, regs->s3, regs->s4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) pr_cont(" s5 : " REG_FMT " s6 : " REG_FMT " s7 : " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) regs->s5, regs->s6, regs->s7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) pr_cont(" s8 : " REG_FMT " s9 : " REG_FMT " s10: " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) regs->s8, regs->s9, regs->s10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) pr_cont(" s11: " REG_FMT " t3 : " REG_FMT " t4 : " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) regs->s11, regs->t3, regs->t4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) pr_cont(" t5 : " REG_FMT " t6 : " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) regs->t5, regs->t6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) pr_cont("status: " REG_FMT " badaddr: " REG_FMT " cause: " REG_FMT "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) regs->status, regs->badaddr, regs->cause);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) void start_thread(struct pt_regs *regs, unsigned long pc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) unsigned long sp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) regs->status = SR_PIE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (has_fpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) regs->status |= SR_FS_INITIAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * Restore the initial value to the FP register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * before starting the user program.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) fstate_restore(current, regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) regs->epc = pc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) regs->sp = sp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) void flush_thread(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #ifdef CONFIG_FPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * Reset FPU state and context
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * frm: round to nearest, ties to even (IEEE default)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * fflags: accrued exceptions cleared
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) fstate_off(current, task_pt_regs(current));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) memset(¤t->thread.fstate, 0, sizeof(current->thread.fstate));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) fstate_save(src, task_pt_regs(src));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) *dst = *src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct task_struct *p, unsigned long tls)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct pt_regs *childregs = task_pt_regs(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* p->thread holds context to be restored by __switch_to() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (unlikely(p->flags & PF_KTHREAD)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Kernel thread */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) memset(childregs, 0, sizeof(struct pt_regs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) childregs->gp = gp_in_global;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* Supervisor/Machine, irqs on: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) childregs->status = SR_PP | SR_PIE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) p->thread.ra = (unsigned long)ret_from_kernel_thread;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) p->thread.s[0] = usp; /* fn */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) p->thread.s[1] = arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) *childregs = *(current_pt_regs());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (usp) /* User fork */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) childregs->sp = usp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (clone_flags & CLONE_SETTLS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) childregs->tp = tls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) childregs->a0 = 0; /* Return value of fork() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) p->thread.ra = (unsigned long)ret_from_fork;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) p->thread.sp = (unsigned long)childregs; /* kernel sp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }