extra-y := head.o init_task.o vmlinux.lds
-obj-y := debugtraps.o io.o io_generic.o irq.o machvec.o process.o ptrace.o \
- semaphore.o setup.o signal.o sys_sh.o syscalls.o \
+obj-y := debugtraps.o io.o io_generic.o irq.o machvec.o process_32.o \
+ ptrace.o semaphore.o setup.o signal.o sys_sh.o syscalls.o \
time.o topology.o traps.o
obj-y += cpu/ timers/
+++ /dev/null
-/*
- * arch/sh/kernel/process.c
- *
- * This file handles the architecture-dependent parts of process handling..
- *
- * Copyright (C) 1995 Linus Torvalds
- *
- * 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
- */
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/elfcore.h>
-#include <linux/pm.h>
-#include <linux/kallsyms.h>
-#include <linux/kexec.h>
-#include <linux/kdebug.h>
-#include <linux/tick.h>
-#include <linux/reboot.h>
-#include <linux/fs.h>
-#include <linux/preempt.h>
-#include <asm/uaccess.h>
-#include <asm/mmu_context.h>
-#include <asm/pgalloc.h>
-#include <asm/system.h>
-#include <asm/ubc.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) */
- asm volatile("ldc %0, sr\n\t"
- "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001));
-}
-
-void machine_halt(void)
-{
- local_irq_disable();
-
- while (1)
- cpu_sleep();
-}
-
-void machine_power_off(void)
-{
- if (pm_power_off)
- pm_power_off();
-}
-
-void show_regs(struct pt_regs * regs)
-{
- printk("\n");
- printk("Pid : %d, Comm: %20s\n", task_pid_nr(current), 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
- printk("TEA : %08x ", ctrl_inl(MMU_TEA));
-#else
- printk(" ");
-#endif
- printk("%s\n", print_tainted());
-
- printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n",
- regs->regs[0],regs->regs[1],
- regs->regs[2],regs->regs[3]);
- printk("R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n",
- regs->regs[4],regs->regs[5],
- regs->regs[6],regs->regs[7]);
- printk("R8 : %08lx R9 : %08lx R10 : %08lx R11 : %08lx\n",
- regs->regs[8],regs->regs[9],
- regs->regs[10],regs->regs[11]);
- printk("R12 : %08lx R13 : %08lx R14 : %08lx\n",
- regs->regs[12],regs->regs[13],
- regs->regs[14]);
- printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n",
- regs->mach, regs->macl, regs->gbr, regs->pr);
-
- show_trace(NULL, (unsigned long *)regs->regs[15], 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");
-
-/* 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;
-
- memset(®s, 0, sizeof(regs));
- regs.regs[4] = (unsigned long)arg;
- regs.regs[5] = (unsigned long)fn;
-
- regs.pc = (unsigned long)kernel_thread_helper;
- regs.sr = (1 << 30);
-
- /* Ok, create the new process.. */
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
- ®s, 0, NULL, NULL);
-}
-
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
- if (current->thread.ubc_pc) {
- current->thread.ubc_pc = 0;
- ubc_usercnt -= 1;
- }
-}
-
-void flush_thread(void)
-{
-#if defined(CONFIG_SH_FPU)
- struct task_struct *tsk = current;
- /* Forget lazy FPU state */
- clear_fpu(tsk, task_pt_regs(tsk));
- clear_used_math();
-#endif
-}
-
-void release_thread(struct task_struct *dead_task)
-{
- /* do nothing */
-}
-
-/* Fill in the fpu structure for a core dump.. */
-int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
-{
- int fpvalid = 0;
-
-#if defined(CONFIG_SH_FPU)
- 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));
- }
-#endif
-
- return fpvalid;
-}
-
-asmlinkage void ret_from_fork(void);
-
-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;
-
- unlazy_fpu(tsk, regs);
- p->thread.fpu = tsk->thread.fpu;
- copy_to_stopped_child_used_math(p);
-#endif
-
- childregs = task_pt_regs(p);
- *childregs = *regs;
-
- if (user_mode(regs)) {
- childregs->regs[15] = usp;
- ti->addr_limit = USER_DS;
- } else {
- childregs->regs[15] = (unsigned long)childregs;
- ti->addr_limit = KERNEL_DS;
- }
-
- if (clone_flags & CLONE_SETTLS)
- childregs->gbr = childregs->regs[0];
-
- childregs->regs[0] = 0; /* Set return value for child */
-
- p->thread.sp = (unsigned long) childregs;
- p->thread.pc = (unsigned long) ret_from_fork;
-
- p->thread.ubc_pc = 0;
-
- return 0;
-}
-
-/* Tracing by user break controller. */
-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 wrote last, for checking update */
- val = ctrl_inl(UBC_CRR0);
-
-#else /* CONFIG_CPU_SH4A */
- ctrl_outl(pc, UBC_BARA);
-
-#ifdef CONFIG_MMU
- ctrl_outb(asid, UBC_BASRA);
-#endif
-
- ctrl_outl(0, UBC_BAMRA);
-
- if (current_cpu_data.type == CPU_SH7729 ||
- current_cpu_data.type == CPU_SH7710 ||
- current_cpu_data.type == CPU_SH7712) {
- 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 */
-}
-
-/*
- * switch_to(x,y) should switch tasks from x to y.
- *
- */
-struct task_struct *__switch_to(struct task_struct *prev,
- struct task_struct *next)
-{
-#if defined(CONFIG_SH_FPU)
- 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
- * k7 (r7_bank1)
- */
- asm volatile("ldc %0, r7_bank"
- : /* no output */
- : "r" (task_thread_info(next)));
-#endif
-
- /* 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) {
- int asid = 0;
-#ifdef CONFIG_MMU
- asid |= cpu_asid(smp_processor_id(), next->mm);
-#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)
-{
-#ifdef CONFIG_MMU
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
- return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL);
-#else
- /* fork almost works, enough to trick you into looking elsewhere :-( */
- return -EINVAL;
-#endif
-}
-
-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 = RELOC_HIDE(&__regs, 0);
- if (!newsp)
- newsp = regs->regs[15];
- return do_fork(clone_flags, newsp, regs, 0,
- (int __user *)parent_tidptr,
- (int __user *)child_tidptr);
-}
-
-/*
- * This is trivial, and on the face of it looks like it
- * could equally well be done in user mode.
- *
- * Not so, for quite unobvious reasons - register pressure.
- * In user mode vfork() cannot have a stack frame, and if
- * done by calling the "clone()" system call directly, you
- * do not have enough call-clobbered registers to hold all
- * the information you need.
- */
-asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
-{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[15], regs,
- 0, NULL, NULL);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv,
- char __user * __user *uenvp, unsigned long r7,
- struct pt_regs __regs)
-{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
- int error;
- char *filename;
-
- filename = getname(ufilename);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
-
- error = do_execve(filename, uargv, uenvp, regs);
- if (error == 0) {
- task_lock(current);
- current->ptrace &= ~PT_DTRACE;
- task_unlock(current);
- }
- putname(filename);
-out:
- return error;
-}
-
-unsigned long get_wchan(struct task_struct *p)
-{
- unsigned long pc;
-
- if (!p || p == current || p->state == TASK_RUNNING)
- return 0;
-
- /*
- * The same comment as on the Alpha applies here, too ...
- */
- pc = thread_saved_pc(p);
-
-#ifdef CONFIG_FRAME_POINTER
- if (in_sched_functions(pc)) {
- unsigned long schedule_frame = (unsigned long)p->thread.sp;
- return ((unsigned long *)schedule_frame)[21];
- }
-#endif
-
- return pc;
-}
-
-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;
-
- 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);
-}
--- /dev/null
+/*
+ * arch/sh/kernel/process.c
+ *
+ * This file handles the architecture-dependent parts of process handling..
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * 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
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/elfcore.h>
+#include <linux/pm.h>
+#include <linux/kallsyms.h>
+#include <linux/kexec.h>
+#include <linux/kdebug.h>
+#include <linux/tick.h>
+#include <linux/reboot.h>
+#include <linux/fs.h>
+#include <linux/preempt.h>
+#include <asm/uaccess.h>
+#include <asm/mmu_context.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
+#include <asm/ubc.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) */
+ asm volatile("ldc %0, sr\n\t"
+ "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001));
+}
+
+void machine_halt(void)
+{
+ local_irq_disable();
+
+ while (1)
+ cpu_sleep();
+}
+
+void machine_power_off(void)
+{
+ if (pm_power_off)
+ pm_power_off();
+}
+
+void show_regs(struct pt_regs * regs)
+{
+ printk("\n");
+ printk("Pid : %d, Comm: %20s\n", task_pid_nr(current), 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
+ printk("TEA : %08x ", ctrl_inl(MMU_TEA));
+#else
+ printk(" ");
+#endif
+ printk("%s\n", print_tainted());
+
+ printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n",
+ regs->regs[0],regs->regs[1],
+ regs->regs[2],regs->regs[3]);
+ printk("R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n",
+ regs->regs[4],regs->regs[5],
+ regs->regs[6],regs->regs[7]);
+ printk("R8 : %08lx R9 : %08lx R10 : %08lx R11 : %08lx\n",
+ regs->regs[8],regs->regs[9],
+ regs->regs[10],regs->regs[11]);
+ printk("R12 : %08lx R13 : %08lx R14 : %08lx\n",
+ regs->regs[12],regs->regs[13],
+ regs->regs[14]);
+ printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n",
+ regs->mach, regs->macl, regs->gbr, regs->pr);
+
+ show_trace(NULL, (unsigned long *)regs->regs[15], 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");
+
+/* 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;
+
+ memset(®s, 0, sizeof(regs));
+ regs.regs[4] = (unsigned long)arg;
+ regs.regs[5] = (unsigned long)fn;
+
+ regs.pc = (unsigned long)kernel_thread_helper;
+ regs.sr = (1 << 30);
+
+ /* Ok, create the new process.. */
+ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
+ ®s, 0, NULL, NULL);
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+ if (current->thread.ubc_pc) {
+ current->thread.ubc_pc = 0;
+ ubc_usercnt -= 1;
+ }
+}
+
+void flush_thread(void)
+{
+#if defined(CONFIG_SH_FPU)
+ struct task_struct *tsk = current;
+ /* Forget lazy FPU state */
+ clear_fpu(tsk, task_pt_regs(tsk));
+ clear_used_math();
+#endif
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+ /* do nothing */
+}
+
+/* Fill in the fpu structure for a core dump.. */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+{
+ int fpvalid = 0;
+
+#if defined(CONFIG_SH_FPU)
+ 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));
+ }
+#endif
+
+ return fpvalid;
+}
+
+asmlinkage void ret_from_fork(void);
+
+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;
+
+ unlazy_fpu(tsk, regs);
+ p->thread.fpu = tsk->thread.fpu;
+ copy_to_stopped_child_used_math(p);
+#endif
+
+ childregs = task_pt_regs(p);
+ *childregs = *regs;
+
+ if (user_mode(regs)) {
+ childregs->regs[15] = usp;
+ ti->addr_limit = USER_DS;
+ } else {
+ childregs->regs[15] = (unsigned long)childregs;
+ ti->addr_limit = KERNEL_DS;
+ }
+
+ if (clone_flags & CLONE_SETTLS)
+ childregs->gbr = childregs->regs[0];
+
+ childregs->regs[0] = 0; /* Set return value for child */
+
+ p->thread.sp = (unsigned long) childregs;
+ p->thread.pc = (unsigned long) ret_from_fork;
+
+ p->thread.ubc_pc = 0;
+
+ return 0;
+}
+
+/* Tracing by user break controller. */
+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 wrote last, for checking update */
+ val = ctrl_inl(UBC_CRR0);
+
+#else /* CONFIG_CPU_SH4A */
+ ctrl_outl(pc, UBC_BARA);
+
+#ifdef CONFIG_MMU
+ ctrl_outb(asid, UBC_BASRA);
+#endif
+
+ ctrl_outl(0, UBC_BAMRA);
+
+ if (current_cpu_data.type == CPU_SH7729 ||
+ current_cpu_data.type == CPU_SH7710 ||
+ current_cpu_data.type == CPU_SH7712) {
+ 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 */
+}
+
+/*
+ * switch_to(x,y) should switch tasks from x to y.
+ *
+ */
+struct task_struct *__switch_to(struct task_struct *prev,
+ struct task_struct *next)
+{
+#if defined(CONFIG_SH_FPU)
+ 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
+ * k7 (r7_bank1)
+ */
+ asm volatile("ldc %0, r7_bank"
+ : /* no output */
+ : "r" (task_thread_info(next)));
+#endif
+
+ /* 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) {
+ int asid = 0;
+#ifdef CONFIG_MMU
+ asid |= cpu_asid(smp_processor_id(), next->mm);
+#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)
+{
+#ifdef CONFIG_MMU
+ struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL);
+#else
+ /* fork almost works, enough to trick you into looking elsewhere :-( */
+ return -EINVAL;
+#endif
+}
+
+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 = RELOC_HIDE(&__regs, 0);
+ if (!newsp)
+ newsp = regs->regs[15];
+ return do_fork(clone_flags, newsp, regs, 0,
+ (int __user *)parent_tidptr,
+ (int __user *)child_tidptr);
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs __regs)
+{
+ struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[15], regs,
+ 0, NULL, NULL);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv,
+ char __user * __user *uenvp, unsigned long r7,
+ struct pt_regs __regs)
+{
+ struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ int error;
+ char *filename;
+
+ filename = getname(ufilename);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ goto out;
+
+ error = do_execve(filename, uargv, uenvp, regs);
+ if (error == 0) {
+ task_lock(current);
+ current->ptrace &= ~PT_DTRACE;
+ task_unlock(current);
+ }
+ putname(filename);
+out:
+ return error;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long pc;
+
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+
+ /*
+ * The same comment as on the Alpha applies here, too ...
+ */
+ pc = thread_saved_pc(p);
+
+#ifdef CONFIG_FRAME_POINTER
+ if (in_sched_functions(pc)) {
+ unsigned long schedule_frame = (unsigned long)p->thread.sp;
+ return ((unsigned long *)schedule_frame)[21];
+ }
+#endif
+
+ return pc;
+}
+
+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;
+
+ 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);
+}
--- /dev/null
+/*
+ * 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.
+ *
+ * arch/sh64/kernel/process.c
+ *
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ * Copyright (C) 2003 Paul Mundt
+ * Copyright (C) 2003, 2004 Richard Curnow
+ *
+ * Started from SH3/4 version:
+ * Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
+ *
+ * In turn started from i386 version:
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/ptrace.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+struct task_struct *last_task_used_math = NULL;
+
+static int hlt_counter = 1;
+
+#define HARD_IDLE_TIMEOUT (HZ / 3)
+
+void disable_hlt(void)
+{
+ hlt_counter++;
+}
+
+void enable_hlt(void)
+{
+ hlt_counter--;
+}
+
+static int __init nohlt_setup(char *__unused)
+{
+ hlt_counter = 1;
+ return 1;
+}
+
+static int __init hlt_setup(char *__unused)
+{
+ hlt_counter = 0;
+ return 1;
+}
+
+__setup("nohlt", nohlt_setup);
+__setup("hlt", hlt_setup);
+
+static inline void hlt(void)
+{
+ __asm__ __volatile__ ("sleep" : : : "memory");
+}
+
+/*
+ * The idle loop on a uniprocessor SH..
+ */
+void cpu_idle(void)
+{
+ /* endless idle loop with no priority at all */
+ while (1) {
+ if (hlt_counter) {
+ while (!need_resched())
+ cpu_relax();
+ } else {
+ local_irq_disable();
+ while (!need_resched()) {
+ local_irq_enable();
+ hlt();
+ local_irq_disable();
+ }
+ local_irq_enable();
+ }
+ preempt_enable_no_resched();
+ schedule();
+ preempt_disable();
+ }
+
+}
+
+void machine_restart(char * __unused)
+{
+ extern void phys_stext(void);
+
+ phys_stext();
+}
+
+void machine_halt(void)
+{
+ for (;;);
+}
+
+void machine_power_off(void)
+{
+ extern void enter_deep_standby(void);
+
+ enter_deep_standby();
+}
+
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+void show_regs(struct pt_regs * regs)
+{
+ unsigned long long ah, al, bh, bl, ch, cl;
+
+ printk("\n");
+
+ ah = (regs->pc) >> 32;
+ al = (regs->pc) & 0xffffffff;
+ bh = (regs->regs[18]) >> 32;
+ bl = (regs->regs[18]) & 0xffffffff;
+ ch = (regs->regs[15]) >> 32;
+ cl = (regs->regs[15]) & 0xffffffff;
+ printk("PC : %08Lx%08Lx LINK: %08Lx%08Lx SP : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->sr) >> 32;
+ al = (regs->sr) & 0xffffffff;
+ asm volatile ("getcon " __TEA ", %0" : "=r" (bh));
+ asm volatile ("getcon " __TEA ", %0" : "=r" (bl));
+ bh = (bh) >> 32;
+ bl = (bl) & 0xffffffff;
+ asm volatile ("getcon " __KCR0 ", %0" : "=r" (ch));
+ asm volatile ("getcon " __KCR0 ", %0" : "=r" (cl));
+ ch = (ch) >> 32;
+ cl = (cl) & 0xffffffff;
+ printk("SR : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[0]) >> 32;
+ al = (regs->regs[0]) & 0xffffffff;
+ bh = (regs->regs[1]) >> 32;
+ bl = (regs->regs[1]) & 0xffffffff;
+ ch = (regs->regs[2]) >> 32;
+ cl = (regs->regs[2]) & 0xffffffff;
+ printk("R0 : %08Lx%08Lx R1 : %08Lx%08Lx R2 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[3]) >> 32;
+ al = (regs->regs[3]) & 0xffffffff;
+ bh = (regs->regs[4]) >> 32;
+ bl = (regs->regs[4]) & 0xffffffff;
+ ch = (regs->regs[5]) >> 32;
+ cl = (regs->regs[5]) & 0xffffffff;
+ printk("R3 : %08Lx%08Lx R4 : %08Lx%08Lx R5 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[6]) >> 32;
+ al = (regs->regs[6]) & 0xffffffff;
+ bh = (regs->regs[7]) >> 32;
+ bl = (regs->regs[7]) & 0xffffffff;
+ ch = (regs->regs[8]) >> 32;
+ cl = (regs->regs[8]) & 0xffffffff;
+ printk("R6 : %08Lx%08Lx R7 : %08Lx%08Lx R8 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[9]) >> 32;
+ al = (regs->regs[9]) & 0xffffffff;
+ bh = (regs->regs[10]) >> 32;
+ bl = (regs->regs[10]) & 0xffffffff;
+ ch = (regs->regs[11]) >> 32;
+ cl = (regs->regs[11]) & 0xffffffff;
+ printk("R9 : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[12]) >> 32;
+ al = (regs->regs[12]) & 0xffffffff;
+ bh = (regs->regs[13]) >> 32;
+ bl = (regs->regs[13]) & 0xffffffff;
+ ch = (regs->regs[14]) >> 32;
+ cl = (regs->regs[14]) & 0xffffffff;
+ printk("R12 : %08Lx%08Lx R13 : %08Lx%08Lx R14 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[16]) >> 32;
+ al = (regs->regs[16]) & 0xffffffff;
+ bh = (regs->regs[17]) >> 32;
+ bl = (regs->regs[17]) & 0xffffffff;
+ ch = (regs->regs[19]) >> 32;
+ cl = (regs->regs[19]) & 0xffffffff;
+ printk("R16 : %08Lx%08Lx R17 : %08Lx%08Lx R19 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[20]) >> 32;
+ al = (regs->regs[20]) & 0xffffffff;
+ bh = (regs->regs[21]) >> 32;
+ bl = (regs->regs[21]) & 0xffffffff;
+ ch = (regs->regs[22]) >> 32;
+ cl = (regs->regs[22]) & 0xffffffff;
+ printk("R20 : %08Lx%08Lx R21 : %08Lx%08Lx R22 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[23]) >> 32;
+ al = (regs->regs[23]) & 0xffffffff;
+ bh = (regs->regs[24]) >> 32;
+ bl = (regs->regs[24]) & 0xffffffff;
+ ch = (regs->regs[25]) >> 32;
+ cl = (regs->regs[25]) & 0xffffffff;
+ printk("R23 : %08Lx%08Lx R24 : %08Lx%08Lx R25 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[26]) >> 32;
+ al = (regs->regs[26]) & 0xffffffff;
+ bh = (regs->regs[27]) >> 32;
+ bl = (regs->regs[27]) & 0xffffffff;
+ ch = (regs->regs[28]) >> 32;
+ cl = (regs->regs[28]) & 0xffffffff;
+ printk("R26 : %08Lx%08Lx R27 : %08Lx%08Lx R28 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[29]) >> 32;
+ al = (regs->regs[29]) & 0xffffffff;
+ bh = (regs->regs[30]) >> 32;
+ bl = (regs->regs[30]) & 0xffffffff;
+ ch = (regs->regs[31]) >> 32;
+ cl = (regs->regs[31]) & 0xffffffff;
+ printk("R29 : %08Lx%08Lx R30 : %08Lx%08Lx R31 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[32]) >> 32;
+ al = (regs->regs[32]) & 0xffffffff;
+ bh = (regs->regs[33]) >> 32;
+ bl = (regs->regs[33]) & 0xffffffff;
+ ch = (regs->regs[34]) >> 32;
+ cl = (regs->regs[34]) & 0xffffffff;
+ printk("R32 : %08Lx%08Lx R33 : %08Lx%08Lx R34 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[35]) >> 32;
+ al = (regs->regs[35]) & 0xffffffff;
+ bh = (regs->regs[36]) >> 32;
+ bl = (regs->regs[36]) & 0xffffffff;
+ ch = (regs->regs[37]) >> 32;
+ cl = (regs->regs[37]) & 0xffffffff;
+ printk("R35 : %08Lx%08Lx R36 : %08Lx%08Lx R37 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[38]) >> 32;
+ al = (regs->regs[38]) & 0xffffffff;
+ bh = (regs->regs[39]) >> 32;
+ bl = (regs->regs[39]) & 0xffffffff;
+ ch = (regs->regs[40]) >> 32;
+ cl = (regs->regs[40]) & 0xffffffff;
+ printk("R38 : %08Lx%08Lx R39 : %08Lx%08Lx R40 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[41]) >> 32;
+ al = (regs->regs[41]) & 0xffffffff;
+ bh = (regs->regs[42]) >> 32;
+ bl = (regs->regs[42]) & 0xffffffff;
+ ch = (regs->regs[43]) >> 32;
+ cl = (regs->regs[43]) & 0xffffffff;
+ printk("R41 : %08Lx%08Lx R42 : %08Lx%08Lx R43 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[44]) >> 32;
+ al = (regs->regs[44]) & 0xffffffff;
+ bh = (regs->regs[45]) >> 32;
+ bl = (regs->regs[45]) & 0xffffffff;
+ ch = (regs->regs[46]) >> 32;
+ cl = (regs->regs[46]) & 0xffffffff;
+ printk("R44 : %08Lx%08Lx R45 : %08Lx%08Lx R46 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[47]) >> 32;
+ al = (regs->regs[47]) & 0xffffffff;
+ bh = (regs->regs[48]) >> 32;
+ bl = (regs->regs[48]) & 0xffffffff;
+ ch = (regs->regs[49]) >> 32;
+ cl = (regs->regs[49]) & 0xffffffff;
+ printk("R47 : %08Lx%08Lx R48 : %08Lx%08Lx R49 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[50]) >> 32;
+ al = (regs->regs[50]) & 0xffffffff;
+ bh = (regs->regs[51]) >> 32;
+ bl = (regs->regs[51]) & 0xffffffff;
+ ch = (regs->regs[52]) >> 32;
+ cl = (regs->regs[52]) & 0xffffffff;
+ printk("R50 : %08Lx%08Lx R51 : %08Lx%08Lx R52 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[53]) >> 32;
+ al = (regs->regs[53]) & 0xffffffff;
+ bh = (regs->regs[54]) >> 32;
+ bl = (regs->regs[54]) & 0xffffffff;
+ ch = (regs->regs[55]) >> 32;
+ cl = (regs->regs[55]) & 0xffffffff;
+ printk("R53 : %08Lx%08Lx R54 : %08Lx%08Lx R55 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[56]) >> 32;
+ al = (regs->regs[56]) & 0xffffffff;
+ bh = (regs->regs[57]) >> 32;
+ bl = (regs->regs[57]) & 0xffffffff;
+ ch = (regs->regs[58]) >> 32;
+ cl = (regs->regs[58]) & 0xffffffff;
+ printk("R56 : %08Lx%08Lx R57 : %08Lx%08Lx R58 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[59]) >> 32;
+ al = (regs->regs[59]) & 0xffffffff;
+ bh = (regs->regs[60]) >> 32;
+ bl = (regs->regs[60]) & 0xffffffff;
+ ch = (regs->regs[61]) >> 32;
+ cl = (regs->regs[61]) & 0xffffffff;
+ printk("R59 : %08Lx%08Lx R60 : %08Lx%08Lx R61 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->regs[62]) >> 32;
+ al = (regs->regs[62]) & 0xffffffff;
+ bh = (regs->tregs[0]) >> 32;
+ bl = (regs->tregs[0]) & 0xffffffff;
+ ch = (regs->tregs[1]) >> 32;
+ cl = (regs->tregs[1]) & 0xffffffff;
+ printk("R62 : %08Lx%08Lx T0 : %08Lx%08Lx T1 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->tregs[2]) >> 32;
+ al = (regs->tregs[2]) & 0xffffffff;
+ bh = (regs->tregs[3]) >> 32;
+ bl = (regs->tregs[3]) & 0xffffffff;
+ ch = (regs->tregs[4]) >> 32;
+ cl = (regs->tregs[4]) & 0xffffffff;
+ printk("T2 : %08Lx%08Lx T3 : %08Lx%08Lx T4 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ ah = (regs->tregs[5]) >> 32;
+ al = (regs->tregs[5]) & 0xffffffff;
+ bh = (regs->tregs[6]) >> 32;
+ bl = (regs->tregs[6]) & 0xffffffff;
+ ch = (regs->tregs[7]) >> 32;
+ cl = (regs->tregs[7]) & 0xffffffff;
+ printk("T5 : %08Lx%08Lx T6 : %08Lx%08Lx T7 : %08Lx%08Lx\n",
+ ah, al, bh, bl, ch, cl);
+
+ /*
+ * If we're in kernel mode, dump the stack too..
+ */
+ if (!user_mode(regs)) {
+ void show_stack(struct task_struct *tsk, unsigned long *sp);
+ unsigned long sp = regs->regs[15] & 0xffffffff;
+ struct task_struct *tsk = get_current();
+
+ tsk->thread.kregs = regs;
+
+ show_stack(tsk, (unsigned long *)sp);
+ }
+}
+
+struct task_struct * alloc_task_struct(void)
+{
+ /* Get task descriptor pages */
+ return (struct task_struct *)
+ __get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE));
+}
+
+void free_task_struct(struct task_struct *p)
+{
+ free_pages((unsigned long) p, get_order(THREAD_SIZE));
+}
+
+/*
+ * Create a kernel thread
+ */
+ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+{
+ do_exit(fn(arg));
+}
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be freed until both the parent and the child have exited.
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ struct pt_regs regs;
+
+ memset(®s, 0, sizeof(regs));
+ regs.regs[2] = (unsigned long)arg;
+ regs.regs[3] = (unsigned long)fn;
+
+ regs.pc = (unsigned long)kernel_thread_helper;
+ regs.sr = (1 << 30);
+
+ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
+ ®s, 0, NULL, NULL);
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+ /* See arch/sparc/kernel/process.c for the precedent for doing this -- RPC.
+
+ The SH-5 FPU save/restore approach relies on last_task_used_math
+ pointing to a live task_struct. When another task tries to use the
+ FPU for the 1st time, the FPUDIS trap handling (see
+ arch/sh64/kernel/fpu.c) will save the existing FPU state to the
+ FP regs field within last_task_used_math before re-loading the new
+ task's FPU state (or initialising it if the FPU has been used
+ before). So if last_task_used_math is stale, and its page has already been
+ re-allocated for another use, the consequences are rather grim. Unless we
+ null it here, there is no other path through which it would get safely
+ nulled. */
+
+#ifdef CONFIG_SH_FPU
+ if (last_task_used_math == current) {
+ last_task_used_math = NULL;
+ }
+#endif
+}
+
+void flush_thread(void)
+{
+
+ /* Called by fs/exec.c (flush_old_exec) to remove traces of a
+ * previously running executable. */
+#ifdef CONFIG_SH_FPU
+ if (last_task_used_math == current) {
+ last_task_used_math = NULL;
+ }
+ /* Force FPU state to be reinitialised after exec */
+ clear_used_math();
+#endif
+
+ /* if we are a kernel thread, about to change to user thread,
+ * update kreg
+ */
+ if(current->thread.kregs==&fake_swapper_regs) {
+ current->thread.kregs =
+ ((struct pt_regs *)(THREAD_SIZE + (unsigned long) current) - 1);
+ current->thread.uregs = current->thread.kregs;
+ }
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+ /* do nothing */
+}
+
+/* Fill in the fpu structure for a core dump.. */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+{
+#ifdef CONFIG_SH_FPU
+ int fpvalid;
+ struct task_struct *tsk = current;
+
+ fpvalid = !!tsk_used_math(tsk);
+ if (fpvalid) {
+ if (current == last_task_used_math) {
+ grab_fpu();
+ fpsave(&tsk->thread.fpu.hard);
+ release_fpu();
+ last_task_used_math = 0;
+ regs->sr |= SR_FD;
+ }
+
+ memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
+ }
+
+ return fpvalid;
+#else
+ return 0; /* Task didn't use the fpu at all. */
+#endif
+}
+
+asmlinkage void ret_from_fork(void);
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ unsigned long unused,
+ struct task_struct *p, struct pt_regs *regs)
+{
+ struct pt_regs *childregs;
+ unsigned long long se; /* Sign extension */
+
+#ifdef CONFIG_SH_FPU
+ if(last_task_used_math == current) {
+ grab_fpu();
+ fpsave(¤t->thread.fpu.hard);
+ release_fpu();
+ last_task_used_math = NULL;
+ regs->sr |= SR_FD;
+ }
+#endif
+ /* Copy from sh version */
+ childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1;
+
+ *childregs = *regs;
+
+ if (user_mode(regs)) {
+ childregs->regs[15] = usp;
+ p->thread.uregs = childregs;
+ } else {
+ childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
+ }
+
+ childregs->regs[9] = 0; /* Set return value for child */
+ childregs->sr |= SR_FD; /* Invalidate FPU flag */
+
+ p->thread.sp = (unsigned long) childregs;
+ p->thread.pc = (unsigned long) ret_from_fork;
+
+ /*
+ * Sign extend the edited stack.
+ * Note that thread.pc and thread.pc will stay
+ * 32-bit wide and context switch must take care
+ * of NEFF sign extension.
+ */
+
+ se = childregs->regs[15];
+ se = (se & NEFF_SIGN) ? (se | NEFF_MASK) : se;
+ childregs->regs[15] = se;
+
+ return 0;
+}
+
+asmlinkage int sys_fork(unsigned long r2, unsigned long r3,
+ unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs *pregs)
+{
+ return do_fork(SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
+}
+
+asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+ unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs *pregs)
+{
+ if (!newsp)
+ newsp = pregs->regs[15];
+ return do_fork(clone_flags, newsp, pregs, 0, 0, 0);
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage int sys_vfork(unsigned long r2, unsigned long r3,
+ unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs *pregs)
+{
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(char *ufilename, char **uargv,
+ char **uenvp, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs *pregs)
+{
+ int error;
+ char *filename;
+
+ lock_kernel();
+ filename = getname((char __user *)ufilename);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ goto out;
+
+ error = do_execve(filename,
+ (char __user * __user *)uargv,
+ (char __user * __user *)uenvp,
+ pregs);
+ if (error == 0) {
+ task_lock(current);
+ current->ptrace &= ~PT_DTRACE;
+ task_unlock(current);
+ }
+ putname(filename);
+out:
+ unlock_kernel();
+ return error;
+}
+
+/*
+ * These bracket the sleeping functions..
+ */
+extern void interruptible_sleep_on(wait_queue_head_t *q);
+
+#define mid_sched ((unsigned long) interruptible_sleep_on)
+
+static int in_sh64_switch_to(unsigned long pc)
+{
+ extern char __sh64_switch_to_end;
+ /* For a sleeping task, the PC is somewhere in the middle of the function,
+ so we don't have to worry about masking the LSB off */
+ return (pc >= (unsigned long) sh64_switch_to) &&
+ (pc < (unsigned long) &__sh64_switch_to_end);
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long schedule_fp;
+ unsigned long sh64_switch_to_fp;
+ unsigned long schedule_caller_pc;
+ unsigned long pc;
+
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+
+ /*
+ * The same comment as on the Alpha applies here, too ...
+ */
+ pc = thread_saved_pc(p);
+
+#ifdef CONFIG_FRAME_POINTER
+ if (in_sh64_switch_to(pc)) {
+ sh64_switch_to_fp = (long) p->thread.sp;
+ /* r14 is saved at offset 4 in the sh64_switch_to frame */
+ schedule_fp = *(unsigned long *) (long)(sh64_switch_to_fp + 4);
+
+ /* and the caller of 'schedule' is (currently!) saved at offset 24
+ in the frame of schedule (from disasm) */
+ schedule_caller_pc = *(unsigned long *) (long)(schedule_fp + 24);
+ return schedule_caller_pc;
+ }
+#endif
+ return pc;
+}
+
+/* Provide a /proc/asids file that lists out the
+ ASIDs currently associated with the processes. (If the DM.PC register is
+ examined through the debug link, this shows ASID + PC. To make use of this,
+ the PID->ASID relationship needs to be known. This is primarily for
+ debugging.)
+ */
+
+#if defined(CONFIG_SH64_PROC_ASIDS)
+static int
+asids_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, void *data)
+{
+ int len=0;
+ struct task_struct *p;
+ read_lock(&tasklist_lock);
+ for_each_process(p) {
+ int pid = p->pid;
+ struct mm_struct *mm;
+ if (!pid) continue;
+ mm = p->mm;
+ if (mm) {
+ unsigned long asid, context;
+ context = mm->context;
+ asid = (context & 0xff);
+ len += sprintf(buf+len, "%5d : %02lx\n", pid, asid);
+ } else {
+ len += sprintf(buf+len, "%5d : (none)\n", pid);
+ }
+ }
+ read_unlock(&tasklist_lock);
+ *eof = 1;
+ return len;
+}
+
+static int __init register_proc_asids(void)
+{
+ create_proc_read_entry("asids", 0, NULL, asids_proc_info, NULL);
+ return 0;
+}
+__initcall(register_proc_asids);
+#endif
+++ /dev/null
-/*
- * 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.
- *
- * arch/sh64/kernel/process.c
- *
- * Copyright (C) 2000, 2001 Paolo Alberelli
- * Copyright (C) 2003 Paul Mundt
- * Copyright (C) 2003, 2004 Richard Curnow
- *
- * Started from SH3/4 version:
- * Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
- *
- * In turn started from i386 version:
- * Copyright (C) 1995 Linus Torvalds
- *
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/ptrace.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-
-struct task_struct *last_task_used_math = NULL;
-
-static int hlt_counter = 1;
-
-#define HARD_IDLE_TIMEOUT (HZ / 3)
-
-void disable_hlt(void)
-{
- hlt_counter++;
-}
-
-void enable_hlt(void)
-{
- hlt_counter--;
-}
-
-static int __init nohlt_setup(char *__unused)
-{
- hlt_counter = 1;
- return 1;
-}
-
-static int __init hlt_setup(char *__unused)
-{
- hlt_counter = 0;
- return 1;
-}
-
-__setup("nohlt", nohlt_setup);
-__setup("hlt", hlt_setup);
-
-static inline void hlt(void)
-{
- __asm__ __volatile__ ("sleep" : : : "memory");
-}
-
-/*
- * The idle loop on a uniprocessor SH..
- */
-void cpu_idle(void)
-{
- /* endless idle loop with no priority at all */
- while (1) {
- if (hlt_counter) {
- while (!need_resched())
- cpu_relax();
- } else {
- local_irq_disable();
- while (!need_resched()) {
- local_irq_enable();
- hlt();
- local_irq_disable();
- }
- local_irq_enable();
- }
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
-
-}
-
-void machine_restart(char * __unused)
-{
- extern void phys_stext(void);
-
- phys_stext();
-}
-
-void machine_halt(void)
-{
- for (;;);
-}
-
-void machine_power_off(void)
-{
- extern void enter_deep_standby(void);
-
- enter_deep_standby();
-}
-
-void (*pm_power_off)(void) = machine_power_off;
-EXPORT_SYMBOL(pm_power_off);
-
-void show_regs(struct pt_regs * regs)
-{
- unsigned long long ah, al, bh, bl, ch, cl;
-
- printk("\n");
-
- ah = (regs->pc) >> 32;
- al = (regs->pc) & 0xffffffff;
- bh = (regs->regs[18]) >> 32;
- bl = (regs->regs[18]) & 0xffffffff;
- ch = (regs->regs[15]) >> 32;
- cl = (regs->regs[15]) & 0xffffffff;
- printk("PC : %08Lx%08Lx LINK: %08Lx%08Lx SP : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->sr) >> 32;
- al = (regs->sr) & 0xffffffff;
- asm volatile ("getcon " __TEA ", %0" : "=r" (bh));
- asm volatile ("getcon " __TEA ", %0" : "=r" (bl));
- bh = (bh) >> 32;
- bl = (bl) & 0xffffffff;
- asm volatile ("getcon " __KCR0 ", %0" : "=r" (ch));
- asm volatile ("getcon " __KCR0 ", %0" : "=r" (cl));
- ch = (ch) >> 32;
- cl = (cl) & 0xffffffff;
- printk("SR : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[0]) >> 32;
- al = (regs->regs[0]) & 0xffffffff;
- bh = (regs->regs[1]) >> 32;
- bl = (regs->regs[1]) & 0xffffffff;
- ch = (regs->regs[2]) >> 32;
- cl = (regs->regs[2]) & 0xffffffff;
- printk("R0 : %08Lx%08Lx R1 : %08Lx%08Lx R2 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[3]) >> 32;
- al = (regs->regs[3]) & 0xffffffff;
- bh = (regs->regs[4]) >> 32;
- bl = (regs->regs[4]) & 0xffffffff;
- ch = (regs->regs[5]) >> 32;
- cl = (regs->regs[5]) & 0xffffffff;
- printk("R3 : %08Lx%08Lx R4 : %08Lx%08Lx R5 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[6]) >> 32;
- al = (regs->regs[6]) & 0xffffffff;
- bh = (regs->regs[7]) >> 32;
- bl = (regs->regs[7]) & 0xffffffff;
- ch = (regs->regs[8]) >> 32;
- cl = (regs->regs[8]) & 0xffffffff;
- printk("R6 : %08Lx%08Lx R7 : %08Lx%08Lx R8 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[9]) >> 32;
- al = (regs->regs[9]) & 0xffffffff;
- bh = (regs->regs[10]) >> 32;
- bl = (regs->regs[10]) & 0xffffffff;
- ch = (regs->regs[11]) >> 32;
- cl = (regs->regs[11]) & 0xffffffff;
- printk("R9 : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[12]) >> 32;
- al = (regs->regs[12]) & 0xffffffff;
- bh = (regs->regs[13]) >> 32;
- bl = (regs->regs[13]) & 0xffffffff;
- ch = (regs->regs[14]) >> 32;
- cl = (regs->regs[14]) & 0xffffffff;
- printk("R12 : %08Lx%08Lx R13 : %08Lx%08Lx R14 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[16]) >> 32;
- al = (regs->regs[16]) & 0xffffffff;
- bh = (regs->regs[17]) >> 32;
- bl = (regs->regs[17]) & 0xffffffff;
- ch = (regs->regs[19]) >> 32;
- cl = (regs->regs[19]) & 0xffffffff;
- printk("R16 : %08Lx%08Lx R17 : %08Lx%08Lx R19 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[20]) >> 32;
- al = (regs->regs[20]) & 0xffffffff;
- bh = (regs->regs[21]) >> 32;
- bl = (regs->regs[21]) & 0xffffffff;
- ch = (regs->regs[22]) >> 32;
- cl = (regs->regs[22]) & 0xffffffff;
- printk("R20 : %08Lx%08Lx R21 : %08Lx%08Lx R22 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[23]) >> 32;
- al = (regs->regs[23]) & 0xffffffff;
- bh = (regs->regs[24]) >> 32;
- bl = (regs->regs[24]) & 0xffffffff;
- ch = (regs->regs[25]) >> 32;
- cl = (regs->regs[25]) & 0xffffffff;
- printk("R23 : %08Lx%08Lx R24 : %08Lx%08Lx R25 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[26]) >> 32;
- al = (regs->regs[26]) & 0xffffffff;
- bh = (regs->regs[27]) >> 32;
- bl = (regs->regs[27]) & 0xffffffff;
- ch = (regs->regs[28]) >> 32;
- cl = (regs->regs[28]) & 0xffffffff;
- printk("R26 : %08Lx%08Lx R27 : %08Lx%08Lx R28 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[29]) >> 32;
- al = (regs->regs[29]) & 0xffffffff;
- bh = (regs->regs[30]) >> 32;
- bl = (regs->regs[30]) & 0xffffffff;
- ch = (regs->regs[31]) >> 32;
- cl = (regs->regs[31]) & 0xffffffff;
- printk("R29 : %08Lx%08Lx R30 : %08Lx%08Lx R31 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[32]) >> 32;
- al = (regs->regs[32]) & 0xffffffff;
- bh = (regs->regs[33]) >> 32;
- bl = (regs->regs[33]) & 0xffffffff;
- ch = (regs->regs[34]) >> 32;
- cl = (regs->regs[34]) & 0xffffffff;
- printk("R32 : %08Lx%08Lx R33 : %08Lx%08Lx R34 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[35]) >> 32;
- al = (regs->regs[35]) & 0xffffffff;
- bh = (regs->regs[36]) >> 32;
- bl = (regs->regs[36]) & 0xffffffff;
- ch = (regs->regs[37]) >> 32;
- cl = (regs->regs[37]) & 0xffffffff;
- printk("R35 : %08Lx%08Lx R36 : %08Lx%08Lx R37 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[38]) >> 32;
- al = (regs->regs[38]) & 0xffffffff;
- bh = (regs->regs[39]) >> 32;
- bl = (regs->regs[39]) & 0xffffffff;
- ch = (regs->regs[40]) >> 32;
- cl = (regs->regs[40]) & 0xffffffff;
- printk("R38 : %08Lx%08Lx R39 : %08Lx%08Lx R40 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[41]) >> 32;
- al = (regs->regs[41]) & 0xffffffff;
- bh = (regs->regs[42]) >> 32;
- bl = (regs->regs[42]) & 0xffffffff;
- ch = (regs->regs[43]) >> 32;
- cl = (regs->regs[43]) & 0xffffffff;
- printk("R41 : %08Lx%08Lx R42 : %08Lx%08Lx R43 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[44]) >> 32;
- al = (regs->regs[44]) & 0xffffffff;
- bh = (regs->regs[45]) >> 32;
- bl = (regs->regs[45]) & 0xffffffff;
- ch = (regs->regs[46]) >> 32;
- cl = (regs->regs[46]) & 0xffffffff;
- printk("R44 : %08Lx%08Lx R45 : %08Lx%08Lx R46 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[47]) >> 32;
- al = (regs->regs[47]) & 0xffffffff;
- bh = (regs->regs[48]) >> 32;
- bl = (regs->regs[48]) & 0xffffffff;
- ch = (regs->regs[49]) >> 32;
- cl = (regs->regs[49]) & 0xffffffff;
- printk("R47 : %08Lx%08Lx R48 : %08Lx%08Lx R49 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[50]) >> 32;
- al = (regs->regs[50]) & 0xffffffff;
- bh = (regs->regs[51]) >> 32;
- bl = (regs->regs[51]) & 0xffffffff;
- ch = (regs->regs[52]) >> 32;
- cl = (regs->regs[52]) & 0xffffffff;
- printk("R50 : %08Lx%08Lx R51 : %08Lx%08Lx R52 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[53]) >> 32;
- al = (regs->regs[53]) & 0xffffffff;
- bh = (regs->regs[54]) >> 32;
- bl = (regs->regs[54]) & 0xffffffff;
- ch = (regs->regs[55]) >> 32;
- cl = (regs->regs[55]) & 0xffffffff;
- printk("R53 : %08Lx%08Lx R54 : %08Lx%08Lx R55 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[56]) >> 32;
- al = (regs->regs[56]) & 0xffffffff;
- bh = (regs->regs[57]) >> 32;
- bl = (regs->regs[57]) & 0xffffffff;
- ch = (regs->regs[58]) >> 32;
- cl = (regs->regs[58]) & 0xffffffff;
- printk("R56 : %08Lx%08Lx R57 : %08Lx%08Lx R58 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[59]) >> 32;
- al = (regs->regs[59]) & 0xffffffff;
- bh = (regs->regs[60]) >> 32;
- bl = (regs->regs[60]) & 0xffffffff;
- ch = (regs->regs[61]) >> 32;
- cl = (regs->regs[61]) & 0xffffffff;
- printk("R59 : %08Lx%08Lx R60 : %08Lx%08Lx R61 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->regs[62]) >> 32;
- al = (regs->regs[62]) & 0xffffffff;
- bh = (regs->tregs[0]) >> 32;
- bl = (regs->tregs[0]) & 0xffffffff;
- ch = (regs->tregs[1]) >> 32;
- cl = (regs->tregs[1]) & 0xffffffff;
- printk("R62 : %08Lx%08Lx T0 : %08Lx%08Lx T1 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->tregs[2]) >> 32;
- al = (regs->tregs[2]) & 0xffffffff;
- bh = (regs->tregs[3]) >> 32;
- bl = (regs->tregs[3]) & 0xffffffff;
- ch = (regs->tregs[4]) >> 32;
- cl = (regs->tregs[4]) & 0xffffffff;
- printk("T2 : %08Lx%08Lx T3 : %08Lx%08Lx T4 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- ah = (regs->tregs[5]) >> 32;
- al = (regs->tregs[5]) & 0xffffffff;
- bh = (regs->tregs[6]) >> 32;
- bl = (regs->tregs[6]) & 0xffffffff;
- ch = (regs->tregs[7]) >> 32;
- cl = (regs->tregs[7]) & 0xffffffff;
- printk("T5 : %08Lx%08Lx T6 : %08Lx%08Lx T7 : %08Lx%08Lx\n",
- ah, al, bh, bl, ch, cl);
-
- /*
- * If we're in kernel mode, dump the stack too..
- */
- if (!user_mode(regs)) {
- void show_stack(struct task_struct *tsk, unsigned long *sp);
- unsigned long sp = regs->regs[15] & 0xffffffff;
- struct task_struct *tsk = get_current();
-
- tsk->thread.kregs = regs;
-
- show_stack(tsk, (unsigned long *)sp);
- }
-}
-
-struct task_struct * alloc_task_struct(void)
-{
- /* Get task descriptor pages */
- return (struct task_struct *)
- __get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE));
-}
-
-void free_task_struct(struct task_struct *p)
-{
- free_pages((unsigned long) p, get_order(THREAD_SIZE));
-}
-
-/*
- * Create a kernel thread
- */
-ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
-{
- do_exit(fn(arg));
-}
-
-/*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
- * who haven't done an "execve()") should use this: it will work within
- * a system call from a "real" process, but the process memory space will
- * not be freed until both the parent and the child have exited.
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(®s, 0, sizeof(regs));
- regs.regs[2] = (unsigned long)arg;
- regs.regs[3] = (unsigned long)fn;
-
- regs.pc = (unsigned long)kernel_thread_helper;
- regs.sr = (1 << 30);
-
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
- ®s, 0, NULL, NULL);
-}
-
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
- /* See arch/sparc/kernel/process.c for the precedent for doing this -- RPC.
-
- The SH-5 FPU save/restore approach relies on last_task_used_math
- pointing to a live task_struct. When another task tries to use the
- FPU for the 1st time, the FPUDIS trap handling (see
- arch/sh64/kernel/fpu.c) will save the existing FPU state to the
- FP regs field within last_task_used_math before re-loading the new
- task's FPU state (or initialising it if the FPU has been used
- before). So if last_task_used_math is stale, and its page has already been
- re-allocated for another use, the consequences are rather grim. Unless we
- null it here, there is no other path through which it would get safely
- nulled. */
-
-#ifdef CONFIG_SH_FPU
- if (last_task_used_math == current) {
- last_task_used_math = NULL;
- }
-#endif
-}
-
-void flush_thread(void)
-{
-
- /* Called by fs/exec.c (flush_old_exec) to remove traces of a
- * previously running executable. */
-#ifdef CONFIG_SH_FPU
- if (last_task_used_math == current) {
- last_task_used_math = NULL;
- }
- /* Force FPU state to be reinitialised after exec */
- clear_used_math();
-#endif
-
- /* if we are a kernel thread, about to change to user thread,
- * update kreg
- */
- if(current->thread.kregs==&fake_swapper_regs) {
- current->thread.kregs =
- ((struct pt_regs *)(THREAD_SIZE + (unsigned long) current) - 1);
- current->thread.uregs = current->thread.kregs;
- }
-}
-
-void release_thread(struct task_struct *dead_task)
-{
- /* do nothing */
-}
-
-/* Fill in the fpu structure for a core dump.. */
-int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
-{
-#ifdef CONFIG_SH_FPU
- int fpvalid;
- struct task_struct *tsk = current;
-
- fpvalid = !!tsk_used_math(tsk);
- if (fpvalid) {
- if (current == last_task_used_math) {
- grab_fpu();
- fpsave(&tsk->thread.fpu.hard);
- release_fpu();
- last_task_used_math = 0;
- regs->sr |= SR_FD;
- }
-
- memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
- }
-
- return fpvalid;
-#else
- return 0; /* Task didn't use the fpu at all. */
-#endif
-}
-
-asmlinkage void ret_from_fork(void);
-
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
- unsigned long unused,
- struct task_struct *p, struct pt_regs *regs)
-{
- struct pt_regs *childregs;
- unsigned long long se; /* Sign extension */
-
-#ifdef CONFIG_SH_FPU
- if(last_task_used_math == current) {
- grab_fpu();
- fpsave(¤t->thread.fpu.hard);
- release_fpu();
- last_task_used_math = NULL;
- regs->sr |= SR_FD;
- }
-#endif
- /* Copy from sh version */
- childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1;
-
- *childregs = *regs;
-
- if (user_mode(regs)) {
- childregs->regs[15] = usp;
- p->thread.uregs = childregs;
- } else {
- childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
- }
-
- childregs->regs[9] = 0; /* Set return value for child */
- childregs->sr |= SR_FD; /* Invalidate FPU flag */
-
- p->thread.sp = (unsigned long) childregs;
- p->thread.pc = (unsigned long) ret_from_fork;
-
- /*
- * Sign extend the edited stack.
- * Note that thread.pc and thread.pc will stay
- * 32-bit wide and context switch must take care
- * of NEFF sign extension.
- */
-
- se = childregs->regs[15];
- se = (se & NEFF_SIGN) ? (se | NEFF_MASK) : se;
- childregs->regs[15] = se;
-
- return 0;
-}
-
-asmlinkage int sys_fork(unsigned long r2, unsigned long r3,
- unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs *pregs)
-{
- return do_fork(SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
-}
-
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
- unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs *pregs)
-{
- if (!newsp)
- newsp = pregs->regs[15];
- return do_fork(clone_flags, newsp, pregs, 0, 0, 0);
-}
-
-/*
- * This is trivial, and on the face of it looks like it
- * could equally well be done in user mode.
- *
- * Not so, for quite unobvious reasons - register pressure.
- * In user mode vfork() cannot have a stack frame, and if
- * done by calling the "clone()" system call directly, you
- * do not have enough call-clobbered registers to hold all
- * the information you need.
- */
-asmlinkage int sys_vfork(unsigned long r2, unsigned long r3,
- unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs *pregs)
-{
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(char *ufilename, char **uargv,
- char **uenvp, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs *pregs)
-{
- int error;
- char *filename;
-
- lock_kernel();
- filename = getname((char __user *)ufilename);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
-
- error = do_execve(filename,
- (char __user * __user *)uargv,
- (char __user * __user *)uenvp,
- pregs);
- if (error == 0) {
- task_lock(current);
- current->ptrace &= ~PT_DTRACE;
- task_unlock(current);
- }
- putname(filename);
-out:
- unlock_kernel();
- return error;
-}
-
-/*
- * These bracket the sleeping functions..
- */
-extern void interruptible_sleep_on(wait_queue_head_t *q);
-
-#define mid_sched ((unsigned long) interruptible_sleep_on)
-
-static int in_sh64_switch_to(unsigned long pc)
-{
- extern char __sh64_switch_to_end;
- /* For a sleeping task, the PC is somewhere in the middle of the function,
- so we don't have to worry about masking the LSB off */
- return (pc >= (unsigned long) sh64_switch_to) &&
- (pc < (unsigned long) &__sh64_switch_to_end);
-}
-
-unsigned long get_wchan(struct task_struct *p)
-{
- unsigned long schedule_fp;
- unsigned long sh64_switch_to_fp;
- unsigned long schedule_caller_pc;
- unsigned long pc;
-
- if (!p || p == current || p->state == TASK_RUNNING)
- return 0;
-
- /*
- * The same comment as on the Alpha applies here, too ...
- */
- pc = thread_saved_pc(p);
-
-#ifdef CONFIG_FRAME_POINTER
- if (in_sh64_switch_to(pc)) {
- sh64_switch_to_fp = (long) p->thread.sp;
- /* r14 is saved at offset 4 in the sh64_switch_to frame */
- schedule_fp = *(unsigned long *) (long)(sh64_switch_to_fp + 4);
-
- /* and the caller of 'schedule' is (currently!) saved at offset 24
- in the frame of schedule (from disasm) */
- schedule_caller_pc = *(unsigned long *) (long)(schedule_fp + 24);
- return schedule_caller_pc;
- }
-#endif
- return pc;
-}
-
-/* Provide a /proc/asids file that lists out the
- ASIDs currently associated with the processes. (If the DM.PC register is
- examined through the debug link, this shows ASID + PC. To make use of this,
- the PID->ASID relationship needs to be known. This is primarily for
- debugging.)
- */
-
-#if defined(CONFIG_SH64_PROC_ASIDS)
-static int
-asids_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, void *data)
-{
- int len=0;
- struct task_struct *p;
- read_lock(&tasklist_lock);
- for_each_process(p) {
- int pid = p->pid;
- struct mm_struct *mm;
- if (!pid) continue;
- mm = p->mm;
- if (mm) {
- unsigned long asid, context;
- context = mm->context;
- asid = (context & 0xff);
- len += sprintf(buf+len, "%5d : %02lx\n", pid, asid);
- } else {
- len += sprintf(buf+len, "%5d : (none)\n", pid);
- }
- }
- read_unlock(&tasklist_lock);
- *eof = 1;
- return len;
-}
-
-static int __init register_proc_asids(void)
-{
- create_proc_read_entry("asids", 0, NULL, asids_proc_info, NULL);
- return 0;
-}
-__initcall(register_proc_asids);
-#endif