1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Access to user system call parameters and results 4 * 5 * Copyright (C) 2008 Red Hat, Inc. All rights reserved. 6 * 7 * See asm-generic/syscall.h for descriptions of what we must do here. 8 */ 9 10 #ifndef _ASM_SYSCALL_H 11 #define _ASM_SYSCALL_H 1 12 13 #include <uapi/linux/audit.h> 14 #include <linux/sched.h> 15 #include <linux/thread_info.h> 16 17 #ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER 18 typedef long (*syscall_fn)(const struct pt_regs *); 19 #else 20 typedef long (*syscall_fn)(unsigned long, unsigned long, unsigned long, 21 unsigned long, unsigned long, unsigned long); 22 #endif 23 24 /* ftrace syscalls requires exporting the sys_call_table */ 25 extern const syscall_fn sys_call_table[]; 26 extern const syscall_fn compat_sys_call_table[]; 27 28 static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 29 { 30 /* 31 * Note that we are returning an int here. That means 0xffffffff, ie. 32 * 32-bit negative 1, will be interpreted as -1 on a 64-bit kernel. 33 * This is important for seccomp so that compat tasks can set r0 = -1 34 * to reject the syscall. 35 */ 36 if (trap_is_syscall(regs)) 37 return regs->gpr[0]; 38 else 39 return -1; 40 } 41 42 static inline void syscall_rollback(struct task_struct *task, 43 struct pt_regs *regs) 44 { 45 regs->gpr[3] = regs->orig_gpr3; 46 } 47 48 static inline long syscall_get_error(struct task_struct *task, 49 struct pt_regs *regs) 50 { 51 if (trap_is_scv(regs)) { 52 unsigned long error = regs->gpr[3]; 53 54 return IS_ERR_VALUE(error) ? error : 0; 55 } else { 56 /* 57 * If the system call failed, 58 * regs->gpr[3] contains a positive ERRORCODE. 59 */ 60 return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 0; 61 } 62 } 63 64 static inline long syscall_get_return_value(struct task_struct *task, 65 struct pt_regs *regs) 66 { 67 return regs->gpr[3]; 68 } 69 70 static inline void syscall_set_return_value(struct task_struct *task, 71 struct pt_regs *regs, 72 int error, long val) 73 { 74 if (trap_is_scv(regs)) { 75 regs->gpr[3] = (long) error ?: val; 76 } else { 77 /* 78 * In the general case it's not obvious that we must deal with 79 * CCR here, as the syscall exit path will also do that for us. 80 * However there are some places, eg. the signal code, which 81 * check ccr to decide if the value in r3 is actually an error. 82 */ 83 if (error) { 84 regs->ccr |= 0x10000000L; 85 regs->gpr[3] = error; 86 } else { 87 regs->ccr &= ~0x10000000L; 88 regs->gpr[3] = val; 89 } 90 } 91 } 92 93 static inline void syscall_get_arguments(struct task_struct *task, 94 struct pt_regs *regs, 95 unsigned long *args) 96 { 97 unsigned long val, mask = -1UL; 98 unsigned int n = 6; 99 100 if (is_tsk_32bit_task(task)) 101 mask = 0xffffffff; 102 103 while (n--) { 104 if (n == 0) 105 val = regs->orig_gpr3; 106 else 107 val = regs->gpr[3 + n]; 108 109 args[n] = val & mask; 110 } 111 } 112 113 static inline int syscall_get_arch(struct task_struct *task) 114 { 115 if (is_tsk_32bit_task(task)) 116 return AUDIT_ARCH_PPC; 117 else if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN)) 118 return AUDIT_ARCH_PPC64LE; 119 else 120 return AUDIT_ARCH_PPC64; 121 } 122 #endif /* _ASM_SYSCALL_H */ 123