X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fkernel%2Fsys_arm.c;h=c087e26021c0f6a58b2fc7f72a24f2f9a37df50a;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=4f98f2485f968348f96396c564eb2acf72c755aa;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index 4f98f2485..c087e2602 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c @@ -12,6 +12,7 @@ * have a non-standard calling sequence on the Linux/arm * platform. */ +#include #include #include #include @@ -50,6 +51,13 @@ asmlinkage int sys_pipe(unsigned long __user *fildes) return error; } +/* + * This is the lowest virtual address we can permit any user space + * mapping to be mapped at. This is particularly important for + * non-high vector CPUs. + */ +#define MIN_MAP_ADDR (PAGE_SIZE) + /* common code for old and new mmaps */ inline long do_mmap2( unsigned long addr, unsigned long len, @@ -61,11 +69,7 @@ inline long do_mmap2( flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - /* - * If we are doing a fixed mapping, and address < PAGE_SIZE, - * then deny it. - */ - if (flags & MAP_FIXED && addr < PAGE_SIZE && vectors_base() == 0) + if (flags & MAP_FIXED && addr < MIN_MAP_ADDR) goto out; error = -EBADF; @@ -118,12 +122,7 @@ sys_arm_mremap(unsigned long addr, unsigned long old_len, { unsigned long ret = -EINVAL; - /* - * If we are doing a fixed mapping, and address < PAGE_SIZE, - * then deny it. - */ - if (flags & MREMAP_FIXED && new_addr < PAGE_SIZE && - vectors_base() == 0) + if (flags & MREMAP_FIXED && new_addr < MIN_MAP_ADDR) goto out; down_write(¤t->mm->mmap_sem); @@ -177,7 +176,7 @@ asmlinkage int sys_ipc(uint call, int first, int second, int third, union semun fourth; if (!ptr) return -EINVAL; - if (get_user(fourth.__pad, (void __user **) ptr)) + if (get_user(fourth.__pad, (void __user * __user *) ptr)) return -EFAULT; return sys_semctl (first, second, third, fourth); } @@ -216,11 +215,8 @@ asmlinkage int sys_ipc(uint call, int first, int second, int third, return ret; return put_user(raddr, (ulong __user *)third); } - case 1: /* iBCS2 emulator entry point */ - if (!segment_eq(get_fs(), get_ds())) - return -EINVAL; - return do_shmat(first, (char __user *) ptr, - second, (ulong __user *) third); + case 1: /* Of course, we don't support iBCS2! */ + return -EINVAL; } case SHMDT: return sys_shmdt ((char __user *)ptr); @@ -245,18 +241,14 @@ asmlinkage int sys_fork(struct pt_regs *regs) /* Clone a task - this clones the calling program thread. * This is called indirectly via a small wrapper */ -asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs) +asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, + int __user *parent_tidptr, int tls_val, + int __user *child_tidptr, struct pt_regs *regs) { - /* - * We don't support SETTID / CLEARTID - */ - if (clone_flags & (CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID)) - return -EINVAL; - if (!newsp) newsp = regs->ARM_sp; - return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL); + return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); } asmlinkage int sys_vfork(struct pt_regs *regs) @@ -282,3 +274,43 @@ asmlinkage int sys_execve(char __user *filenamei, char __user * __user *argv, out: return error; } + +long execve(const char *filename, char **argv, char **envp) +{ + struct pt_regs regs; + int ret; + + memset(®s, 0, sizeof(struct pt_regs)); + ret = do_execve((char *)filename, (char __user * __user *)argv, + (char __user * __user *)envp, ®s); + 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" (®s), + "Ir" (sizeof(regs)) + : "r0", "r1", "r2", "r3", "ip", "memory"); + + out: + return ret; +} +EXPORT_SYMBOL(execve);