aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/kernel')
-rw-r--r--arch/m68k/kernel/process.c377
-rw-r--r--arch/m68k/kernel/process_mm.c367
-rw-r--r--arch/m68k/kernel/process_no.c404
-rw-r--r--arch/m68k/kernel/ptrace.c306
-rw-r--r--arch/m68k/kernel/ptrace_mm.c295
-rw-r--r--arch/m68k/kernel/ptrace_no.c255
-rw-r--r--arch/m68k/kernel/setup_no.c3
-rw-r--r--arch/m68k/kernel/time.c116
-rw-r--r--arch/m68k/kernel/time_mm.c114
-rw-r--r--arch/m68k/kernel/time_no.c90
-rw-r--r--arch/m68k/kernel/vmlinux-nommu.lds200
11 files changed, 841 insertions, 1686 deletions
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 6cf4bd6e34f8..c54ef927e483 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -1,5 +1,378 @@
1/*
2 * linux/arch/m68k/kernel/process.c
3 *
4 * Copyright (C) 1995 Hamish Macdonald
5 *
6 * 68060 fixes by Jesper Skov
7 */
8
9/*
10 * This file handles the architecture-dependent parts of process handling..
11 */
12
13#include <linux/errno.h>
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/mm.h>
18#include <linux/slab.h>
19#include <linux/fs.h>
20#include <linux/smp.h>
21#include <linux/stddef.h>
22#include <linux/unistd.h>
23#include <linux/ptrace.h>
24#include <linux/user.h>
25#include <linux/reboot.h>
26#include <linux/init_task.h>
27#include <linux/mqueue.h>
28
29#include <asm/uaccess.h>
30#include <asm/system.h>
31#include <asm/traps.h>
32#include <asm/machdep.h>
33#include <asm/setup.h>
34#include <asm/pgtable.h>
35
36
37asmlinkage void ret_from_fork(void);
38
39
40/*
41 * Return saved PC from a blocked thread
42 */
43unsigned long thread_saved_pc(struct task_struct *tsk)
44{
45 struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
46 /* Check whether the thread is blocked in resume() */
47 if (in_sched_functions(sw->retpc))
48 return ((unsigned long *)sw->a6)[1];
49 else
50 return sw->retpc;
51}
52
53/*
54 * The idle loop on an m68k..
55 */
56static void default_idle(void)
57{
58 if (!need_resched())
59#if defined(MACH_ATARI_ONLY)
60 /* block out HSYNC on the atari (falcon) */
61 __asm__("stop #0x2200" : : : "cc");
62#else
63 __asm__("stop #0x2000" : : : "cc");
64#endif
65}
66
67void (*idle)(void) = default_idle;
68
69/*
70 * The idle thread. There's no useful work to be
71 * done, so just try to conserve power and have a
72 * low exit latency (ie sit in a loop waiting for
73 * somebody to say that they'd like to reschedule)
74 */
75void cpu_idle(void)
76{
77 /* endless idle loop with no priority at all */
78 while (1) {
79 while (!need_resched())
80 idle();
81 schedule_preempt_disabled();
82 }
83}
84
85void machine_restart(char * __unused)
86{
87 if (mach_reset)
88 mach_reset();
89 for (;;);
90}
91
92void machine_halt(void)
93{
94 if (mach_halt)
95 mach_halt();
96 for (;;);
97}
98
99void machine_power_off(void)
100{
101 if (mach_power_off)
102 mach_power_off();
103 for (;;);
104}
105
106void (*pm_power_off)(void) = machine_power_off;
107EXPORT_SYMBOL(pm_power_off);
108
109void show_regs(struct pt_regs * regs)
110{
111 printk("\n");
112 printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n",
113 regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
114 printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n",
115 regs->orig_d0, regs->d0, regs->a2, regs->a1);
116 printk("A0: %08lx D5: %08lx D4: %08lx\n",
117 regs->a0, regs->d5, regs->d4);
118 printk("D3: %08lx D2: %08lx D1: %08lx\n",
119 regs->d3, regs->d2, regs->d1);
120 if (!(regs->sr & PS_S))
121 printk("USP: %08lx\n", rdusp());
122}
123
124/*
125 * Create a kernel thread
126 */
127int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
128{
129 int pid;
130 mm_segment_t fs;
131
132 fs = get_fs();
133 set_fs (KERNEL_DS);
134
135 {
136 register long retval __asm__ ("d0");
137 register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
138
139 retval = __NR_clone;
140 __asm__ __volatile__
141 ("clrl %%d2\n\t"
142 "trap #0\n\t" /* Linux/m68k system call */
143 "tstl %0\n\t" /* child or parent */
144 "jne 1f\n\t" /* parent - jump */
145#ifdef CONFIG_MMU
146 "lea %%sp@(%c7),%6\n\t" /* reload current */
147 "movel %6@,%6\n\t"
148#endif
149 "movel %3,%%sp@-\n\t" /* push argument */
150 "jsr %4@\n\t" /* call fn */
151 "movel %0,%%d1\n\t" /* pass exit value */
152 "movel %2,%%d0\n\t" /* exit */
153 "trap #0\n"
154 "1:"
155 : "+d" (retval)
156 : "i" (__NR_clone), "i" (__NR_exit),
157 "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
158 "i" (-THREAD_SIZE)
159 : "d2");
160
161 pid = retval;
162 }
163
164 set_fs (fs);
165 return pid;
166}
167EXPORT_SYMBOL(kernel_thread);
168
169void flush_thread(void)
170{
171 current->thread.fs = __USER_DS;
172#ifdef CONFIG_FPU
173 if (!FPU_IS_EMU) {
174 unsigned long zero = 0;
175 asm volatile("frestore %0": :"m" (zero));
176 }
177#endif
178}
179
180/*
181 * "m68k_fork()".. By the time we get here, the
182 * non-volatile registers have also been saved on the
183 * stack. We do some ugly pointer stuff here.. (see
184 * also copy_thread)
185 */
186
187asmlinkage int m68k_fork(struct pt_regs *regs)
188{
1#ifdef CONFIG_MMU 189#ifdef CONFIG_MMU
2#include "process_mm.c" 190 return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
3#else 191#else
4#include "process_no.c" 192 return -EINVAL;
5#endif 193#endif
194}
195
196asmlinkage int m68k_vfork(struct pt_regs *regs)
197{
198 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
199 NULL, NULL);
200}
201
202asmlinkage int m68k_clone(struct pt_regs *regs)
203{
204 unsigned long clone_flags;
205 unsigned long newsp;
206 int __user *parent_tidptr, *child_tidptr;
207
208 /* syscall2 puts clone_flags in d1 and usp in d2 */
209 clone_flags = regs->d1;
210 newsp = regs->d2;
211 parent_tidptr = (int __user *)regs->d3;
212 child_tidptr = (int __user *)regs->d4;
213 if (!newsp)
214 newsp = rdusp();
215 return do_fork(clone_flags, newsp, regs, 0,
216 parent_tidptr, child_tidptr);
217}
218
219int copy_thread(unsigned long clone_flags, unsigned long usp,
220 unsigned long unused,
221 struct task_struct * p, struct pt_regs * regs)
222{
223 struct pt_regs * childregs;
224 struct switch_stack * childstack, *stack;
225 unsigned long *retp;
226
227 childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
228
229 *childregs = *regs;
230 childregs->d0 = 0;
231
232 retp = ((unsigned long *) regs);
233 stack = ((struct switch_stack *) retp) - 1;
234
235 childstack = ((struct switch_stack *) childregs) - 1;
236 *childstack = *stack;
237 childstack->retpc = (unsigned long)ret_from_fork;
238
239 p->thread.usp = usp;
240 p->thread.ksp = (unsigned long)childstack;
241
242 if (clone_flags & CLONE_SETTLS)
243 task_thread_info(p)->tp_value = regs->d5;
244
245 /*
246 * Must save the current SFC/DFC value, NOT the value when
247 * the parent was last descheduled - RGH 10-08-96
248 */
249 p->thread.fs = get_fs().seg;
250
251#ifdef CONFIG_FPU
252 if (!FPU_IS_EMU) {
253 /* Copy the current fpu state */
254 asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
255
256 if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) {
257 if (CPU_IS_COLDFIRE) {
258 asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t"
259 "fmovel %/fpiar,%1\n\t"
260 "fmovel %/fpcr,%2\n\t"
261 "fmovel %/fpsr,%3"
262 :
263 : "m" (p->thread.fp[0]),
264 "m" (p->thread.fpcntl[0]),
265 "m" (p->thread.fpcntl[1]),
266 "m" (p->thread.fpcntl[2])
267 : "memory");
268 } else {
269 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
270 "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
271 :
272 : "m" (p->thread.fp[0]),
273 "m" (p->thread.fpcntl[0])
274 : "memory");
275 }
276 }
277
278 /* Restore the state in case the fpu was busy */
279 asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
280 }
281#endif /* CONFIG_FPU */
282
283 return 0;
284}
285
286/* Fill in the fpu structure for a core dump. */
287#ifdef CONFIG_FPU
288int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
289{
290 char fpustate[216];
291
292 if (FPU_IS_EMU) {
293 int i;
294
295 memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
296 memcpy(fpu->fpregs, current->thread.fp, 96);
297 /* Convert internal fpu reg representation
298 * into long double format
299 */
300 for (i = 0; i < 24; i += 3)
301 fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
302 ((fpu->fpregs[i] & 0x0000ffff) << 16);
303 return 1;
304 }
305
306 /* First dump the fpu context to avoid protocol violation. */
307 asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
308 if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
309 return 0;
310
311 if (CPU_IS_COLDFIRE) {
312 asm volatile ("fmovel %/fpiar,%0\n\t"
313 "fmovel %/fpcr,%1\n\t"
314 "fmovel %/fpsr,%2\n\t"
315 "fmovemd %/fp0-%/fp7,%3"
316 :
317 : "m" (fpu->fpcntl[0]),
318 "m" (fpu->fpcntl[1]),
319 "m" (fpu->fpcntl[2]),
320 "m" (fpu->fpregs[0])
321 : "memory");
322 } else {
323 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
324 :
325 : "m" (fpu->fpcntl[0])
326 : "memory");
327 asm volatile ("fmovemx %/fp0-%/fp7,%0"
328 :
329 : "m" (fpu->fpregs[0])
330 : "memory");
331 }
332
333 return 1;
334}
335EXPORT_SYMBOL(dump_fpu);
336#endif /* CONFIG_FPU */
337
338/*
339 * sys_execve() executes a new program.
340 */
341asmlinkage int sys_execve(const char __user *name,
342 const char __user *const __user *argv,
343 const char __user *const __user *envp)
344{
345 int error;
346 char * filename;
347 struct pt_regs *regs = (struct pt_regs *) &name;
348
349 filename = getname(name);
350 error = PTR_ERR(filename);
351 if (IS_ERR(filename))
352 return error;
353 error = do_execve(filename, argv, envp, regs);
354 putname(filename);
355 return error;
356}
357
358unsigned long get_wchan(struct task_struct *p)
359{
360 unsigned long fp, pc;
361 unsigned long stack_page;
362 int count = 0;
363 if (!p || p == current || p->state == TASK_RUNNING)
364 return 0;
365
366 stack_page = (unsigned long)task_stack_page(p);
367 fp = ((struct switch_stack *)p->thread.ksp)->a6;
368 do {
369 if (fp < stack_page+sizeof(struct thread_info) ||
370 fp >= 8184+stack_page)
371 return 0;
372 pc = ((unsigned long *)fp)[1];
373 if (!in_sched_functions(pc))
374 return pc;
375 fp = *(unsigned long *) fp;
376 } while (count++ < 16);
377 return 0;
378}
diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c
deleted file mode 100644
index fe4186b5fc32..000000000000
--- a/arch/m68k/kernel/process_mm.c
+++ /dev/null
@@ -1,367 +0,0 @@
1/*
2 * linux/arch/m68k/kernel/process.c
3 *
4 * Copyright (C) 1995 Hamish Macdonald
5 *
6 * 68060 fixes by Jesper Skov
7 */
8
9/*
10 * This file handles the architecture-dependent parts of process handling..
11 */
12
13#include <linux/errno.h>
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/mm.h>
18#include <linux/slab.h>
19#include <linux/fs.h>
20#include <linux/smp.h>
21#include <linux/stddef.h>
22#include <linux/unistd.h>
23#include <linux/ptrace.h>
24#include <linux/user.h>
25#include <linux/reboot.h>
26#include <linux/init_task.h>
27#include <linux/mqueue.h>
28
29#include <asm/uaccess.h>
30#include <asm/system.h>
31#include <asm/traps.h>
32#include <asm/machdep.h>
33#include <asm/setup.h>
34#include <asm/pgtable.h>
35
36
37asmlinkage void ret_from_fork(void);
38
39
40/*
41 * Return saved PC from a blocked thread
42 */
43unsigned long thread_saved_pc(struct task_struct *tsk)
44{
45 struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
46 /* Check whether the thread is blocked in resume() */
47 if (in_sched_functions(sw->retpc))
48 return ((unsigned long *)sw->a6)[1];
49 else
50 return sw->retpc;
51}
52
53/*
54 * The idle loop on an m68k..
55 */
56static void default_idle(void)
57{
58 if (!need_resched())
59#if defined(MACH_ATARI_ONLY)
60 /* block out HSYNC on the atari (falcon) */
61 __asm__("stop #0x2200" : : : "cc");
62#else
63 __asm__("stop #0x2000" : : : "cc");
64#endif
65}
66
67void (*idle)(void) = default_idle;
68
69/*
70 * The idle thread. There's no useful work to be
71 * done, so just try to conserve power and have a
72 * low exit latency (ie sit in a loop waiting for
73 * somebody to say that they'd like to reschedule)
74 */
75void cpu_idle(void)
76{
77 /* endless idle loop with no priority at all */
78 while (1) {
79 while (!need_resched())
80 idle();
81 schedule_preempt_disabled();
82 }
83}
84
85void machine_restart(char * __unused)
86{
87 if (mach_reset)
88 mach_reset();
89 for (;;);
90}
91
92void machine_halt(void)
93{
94 if (mach_halt)
95 mach_halt();
96 for (;;);
97}
98
99void machine_power_off(void)
100{
101 if (mach_power_off)
102 mach_power_off();
103 for (;;);
104}
105
106void (*pm_power_off)(void) = machine_power_off;
107EXPORT_SYMBOL(pm_power_off);
108
109void show_regs(struct pt_regs * regs)
110{
111 printk("\n");
112 printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n",
113 regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
114 printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n",
115 regs->orig_d0, regs->d0, regs->a2, regs->a1);
116 printk("A0: %08lx D5: %08lx D4: %08lx\n",
117 regs->a0, regs->d5, regs->d4);
118 printk("D3: %08lx D2: %08lx D1: %08lx\n",
119 regs->d3, regs->d2, regs->d1);
120 if (!(regs->sr & PS_S))
121 printk("USP: %08lx\n", rdusp());
122}
123
124/*
125 * Create a kernel thread
126 */
127int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
128{
129 int pid;
130 mm_segment_t fs;
131
132 fs = get_fs();
133 set_fs (KERNEL_DS);
134
135 {
136 register long retval __asm__ ("d0");
137 register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
138
139 retval = __NR_clone;
140 __asm__ __volatile__
141 ("clrl %%d2\n\t"
142 "trap #0\n\t" /* Linux/m68k system call */
143 "tstl %0\n\t" /* child or parent */
144 "jne 1f\n\t" /* parent - jump */
145 "lea %%sp@(%c7),%6\n\t" /* reload current */
146 "movel %6@,%6\n\t"
147 "movel %3,%%sp@-\n\t" /* push argument */
148 "jsr %4@\n\t" /* call fn */
149 "movel %0,%%d1\n\t" /* pass exit value */
150 "movel %2,%%d0\n\t" /* exit */
151 "trap #0\n"
152 "1:"
153 : "+d" (retval)
154 : "i" (__NR_clone), "i" (__NR_exit),
155 "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
156 "i" (-THREAD_SIZE)
157 : "d2");
158
159 pid = retval;
160 }
161
162 set_fs (fs);
163 return pid;
164}
165EXPORT_SYMBOL(kernel_thread);
166
167void flush_thread(void)
168{
169 unsigned long zero = 0;
170
171 current->thread.fs = __USER_DS;
172 if (!FPU_IS_EMU)
173 asm volatile("frestore %0": :"m" (zero));
174}
175
176/*
177 * "m68k_fork()".. By the time we get here, the
178 * non-volatile registers have also been saved on the
179 * stack. We do some ugly pointer stuff here.. (see
180 * also copy_thread)
181 */
182
183asmlinkage int m68k_fork(struct pt_regs *regs)
184{
185 return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
186}
187
188asmlinkage int m68k_vfork(struct pt_regs *regs)
189{
190 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
191 NULL, NULL);
192}
193
194asmlinkage int m68k_clone(struct pt_regs *regs)
195{
196 unsigned long clone_flags;
197 unsigned long newsp;
198 int __user *parent_tidptr, *child_tidptr;
199
200 /* syscall2 puts clone_flags in d1 and usp in d2 */
201 clone_flags = regs->d1;
202 newsp = regs->d2;
203 parent_tidptr = (int __user *)regs->d3;
204 child_tidptr = (int __user *)regs->d4;
205 if (!newsp)
206 newsp = rdusp();
207 return do_fork(clone_flags, newsp, regs, 0,
208 parent_tidptr, child_tidptr);
209}
210
211int copy_thread(unsigned long clone_flags, unsigned long usp,
212 unsigned long unused,
213 struct task_struct * p, struct pt_regs * regs)
214{
215 struct pt_regs * childregs;
216 struct switch_stack * childstack, *stack;
217 unsigned long *retp;
218
219 childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
220
221 *childregs = *regs;
222 childregs->d0 = 0;
223
224 retp = ((unsigned long *) regs);
225 stack = ((struct switch_stack *) retp) - 1;
226
227 childstack = ((struct switch_stack *) childregs) - 1;
228 *childstack = *stack;
229 childstack->retpc = (unsigned long)ret_from_fork;
230
231 p->thread.usp = usp;
232 p->thread.ksp = (unsigned long)childstack;
233
234 if (clone_flags & CLONE_SETTLS)
235 task_thread_info(p)->tp_value = regs->d5;
236
237 /*
238 * Must save the current SFC/DFC value, NOT the value when
239 * the parent was last descheduled - RGH 10-08-96
240 */
241 p->thread.fs = get_fs().seg;
242
243 if (!FPU_IS_EMU) {
244 /* Copy the current fpu state */
245 asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
246
247 if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) {
248 if (CPU_IS_COLDFIRE) {
249 asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t"
250 "fmovel %/fpiar,%1\n\t"
251 "fmovel %/fpcr,%2\n\t"
252 "fmovel %/fpsr,%3"
253 :
254 : "m" (p->thread.fp[0]),
255 "m" (p->thread.fpcntl[0]),
256 "m" (p->thread.fpcntl[1]),
257 "m" (p->thread.fpcntl[2])
258 : "memory");
259 } else {
260 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
261 "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
262 :
263 : "m" (p->thread.fp[0]),
264 "m" (p->thread.fpcntl[0])
265 : "memory");
266 }
267 }
268
269 /* Restore the state in case the fpu was busy */
270 asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
271 }
272
273 return 0;
274}
275
276/* Fill in the fpu structure for a core dump. */
277
278int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
279{
280 char fpustate[216];
281
282 if (FPU_IS_EMU) {
283 int i;
284
285 memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
286 memcpy(fpu->fpregs, current->thread.fp, 96);
287 /* Convert internal fpu reg representation
288 * into long double format
289 */
290 for (i = 0; i < 24; i += 3)
291 fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
292 ((fpu->fpregs[i] & 0x0000ffff) << 16);
293 return 1;
294 }
295
296 /* First dump the fpu context to avoid protocol violation. */
297 asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
298 if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
299 return 0;
300
301 if (CPU_IS_COLDFIRE) {
302 asm volatile ("fmovel %/fpiar,%0\n\t"
303 "fmovel %/fpcr,%1\n\t"
304 "fmovel %/fpsr,%2\n\t"
305 "fmovemd %/fp0-%/fp7,%3"
306 :
307 : "m" (fpu->fpcntl[0]),
308 "m" (fpu->fpcntl[1]),
309 "m" (fpu->fpcntl[2]),
310 "m" (fpu->fpregs[0])
311 : "memory");
312 } else {
313 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
314 :
315 : "m" (fpu->fpcntl[0])
316 : "memory");
317 asm volatile ("fmovemx %/fp0-%/fp7,%0"
318 :
319 : "m" (fpu->fpregs[0])
320 : "memory");
321 }
322
323 return 1;
324}
325EXPORT_SYMBOL(dump_fpu);
326
327/*
328 * sys_execve() executes a new program.
329 */
330asmlinkage int sys_execve(const char __user *name,
331 const char __user *const __user *argv,
332 const char __user *const __user *envp)
333{
334 int error;
335 char * filename;
336 struct pt_regs *regs = (struct pt_regs *) &name;
337
338 filename = getname(name);
339 error = PTR_ERR(filename);
340 if (IS_ERR(filename))
341 return error;
342 error = do_execve(filename, argv, envp, regs);
343 putname(filename);
344 return error;
345}
346
347unsigned long get_wchan(struct task_struct *p)
348{
349 unsigned long fp, pc;
350 unsigned long stack_page;
351 int count = 0;
352 if (!p || p == current || p->state == TASK_RUNNING)
353 return 0;
354
355 stack_page = (unsigned long)task_stack_page(p);
356 fp = ((struct switch_stack *)p->thread.ksp)->a6;
357 do {
358 if (fp < stack_page+sizeof(struct thread_info) ||
359 fp >= 8184+stack_page)
360 return 0;
361 pc = ((unsigned long *)fp)[1];
362 if (!in_sched_functions(pc))
363 return pc;
364 fp = *(unsigned long *) fp;
365 } while (count++ < 16);
366 return 0;
367}
diff --git a/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c
deleted file mode 100644
index f7fe6c348595..000000000000
--- a/arch/m68k/kernel/process_no.c
+++ /dev/null
@@ -1,404 +0,0 @@
1/*
2 * linux/arch/m68knommu/kernel/process.c
3 *
4 * Copyright (C) 1995 Hamish Macdonald
5 *
6 * 68060 fixes by Jesper Skov
7 *
8 * uClinux changes
9 * Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
10 */
11
12/*
13 * This file handles the architecture-dependent parts of process handling..
14 */
15
16#include <linux/module.h>
17#include <linux/errno.h>
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/mm.h>
21#include <linux/smp.h>
22#include <linux/stddef.h>
23#include <linux/unistd.h>
24#include <linux/ptrace.h>
25#include <linux/user.h>
26#include <linux/interrupt.h>
27#include <linux/reboot.h>
28#include <linux/fs.h>
29#include <linux/slab.h>
30
31#include <asm/uaccess.h>
32#include <asm/system.h>
33#include <asm/traps.h>
34#include <asm/machdep.h>
35#include <asm/setup.h>
36#include <asm/pgtable.h>
37
38asmlinkage void ret_from_fork(void);
39
40/*
41 * The following aren't currently used.
42 */
43void (*pm_idle)(void);
44EXPORT_SYMBOL(pm_idle);
45
46void (*pm_power_off)(void);
47EXPORT_SYMBOL(pm_power_off);
48
49/*
50 * The idle loop on an m68knommu..
51 */
52static void default_idle(void)
53{
54 local_irq_disable();
55 while (!need_resched()) {
56 /* This stop will re-enable interrupts */
57 __asm__("stop #0x2000" : : : "cc");
58 local_irq_disable();
59 }
60 local_irq_enable();
61}
62
63void (*idle)(void) = default_idle;
64
65/*
66 * The idle thread. There's no useful work to be
67 * done, so just try to conserve power and have a
68 * low exit latency (ie sit in a loop waiting for
69 * somebody to say that they'd like to reschedule)
70 */
71void cpu_idle(void)
72{
73 /* endless idle loop with no priority at all */
74 while (1) {
75 idle();
76 schedule_preempt_disabled();
77 }
78}
79
80void machine_restart(char * __unused)
81{
82 if (mach_reset)
83 mach_reset();
84 for (;;);
85}
86
87void machine_halt(void)
88{
89 if (mach_halt)
90 mach_halt();
91 for (;;);
92}
93
94void machine_power_off(void)
95{
96 if (mach_power_off)
97 mach_power_off();
98 for (;;);
99}
100
101void show_regs(struct pt_regs * regs)
102{
103 printk(KERN_NOTICE "\n");
104 printk(KERN_NOTICE "Format %02x Vector: %04x PC: %08lx Status: %04x %s\n",
105 regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
106 printk(KERN_NOTICE "ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n",
107 regs->orig_d0, regs->d0, regs->a2, regs->a1);
108 printk(KERN_NOTICE "A0: %08lx D5: %08lx D4: %08lx\n",
109 regs->a0, regs->d5, regs->d4);
110 printk(KERN_NOTICE "D3: %08lx D2: %08lx D1: %08lx\n",
111 regs->d3, regs->d2, regs->d1);
112 if (!(regs->sr & PS_S))
113 printk(KERN_NOTICE "USP: %08lx\n", rdusp());
114}
115
116/*
117 * Create a kernel thread
118 */
119int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
120{
121 int retval;
122 long clone_arg = flags | CLONE_VM;
123 mm_segment_t fs;
124
125 fs = get_fs();
126 set_fs(KERNEL_DS);
127
128 __asm__ __volatile__ (
129 "movel %%sp, %%d2\n\t"
130 "movel %5, %%d1\n\t"
131 "movel %1, %%d0\n\t"
132 "trap #0\n\t"
133 "cmpl %%sp, %%d2\n\t"
134 "jeq 1f\n\t"
135 "movel %3, %%sp@-\n\t"
136 "jsr %4@\n\t"
137 "movel %2, %%d0\n\t"
138 "trap #0\n"
139 "1:\n\t"
140 "movel %%d0, %0\n"
141 : "=d" (retval)
142 : "i" (__NR_clone),
143 "i" (__NR_exit),
144 "a" (arg),
145 "a" (fn),
146 "a" (clone_arg)
147 : "cc", "%d0", "%d1", "%d2");
148
149 set_fs(fs);
150 return retval;
151}
152EXPORT_SYMBOL(kernel_thread);
153
154void flush_thread(void)
155{
156#ifdef CONFIG_FPU
157 unsigned long zero = 0;
158#endif
159
160 current->thread.fs = __USER_DS;
161#ifdef CONFIG_FPU
162 if (!FPU_IS_EMU)
163 asm volatile (".chip 68k/68881\n\t"
164 "frestore %0\n\t"
165 ".chip 68k" : : "m" (zero));
166#endif
167}
168
169/*
170 * "m68k_fork()".. By the time we get here, the
171 * non-volatile registers have also been saved on the
172 * stack. We do some ugly pointer stuff here.. (see
173 * also copy_thread)
174 */
175
176asmlinkage int m68k_fork(struct pt_regs *regs)
177{
178 /* fork almost works, enough to trick you into looking elsewhere :-( */
179 return(-EINVAL);
180}
181
182asmlinkage int m68k_vfork(struct pt_regs *regs)
183{
184 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
185}
186
187asmlinkage int m68k_clone(struct pt_regs *regs)
188{
189 unsigned long clone_flags;
190 unsigned long newsp;
191
192 /* syscall2 puts clone_flags in d1 and usp in d2 */
193 clone_flags = regs->d1;
194 newsp = regs->d2;
195 if (!newsp)
196 newsp = rdusp();
197 return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
198}
199
200int copy_thread(unsigned long clone_flags,
201 unsigned long usp, unsigned long topstk,
202 struct task_struct * p, struct pt_regs * regs)
203{
204 struct pt_regs * childregs;
205 struct switch_stack * childstack, *stack;
206 unsigned long *retp;
207
208 childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
209
210 *childregs = *regs;
211 childregs->d0 = 0;
212
213 retp = ((unsigned long *) regs);
214 stack = ((struct switch_stack *) retp) - 1;
215
216 childstack = ((struct switch_stack *) childregs) - 1;
217 *childstack = *stack;
218 childstack->retpc = (unsigned long)ret_from_fork;
219
220 p->thread.usp = usp;
221 p->thread.ksp = (unsigned long)childstack;
222
223 if (clone_flags & CLONE_SETTLS)
224 task_thread_info(p)->tp_value = regs->d5;
225
226 /*
227 * Must save the current SFC/DFC value, NOT the value when
228 * the parent was last descheduled - RGH 10-08-96
229 */
230 p->thread.fs = get_fs().seg;
231
232#ifdef CONFIG_FPU
233 if (!FPU_IS_EMU) {
234 /* Copy the current fpu state */
235 asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
236
237 if (p->thread.fpstate[0])
238 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
239 "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
240 : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
241 : "memory");
242 /* Restore the state in case the fpu was busy */
243 asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
244 }
245#endif
246
247 return 0;
248}
249
250/* Fill in the fpu structure for a core dump. */
251
252int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
253{
254#ifdef CONFIG_FPU
255 char fpustate[216];
256
257 if (FPU_IS_EMU) {
258 int i;
259
260 memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
261 memcpy(fpu->fpregs, current->thread.fp, 96);
262 /* Convert internal fpu reg representation
263 * into long double format
264 */
265 for (i = 0; i < 24; i += 3)
266 fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
267 ((fpu->fpregs[i] & 0x0000ffff) << 16);
268 return 1;
269 }
270
271 /* First dump the fpu context to avoid protocol violation. */
272 asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
273 if (!fpustate[0])
274 return 0;
275
276 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
277 :: "m" (fpu->fpcntl[0])
278 : "memory");
279 asm volatile ("fmovemx %/fp0-%/fp7,%0"
280 :: "m" (fpu->fpregs[0])
281 : "memory");
282#endif
283 return 1;
284}
285EXPORT_SYMBOL(dump_fpu);
286
287/*
288 * Generic dumping code. Used for panic and debug.
289 */
290void dump(struct pt_regs *fp)
291{
292 unsigned long *sp;
293 unsigned char *tp;
294 int i;
295
296 printk(KERN_EMERG "\nCURRENT PROCESS:\n\n");
297 printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid);
298
299 if (current->mm) {
300 printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
301 (int) current->mm->start_code,
302 (int) current->mm->end_code,
303 (int) current->mm->start_data,
304 (int) current->mm->end_data,
305 (int) current->mm->end_data,
306 (int) current->mm->brk);
307 printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n",
308 (int) current->mm->start_stack,
309 (int)(((unsigned long) current) + THREAD_SIZE));
310 }
311
312 printk(KERN_EMERG "PC: %08lx\n", fp->pc);
313 printk(KERN_EMERG "SR: %08lx SP: %08lx\n", (long) fp->sr, (long) fp);
314 printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
315 fp->d0, fp->d1, fp->d2, fp->d3);
316 printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
317 fp->d4, fp->d5, fp->a0, fp->a1);
318 printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %p\n",
319 (unsigned int) rdusp(), fp);
320
321 printk(KERN_EMERG "\nCODE:");
322 tp = ((unsigned char *) fp->pc) - 0x20;
323 for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) {
324 if ((i % 0x10) == 0)
325 printk(KERN_EMERG "%p: ", tp + i);
326 printk("%08x ", (int) *sp++);
327 }
328 printk(KERN_EMERG "\n");
329
330 printk(KERN_EMERG "KERNEL STACK:");
331 tp = ((unsigned char *) fp) - 0x40;
332 for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
333 if ((i % 0x10) == 0)
334 printk(KERN_EMERG "%p: ", tp + i);
335 printk("%08x ", (int) *sp++);
336 }
337 printk(KERN_EMERG "\n");
338
339 printk(KERN_EMERG "USER STACK:");
340 tp = (unsigned char *) (rdusp() - 0x10);
341 for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
342 if ((i % 0x10) == 0)
343 printk(KERN_EMERG "%p: ", tp + i);
344 printk("%08x ", (int) *sp++);
345 }
346 printk(KERN_EMERG "\n");
347}
348
349/*
350 * sys_execve() executes a new program.
351 */
352asmlinkage int sys_execve(const char *name,
353 const char *const *argv,
354 const char *const *envp)
355{
356 int error;
357 char * filename;
358 struct pt_regs *regs = (struct pt_regs *) &name;
359
360 filename = getname(name);
361 error = PTR_ERR(filename);
362 if (IS_ERR(filename))
363 return error;
364 error = do_execve(filename, argv, envp, regs);
365 putname(filename);
366 return error;
367}
368
369unsigned long get_wchan(struct task_struct *p)
370{
371 unsigned long fp, pc;
372 unsigned long stack_page;
373 int count = 0;
374 if (!p || p == current || p->state == TASK_RUNNING)
375 return 0;
376
377 stack_page = (unsigned long)p;
378 fp = ((struct switch_stack *)p->thread.ksp)->a6;
379 do {
380 if (fp < stack_page+sizeof(struct thread_info) ||
381 fp >= THREAD_SIZE-8+stack_page)
382 return 0;
383 pc = ((unsigned long *)fp)[1];
384 if (!in_sched_functions(pc))
385 return pc;
386 fp = *(unsigned long *) fp;
387 } while (count++ < 16);
388 return 0;
389}
390
391/*
392 * Return saved PC of a blocked thread.
393 */
394unsigned long thread_saved_pc(struct task_struct *tsk)
395{
396 struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
397
398 /* Check whether the thread is blocked in resume() */
399 if (in_sched_functions(sw->retpc))
400 return ((unsigned long *)sw->a6)[1];
401 else
402 return sw->retpc;
403}
404
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 07a417550e94..149a05f8b9ee 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -1,5 +1,305 @@
1/*
2 * linux/arch/m68k/kernel/ptrace.c
3 *
4 * Copyright (C) 1994 by Hamish Macdonald
5 * Taken from linux/kernel/ptrace.c and modified for M680x0.
6 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
7 *
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of
10 * this archive for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <linux/smp.h>
17#include <linux/errno.h>
18#include <linux/ptrace.h>
19#include <linux/user.h>
20#include <linux/signal.h>
21#include <linux/tracehook.h>
22
23#include <asm/uaccess.h>
24#include <asm/page.h>
25#include <asm/pgtable.h>
26#include <asm/system.h>
27#include <asm/processor.h>
28
29/*
30 * does not yet catch signals sent when the child dies.
31 * in exit.c or in signal.c.
32 */
33
34/* determines which bits in the SR the user has access to. */
35/* 1 = access 0 = no access */
36#define SR_MASK 0x001f
37
38/* sets the trace bits. */
39#define TRACE_BITS 0xC000
40#define T1_BIT 0x8000
41#define T0_BIT 0x4000
42
43/* Find the stack offset for a register, relative to thread.esp0. */
44#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
45#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
46 - sizeof(struct switch_stack))
47/* Mapping from PT_xxx to the stack offset at which the register is
48 saved. Notice that usp has no stack-slot and needs to be treated
49 specially (see get_reg/put_reg below). */
50static const int regoff[] = {
51 [0] = PT_REG(d1),
52 [1] = PT_REG(d2),
53 [2] = PT_REG(d3),
54 [3] = PT_REG(d4),
55 [4] = PT_REG(d5),
56 [5] = SW_REG(d6),
57 [6] = SW_REG(d7),
58 [7] = PT_REG(a0),
59 [8] = PT_REG(a1),
60 [9] = PT_REG(a2),
61 [10] = SW_REG(a3),
62 [11] = SW_REG(a4),
63 [12] = SW_REG(a5),
64 [13] = SW_REG(a6),
65 [14] = PT_REG(d0),
66 [15] = -1,
67 [16] = PT_REG(orig_d0),
68 [17] = PT_REG(sr),
69 [18] = PT_REG(pc),
70};
71
72/*
73 * Get contents of register REGNO in task TASK.
74 */
75static inline long get_reg(struct task_struct *task, int regno)
76{
77 unsigned long *addr;
78
79 if (regno == PT_USP)
80 addr = &task->thread.usp;
81 else if (regno < ARRAY_SIZE(regoff))
82 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
83 else
84 return 0;
85 /* Need to take stkadj into account. */
86 if (regno == PT_SR || regno == PT_PC) {
87 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
88 addr = (unsigned long *) ((unsigned long)addr + stkadj);
89 /* The sr is actually a 16 bit register. */
90 if (regno == PT_SR)
91 return *(unsigned short *)addr;
92 }
93 return *addr;
94}
95
96/*
97 * Write contents of register REGNO in task TASK.
98 */
99static inline int put_reg(struct task_struct *task, int regno,
100 unsigned long data)
101{
102 unsigned long *addr;
103
104 if (regno == PT_USP)
105 addr = &task->thread.usp;
106 else if (regno < ARRAY_SIZE(regoff))
107 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
108 else
109 return -1;
110 /* Need to take stkadj into account. */
111 if (regno == PT_SR || regno == PT_PC) {
112 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
113 addr = (unsigned long *) ((unsigned long)addr + stkadj);
114 /* The sr is actually a 16 bit register. */
115 if (regno == PT_SR) {
116 *(unsigned short *)addr = data;
117 return 0;
118 }
119 }
120 *addr = data;
121 return 0;
122}
123
124/*
125 * Make sure the single step bit is not set.
126 */
127static inline void singlestep_disable(struct task_struct *child)
128{
129 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
130 put_reg(child, PT_SR, tmp);
131 clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
132}
133
134/*
135 * Called by kernel/ptrace.c when detaching..
136 */
137void ptrace_disable(struct task_struct *child)
138{
139 singlestep_disable(child);
140}
141
142void user_enable_single_step(struct task_struct *child)
143{
144 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
145 put_reg(child, PT_SR, tmp | T1_BIT);
146 set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
147}
148
1#ifdef CONFIG_MMU 149#ifdef CONFIG_MMU
2#include "ptrace_mm.c" 150void user_enable_block_step(struct task_struct *child)
3#else 151{
4#include "ptrace_no.c" 152 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
153 put_reg(child, PT_SR, tmp | T0_BIT);
154}
5#endif 155#endif
156
157void user_disable_single_step(struct task_struct *child)
158{
159 singlestep_disable(child);
160}
161
162long arch_ptrace(struct task_struct *child, long request,
163 unsigned long addr, unsigned long data)
164{
165 unsigned long tmp;
166 int i, ret = 0;
167 int regno = addr >> 2; /* temporary hack. */
168 unsigned long __user *datap = (unsigned long __user *) data;
169
170 switch (request) {
171 /* read the word at location addr in the USER area. */
172 case PTRACE_PEEKUSR:
173 if (addr & 3)
174 goto out_eio;
175
176 if (regno >= 0 && regno < 19) {
177 tmp = get_reg(child, regno);
178 } else if (regno >= 21 && regno < 49) {
179 tmp = child->thread.fp[regno - 21];
180 /* Convert internal fpu reg representation
181 * into long double format
182 */
183 if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
184 tmp = ((tmp & 0xffff0000) << 15) |
185 ((tmp & 0x0000ffff) << 16);
186#ifndef CONFIG_MMU
187 } else if (regno == 49) {
188 tmp = child->mm->start_code;
189 } else if (regno == 50) {
190 tmp = child->mm->start_data;
191 } else if (regno == 51) {
192 tmp = child->mm->end_code;
193#endif
194 } else
195 goto out_eio;
196 ret = put_user(tmp, datap);
197 break;
198
199 case PTRACE_POKEUSR:
200 /* write the word at location addr in the USER area */
201 if (addr & 3)
202 goto out_eio;
203
204 if (regno == PT_SR) {
205 data &= SR_MASK;
206 data |= get_reg(child, PT_SR) & ~SR_MASK;
207 }
208 if (regno >= 0 && regno < 19) {
209 if (put_reg(child, regno, data))
210 goto out_eio;
211 } else if (regno >= 21 && regno < 48) {
212 /* Convert long double format
213 * into internal fpu reg representation
214 */
215 if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
216 data <<= 15;
217 data = (data & 0xffff0000) |
218 ((data & 0x0000ffff) >> 1);
219 }
220 child->thread.fp[regno - 21] = data;
221 } else
222 goto out_eio;
223 break;
224
225 case PTRACE_GETREGS: /* Get all gp regs from the child. */
226 for (i = 0; i < 19; i++) {
227 tmp = get_reg(child, i);
228 ret = put_user(tmp, datap);
229 if (ret)
230 break;
231 datap++;
232 }
233 break;
234
235 case PTRACE_SETREGS: /* Set all gp regs in the child. */
236 for (i = 0; i < 19; i++) {
237 ret = get_user(tmp, datap);
238 if (ret)
239 break;
240 if (i == PT_SR) {
241 tmp &= SR_MASK;
242 tmp |= get_reg(child, PT_SR) & ~SR_MASK;
243 }
244 put_reg(child, i, tmp);
245 datap++;
246 }
247 break;
248
249 case PTRACE_GETFPREGS: /* Get the child FPU state. */
250 if (copy_to_user(datap, &child->thread.fp,
251 sizeof(struct user_m68kfp_struct)))
252 ret = -EFAULT;
253 break;
254
255 case PTRACE_SETFPREGS: /* Set the child FPU state. */
256 if (copy_from_user(&child->thread.fp, datap,
257 sizeof(struct user_m68kfp_struct)))
258 ret = -EFAULT;
259 break;
260
261 case PTRACE_GET_THREAD_AREA:
262 ret = put_user(task_thread_info(child)->tp_value, datap);
263 break;
264
265 default:
266 ret = ptrace_request(child, request, addr, data);
267 break;
268 }
269
270 return ret;
271out_eio:
272 return -EIO;
273}
274
275asmlinkage void syscall_trace(void)
276{
277 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
278 ? 0x80 : 0));
279 /*
280 * this isn't the same as continuing with a signal, but it will do
281 * for normal use. strace only continues with a signal if the
282 * stopping signal is not SIGTRAP. -brl
283 */
284 if (current->exit_code) {
285 send_sig(current->exit_code, current, 1);
286 current->exit_code = 0;
287 }
288}
289
290#ifdef CONFIG_COLDFIRE
291asmlinkage int syscall_trace_enter(void)
292{
293 int ret = 0;
294
295 if (test_thread_flag(TIF_SYSCALL_TRACE))
296 ret = tracehook_report_syscall_entry(task_pt_regs(current));
297 return ret;
298}
299
300asmlinkage void syscall_trace_leave(void)
301{
302 if (test_thread_flag(TIF_SYSCALL_TRACE))
303 tracehook_report_syscall_exit(task_pt_regs(current), 0);
304}
305#endif /* CONFIG_COLDFIRE */
diff --git a/arch/m68k/kernel/ptrace_mm.c b/arch/m68k/kernel/ptrace_mm.c
deleted file mode 100644
index 7bc999b73529..000000000000
--- a/arch/m68k/kernel/ptrace_mm.c
+++ /dev/null
@@ -1,295 +0,0 @@
1/*
2 * linux/arch/m68k/kernel/ptrace.c
3 *
4 * Copyright (C) 1994 by Hamish Macdonald
5 * Taken from linux/kernel/ptrace.c and modified for M680x0.
6 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
7 *
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of
10 * this archive for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <linux/smp.h>
17#include <linux/errno.h>
18#include <linux/ptrace.h>
19#include <linux/user.h>
20#include <linux/signal.h>
21#include <linux/tracehook.h>
22
23#include <asm/uaccess.h>
24#include <asm/page.h>
25#include <asm/pgtable.h>
26#include <asm/system.h>
27#include <asm/processor.h>
28
29/*
30 * does not yet catch signals sent when the child dies.
31 * in exit.c or in signal.c.
32 */
33
34/* determines which bits in the SR the user has access to. */
35/* 1 = access 0 = no access */
36#define SR_MASK 0x001f
37
38/* sets the trace bits. */
39#define TRACE_BITS 0xC000
40#define T1_BIT 0x8000
41#define T0_BIT 0x4000
42
43/* Find the stack offset for a register, relative to thread.esp0. */
44#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
45#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
46 - sizeof(struct switch_stack))
47/* Mapping from PT_xxx to the stack offset at which the register is
48 saved. Notice that usp has no stack-slot and needs to be treated
49 specially (see get_reg/put_reg below). */
50static const int regoff[] = {
51 [0] = PT_REG(d1),
52 [1] = PT_REG(d2),
53 [2] = PT_REG(d3),
54 [3] = PT_REG(d4),
55 [4] = PT_REG(d5),
56 [5] = SW_REG(d6),
57 [6] = SW_REG(d7),
58 [7] = PT_REG(a0),
59 [8] = PT_REG(a1),
60 [9] = PT_REG(a2),
61 [10] = SW_REG(a3),
62 [11] = SW_REG(a4),
63 [12] = SW_REG(a5),
64 [13] = SW_REG(a6),
65 [14] = PT_REG(d0),
66 [15] = -1,
67 [16] = PT_REG(orig_d0),
68 [17] = PT_REG(sr),
69 [18] = PT_REG(pc),
70};
71
72/*
73 * Get contents of register REGNO in task TASK.
74 */
75static inline long get_reg(struct task_struct *task, int regno)
76{
77 unsigned long *addr;
78
79 if (regno == PT_USP)
80 addr = &task->thread.usp;
81 else if (regno < ARRAY_SIZE(regoff))
82 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
83 else
84 return 0;
85 /* Need to take stkadj into account. */
86 if (regno == PT_SR || regno == PT_PC) {
87 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
88 addr = (unsigned long *) ((unsigned long)addr + stkadj);
89 /* The sr is actually a 16 bit register. */
90 if (regno == PT_SR)
91 return *(unsigned short *)addr;
92 }
93 return *addr;
94}
95
96/*
97 * Write contents of register REGNO in task TASK.
98 */
99static inline int put_reg(struct task_struct *task, int regno,
100 unsigned long data)
101{
102 unsigned long *addr;
103
104 if (regno == PT_USP)
105 addr = &task->thread.usp;
106 else if (regno < ARRAY_SIZE(regoff))
107 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
108 else
109 return -1;
110 /* Need to take stkadj into account. */
111 if (regno == PT_SR || regno == PT_PC) {
112 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
113 addr = (unsigned long *) ((unsigned long)addr + stkadj);
114 /* The sr is actually a 16 bit register. */
115 if (regno == PT_SR) {
116 *(unsigned short *)addr = data;
117 return 0;
118 }
119 }
120 *addr = data;
121 return 0;
122}
123
124/*
125 * Make sure the single step bit is not set.
126 */
127static inline void singlestep_disable(struct task_struct *child)
128{
129 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
130 put_reg(child, PT_SR, tmp);
131 clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
132}
133
134/*
135 * Called by kernel/ptrace.c when detaching..
136 */
137void ptrace_disable(struct task_struct *child)
138{
139 singlestep_disable(child);
140}
141
142void user_enable_single_step(struct task_struct *child)
143{
144 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
145 put_reg(child, PT_SR, tmp | T1_BIT);
146 set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
147}
148
149void user_enable_block_step(struct task_struct *child)
150{
151 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
152 put_reg(child, PT_SR, tmp | T0_BIT);
153}
154
155void user_disable_single_step(struct task_struct *child)
156{
157 singlestep_disable(child);
158}
159
160long arch_ptrace(struct task_struct *child, long request,
161 unsigned long addr, unsigned long data)
162{
163 unsigned long tmp;
164 int i, ret = 0;
165 int regno = addr >> 2; /* temporary hack. */
166 unsigned long __user *datap = (unsigned long __user *) data;
167
168 switch (request) {
169 /* read the word at location addr in the USER area. */
170 case PTRACE_PEEKUSR:
171 if (addr & 3)
172 goto out_eio;
173
174 if (regno >= 0 && regno < 19) {
175 tmp = get_reg(child, regno);
176 } else if (regno >= 21 && regno < 49) {
177 tmp = child->thread.fp[regno - 21];
178 /* Convert internal fpu reg representation
179 * into long double format
180 */
181 if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
182 tmp = ((tmp & 0xffff0000) << 15) |
183 ((tmp & 0x0000ffff) << 16);
184 } else
185 goto out_eio;
186 ret = put_user(tmp, datap);
187 break;
188
189 case PTRACE_POKEUSR:
190 /* write the word at location addr in the USER area */
191 if (addr & 3)
192 goto out_eio;
193
194 if (regno == PT_SR) {
195 data &= SR_MASK;
196 data |= get_reg(child, PT_SR) & ~SR_MASK;
197 }
198 if (regno >= 0 && regno < 19) {
199 if (put_reg(child, regno, data))
200 goto out_eio;
201 } else if (regno >= 21 && regno < 48) {
202 /* Convert long double format
203 * into internal fpu reg representation
204 */
205 if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
206 data <<= 15;
207 data = (data & 0xffff0000) |
208 ((data & 0x0000ffff) >> 1);
209 }
210 child->thread.fp[regno - 21] = data;
211 } else
212 goto out_eio;
213 break;
214
215 case PTRACE_GETREGS: /* Get all gp regs from the child. */
216 for (i = 0; i < 19; i++) {
217 tmp = get_reg(child, i);
218 ret = put_user(tmp, datap);
219 if (ret)
220 break;
221 datap++;
222 }
223 break;
224
225 case PTRACE_SETREGS: /* Set all gp regs in the child. */
226 for (i = 0; i < 19; i++) {
227 ret = get_user(tmp, datap);
228 if (ret)
229 break;
230 if (i == PT_SR) {
231 tmp &= SR_MASK;
232 tmp |= get_reg(child, PT_SR) & ~SR_MASK;
233 }
234 put_reg(child, i, tmp);
235 datap++;
236 }
237 break;
238
239 case PTRACE_GETFPREGS: /* Get the child FPU state. */
240 if (copy_to_user(datap, &child->thread.fp,
241 sizeof(struct user_m68kfp_struct)))
242 ret = -EFAULT;
243 break;
244
245 case PTRACE_SETFPREGS: /* Set the child FPU state. */
246 if (copy_from_user(&child->thread.fp, datap,
247 sizeof(struct user_m68kfp_struct)))
248 ret = -EFAULT;
249 break;
250
251 case PTRACE_GET_THREAD_AREA:
252 ret = put_user(task_thread_info(child)->tp_value, datap);
253 break;
254
255 default:
256 ret = ptrace_request(child, request, addr, data);
257 break;
258 }
259
260 return ret;
261out_eio:
262 return -EIO;
263}
264
265asmlinkage void syscall_trace(void)
266{
267 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
268 ? 0x80 : 0));
269 /*
270 * this isn't the same as continuing with a signal, but it will do
271 * for normal use. strace only continues with a signal if the
272 * stopping signal is not SIGTRAP. -brl
273 */
274 if (current->exit_code) {
275 send_sig(current->exit_code, current, 1);
276 current->exit_code = 0;
277 }
278}
279
280#ifdef CONFIG_COLDFIRE
281asmlinkage int syscall_trace_enter(void)
282{
283 int ret = 0;
284
285 if (test_thread_flag(TIF_SYSCALL_TRACE))
286 ret = tracehook_report_syscall_entry(task_pt_regs(current));
287 return ret;
288}
289
290asmlinkage void syscall_trace_leave(void)
291{
292 if (test_thread_flag(TIF_SYSCALL_TRACE))
293 tracehook_report_syscall_exit(task_pt_regs(current), 0);
294}
295#endif /* CONFIG_COLDFIRE */
diff --git a/arch/m68k/kernel/ptrace_no.c b/arch/m68k/kernel/ptrace_no.c
deleted file mode 100644
index 6709fb707335..000000000000
--- a/arch/m68k/kernel/ptrace_no.c
+++ /dev/null
@@ -1,255 +0,0 @@
1/*
2 * linux/arch/m68knommu/kernel/ptrace.c
3 *
4 * Copyright (C) 1994 by Hamish Macdonald
5 * Taken from linux/kernel/ptrace.c and modified for M680x0.
6 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
7 *
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of
10 * this archive for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <linux/smp.h>
17#include <linux/errno.h>
18#include <linux/ptrace.h>
19#include <linux/user.h>
20#include <linux/signal.h>
21#include <linux/tracehook.h>
22
23#include <asm/uaccess.h>
24#include <asm/page.h>
25#include <asm/pgtable.h>
26#include <asm/system.h>
27#include <asm/processor.h>
28
29/*
30 * does not yet catch signals sent when the child dies.
31 * in exit.c or in signal.c.
32 */
33
34/* determines which bits in the SR the user has access to. */
35/* 1 = access 0 = no access */
36#define SR_MASK 0x001f
37
38/* sets the trace bits. */
39#define TRACE_BITS 0x8000
40
41/* Find the stack offset for a register, relative to thread.esp0. */
42#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
43#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
44 - sizeof(struct switch_stack))
45/* Mapping from PT_xxx to the stack offset at which the register is
46 saved. Notice that usp has no stack-slot and needs to be treated
47 specially (see get_reg/put_reg below). */
48static int regoff[] = {
49 PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
50 PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
51 PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
52 SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
53 PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
54};
55
56/*
57 * Get contents of register REGNO in task TASK.
58 */
59static inline long get_reg(struct task_struct *task, int regno)
60{
61 unsigned long *addr;
62
63 if (regno == PT_USP)
64 addr = &task->thread.usp;
65 else if (regno < ARRAY_SIZE(regoff))
66 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
67 else
68 return 0;
69 return *addr;
70}
71
72/*
73 * Write contents of register REGNO in task TASK.
74 */
75static inline int put_reg(struct task_struct *task, int regno,
76 unsigned long data)
77{
78 unsigned long *addr;
79
80 if (regno == PT_USP)
81 addr = &task->thread.usp;
82 else if (regno < ARRAY_SIZE(regoff))
83 addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
84 else
85 return -1;
86 *addr = data;
87 return 0;
88}
89
90void user_enable_single_step(struct task_struct *task)
91{
92 unsigned long srflags;
93 srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16);
94 put_reg(task, PT_SR, srflags);
95}
96
97void user_disable_single_step(struct task_struct *task)
98{
99 unsigned long srflags;
100 srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16);
101 put_reg(task, PT_SR, srflags);
102}
103
104/*
105 * Called by kernel/ptrace.c when detaching..
106 *
107 * Make sure the single step bit is not set.
108 */
109void ptrace_disable(struct task_struct *child)
110{
111 /* make sure the single step bit is not set. */
112 user_disable_single_step(child);
113}
114
115long arch_ptrace(struct task_struct *child, long request,
116 unsigned long addr, unsigned long data)
117{
118 int ret;
119 int regno = addr >> 2;
120 unsigned long __user *datap = (unsigned long __user *) data;
121
122 switch (request) {
123 /* read the word at location addr in the USER area. */
124 case PTRACE_PEEKUSR: {
125 unsigned long tmp;
126
127 ret = -EIO;
128 if ((addr & 3) || addr > sizeof(struct user) - 3)
129 break;
130
131 tmp = 0; /* Default return condition */
132 ret = -EIO;
133 if (regno < 19) {
134 tmp = get_reg(child, regno);
135 if (regno == PT_SR)
136 tmp >>= 16;
137 } else if (regno >= 21 && regno < 49) {
138 tmp = child->thread.fp[regno - 21];
139 } else if (regno == 49) {
140 tmp = child->mm->start_code;
141 } else if (regno == 50) {
142 tmp = child->mm->start_data;
143 } else if (regno == 51) {
144 tmp = child->mm->end_code;
145 } else
146 break;
147 ret = put_user(tmp, datap);
148 break;
149 }
150
151 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
152 ret = -EIO;
153 if ((addr & 3) || addr > sizeof(struct user) - 3)
154 break;
155
156 if (regno == PT_SR) {
157 data &= SR_MASK;
158 data <<= 16;
159 data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
160 }
161 if (regno < 19) {
162 if (put_reg(child, regno, data))
163 break;
164 ret = 0;
165 break;
166 }
167 if (regno >= 21 && regno < 48)
168 {
169 child->thread.fp[regno - 21] = data;
170 ret = 0;
171 }
172 break;
173
174 case PTRACE_GETREGS: { /* Get all gp regs from the child. */
175 int i;
176 unsigned long tmp;
177 for (i = 0; i < 19; i++) {
178 tmp = get_reg(child, i);
179 if (i == PT_SR)
180 tmp >>= 16;
181 if (put_user(tmp, datap)) {
182 ret = -EFAULT;
183 break;
184 }
185 datap++;
186 }
187 ret = 0;
188 break;
189 }
190
191 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
192 int i;
193 unsigned long tmp;
194 for (i = 0; i < 19; i++) {
195 if (get_user(tmp, datap)) {
196 ret = -EFAULT;
197 break;
198 }
199 if (i == PT_SR) {
200 tmp &= SR_MASK;
201 tmp <<= 16;
202 tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
203 }
204 put_reg(child, i, tmp);
205 datap++;
206 }
207 ret = 0;
208 break;
209 }
210
211#ifdef PTRACE_GETFPREGS
212 case PTRACE_GETFPREGS: { /* Get the child FPU state. */
213 ret = 0;
214 if (copy_to_user(datap, &child->thread.fp,
215 sizeof(struct user_m68kfp_struct)))
216 ret = -EFAULT;
217 break;
218 }
219#endif
220
221#ifdef PTRACE_SETFPREGS
222 case PTRACE_SETFPREGS: { /* Set the child FPU state. */
223 ret = 0;
224 if (copy_from_user(&child->thread.fp, datap,
225 sizeof(struct user_m68kfp_struct)))
226 ret = -EFAULT;
227 break;
228 }
229#endif
230
231 case PTRACE_GET_THREAD_AREA:
232 ret = put_user(task_thread_info(child)->tp_value, datap);
233 break;
234
235 default:
236 ret = ptrace_request(child, request, addr, data);
237 break;
238 }
239 return ret;
240}
241
242asmlinkage int syscall_trace_enter(void)
243{
244 int ret = 0;
245
246 if (test_thread_flag(TIF_SYSCALL_TRACE))
247 ret = tracehook_report_syscall_entry(task_pt_regs(current));
248 return ret;
249}
250
251asmlinkage void syscall_trace_leave(void)
252{
253 if (test_thread_flag(TIF_SYSCALL_TRACE))
254 tracehook_report_syscall_exit(task_pt_regs(current), 0);
255}
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
index ca3df0dc7e88..7dc186b7a85f 100644
--- a/arch/m68k/kernel/setup_no.c
+++ b/arch/m68k/kernel/setup_no.c
@@ -31,6 +31,7 @@
31#include <linux/init.h> 31#include <linux/init.h>
32#include <linux/initrd.h> 32#include <linux/initrd.h>
33#include <linux/root_dev.h> 33#include <linux/root_dev.h>
34#include <linux/rtc.h>
34 35
35#include <asm/setup.h> 36#include <asm/setup.h>
36#include <asm/irq.h> 37#include <asm/irq.h>
@@ -47,7 +48,9 @@ EXPORT_SYMBOL(memory_end);
47char __initdata command_line[COMMAND_LINE_SIZE]; 48char __initdata command_line[COMMAND_LINE_SIZE];
48 49
49/* machine dependent timer functions */ 50/* machine dependent timer functions */
51void (*mach_sched_init)(irq_handler_t handler) __initdata = NULL;
50int (*mach_set_clock_mmss)(unsigned long); 52int (*mach_set_clock_mmss)(unsigned long);
53int (*mach_hwclk) (int, struct rtc_time*);
51 54
52/* machine dependent reboot functions */ 55/* machine dependent reboot functions */
53void (*mach_reset)(void); 56void (*mach_reset)(void);
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 75ab79b3bdeb..d7deb7fc7eb5 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -1,5 +1,111 @@
1#if defined(CONFIG_MMU) && !defined(CONFIG_COLDFIRE) 1/*
2#include "time_mm.c" 2 * linux/arch/m68k/kernel/time.c
3#else 3 *
4#include "time_no.c" 4 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
5#endif 5 *
6 * This file contains the m68k-specific time handling details.
7 * Most of the stuff is located in the machine specific files.
8 *
9 * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
10 * "A Kernel Model for Precision Timekeeping" by Dave Mills
11 */
12
13#include <linux/errno.h>
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/param.h>
18#include <linux/string.h>
19#include <linux/mm.h>
20#include <linux/rtc.h>
21#include <linux/platform_device.h>
22
23#include <asm/machdep.h>
24#include <asm/io.h>
25#include <asm/irq_regs.h>
26
27#include <linux/time.h>
28#include <linux/timex.h>
29#include <linux/profile.h>
30
31/*
32 * timer_interrupt() needs to keep up the real-time clock,
33 * as well as call the "xtime_update()" routine every clocktick
34 */
35static irqreturn_t timer_interrupt(int irq, void *dummy)
36{
37 xtime_update(1);
38 update_process_times(user_mode(get_irq_regs()));
39 profile_tick(CPU_PROFILING);
40
41#ifdef CONFIG_HEARTBEAT
42 /* use power LED as a heartbeat instead -- much more useful
43 for debugging -- based on the version for PReP by Cort */
44 /* acts like an actual heart beat -- ie thump-thump-pause... */
45 if (mach_heartbeat) {
46 static unsigned cnt = 0, period = 0, dist = 0;
47
48 if (cnt == 0 || cnt == dist)
49 mach_heartbeat( 1 );
50 else if (cnt == 7 || cnt == dist+7)
51 mach_heartbeat( 0 );
52
53 if (++cnt > period) {
54 cnt = 0;
55 /* The hyperbolic function below modifies the heartbeat period
56 * length in dependency of the current (5min) load. It goes
57 * through the points f(0)=126, f(1)=86, f(5)=51,
58 * f(inf)->30. */
59 period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
60 dist = period / 4;
61 }
62 }
63#endif /* CONFIG_HEARTBEAT */
64 return IRQ_HANDLED;
65}
66
67void read_persistent_clock(struct timespec *ts)
68{
69 struct rtc_time time;
70 ts->tv_sec = 0;
71 ts->tv_nsec = 0;
72
73 if (mach_hwclk) {
74 mach_hwclk(0, &time);
75
76 if ((time.tm_year += 1900) < 1970)
77 time.tm_year += 100;
78 ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
79 time.tm_hour, time.tm_min, time.tm_sec);
80 }
81}
82
83void __init time_init(void)
84{
85 mach_sched_init(timer_interrupt);
86}
87
88#ifdef CONFIG_M68KCLASSIC
89
90u32 arch_gettimeoffset(void)
91{
92 return mach_gettimeoffset() * 1000;
93}
94
95static int __init rtc_init(void)
96{
97 struct platform_device *pdev;
98
99 if (!mach_hwclk)
100 return -ENODEV;
101
102 pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
103 if (IS_ERR(pdev))
104 return PTR_ERR(pdev);
105
106 return 0;
107}
108
109module_init(rtc_init);
110
111#endif /* CONFIG_M68KCLASSIC */
diff --git a/arch/m68k/kernel/time_mm.c b/arch/m68k/kernel/time_mm.c
deleted file mode 100644
index 18b34ee5db3b..000000000000
--- a/arch/m68k/kernel/time_mm.c
+++ /dev/null
@@ -1,114 +0,0 @@
1/*
2 * linux/arch/m68k/kernel/time.c
3 *
4 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
5 *
6 * This file contains the m68k-specific time handling details.
7 * Most of the stuff is located in the machine specific files.
8 *
9 * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
10 * "A Kernel Model for Precision Timekeeping" by Dave Mills
11 */
12
13#include <linux/errno.h>
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/param.h>
18#include <linux/string.h>
19#include <linux/mm.h>
20#include <linux/rtc.h>
21#include <linux/platform_device.h>
22
23#include <asm/machdep.h>
24#include <asm/io.h>
25#include <asm/irq_regs.h>
26
27#include <linux/time.h>
28#include <linux/timex.h>
29#include <linux/profile.h>
30
31static inline int set_rtc_mmss(unsigned long nowtime)
32{
33 if (mach_set_clock_mmss)
34 return mach_set_clock_mmss (nowtime);
35 return -1;
36}
37
38/*
39 * timer_interrupt() needs to keep up the real-time clock,
40 * as well as call the "xtime_update()" routine every clocktick
41 */
42static irqreturn_t timer_interrupt(int irq, void *dummy)
43{
44 xtime_update(1);
45 update_process_times(user_mode(get_irq_regs()));
46 profile_tick(CPU_PROFILING);
47
48#ifdef CONFIG_HEARTBEAT
49 /* use power LED as a heartbeat instead -- much more useful
50 for debugging -- based on the version for PReP by Cort */
51 /* acts like an actual heart beat -- ie thump-thump-pause... */
52 if (mach_heartbeat) {
53 static unsigned cnt = 0, period = 0, dist = 0;
54
55 if (cnt == 0 || cnt == dist)
56 mach_heartbeat( 1 );
57 else if (cnt == 7 || cnt == dist+7)
58 mach_heartbeat( 0 );
59
60 if (++cnt > period) {
61 cnt = 0;
62 /* The hyperbolic function below modifies the heartbeat period
63 * length in dependency of the current (5min) load. It goes
64 * through the points f(0)=126, f(1)=86, f(5)=51,
65 * f(inf)->30. */
66 period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
67 dist = period / 4;
68 }
69 }
70#endif /* CONFIG_HEARTBEAT */
71 return IRQ_HANDLED;
72}
73
74void read_persistent_clock(struct timespec *ts)
75{
76 struct rtc_time time;
77 ts->tv_sec = 0;
78 ts->tv_nsec = 0;
79
80 if (mach_hwclk) {
81 mach_hwclk(0, &time);
82
83 if ((time.tm_year += 1900) < 1970)
84 time.tm_year += 100;
85 ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
86 time.tm_hour, time.tm_min, time.tm_sec);
87 }
88}
89
90void __init time_init(void)
91{
92 mach_sched_init(timer_interrupt);
93}
94
95u32 arch_gettimeoffset(void)
96{
97 return mach_gettimeoffset() * 1000;
98}
99
100static int __init rtc_init(void)
101{
102 struct platform_device *pdev;
103
104 if (!mach_hwclk)
105 return -ENODEV;
106
107 pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
108 if (IS_ERR(pdev))
109 return PTR_ERR(pdev);
110
111 return 0;
112}
113
114module_init(rtc_init);
diff --git a/arch/m68k/kernel/time_no.c b/arch/m68k/kernel/time_no.c
deleted file mode 100644
index 3ef0f7768dcd..000000000000
--- a/arch/m68k/kernel/time_no.c
+++ /dev/null
@@ -1,90 +0,0 @@
1/*
2 * linux/arch/m68knommu/kernel/time.c
3 *
4 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
5 *
6 * This file contains the m68k-specific time handling details.
7 * Most of the stuff is located in the machine specific files.
8 *
9 * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
10 * "A Kernel Model for Precision Timekeeping" by Dave Mills
11 */
12
13#include <linux/errno.h>
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/param.h>
18#include <linux/string.h>
19#include <linux/mm.h>
20#include <linux/profile.h>
21#include <linux/time.h>
22#include <linux/timex.h>
23
24#include <asm/machdep.h>
25#include <asm/irq_regs.h>
26
27#define TICK_SIZE (tick_nsec / 1000)
28
29/* machine dependent timer functions */
30void (*mach_gettod)(int*, int*, int*, int*, int*, int*);
31
32static inline int set_rtc_mmss(unsigned long nowtime)
33{
34 if (mach_set_clock_mmss)
35 return mach_set_clock_mmss (nowtime);
36 return -1;
37}
38
39#ifndef CONFIG_GENERIC_CLOCKEVENTS
40/*
41 * timer_interrupt() needs to keep up the real-time clock,
42 * as well as call the "xtime_update()" routine every clocktick
43 */
44irqreturn_t arch_timer_interrupt(int irq, void *dummy)
45{
46
47 if (current->pid)
48 profile_tick(CPU_PROFILING);
49
50 xtime_update(1);
51
52 update_process_times(user_mode(get_irq_regs()));
53
54 return(IRQ_HANDLED);
55}
56#endif
57
58static unsigned long read_rtc_mmss(void)
59{
60 unsigned int year, mon, day, hour, min, sec;
61
62 if (mach_gettod) {
63 mach_gettod(&year, &mon, &day, &hour, &min, &sec);
64 if ((year += 1900) < 1970)
65 year += 100;
66 } else {
67 year = 1970;
68 mon = day = 1;
69 hour = min = sec = 0;
70 }
71
72
73 return mktime(year, mon, day, hour, min, sec);
74}
75
76void read_persistent_clock(struct timespec *ts)
77{
78 ts->tv_sec = read_rtc_mmss();
79 ts->tv_nsec = 0;
80}
81
82int update_persistent_clock(struct timespec now)
83{
84 return set_rtc_mmss(now.tv_sec);
85}
86
87void time_init(void)
88{
89 hw_timer_init();
90}
diff --git a/arch/m68k/kernel/vmlinux-nommu.lds b/arch/m68k/kernel/vmlinux-nommu.lds
index 8e66ccb0935e..40e02d9c38b4 100644
--- a/arch/m68k/kernel/vmlinux-nommu.lds
+++ b/arch/m68k/kernel/vmlinux-nommu.lds
@@ -1,195 +1,93 @@
1/* 1/*
2 * vmlinux.lds.S -- master linker script for m68knommu arch 2 * vmlinux.lds.S -- master linker script for m68knommu arch
3 * 3 *
4 * (C) Copyright 2002-2006, Greg Ungerer <gerg@snapgear.com> 4 * (C) Copyright 2002-2012, Greg Ungerer <gerg@snapgear.com>
5 * 5 *
6 * This linker script is equipped to build either ROM loaded or RAM 6 * This linker script is equipped to build either ROM loaded or RAM
7 * run kernels. 7 * run kernels.
8 */ 8 */
9 9
10#include <asm-generic/vmlinux.lds.h>
11#include <asm/page.h>
12#include <asm/thread_info.h>
13
14#if defined(CONFIG_RAMKERNEL) 10#if defined(CONFIG_RAMKERNEL)
15#define RAM_START CONFIG_KERNELBASE 11#define KTEXT_ADDR CONFIG_KERNELBASE
16#define RAM_LENGTH (CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE)
17#define TEXT ram
18#define DATA ram
19#define INIT ram
20#define BSSS ram
21#endif
22#if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL)
23#define RAM_START CONFIG_RAMBASE
24#define RAM_LENGTH CONFIG_RAMSIZE
25#define ROMVEC_START CONFIG_ROMVEC
26#define ROMVEC_LENGTH CONFIG_ROMVECSIZE
27#define ROM_START CONFIG_ROMSTART
28#define ROM_LENGTH CONFIG_ROMSIZE
29#define TEXT rom
30#define DATA ram
31#define INIT ram
32#define BSSS ram
33#endif 12#endif
34 13#if defined(CONFIG_ROMKERNEL)
35#ifndef DATA_ADDR 14#define KTEXT_ADDR CONFIG_ROMSTART
36#define DATA_ADDR 15#define KDATA_ADDR CONFIG_KERNELBASE
16#define LOAD_OFFSET KDATA_ADDR + (ADDR(.text) + SIZEOF(.text))
37#endif 17#endif
38 18
19#include <asm/page.h>
20#include <asm/thread_info.h>
21#include <asm-generic/vmlinux.lds.h>
39 22
40OUTPUT_ARCH(m68k) 23OUTPUT_ARCH(m68k)
41ENTRY(_start) 24ENTRY(_start)
42 25
43MEMORY {
44 ram : ORIGIN = RAM_START, LENGTH = RAM_LENGTH
45#ifdef ROM_START
46 romvec : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH
47 rom : ORIGIN = ROM_START, LENGTH = ROM_LENGTH
48#endif
49}
50
51jiffies = jiffies_64 + 4; 26jiffies = jiffies_64 + 4;
52 27
53SECTIONS { 28SECTIONS {
54 29
55#ifdef ROMVEC_START 30#ifdef CONFIG_ROMVEC
56 . = ROMVEC_START ; 31 . = CONFIG_ROMVEC;
57 .romvec : { 32 .romvec : {
58 __rom_start = . ; 33 __rom_start = .;
59 _romvec = .; 34 _romvec = .;
35 *(.romvec)
60 *(.data..initvect) 36 *(.data..initvect)
61 } > romvec 37 }
62#endif 38#endif
63 39
40 . = KTEXT_ADDR;
41
42 _text = .;
43 _stext = .;
64 .text : { 44 .text : {
65 _text = .;
66 _stext = . ;
67 HEAD_TEXT 45 HEAD_TEXT
68 TEXT_TEXT 46 TEXT_TEXT
69 SCHED_TEXT 47 SCHED_TEXT
70 LOCK_TEXT 48 LOCK_TEXT
71 *(.text..lock)
72 *(.fixup) 49 *(.fixup)
50 . = ALIGN(16);
51 }
52 _etext = .;
53
54#ifdef KDATA_ADDR
55 . = KDATA_ADDR;
56#endif
57
58 _sdata = .;
59 RO_DATA_SECTION(PAGE_SIZE)
60 RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE)
61 _edata = .;
73 62
74 . = ALIGN(16); /* Exception table */ 63 EXCEPTION_TABLE(16)
75 __start___ex_table = .; 64 NOTES
76 *(__ex_table)
77 __stop___ex_table = .;
78
79 *(.rodata) *(.rodata.*)
80 *(__vermagic) /* Kernel version magic */
81 *(.rodata1)
82 *(.rodata.str1.1)
83
84 /* Kernel symbol table: Normal symbols */
85 . = ALIGN(4);
86 __start___ksymtab = .;
87 *(SORT(___ksymtab+*))
88 __stop___ksymtab = .;
89
90 /* Kernel symbol table: GPL-only symbols */
91 __start___ksymtab_gpl = .;
92 *(SORT(___ksymtab_gpl+*))
93 __stop___ksymtab_gpl = .;
94
95 /* Kernel symbol table: Normal unused symbols */
96 __start___ksymtab_unused = .;
97 *(SORT(___ksymtab_unused+*))
98 __stop___ksymtab_unused = .;
99
100 /* Kernel symbol table: GPL-only unused symbols */
101 __start___ksymtab_unused_gpl = .;
102 *(SORT(___ksymtab_unused_gpl+*))
103 __stop___ksymtab_unused_gpl = .;
104
105 /* Kernel symbol table: GPL-future symbols */
106 __start___ksymtab_gpl_future = .;
107 *(SORT(___ksymtab_gpl_future+*))
108 __stop___ksymtab_gpl_future = .;
109
110 /* Kernel symbol table: Normal symbols */
111 __start___kcrctab = .;
112 *(SORT(___kcrctab+*))
113 __stop___kcrctab = .;
114
115 /* Kernel symbol table: GPL-only symbols */
116 __start___kcrctab_gpl = .;
117 *(SORT(___kcrctab_gpl+*))
118 __stop___kcrctab_gpl = .;
119
120 /* Kernel symbol table: Normal unused symbols */
121 __start___kcrctab_unused = .;
122 *(SORT(___kcrctab_unused+*))
123 __stop___kcrctab_unused = .;
124
125 /* Kernel symbol table: GPL-only unused symbols */
126 __start___kcrctab_unused_gpl = .;
127 *(SORT(___kcrctab_unused_gpl+*))
128 __stop___kcrctab_unused_gpl = .;
129
130 /* Kernel symbol table: GPL-future symbols */
131 __start___kcrctab_gpl_future = .;
132 *(SORT(___kcrctab_gpl_future+*))
133 __stop___kcrctab_gpl_future = .;
134
135 /* Kernel symbol table: strings */
136 *(__ksymtab_strings)
137
138 /* Built-in module parameters */
139 . = ALIGN(4) ;
140 __start___param = .;
141 *(__param)
142 __stop___param = .;
143
144 /* Built-in module versions */
145 . = ALIGN(4) ;
146 __start___modver = .;
147 *(__modver)
148 __stop___modver = .;
149
150 . = ALIGN(4) ;
151 _etext = . ;
152 } > TEXT
153
154 .data DATA_ADDR : {
155 . = ALIGN(4);
156 _sdata = . ;
157 DATA_DATA
158 CACHELINE_ALIGNED_DATA(32)
159 PAGE_ALIGNED_DATA(PAGE_SIZE)
160 *(.data..shared_aligned)
161 INIT_TASK_DATA(THREAD_SIZE)
162 _edata = . ;
163 } > DATA
164 65
66 . = ALIGN(PAGE_SIZE);
67 __init_begin = .;
68 INIT_TEXT_SECTION(PAGE_SIZE)
69 INIT_DATA_SECTION(16)
70 PERCPU_SECTION(16)
165 .m68k_fixup : { 71 .m68k_fixup : {
166 __start_fixup = .; 72 __start_fixup = .;
167 *(.m68k_fixup) 73 *(.m68k_fixup)
168 __stop_fixup = .; 74 __stop_fixup = .;
169 } > DATA 75 }
170 NOTES > DATA
171
172 .init.text : {
173 . = ALIGN(PAGE_SIZE);
174 __init_begin = .;
175 } > INIT
176 INIT_TEXT_SECTION(PAGE_SIZE) > INIT
177 INIT_DATA_SECTION(16) > INIT
178 .init.data : { 76 .init.data : {
179 . = ALIGN(PAGE_SIZE); 77 . = ALIGN(PAGE_SIZE);
180 __init_end = .; 78 __init_end = .;
181 } > INIT 79 }
182 80
183 .bss : { 81 _sbss = .;
184 . = ALIGN(4); 82 BSS_SECTION(0, 0, 0)
185 _sbss = . ; 83 _ebss = .;
186 *(.bss) 84
187 *(COMMON) 85 _end = .;
188 . = ALIGN(4) ; 86
189 _ebss = . ; 87 STABS_DEBUG
190 _end = . ; 88 .comment 0 : { *(.comment) }
191 } > BSSS
192 89
90 /* Sections to be discarded */
193 DISCARDS 91 DISCARDS
194} 92}
195 93