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 23055b1212SAKASHI Takahiro extern const void *sys_call_table[]; 24f27bb139SMarc Zyngier 25f27bb139SMarc Zyngier static inline int syscall_get_nr(struct task_struct *task, 26f27bb139SMarc Zyngier struct pt_regs *regs) 27f27bb139SMarc Zyngier { 28f27bb139SMarc Zyngier return regs->syscallno; 29f27bb139SMarc Zyngier } 30f27bb139SMarc Zyngier 31f27bb139SMarc Zyngier static inline void syscall_rollback(struct task_struct *task, 32f27bb139SMarc Zyngier struct pt_regs *regs) 33f27bb139SMarc Zyngier { 34f27bb139SMarc Zyngier regs->regs[0] = regs->orig_x0; 35f27bb139SMarc Zyngier } 36f27bb139SMarc Zyngier 37f27bb139SMarc Zyngier 38f27bb139SMarc Zyngier static inline long syscall_get_error(struct task_struct *task, 39f27bb139SMarc Zyngier struct pt_regs *regs) 40f27bb139SMarc Zyngier { 41f27bb139SMarc Zyngier unsigned long error = regs->regs[0]; 42f27bb139SMarc Zyngier return IS_ERR_VALUE(error) ? error : 0; 43f27bb139SMarc Zyngier } 44f27bb139SMarc Zyngier 45f27bb139SMarc Zyngier static inline long syscall_get_return_value(struct task_struct *task, 46f27bb139SMarc Zyngier struct pt_regs *regs) 47f27bb139SMarc Zyngier { 48f27bb139SMarc Zyngier return regs->regs[0]; 49f27bb139SMarc Zyngier } 50f27bb139SMarc Zyngier 51f27bb139SMarc Zyngier static inline void syscall_set_return_value(struct task_struct *task, 52f27bb139SMarc Zyngier struct pt_regs *regs, 53f27bb139SMarc Zyngier int error, long val) 54f27bb139SMarc Zyngier { 55f27bb139SMarc Zyngier regs->regs[0] = (long) error ? error : val; 56f27bb139SMarc Zyngier } 57f27bb139SMarc Zyngier 58f27bb139SMarc Zyngier #define SYSCALL_MAX_ARGS 6 59f27bb139SMarc Zyngier 60f27bb139SMarc Zyngier static inline void syscall_get_arguments(struct task_struct *task, 61f27bb139SMarc Zyngier struct pt_regs *regs, 62f27bb139SMarc Zyngier unsigned int i, unsigned int n, 63f27bb139SMarc Zyngier unsigned long *args) 64f27bb139SMarc Zyngier { 657b22c035SAKASHI Takahiro if (n == 0) 667b22c035SAKASHI Takahiro return; 677b22c035SAKASHI Takahiro 68f27bb139SMarc Zyngier if (i + n > SYSCALL_MAX_ARGS) { 69f27bb139SMarc Zyngier unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i; 70f27bb139SMarc Zyngier unsigned int n_bad = n + i - SYSCALL_MAX_ARGS; 71f27bb139SMarc Zyngier pr_warning("%s called with max args %d, handling only %d\n", 72f27bb139SMarc Zyngier __func__, i + n, SYSCALL_MAX_ARGS); 73f27bb139SMarc Zyngier memset(args_bad, 0, n_bad * sizeof(args[0])); 74f27bb139SMarc Zyngier } 75f27bb139SMarc Zyngier 76f27bb139SMarc Zyngier if (i == 0) { 77f27bb139SMarc Zyngier args[0] = regs->orig_x0; 78f27bb139SMarc Zyngier args++; 79f27bb139SMarc Zyngier i++; 80f27bb139SMarc Zyngier n--; 81f27bb139SMarc Zyngier } 82f27bb139SMarc Zyngier 83f27bb139SMarc Zyngier memcpy(args, ®s->regs[i], n * sizeof(args[0])); 84f27bb139SMarc Zyngier } 85f27bb139SMarc Zyngier 86f27bb139SMarc Zyngier static inline void syscall_set_arguments(struct task_struct *task, 87f27bb139SMarc Zyngier struct pt_regs *regs, 88f27bb139SMarc Zyngier unsigned int i, unsigned int n, 89f27bb139SMarc Zyngier const unsigned long *args) 90f27bb139SMarc Zyngier { 917b22c035SAKASHI Takahiro if (n == 0) 927b22c035SAKASHI Takahiro return; 937b22c035SAKASHI Takahiro 94f27bb139SMarc Zyngier if (i + n > SYSCALL_MAX_ARGS) { 95f27bb139SMarc Zyngier pr_warning("%s called with max args %d, handling only %d\n", 96f27bb139SMarc Zyngier __func__, i + n, SYSCALL_MAX_ARGS); 97f27bb139SMarc Zyngier n = SYSCALL_MAX_ARGS - i; 98f27bb139SMarc Zyngier } 99f27bb139SMarc Zyngier 100f27bb139SMarc Zyngier if (i == 0) { 101f27bb139SMarc Zyngier regs->orig_x0 = args[0]; 102f27bb139SMarc Zyngier args++; 103f27bb139SMarc Zyngier i++; 104f27bb139SMarc Zyngier n--; 105f27bb139SMarc Zyngier } 106f27bb139SMarc Zyngier 107f27bb139SMarc Zyngier memcpy(®s->regs[i], args, n * sizeof(args[0])); 108f27bb139SMarc Zyngier } 109f27bb139SMarc Zyngier 110875cbf3eSAKASHI Takahiro /* 111875cbf3eSAKASHI Takahiro * We don't care about endianness (__AUDIT_ARCH_LE bit) here because 112875cbf3eSAKASHI Takahiro * AArch64 has the same system calls both on little- and big- endian. 113875cbf3eSAKASHI Takahiro */ 114875cbf3eSAKASHI Takahiro static inline int syscall_get_arch(void) 115875cbf3eSAKASHI Takahiro { 116875cbf3eSAKASHI Takahiro if (is_compat_task()) 117875cbf3eSAKASHI Takahiro return AUDIT_ARCH_ARM; 118875cbf3eSAKASHI Takahiro 119875cbf3eSAKASHI Takahiro return AUDIT_ARCH_AARCH64; 120875cbf3eSAKASHI Takahiro } 121875cbf3eSAKASHI Takahiro 122f27bb139SMarc Zyngier #endif /* __ASM_SYSCALL_H */ 123