1 /* $Id: process.c,v 1.28 2004/05/05 16:54:23 lethal Exp $ 2 * 3 * linux/arch/sh/kernel/process.c 4 * 5 * Copyright (C) 1995 Linus Torvalds 6 * 7 * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima 8 */ 9 10 /* 11 * This file handles the architecture-dependent parts of process handling.. 12 */ 13 14 #include <linux/module.h> 15 #include <linux/unistd.h> 16 #include <linux/mm.h> 17 #include <linux/elfcore.h> 18 #include <linux/slab.h> 19 #include <linux/a.out.h> 20 #include <linux/ptrace.h> 21 #include <linux/platform.h> 22 #include <linux/kallsyms.h> 23 24 #include <asm/io.h> 25 #include <asm/uaccess.h> 26 #include <asm/mmu_context.h> 27 #include <asm/elf.h> 28 #if defined(CONFIG_SH_HS7751RVOIP) 29 #include <asm/hs7751rvoip/hs7751rvoip.h> 30 #elif defined(CONFIG_SH_RTS7751R2D) 31 #include <asm/rts7751r2d/rts7751r2d.h> 32 #endif 33 34 static int hlt_counter=0; 35 36 int ubc_usercnt = 0; 37 38 #define HARD_IDLE_TIMEOUT (HZ / 3) 39 40 void disable_hlt(void) 41 { 42 hlt_counter++; 43 } 44 45 EXPORT_SYMBOL(disable_hlt); 46 47 void enable_hlt(void) 48 { 49 hlt_counter--; 50 } 51 52 EXPORT_SYMBOL(enable_hlt); 53 54 void default_idle(void) 55 { 56 /* endless idle loop with no priority at all */ 57 while (1) { 58 if (hlt_counter) { 59 while (1) 60 if (need_resched()) 61 break; 62 } else { 63 while (!need_resched()) 64 cpu_sleep(); 65 } 66 67 schedule(); 68 } 69 } 70 71 void cpu_idle(void) 72 { 73 default_idle(); 74 } 75 76 void machine_restart(char * __unused) 77 { 78 /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */ 79 asm volatile("ldc %0, sr\n\t" 80 "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001)); 81 } 82 83 void machine_halt(void) 84 { 85 #if defined(CONFIG_SH_HS7751RVOIP) 86 unsigned short value; 87 88 value = ctrl_inw(PA_OUTPORTR); 89 ctrl_outw((value & 0xffdf), PA_OUTPORTR); 90 #elif defined(CONFIG_SH_RTS7751R2D) 91 ctrl_outw(0x0001, PA_POWOFF); 92 #endif 93 while (1) 94 cpu_sleep(); 95 } 96 97 void machine_power_off(void) 98 { 99 #if defined(CONFIG_SH_HS7751RVOIP) 100 unsigned short value; 101 102 value = ctrl_inw(PA_OUTPORTR); 103 ctrl_outw((value & 0xffdf), PA_OUTPORTR); 104 #elif defined(CONFIG_SH_RTS7751R2D) 105 ctrl_outw(0x0001, PA_POWOFF); 106 #endif 107 } 108 109 void show_regs(struct pt_regs * regs) 110 { 111 printk("\n"); 112 printk("Pid : %d, Comm: %20s\n", current->pid, current->comm); 113 print_symbol("PC is at %s\n", regs->pc); 114 printk("PC : %08lx SP : %08lx SR : %08lx ", 115 regs->pc, regs->regs[15], regs->sr); 116 #ifdef CONFIG_MMU 117 printk("TEA : %08x ", ctrl_inl(MMU_TEA)); 118 #else 119 printk(" "); 120 #endif 121 printk("%s\n", print_tainted()); 122 123 printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n", 124 regs->regs[0],regs->regs[1], 125 regs->regs[2],regs->regs[3]); 126 printk("R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n", 127 regs->regs[4],regs->regs[5], 128 regs->regs[6],regs->regs[7]); 129 printk("R8 : %08lx R9 : %08lx R10 : %08lx R11 : %08lx\n", 130 regs->regs[8],regs->regs[9], 131 regs->regs[10],regs->regs[11]); 132 printk("R12 : %08lx R13 : %08lx R14 : %08lx\n", 133 regs->regs[12],regs->regs[13], 134 regs->regs[14]); 135 printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n", 136 regs->mach, regs->macl, regs->gbr, regs->pr); 137 138 /* 139 * If we're in kernel mode, dump the stack too.. 140 */ 141 if (!user_mode(regs)) { 142 extern void show_task(unsigned long *sp); 143 unsigned long sp = regs->regs[15]; 144 145 show_task((unsigned long *)sp); 146 } 147 } 148 149 /* 150 * Create a kernel thread 151 */ 152 153 /* 154 * This is the mechanism for creating a new kernel thread. 155 * 156 */ 157 extern void kernel_thread_helper(void); 158 __asm__(".align 5\n" 159 "kernel_thread_helper:\n\t" 160 "jsr @r5\n\t" 161 " nop\n\t" 162 "mov.l 1f, r1\n\t" 163 "jsr @r1\n\t" 164 " mov r0, r4\n\t" 165 ".align 2\n\t" 166 "1:.long do_exit"); 167 168 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) 169 { /* Don't use this in BL=1(cli). Or else, CPU resets! */ 170 struct pt_regs regs; 171 172 memset(®s, 0, sizeof(regs)); 173 regs.regs[4] = (unsigned long) arg; 174 regs.regs[5] = (unsigned long) fn; 175 176 regs.pc = (unsigned long) kernel_thread_helper; 177 regs.sr = (1 << 30); 178 179 /* Ok, create the new process.. */ 180 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); 181 } 182 183 /* 184 * Free current thread data structures etc.. 185 */ 186 void exit_thread(void) 187 { 188 if (current->thread.ubc_pc) { 189 current->thread.ubc_pc = 0; 190 ubc_usercnt -= 1; 191 } 192 } 193 194 void flush_thread(void) 195 { 196 #if defined(CONFIG_SH_FPU) 197 struct task_struct *tsk = current; 198 struct pt_regs *regs = (struct pt_regs *) 199 ((unsigned long)tsk->thread_info 200 + THREAD_SIZE - sizeof(struct pt_regs) 201 - sizeof(unsigned long)); 202 203 /* Forget lazy FPU state */ 204 clear_fpu(tsk, regs); 205 clear_used_math(); 206 #endif 207 } 208 209 void release_thread(struct task_struct *dead_task) 210 { 211 /* do nothing */ 212 } 213 214 /* Fill in the fpu structure for a core dump.. */ 215 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) 216 { 217 int fpvalid = 0; 218 219 #if defined(CONFIG_SH_FPU) 220 struct task_struct *tsk = current; 221 222 fpvalid = !!tsk_used_math(tsk); 223 if (fpvalid) { 224 unlazy_fpu(tsk, regs); 225 memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu)); 226 } 227 #endif 228 229 return fpvalid; 230 } 231 232 /* 233 * Capture the user space registers if the task is not running (in user space) 234 */ 235 int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) 236 { 237 struct pt_regs ptregs; 238 239 ptregs = *(struct pt_regs *) 240 ((unsigned long)tsk->thread_info + THREAD_SIZE 241 - sizeof(struct pt_regs) 242 #ifdef CONFIG_SH_DSP 243 - sizeof(struct pt_dspregs) 244 #endif 245 - sizeof(unsigned long)); 246 elf_core_copy_regs(regs, &ptregs); 247 248 return 1; 249 } 250 251 int 252 dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *fpu) 253 { 254 int fpvalid = 0; 255 256 #if defined(CONFIG_SH_FPU) 257 fpvalid = !!tsk_used_math(tsk); 258 if (fpvalid) { 259 struct pt_regs *regs = (struct pt_regs *) 260 ((unsigned long)tsk->thread_info 261 + THREAD_SIZE - sizeof(struct pt_regs) 262 - sizeof(unsigned long)); 263 unlazy_fpu(tsk, regs); 264 memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu)); 265 } 266 #endif 267 268 return fpvalid; 269 } 270 271 asmlinkage void ret_from_fork(void); 272 273 int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, 274 unsigned long unused, 275 struct task_struct *p, struct pt_regs *regs) 276 { 277 struct pt_regs *childregs; 278 #if defined(CONFIG_SH_FPU) 279 struct task_struct *tsk = current; 280 281 unlazy_fpu(tsk, regs); 282 p->thread.fpu = tsk->thread.fpu; 283 copy_to_stopped_child_used_math(p); 284 #endif 285 286 childregs = ((struct pt_regs *) 287 (THREAD_SIZE + (unsigned long) p->thread_info) 288 #ifdef CONFIG_SH_DSP 289 - sizeof(struct pt_dspregs) 290 #endif 291 - sizeof(unsigned long)) - 1; 292 *childregs = *regs; 293 294 if (user_mode(regs)) { 295 childregs->regs[15] = usp; 296 } else { 297 childregs->regs[15] = (unsigned long)p->thread_info + THREAD_SIZE; 298 } 299 if (clone_flags & CLONE_SETTLS) { 300 childregs->gbr = childregs->regs[0]; 301 } 302 childregs->regs[0] = 0; /* Set return value for child */ 303 304 p->thread.sp = (unsigned long) childregs; 305 p->thread.pc = (unsigned long) ret_from_fork; 306 307 p->thread.ubc_pc = 0; 308 309 return 0; 310 } 311 312 /* 313 * fill in the user structure for a core dump.. 314 */ 315 void dump_thread(struct pt_regs * regs, struct user * dump) 316 { 317 dump->magic = CMAGIC; 318 dump->start_code = current->mm->start_code; 319 dump->start_data = current->mm->start_data; 320 dump->start_stack = regs->regs[15] & ~(PAGE_SIZE - 1); 321 dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT; 322 dump->u_dsize = (current->mm->brk + (PAGE_SIZE-1) - dump->start_data) >> PAGE_SHIFT; 323 dump->u_ssize = (current->mm->start_stack - dump->start_stack + 324 PAGE_SIZE - 1) >> PAGE_SHIFT; 325 /* Debug registers will come here. */ 326 327 dump->regs = *regs; 328 329 dump->u_fpvalid = dump_fpu(regs, &dump->fpu); 330 } 331 332 /* Tracing by user break controller. */ 333 static void 334 ubc_set_tracing(int asid, unsigned long pc) 335 { 336 ctrl_outl(pc, UBC_BARA); 337 338 /* We don't have any ASID settings for the SH-2! */ 339 if (cpu_data->type != CPU_SH7604) 340 ctrl_outb(asid, UBC_BASRA); 341 342 ctrl_outl(0, UBC_BAMRA); 343 344 if (cpu_data->type == CPU_SH7729) { 345 ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); 346 ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); 347 } else { 348 ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA); 349 ctrl_outw(BRCR_PCBA, UBC_BRCR); 350 } 351 } 352 353 /* 354 * switch_to(x,y) should switch tasks from x to y. 355 * 356 */ 357 struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next) 358 { 359 #if defined(CONFIG_SH_FPU) 360 struct pt_regs *regs = (struct pt_regs *) 361 ((unsigned long)prev->thread_info 362 + THREAD_SIZE - sizeof(struct pt_regs) 363 - sizeof(unsigned long)); 364 unlazy_fpu(prev, regs); 365 #endif 366 367 #ifdef CONFIG_PREEMPT 368 { 369 unsigned long flags; 370 struct pt_regs *regs; 371 372 local_irq_save(flags); 373 regs = (struct pt_regs *) 374 ((unsigned long)prev->thread_info 375 + THREAD_SIZE - sizeof(struct pt_regs) 376 #ifdef CONFIG_SH_DSP 377 - sizeof(struct pt_dspregs) 378 #endif 379 - sizeof(unsigned long)); 380 if (user_mode(regs) && regs->regs[15] >= 0xc0000000) { 381 int offset = (int)regs->regs[15]; 382 383 /* Reset stack pointer: clear critical region mark */ 384 regs->regs[15] = regs->regs[1]; 385 if (regs->pc < regs->regs[0]) 386 /* Go to rewind point */ 387 regs->pc = regs->regs[0] + offset; 388 } 389 local_irq_restore(flags); 390 } 391 #endif 392 393 /* 394 * Restore the kernel mode register 395 * k7 (r7_bank1) 396 */ 397 asm volatile("ldc %0, r7_bank" 398 : /* no output */ 399 : "r" (next->thread_info)); 400 401 #ifdef CONFIG_MMU 402 /* If no tasks are using the UBC, we're done */ 403 if (ubc_usercnt == 0) 404 /* If no tasks are using the UBC, we're done */; 405 else if (next->thread.ubc_pc && next->mm) { 406 ubc_set_tracing(next->mm->context & MMU_CONTEXT_ASID_MASK, 407 next->thread.ubc_pc); 408 } else { 409 ctrl_outw(0, UBC_BBRA); 410 ctrl_outw(0, UBC_BBRB); 411 } 412 #endif 413 414 return prev; 415 } 416 417 asmlinkage int sys_fork(unsigned long r4, unsigned long r5, 418 unsigned long r6, unsigned long r7, 419 struct pt_regs regs) 420 { 421 #ifdef CONFIG_MMU 422 return do_fork(SIGCHLD, regs.regs[15], ®s, 0, NULL, NULL); 423 #else 424 /* fork almost works, enough to trick you into looking elsewhere :-( */ 425 return -EINVAL; 426 #endif 427 } 428 429 asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, 430 unsigned long parent_tidptr, 431 unsigned long child_tidptr, 432 struct pt_regs regs) 433 { 434 if (!newsp) 435 newsp = regs.regs[15]; 436 return do_fork(clone_flags, newsp, ®s, 0, 437 (int __user *)parent_tidptr, (int __user *)child_tidptr); 438 } 439 440 /* 441 * This is trivial, and on the face of it looks like it 442 * could equally well be done in user mode. 443 * 444 * Not so, for quite unobvious reasons - register pressure. 445 * In user mode vfork() cannot have a stack frame, and if 446 * done by calling the "clone()" system call directly, you 447 * do not have enough call-clobbered registers to hold all 448 * the information you need. 449 */ 450 asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, 451 unsigned long r6, unsigned long r7, 452 struct pt_regs regs) 453 { 454 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], ®s, 455 0, NULL, NULL); 456 } 457 458 /* 459 * sys_execve() executes a new program. 460 */ 461 asmlinkage int sys_execve(char *ufilename, char **uargv, 462 char **uenvp, unsigned long r7, 463 struct pt_regs regs) 464 { 465 int error; 466 char *filename; 467 468 filename = getname((char __user *)ufilename); 469 error = PTR_ERR(filename); 470 if (IS_ERR(filename)) 471 goto out; 472 473 error = do_execve(filename, 474 (char __user * __user *)uargv, 475 (char __user * __user *)uenvp, 476 ®s); 477 if (error == 0) { 478 task_lock(current); 479 current->ptrace &= ~PT_DTRACE; 480 task_unlock(current); 481 } 482 putname(filename); 483 out: 484 return error; 485 } 486 487 unsigned long get_wchan(struct task_struct *p) 488 { 489 unsigned long schedule_frame; 490 unsigned long pc; 491 492 if (!p || p == current || p->state == TASK_RUNNING) 493 return 0; 494 495 /* 496 * The same comment as on the Alpha applies here, too ... 497 */ 498 pc = thread_saved_pc(p); 499 if (in_sched_functions(pc)) { 500 schedule_frame = ((unsigned long *)(long)p->thread.sp)[1]; 501 return (unsigned long)((unsigned long *)schedule_frame)[1]; 502 } 503 return pc; 504 } 505 506 asmlinkage void break_point_trap(unsigned long r4, unsigned long r5, 507 unsigned long r6, unsigned long r7, 508 struct pt_regs regs) 509 { 510 /* Clear tracing. */ 511 ctrl_outw(0, UBC_BBRA); 512 ctrl_outw(0, UBC_BBRB); 513 current->thread.ubc_pc = 0; 514 ubc_usercnt -= 1; 515 516 force_sig(SIGTRAP, current); 517 } 518 519 asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5, 520 unsigned long r6, unsigned long r7, 521 struct pt_regs regs) 522 { 523 regs.pc -= 2; 524 force_sig(SIGTRAP, current); 525 } 526