2 * linux/arch/m68k/kernel/process.c
4 * Copyright (C) 1995 Hamish Macdonald
6 * 68060 fixes by Jesper Skov
10 * This file handles the architecture-dependent parts of process handling..
13 #include <linux/config.h>
14 #include <linux/errno.h>
15 #include <linux/sched.h>
16 #include <linux/kernel.h>
18 #include <linux/smp.h>
19 #include <linux/smp_lock.h>
20 #include <linux/stddef.h>
21 #include <linux/unistd.h>
22 #include <linux/ptrace.h>
23 #include <linux/malloc.h>
24 #include <linux/user.h>
25 #include <linux/a.out.h>
26 #include <linux/reboot.h>
28 #include <asm/uaccess.h>
29 #include <asm/system.h>
30 #include <asm/traps.h>
31 #include <asm/machdep.h>
32 #include <asm/setup.h>
33 #include <asm/pgtable.h>
36 * Initial task structure. Make this a per-architecture thing,
37 * because different architectures tend to have different
38 * alignment requirements and potentially different initial
41 static struct vm_area_struct init_mmap
= INIT_MMAP
;
42 static struct fs_struct init_fs
= INIT_FS
;
43 static struct file
* init_fd_array
[NR_OPEN
] = { NULL
, };
44 static struct files_struct init_files
= INIT_FILES
;
45 static struct signal_struct init_signals
= INIT_SIGNALS
;
46 struct mm_struct init_mm
= INIT_MM(init_mm
);
48 union task_union init_task_union
49 __attribute__((section("init_task"), aligned(2*PAGE_SIZE
)))
50 = { task
: INIT_TASK
};
52 asmlinkage
void ret_from_exception(void);
55 * The idle loop on an m68k..
57 asmlinkage
int sys_idle(void)
59 if (current
->pid
!= 0)
62 /* endless idle loop with no priority at all */
63 current
->priority
= 0;
64 current
->counter
= -100;
66 if (!current
->need_resched
)
67 #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
68 /* block out HSYNC on the atari (falcon) */
69 __asm__("stop #0x2200" : : : "cc");
70 #else /* portable version */
71 __asm__("stop #0x2000" : : : "cc");
72 #endif /* machine compilation types */
78 void machine_restart(char * __unused
)
84 void machine_halt(void)
88 void machine_power_off(void)
90 #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
91 apm_set_power_state(APM_STATE_OFF
);
95 void show_regs(struct pt_regs
* regs
)
98 printk("Format %02x Vector: %04x PC: %08lx Status: %04x\n",
99 regs
->format
, regs
->vector
, regs
->pc
, regs
->sr
);
100 printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n",
101 regs
->orig_d0
, regs
->d0
, regs
->a2
, regs
->a1
);
102 printk("A0: %08lx D5: %08lx D4: %08lx\n",
103 regs
->a0
, regs
->d5
, regs
->d4
);
104 printk("D3: %08lx D2: %08lx D1: %08lx\n",
105 regs
->d3
, regs
->d2
, regs
->d1
);
106 if (!(regs
->sr
& PS_S
))
107 printk("USP: %08lx\n", rdusp());
111 * Create a kernel thread
113 int kernel_thread(int (*fn
)(void *), void * arg
, unsigned long flags
)
122 register long retval
__asm__ ("d0");
123 register long clone_arg
__asm__ ("d1") = flags
| CLONE_VM
;
127 "trap #0\n\t" /* Linux/m68k system call */
128 "tstl %0\n\t" /* child or parent */
129 "jne 1f\n\t" /* parent - jump */
130 "lea %%sp@(-8192),%6\n\t" /* reload current */
131 "movel %3,%%sp@-\n\t" /* push argument */
132 "jsr %4@\n\t" /* call fn */
133 "movel %0,%%d1\n\t" /* pass exit value */
134 "movel %2,%0\n\t" /* exit */
138 : "0" (__NR_clone
), "i" (__NR_exit
),
139 "r" (arg
), "a" (fn
), "d" (clone_arg
), "r" (current
)
148 void flush_thread(void)
150 unsigned long zero
= 0;
152 current
->tss
.fs
= __USER_DS
;
153 asm volatile (".chip 68k/68881\n\t"
155 ".chip 68k" : : "a" (&zero
));
159 * "m68k_fork()".. By the time we get here, the
160 * non-volatile registers have also been saved on the
161 * stack. We do some ugly pointer stuff here.. (see
165 asmlinkage
int m68k_fork(struct pt_regs
*regs
)
167 return do_fork(SIGCHLD
, rdusp(), regs
);
170 asmlinkage
int m68k_vfork(struct pt_regs
*regs
)
172 return do_fork(CLONE_VFORK
| CLONE_VM
| SIGCHLD
, rdusp(), regs
);
175 asmlinkage
int m68k_clone(struct pt_regs
*regs
)
177 unsigned long clone_flags
;
180 /* syscall2 puts clone_flags in d1 and usp in d2 */
181 clone_flags
= regs
->d1
;
185 return do_fork(clone_flags
, newsp
, regs
);
188 int copy_thread(int nr
, unsigned long clone_flags
, unsigned long usp
,
189 struct task_struct
* p
, struct pt_regs
* regs
)
191 struct pt_regs
* childregs
;
192 struct switch_stack
* childstack
, *stack
;
193 unsigned long stack_offset
, *retp
;
195 stack_offset
= 2*PAGE_SIZE
- sizeof(struct pt_regs
);
196 childregs
= (struct pt_regs
*) ((unsigned long) p
+ stack_offset
);
201 retp
= ((unsigned long *) regs
);
202 stack
= ((struct switch_stack
*) retp
) - 1;
204 childstack
= ((struct switch_stack
*) childregs
) - 1;
205 *childstack
= *stack
;
206 childstack
->retpc
= (unsigned long) ret_from_exception
;
209 p
->tss
.ksp
= (unsigned long)childstack
;
211 * Must save the current SFC/DFC value, NOT the value when
212 * the parent was last descheduled - RGH 10-08-96
214 p
->tss
.fs
= get_fs().seg
;
216 /* Copy the current fpu state */
217 asm volatile ("fsave %0" : : "m" (p
->tss
.fpstate
[0]) : "memory");
219 if (!CPU_IS_060
? p
->tss
.fpstate
[0] : p
->tss
.fpstate
[2])
220 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
221 "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
222 : : "m" (p
->tss
.fp
[0]), "m" (p
->tss
.fpcntl
[0])
224 /* Restore the state in case the fpu was busy */
225 asm volatile ("frestore %0" : : "m" (p
->tss
.fpstate
[0]));
230 /* Fill in the fpu structure for a core dump. */
232 int dump_fpu (struct pt_regs
*regs
, struct user_m68kfp_struct
*fpu
)
236 /* First dump the fpu context to avoid protocol violation. */
237 asm volatile ("fsave %0" :: "m" (fpustate
[0]) : "memory");
238 if (!CPU_IS_060
? !fpustate
[0] : !fpustate
[2])
241 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
242 :: "m" (fpu
->fpcntl
[0])
244 asm volatile ("fmovemx %/fp0-%/fp7,%0"
245 :: "m" (fpu
->fpregs
[0])
251 * fill in the user structure for a core dump..
253 void dump_thread(struct pt_regs
* regs
, struct user
* dump
)
255 struct switch_stack
*sw
;
257 /* changed the size calculations - should hopefully work better. lbt */
258 dump
->magic
= CMAGIC
;
259 dump
->start_code
= 0;
260 dump
->start_stack
= rdusp() & ~(PAGE_SIZE
- 1);
261 dump
->u_tsize
= ((unsigned long) current
->mm
->end_code
) >> PAGE_SHIFT
;
262 dump
->u_dsize
= ((unsigned long) (current
->mm
->brk
+
263 (PAGE_SIZE
-1))) >> PAGE_SHIFT
;
264 dump
->u_dsize
-= dump
->u_tsize
;
267 if (dump
->start_stack
< TASK_SIZE
)
268 dump
->u_ssize
= ((unsigned long) (TASK_SIZE
- dump
->start_stack
)) >> PAGE_SHIFT
;
270 dump
->u_ar0
= (struct user_regs_struct
*)((int)&dump
->regs
- (int)dump
);
271 sw
= ((struct switch_stack
*)regs
) - 1;
272 dump
->regs
.d1
= regs
->d1
;
273 dump
->regs
.d2
= regs
->d2
;
274 dump
->regs
.d3
= regs
->d3
;
275 dump
->regs
.d4
= regs
->d4
;
276 dump
->regs
.d5
= regs
->d5
;
277 dump
->regs
.d6
= sw
->d6
;
278 dump
->regs
.d7
= sw
->d7
;
279 dump
->regs
.a0
= regs
->a0
;
280 dump
->regs
.a1
= regs
->a1
;
281 dump
->regs
.a2
= regs
->a2
;
282 dump
->regs
.a3
= sw
->a3
;
283 dump
->regs
.a4
= sw
->a4
;
284 dump
->regs
.a5
= sw
->a5
;
285 dump
->regs
.a6
= sw
->a6
;
286 dump
->regs
.d0
= regs
->d0
;
287 dump
->regs
.orig_d0
= regs
->orig_d0
;
288 dump
->regs
.stkadj
= regs
->stkadj
;
289 dump
->regs
.sr
= regs
->sr
;
290 dump
->regs
.pc
= regs
->pc
;
291 dump
->regs
.fmtvec
= (regs
->format
<< 12) | regs
->vector
;
292 /* dump floating point stuff */
293 dump
->u_fpvalid
= dump_fpu (regs
, &dump
->m68kfp
);
297 * sys_execve() executes a new program.
299 asmlinkage
int sys_execve(char *name
, char **argv
, char **envp
)
303 struct pt_regs
*regs
= (struct pt_regs
*) &name
;
306 filename
= getname(name
);
307 error
= PTR_ERR(filename
);
308 if (IS_ERR(filename
))
310 error
= do_execve(filename
, argv
, envp
, regs
);