diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-15 02:23:22 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-15 11:14:38 -0400 |
| commit | 5adc807f707535a5ce97b5d69472ee74d6d099ac (patch) | |
| tree | 837bc92007282a8acb0145ad7104bb0b7588470b /arch/avr32/kernel | |
| parent | ddffeb8c4d0331609ef2581d84de4d763607bd37 (diff) | |
avr32: switch to generic kernel_thread()/kernel_execve()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/avr32/kernel')
| -rw-r--r-- | arch/avr32/kernel/Makefile | 2 | ||||
| -rw-r--r-- | arch/avr32/kernel/entry-avr32b.S | 14 | ||||
| -rw-r--r-- | arch/avr32/kernel/process.c | 67 | ||||
| -rw-r--r-- | arch/avr32/kernel/sys_avr32.c | 24 |
4 files changed, 26 insertions, 81 deletions
diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile index 9e2c465ef3a6..119a2e41defe 100644 --- a/arch/avr32/kernel/Makefile +++ b/arch/avr32/kernel/Makefile | |||
| @@ -7,7 +7,7 @@ extra-y := head.o vmlinux.lds | |||
| 7 | obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o | 7 | obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o |
| 8 | obj-y += syscall_table.o syscall-stubs.o irq.o | 8 | obj-y += syscall_table.o syscall-stubs.o irq.o |
| 9 | obj-y += setup.o traps.o ocd.o ptrace.o | 9 | obj-y += setup.o traps.o ocd.o ptrace.o |
| 10 | obj-y += signal.o sys_avr32.o process.o time.o | 10 | obj-y += signal.o process.o time.o |
| 11 | obj-y += switch_to.o cpu.o | 11 | obj-y += switch_to.o cpu.o |
| 12 | obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o | 12 | obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o |
| 13 | obj-$(CONFIG_KPROBES) += kprobes.o | 13 | obj-$(CONFIG_KPROBES) += kprobes.o |
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index df2884181313..9899d3cc6f03 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S | |||
| @@ -251,13 +251,15 @@ syscall_badsys: | |||
| 251 | .global ret_from_fork | 251 | .global ret_from_fork |
| 252 | ret_from_fork: | 252 | ret_from_fork: |
| 253 | call schedule_tail | 253 | call schedule_tail |
| 254 | mov r12, 0 | ||
| 255 | rjmp syscall_return | ||
| 254 | 256 | ||
| 255 | /* check for syscall tracing */ | 257 | .global ret_from_kernel_thread |
| 256 | get_thread_info r0 | 258 | ret_from_kernel_thread: |
| 257 | ld.w r1, r0[TI_flags] | 259 | call schedule_tail |
| 258 | andl r1, _TIF_ALLWORK_MASK, COH | 260 | mov r12, r0 |
| 259 | brne syscall_exit_work | 261 | mov lr, r2 /* syscall_return */ |
| 260 | rjmp syscall_exit_cont | 262 | mov pc, r1 |
| 261 | 263 | ||
| 262 | syscall_trace_enter: | 264 | syscall_trace_enter: |
| 263 | pushm r8-r12 | 265 | pushm r8-r12 |
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c index 1bb0a8abd79b..07380c3a4f78 100644 --- a/arch/avr32/kernel/process.c +++ b/arch/avr32/kernel/process.c | |||
| @@ -69,44 +69,6 @@ void machine_restart(char *cmd) | |||
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | /* | 71 | /* |
| 72 | * PC is actually discarded when returning from a system call -- the | ||
| 73 | * return address must be stored in LR. This function will make sure | ||
| 74 | * LR points to do_exit before starting the thread. | ||
| 75 | * | ||
| 76 | * Also, when returning from fork(), r12 is 0, so we must copy the | ||
| 77 | * argument as well. | ||
| 78 | * | ||
| 79 | * r0 : The argument to the main thread function | ||
| 80 | * r1 : The address of do_exit | ||
| 81 | * r2 : The address of the main thread function | ||
| 82 | */ | ||
| 83 | asmlinkage extern void kernel_thread_helper(void); | ||
| 84 | __asm__(" .type kernel_thread_helper, @function\n" | ||
| 85 | "kernel_thread_helper:\n" | ||
| 86 | " mov r12, r0\n" | ||
| 87 | " mov lr, r2\n" | ||
| 88 | " mov pc, r1\n" | ||
| 89 | " .size kernel_thread_helper, . - kernel_thread_helper"); | ||
| 90 | |||
| 91 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
| 92 | { | ||
| 93 | struct pt_regs regs; | ||
| 94 | |||
| 95 | memset(®s, 0, sizeof(regs)); | ||
| 96 | |||
| 97 | regs.r0 = (unsigned long)arg; | ||
| 98 | regs.r1 = (unsigned long)fn; | ||
| 99 | regs.r2 = (unsigned long)do_exit; | ||
| 100 | regs.lr = (unsigned long)kernel_thread_helper; | ||
| 101 | regs.pc = (unsigned long)kernel_thread_helper; | ||
| 102 | regs.sr = MODE_SUPERVISOR; | ||
| 103 | |||
| 104 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, | ||
| 105 | 0, ®s, 0, NULL, NULL); | ||
| 106 | } | ||
| 107 | EXPORT_SYMBOL(kernel_thread); | ||
| 108 | |||
| 109 | /* | ||
| 110 | * Free current thread data structures etc | 72 | * Free current thread data structures etc |
| 111 | */ | 73 | */ |
| 112 | void exit_thread(void) | 74 | void exit_thread(void) |
| @@ -332,26 +294,31 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
| 332 | } | 294 | } |
| 333 | 295 | ||
| 334 | asmlinkage void ret_from_fork(void); | 296 | asmlinkage void ret_from_fork(void); |
| 297 | asmlinkage void ret_from_kernel_thread(void); | ||
| 298 | asmlinkage void syscall_return(void); | ||
| 335 | 299 | ||
| 336 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 300 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
| 337 | unsigned long unused, | 301 | unsigned long arg, |
| 338 | struct task_struct *p, struct pt_regs *regs) | 302 | struct task_struct *p, struct pt_regs *regs) |
| 339 | { | 303 | { |
| 340 | struct pt_regs *childregs; | 304 | struct pt_regs *childregs = task_pt_regs(p); |
| 341 | 305 | ||
| 342 | childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1; | 306 | if (unlikely(!regs)) { |
| 343 | *childregs = *regs; | 307 | memset(childregs, 0, sizeof(struct pt_regs)); |
| 344 | 308 | p->thread.cpu_context.r0 = arg; | |
| 345 | if (user_mode(regs)) | 309 | p->thread.cpu_context.r1 = usp; /* fn */ |
| 310 | p->thread.cpu_context.r2 = syscall_return; | ||
| 311 | p->thread.cpu_context.pc = (unsigned long)ret_from_kernel_thread; | ||
| 312 | childregs->sr = MODE_SUPERVISOR; | ||
| 313 | } else { | ||
| 314 | *childregs = *regs; | ||
| 346 | childregs->sp = usp; | 315 | childregs->sp = usp; |
| 347 | else | 316 | childregs->r12 = 0; /* Set return value for child */ |
| 348 | childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; | 317 | p->thread.cpu_context.pc = (unsigned long)ret_from_fork; |
| 349 | 318 | } | |
| 350 | childregs->r12 = 0; /* Set return value for child */ | ||
| 351 | 319 | ||
| 352 | p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM; | 320 | p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM; |
| 353 | p->thread.cpu_context.ksp = (unsigned long)childregs; | 321 | p->thread.cpu_context.ksp = (unsigned long)childregs; |
| 354 | p->thread.cpu_context.pc = (unsigned long)ret_from_fork; | ||
| 355 | 322 | ||
| 356 | clear_tsk_thread_flag(p, TIF_DEBUG); | 323 | clear_tsk_thread_flag(p, TIF_DEBUG); |
| 357 | if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG)) | 324 | if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG)) |
diff --git a/arch/avr32/kernel/sys_avr32.c b/arch/avr32/kernel/sys_avr32.c deleted file mode 100644 index 62635a09ae3e..000000000000 --- a/arch/avr32/kernel/sys_avr32.c +++ /dev/null | |||
| @@ -1,24 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2004-2006 Atmel Corporation | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | #include <linux/unistd.h> | ||
| 9 | |||
| 10 | int kernel_execve(const char *file, | ||
| 11 | const char *const *argv, | ||
| 12 | const char *const *envp) | ||
| 13 | { | ||
| 14 | register long scno asm("r8") = __NR_execve; | ||
| 15 | register long sc1 asm("r12") = (long)file; | ||
| 16 | register long sc2 asm("r11") = (long)argv; | ||
| 17 | register long sc3 asm("r10") = (long)envp; | ||
| 18 | |||
| 19 | asm volatile("scall" | ||
| 20 | : "=r"(sc1) | ||
| 21 | : "r"(scno), "0"(sc1), "r"(sc2), "r"(sc3) | ||
| 22 | : "cc", "memory"); | ||
| 23 | return sc1; | ||
| 24 | } | ||
