1f27bb139SMarc Zyngier /* 2f27bb139SMarc Zyngier * Copyright (C) 2012 ARM Ltd. 3f27bb139SMarc Zyngier * 4f27bb139SMarc Zyngier * This program is free software; you can redistribute it and/or modify 5f27bb139SMarc Zyngier * it under the terms of the GNU General Public License version 2 as 6f27bb139SMarc Zyngier * published by the Free Software Foundation. 7f27bb139SMarc Zyngier * 8f27bb139SMarc Zyngier * This program is distributed in the hope that it will be useful, 9f27bb139SMarc Zyngier * but WITHOUT ANY WARRANTY; without even the implied warranty of 10f27bb139SMarc Zyngier * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11f27bb139SMarc Zyngier * GNU General Public License for more details. 12f27bb139SMarc Zyngier * 13f27bb139SMarc Zyngier * You should have received a copy of the GNU General Public License 14f27bb139SMarc Zyngier * along with this program. If not, see <http://www.gnu.org/licenses/>. 15f27bb139SMarc Zyngier */ 16f27bb139SMarc Zyngier #ifndef __ASM_SYSCALL_H 17f27bb139SMarc Zyngier #define __ASM_SYSCALL_H 18f27bb139SMarc Zyngier 19875cbf3eSAKASHI Takahiro #include <uapi/linux/audit.h> 20875cbf3eSAKASHI Takahiro #include <linux/compat.h> 21f27bb139SMarc Zyngier #include <linux/err.h> 22f27bb139SMarc Zyngier 2327d83e68SMark Rutland typedef long (*syscall_fn_t)(unsigned long, unsigned long, 2427d83e68SMark Rutland unsigned long, unsigned long, 2527d83e68SMark Rutland unsigned long, unsigned long); 2627d83e68SMark Rutland 2727d83e68SMark Rutland extern const syscall_fn_t sys_call_table[]; 28f27bb139SMarc Zyngier 293b714275SMark Rutland #ifdef CONFIG_COMPAT 303b714275SMark Rutland extern const syscall_fn_t compat_sys_call_table[]; 313b714275SMark Rutland #endif 323b714275SMark Rutland 33f27bb139SMarc Zyngier static inline int syscall_get_nr(struct task_struct *task, 34f27bb139SMarc Zyngier struct pt_regs *regs) 35f27bb139SMarc Zyngier { 36f27bb139SMarc Zyngier return regs->syscallno; 37f27bb139SMarc Zyngier } 38f27bb139SMarc Zyngier 39f27bb139SMarc Zyngier static inline void syscall_rollback(struct task_struct *task, 40f27bb139SMarc Zyngier struct pt_regs *regs) 41f27bb139SMarc Zyngier { 42f27bb139SMarc Zyngier regs->regs[0] = regs->orig_x0; 43f27bb139SMarc Zyngier } 44f27bb139SMarc Zyngier 45f27bb139SMarc Zyngier 46f27bb139SMarc Zyngier static inline long syscall_get_error(struct task_struct *task, 47f27bb139SMarc Zyngier struct pt_regs *regs) 48f27bb139SMarc Zyngier { 49f27bb139SMarc Zyngier unsigned long error = regs->regs[0]; 50f27bb139SMarc Zyngier return IS_ERR_VALUE(error) ? error : 0; 51f27bb139SMarc Zyngier } 52f27bb139SMarc Zyngier 53f27bb139SMarc Zyngier static inline long syscall_get_return_value(struct task_struct *task, 54f27bb139SMarc Zyngier struct pt_regs *regs) 55f27bb139SMarc Zyngier { 56f27bb139SMarc Zyngier return regs->regs[0]; 57f27bb139SMarc Zyngier } 58f27bb139SMarc Zyngier 59f27bb139SMarc Zyngier static inline void syscall_set_return_value(struct task_struct *task, 60f27bb139SMarc Zyngier struct pt_regs *regs, 61f27bb139SMarc Zyngier int error, long val) 62f27bb139SMarc Zyngier { 63f27bb139SMarc Zyngier regs->regs[0] = (long) error ? error : val; 64f27bb139SMarc Zyngier } 65f27bb139SMarc Zyngier 66f27bb139SMarc Zyngier #define SYSCALL_MAX_ARGS 6 67f27bb139SMarc Zyngier 68f27bb139SMarc Zyngier static inline void syscall_get_arguments(struct task_struct *task, 69f27bb139SMarc Zyngier struct pt_regs *regs, 70f27bb139SMarc Zyngier unsigned int i, unsigned int n, 71f27bb139SMarc Zyngier unsigned long *args) 72f27bb139SMarc Zyngier { 737b22c035SAKASHI Takahiro if (n == 0) 747b22c035SAKASHI Takahiro return; 757b22c035SAKASHI Takahiro 76f27bb139SMarc Zyngier if (i + n > SYSCALL_MAX_ARGS) { 77f27bb139SMarc Zyngier unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i; 78f27bb139SMarc Zyngier unsigned int n_bad = n + i - SYSCALL_MAX_ARGS; 79f27bb139SMarc Zyngier pr_warning("%s called with max args %d, handling only %d\n", 80f27bb139SMarc Zyngier __func__, i + n, SYSCALL_MAX_ARGS); 81f27bb139SMarc Zyngier memset(args_bad, 0, n_bad * sizeof(args[0])); 82f27bb139SMarc Zyngier } 83f27bb139SMarc Zyngier 84f27bb139SMarc Zyngier if (i == 0) { 85f27bb139SMarc Zyngier args[0] = regs->orig_x0; 86f27bb139SMarc Zyngier args++; 87f27bb139SMarc Zyngier i++; 88f27bb139SMarc Zyngier n--; 89f27bb139SMarc Zyngier } 90f27bb139SMarc Zyngier 91f27bb139SMarc Zyngier memcpy(args, ®s->regs[i], n * sizeof(args[0])); 92f27bb139SMarc Zyngier } 93f27bb139SMarc Zyngier 94f27bb139SMarc Zyngier static inline void syscall_set_arguments(struct task_struct *task, 95f27bb139SMarc Zyngier struct pt_regs *regs, 96f27bb139SMarc Zyngier unsigned int i, unsigned int n, 97f27bb139SMarc Zyngier const unsigned long *args) 98f27bb139SMarc Zyngier { 997b22c035SAKASHI Takahiro if (n == 0) 1007b22c035SAKASHI Takahiro return; 1017b22c035SAKASHI Takahiro 102f27bb139SMarc Zyngier if (i + n > SYSCALL_MAX_ARGS) { 103f27bb139SMarc Zyngier pr_warning("%s called with max args %d, handling only %d\n", 104f27bb139SMarc Zyngier __func__, i + n, SYSCALL_MAX_ARGS); 105f27bb139SMarc Zyngier n = SYSCALL_MAX_ARGS - i; 106f27bb139SMarc Zyngier } 107f27bb139SMarc Zyngier 108f27bb139SMarc Zyngier if (i == 0) { 109f27bb139SMarc Zyngier regs->orig_x0 = args[0]; 110f27bb139SMarc Zyngier args++; 111f27bb139SMarc Zyngier i++; 112f27bb139SMarc Zyngier n--; 113f27bb139SMarc Zyngier } 114f27bb139SMarc Zyngier 115f27bb139SMarc Zyngier memcpy(®s->regs[i], args, n * sizeof(args[0])); 116f27bb139SMarc Zyngier } 117f27bb139SMarc Zyngier 118875cbf3eSAKASHI Takahiro /* 119875cbf3eSAKASHI Takahiro * We don't care about endianness (__AUDIT_ARCH_LE bit) here because 120875cbf3eSAKASHI Takahiro * AArch64 has the same system calls both on little- and big- endian. 121875cbf3eSAKASHI Takahiro */ 122875cbf3eSAKASHI Takahiro static inline int syscall_get_arch(void) 123875cbf3eSAKASHI Takahiro { 124875cbf3eSAKASHI Takahiro if (is_compat_task()) 125875cbf3eSAKASHI Takahiro return AUDIT_ARCH_ARM; 126875cbf3eSAKASHI Takahiro 127875cbf3eSAKASHI Takahiro return AUDIT_ARCH_AARCH64; 128875cbf3eSAKASHI Takahiro } 129875cbf3eSAKASHI Takahiro 130f27bb139SMarc Zyngier #endif /* __ASM_SYSCALL_H */ 131