diff options
Diffstat (limited to 'arch/m68k/kernel')
-rw-r--r-- | arch/m68k/kernel/process.c | 377 | ||||
-rw-r--r-- | arch/m68k/kernel/process_mm.c | 367 | ||||
-rw-r--r-- | arch/m68k/kernel/process_no.c | 404 | ||||
-rw-r--r-- | arch/m68k/kernel/ptrace.c | 306 | ||||
-rw-r--r-- | arch/m68k/kernel/ptrace_mm.c | 295 | ||||
-rw-r--r-- | arch/m68k/kernel/ptrace_no.c | 255 | ||||
-rw-r--r-- | arch/m68k/kernel/setup_no.c | 3 | ||||
-rw-r--r-- | arch/m68k/kernel/time.c | 116 | ||||
-rw-r--r-- | arch/m68k/kernel/time_mm.c | 114 | ||||
-rw-r--r-- | arch/m68k/kernel/time_no.c | 90 | ||||
-rw-r--r-- | arch/m68k/kernel/vmlinux-nommu.lds | 200 |
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 | |||
37 | asmlinkage void ret_from_fork(void); | ||
38 | |||
39 | |||
40 | /* | ||
41 | * Return saved PC from a blocked thread | ||
42 | */ | ||
43 | unsigned 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 | */ | ||
56 | static 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 | |||
67 | void (*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 | */ | ||
75 | void 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 | |||
85 | void machine_restart(char * __unused) | ||
86 | { | ||
87 | if (mach_reset) | ||
88 | mach_reset(); | ||
89 | for (;;); | ||
90 | } | ||
91 | |||
92 | void machine_halt(void) | ||
93 | { | ||
94 | if (mach_halt) | ||
95 | mach_halt(); | ||
96 | for (;;); | ||
97 | } | ||
98 | |||
99 | void machine_power_off(void) | ||
100 | { | ||
101 | if (mach_power_off) | ||
102 | mach_power_off(); | ||
103 | for (;;); | ||
104 | } | ||
105 | |||
106 | void (*pm_power_off)(void) = machine_power_off; | ||
107 | EXPORT_SYMBOL(pm_power_off); | ||
108 | |||
109 | void 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 | */ | ||
127 | int 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 | } | ||
167 | EXPORT_SYMBOL(kernel_thread); | ||
168 | |||
169 | void 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 | |||
187 | asmlinkage 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 | |||
196 | asmlinkage 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 | |||
202 | asmlinkage 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 | |||
219 | int 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 | ||
288 | int 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 | } | ||
335 | EXPORT_SYMBOL(dump_fpu); | ||
336 | #endif /* CONFIG_FPU */ | ||
337 | |||
338 | /* | ||
339 | * sys_execve() executes a new program. | ||
340 | */ | ||
341 | asmlinkage 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 | |||
358 | unsigned 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 | |||
37 | asmlinkage void ret_from_fork(void); | ||
38 | |||
39 | |||
40 | /* | ||
41 | * Return saved PC from a blocked thread | ||
42 | */ | ||
43 | unsigned 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 | */ | ||
56 | static 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 | |||
67 | void (*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 | */ | ||
75 | void 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 | |||
85 | void machine_restart(char * __unused) | ||
86 | { | ||
87 | if (mach_reset) | ||
88 | mach_reset(); | ||
89 | for (;;); | ||
90 | } | ||
91 | |||
92 | void machine_halt(void) | ||
93 | { | ||
94 | if (mach_halt) | ||
95 | mach_halt(); | ||
96 | for (;;); | ||
97 | } | ||
98 | |||
99 | void machine_power_off(void) | ||
100 | { | ||
101 | if (mach_power_off) | ||
102 | mach_power_off(); | ||
103 | for (;;); | ||
104 | } | ||
105 | |||
106 | void (*pm_power_off)(void) = machine_power_off; | ||
107 | EXPORT_SYMBOL(pm_power_off); | ||
108 | |||
109 | void 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 | */ | ||
127 | int 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 | } | ||
165 | EXPORT_SYMBOL(kernel_thread); | ||
166 | |||
167 | void 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 | |||
183 | asmlinkage int m68k_fork(struct pt_regs *regs) | ||
184 | { | ||
185 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
186 | } | ||
187 | |||
188 | asmlinkage 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 | |||
194 | asmlinkage 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 | |||
211 | int 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 | |||
278 | int 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 | } | ||
325 | EXPORT_SYMBOL(dump_fpu); | ||
326 | |||
327 | /* | ||
328 | * sys_execve() executes a new program. | ||
329 | */ | ||
330 | asmlinkage 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 | |||
347 | unsigned 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 | |||
38 | asmlinkage void ret_from_fork(void); | ||
39 | |||
40 | /* | ||
41 | * The following aren't currently used. | ||
42 | */ | ||
43 | void (*pm_idle)(void); | ||
44 | EXPORT_SYMBOL(pm_idle); | ||
45 | |||
46 | void (*pm_power_off)(void); | ||
47 | EXPORT_SYMBOL(pm_power_off); | ||
48 | |||
49 | /* | ||
50 | * The idle loop on an m68knommu.. | ||
51 | */ | ||
52 | static 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 | |||
63 | void (*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 | */ | ||
71 | void 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 | |||
80 | void machine_restart(char * __unused) | ||
81 | { | ||
82 | if (mach_reset) | ||
83 | mach_reset(); | ||
84 | for (;;); | ||
85 | } | ||
86 | |||
87 | void machine_halt(void) | ||
88 | { | ||
89 | if (mach_halt) | ||
90 | mach_halt(); | ||
91 | for (;;); | ||
92 | } | ||
93 | |||
94 | void machine_power_off(void) | ||
95 | { | ||
96 | if (mach_power_off) | ||
97 | mach_power_off(); | ||
98 | for (;;); | ||
99 | } | ||
100 | |||
101 | void 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 | */ | ||
119 | int 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 | } | ||
152 | EXPORT_SYMBOL(kernel_thread); | ||
153 | |||
154 | void 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 | |||
176 | asmlinkage int m68k_fork(struct pt_regs *regs) | ||
177 | { | ||
178 | /* fork almost works, enough to trick you into looking elsewhere :-( */ | ||
179 | return(-EINVAL); | ||
180 | } | ||
181 | |||
182 | asmlinkage int m68k_vfork(struct pt_regs *regs) | ||
183 | { | ||
184 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
185 | } | ||
186 | |||
187 | asmlinkage 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 | |||
200 | int 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 | |||
252 | int 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 | } | ||
285 | EXPORT_SYMBOL(dump_fpu); | ||
286 | |||
287 | /* | ||
288 | * Generic dumping code. Used for panic and debug. | ||
289 | */ | ||
290 | void 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 | */ | ||
352 | asmlinkage 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 | |||
369 | unsigned 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 | */ | ||
394 | unsigned 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). */ | ||
50 | static 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 | */ | ||
75 | static 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 | */ | ||
99 | static 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 | */ | ||
127 | static 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 | */ | ||
137 | void ptrace_disable(struct task_struct *child) | ||
138 | { | ||
139 | singlestep_disable(child); | ||
140 | } | ||
141 | |||
142 | void 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" | 150 | void 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 | |||
157 | void user_disable_single_step(struct task_struct *child) | ||
158 | { | ||
159 | singlestep_disable(child); | ||
160 | } | ||
161 | |||
162 | long 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; | ||
271 | out_eio: | ||
272 | return -EIO; | ||
273 | } | ||
274 | |||
275 | asmlinkage 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 | ||
291 | asmlinkage 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 | |||
300 | asmlinkage 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). */ | ||
50 | static 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 | */ | ||
75 | static 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 | */ | ||
99 | static 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 | */ | ||
127 | static 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 | */ | ||
137 | void ptrace_disable(struct task_struct *child) | ||
138 | { | ||
139 | singlestep_disable(child); | ||
140 | } | ||
141 | |||
142 | void 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 | |||
149 | void 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 | |||
155 | void user_disable_single_step(struct task_struct *child) | ||
156 | { | ||
157 | singlestep_disable(child); | ||
158 | } | ||
159 | |||
160 | long 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; | ||
261 | out_eio: | ||
262 | return -EIO; | ||
263 | } | ||
264 | |||
265 | asmlinkage 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 | ||
281 | asmlinkage 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 | |||
290 | asmlinkage 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). */ | ||
48 | static 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 | */ | ||
59 | static 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 | */ | ||
75 | static 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 | |||
90 | void 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 | |||
97 | void 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 | */ | ||
109 | void 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 | |||
115 | long 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 | |||
242 | asmlinkage 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 | |||
251 | asmlinkage 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); | |||
47 | char __initdata command_line[COMMAND_LINE_SIZE]; | 48 | char __initdata command_line[COMMAND_LINE_SIZE]; |
48 | 49 | ||
49 | /* machine dependent timer functions */ | 50 | /* machine dependent timer functions */ |
51 | void (*mach_sched_init)(irq_handler_t handler) __initdata = NULL; | ||
50 | int (*mach_set_clock_mmss)(unsigned long); | 52 | int (*mach_set_clock_mmss)(unsigned long); |
53 | int (*mach_hwclk) (int, struct rtc_time*); | ||
51 | 54 | ||
52 | /* machine dependent reboot functions */ | 55 | /* machine dependent reboot functions */ |
53 | void (*mach_reset)(void); | 56 | void (*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 | */ | ||
35 | static 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 | |||
67 | void 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 | |||
83 | void __init time_init(void) | ||
84 | { | ||
85 | mach_sched_init(timer_interrupt); | ||
86 | } | ||
87 | |||
88 | #ifdef CONFIG_M68KCLASSIC | ||
89 | |||
90 | u32 arch_gettimeoffset(void) | ||
91 | { | ||
92 | return mach_gettimeoffset() * 1000; | ||
93 | } | ||
94 | |||
95 | static 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 | |||
109 | module_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 | |||
31 | static 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 | */ | ||
42 | static 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 | |||
74 | void 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 | |||
90 | void __init time_init(void) | ||
91 | { | ||
92 | mach_sched_init(timer_interrupt); | ||
93 | } | ||
94 | |||
95 | u32 arch_gettimeoffset(void) | ||
96 | { | ||
97 | return mach_gettimeoffset() * 1000; | ||
98 | } | ||
99 | |||
100 | static 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 | |||
114 | module_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 */ | ||
30 | void (*mach_gettod)(int*, int*, int*, int*, int*, int*); | ||
31 | |||
32 | static 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 | */ | ||
44 | irqreturn_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 | |||
58 | static 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 | |||
76 | void read_persistent_clock(struct timespec *ts) | ||
77 | { | ||
78 | ts->tv_sec = read_rtc_mmss(); | ||
79 | ts->tv_nsec = 0; | ||
80 | } | ||
81 | |||
82 | int update_persistent_clock(struct timespec now) | ||
83 | { | ||
84 | return set_rtc_mmss(now.tv_sec); | ||
85 | } | ||
86 | |||
87 | void 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 | ||
40 | OUTPUT_ARCH(m68k) | 23 | OUTPUT_ARCH(m68k) |
41 | ENTRY(_start) | 24 | ENTRY(_start) |
42 | 25 | ||
43 | MEMORY { | ||
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 | |||
51 | jiffies = jiffies_64 + 4; | 26 | jiffies = jiffies_64 + 4; |
52 | 27 | ||
53 | SECTIONS { | 28 | SECTIONS { |
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 | ||