- Kai Germaschewski: ISDN update (including Makefiles)
[davej-history.git] / arch / sparc64 / kernel / process.c
blob4534ad59b14df5b9f73829bdfded3fcb99716e80
1 /* $Id: process.c,v 1.113 2000/11/08 08:14:58 davem Exp $
2 * arch/sparc64/kernel/process.c
4 * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
6 * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7 */
9 /*
10 * This file handles the architecture-dependent parts of process handling..
13 #define __KERNEL_SYSCALLS__
14 #include <stdarg.h>
16 #include <linux/errno.h>
17 #include <linux/sched.h>
18 #include <linux/kernel.h>
19 #include <linux/mm.h>
20 #include <linux/smp.h>
21 #include <linux/smp_lock.h>
22 #include <linux/stddef.h>
23 #include <linux/unistd.h>
24 #include <linux/ptrace.h>
25 #include <linux/malloc.h>
26 #include <linux/user.h>
27 #include <linux/a.out.h>
28 #include <linux/config.h>
29 #include <linux/reboot.h>
30 #include <linux/delay.h>
32 #include <asm/oplib.h>
33 #include <asm/uaccess.h>
34 #include <asm/system.h>
35 #include <asm/page.h>
36 #include <asm/pgalloc.h>
37 #include <asm/pgtable.h>
38 #include <asm/processor.h>
39 #include <asm/pstate.h>
40 #include <asm/elf.h>
41 #include <asm/fpumacro.h>
43 /* #define VERBOSE_SHOWREGS */
45 #ifndef CONFIG_SMP
48 * the idle loop on a Sparc... ;)
50 int cpu_idle(void)
52 if (current->pid != 0)
53 return -EPERM;
55 /* endless idle loop with no priority at all */
56 current->nice = 20;
57 current->counter = -100;
58 init_idle();
60 for (;;) {
61 /* If current->need_resched is zero we should really
62 * setup for a system wakup event and execute a shutdown
63 * instruction.
65 * But this requires writing back the contents of the
66 * L2 cache etc. so implement this later. -DaveM
68 while (!current->need_resched)
69 barrier();
71 schedule();
72 check_pgt_cache();
74 return 0;
77 #else
80 * the idle loop on a UltraMultiPenguin...
82 #define idle_me_harder() (cpu_data[current->processor].idle_volume += 1)
83 #define unidle_me() (cpu_data[current->processor].idle_volume = 0)
84 int cpu_idle(void)
86 current->nice = 20;
87 current->counter = -100;
88 init_idle();
90 while(1) {
91 if (current->need_resched != 0) {
92 unidle_me();
93 schedule();
94 check_pgt_cache();
96 idle_me_harder();
98 /* The store ordering is so that IRQ handlers on
99 * other cpus see our increasing idleness for the buddy
100 * redistribution algorithm. -DaveM
102 membar("#StoreStore | #StoreLoad");
106 #endif
108 extern char reboot_command [];
110 #ifdef CONFIG_SUN_CONSOLE
111 extern void (*prom_palette)(int);
112 extern int serial_console;
113 #endif
115 void machine_halt(void)
117 sti();
118 mdelay(8);
119 cli();
120 #ifdef CONFIG_SUN_CONSOLE
121 if (!serial_console && prom_palette)
122 prom_palette (1);
123 #endif
124 prom_halt();
125 panic("Halt failed!");
128 void machine_restart(char * cmd)
130 char *p;
132 sti();
133 mdelay(8);
134 cli();
136 p = strchr (reboot_command, '\n');
137 if (p) *p = 0;
138 #ifdef CONFIG_SUN_CONSOLE
139 if (!serial_console && prom_palette)
140 prom_palette (1);
141 #endif
142 if (cmd)
143 prom_reboot(cmd);
144 if (*reboot_command)
145 prom_reboot(reboot_command);
146 prom_reboot("");
147 panic("Reboot failed!");
150 static void show_regwindow32(struct pt_regs *regs)
152 struct reg_window32 *rw;
153 struct reg_window32 r_w;
154 mm_segment_t old_fs;
156 __asm__ __volatile__ ("flushw");
157 rw = (struct reg_window32 *)((long)(unsigned)regs->u_regs[14]);
158 old_fs = get_fs();
159 set_fs (USER_DS);
160 if (copy_from_user (&r_w, rw, sizeof(r_w))) {
161 set_fs (old_fs);
162 return;
164 rw = &r_w;
165 set_fs (old_fs);
166 printk("l0: %08x l1: %08x l2: %08x l3: %08x "
167 "l4: %08x l5: %08x l6: %08x l7: %08x\n",
168 rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3],
169 rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
170 printk("i0: %08x i1: %08x i2: %08x i3: %08x "
171 "i4: %08x i5: %08x i6: %08x i7: %08x\n",
172 rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
173 rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
176 static void show_regwindow(struct pt_regs *regs)
178 struct reg_window *rw;
179 struct reg_window r_w;
180 mm_segment_t old_fs;
182 if ((regs->tstate & TSTATE_PRIV) || !(current->thread.flags & SPARC_FLAG_32BIT)) {
183 __asm__ __volatile__ ("flushw");
184 rw = (struct reg_window *)(regs->u_regs[14] + STACK_BIAS);
185 if (!(regs->tstate & TSTATE_PRIV)) {
186 old_fs = get_fs();
187 set_fs (USER_DS);
188 if (copy_from_user (&r_w, rw, sizeof(r_w))) {
189 set_fs (old_fs);
190 return;
192 rw = &r_w;
193 set_fs (old_fs);
195 } else {
196 show_regwindow32(regs);
197 return;
199 printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n",
200 rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3]);
201 printk("l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n",
202 rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
203 printk("i0: %016lx i1: %016lx i2: %016lx i3: %016lx\n",
204 rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3]);
205 printk("i4: %016lx i5: %016lx i6: %016lx i7: %016lx\n",
206 rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
209 void show_stackframe(struct sparc_stackf *sf)
211 unsigned long size;
212 unsigned long *stk;
213 int i;
215 printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n"
216 "l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n",
217 sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3],
218 sf->locals[4], sf->locals[5], sf->locals[6], sf->locals[7]);
219 printk("i0: %016lx i1: %016lx i2: %016lx i3: %016lx\n"
220 "i4: %016lx i5: %016lx fp: %016lx ret_pc: %016lx\n",
221 sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3],
222 sf->ins[4], sf->ins[5], (unsigned long)sf->fp, sf->callers_pc);
223 printk("sp: %016lx x0: %016lx x1: %016lx x2: %016lx\n"
224 "x3: %016lx x4: %016lx x5: %016lx xx: %016lx\n",
225 (unsigned long)sf->structptr, sf->xargs[0], sf->xargs[1],
226 sf->xargs[2], sf->xargs[3], sf->xargs[4], sf->xargs[5],
227 sf->xxargs[0]);
228 size = ((unsigned long)sf->fp) - ((unsigned long)sf);
229 size -= STACKFRAME_SZ;
230 stk = (unsigned long *)((unsigned long)sf + STACKFRAME_SZ);
231 i = 0;
232 do {
233 printk("s%d: %016lx\n", i++, *stk++);
234 } while ((size -= sizeof(unsigned long)));
237 void show_stackframe32(struct sparc_stackf32 *sf)
239 unsigned long size;
240 unsigned *stk;
241 int i;
243 printk("l0: %08x l1: %08x l2: %08x l3: %08x\n",
244 sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3]);
245 printk("l4: %08x l5: %08x l6: %08x l7: %08x\n",
246 sf->locals[4], sf->locals[5], sf->locals[6], sf->locals[7]);
247 printk("i0: %08x i1: %08x i2: %08x i3: %08x\n",
248 sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3]);
249 printk("i4: %08x i5: %08x fp: %08x ret_pc: %08x\n",
250 sf->ins[4], sf->ins[5], sf->fp, sf->callers_pc);
251 printk("sp: %08x x0: %08x x1: %08x x2: %08x\n"
252 "x3: %08x x4: %08x x5: %08x xx: %08x\n",
253 sf->structptr, sf->xargs[0], sf->xargs[1],
254 sf->xargs[2], sf->xargs[3], sf->xargs[4], sf->xargs[5],
255 sf->xxargs[0]);
256 size = ((unsigned long)sf->fp) - ((unsigned long)sf);
257 size -= STACKFRAME32_SZ;
258 stk = (unsigned *)((unsigned long)sf + STACKFRAME32_SZ);
259 i = 0;
260 do {
261 printk("s%d: %08x\n", i++, *stk++);
262 } while ((size -= sizeof(unsigned)));
265 #ifdef CONFIG_SMP
266 static spinlock_t regdump_lock = SPIN_LOCK_UNLOCKED;
267 #endif
269 void __show_regs(struct pt_regs * regs)
271 #ifdef CONFIG_SMP
272 unsigned long flags;
274 spin_lock_irqsave(&regdump_lock, flags);
275 printk("CPU[%d]: local_irq_count[%u] irqs_running[%d]\n",
276 smp_processor_id(),
277 local_irq_count(smp_processor_id()),
278 irqs_running());
279 #endif
280 printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate,
281 regs->tpc, regs->tnpc, regs->y);
282 printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n",
283 regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
284 regs->u_regs[3]);
285 printk("g4: %016lx g5: %016lx g6: %016lx g7: %016lx\n",
286 regs->u_regs[4], regs->u_regs[5], regs->u_regs[6],
287 regs->u_regs[7]);
288 printk("o0: %016lx o1: %016lx o2: %016lx o3: %016lx\n",
289 regs->u_regs[8], regs->u_regs[9], regs->u_regs[10],
290 regs->u_regs[11]);
291 printk("o4: %016lx o5: %016lx sp: %016lx ret_pc: %016lx\n",
292 regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
293 regs->u_regs[15]);
294 show_regwindow(regs);
295 #ifdef CONFIG_SMP
296 spin_unlock_irqrestore(&regdump_lock, flags);
297 #endif
300 #ifdef VERBOSE_SHOWREGS
301 static void idump_from_user (unsigned int *pc)
303 int i;
304 int code;
306 if((((unsigned long) pc) & 3))
307 return;
309 pc -= 3;
310 for(i = -3; i < 6; i++) {
311 get_user(code, pc);
312 printk("%c%08x%c",i?' ':'<',code,i?' ':'>');
313 pc++;
315 printk("\n");
317 #endif
319 void show_regs(struct pt_regs *regs)
321 #ifdef VERBOSE_SHOWREGS
322 extern long etrap, etraptl1;
323 #endif
324 __show_regs(regs);
325 #ifdef CONFIG_SMP
327 extern void smp_report_regs(void);
329 smp_report_regs();
331 #endif
333 #ifdef VERBOSE_SHOWREGS
334 if (regs->tpc >= &etrap && regs->tpc < &etraptl1 &&
335 regs->u_regs[14] >= (long)current - PAGE_SIZE &&
336 regs->u_regs[14] < (long)current + 6 * PAGE_SIZE) {
337 printk ("*********parent**********\n");
338 __show_regs((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ));
339 idump_from_user(((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ))->tpc);
340 printk ("*********endpar**********\n");
342 #endif
345 void show_regs32(struct pt_regs32 *regs)
347 printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr,
348 regs->pc, regs->npc, regs->y);
349 printk("g0: %08x g1: %08x g2: %08x g3: %08x ",
350 regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
351 regs->u_regs[3]);
352 printk("g4: %08x g5: %08x g6: %08x g7: %08x\n",
353 regs->u_regs[4], regs->u_regs[5], regs->u_regs[6],
354 regs->u_regs[7]);
355 printk("o0: %08x o1: %08x o2: %08x o3: %08x ",
356 regs->u_regs[8], regs->u_regs[9], regs->u_regs[10],
357 regs->u_regs[11]);
358 printk("o4: %08x o5: %08x sp: %08x ret_pc: %08x\n",
359 regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
360 regs->u_regs[15]);
363 void show_thread(struct thread_struct *thread)
365 int i;
367 #if 0
368 printk("kregs: 0x%016lx\n", (unsigned long)thread->kregs);
369 show_regs(thread->kregs);
370 #endif
371 printk("ksp: 0x%016lx\n", thread->ksp);
373 if (thread->w_saved) {
374 for (i = 0; i < NSWINS; i++) {
375 if (!thread->rwbuf_stkptrs[i])
376 continue;
377 printk("reg_window[%d]:\n", i);
378 printk("stack ptr: 0x%016lx\n", thread->rwbuf_stkptrs[i]);
380 printk("w_saved: 0x%04x\n", thread->w_saved);
383 printk("flags: 0x%08x\n", thread->flags);
384 printk("current_ds: 0x%x\n", thread->current_ds.seg);
387 /* Free current thread data structures etc.. */
388 void exit_thread(void)
390 struct thread_struct *t = &current->thread;
392 if (t->utraps) {
393 if (t->utraps[0] < 2)
394 kfree (t->utraps);
395 else
396 t->utraps[0]--;
399 /* Turn off performance counters if on. */
400 if (t->flags & SPARC_FLAG_PERFCTR) {
401 t->user_cntd0 = t->user_cntd1 = NULL;
402 t->pcr_reg = 0;
403 t->flags &= ~(SPARC_FLAG_PERFCTR);
404 write_pcr(0);
408 void flush_thread(void)
410 struct thread_struct *t = &current->thread;
412 if (current->mm) {
413 if (t->flags & SPARC_FLAG_32BIT) {
414 struct mm_struct *mm = current->mm;
415 pgd_t *pgd0 = &mm->pgd[0];
416 unsigned long pgd_cache;
418 if (pgd_none(*pgd0)) {
419 pmd_t *page = get_pmd_fast();
420 if (!page)
421 (void) get_pmd_slow(pgd0, 0);
422 else
423 pgd_set(pgd0, page);
425 pgd_cache = pgd_val(*pgd0) << 11UL;
426 __asm__ __volatile__("stxa %0, [%1] %2"
427 : /* no outputs */
428 : "r" (pgd_cache),
429 "r" (TSB_REG),
430 "i" (ASI_DMMU));
433 t->w_saved = 0;
435 /* Turn off performance counters if on. */
436 if (t->flags & SPARC_FLAG_PERFCTR) {
437 t->user_cntd0 = t->user_cntd1 = NULL;
438 t->pcr_reg = 0;
439 t->flags &= ~(SPARC_FLAG_PERFCTR);
440 write_pcr(0);
443 /* Clear FPU register state. */
444 t->fpsaved[0] = 0;
446 if (t->current_ds.seg != ASI_AIUS)
447 set_fs(USER_DS);
449 /* Init new signal delivery disposition. */
450 t->flags &= ~SPARC_FLAG_NEWSIGNALS;
453 /* It's a bit more tricky when 64-bit tasks are involved... */
454 static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
456 unsigned long fp, distance, rval;
458 if (!(current->thread.flags & SPARC_FLAG_32BIT)) {
459 csp += STACK_BIAS;
460 psp += STACK_BIAS;
461 __get_user(fp, &(((struct reg_window *)psp)->ins[6]));
462 } else
463 __get_user(fp, &(((struct reg_window32 *)psp)->ins[6]));
465 /* Now 8-byte align the stack as this is mandatory in the
466 * Sparc ABI due to how register windows work. This hides
467 * the restriction from thread libraries etc. -DaveM
469 csp &= ~7UL;
471 distance = fp - psp;
472 rval = (csp - distance);
473 if (copy_in_user(rval, psp, distance))
474 rval = 0;
475 else if (current->thread.flags & SPARC_FLAG_32BIT) {
476 if (put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6])))
477 rval = 0;
478 } else {
479 if (put_user(((u64)csp - STACK_BIAS),
480 &(((struct reg_window *)rval)->ins[6])))
481 rval = 0;
482 else
483 rval = rval - STACK_BIAS;
486 return rval;
489 /* Standard stuff. */
490 static inline void shift_window_buffer(int first_win, int last_win,
491 struct thread_struct *t)
493 int i;
495 for (i = first_win; i < last_win; i++) {
496 t->rwbuf_stkptrs[i] = t->rwbuf_stkptrs[i+1];
497 memcpy(&t->reg_window[i], &t->reg_window[i+1],
498 sizeof(struct reg_window));
502 void synchronize_user_stack(void)
504 struct thread_struct *t = &current->thread;
505 unsigned long window;
507 flush_user_windows();
508 if ((window = t->w_saved) != 0) {
509 int winsize = REGWIN_SZ;
510 int bias = 0;
512 if (t->flags & SPARC_FLAG_32BIT)
513 winsize = REGWIN32_SZ;
514 else
515 bias = STACK_BIAS;
517 window -= 1;
518 do {
519 unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
520 struct reg_window *rwin = &t->reg_window[window];
522 if (!copy_to_user((char *)sp, rwin, winsize)) {
523 shift_window_buffer(window, t->w_saved - 1, t);
524 t->w_saved--;
526 } while (window--);
530 void fault_in_user_windows(void)
532 struct thread_struct *t = &current->thread;
533 unsigned long window;
534 int winsize = REGWIN_SZ;
535 int bias = 0;
537 if (t->flags & SPARC_FLAG_32BIT)
538 winsize = REGWIN32_SZ;
539 else
540 bias = STACK_BIAS;
542 flush_user_windows();
543 window = t->w_saved;
545 if (window != 0) {
546 window -= 1;
547 do {
548 unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
549 struct reg_window *rwin = &t->reg_window[window];
551 if (copy_to_user((char *)sp, rwin, winsize))
552 goto barf;
553 } while (window--);
555 t->w_saved = 0;
556 return;
558 barf:
559 t->w_saved = window + 1;
560 do_exit(SIGILL);
563 /* Copy a Sparc thread. The fork() return value conventions
564 * under SunOS are nothing short of bletcherous:
565 * Parent --> %o0 == childs pid, %o1 == 0
566 * Child --> %o0 == parents pid, %o1 == 1
568 * NOTE: We have a separate fork kpsr/kwim because
569 * the parent could change these values between
570 * sys_fork invocation and when we reach here
571 * if the parent should sleep while trying to
572 * allocate the task_struct and kernel stack in
573 * do_fork().
575 int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
576 unsigned long unused,
577 struct task_struct *p, struct pt_regs *regs)
579 struct thread_struct *t = &p->thread;
580 char *child_trap_frame;
582 /* Calculate offset to stack_frame & pt_regs */
583 child_trap_frame = ((char *)p) + ((PAGE_SIZE << 1) - (TRACEREG_SZ+REGWIN_SZ));
584 memcpy(child_trap_frame, (((struct reg_window *)regs)-1), (TRACEREG_SZ+REGWIN_SZ));
585 t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
586 t->flags |= SPARC_FLAG_NEWCHILD;
587 t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
588 t->cwp = (regs->tstate + 1) & TSTATE_CWP;
589 t->fpsaved[0] = 0;
591 if (regs->tstate & TSTATE_PRIV) {
592 /* Special case, if we are spawning a kernel thread from
593 * a userspace task (via KMOD, NFS, or similar) we must
594 * disable performance counters in the child because the
595 * address space and protection realm are changing.
597 if (t->flags & SPARC_FLAG_PERFCTR) {
598 t->user_cntd0 = t->user_cntd1 = NULL;
599 t->pcr_reg = 0;
600 t->flags &= ~(SPARC_FLAG_PERFCTR);
602 t->kregs->u_regs[UREG_FP] = p->thread.ksp;
603 t->current_ds = KERNEL_DS;
604 flush_register_windows();
605 memcpy((void *)(t->ksp + STACK_BIAS),
606 (void *)(regs->u_regs[UREG_FP] + STACK_BIAS),
607 sizeof(struct reg_window));
608 t->kregs->u_regs[UREG_G6] = (unsigned long) p;
609 } else {
610 if (t->flags & SPARC_FLAG_32BIT) {
611 sp &= 0x00000000ffffffffUL;
612 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
614 t->kregs->u_regs[UREG_FP] = sp;
615 t->current_ds = USER_DS;
616 if (sp != regs->u_regs[UREG_FP]) {
617 unsigned long csp;
619 csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
620 if (!csp)
621 return -EFAULT;
622 t->kregs->u_regs[UREG_FP] = csp;
624 if (t->utraps)
625 t->utraps[0]++;
628 /* Set the return value for the child. */
629 t->kregs->u_regs[UREG_I0] = current->pid;
630 t->kregs->u_regs[UREG_I1] = 1;
632 /* Set the second return value for the parent. */
633 regs->u_regs[UREG_I1] = 0;
635 return 0;
639 * This is the mechanism for creating a new kernel thread.
641 * NOTE! Only a kernel-only process(ie the swapper or direct descendants
642 * who haven't done an "execve()") should use this: it will work within
643 * a system call from a "real" process, but the process memory space will
644 * not be free'd until both the parent and the child have exited.
646 pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
648 long retval;
650 /* If the parent runs before fn(arg) is called by the child,
651 * the input registers of this function can be clobbered.
652 * So we stash 'fn' and 'arg' into global registers which
653 * will not be modified by the parent.
655 __asm__ __volatile("mov %4, %%g2\n\t" /* Save FN into global */
656 "mov %5, %%g3\n\t" /* Save ARG into global */
657 "mov %1, %%g1\n\t" /* Clone syscall nr. */
658 "mov %2, %%o0\n\t" /* Clone flags. */
659 "mov 0, %%o1\n\t" /* usp arg == 0 */
660 "t 0x6d\n\t" /* Linux/Sparc clone(). */
661 "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */
662 " mov %%o0, %0\n\t"
663 "jmpl %%g2, %%o7\n\t" /* Call the function. */
664 " mov %%g3, %%o0\n\t" /* Set arg in delay. */
665 "mov %3, %%g1\n\t"
666 "t 0x6d\n\t" /* Linux/Sparc exit(). */
667 /* Notreached by child. */
668 "1:" :
669 "=r" (retval) :
670 "i" (__NR_clone), "r" (flags | CLONE_VM),
671 "i" (__NR_exit), "r" (fn), "r" (arg) :
672 "g1", "g2", "g3", "o0", "o1", "memory", "cc");
673 return retval;
677 * fill in the user structure for a core dump..
679 void dump_thread(struct pt_regs * regs, struct user * dump)
681 #if 1
682 /* Only should be used for SunOS and ancient a.out
683 * SparcLinux binaries... Fixme some day when bored.
684 * But for now at least plug the security hole :-)
686 memset(dump, 0, sizeof(struct user));
687 #else
688 unsigned long first_stack_page;
689 dump->magic = SUNOS_CORE_MAGIC;
690 dump->len = sizeof(struct user);
691 dump->regs.psr = regs->psr;
692 dump->regs.pc = regs->pc;
693 dump->regs.npc = regs->npc;
694 dump->regs.y = regs->y;
695 /* fuck me plenty */
696 memcpy(&dump->regs.regs[0], &regs->u_regs[1], (sizeof(unsigned long) * 15));
697 dump->u_tsize = (((unsigned long) current->mm->end_code) -
698 ((unsigned long) current->mm->start_code)) & ~(PAGE_SIZE - 1);
699 dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1)));
700 dump->u_dsize -= dump->u_tsize;
701 dump->u_dsize &= ~(PAGE_SIZE - 1);
702 first_stack_page = (regs->u_regs[UREG_FP] & ~(PAGE_SIZE - 1));
703 dump->u_ssize = (TASK_SIZE - first_stack_page) & ~(PAGE_SIZE - 1);
704 memcpy(&dump->fpu.fpstatus.fregs.regs[0], &current->thread.float_regs[0], (sizeof(unsigned long) * 32));
705 dump->fpu.fpstatus.fsr = current->thread.fsr;
706 dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0;
707 #endif
710 typedef struct {
711 union {
712 unsigned int pr_regs[32];
713 unsigned long pr_dregs[16];
714 } pr_fr;
715 unsigned int __unused;
716 unsigned int pr_fsr;
717 unsigned char pr_qcnt;
718 unsigned char pr_q_entrysize;
719 unsigned char pr_en;
720 unsigned int pr_q[64];
721 } elf_fpregset_t32;
724 * fill in the fpu structure for a core dump.
726 int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
728 unsigned long *kfpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
729 unsigned long fprs = current->thread.fpsaved[0];
731 if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
732 elf_fpregset_t32 *fpregs32 = (elf_fpregset_t32 *)fpregs;
734 if (fprs & FPRS_DL)
735 memcpy(&fpregs32->pr_fr.pr_regs[0], kfpregs,
736 sizeof(unsigned int) * 32);
737 else
738 memset(&fpregs32->pr_fr.pr_regs[0], 0,
739 sizeof(unsigned int) * 32);
740 fpregs32->pr_qcnt = 0;
741 fpregs32->pr_q_entrysize = 8;
742 memset(&fpregs32->pr_q[0], 0,
743 (sizeof(unsigned int) * 64));
744 if (fprs & FPRS_FEF) {
745 fpregs32->pr_fsr = (unsigned int) current->thread.xfsr[0];
746 fpregs32->pr_en = 1;
747 } else {
748 fpregs32->pr_fsr = 0;
749 fpregs32->pr_en = 0;
751 } else {
752 if(fprs & FPRS_DL)
753 memcpy(&fpregs->pr_regs[0], kfpregs,
754 sizeof(unsigned int) * 32);
755 else
756 memset(&fpregs->pr_regs[0], 0,
757 sizeof(unsigned int) * 32);
758 if(fprs & FPRS_DU)
759 memcpy(&fpregs->pr_regs[16], kfpregs+16,
760 sizeof(unsigned int) * 32);
761 else
762 memset(&fpregs->pr_regs[16], 0,
763 sizeof(unsigned int) * 32);
764 if(fprs & FPRS_FEF) {
765 fpregs->pr_fsr = current->thread.xfsr[0];
766 fpregs->pr_gsr = current->thread.gsr[0];
767 } else {
768 fpregs->pr_fsr = fpregs->pr_gsr = 0;
770 fpregs->pr_fprs = fprs;
772 return 1;
776 * sparc_execve() executes a new program after the asm stub has set
777 * things up for us. This should basically do what I want it to.
779 asmlinkage int sparc_execve(struct pt_regs *regs)
781 int error, base = 0;
782 char *filename;
784 /* User register window flush is done by entry.S */
786 /* Check for indirect call. */
787 if (regs->u_regs[UREG_G1] == 0)
788 base = 1;
790 filename = getname((char *)regs->u_regs[base + UREG_I0]);
791 error = PTR_ERR(filename);
792 if (IS_ERR(filename))
793 goto out;
794 error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1],
795 (char **) regs->u_regs[base + UREG_I2], regs);
796 putname(filename);
797 if (!error) {
798 fprs_write(0);
799 current->thread.xfsr[0] = 0;
800 current->thread.fpsaved[0] = 0;
801 regs->tstate &= ~TSTATE_PEF;
803 out:
804 return error;