*
* SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
* Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
- * Copyright (C) 2002 - 2007 Paul Mundt
+ * Copyright (C) 2002 - 2008 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <asm/pgalloc.h>
#include <asm/system.h>
#include <asm/ubc.h>
+#include <asm/fpu.h>
+#include <asm/syscalls.h>
-static int hlt_counter;
int ubc_usercnt = 0;
-void (*pm_idle)(void);
-void (*pm_power_off)(void);
-EXPORT_SYMBOL(pm_power_off);
-
-void disable_hlt(void)
-{
- hlt_counter++;
-}
-EXPORT_SYMBOL(disable_hlt);
-
-void enable_hlt(void)
-{
- hlt_counter--;
-}
-EXPORT_SYMBOL(enable_hlt);
-
-static int __init nohlt_setup(char *__unused)
-{
- hlt_counter = 1;
- return 1;
-}
-__setup("nohlt", nohlt_setup);
-
-static int __init hlt_setup(char *__unused)
-{
- hlt_counter = 0;
- return 1;
-}
-__setup("hlt", hlt_setup);
-
-void default_idle(void)
-{
- if (!hlt_counter) {
- clear_thread_flag(TIF_POLLING_NRFLAG);
- smp_mb__after_clear_bit();
- set_bl_bit();
- while (!need_resched())
- cpu_sleep();
- clear_bl_bit();
- set_thread_flag(TIF_POLLING_NRFLAG);
- } else
- while (!need_resched())
- cpu_relax();
-}
-
-void cpu_idle(void)
-{
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- /* endless idle loop with no priority at all */
- while (1) {
- void (*idle)(void) = pm_idle;
-
- if (!idle)
- idle = default_idle;
-
- tick_nohz_stop_sched_tick();
- while (!need_resched())
- idle();
- tick_nohz_restart_sched_tick();
-
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- check_pgt_cache();
- }
-}
-
void machine_restart(char * __unused)
{
/* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
void show_regs(struct pt_regs * regs)
{
printk("\n");
- printk("Pid : %d, Comm: %20s\n", task_pid_nr(current), current->comm);
+ printk("Pid : %d, Comm: \t\t%s\n", task_pid_nr(current), current->comm);
+ printk("CPU : %d \t\t%s (%s %.*s)\n\n",
+ smp_processor_id(), print_tainted(), init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
+
print_symbol("PC is at %s\n", instruction_pointer(regs));
+ print_symbol("PR is at %s\n", regs->pr);
+
printk("PC : %08lx SP : %08lx SR : %08lx ",
regs->pc, regs->regs[15], regs->sr);
#ifdef CONFIG_MMU
- printk("TEA : %08x ", ctrl_inl(MMU_TEA));
+ printk("TEA : %08x\n", ctrl_inl(MMU_TEA));
#else
- printk(" ");
+ printk("\n");
#endif
- printk("%s\n", print_tainted());
printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n",
regs->regs[0],regs->regs[1],
regs->mach, regs->macl, regs->gbr, regs->pr);
show_trace(NULL, (unsigned long *)regs->regs[15], regs);
+ show_code(regs);
}
/*
* Create a kernel thread
*/
-
-/*
- * This is the mechanism for creating a new kernel thread.
- *
- */
-extern void kernel_thread_helper(void);
-__asm__(".align 5\n"
- "kernel_thread_helper:\n\t"
- "jsr @r5\n\t"
- " nop\n\t"
- "mov.l 1f, r1\n\t"
- "jsr @r1\n\t"
- " mov r0, r4\n\t"
- ".align 2\n\t"
- "1:.long do_exit");
+ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+{
+ do_exit(fn(arg));
+}
/* Don't use this in BL=1(cli). Or else, CPU resets! */
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
struct pt_regs regs;
+ int pid;
memset(®s, 0, sizeof(regs));
regs.regs[4] = (unsigned long)arg;
regs.sr = (1 << 30);
/* Ok, create the new process.. */
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
- ®s, 0, NULL, NULL);
+ pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
+ ®s, 0, NULL, NULL);
+
+ trace_mark(kernel_arch_kthread_create, "pid %d fn %p", pid, fn);
+
+ return pid;
}
/*
struct task_struct *tsk = current;
fpvalid = !!tsk_used_math(tsk);
- if (fpvalid) {
- unlazy_fpu(tsk, regs);
- memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
- }
-#endif
-
- return fpvalid;
-}
-
-/*
- * Capture the user space registers if the task is not running (in user space)
- */
-int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
-{
- struct pt_regs ptregs;
-
- ptregs = *task_pt_regs(tsk);
- elf_core_copy_regs(regs, &ptregs);
-
- return 1;
-}
-
-int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpu)
-{
- int fpvalid = 0;
-
-#if defined(CONFIG_SH_FPU)
- fpvalid = !!tsk_used_math(tsk);
- if (fpvalid) {
- unlazy_fpu(tsk, task_pt_regs(tsk));
- memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
- }
+ if (fpvalid)
+ fpvalid = !fpregs_get(tsk, NULL, 0,
+ sizeof(struct user_fpu_struct),
+ fpu, NULL);
#endif
return fpvalid;
{
struct thread_info *ti = task_thread_info(p);
struct pt_regs *childregs;
-#if defined(CONFIG_SH_FPU)
+#if defined(CONFIG_SH_FPU) || defined(CONFIG_SH_DSP)
struct task_struct *tsk = current;
+#endif
+#if defined(CONFIG_SH_FPU)
unlazy_fpu(tsk, regs);
p->thread.fpu = tsk->thread.fpu;
copy_to_stopped_child_used_math(p);
#endif
+#if defined(CONFIG_SH_DSP)
+ if (is_dsp_enabled(tsk)) {
+ /* We can use the __save_dsp or just copy the struct:
+ * __save_dsp(p);
+ * p->thread.dsp_status.status |= SR_DSP
+ */
+ p->thread.dsp_status = tsk->thread.dsp_status;
+ }
+#endif
+
childregs = task_pt_regs(p);
*childregs = *regs;
unlazy_fpu(prev, task_pt_regs(prev));
#endif
-#if defined(CONFIG_GUSA) && defined(CONFIG_PREEMPT)
- {
- struct pt_regs *regs;
-
- preempt_disable();
- regs = task_pt_regs(prev);
- if (user_mode(regs) && regs->regs[15] >= 0xc0000000) {
- int offset = (int)regs->regs[15];
-
- /* Reset stack pointer: clear critical region mark */
- regs->regs[15] = regs->regs[1];
- if (regs->pc < regs->regs[0])
- /* Go to rewind point */
- regs->pc = regs->regs[0] + offset;
- }
- preempt_enable_no_resched();
- }
-#endif
-
#ifdef CONFIG_MMU
/*
* Restore the kernel mode register
force_sig(SIGTRAP, current);
}
-
-/*
- * Generic trap handler.
- */
-asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
-{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
-
- /* Rewind */
- regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
-
- if (notify_die(DIE_TRAP, "debug trap", regs, 0, regs->tra & 0xff,
- SIGTRAP) == NOTIFY_STOP)
- return;
-
- force_sig(SIGTRAP, current);
-}
-
-/*
- * Special handler for BUG() traps.
- */
-asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
-{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
-
- /* Rewind */
- regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
-
- if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
- SIGTRAP) == NOTIFY_STOP)
- return;
-
-#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);
-}