1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
3*4882a593Smuzhiyun * Copyright (C) 2008-2009 PetaLogix
4*4882a593Smuzhiyun * Copyright (C) 2006 Atmark Techno, Inc.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
7*4882a593Smuzhiyun * License. See the file "COPYING" in the main directory of this archive
8*4882a593Smuzhiyun * for more details.
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/cpu.h>
12*4882a593Smuzhiyun #include <linux/export.h>
13*4882a593Smuzhiyun #include <linux/sched.h>
14*4882a593Smuzhiyun #include <linux/sched/debug.h>
15*4882a593Smuzhiyun #include <linux/sched/task.h>
16*4882a593Smuzhiyun #include <linux/sched/task_stack.h>
17*4882a593Smuzhiyun #include <linux/pm.h>
18*4882a593Smuzhiyun #include <linux/tick.h>
19*4882a593Smuzhiyun #include <linux/bitops.h>
20*4882a593Smuzhiyun #include <linux/ptrace.h>
21*4882a593Smuzhiyun #include <linux/uaccess.h> /* for USER_DS macros */
22*4882a593Smuzhiyun #include <asm/cacheflush.h>
23*4882a593Smuzhiyun
show_regs(struct pt_regs * regs)24*4882a593Smuzhiyun void show_regs(struct pt_regs *regs)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun show_regs_print_info(KERN_INFO);
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun pr_info(" Registers dump: mode=%X\r\n", regs->pt_mode);
29*4882a593Smuzhiyun pr_info(" r1=%08lX, r2=%08lX, r3=%08lX, r4=%08lX\n",
30*4882a593Smuzhiyun regs->r1, regs->r2, regs->r3, regs->r4);
31*4882a593Smuzhiyun pr_info(" r5=%08lX, r6=%08lX, r7=%08lX, r8=%08lX\n",
32*4882a593Smuzhiyun regs->r5, regs->r6, regs->r7, regs->r8);
33*4882a593Smuzhiyun pr_info(" r9=%08lX, r10=%08lX, r11=%08lX, r12=%08lX\n",
34*4882a593Smuzhiyun regs->r9, regs->r10, regs->r11, regs->r12);
35*4882a593Smuzhiyun pr_info(" r13=%08lX, r14=%08lX, r15=%08lX, r16=%08lX\n",
36*4882a593Smuzhiyun regs->r13, regs->r14, regs->r15, regs->r16);
37*4882a593Smuzhiyun pr_info(" r17=%08lX, r18=%08lX, r19=%08lX, r20=%08lX\n",
38*4882a593Smuzhiyun regs->r17, regs->r18, regs->r19, regs->r20);
39*4882a593Smuzhiyun pr_info(" r21=%08lX, r22=%08lX, r23=%08lX, r24=%08lX\n",
40*4882a593Smuzhiyun regs->r21, regs->r22, regs->r23, regs->r24);
41*4882a593Smuzhiyun pr_info(" r25=%08lX, r26=%08lX, r27=%08lX, r28=%08lX\n",
42*4882a593Smuzhiyun regs->r25, regs->r26, regs->r27, regs->r28);
43*4882a593Smuzhiyun pr_info(" r29=%08lX, r30=%08lX, r31=%08lX, rPC=%08lX\n",
44*4882a593Smuzhiyun regs->r29, regs->r30, regs->r31, regs->pc);
45*4882a593Smuzhiyun pr_info(" msr=%08lX, ear=%08lX, esr=%08lX, fsr=%08lX\n",
46*4882a593Smuzhiyun regs->msr, regs->ear, regs->esr, regs->fsr);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun void (*pm_power_off)(void) = NULL;
50*4882a593Smuzhiyun EXPORT_SYMBOL(pm_power_off);
51*4882a593Smuzhiyun
flush_thread(void)52*4882a593Smuzhiyun void flush_thread(void)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun
copy_thread(unsigned long clone_flags,unsigned long usp,unsigned long arg,struct task_struct * p,unsigned long tls)56*4882a593Smuzhiyun int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
57*4882a593Smuzhiyun struct task_struct *p, unsigned long tls)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun struct pt_regs *childregs = task_pt_regs(p);
60*4882a593Smuzhiyun struct thread_info *ti = task_thread_info(p);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
63*4882a593Smuzhiyun /* if we're creating a new kernel thread then just zeroing all
64*4882a593Smuzhiyun * the registers. That's OK for a brand new thread.*/
65*4882a593Smuzhiyun memset(childregs, 0, sizeof(struct pt_regs));
66*4882a593Smuzhiyun memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
67*4882a593Smuzhiyun ti->cpu_context.r1 = (unsigned long)childregs;
68*4882a593Smuzhiyun ti->cpu_context.r20 = (unsigned long)usp; /* fn */
69*4882a593Smuzhiyun ti->cpu_context.r19 = (unsigned long)arg;
70*4882a593Smuzhiyun childregs->pt_mode = 1;
71*4882a593Smuzhiyun local_save_flags(childregs->msr);
72*4882a593Smuzhiyun #ifdef CONFIG_MMU
73*4882a593Smuzhiyun ti->cpu_context.msr = childregs->msr & ~MSR_IE;
74*4882a593Smuzhiyun #endif
75*4882a593Smuzhiyun ti->cpu_context.r15 = (unsigned long)ret_from_kernel_thread - 8;
76*4882a593Smuzhiyun return 0;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun *childregs = *current_pt_regs();
79*4882a593Smuzhiyun if (usp)
80*4882a593Smuzhiyun childregs->r1 = usp;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
83*4882a593Smuzhiyun ti->cpu_context.r1 = (unsigned long)childregs;
84*4882a593Smuzhiyun #ifndef CONFIG_MMU
85*4882a593Smuzhiyun ti->cpu_context.msr = (unsigned long)childregs->msr;
86*4882a593Smuzhiyun #else
87*4882a593Smuzhiyun childregs->msr |= MSR_UMS;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /* we should consider the fact that childregs is a copy of the parent
90*4882a593Smuzhiyun * regs which were saved immediately after entering the kernel state
91*4882a593Smuzhiyun * before enabling VM. This MSR will be restored in switch_to and
92*4882a593Smuzhiyun * RETURN() and we want to have the right machine state there
93*4882a593Smuzhiyun * specifically this state must have INTs disabled before and enabled
94*4882a593Smuzhiyun * after performing rtbd
95*4882a593Smuzhiyun * compose the right MSR for RETURN(). It will work for switch_to also
96*4882a593Smuzhiyun * excepting for VM and UMS
97*4882a593Smuzhiyun * don't touch UMS , CARRY and cache bits
98*4882a593Smuzhiyun * right now MSR is a copy of parent one */
99*4882a593Smuzhiyun childregs->msr &= ~MSR_EIP;
100*4882a593Smuzhiyun childregs->msr |= MSR_IE;
101*4882a593Smuzhiyun childregs->msr &= ~MSR_VM;
102*4882a593Smuzhiyun childregs->msr |= MSR_VMS;
103*4882a593Smuzhiyun childregs->msr |= MSR_EE; /* exceptions will be enabled*/
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun ti->cpu_context.msr = (childregs->msr|MSR_VM);
106*4882a593Smuzhiyun ti->cpu_context.msr &= ~MSR_UMS; /* switch_to to kernel mode */
107*4882a593Smuzhiyun ti->cpu_context.msr &= ~MSR_IE;
108*4882a593Smuzhiyun #endif
109*4882a593Smuzhiyun ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /*
112*4882a593Smuzhiyun * r21 is the thread reg, r10 is 6th arg to clone
113*4882a593Smuzhiyun * which contains TLS area
114*4882a593Smuzhiyun */
115*4882a593Smuzhiyun if (clone_flags & CLONE_SETTLS)
116*4882a593Smuzhiyun childregs->r21 = tls;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun return 0;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
get_wchan(struct task_struct * p)121*4882a593Smuzhiyun unsigned long get_wchan(struct task_struct *p)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun /* TBD (used by procfs) */
124*4882a593Smuzhiyun return 0;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* Set up a thread for executing a new program */
start_thread(struct pt_regs * regs,unsigned long pc,unsigned long usp)128*4882a593Smuzhiyun void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun regs->pc = pc;
131*4882a593Smuzhiyun regs->r1 = usp;
132*4882a593Smuzhiyun regs->pt_mode = 0;
133*4882a593Smuzhiyun #ifdef CONFIG_MMU
134*4882a593Smuzhiyun regs->msr |= MSR_UMS;
135*4882a593Smuzhiyun regs->msr &= ~MSR_VM;
136*4882a593Smuzhiyun #endif
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun #ifdef CONFIG_MMU
140*4882a593Smuzhiyun #include <linux/elfcore.h>
141*4882a593Smuzhiyun /*
142*4882a593Smuzhiyun * Set up a thread for executing a new program
143*4882a593Smuzhiyun */
dump_fpu(struct pt_regs * regs,elf_fpregset_t * fpregs)144*4882a593Smuzhiyun int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun return 0; /* MicroBlaze has no separate FPU registers */
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun #endif /* CONFIG_MMU */
149*4882a593Smuzhiyun
arch_cpu_idle(void)150*4882a593Smuzhiyun void arch_cpu_idle(void)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun raw_local_irq_enable();
153*4882a593Smuzhiyun }
154