X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fsh%2Fkernel%2Fprocess.c;h=9f6aa80613ab24d396365cca4d4f8f5f6fb340eb;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=9fd1723e62192dd524040589677541ed2ee186e1;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 9fd1723e6..9f6aa8061 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -5,6 +5,7 @@ * Copyright (C) 1995 Linus Torvalds * * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima + * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC */ /* @@ -19,7 +20,6 @@ #include #include #include -#include #include #include @@ -27,6 +27,7 @@ #include #include #include +#include static int hlt_counter=0; @@ -81,16 +82,6 @@ void cpu_idle(void) void machine_restart(char * __unused) { - -#ifdef CONFIG_KEXEC - struct kimage *image; - image = xchg(&kexec_image, 0); - if (image) { - machine_shutdown(); - machine_kexec(image); - } -#endif - /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */ asm volatile("ldc %0, sr\n\t" "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001)); @@ -113,8 +104,9 @@ void machine_power_off(void) void show_regs(struct pt_regs * regs) { printk("\n"); - printk("Pid : %d, Comm: %20s\n", current->pid, current->comm); - print_symbol("PC is at %s\n", regs->pc); + printk("Pid : %d:#%u, Comm: %20s\n", + current->pid, current->xid, current->comm); + print_symbol("PC is at %s\n", instruction_pointer(regs)); printk("PC : %08lx SP : %08lx SR : %08lx ", regs->pc, regs->regs[15], regs->sr); #ifdef CONFIG_MMU @@ -139,15 +131,7 @@ void show_regs(struct pt_regs * regs) printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n", regs->mach, regs->macl, regs->gbr, regs->pr); - /* - * If we're in kernel mode, dump the stack too.. - */ - if (!user_mode(regs)) { - extern void show_task(unsigned long *sp); - unsigned long sp = regs->regs[15]; - - show_task((unsigned long *)sp); - } + show_trace(NULL, (unsigned long *)regs->regs[15], regs); } /* @@ -181,7 +165,8 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) regs.sr = (1 << 30); /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, + 0, ®s, 0, NULL, NULL); } /* @@ -263,6 +248,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) { + struct thread_info *ti = task_thread_info(p); struct pt_regs *childregs; #if defined(CONFIG_SH_FPU) struct task_struct *tsk = current; @@ -277,8 +263,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, if (user_mode(regs)) { childregs->regs[15] = usp; + ti->addr_limit = USER_DS; } else { childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE; + ti->addr_limit = KERNEL_DS; } if (clone_flags & CLONE_SETTLS) { childregs->gbr = childregs->regs[0]; @@ -297,21 +285,42 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, static void ubc_set_tracing(int asid, unsigned long pc) { +#if defined(CONFIG_CPU_SH4A) + unsigned long val; + + val = (UBC_CBR_ID_INST | UBC_CBR_RW_READ | UBC_CBR_CE); + val |= (UBC_CBR_AIE | UBC_CBR_AIV_SET(asid)); + + ctrl_outl(val, UBC_CBR0); + ctrl_outl(pc, UBC_CAR0); + ctrl_outl(0x0, UBC_CAMR0); + ctrl_outl(0x0, UBC_CBCR); + + val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE); + ctrl_outl(val, UBC_CRR0); + + /* Read UBC register that we writed last. For chekking UBC Register changed */ + val = ctrl_inl(UBC_CRR0); + +#else /* CONFIG_CPU_SH4A */ ctrl_outl(pc, UBC_BARA); +#ifdef CONFIG_MMU /* We don't have any ASID settings for the SH-2! */ if (cpu_data->type != CPU_SH7604) ctrl_outb(asid, UBC_BASRA); +#endif ctrl_outl(0, UBC_BAMRA); - if (cpu_data->type == CPU_SH7729) { + if (cpu_data->type == CPU_SH7729 || cpu_data->type == CPU_SH7710) { ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); } else { ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA); ctrl_outw(BRCR_PCBA, UBC_BRCR); } +#endif /* CONFIG_CPU_SH4A */ } /* @@ -344,6 +353,7 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne } #endif +#ifdef CONFIG_MMU /* * Restore the kernel mode register * k7 (r7_bank1) @@ -351,29 +361,37 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne asm volatile("ldc %0, r7_bank" : /* no output */ : "r" (task_thread_info(next))); +#endif -#ifdef CONFIG_MMU /* If no tasks are using the UBC, we're done */ if (ubc_usercnt == 0) /* If no tasks are using the UBC, we're done */; else if (next->thread.ubc_pc && next->mm) { - ubc_set_tracing(next->mm->context & MMU_CONTEXT_ASID_MASK, - next->thread.ubc_pc); + int asid = 0; +#ifdef CONFIG_MMU + asid |= next->mm->context.id & MMU_CONTEXT_ASID_MASK; +#endif + ubc_set_tracing(asid, next->thread.ubc_pc); } else { +#if defined(CONFIG_CPU_SH4A) + ctrl_outl(UBC_CBR_INIT, UBC_CBR0); + ctrl_outl(UBC_CRR_INIT, UBC_CRR0); +#else ctrl_outw(0, UBC_BBRA); ctrl_outw(0, UBC_BBRB); - } #endif + } return prev; } asmlinkage int sys_fork(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); #ifdef CONFIG_MMU - return do_fork(SIGCHLD, regs.regs[15], ®s, 0, NULL, NULL); + return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL); #else /* fork almost works, enough to trick you into looking elsewhere :-( */ return -EINVAL; @@ -383,11 +401,12 @@ asmlinkage int sys_fork(unsigned long r4, unsigned long r5, asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, unsigned long parent_tidptr, unsigned long child_tidptr, - struct pt_regs regs) + struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); if (!newsp) - newsp = regs.regs[15]; - return do_fork(clone_flags, newsp, ®s, 0, + newsp = regs->regs[15]; + return do_fork(clone_flags, newsp, regs, 0, (int __user *)parent_tidptr, (int __user *)child_tidptr); } @@ -403,9 +422,10 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, */ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], ®s, + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[15], regs, 0, NULL, NULL); } @@ -414,8 +434,9 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, */ asmlinkage int sys_execve(char *ufilename, char **uargv, char **uenvp, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); int error; char *filename; @@ -427,7 +448,7 @@ asmlinkage int sys_execve(char *ufilename, char **uargv, error = do_execve(filename, (char __user * __user *)uargv, (char __user * __user *)uenvp, - ®s); + regs); if (error == 0) { task_lock(current); current->ptrace &= ~PT_DTRACE; @@ -451,19 +472,23 @@ unsigned long get_wchan(struct task_struct *p) */ pc = thread_saved_pc(p); if (in_sched_functions(pc)) { - schedule_frame = ((unsigned long *)(long)p->thread.sp)[1]; - return (unsigned long)((unsigned long *)schedule_frame)[1]; + schedule_frame = (unsigned long)p->thread.sp; + return ((unsigned long *)schedule_frame)[21]; } + return pc; } -asmlinkage void break_point_trap(unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs regs) +asmlinkage void break_point_trap(void) { /* Clear tracing. */ +#if defined(CONFIG_CPU_SH4A) + ctrl_outl(UBC_CBR_INIT, UBC_CBR0); + ctrl_outl(UBC_CRR_INIT, UBC_CRR0); +#else ctrl_outw(0, UBC_BBRA); ctrl_outw(0, UBC_BBRB); +#endif current->thread.ubc_pc = 0; ubc_usercnt -= 1; @@ -472,8 +497,20 @@ asmlinkage void break_point_trap(unsigned long r4, unsigned long r5, asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs regs) + struct pt_regs __regs) { - regs.pc -= 2; + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + + /* Rewind */ + regs->pc -= 2; + +#ifdef CONFIG_BUG + if (__kernel_text_address(instruction_pointer(regs))) { + u16 insn = *(u16 *)instruction_pointer(regs); + if (insn == TRAPA_BUG_OPCODE) + handle_BUG(regs); + } +#endif + force_sig(SIGTRAP, current); }