mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
avr32: switch to generic kernel_thread()/kernel_execve()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
ddffeb8c4d
commit
5adc807f70
@ -17,6 +17,8 @@ config AVR32
|
|||||||
select GENERIC_CLOCKEVENTS
|
select GENERIC_CLOCKEVENTS
|
||||||
select HAVE_MOD_ARCH_SPECIFIC
|
select HAVE_MOD_ARCH_SPECIFIC
|
||||||
select MODULES_USE_ELF_RELA
|
select MODULES_USE_ELF_RELA
|
||||||
|
select GENERIC_KERNEL_THREAD
|
||||||
|
select GENERIC_KERNEL_EXECVE
|
||||||
help
|
help
|
||||||
AVR32 is a high-performance 32-bit RISC microprocessor core,
|
AVR32 is a high-performance 32-bit RISC microprocessor core,
|
||||||
designed for cost-sensitive embedded applications, with particular
|
designed for cost-sensitive embedded applications, with particular
|
||||||
|
@ -142,9 +142,6 @@ struct task_struct;
|
|||||||
/* Free all resources held by a thread */
|
/* Free all resources held by a thread */
|
||||||
extern void release_thread(struct task_struct *);
|
extern void release_thread(struct task_struct *);
|
||||||
|
|
||||||
/* Create a kernel thread without removing it from tasklists */
|
|
||||||
extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
|
|
||||||
|
|
||||||
/* Return saved PC of a blocked thread */
|
/* Return saved PC of a blocked thread */
|
||||||
#define thread_saved_pc(tsk) ((tsk)->thread.cpu_context.pc)
|
#define thread_saved_pc(tsk) ((tsk)->thread.cpu_context.pc)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ extra-y := head.o vmlinux.lds
|
|||||||
obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o
|
obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o
|
||||||
obj-y += syscall_table.o syscall-stubs.o irq.o
|
obj-y += syscall_table.o syscall-stubs.o irq.o
|
||||||
obj-y += setup.o traps.o ocd.o ptrace.o
|
obj-y += setup.o traps.o ocd.o ptrace.o
|
||||||
obj-y += signal.o sys_avr32.o process.o time.o
|
obj-y += signal.o process.o time.o
|
||||||
obj-y += switch_to.o cpu.o
|
obj-y += switch_to.o cpu.o
|
||||||
obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o
|
obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o
|
||||||
obj-$(CONFIG_KPROBES) += kprobes.o
|
obj-$(CONFIG_KPROBES) += kprobes.o
|
||||||
|
@ -251,13 +251,15 @@ syscall_badsys:
|
|||||||
.global ret_from_fork
|
.global ret_from_fork
|
||||||
ret_from_fork:
|
ret_from_fork:
|
||||||
call schedule_tail
|
call schedule_tail
|
||||||
|
mov r12, 0
|
||||||
|
rjmp syscall_return
|
||||||
|
|
||||||
/* check for syscall tracing */
|
.global ret_from_kernel_thread
|
||||||
get_thread_info r0
|
ret_from_kernel_thread:
|
||||||
ld.w r1, r0[TI_flags]
|
call schedule_tail
|
||||||
andl r1, _TIF_ALLWORK_MASK, COH
|
mov r12, r0
|
||||||
brne syscall_exit_work
|
mov lr, r2 /* syscall_return */
|
||||||
rjmp syscall_exit_cont
|
mov pc, r1
|
||||||
|
|
||||||
syscall_trace_enter:
|
syscall_trace_enter:
|
||||||
pushm r8-r12
|
pushm r8-r12
|
||||||
|
@ -68,44 +68,6 @@ void machine_restart(char *cmd)
|
|||||||
while (1) ;
|
while (1) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* PC is actually discarded when returning from a system call -- the
|
|
||||||
* return address must be stored in LR. This function will make sure
|
|
||||||
* LR points to do_exit before starting the thread.
|
|
||||||
*
|
|
||||||
* Also, when returning from fork(), r12 is 0, so we must copy the
|
|
||||||
* argument as well.
|
|
||||||
*
|
|
||||||
* r0 : The argument to the main thread function
|
|
||||||
* r1 : The address of do_exit
|
|
||||||
* r2 : The address of the main thread function
|
|
||||||
*/
|
|
||||||
asmlinkage extern void kernel_thread_helper(void);
|
|
||||||
__asm__(" .type kernel_thread_helper, @function\n"
|
|
||||||
"kernel_thread_helper:\n"
|
|
||||||
" mov r12, r0\n"
|
|
||||||
" mov lr, r2\n"
|
|
||||||
" mov pc, r1\n"
|
|
||||||
" .size kernel_thread_helper, . - kernel_thread_helper");
|
|
||||||
|
|
||||||
int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
|
|
||||||
{
|
|
||||||
struct pt_regs regs;
|
|
||||||
|
|
||||||
memset(®s, 0, sizeof(regs));
|
|
||||||
|
|
||||||
regs.r0 = (unsigned long)arg;
|
|
||||||
regs.r1 = (unsigned long)fn;
|
|
||||||
regs.r2 = (unsigned long)do_exit;
|
|
||||||
regs.lr = (unsigned long)kernel_thread_helper;
|
|
||||||
regs.pc = (unsigned long)kernel_thread_helper;
|
|
||||||
regs.sr = MODE_SUPERVISOR;
|
|
||||||
|
|
||||||
return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
|
|
||||||
0, ®s, 0, NULL, NULL);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(kernel_thread);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free current thread data structures etc
|
* Free current thread data structures etc
|
||||||
*/
|
*/
|
||||||
@ -332,26 +294,31 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage void ret_from_fork(void);
|
asmlinkage void ret_from_fork(void);
|
||||||
|
asmlinkage void ret_from_kernel_thread(void);
|
||||||
|
asmlinkage void syscall_return(void);
|
||||||
|
|
||||||
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
unsigned long unused,
|
unsigned long arg,
|
||||||
struct task_struct *p, struct pt_regs *regs)
|
struct task_struct *p, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct pt_regs *childregs;
|
struct pt_regs *childregs = task_pt_regs(p);
|
||||||
|
|
||||||
childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1;
|
if (unlikely(!regs)) {
|
||||||
|
memset(childregs, 0, sizeof(struct pt_regs));
|
||||||
|
p->thread.cpu_context.r0 = arg;
|
||||||
|
p->thread.cpu_context.r1 = usp; /* fn */
|
||||||
|
p->thread.cpu_context.r2 = syscall_return;
|
||||||
|
p->thread.cpu_context.pc = (unsigned long)ret_from_kernel_thread;
|
||||||
|
childregs->sr = MODE_SUPERVISOR;
|
||||||
|
} else {
|
||||||
*childregs = *regs;
|
*childregs = *regs;
|
||||||
|
|
||||||
if (user_mode(regs))
|
|
||||||
childregs->sp = usp;
|
childregs->sp = usp;
|
||||||
else
|
|
||||||
childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
|
|
||||||
|
|
||||||
childregs->r12 = 0; /* Set return value for child */
|
childregs->r12 = 0; /* Set return value for child */
|
||||||
|
p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
|
||||||
|
}
|
||||||
|
|
||||||
p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM;
|
p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM;
|
||||||
p->thread.cpu_context.ksp = (unsigned long)childregs;
|
p->thread.cpu_context.ksp = (unsigned long)childregs;
|
||||||
p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
|
|
||||||
|
|
||||||
clear_tsk_thread_flag(p, TIF_DEBUG);
|
clear_tsk_thread_flag(p, TIF_DEBUG);
|
||||||
if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))
|
if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2004-2006 Atmel Corporation
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*/
|
|
||||||
#include <linux/unistd.h>
|
|
||||||
|
|
||||||
int kernel_execve(const char *file,
|
|
||||||
const char *const *argv,
|
|
||||||
const char *const *envp)
|
|
||||||
{
|
|
||||||
register long scno asm("r8") = __NR_execve;
|
|
||||||
register long sc1 asm("r12") = (long)file;
|
|
||||||
register long sc2 asm("r11") = (long)argv;
|
|
||||||
register long sc3 asm("r10") = (long)envp;
|
|
||||||
|
|
||||||
asm volatile("scall"
|
|
||||||
: "=r"(sc1)
|
|
||||||
: "r"(scno), "0"(sc1), "r"(sc2), "r"(sc3)
|
|
||||||
: "cc", "memory");
|
|
||||||
return sc1;
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user