1 /* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 1994 - 1999, 2000 by Ralf Baechle and others. 7 * Copyright (C) 2005, 2006 by Ralf Baechle (ralf@linux-mips.org) 8 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 9 * Copyright (C) 2004 Thiemo Seufer 10 */ 11 #include <linux/config.h> 12 #include <linux/errno.h> 13 #include <linux/module.h> 14 #include <linux/sched.h> 15 #include <linux/kernel.h> 16 #include <linux/mm.h> 17 #include <linux/stddef.h> 18 #include <linux/unistd.h> 19 #include <linux/ptrace.h> 20 #include <linux/slab.h> 21 #include <linux/mman.h> 22 #include <linux/personality.h> 23 #include <linux/sys.h> 24 #include <linux/user.h> 25 #include <linux/a.out.h> 26 #include <linux/init.h> 27 #include <linux/completion.h> 28 #include <linux/kallsyms.h> 29 30 #include <asm/abi.h> 31 #include <asm/bootinfo.h> 32 #include <asm/cpu.h> 33 #include <asm/dsp.h> 34 #include <asm/fpu.h> 35 #include <asm/pgtable.h> 36 #include <asm/system.h> 37 #include <asm/mipsregs.h> 38 #include <asm/processor.h> 39 #include <asm/uaccess.h> 40 #include <asm/io.h> 41 #include <asm/elf.h> 42 #include <asm/isadep.h> 43 #include <asm/inst.h> 44 45 /* 46 * The idle thread. There's no useful work to be done, so just try to conserve 47 * power and have a low exit latency (ie sit in a loop waiting for somebody to 48 * say that they'd like to reschedule) 49 */ 50 ATTRIB_NORET void cpu_idle(void) 51 { 52 /* endless idle loop with no priority at all */ 53 while (1) { 54 while (!need_resched()) 55 if (cpu_wait) 56 (*cpu_wait)(); 57 preempt_enable_no_resched(); 58 schedule(); 59 preempt_disable(); 60 } 61 } 62 63 extern void do_signal(struct pt_regs *regs); 64 extern void do_signal32(struct pt_regs *regs); 65 66 /* 67 * Native o32 and N64 ABI without DSP ASE 68 */ 69 extern int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, 70 int signr, sigset_t *set); 71 extern int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, 72 int signr, sigset_t *set, siginfo_t *info); 73 74 struct mips_abi mips_abi = { 75 .do_signal = do_signal, 76 #ifdef CONFIG_TRAD_SIGNALS 77 .setup_frame = setup_frame, 78 #endif 79 .setup_rt_frame = setup_rt_frame 80 }; 81 82 #ifdef CONFIG_MIPS32_O32 83 /* 84 * o32 compatibility on 64-bit kernels, without DSP ASE 85 */ 86 extern int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, 87 int signr, sigset_t *set); 88 extern int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, 89 int signr, sigset_t *set, siginfo_t *info); 90 91 struct mips_abi mips_abi_32 = { 92 .do_signal = do_signal32, 93 .setup_frame = setup_frame_32, 94 .setup_rt_frame = setup_rt_frame_32 95 }; 96 #endif /* CONFIG_MIPS32_O32 */ 97 98 #ifdef CONFIG_MIPS32_N32 99 /* 100 * N32 on 64-bit kernels, without DSP ASE 101 */ 102 extern int setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs, 103 int signr, sigset_t *set, siginfo_t *info); 104 105 struct mips_abi mips_abi_n32 = { 106 .do_signal = do_signal, 107 .setup_rt_frame = setup_rt_frame_n32 108 }; 109 #endif /* CONFIG_MIPS32_N32 */ 110 111 asmlinkage void ret_from_fork(void); 112 113 void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) 114 { 115 unsigned long status; 116 117 /* New thread loses kernel privileges. */ 118 status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|KU_MASK); 119 #ifdef CONFIG_64BIT 120 status &= ~ST0_FR; 121 status |= (current->thread.mflags & MF_32BIT_REGS) ? 0 : ST0_FR; 122 #endif 123 status |= KU_USER; 124 regs->cp0_status = status; 125 clear_used_math(); 126 lose_fpu(); 127 if (cpu_has_dsp) 128 __init_dsp(); 129 regs->cp0_epc = pc; 130 regs->regs[29] = sp; 131 current_thread_info()->addr_limit = USER_DS; 132 } 133 134 void exit_thread(void) 135 { 136 } 137 138 void flush_thread(void) 139 { 140 } 141 142 int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, 143 unsigned long unused, struct task_struct *p, struct pt_regs *regs) 144 { 145 struct thread_info *ti = task_thread_info(p); 146 struct pt_regs *childregs; 147 long childksp; 148 p->set_child_tid = p->clear_child_tid = NULL; 149 150 childksp = (unsigned long)task_stack_page(p) + THREAD_SIZE - 32; 151 152 preempt_disable(); 153 154 if (is_fpu_owner()) 155 save_fp(p); 156 157 if (cpu_has_dsp) 158 save_dsp(p); 159 160 preempt_enable(); 161 162 /* set up new TSS. */ 163 childregs = (struct pt_regs *) childksp - 1; 164 *childregs = *regs; 165 childregs->regs[7] = 0; /* Clear error flag */ 166 167 #if defined(CONFIG_BINFMT_IRIX) 168 if (current->personality != PER_LINUX) { 169 /* Under IRIX things are a little different. */ 170 childregs->regs[3] = 1; 171 regs->regs[3] = 0; 172 } 173 #endif 174 childregs->regs[2] = 0; /* Child gets zero as return value */ 175 regs->regs[2] = p->pid; 176 177 if (childregs->cp0_status & ST0_CU0) { 178 childregs->regs[28] = (unsigned long) ti; 179 childregs->regs[29] = childksp; 180 ti->addr_limit = KERNEL_DS; 181 } else { 182 childregs->regs[29] = usp; 183 ti->addr_limit = USER_DS; 184 } 185 p->thread.reg29 = (unsigned long) childregs; 186 p->thread.reg31 = (unsigned long) ret_from_fork; 187 188 /* 189 * New tasks lose permission to use the fpu. This accelerates context 190 * switching for most programs since they don't use the fpu. 191 */ 192 p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1); 193 childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); 194 clear_tsk_thread_flag(p, TIF_USEDFPU); 195 196 if (clone_flags & CLONE_SETTLS) 197 ti->tp_value = regs->regs[7]; 198 199 return 0; 200 } 201 202 /* Fill in the fpu structure for a core dump.. */ 203 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) 204 { 205 memcpy(r, ¤t->thread.fpu, sizeof(current->thread.fpu)); 206 207 return 1; 208 } 209 210 void elf_dump_regs(elf_greg_t *gp, struct pt_regs *regs) 211 { 212 int i; 213 214 for (i = 0; i < EF_R0; i++) 215 gp[i] = 0; 216 gp[EF_R0] = 0; 217 for (i = 1; i <= 31; i++) 218 gp[EF_R0 + i] = regs->regs[i]; 219 gp[EF_R26] = 0; 220 gp[EF_R27] = 0; 221 gp[EF_LO] = regs->lo; 222 gp[EF_HI] = regs->hi; 223 gp[EF_CP0_EPC] = regs->cp0_epc; 224 gp[EF_CP0_BADVADDR] = regs->cp0_badvaddr; 225 gp[EF_CP0_STATUS] = regs->cp0_status; 226 gp[EF_CP0_CAUSE] = regs->cp0_cause; 227 #ifdef EF_UNUSED0 228 gp[EF_UNUSED0] = 0; 229 #endif 230 } 231 232 int dump_task_regs (struct task_struct *tsk, elf_gregset_t *regs) 233 { 234 elf_dump_regs(*regs, task_pt_regs(tsk)); 235 return 1; 236 } 237 238 int dump_task_fpu (struct task_struct *t, elf_fpregset_t *fpr) 239 { 240 memcpy(fpr, &t->thread.fpu, sizeof(current->thread.fpu)); 241 242 return 1; 243 } 244 245 /* 246 * Create a kernel thread 247 */ 248 ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *)) 249 { 250 do_exit(fn(arg)); 251 } 252 253 long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) 254 { 255 struct pt_regs regs; 256 257 memset(®s, 0, sizeof(regs)); 258 259 regs.regs[4] = (unsigned long) arg; 260 regs.regs[5] = (unsigned long) fn; 261 regs.cp0_epc = (unsigned long) kernel_thread_helper; 262 regs.cp0_status = read_c0_status(); 263 #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) 264 regs.cp0_status &= ~(ST0_KUP | ST0_IEC); 265 regs.cp0_status |= ST0_IEP; 266 #else 267 regs.cp0_status |= ST0_EXL; 268 #endif 269 270 /* Ok, create the new process.. */ 271 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); 272 } 273 274 static struct mips_frame_info { 275 void *func; 276 unsigned long func_size; 277 int frame_size; 278 int pc_offset; 279 } *schedule_frame, mfinfo[64]; 280 static int mfinfo_num; 281 282 static int __init get_frame_info(struct mips_frame_info *info) 283 { 284 int i; 285 void *func = info->func; 286 union mips_instruction *ip = (union mips_instruction *)func; 287 info->pc_offset = -1; 288 info->frame_size = 0; 289 for (i = 0; i < 128; i++, ip++) { 290 /* if jal, jalr, jr, stop. */ 291 if (ip->j_format.opcode == jal_op || 292 (ip->r_format.opcode == spec_op && 293 (ip->r_format.func == jalr_op || 294 ip->r_format.func == jr_op))) 295 break; 296 297 if (info->func_size && i >= info->func_size / 4) 298 break; 299 if ( 300 #ifdef CONFIG_32BIT 301 ip->i_format.opcode == addiu_op && 302 #endif 303 #ifdef CONFIG_64BIT 304 ip->i_format.opcode == daddiu_op && 305 #endif 306 ip->i_format.rs == 29 && 307 ip->i_format.rt == 29) { 308 /* addiu/daddiu sp,sp,-imm */ 309 if (info->frame_size) 310 continue; 311 info->frame_size = - ip->i_format.simmediate; 312 } 313 314 if ( 315 #ifdef CONFIG_32BIT 316 ip->i_format.opcode == sw_op && 317 #endif 318 #ifdef CONFIG_64BIT 319 ip->i_format.opcode == sd_op && 320 #endif 321 ip->i_format.rs == 29 && 322 ip->i_format.rt == 31) { 323 /* sw / sd $ra, offset($sp) */ 324 if (info->pc_offset != -1) 325 continue; 326 info->pc_offset = 327 ip->i_format.simmediate / sizeof(long); 328 } 329 } 330 if (info->pc_offset == -1 || info->frame_size == 0) { 331 if (func == schedule) 332 printk("Can't analyze prologue code at %p\n", func); 333 info->pc_offset = -1; 334 info->frame_size = 0; 335 } 336 337 return 0; 338 } 339 340 static int __init frame_info_init(void) 341 { 342 int i; 343 #ifdef CONFIG_KALLSYMS 344 char *modname; 345 char namebuf[KSYM_NAME_LEN + 1]; 346 unsigned long start, size, ofs; 347 extern char __sched_text_start[], __sched_text_end[]; 348 extern char __lock_text_start[], __lock_text_end[]; 349 350 start = (unsigned long)__sched_text_start; 351 for (i = 0; i < ARRAY_SIZE(mfinfo); i++) { 352 if (start == (unsigned long)schedule) 353 schedule_frame = &mfinfo[i]; 354 if (!kallsyms_lookup(start, &size, &ofs, &modname, namebuf)) 355 break; 356 mfinfo[i].func = (void *)(start + ofs); 357 mfinfo[i].func_size = size; 358 start += size - ofs; 359 if (start >= (unsigned long)__lock_text_end) 360 break; 361 if (start == (unsigned long)__sched_text_end) 362 start = (unsigned long)__lock_text_start; 363 } 364 #else 365 mfinfo[0].func = schedule; 366 schedule_frame = &mfinfo[0]; 367 #endif 368 for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) 369 get_frame_info(&mfinfo[i]); 370 371 mfinfo_num = i; 372 return 0; 373 } 374 375 arch_initcall(frame_info_init); 376 377 /* 378 * Return saved PC of a blocked thread. 379 */ 380 unsigned long thread_saved_pc(struct task_struct *tsk) 381 { 382 struct thread_struct *t = &tsk->thread; 383 384 /* New born processes are a special case */ 385 if (t->reg31 == (unsigned long) ret_from_fork) 386 return t->reg31; 387 388 if (!schedule_frame || schedule_frame->pc_offset < 0) 389 return 0; 390 return ((unsigned long *)t->reg29)[schedule_frame->pc_offset]; 391 } 392 393 /* get_wchan - a maintenance nightmare^W^Wpain in the ass ... */ 394 unsigned long get_wchan(struct task_struct *p) 395 { 396 unsigned long stack_page; 397 unsigned long pc; 398 #ifdef CONFIG_KALLSYMS 399 unsigned long frame; 400 #endif 401 402 if (!p || p == current || p->state == TASK_RUNNING) 403 return 0; 404 405 stack_page = (unsigned long)task_stack_page(p); 406 if (!stack_page || !mfinfo_num) 407 return 0; 408 409 pc = thread_saved_pc(p); 410 #ifdef CONFIG_KALLSYMS 411 if (!in_sched_functions(pc)) 412 return pc; 413 414 frame = p->thread.reg29 + schedule_frame->frame_size; 415 do { 416 int i; 417 418 if (frame < stack_page || frame > stack_page + THREAD_SIZE - 32) 419 return 0; 420 421 for (i = mfinfo_num - 1; i >= 0; i--) { 422 if (pc >= (unsigned long) mfinfo[i].func) 423 break; 424 } 425 if (i < 0) 426 break; 427 428 pc = ((unsigned long *)frame)[mfinfo[i].pc_offset]; 429 if (!mfinfo[i].frame_size) 430 break; 431 frame += mfinfo[i].frame_size; 432 } while (in_sched_functions(pc)); 433 #endif 434 435 return pc; 436 } 437 438 EXPORT_SYMBOL(get_wchan); 439