]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - arch/avr32/kernel/process.c
sched/headers: Prepare for new header dependencies before moving code to <linux/sched...
[mirror_ubuntu-artful-kernel.git] / arch / avr32 / kernel / process.c
CommitLineData
5f97f7f9
HS
1/*
2 * Copyright (C) 2004-2006 Atmel Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8#include <linux/sched.h>
b17b0153 9#include <linux/sched/debug.h>
5f97f7f9
HS
10#include <linux/module.h>
11#include <linux/kallsyms.h>
12#include <linux/fs.h>
b3bc2c55 13#include <linux/pm.h>
5f97f7f9 14#include <linux/ptrace.h>
5a0e3ad6 15#include <linux/slab.h>
5f97f7f9 16#include <linux/reboot.h>
d45ad062 17#include <linux/tick.h>
623b0355 18#include <linux/uaccess.h>
5f97f7f9
HS
19#include <linux/unistd.h>
20
21#include <asm/sysreg.h>
22#include <asm/ocd.h>
c80ce2d5 23#include <asm/syscalls.h>
5f97f7f9 24
3663b736 25#include <mach/pm.h>
7e59128f 26
b3bc2c55 27void (*pm_power_off)(void);
5f97f7f9
HS
28EXPORT_SYMBOL(pm_power_off);
29
30/*
31 * This file handles the architecture-dependent parts of process handling..
32 */
33
01426478 34void arch_cpu_idle(void)
5f97f7f9 35{
01426478 36 cpu_enter_idle();
5f97f7f9
HS
37}
38
39void machine_halt(void)
40{
c2eb5090
HS
41 /*
42 * Enter Stop mode. The 32 kHz oscillator will keep running so
43 * the RTC will keep the time properly and the system will
44 * boot quickly.
45 */
46 asm volatile("sleep 3\n\t"
47 "sub pc, -2");
5f97f7f9
HS
48}
49
50void machine_power_off(void)
51{
ed3fa7c9
PM
52 if (pm_power_off)
53 pm_power_off();
5f97f7f9
HS
54}
55
56void machine_restart(char *cmd)
57{
8dfe8f29
HS
58 ocd_write(DC, (1 << OCD_DC_DBE_BIT));
59 ocd_write(DC, (1 << OCD_DC_RES_BIT));
5f97f7f9
HS
60 while (1) ;
61}
62
5f97f7f9
HS
63/*
64 * Free current thread data structures etc
65 */
e6464694 66void exit_thread(struct task_struct *tsk)
5f97f7f9 67{
e6464694 68 ocd_disable(tsk);
5f97f7f9
HS
69}
70
71void flush_thread(void)
72{
73 /* nothing to do */
74}
75
76void release_thread(struct task_struct *dead_task)
77{
78 /* do nothing */
79}
80
623b0355
HS
81static void dump_mem(const char *str, const char *log_lvl,
82 unsigned long bottom, unsigned long top)
83{
84 unsigned long p;
85 int i;
86
87 printk("%s%s(0x%08lx to 0x%08lx)\n", log_lvl, str, bottom, top);
88
89 for (p = bottom & ~31; p < top; ) {
90 printk("%s%04lx: ", log_lvl, p & 0xffff);
91
92 for (i = 0; i < 8; i++, p += 4) {
93 unsigned int val;
94
95 if (p < bottom || p >= top)
96 printk(" ");
97 else {
98 if (__get_user(val, (unsigned int __user *)p)) {
99 printk("\n");
100 goto out;
101 }
102 printk("%08x ", val);
103 }
104 }
105 printk("\n");
106 }
107
108out:
109 return;
110}
111
112static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
113{
114 return (p > (unsigned long)tinfo)
115 && (p < (unsigned long)tinfo + THREAD_SIZE - 3);
116}
117
118#ifdef CONFIG_FRAME_POINTER
119static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp,
120 struct pt_regs *regs, const char *log_lvl)
121{
122 unsigned long lr, fp;
123 struct thread_info *tinfo;
124
125 if (regs)
126 fp = regs->r7;
127 else if (tsk == current)
128 asm("mov %0, r7" : "=r"(fp));
129 else
130 fp = tsk->thread.cpu_context.r7;
131
132 /*
133 * Walk the stack as long as the frame pointer (a) is within
134 * the kernel stack of the task, and (b) it doesn't move
135 * downwards.
136 */
137 tinfo = task_thread_info(tsk);
138 printk("%sCall trace:\n", log_lvl);
139 while (valid_stack_ptr(tinfo, fp)) {
140 unsigned long new_fp;
141
142 lr = *(unsigned long *)fp;
143#ifdef CONFIG_KALLSYMS
144 printk("%s [<%08lx>] ", log_lvl, lr);
145#else
146 printk(" [<%08lx>] ", lr);
147#endif
148 print_symbol("%s\n", lr);
149
150 new_fp = *(unsigned long *)(fp + 4);
151 if (new_fp <= fp)
152 break;
153 fp = new_fp;
154 }
155 printk("\n");
156}
157#else
158static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp,
159 struct pt_regs *regs, const char *log_lvl)
160{
161 unsigned long addr;
162
163 printk("%sCall trace:\n", log_lvl);
164
165 while (!kstack_end(sp)) {
166 addr = *sp++;
167 if (kernel_text_address(addr)) {
168#ifdef CONFIG_KALLSYMS
169 printk("%s [<%08lx>] ", log_lvl, addr);
170#else
171 printk(" [<%08lx>] ", addr);
172#endif
173 print_symbol("%s\n", addr);
174 }
175 }
176 printk("\n");
177}
178#endif
179
180void show_stack_log_lvl(struct task_struct *tsk, unsigned long sp,
181 struct pt_regs *regs, const char *log_lvl)
182{
183 struct thread_info *tinfo;
184
185 if (sp == 0) {
186 if (tsk)
187 sp = tsk->thread.cpu_context.ksp;
188 else
189 sp = (unsigned long)&tinfo;
190 }
191 if (!tsk)
192 tsk = current;
193
194 tinfo = task_thread_info(tsk);
195
196 if (valid_stack_ptr(tinfo, sp)) {
197 dump_mem("Stack: ", log_lvl, sp,
198 THREAD_SIZE + (unsigned long)tinfo);
199 show_trace_log_lvl(tsk, (unsigned long *)sp, regs, log_lvl);
200 }
201}
202
203void show_stack(struct task_struct *tsk, unsigned long *stack)
204{
205 show_stack_log_lvl(tsk, (unsigned long)stack, NULL, "");
206}
207
5f97f7f9
HS
208static const char *cpu_modes[] = {
209 "Application", "Supervisor", "Interrupt level 0", "Interrupt level 1",
210 "Interrupt level 2", "Interrupt level 3", "Exception", "NMI"
211};
212
623b0355 213void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl)
5f97f7f9
HS
214{
215 unsigned long sp = regs->sp;
216 unsigned long lr = regs->lr;
217 unsigned long mode = (regs->sr & MODE_MASK) >> MODE_SHIFT;
218
a43cb95d
TH
219 show_regs_print_info(log_lvl);
220
623b0355 221 if (!user_mode(regs)) {
5f97f7f9
HS
222 sp = (unsigned long)regs + FRAME_SIZE_FULL;
223
623b0355
HS
224 printk("%s", log_lvl);
225 print_symbol("PC is at %s\n", instruction_pointer(regs));
226 printk("%s", log_lvl);
227 print_symbol("LR is at %s\n", lr);
228 }
229
230 printk("%spc : [<%08lx>] lr : [<%08lx>] %s\n"
231 "%ssp : %08lx r12: %08lx r11: %08lx\n",
232 log_lvl, instruction_pointer(regs), lr, print_tainted(),
233 log_lvl, sp, regs->r12, regs->r11);
234 printk("%sr10: %08lx r9 : %08lx r8 : %08lx\n",
235 log_lvl, regs->r10, regs->r9, regs->r8);
236 printk("%sr7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
237 log_lvl, regs->r7, regs->r6, regs->r5, regs->r4);
238 printk("%sr3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
239 log_lvl, regs->r3, regs->r2, regs->r1, regs->r0);
240 printk("%sFlags: %c%c%c%c%c\n", log_lvl,
5f97f7f9
HS
241 regs->sr & SR_Q ? 'Q' : 'q',
242 regs->sr & SR_V ? 'V' : 'v',
243 regs->sr & SR_N ? 'N' : 'n',
244 regs->sr & SR_Z ? 'Z' : 'z',
245 regs->sr & SR_C ? 'C' : 'c');
df679771 246 printk("%sMode bits: %c%c%c%c%c%c%c%c%c%c\n", log_lvl,
5f97f7f9 247 regs->sr & SR_H ? 'H' : 'h',
5f97f7f9 248 regs->sr & SR_J ? 'J' : 'j',
df679771
HS
249 regs->sr & SR_DM ? 'M' : 'm',
250 regs->sr & SR_D ? 'D' : 'd',
5f97f7f9
HS
251 regs->sr & SR_EM ? 'E' : 'e',
252 regs->sr & SR_I3M ? '3' : '.',
253 regs->sr & SR_I2M ? '2' : '.',
254 regs->sr & SR_I1M ? '1' : '.',
255 regs->sr & SR_I0M ? '0' : '.',
256 regs->sr & SR_GM ? 'G' : 'g');
623b0355 257 printk("%sCPU Mode: %s\n", log_lvl, cpu_modes[mode]);
623b0355
HS
258}
259
260void show_regs(struct pt_regs *regs)
261{
262 unsigned long sp = regs->sp;
263
264 if (!user_mode(regs))
265 sp = (unsigned long)regs + FRAME_SIZE_FULL;
5f97f7f9 266
623b0355
HS
267 show_regs_log_lvl(regs, "");
268 show_trace_log_lvl(current, (unsigned long *)sp, regs, "");
5f97f7f9
HS
269}
270EXPORT_SYMBOL(show_regs);
271
272/* Fill in the fpu structure for a core dump. This is easy -- we don't have any */
273int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
274{
275 /* Not valid */
276 return 0;
277}
278
279asmlinkage void ret_from_fork(void);
5adc807f
AV
280asmlinkage void ret_from_kernel_thread(void);
281asmlinkage void syscall_return(void);
5f97f7f9 282
6f2c55b8 283int copy_thread(unsigned long clone_flags, unsigned long usp,
5adc807f 284 unsigned long arg,
afa86fc4 285 struct task_struct *p)
5f97f7f9 286{
5adc807f
AV
287 struct pt_regs *childregs = task_pt_regs(p);
288
584271bc 289 if (unlikely(p->flags & PF_KTHREAD)) {
5adc807f
AV
290 memset(childregs, 0, sizeof(struct pt_regs));
291 p->thread.cpu_context.r0 = arg;
292 p->thread.cpu_context.r1 = usp; /* fn */
395e73a2 293 p->thread.cpu_context.r2 = (unsigned long)syscall_return;
5adc807f
AV
294 p->thread.cpu_context.pc = (unsigned long)ret_from_kernel_thread;
295 childregs->sr = MODE_SUPERVISOR;
296 } else {
584271bc
AV
297 *childregs = *current_pt_regs();
298 if (usp)
299 childregs->sp = usp;
5adc807f
AV
300 childregs->r12 = 0; /* Set return value for child */
301 p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
302 }
5f97f7f9
HS
303
304 p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM;
305 p->thread.cpu_context.ksp = (unsigned long)childregs;
5f97f7f9 306
325d6f55 307 clear_tsk_thread_flag(p, TIF_DEBUG);
13b54a50
HS
308 if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))
309 ocd_enable(p);
310
5f97f7f9
HS
311 return 0;
312}
313
5f97f7f9
HS
314/*
315 * This function is supposed to answer the question "who called
316 * schedule()?"
317 */
318unsigned long get_wchan(struct task_struct *p)
319{
320 unsigned long pc;
321 unsigned long stack_page;
322
323 if (!p || p == current || p->state == TASK_RUNNING)
324 return 0;
325
c9f4f06d 326 stack_page = (unsigned long)task_stack_page(p);
5f97f7f9
HS
327 BUG_ON(!stack_page);
328
329 /*
330 * The stored value of PC is either the address right after
331 * the call to __switch_to() or ret_from_fork.
332 */
333 pc = thread_saved_pc(p);
334 if (in_sched_functions(pc)) {
335#ifdef CONFIG_FRAME_POINTER
336 unsigned long fp = p->thread.cpu_context.r7;
337 BUG_ON(fp < stack_page || fp > (THREAD_SIZE + stack_page));
338 pc = *(unsigned long *)fp;
339#else
340 /*
341 * We depend on the frame size of schedule here, which
342 * is actually quite ugly. It might be possible to
343 * determine the frame size automatically at build
344 * time by doing this:
0a0fca9d 345 * - compile sched/core.c
5f97f7f9
HS
346 * - disassemble the resulting sched.o
347 * - look for 'sub sp,??' shortly after '<schedule>:'
348 */
349 unsigned long sp = p->thread.cpu_context.ksp + 16;
350 BUG_ON(sp < stack_page || sp > (THREAD_SIZE + stack_page));
351 pc = *(unsigned long *)sp;
352#endif
353 }
354
355 return pc;
356}