1 /* 2 * OpenRISC process.c 3 * 4 * Linux architectural port borrowing liberally from similar works of 5 * others. All original copyrights apply as per the original source 6 * declaration. 7 * 8 * Modifications for the OpenRISC architecture: 9 * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> 10 * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 15 * 2 of the License, or (at your option) any later version. 16 * 17 * This file handles the architecture-dependent parts of process handling... 18 */ 19 20 #define __KERNEL_SYSCALLS__ 21 #include <stdarg.h> 22 23 #include <linux/errno.h> 24 #include <linux/sched.h> 25 #include <linux/kernel.h> 26 #include <linux/module.h> 27 #include <linux/mm.h> 28 #include <linux/stddef.h> 29 #include <linux/unistd.h> 30 #include <linux/ptrace.h> 31 #include <linux/slab.h> 32 #include <linux/elfcore.h> 33 #include <linux/interrupt.h> 34 #include <linux/delay.h> 35 #include <linux/init_task.h> 36 #include <linux/mqueue.h> 37 #include <linux/fs.h> 38 39 #include <asm/uaccess.h> 40 #include <asm/pgtable.h> 41 #include <asm/system.h> 42 #include <asm/io.h> 43 #include <asm/processor.h> 44 #include <asm/spr_defs.h> 45 46 #include <linux/smp.h> 47 48 /* 49 * Pointer to Current thread info structure. 50 * 51 * Used at user space -> kernel transitions. 52 */ 53 struct thread_info *current_thread_info_set[NR_CPUS] = { &init_thread_info, }; 54 55 void machine_restart(void) 56 { 57 printk(KERN_INFO "*** MACHINE RESTART ***\n"); 58 __asm__("l.nop 1"); 59 } 60 61 /* 62 * Similar to machine_power_off, but don't shut off power. Add code 63 * here to freeze the system for e.g. post-mortem debug purpose when 64 * possible. This halt has nothing to do with the idle halt. 65 */ 66 void machine_halt(void) 67 { 68 printk(KERN_INFO "*** MACHINE HALT ***\n"); 69 __asm__("l.nop 1"); 70 } 71 72 /* If or when software power-off is implemented, add code here. */ 73 void machine_power_off(void) 74 { 75 printk(KERN_INFO "*** MACHINE POWER OFF ***\n"); 76 __asm__("l.nop 1"); 77 } 78 79 void (*pm_power_off) (void) = machine_power_off; 80 81 /* 82 * When a process does an "exec", machine state like FPU and debug 83 * registers need to be reset. This is a hook function for that. 84 * Currently we don't have any such state to reset, so this is empty. 85 */ 86 void flush_thread(void) 87 { 88 } 89 90 void show_regs(struct pt_regs *regs) 91 { 92 extern void show_registers(struct pt_regs *regs); 93 94 /* __PHX__ cleanup this mess */ 95 show_registers(regs); 96 } 97 98 unsigned long thread_saved_pc(struct task_struct *t) 99 { 100 return (unsigned long)user_regs(t->stack)->pc; 101 } 102 103 void release_thread(struct task_struct *dead_task) 104 { 105 } 106 107 /* 108 * Copy the thread-specific (arch specific) info from the current 109 * process to the new one p 110 */ 111 extern asmlinkage void ret_from_fork(void); 112 113 int 114 copy_thread(unsigned long clone_flags, unsigned long usp, 115 unsigned long unused, struct task_struct *p, struct pt_regs *regs) 116 { 117 struct pt_regs *childregs; 118 struct pt_regs *kregs; 119 unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; 120 struct thread_info *ti; 121 unsigned long top_of_kernel_stack; 122 123 top_of_kernel_stack = sp; 124 125 p->set_child_tid = p->clear_child_tid = NULL; 126 127 /* Copy registers */ 128 /* redzone */ 129 sp -= STACK_FRAME_OVERHEAD; 130 sp -= sizeof(struct pt_regs); 131 childregs = (struct pt_regs *)sp; 132 133 /* Copy parent registers */ 134 *childregs = *regs; 135 136 if ((childregs->sr & SPR_SR_SM) == 1) { 137 /* for kernel thread, set `current_thread_info' 138 * and stackptr in new task 139 */ 140 childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; 141 childregs->gpr[10] = (unsigned long)task_thread_info(p); 142 } else { 143 childregs->sp = usp; 144 } 145 146 childregs->gpr[11] = 0; /* Result from fork() */ 147 148 /* 149 * The way this works is that at some point in the future 150 * some task will call _switch to switch to the new task. 151 * That will pop off the stack frame created below and start 152 * the new task running at ret_from_fork. The new task will 153 * do some house keeping and then return from the fork or clone 154 * system call, using the stack frame created above. 155 */ 156 /* redzone */ 157 sp -= STACK_FRAME_OVERHEAD; 158 sp -= sizeof(struct pt_regs); 159 kregs = (struct pt_regs *)sp; 160 161 ti = task_thread_info(p); 162 ti->ksp = sp; 163 164 /* kregs->sp must store the location of the 'pre-switch' kernel stack 165 * pointer... for a newly forked process, this is simply the top of 166 * the kernel stack. 167 */ 168 kregs->sp = top_of_kernel_stack; 169 kregs->gpr[3] = (unsigned long)current; /* arg to schedule_tail */ 170 kregs->gpr[10] = (unsigned long)task_thread_info(p); 171 kregs->gpr[9] = (unsigned long)ret_from_fork; 172 173 return 0; 174 } 175 176 /* 177 * Set up a thread for executing a new program 178 */ 179 void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) 180 { 181 unsigned long sr = regs->sr & ~SPR_SR_SM; 182 183 set_fs(USER_DS); 184 memset(regs->gpr, 0, sizeof(regs->gpr)); 185 186 regs->pc = pc; 187 regs->sr = sr; 188 regs->sp = sp; 189 190 /* printk("start thread, ksp = %lx\n", current_thread_info()->ksp);*/ 191 } 192 193 /* Fill in the fpu structure for a core dump. */ 194 int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpu) 195 { 196 /* TODO */ 197 return 0; 198 } 199 200 extern struct thread_info *_switch(struct thread_info *old_ti, 201 struct thread_info *new_ti); 202 203 struct task_struct *__switch_to(struct task_struct *old, 204 struct task_struct *new) 205 { 206 struct task_struct *last; 207 struct thread_info *new_ti, *old_ti; 208 unsigned long flags; 209 210 local_irq_save(flags); 211 212 /* current_set is an array of saved current pointers 213 * (one for each cpu). we need them at user->kernel transition, 214 * while we save them at kernel->user transition 215 */ 216 new_ti = new->stack; 217 old_ti = old->stack; 218 219 current_thread_info_set[smp_processor_id()] = new_ti; 220 last = (_switch(old_ti, new_ti))->task; 221 222 local_irq_restore(flags); 223 224 return last; 225 } 226 227 /* 228 * Write out registers in core dump format, as defined by the 229 * struct user_regs_struct 230 */ 231 void dump_elf_thread(elf_greg_t *dest, struct pt_regs* regs) 232 { 233 dest[0] = 0; /* r0 */ 234 memcpy(dest+1, regs->gpr+1, 31*sizeof(unsigned long)); 235 dest[32] = regs->pc; 236 dest[33] = regs->sr; 237 dest[34] = 0; 238 dest[35] = 0; 239 } 240 241 extern void _kernel_thread_helper(void); 242 243 void __noreturn kernel_thread_helper(int (*fn) (void *), void *arg) 244 { 245 do_exit(fn(arg)); 246 } 247 248 /* 249 * Create a kernel thread. 250 */ 251 int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags) 252 { 253 struct pt_regs regs; 254 255 memset(®s, 0, sizeof(regs)); 256 257 regs.gpr[20] = (unsigned long)fn; 258 regs.gpr[22] = (unsigned long)arg; 259 regs.sr = mfspr(SPR_SR); 260 regs.pc = (unsigned long)_kernel_thread_helper; 261 262 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 263 0, ®s, 0, NULL, NULL); 264 } 265 266 /* 267 * sys_execve() executes a new program. 268 */ 269 asmlinkage long _sys_execve(const char __user *name, 270 const char __user * const __user *argv, 271 const char __user * const __user *envp, 272 struct pt_regs *regs) 273 { 274 int error; 275 char *filename; 276 277 filename = getname(name); 278 error = PTR_ERR(filename); 279 280 if (IS_ERR(filename)) 281 goto out; 282 283 error = do_execve(filename, argv, envp, regs); 284 putname(filename); 285 286 out: 287 return error; 288 } 289 290 unsigned long get_wchan(struct task_struct *p) 291 { 292 /* TODO */ 293 294 return 0; 295 } 296 297 int kernel_execve(const char *filename, char *const argv[], char *const envp[]) 298 { 299 register long __res asm("r11") = __NR_execve; 300 register long __a asm("r3") = (long)(filename); 301 register long __b asm("r4") = (long)(argv); 302 register long __c asm("r5") = (long)(envp); 303 __asm__ volatile ("l.sys 1" 304 : "=r" (__res), "=r"(__a), "=r"(__b), "=r"(__c) 305 : "0"(__res), "1"(__a), "2"(__b), "3"(__c) 306 : "r6", "r7", "r8", "r12", "r13", "r15", 307 "r17", "r19", "r21", "r23", "r25", "r27", 308 "r29", "r31"); 309 __asm__ volatile ("l.nop"); 310 return __res; 311 } 312