^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) // Copyright (C) 2005-2017 Andes Technology Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/sched/debug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/sched/task_stack.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/kallsyms.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <asm/elf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/proc-fns.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/fpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #if IS_ENABLED(CONFIG_LAZY_FPU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct task_struct *last_task_used_math;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) extern void setup_mm_for_reboot(char mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) extern inline void arch_reset(char mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) if (mode == 's') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /* Use cpu handler, jump to 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) cpu_reset(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) void (*pm_power_off) (void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) EXPORT_SYMBOL(pm_power_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static char reboot_mode_nds32 = 'h';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) int __init reboot_setup(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) reboot_mode_nds32 = str[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static int cpub_pwroff(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) __setup("reboot=", reboot_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) void machine_halt(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) cpub_pwroff();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) EXPORT_SYMBOL(machine_halt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) void machine_power_off(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (pm_power_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) pm_power_off();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) EXPORT_SYMBOL(machine_power_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) void machine_restart(char *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * Clean and disable cache, and turn off interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) cpu_proc_fin();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * Tell the mm system that we are going to reboot -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * we may need it to insert some 1:1 mappings so that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * soft boot works.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) setup_mm_for_reboot(reboot_mode_nds32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /* Execute kernel restart handler call chain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) do_kernel_restart(cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * Now call the architecture specific reboot code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) arch_reset(reboot_mode_nds32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * Whoops - the architecture was unable to reboot.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * Tell the user!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) mdelay(1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) pr_info("Reboot failed -- System halted\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) while (1) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) EXPORT_SYMBOL(machine_restart);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) void show_regs(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) printk("PC is at %pS\n", (void *)instruction_pointer(regs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) printk("LP is at %pS\n", (void *)regs->lp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) pr_info("pc : [<%08lx>] lp : [<%08lx>] %s\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) "sp : %08lx fp : %08lx gp : %08lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) instruction_pointer(regs),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) regs->lp, print_tainted(), regs->sp, regs->fp, regs->gp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) pr_info("r25: %08lx r24: %08lx\n", regs->uregs[25], regs->uregs[24]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) pr_info("r23: %08lx r22: %08lx r21: %08lx r20: %08lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) regs->uregs[23], regs->uregs[22],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) regs->uregs[21], regs->uregs[20]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) pr_info("r19: %08lx r18: %08lx r17: %08lx r16: %08lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) regs->uregs[19], regs->uregs[18],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) regs->uregs[17], regs->uregs[16]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) pr_info("r15: %08lx r14: %08lx r13: %08lx r12: %08lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) regs->uregs[15], regs->uregs[14],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) regs->uregs[13], regs->uregs[12]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) pr_info("r11: %08lx r10: %08lx r9 : %08lx r8 : %08lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) regs->uregs[11], regs->uregs[10],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) regs->uregs[9], regs->uregs[8]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) pr_info("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) regs->uregs[7], regs->uregs[6], regs->uregs[5], regs->uregs[4]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) pr_info("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) regs->uregs[3], regs->uregs[2], regs->uregs[1], regs->uregs[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) pr_info(" IRQs o%s Segment %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) interrupts_enabled(regs) ? "n" : "ff",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) uaccess_kernel() ? "kernel" : "user");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) EXPORT_SYMBOL(show_regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) void exit_thread(struct task_struct *tsk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) #if defined(CONFIG_FPU) && defined(CONFIG_LAZY_FPU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (last_task_used_math == tsk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) last_task_used_math = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) void flush_thread(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) #if defined(CONFIG_FPU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) clear_fpu(task_pt_regs(current));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) clear_used_math();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) # ifdef CONFIG_LAZY_FPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (last_task_used_math == current)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) last_task_used_math = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) # endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) DEFINE_PER_CPU(struct task_struct *, __entry_task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) int copy_thread(unsigned long clone_flags, unsigned long stack_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) unsigned long stk_sz, struct task_struct *p, unsigned long tls)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) struct pt_regs *childregs = task_pt_regs(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (unlikely(p->flags & PF_KTHREAD)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) memset(childregs, 0, sizeof(struct pt_regs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) /* kernel thread fn */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) p->thread.cpu_context.r6 = stack_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /* kernel thread argument */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) p->thread.cpu_context.r7 = stk_sz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) *childregs = *current_pt_regs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (stack_start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) childregs->sp = stack_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /* child get zero as ret. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) childregs->uregs[0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) childregs->osp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (clone_flags & CLONE_SETTLS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) childregs->uregs[25] = tls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /* cpu context switching */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) p->thread.cpu_context.sp = (unsigned long)childregs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) #if IS_ENABLED(CONFIG_FPU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (used_math()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) # if !IS_ENABLED(CONFIG_LAZY_FPU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) unlazy_fpu(current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) # else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) preempt_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (last_task_used_math == current)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) save_fpu(current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) preempt_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) # endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) p->thread.fpu = current->thread.fpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) clear_fpu(task_pt_regs(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) set_stopped_child_used_math(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) #ifdef CONFIG_HWZOL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) childregs->lb = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) childregs->le = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) childregs->lc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) #if IS_ENABLED(CONFIG_FPU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) struct task_struct *_switch_fpu(struct task_struct *prev, struct task_struct *next)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) #if !IS_ENABLED(CONFIG_LAZY_FPU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) unlazy_fpu(prev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (!(next->flags & PF_KTHREAD))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) clear_fpu(task_pt_regs(next));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return prev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * fill in the fpe structure for a core dump...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) int fpvalid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) #if IS_ENABLED(CONFIG_FPU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) struct task_struct *tsk = current;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) fpvalid = tsk_used_math(tsk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (fpvalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) lose_fpu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) memcpy(fpu, &tsk->thread.fpu, sizeof(*fpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return fpvalid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) EXPORT_SYMBOL(dump_fpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) unsigned long get_wchan(struct task_struct *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) unsigned long fp, lr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) unsigned long stack_start, stack_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (!p || p == current || p->state == TASK_RUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (IS_ENABLED(CONFIG_FRAME_POINTER)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) stack_start = (unsigned long)end_of_stack(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) stack_end = (unsigned long)task_stack_page(p) + THREAD_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) fp = thread_saved_fp(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (fp < stack_start || fp > stack_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) lr = ((unsigned long *)fp)[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (!in_sched_functions(lr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return lr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) fp = *(unsigned long *)(fp + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) } while (count++ < 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) EXPORT_SYMBOL(get_wchan);