Commit 0dc18742 authored by Ian Molton's avatar Ian Molton Committed by Linus Torvalds

[PATCH] arm26: new execve code

This pulls in the execve changes made in arm32.

Also, drops some old arm32 power management stuff thats no longer relevant
in process.c.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3544d7de
......@@ -67,42 +67,22 @@ static int __init hlt_setup(char *__unused)
__setup("nohlt", nohlt_setup);
__setup("hlt", hlt_setup);
/*
* The following aren't currently used.
*/
void (*pm_idle)(void);
void (*pm_power_off)(void);
/*
* This is our default idle handler. We need to disable
* interrupts here to ensure we don't miss a wakeup call.
*/
void default_idle(void)
{
local_irq_disable();
if (!need_resched() && !hlt_counter)
local_irq_enable();
}
/*
* The idle thread. We try to conserve power, while trying to keep
* overall latency low. The architecture specific idle is passed
* a value to indicate the level of "idleness" of the system.
*/
void cpu_idle(void)
{
/* endless idle loop with no priority at all */
preempt_disable();
while (1) {
void (*idle)(void) = pm_idle;
if (!idle)
idle = default_idle;
leds_event(led_idle_start);
while (!need_resched())
idle();
leds_event(led_idle_end);
schedule();
while (!need_resched()) {
local_irq_disable();
if (!need_resched() && !hlt_counter)
local_irq_enable();
}
}
schedule();
}
static char reboot_mode = 'h';
......@@ -115,20 +95,15 @@ int __init reboot_setup(char *str)
__setup("reboot=", reboot_setup);
/* ARM26 cant do these but we still need to define them. */
void machine_halt(void)
{
leds_event(led_halted);
}
EXPORT_SYMBOL(machine_halt);
void machine_power_off(void)
{
leds_event(led_halted);
if (pm_power_off)
pm_power_off();
}
EXPORT_SYMBOL(machine_halt);
EXPORT_SYMBOL(machine_power_off);
void machine_restart(char * __unused)
......@@ -306,7 +281,7 @@ void release_thread(struct task_struct *dead_task)
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
int
copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
copy_thread(int nr, unsigned long clone_flags, unsigned long stack_start,
unsigned long unused, struct task_struct *p, struct pt_regs *regs)
{
struct thread_info *thread = p->thread_info;
......@@ -315,7 +290,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
childregs = __get_user_regs(thread);
*childregs = *regs;
childregs->ARM_r0 = 0;
childregs->ARM_sp = esp;
childregs->ARM_sp = stack_start;
memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
thread->cpu_context.sp = (unsigned long)childregs;
......@@ -367,35 +342,42 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
}
/*
* This is the mechanism for creating a new kernel thread.
*
* NOTE! Only a kernel-only process(ie the swapper or direct descendants
* who haven't done an "execve()") should use this: it will work within
* a system call from a "real" process, but the process memory space will
* not be free'd until both the parent and the child have exited.
* FIXME - taken from arm32
* Shuffle the argument into the correct register before calling the
* thread function. r1 is the thread argument, r2 is the pointer to
* the thread function, and r3 points to the exit function.
* FIXME - make sure this is right - the older code used to zero fp
* and cause the parent to call sys_exit (do_exit in this version)
*/
extern void kernel_thread_helper(void);
asm( ".section .text\n"
" .align\n"
" .type kernel_thread_helper, #function\n"
"kernel_thread_helper:\n"
" mov r0, r1\n"
" mov lr, r3\n"
" mov pc, r2\n"
" .size kernel_thread_helper, . - kernel_thread_helper\n"
" .previous");
/*
* Create a kernel thread.
*/
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
register unsigned int r0 asm("r0") = flags | CLONE_VM | CLONE_UNTRACED;
register unsigned int r1 asm("r1") = 0;
register pid_t __ret asm("r0");
__asm__ __volatile__(
__syscall(clone)" @ kernel_thread sys_clone \n\
movs %0, r0 @ if we are the child \n\
bne 1f \n\
mov fp, #0 @ ensure that fp is zero \n\
mov r0, %4 \n\
mov lr, pc \n\
mov pc, %3 \n\
b sys_exit \n\
1: "
: "=r" (__ret)
: "0" (r0), "r" (r1), "r" (fn), "r" (arg)
: "lr");
return __ret;
struct pt_regs regs;
memset(&regs, 0, sizeof(regs));
regs.ARM_r1 = (unsigned long)arg;
regs.ARM_r2 = (unsigned long)fn;
regs.ARM_r3 = (unsigned long)do_exit;
regs.ARM_pc = (unsigned long)kernel_thread_helper | MODE_SVC26;
return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}
EXPORT_SYMBOL(kernel_thread);
unsigned long get_wchan(struct task_struct *p)
{
......
......@@ -13,6 +13,7 @@
* have a non-standard calling sequence on the Linux/arm
* platform.
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/slab.h>
......@@ -281,3 +282,43 @@ asmlinkage int sys_execve(char *filenamei, char **argv, char **envp, struct pt_r
out:
return error;
}
/* FIXME - see if this is correct for arm26 */
long execve(const char *filename, char **argv, char **envp)
{
struct pt_regs regs;
int ret;
memset(&regs, 0, sizeof(struct pt_regs));
ret = do_execve((char *)filename, (char __user * __user *)argv, (char __user * __user *)envp, &regs);
if (ret < 0)
goto out;
/*
* Save argc to the register structure for userspace.
*/
regs.ARM_r0 = ret;
/*
* We were successful. We won't be returning to our caller, but
* instead to user space by manipulating the kernel stack.
*/
asm( "add r0, %0, %1\n\t"
"mov r1, %2\n\t"
"mov r2, %3\n\t"
"bl memmove\n\t" /* copy regs to top of stack */
"mov r8, #0\n\t" /* not a syscall */
"mov r9, %0\n\t" /* thread structure */
"mov sp, r0\n\t" /* reposition stack pointer */
"b ret_to_user"
:
: "r" (current_thread_info()),
"Ir" (THREAD_SIZE - 8 - sizeof(regs)),
"r" (&regs),
"Ir" (sizeof(regs))
: "r0", "r1", "r2", "r3", "ip", "memory");
out:
return ret;
}
EXPORT_SYMBOL(execve);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment