1/* MN10300 Process handling code 2 * 3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11#include <linux/module.h> 12#include <linux/errno.h> 13#include <linux/sched.h> 14#include <linux/kernel.h> 15#include <linux/mm.h> 16#include <linux/smp.h> 17#include <linux/smp_lock.h> 18#include <linux/stddef.h> 19#include <linux/unistd.h> 20#include <linux/ptrace.h> 21#include <linux/user.h> 22#include <linux/interrupt.h> 23#include <linux/delay.h> 24#include <linux/reboot.h> 25#include <linux/percpu.h> 26#include <linux/err.h> 27#include <linux/fs.h> 28#include <linux/slab.h> 29#include <asm/uaccess.h> 30#include <asm/pgtable.h> 31#include <asm/system.h> 32#include <asm/io.h> 33#include <asm/processor.h> 34#include <asm/mmu_context.h> 35#include <asm/fpu.h> 36#include <asm/reset-regs.h> 37#include <asm/gdb-stub.h> 38#include "internal.h" 39 40/* 41 * power management idle function, if any.. 42 */ 43void (*pm_idle)(void); 44EXPORT_SYMBOL(pm_idle); 45 46/* 47 * return saved PC of a blocked thread. 48 */ 49unsigned long thread_saved_pc(struct task_struct *tsk) 50{ 51 return ((unsigned long *) tsk->thread.sp)[3]; 52} 53 54/* 55 * power off function, if any 56 */ 57void (*pm_power_off)(void); 58EXPORT_SYMBOL(pm_power_off); 59 60/* 61 * we use this if we don't have any better idle routine 62 */ 63static void default_idle(void) 64{ 65 local_irq_disable(); 66 if (!need_resched()) 67 safe_halt(); 68 else 69 local_irq_enable(); 70} 71 72/* 73 * the idle thread 74 * - there's no useful work to be done, so just try to conserve power and have 75 * a low exit latency (ie sit in a loop waiting for somebody to say that 76 * they'd like to reschedule) 77 */ 78void cpu_idle(void) 79{ 80 int cpu = smp_processor_id(); 81 82 /* endless idle loop with no priority at all */ 83 for (;;) { 84 while (!need_resched()) { 85 void (*idle)(void); 86 87 smp_rmb(); 88 idle = pm_idle; 89 if (!idle) 90 idle = default_idle; 91 92 irq_stat[cpu].idle_timestamp = jiffies; 93 idle(); 94 } 95 96 preempt_enable_no_resched(); 97 schedule(); 98 preempt_disable(); 99 } 100} 101 102void release_segments(struct mm_struct *mm) 103{ 104} 105 106void machine_restart(char *cmd) 107{ 108#ifdef CONFIG_GDBSTUB 109 gdbstub_exit(0); 110#endif 111 112#ifdef mn10300_unit_hard_reset 113 mn10300_unit_hard_reset(); 114#else 115 mn10300_proc_hard_reset(); 116#endif 117} 118 119void machine_halt(void) 120{ 121#ifdef CONFIG_GDBSTUB 122 gdbstub_exit(0); 123#endif 124} 125 126void machine_power_off(void) 127{ 128#ifdef CONFIG_GDBSTUB 129 gdbstub_exit(0); 130#endif 131} 132 133void show_regs(struct pt_regs *regs) 134{ 135} 136 137/* 138 * create a kernel thread 139 */ 140int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) 141{ 142 struct pt_regs regs; 143 144 memset(®s, 0, sizeof(regs)); 145 146 regs.a2 = (unsigned long) fn; 147 regs.d2 = (unsigned long) arg; 148 regs.pc = (unsigned long) kernel_thread_helper; 149 local_save_flags(regs.epsw); 150 regs.epsw |= EPSW_IE | EPSW_IM_7; 151 152 /* Ok, create the new process.. */ 153 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, 154 NULL, NULL); 155} 156EXPORT_SYMBOL(kernel_thread); 157 158/* 159 * free current thread data structures etc.. 160 */ 161void exit_thread(void) 162{ 163 exit_fpu(); 164} 165 166void flush_thread(void) 167{ 168 flush_fpu(); 169} 170 171void release_thread(struct task_struct *dead_task) 172{ 173} 174 175/* 176 * we do not have to muck with descriptors here, that is 177 * done in switch_mm() as needed. 178 */ 179void copy_segments(struct task_struct *p, struct mm_struct *new_mm) 180{ 181} 182 183/* 184 * this gets called before we allocate a new thread and copy the current task 185 * into it so that we can store lazy state into memory 186 */ 187void prepare_to_copy(struct task_struct *tsk) 188{ 189 unlazy_fpu(tsk); 190} 191 192/* 193 * set up the kernel stack for a new thread and copy arch-specific thread 194 * control information 195 */ 196int copy_thread(unsigned long clone_flags, 197 unsigned long c_usp, unsigned long ustk_size, 198 struct task_struct *p, struct pt_regs *kregs) 199{ 200 struct pt_regs *c_uregs, *c_kregs, *uregs; 201 unsigned long c_ksp; 202 203 uregs = current->thread.uregs; 204 205 c_ksp = (unsigned long) task_stack_page(p) + THREAD_SIZE; 206 207 /* allocate the userspace exception frame and set it up */ 208 c_ksp -= sizeof(struct pt_regs); 209 c_uregs = (struct pt_regs *) c_ksp; 210 211 p->thread.uregs = c_uregs; 212 *c_uregs = *uregs; 213 c_uregs->sp = c_usp; 214 c_uregs->epsw &= ~EPSW_FE; /* my FPU */ 215 216 c_ksp -= 12; /* allocate function call ABI slack */ 217 218 /* the new TLS pointer is passed in as arg #5 to sys_clone() */ 219 if (clone_flags & CLONE_SETTLS) 220 c_uregs->e2 = __frame->d3; 221 222 /* set up the return kernel frame if called from kernel_thread() */ 223 c_kregs = c_uregs; 224 if (kregs != uregs) { 225 c_ksp -= sizeof(struct pt_regs); 226 c_kregs = (struct pt_regs *) c_ksp; 227 *c_kregs = *kregs; 228 c_kregs->sp = c_usp; 229 c_kregs->next = c_uregs; 230#ifdef CONFIG_MN10300_CURRENT_IN_E2 231 c_kregs->e2 = (unsigned long) p; /* current */ 232#endif 233 234 c_ksp -= 12; /* allocate function call ABI slack */ 235 } 236 237 /* set up things up so the scheduler can start the new task */ 238 p->thread.__frame = c_kregs; 239 p->thread.a3 = (unsigned long) c_kregs; 240 p->thread.sp = c_ksp; 241 p->thread.pc = (unsigned long) ret_from_fork; 242 p->thread.wchan = (unsigned long) ret_from_fork; 243 p->thread.usp = c_usp; 244 245 return 0; 246} 247 248/* 249 * clone a process 250 * - tlsptr is retrieved by copy_thread() from __frame->d3 251 */ 252asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, 253 int __user *parent_tidptr, int __user *child_tidptr, 254 int __user *tlsptr) 255{ 256 return do_fork(clone_flags, newsp ?: __frame->sp, __frame, 0, 257 parent_tidptr, child_tidptr); 258} 259 260asmlinkage long sys_fork(void) 261{ 262 return do_fork(SIGCHLD, __frame->sp, __frame, 0, NULL, NULL); 263} 264 265asmlinkage long sys_vfork(void) 266{ 267 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, __frame->sp, __frame, 268 0, NULL, NULL); 269} 270 271asmlinkage long sys_execve(const char __user *name, 272 const char __user *const __user *argv, 273 const char __user *const __user *envp) 274{ 275 char *filename; 276 int error; 277 278 filename = getname(name); 279 error = PTR_ERR(filename); 280 if (IS_ERR(filename)) 281 return error; 282 error = do_execve(filename, argv, envp, __frame); 283 putname(filename); 284 return error; 285} 286 287unsigned long get_wchan(struct task_struct *p) 288{ 289 return p->thread.wchan; 290} 291