xref: /openbmc/linux/arch/powerpc/include/asm/syscall.h (revision 7e92e01b)
12522fe45SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
2b8b572e1SStephen Rothwell /*
3b8b572e1SStephen Rothwell  * Access to user system call parameters and results
4b8b572e1SStephen Rothwell  *
5b8b572e1SStephen Rothwell  * Copyright (C) 2008 Red Hat, Inc.  All rights reserved.
6b8b572e1SStephen Rothwell  *
7b8b572e1SStephen Rothwell  * See asm-generic/syscall.h for descriptions of what we must do here.
8b8b572e1SStephen Rothwell  */
9b8b572e1SStephen Rothwell 
10b8b572e1SStephen Rothwell #ifndef _ASM_SYSCALL_H
11b8b572e1SStephen Rothwell #define _ASM_SYSCALL_H	1
12b8b572e1SStephen Rothwell 
13ce5d1128SEric Paris #include <uapi/linux/audit.h>
14b8b572e1SStephen Rothwell #include <linux/sched.h>
1575dddcbdSEric Paris #include <linux/thread_info.h>
16b8b572e1SStephen Rothwell 
17*7e92e01bSRohan McLure #ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER
18*7e92e01bSRohan McLure typedef long (*syscall_fn)(const struct pt_regs *);
19*7e92e01bSRohan McLure #else
208640de0dSRohan McLure typedef long (*syscall_fn)(unsigned long, unsigned long, unsigned long,
218640de0dSRohan McLure 			   unsigned long, unsigned long, unsigned long);
22*7e92e01bSRohan McLure #endif
238640de0dSRohan McLure 
2402424d89SIan Munsie /* ftrace syscalls requires exporting the sys_call_table */
258640de0dSRohan McLure extern const syscall_fn sys_call_table[];
268640de0dSRohan McLure extern const syscall_fn compat_sys_call_table[];
2702424d89SIan Munsie 
syscall_get_nr(struct task_struct * task,struct pt_regs * regs)28e9fbe686SMichael Ellerman static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
29b8b572e1SStephen Rothwell {
30e9fbe686SMichael Ellerman 	/*
31e9fbe686SMichael Ellerman 	 * Note that we are returning an int here. That means 0xffffffff, ie.
32e9fbe686SMichael Ellerman 	 * 32-bit negative 1, will be interpreted as -1 on a 64-bit kernel.
33e9fbe686SMichael Ellerman 	 * This is important for seccomp so that compat tasks can set r0 = -1
34e9fbe686SMichael Ellerman 	 * to reject the syscall.
35e9fbe686SMichael Ellerman 	 */
36912237eaSNicholas Piggin 	if (trap_is_syscall(regs))
37912237eaSNicholas Piggin 		return regs->gpr[0];
38912237eaSNicholas Piggin 	else
39912237eaSNicholas Piggin 		return -1;
40b8b572e1SStephen Rothwell }
41b8b572e1SStephen Rothwell 
syscall_rollback(struct task_struct * task,struct pt_regs * regs)42b8b572e1SStephen Rothwell static inline void syscall_rollback(struct task_struct *task,
43b8b572e1SStephen Rothwell 				    struct pt_regs *regs)
44b8b572e1SStephen Rothwell {
45b8b572e1SStephen Rothwell 	regs->gpr[3] = regs->orig_gpr3;
46b8b572e1SStephen Rothwell }
47b8b572e1SStephen Rothwell 
syscall_get_error(struct task_struct * task,struct pt_regs * regs)48f296f1dfSDmitry V. Levin static inline long syscall_get_error(struct task_struct *task,
49f296f1dfSDmitry V. Levin 				     struct pt_regs *regs)
50f296f1dfSDmitry V. Levin {
51d72500f9SNicholas Piggin 	if (trap_is_scv(regs)) {
52d72500f9SNicholas Piggin 		unsigned long error = regs->gpr[3];
53d72500f9SNicholas Piggin 
54d72500f9SNicholas Piggin 		return IS_ERR_VALUE(error) ? error : 0;
55d72500f9SNicholas Piggin 	} else {
56f296f1dfSDmitry V. Levin 		/*
57f296f1dfSDmitry V. Levin 		 * If the system call failed,
58f296f1dfSDmitry V. Levin 		 * regs->gpr[3] contains a positive ERRORCODE.
59f296f1dfSDmitry V. Levin 		 */
60f296f1dfSDmitry V. Levin 		return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 0;
61f296f1dfSDmitry V. Levin 	}
62d72500f9SNicholas Piggin }
63f296f1dfSDmitry V. Levin 
syscall_get_return_value(struct task_struct * task,struct pt_regs * regs)64b8b572e1SStephen Rothwell static inline long syscall_get_return_value(struct task_struct *task,
65b8b572e1SStephen Rothwell 					    struct pt_regs *regs)
66b8b572e1SStephen Rothwell {
67b8b572e1SStephen Rothwell 	return regs->gpr[3];
68b8b572e1SStephen Rothwell }
69b8b572e1SStephen Rothwell 
syscall_set_return_value(struct task_struct * task,struct pt_regs * regs,int error,long val)70b8b572e1SStephen Rothwell static inline void syscall_set_return_value(struct task_struct *task,
71b8b572e1SStephen Rothwell 					    struct pt_regs *regs,
72b8b572e1SStephen Rothwell 					    int error, long val)
73b8b572e1SStephen Rothwell {
74d72500f9SNicholas Piggin 	if (trap_is_scv(regs)) {
75d72500f9SNicholas Piggin 		regs->gpr[3] = (long) error ?: val;
76d72500f9SNicholas Piggin 	} else {
771b1a3702SMichael Ellerman 		/*
78d72500f9SNicholas Piggin 		 * In the general case it's not obvious that we must deal with
79d72500f9SNicholas Piggin 		 * CCR here, as the syscall exit path will also do that for us.
80d72500f9SNicholas Piggin 		 * However there are some places, eg. the signal code, which
81d72500f9SNicholas Piggin 		 * check ccr to decide if the value in r3 is actually an error.
821b1a3702SMichael Ellerman 		 */
83b8b572e1SStephen Rothwell 		if (error) {
84409d241bSNathan Lynch 			regs->ccr |= 0x10000000L;
851b1a3702SMichael Ellerman 			regs->gpr[3] = error;
86b8b572e1SStephen Rothwell 		} else {
87409d241bSNathan Lynch 			regs->ccr &= ~0x10000000L;
88b8b572e1SStephen Rothwell 			regs->gpr[3] = val;
89b8b572e1SStephen Rothwell 		}
90b8b572e1SStephen Rothwell 	}
91d72500f9SNicholas Piggin }
92b8b572e1SStephen Rothwell 
syscall_get_arguments(struct task_struct * task,struct pt_regs * regs,unsigned long * args)93b8b572e1SStephen Rothwell static inline void syscall_get_arguments(struct task_struct *task,
94b8b572e1SStephen Rothwell 					 struct pt_regs *regs,
95b8b572e1SStephen Rothwell 					 unsigned long *args)
96b8b572e1SStephen Rothwell {
971cb9839bSMichael Ellerman 	unsigned long val, mask = -1UL;
98b35f549dSSteven Rostedt (Red Hat) 	unsigned int n = 6;
99a7657844SMichael Ellerman 
10025274524SChristophe Leroy 	if (is_tsk_32bit_task(task))
101a7657844SMichael Ellerman 		mask = 0xffffffff;
102898a1ef0SChristophe Leroy 
1031cb9839bSMichael Ellerman 	while (n--) {
104b35f549dSSteven Rostedt (Red Hat) 		if (n == 0)
1051cb9839bSMichael Ellerman 			val = regs->orig_gpr3;
1061cb9839bSMichael Ellerman 		else
107b35f549dSSteven Rostedt (Red Hat) 			val = regs->gpr[3 + n];
1081cb9839bSMichael Ellerman 
1091cb9839bSMichael Ellerman 		args[n] = val & mask;
1101cb9839bSMichael Ellerman 	}
111b8b572e1SStephen Rothwell }
112b8b572e1SStephen Rothwell 
syscall_get_arch(struct task_struct * task)11316add411SDmitry V. Levin static inline int syscall_get_arch(struct task_struct *task)
114ce5d1128SEric Paris {
11525274524SChristophe Leroy 	if (is_tsk_32bit_task(task))
116770cec16SChristophe Leroy 		return AUDIT_ARCH_PPC;
117770cec16SChristophe Leroy 	else if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
118770cec16SChristophe Leroy 		return AUDIT_ARCH_PPC64LE;
11916add411SDmitry V. Levin 	else
120770cec16SChristophe Leroy 		return AUDIT_ARCH_PPC64;
121ce5d1128SEric Paris }
122b8b572e1SStephen Rothwell #endif	/* _ASM_SYSCALL_H */
123