diff options
Diffstat (limited to 'arch/sh/kernel/process.c')
-rw-r--r-- | arch/sh/kernel/process.c | 95 |
1 files changed, 52 insertions, 43 deletions
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 486c06e18033..9d6a438b3eaf 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c | |||
@@ -1,42 +1,30 @@ | |||
1 | /* $Id: process.c,v 1.28 2004/05/05 16:54:23 lethal Exp $ | 1 | /* |
2 | * arch/sh/kernel/process.c | ||
2 | * | 3 | * |
3 | * linux/arch/sh/kernel/process.c | 4 | * This file handles the architecture-dependent parts of process handling.. |
4 | * | 5 | * |
5 | * Copyright (C) 1995 Linus Torvalds | 6 | * Copyright (C) 1995 Linus Torvalds |
6 | * | 7 | * |
7 | * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima | 8 | * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima |
8 | * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC | 9 | * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC |
10 | * Copyright (C) 2002 - 2006 Paul Mundt | ||
9 | */ | 11 | */ |
10 | |||
11 | /* | ||
12 | * This file handles the architecture-dependent parts of process handling.. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | 12 | #include <linux/module.h> |
16 | #include <linux/unistd.h> | ||
17 | #include <linux/mm.h> | 13 | #include <linux/mm.h> |
18 | #include <linux/elfcore.h> | 14 | #include <linux/elfcore.h> |
19 | #include <linux/a.out.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/pm.h> | 15 | #include <linux/pm.h> |
22 | #include <linux/ptrace.h> | ||
23 | #include <linux/kallsyms.h> | 16 | #include <linux/kallsyms.h> |
24 | #include <linux/kexec.h> | 17 | #include <linux/kexec.h> |
25 | |||
26 | #include <asm/io.h> | ||
27 | #include <asm/uaccess.h> | 18 | #include <asm/uaccess.h> |
28 | #include <asm/mmu_context.h> | 19 | #include <asm/mmu_context.h> |
29 | #include <asm/elf.h> | ||
30 | #include <asm/ubc.h> | 20 | #include <asm/ubc.h> |
31 | 21 | ||
32 | static int hlt_counter=0; | 22 | static int hlt_counter; |
33 | |||
34 | int ubc_usercnt = 0; | 23 | int ubc_usercnt = 0; |
35 | 24 | ||
36 | #define HARD_IDLE_TIMEOUT (HZ / 3) | 25 | #define HARD_IDLE_TIMEOUT (HZ / 3) |
37 | 26 | ||
38 | void (*pm_idle)(void); | 27 | void (*pm_idle)(void); |
39 | |||
40 | void (*pm_power_off)(void); | 28 | void (*pm_power_off)(void); |
41 | EXPORT_SYMBOL(pm_power_off); | 29 | EXPORT_SYMBOL(pm_power_off); |
42 | 30 | ||
@@ -44,14 +32,12 @@ void disable_hlt(void) | |||
44 | { | 32 | { |
45 | hlt_counter++; | 33 | hlt_counter++; |
46 | } | 34 | } |
47 | |||
48 | EXPORT_SYMBOL(disable_hlt); | 35 | EXPORT_SYMBOL(disable_hlt); |
49 | 36 | ||
50 | void enable_hlt(void) | 37 | void enable_hlt(void) |
51 | { | 38 | { |
52 | hlt_counter--; | 39 | hlt_counter--; |
53 | } | 40 | } |
54 | |||
55 | EXPORT_SYMBOL(enable_hlt); | 41 | EXPORT_SYMBOL(enable_hlt); |
56 | 42 | ||
57 | void default_idle(void) | 43 | void default_idle(void) |
@@ -152,19 +138,21 @@ __asm__(".align 5\n" | |||
152 | ".align 2\n\t" | 138 | ".align 2\n\t" |
153 | "1:.long do_exit"); | 139 | "1:.long do_exit"); |
154 | 140 | ||
141 | /* Don't use this in BL=1(cli). Or else, CPU resets! */ | ||
155 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | 142 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) |
156 | { /* Don't use this in BL=1(cli). Or else, CPU resets! */ | 143 | { |
157 | struct pt_regs regs; | 144 | struct pt_regs regs; |
158 | 145 | ||
159 | memset(®s, 0, sizeof(regs)); | 146 | memset(®s, 0, sizeof(regs)); |
160 | regs.regs[4] = (unsigned long) arg; | 147 | regs.regs[4] = (unsigned long)arg; |
161 | regs.regs[5] = (unsigned long) fn; | 148 | regs.regs[5] = (unsigned long)fn; |
162 | 149 | ||
163 | regs.pc = (unsigned long) kernel_thread_helper; | 150 | regs.pc = (unsigned long)kernel_thread_helper; |
164 | regs.sr = (1 << 30); | 151 | regs.sr = (1 << 30); |
165 | 152 | ||
166 | /* Ok, create the new process.. */ | 153 | /* Ok, create the new process.. */ |
167 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | 154 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, |
155 | ®s, 0, NULL, NULL); | ||
168 | } | 156 | } |
169 | 157 | ||
170 | /* | 158 | /* |
@@ -211,21 +199,20 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
211 | return fpvalid; | 199 | return fpvalid; |
212 | } | 200 | } |
213 | 201 | ||
214 | /* | 202 | /* |
215 | * Capture the user space registers if the task is not running (in user space) | 203 | * Capture the user space registers if the task is not running (in user space) |
216 | */ | 204 | */ |
217 | int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) | 205 | int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) |
218 | { | 206 | { |
219 | struct pt_regs ptregs; | 207 | struct pt_regs ptregs; |
220 | 208 | ||
221 | ptregs = *task_pt_regs(tsk); | 209 | ptregs = *task_pt_regs(tsk); |
222 | elf_core_copy_regs(regs, &ptregs); | 210 | elf_core_copy_regs(regs, &ptregs); |
223 | 211 | ||
224 | return 1; | 212 | return 1; |
225 | } | 213 | } |
226 | 214 | ||
227 | int | 215 | int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpu) |
228 | dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *fpu) | ||
229 | { | 216 | { |
230 | int fpvalid = 0; | 217 | int fpvalid = 0; |
231 | 218 | ||
@@ -263,12 +250,14 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, | |||
263 | childregs->regs[15] = usp; | 250 | childregs->regs[15] = usp; |
264 | ti->addr_limit = USER_DS; | 251 | ti->addr_limit = USER_DS; |
265 | } else { | 252 | } else { |
266 | childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE; | 253 | childregs->regs[15] = (unsigned long)task_stack_page(p) + |
254 | THREAD_SIZE; | ||
267 | ti->addr_limit = KERNEL_DS; | 255 | ti->addr_limit = KERNEL_DS; |
268 | } | 256 | } |
269 | if (clone_flags & CLONE_SETTLS) { | 257 | |
258 | if (clone_flags & CLONE_SETTLS) | ||
270 | childregs->gbr = childregs->regs[0]; | 259 | childregs->gbr = childregs->regs[0]; |
271 | } | 260 | |
272 | childregs->regs[0] = 0; /* Set return value for child */ | 261 | childregs->regs[0] = 0; /* Set return value for child */ |
273 | 262 | ||
274 | p->thread.sp = (unsigned long) childregs; | 263 | p->thread.sp = (unsigned long) childregs; |
@@ -280,8 +269,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, | |||
280 | } | 269 | } |
281 | 270 | ||
282 | /* Tracing by user break controller. */ | 271 | /* Tracing by user break controller. */ |
283 | static void | 272 | static void ubc_set_tracing(int asid, unsigned long pc) |
284 | ubc_set_tracing(int asid, unsigned long pc) | ||
285 | { | 273 | { |
286 | #if defined(CONFIG_CPU_SH4A) | 274 | #if defined(CONFIG_CPU_SH4A) |
287 | unsigned long val; | 275 | unsigned long val; |
@@ -297,7 +285,7 @@ ubc_set_tracing(int asid, unsigned long pc) | |||
297 | val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE); | 285 | val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE); |
298 | ctrl_outl(val, UBC_CRR0); | 286 | ctrl_outl(val, UBC_CRR0); |
299 | 287 | ||
300 | /* Read UBC register that we writed last. For chekking UBC Register changed */ | 288 | /* Read UBC register that we wrote last, for checking update */ |
301 | val = ctrl_inl(UBC_CRR0); | 289 | val = ctrl_inl(UBC_CRR0); |
302 | 290 | ||
303 | #else /* CONFIG_CPU_SH4A */ | 291 | #else /* CONFIG_CPU_SH4A */ |
@@ -305,13 +293,14 @@ ubc_set_tracing(int asid, unsigned long pc) | |||
305 | 293 | ||
306 | #ifdef CONFIG_MMU | 294 | #ifdef CONFIG_MMU |
307 | /* We don't have any ASID settings for the SH-2! */ | 295 | /* We don't have any ASID settings for the SH-2! */ |
308 | if (cpu_data->type != CPU_SH7604) | 296 | if (current_cpu_data.type != CPU_SH7604) |
309 | ctrl_outb(asid, UBC_BASRA); | 297 | ctrl_outb(asid, UBC_BASRA); |
310 | #endif | 298 | #endif |
311 | 299 | ||
312 | ctrl_outl(0, UBC_BAMRA); | 300 | ctrl_outl(0, UBC_BAMRA); |
313 | 301 | ||
314 | if (cpu_data->type == CPU_SH7729 || cpu_data->type == CPU_SH7710) { | 302 | if (current_cpu_data.type == CPU_SH7729 || |
303 | current_cpu_data.type == CPU_SH7710) { | ||
315 | ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); | 304 | ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); |
316 | ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); | 305 | ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); |
317 | } else { | 306 | } else { |
@@ -325,7 +314,8 @@ ubc_set_tracing(int asid, unsigned long pc) | |||
325 | * switch_to(x,y) should switch tasks from x to y. | 314 | * switch_to(x,y) should switch tasks from x to y. |
326 | * | 315 | * |
327 | */ | 316 | */ |
328 | struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next) | 317 | struct task_struct *__switch_to(struct task_struct *prev, |
318 | struct task_struct *next) | ||
329 | { | 319 | { |
330 | #if defined(CONFIG_SH_FPU) | 320 | #if defined(CONFIG_SH_FPU) |
331 | unlazy_fpu(prev, task_pt_regs(prev)); | 321 | unlazy_fpu(prev, task_pt_regs(prev)); |
@@ -354,7 +344,7 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne | |||
354 | #ifdef CONFIG_MMU | 344 | #ifdef CONFIG_MMU |
355 | /* | 345 | /* |
356 | * Restore the kernel mode register | 346 | * Restore the kernel mode register |
357 | * k7 (r7_bank1) | 347 | * k7 (r7_bank1) |
358 | */ | 348 | */ |
359 | asm volatile("ldc %0, r7_bank" | 349 | asm volatile("ldc %0, r7_bank" |
360 | : /* no output */ | 350 | : /* no output */ |
@@ -367,7 +357,7 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne | |||
367 | else if (next->thread.ubc_pc && next->mm) { | 357 | else if (next->thread.ubc_pc && next->mm) { |
368 | int asid = 0; | 358 | int asid = 0; |
369 | #ifdef CONFIG_MMU | 359 | #ifdef CONFIG_MMU |
370 | asid |= next->mm->context.id & MMU_CONTEXT_ASID_MASK; | 360 | asid |= cpu_asid(smp_processor_id(), next->mm); |
371 | #endif | 361 | #endif |
372 | ubc_set_tracing(asid, next->thread.ubc_pc); | 362 | ubc_set_tracing(asid, next->thread.ubc_pc); |
373 | } else { | 363 | } else { |
@@ -405,7 +395,8 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | |||
405 | if (!newsp) | 395 | if (!newsp) |
406 | newsp = regs->regs[15]; | 396 | newsp = regs->regs[15]; |
407 | return do_fork(clone_flags, newsp, regs, 0, | 397 | return do_fork(clone_flags, newsp, regs, 0, |
408 | (int __user *)parent_tidptr, (int __user *)child_tidptr); | 398 | (int __user *)parent_tidptr, |
399 | (int __user *)child_tidptr); | ||
409 | } | 400 | } |
410 | 401 | ||
411 | /* | 402 | /* |
@@ -493,9 +484,27 @@ asmlinkage void break_point_trap(void) | |||
493 | force_sig(SIGTRAP, current); | 484 | force_sig(SIGTRAP, current); |
494 | } | 485 | } |
495 | 486 | ||
496 | asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5, | 487 | /* |
497 | unsigned long r6, unsigned long r7, | 488 | * Generic trap handler. |
498 | struct pt_regs __regs) | 489 | */ |
490 | asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5, | ||
491 | unsigned long r6, unsigned long r7, | ||
492 | struct pt_regs __regs) | ||
493 | { | ||
494 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
495 | |||
496 | /* Rewind */ | ||
497 | regs->pc -= 2; | ||
498 | |||
499 | force_sig(SIGTRAP, current); | ||
500 | } | ||
501 | |||
502 | /* | ||
503 | * Special handler for BUG() traps. | ||
504 | */ | ||
505 | asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5, | ||
506 | unsigned long r6, unsigned long r7, | ||
507 | struct pt_regs __regs) | ||
499 | { | 508 | { |
500 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | 509 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
501 | 510 | ||