From 8bfdb4ba016d5b2cc415ce516c5697feaa04f83f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 14 Oct 2012 01:41:42 -0400 Subject: [PATCH] --- yaml --- r: 340311 b: refs/heads/master c: 7147e215480323bb2617fcebf585c447188ff760 h: refs/heads/master i: 340309: d515b914d7b461c5540301702f2ed5cdc8c06a0b 340307: f60e450b2c9538e29991e18a3951e56b57fc1826 340303: 3bbd355d5d3ec005b052bf153116222b07da7c9d v: v3 --- [refs] | 2 +- trunk/arch/score/Kconfig | 2 - trunk/arch/score/include/asm/processor.h | 1 + trunk/arch/score/include/asm/syscalls.h | 1 + trunk/arch/score/include/asm/unistd.h | 1 - trunk/arch/score/kernel/entry.S | 12 ++--- trunk/arch/score/kernel/process.c | 55 ++++++++++++++------ trunk/arch/score/kernel/sys_score.c | 54 ++++++++++++++++++++ trunk/arch/sh/Kconfig | 2 + trunk/arch/sh/include/asm/processor_32.h | 5 -- trunk/arch/sh/include/asm/processor_64.h | 5 -- trunk/arch/sh/kernel/Makefile | 3 +- trunk/arch/sh/kernel/cpu/sh5/entry.S | 19 +++++++ trunk/arch/sh/kernel/entry-common.S | 13 +++++ trunk/arch/sh/kernel/process_32.c | 64 +++++++----------------- trunk/arch/sh/kernel/process_64.c | 60 ++++++---------------- trunk/arch/sh/kernel/sys_sh32.c | 24 --------- trunk/arch/sh/kernel/sys_sh64.c | 50 ------------------ 18 files changed, 174 insertions(+), 199 deletions(-) delete mode 100644 trunk/arch/sh/kernel/sys_sh64.c diff --git a/[refs] b/[refs] index cd1145bd372f..212c50339c3c 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 1ffbed7220331dabc04dee6d3c520b5b022b9245 +refs/heads/master: 7147e215480323bb2617fcebf585c447188ff760 diff --git a/trunk/arch/score/Kconfig b/trunk/arch/score/Kconfig index a285e78fb9c5..4f93a431a45a 100644 --- a/trunk/arch/score/Kconfig +++ b/trunk/arch/score/Kconfig @@ -13,8 +13,6 @@ config SCORE select GENERIC_CLOCKEVENTS select HAVE_MOD_ARCH_SPECIFIC select MODULES_USE_ELF_REL - select GENERIC_KERNEL_THREAD - select GENERIC_KERNEL_EXECVE choice prompt "System type" diff --git a/trunk/arch/score/include/asm/processor.h b/trunk/arch/score/include/asm/processor.h index d9a922d8711b..ab3aceb54209 100644 --- a/trunk/arch/score/include/asm/processor.h +++ b/trunk/arch/score/include/asm/processor.h @@ -13,6 +13,7 @@ struct task_struct; */ extern void (*cpu_wait)(void); +extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); extern unsigned long thread_saved_pc(struct task_struct *tsk); extern void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp); diff --git a/trunk/arch/score/include/asm/syscalls.h b/trunk/arch/score/include/asm/syscalls.h index 8d332534342f..1dd5e0d6b0c3 100644 --- a/trunk/arch/score/include/asm/syscalls.h +++ b/trunk/arch/score/include/asm/syscalls.h @@ -2,6 +2,7 @@ #define _ASM_SCORE_SYSCALLS_H asmlinkage long score_clone(struct pt_regs *regs); +asmlinkage long score_execve(struct pt_regs *regs); asmlinkage long score_sigaltstack(struct pt_regs *regs); asmlinkage long score_rt_sigreturn(struct pt_regs *regs); diff --git a/trunk/arch/score/include/asm/unistd.h b/trunk/arch/score/include/asm/unistd.h index b006ca435120..a862384e9c16 100644 --- a/trunk/arch/score/include/asm/unistd.h +++ b/trunk/arch/score/include/asm/unistd.h @@ -4,6 +4,5 @@ #define __ARCH_WANT_SYSCALL_NO_FLAGS #define __ARCH_WANT_SYSCALL_OFF_T #define __ARCH_WANT_SYSCALL_DEPRECATED -#define __ARCH_WANT_SYS_EXECVE #include diff --git a/trunk/arch/score/kernel/entry.S b/trunk/arch/score/kernel/entry.S index da9901088bbb..83bb96079c43 100644 --- a/trunk/arch/score/kernel/entry.S +++ b/trunk/arch/score/kernel/entry.S @@ -278,13 +278,6 @@ need_resched: nop #endif -ENTRY(ret_from_kernel_thread) - bl schedule_tail # r4=struct task_struct *prev - nop - mv r4, r13 - brl r12 - j syscall_exit - ENTRY(ret_from_fork) bl schedule_tail # r4=struct task_struct *prev @@ -487,6 +480,11 @@ illegal_syscall: sw r9, [r0, PT_R7] j syscall_return +ENTRY(sys_execve) + mv r4, r0 + la r8, score_execve + br r8 + ENTRY(sys_clone) mv r4, r0 la r8, score_clone diff --git a/trunk/arch/score/kernel/process.c b/trunk/arch/score/kernel/process.c index 6f311cf64b99..637970cfd3f4 100644 --- a/trunk/arch/score/kernel/process.c +++ b/trunk/arch/score/kernel/process.c @@ -60,7 +60,6 @@ void __noreturn cpu_idle(void) } void ret_from_fork(void); -void ret_from_kernel_thread(void); void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { @@ -87,27 +86,29 @@ void flush_thread(void) {} * set up the kernel stack and exception frames for a new process */ int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long arg, + unsigned long unused, struct task_struct *p, struct pt_regs *regs) { struct thread_info *ti = task_thread_info(p); struct pt_regs *childregs = task_pt_regs(p); - p->thread.reg0 = (unsigned long) childregs; - if (unlikely(!regs)) { - memset(childregs, 0, sizeof(struct pt_regs)); - p->thread->reg12 = usp; - p->thread->reg13 = arg; - p->thread.reg3 = (unsigned long) ret_from_kernel_thread; + p->set_child_tid = NULL; + p->clear_child_tid = NULL; + + *childregs = *regs; + childregs->regs[7] = 0; /* Clear error flag */ + childregs->regs[4] = 0; /* Child gets zero as return value */ + regs->regs[4] = p->pid; + + if (childregs->cp0_psr & 0x8) { /* test kernel fork or user fork */ + childregs->regs[0] = usp; /* user fork */ } else { - *childregs = *regs; - childregs->regs[7] = 0; /* Clear error flag */ - childregs->regs[4] = 0; /* Child gets zero as return value */ - childregs->regs[0] = usp; /* user fork */ - regs->regs[4] = p->pid; /* WTF? */ - p->thread.reg3 = (unsigned long) ret_from_fork; + childregs->regs[28] = (unsigned long) ti; /* kernel fork */ + childregs->regs[0] = (unsigned long) childregs; } + p->thread.reg0 = (unsigned long) childregs; + p->thread.reg3 = (unsigned long) ret_from_fork; p->thread.cp0_psr = 0; return 0; @@ -119,6 +120,32 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) return 1; } +static void __noreturn +kernel_thread_helper(void *unused0, int (*fn)(void *), + void *arg, void *unused1) +{ + do_exit(fn(arg)); +} + +/* + * Create a kernel thread. + */ +long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +{ + struct pt_regs regs; + + memset(®s, 0, sizeof(regs)); + + regs.regs[6] = (unsigned long) arg; + regs.regs[5] = (unsigned long) fn; + regs.cp0_epc = (unsigned long) kernel_thread_helper; + regs.cp0_psr = (regs.cp0_psr & ~(0x1|0x4|0x8)) | \ + ((regs.cp0_psr & 0x3) << 2); + + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, \ + 0, ®s, 0, NULL, NULL); +} + unsigned long thread_saved_pc(struct task_struct *tsk) { return task_pt_regs(tsk)->cp0_epc; diff --git a/trunk/arch/score/kernel/sys_score.c b/trunk/arch/score/kernel/sys_score.c index c54434c2fd9d..d45cf00a3351 100644 --- a/trunk/arch/score/kernel/sys_score.c +++ b/trunk/arch/score/kernel/sys_score.c @@ -83,3 +83,57 @@ score_vfork(struct pt_regs *regs) return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[0], regs, 0, NULL, NULL); } + +/* + * sys_execve() executes a new program. + * This is called indirectly via a small wrapper + */ +asmlinkage long +score_execve(struct pt_regs *regs) +{ + int error; + struct filename *filename; + + filename = getname((char __user*)regs->regs[4]); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + return error; + + error = do_execve(filename->name, + (const char __user *const __user *)regs->regs[5], + (const char __user *const __user *)regs->regs[6], + regs); + + putname(filename); + return error; +} + +/* + * Do a system call from kernel instead of calling sys_execve so we + * end up with proper pt_regs. + */ +asmlinkage +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) +{ + register unsigned long __r4 asm("r4") = (unsigned long) filename; + register unsigned long __r5 asm("r5") = (unsigned long) argv; + register unsigned long __r6 asm("r6") = (unsigned long) envp; + register unsigned long __r7 asm("r7"); + + __asm__ __volatile__ (" \n" + "ldi r27, %5 \n" + "syscall \n" + "mv %0, r4 \n" + "mv %1, r7 \n" + : "=&r" (__r4), "=r" (__r7) + : "r" (__r4), "r" (__r5), "r" (__r6), "i" (__NR_execve) + : "r8", "r9", "r10", "r11", "r22", "r23", "r24", "r25", + "r26", "r27", "memory"); + + if (__r7 == 0) + return __r4; + + return -__r4; +} diff --git a/trunk/arch/sh/Kconfig b/trunk/arch/sh/Kconfig index babc2b826c5c..8451317eed58 100644 --- a/trunk/arch/sh/Kconfig +++ b/trunk/arch/sh/Kconfig @@ -40,6 +40,8 @@ config SUPERH select GENERIC_STRNLEN_USER select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER select MODULES_USE_ELF_RELA + select GENERIC_KERNEL_THREAD + select GENERIC_KERNEL_EXECVE help The SuperH is a RISC processor targeted for use in embedded systems and consumer electronics; it was also used in the Sega Dreamcast diff --git a/trunk/arch/sh/include/asm/processor_32.h b/trunk/arch/sh/include/asm/processor_32.h index b6311fd2d066..b1320d55ca30 100644 --- a/trunk/arch/sh/include/asm/processor_32.h +++ b/trunk/arch/sh/include/asm/processor_32.h @@ -126,11 +126,6 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_pc, unsigned lo /* Free all resources held by a thread. */ 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); - /* Copy and release all segment info associated with a VM */ #define copy_segments(p, mm) do { } while(0) #define release_segments(mm) do { } while(0) diff --git a/trunk/arch/sh/include/asm/processor_64.h b/trunk/arch/sh/include/asm/processor_64.h index cd6029fb2c01..1ee8946f0952 100644 --- a/trunk/arch/sh/include/asm/processor_64.h +++ b/trunk/arch/sh/include/asm/processor_64.h @@ -159,11 +159,6 @@ struct mm_struct; /* Free all resources held by a thread. */ 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); - /* Copy and release all segment info associated with a VM */ #define copy_segments(p, mm) do { } while (0) diff --git a/trunk/arch/sh/kernel/Makefile b/trunk/arch/sh/kernel/Makefile index 88571ff8eeec..f259b37874e9 100644 --- a/trunk/arch/sh/kernel/Makefile +++ b/trunk/arch/sh/kernel/Makefile @@ -16,7 +16,7 @@ obj-y := debugtraps.o dma-nommu.o dumpstack.o \ machvec.o nmi_debug.o process.o \ process_$(BITS).o ptrace.o ptrace_$(BITS).o \ reboot.o return_address.o \ - setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ + setup.o signal_$(BITS).o sys_sh.o \ syscalls_$(BITS).o time.o topology.o traps.o \ traps_$(BITS).o unwinder.o @@ -25,6 +25,7 @@ obj-y += iomap.o obj-$(CONFIG_HAS_IOPORT) += ioport.o endif +obj-$(CONFIG_SUPERH32) += sys_sh32.o obj-y += cpu/ obj-$(CONFIG_VSYSCALL) += vsyscall/ obj-$(CONFIG_SMP) += smp.o diff --git a/trunk/arch/sh/kernel/cpu/sh5/entry.S b/trunk/arch/sh/kernel/cpu/sh5/entry.S index 7e605b95592a..0c8d0377d40b 100644 --- a/trunk/arch/sh/kernel/cpu/sh5/entry.S +++ b/trunk/arch/sh/kernel/cpu/sh5/entry.S @@ -1228,6 +1228,25 @@ ret_from_fork: pta ret_from_syscall, tr0 blink tr0, ZERO +.global ret_from_kernel_thread +ret_from_kernel_thread: + + movi schedule_tail,r5 + ori r5, 1, r5 + ptabs r5, tr0 + blink tr0, LINK + + ld.q SP, FRAME_R(2), r2 + ld.q SP, FRAME_R(3), r3 + ptabs r3, tr0 + blink tr0, LINK + + ld.q SP, FRAME_S(FSPC), r2 + addi r2, 4, r2 /* Move PC, being pre-execution event */ + st.q SP, FRAME_S(FSPC), r2 + pta ret_from_syscall, tr0 + blink tr0, ZERO + syscall_allowed: /* Use LINK to deflect the exit point, default is syscall_ret */ pta syscall_ret, tr0 diff --git a/trunk/arch/sh/kernel/entry-common.S b/trunk/arch/sh/kernel/entry-common.S index b96489d8b27d..9b6e4beeb296 100644 --- a/trunk/arch/sh/kernel/entry-common.S +++ b/trunk/arch/sh/kernel/entry-common.S @@ -297,6 +297,19 @@ ret_from_fork: mov r0, r4 bra syscall_exit nop + + .align 2 + .globl ret_from_kernel_thread +ret_from_kernel_thread: + mov.l 1f, r8 + jsr @r8 + mov r0, r4 + mov.l @(OFF_R5,r15), r5 ! fn + jsr @r5 + mov.l @(OFF_R4,r15), r4 ! arg + bra syscall_exit + nop + .align 2 1: .long schedule_tail diff --git a/trunk/arch/sh/kernel/process_32.c b/trunk/arch/sh/kernel/process_32.c index ba7345f37bc9..b55070b9a634 100644 --- a/trunk/arch/sh/kernel/process_32.c +++ b/trunk/arch/sh/kernel/process_32.c @@ -68,38 +68,6 @@ void show_regs(struct pt_regs * regs) show_code(regs); } -/* - * Create a kernel thread - */ -__noreturn void kernel_thread_helper(void *arg, int (*fn)(void *)) -{ - do_exit(fn(arg)); -} - -/* Don't use this in BL=1(cli). Or else, CPU resets! */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - struct pt_regs regs; - int pid; - - memset(®s, 0, sizeof(regs)); - regs.regs[4] = (unsigned long)arg; - regs.regs[5] = (unsigned long)fn; - - regs.pc = (unsigned long)kernel_thread_helper; - regs.sr = SR_MD; -#if defined(CONFIG_SH_FPU) - regs.sr |= SR_FD; -#endif - - /* Ok, create the new process.. */ - pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, - ®s, 0, NULL, NULL); - - return pid; -} -EXPORT_SYMBOL(kernel_thread); - void start_thread(struct pt_regs *regs, unsigned long new_pc, unsigned long new_sp) { @@ -157,9 +125,10 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) EXPORT_SYMBOL(dump_fpu); asmlinkage void ret_from_fork(void); +asmlinkage void ret_from_kernel_thread(void); 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 thread_info *ti = task_thread_info(p); @@ -177,29 +146,34 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, } #endif - childregs = task_pt_regs(p); - *childregs = *regs; + memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); - if (user_mode(regs)) { - childregs->regs[15] = usp; - ti->addr_limit = USER_DS; - } else { - childregs->regs[15] = (unsigned long)childregs; + childregs = task_pt_regs(p); + p->thread.sp = (unsigned long) childregs; + if (unlikely(p->flags & PF_KTHREAD)) { + memset(childregs, 0, sizeof(struct pt_regs)); + p->thread.pc = (unsigned long) ret_from_kernel_thread; + childregs->regs[4] = arg; + childregs->regs[5] = usp; + childregs->sr = SR_MD; +#if defined(CONFIG_SH_FPU) + childregs->sr |= SR_FD; +#endif ti->addr_limit = KERNEL_DS; ti->status &= ~TS_USEDFPU; p->fpu_counter = 0; + return 0; } + *childregs = *regs; + + childregs->regs[15] = usp; + ti->addr_limit = USER_DS; if (clone_flags & CLONE_SETTLS) childregs->gbr = childregs->regs[0]; childregs->regs[0] = 0; /* Set return value for child */ - - p->thread.sp = (unsigned long) childregs; p->thread.pc = (unsigned long) ret_from_fork; - - memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); - return 0; } diff --git a/trunk/arch/sh/kernel/process_64.c b/trunk/arch/sh/kernel/process_64.c index 98a709f0c3c4..fd338b030fd9 100644 --- a/trunk/arch/sh/kernel/process_64.c +++ b/trunk/arch/sh/kernel/process_64.c @@ -284,39 +284,6 @@ void show_regs(struct pt_regs *regs) } } -/* - * Create a kernel thread - */ -__noreturn void kernel_thread_helper(void *arg, int (*fn)(void *)) -{ - do_exit(fn(arg)); -} - -/* - * 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 freed until both the parent and the child have exited. - */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - struct pt_regs regs; - - memset(®s, 0, sizeof(regs)); - regs.regs[2] = (unsigned long)arg; - regs.regs[3] = (unsigned long)fn; - - regs.pc = (unsigned long)kernel_thread_helper; - regs.sr = (1 << 30); - - /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, - ®s, 0, NULL, NULL); -} -EXPORT_SYMBOL(kernel_thread); - /* * Free current thread data structures etc.. */ @@ -401,15 +368,17 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) EXPORT_SYMBOL(dump_fpu); asmlinkage void ret_from_fork(void); +asmlinkage void ret_from_kernel_thread(void); 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 pt_regs *childregs; #ifdef CONFIG_SH_FPU - if(last_task_used_math == current) { + /* can't happen for a kernel thread */ + if (last_task_used_math == current) { enable_fpu(); save_fpu(current); disable_fpu(); @@ -419,7 +388,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, #endif /* Copy from sh version */ childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1; + p->thread.sp = (unsigned long) childregs; + if (unlikely(p->flags & PF_KTHREAD)) { + memset(childregs, 0, sizeof(struct pt_regs)); + childregs->regs[2] = (unsigned long)arg; + childregs->regs[3] = (unsigned long)fn; + childregs->sr = (1 << 30); /* not user_mode */ + childregs->sr |= SR_FD; /* Invalidate FPU flag */ + p->thread.pc = (unsigned long) ret_from_kernel_thread; + return 0; + } *childregs = *regs; /* @@ -428,19 +407,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, * 32-bit wide and context switch must take care * of NEFF sign extension. */ - if (user_mode(regs)) { - childregs->regs[15] = neff_sign_extend(usp); - p->thread.uregs = childregs; - } else { - childregs->regs[15] = - neff_sign_extend((unsigned long)task_stack_page(p) + - THREAD_SIZE); - } + childregs->regs[15] = neff_sign_extend(usp); + p->thread.uregs = childregs; childregs->regs[9] = 0; /* Set return value for child */ childregs->sr |= SR_FD; /* Invalidate FPU flag */ - p->thread.sp = (unsigned long) childregs; p->thread.pc = (unsigned long) ret_from_fork; return 0; diff --git a/trunk/arch/sh/kernel/sys_sh32.c b/trunk/arch/sh/kernel/sys_sh32.c index f56b6fe5c5d0..497bab3a0401 100644 --- a/trunk/arch/sh/kernel/sys_sh32.c +++ b/trunk/arch/sh/kernel/sys_sh32.c @@ -60,27 +60,3 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1, (u64)len0 << 32 | len1, advice); #endif } - -#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A) -#define SYSCALL_ARG3 "trapa #0x23" -#else -#define SYSCALL_ARG3 "trapa #0x13" -#endif - -/* - * Do a system call from kernel instead of calling sys_execve so we - * end up with proper pt_regs. - */ -int kernel_execve(const char *filename, - const char *const argv[], - const char *const envp[]) -{ - register long __sc0 __asm__ ("r3") = __NR_execve; - register long __sc4 __asm__ ("r4") = (long) filename; - register long __sc5 __asm__ ("r5") = (long) argv; - register long __sc6 __asm__ ("r6") = (long) envp; - __asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0) - : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) - : "memory"); - return __sc0; -} diff --git a/trunk/arch/sh/kernel/sys_sh64.c b/trunk/arch/sh/kernel/sys_sh64.c deleted file mode 100644 index c5a38c4bf410..000000000000 --- a/trunk/arch/sh/kernel/sys_sh64.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * arch/sh/kernel/sys_sh64.c - * - * Copyright (C) 2000, 2001 Paolo Alberelli - * - * This file contains various random system calls that - * have a non-standard calling sequence on the Linux/SH5 - * platform. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Do a system call from kernel instead of calling sys_execve so we - * end up with proper pt_regs. - */ -int kernel_execve(const char *filename, - const char *const argv[], - const char *const envp[]) -{ - register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve); - register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename; - register unsigned long __sc3 __asm__ ("r3") = (unsigned long) argv; - register unsigned long __sc4 __asm__ ("r4") = (unsigned long) envp; - __asm__ __volatile__ ("trapa %1 !\t\t\t execve(%2,%3,%4)" - : "=r" (__sc0) - : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) ); - __asm__ __volatile__ ("!dummy %0 %1 %2 %3" - : : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) : "memory"); - return __sc0; -}