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