1*7992d60dSCatalin Marinas /* 2*7992d60dSCatalin Marinas * AArch64-specific system calls implementation 3*7992d60dSCatalin Marinas * 4*7992d60dSCatalin Marinas * Copyright (C) 2012 ARM Ltd. 5*7992d60dSCatalin Marinas * Author: Catalin Marinas <[email protected]> 6*7992d60dSCatalin Marinas * 7*7992d60dSCatalin Marinas * This program is free software; you can redistribute it and/or modify 8*7992d60dSCatalin Marinas * it under the terms of the GNU General Public License version 2 as 9*7992d60dSCatalin Marinas * published by the Free Software Foundation. 10*7992d60dSCatalin Marinas * 11*7992d60dSCatalin Marinas * This program is distributed in the hope that it will be useful, 12*7992d60dSCatalin Marinas * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*7992d60dSCatalin Marinas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*7992d60dSCatalin Marinas * GNU General Public License for more details. 15*7992d60dSCatalin Marinas * 16*7992d60dSCatalin Marinas * You should have received a copy of the GNU General Public License 17*7992d60dSCatalin Marinas * along with this program. If not, see <http://www.gnu.org/licenses/>. 18*7992d60dSCatalin Marinas */ 19*7992d60dSCatalin Marinas 20*7992d60dSCatalin Marinas #include <linux/compiler.h> 21*7992d60dSCatalin Marinas #include <linux/errno.h> 22*7992d60dSCatalin Marinas #include <linux/fs.h> 23*7992d60dSCatalin Marinas #include <linux/mm.h> 24*7992d60dSCatalin Marinas #include <linux/export.h> 25*7992d60dSCatalin Marinas #include <linux/sched.h> 26*7992d60dSCatalin Marinas #include <linux/slab.h> 27*7992d60dSCatalin Marinas #include <linux/syscalls.h> 28*7992d60dSCatalin Marinas 29*7992d60dSCatalin Marinas /* 30*7992d60dSCatalin Marinas * Clone a task - this clones the calling program thread. 31*7992d60dSCatalin Marinas */ 32*7992d60dSCatalin Marinas asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, 33*7992d60dSCatalin Marinas int __user *parent_tidptr, unsigned long tls_val, 34*7992d60dSCatalin Marinas int __user *child_tidptr, struct pt_regs *regs) 35*7992d60dSCatalin Marinas { 36*7992d60dSCatalin Marinas if (!newsp) 37*7992d60dSCatalin Marinas newsp = regs->sp; 38*7992d60dSCatalin Marinas /* 16-byte aligned stack mandatory on AArch64 */ 39*7992d60dSCatalin Marinas if (newsp & 15) 40*7992d60dSCatalin Marinas return -EINVAL; 41*7992d60dSCatalin Marinas return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); 42*7992d60dSCatalin Marinas } 43*7992d60dSCatalin Marinas 44*7992d60dSCatalin Marinas /* 45*7992d60dSCatalin Marinas * sys_execve() executes a new program. 46*7992d60dSCatalin Marinas */ 47*7992d60dSCatalin Marinas asmlinkage long sys_execve(const char __user *filenamei, 48*7992d60dSCatalin Marinas const char __user *const __user *argv, 49*7992d60dSCatalin Marinas const char __user *const __user *envp, 50*7992d60dSCatalin Marinas struct pt_regs *regs) 51*7992d60dSCatalin Marinas { 52*7992d60dSCatalin Marinas long error; 53*7992d60dSCatalin Marinas char * filename; 54*7992d60dSCatalin Marinas 55*7992d60dSCatalin Marinas filename = getname(filenamei); 56*7992d60dSCatalin Marinas error = PTR_ERR(filename); 57*7992d60dSCatalin Marinas if (IS_ERR(filename)) 58*7992d60dSCatalin Marinas goto out; 59*7992d60dSCatalin Marinas error = do_execve(filename, argv, envp, regs); 60*7992d60dSCatalin Marinas putname(filename); 61*7992d60dSCatalin Marinas out: 62*7992d60dSCatalin Marinas return error; 63*7992d60dSCatalin Marinas } 64*7992d60dSCatalin Marinas 65*7992d60dSCatalin Marinas int kernel_execve(const char *filename, 66*7992d60dSCatalin Marinas const char *const argv[], 67*7992d60dSCatalin Marinas const char *const envp[]) 68*7992d60dSCatalin Marinas { 69*7992d60dSCatalin Marinas struct pt_regs regs; 70*7992d60dSCatalin Marinas int ret; 71*7992d60dSCatalin Marinas 72*7992d60dSCatalin Marinas memset(®s, 0, sizeof(struct pt_regs)); 73*7992d60dSCatalin Marinas ret = do_execve(filename, 74*7992d60dSCatalin Marinas (const char __user *const __user *)argv, 75*7992d60dSCatalin Marinas (const char __user *const __user *)envp, ®s); 76*7992d60dSCatalin Marinas if (ret < 0) 77*7992d60dSCatalin Marinas goto out; 78*7992d60dSCatalin Marinas 79*7992d60dSCatalin Marinas /* 80*7992d60dSCatalin Marinas * Save argc to the register structure for userspace. 81*7992d60dSCatalin Marinas */ 82*7992d60dSCatalin Marinas regs.regs[0] = ret; 83*7992d60dSCatalin Marinas 84*7992d60dSCatalin Marinas /* 85*7992d60dSCatalin Marinas * We were successful. We won't be returning to our caller, but 86*7992d60dSCatalin Marinas * instead to user space by manipulating the kernel stack. 87*7992d60dSCatalin Marinas */ 88*7992d60dSCatalin Marinas asm( "add x0, %0, %1\n\t" 89*7992d60dSCatalin Marinas "mov x1, %2\n\t" 90*7992d60dSCatalin Marinas "mov x2, %3\n\t" 91*7992d60dSCatalin Marinas "bl memmove\n\t" /* copy regs to top of stack */ 92*7992d60dSCatalin Marinas "mov x27, #0\n\t" /* not a syscall */ 93*7992d60dSCatalin Marinas "mov x28, %0\n\t" /* thread structure */ 94*7992d60dSCatalin Marinas "mov sp, x0\n\t" /* reposition stack pointer */ 95*7992d60dSCatalin Marinas "b ret_to_user" 96*7992d60dSCatalin Marinas : 97*7992d60dSCatalin Marinas : "r" (current_thread_info()), 98*7992d60dSCatalin Marinas "Ir" (THREAD_START_SP - sizeof(regs)), 99*7992d60dSCatalin Marinas "r" (®s), 100*7992d60dSCatalin Marinas "Ir" (sizeof(regs)) 101*7992d60dSCatalin Marinas : "x0", "x1", "x2", "x27", "x28", "x30", "memory"); 102*7992d60dSCatalin Marinas 103*7992d60dSCatalin Marinas out: 104*7992d60dSCatalin Marinas return ret; 105*7992d60dSCatalin Marinas } 106*7992d60dSCatalin Marinas EXPORT_SYMBOL(kernel_execve); 107*7992d60dSCatalin Marinas 108*7992d60dSCatalin Marinas asmlinkage long sys_mmap(unsigned long addr, unsigned long len, 109*7992d60dSCatalin Marinas unsigned long prot, unsigned long flags, 110*7992d60dSCatalin Marinas unsigned long fd, off_t off) 111*7992d60dSCatalin Marinas { 112*7992d60dSCatalin Marinas if (offset_in_page(off) != 0) 113*7992d60dSCatalin Marinas return -EINVAL; 114*7992d60dSCatalin Marinas 115*7992d60dSCatalin Marinas return sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); 116*7992d60dSCatalin Marinas } 117*7992d60dSCatalin Marinas 118*7992d60dSCatalin Marinas /* 119*7992d60dSCatalin Marinas * Wrappers to pass the pt_regs argument. 120*7992d60dSCatalin Marinas */ 121*7992d60dSCatalin Marinas #define sys_execve sys_execve_wrapper 122*7992d60dSCatalin Marinas #define sys_clone sys_clone_wrapper 123*7992d60dSCatalin Marinas #define sys_rt_sigreturn sys_rt_sigreturn_wrapper 124*7992d60dSCatalin Marinas #define sys_sigaltstack sys_sigaltstack_wrapper 125*7992d60dSCatalin Marinas 126*7992d60dSCatalin Marinas #include <asm/syscalls.h> 127*7992d60dSCatalin Marinas 128*7992d60dSCatalin Marinas #undef __SYSCALL 129*7992d60dSCatalin Marinas #define __SYSCALL(nr, sym) [nr] = sym, 130*7992d60dSCatalin Marinas 131*7992d60dSCatalin Marinas /* 132*7992d60dSCatalin Marinas * The sys_call_table array must be 4K aligned to be accessible from 133*7992d60dSCatalin Marinas * kernel/entry.S. 134*7992d60dSCatalin Marinas */ 135*7992d60dSCatalin Marinas void *sys_call_table[__NR_syscalls] __aligned(4096) = { 136*7992d60dSCatalin Marinas [0 ... __NR_syscalls - 1] = sys_ni_syscall, 137*7992d60dSCatalin Marinas #include <asm/unistd.h> 138*7992d60dSCatalin Marinas }; 139