162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Access to user system call parameters and results
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2008 Red Hat, Inc.  All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * See asm-generic/syscall.h for descriptions of what we must do here.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#ifndef _ASM_SYSCALL_H
1162306a36Sopenharmony_ci#define _ASM_SYSCALL_H	1
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <uapi/linux/audit.h>
1462306a36Sopenharmony_ci#include <linux/sched.h>
1562306a36Sopenharmony_ci#include <linux/thread_info.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER
1862306a36Sopenharmony_citypedef long (*syscall_fn)(const struct pt_regs *);
1962306a36Sopenharmony_ci#else
2062306a36Sopenharmony_citypedef long (*syscall_fn)(unsigned long, unsigned long, unsigned long,
2162306a36Sopenharmony_ci			   unsigned long, unsigned long, unsigned long);
2262306a36Sopenharmony_ci#endif
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* ftrace syscalls requires exporting the sys_call_table */
2562306a36Sopenharmony_ciextern const syscall_fn sys_call_table[];
2662306a36Sopenharmony_ciextern const syscall_fn compat_sys_call_table[];
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	/*
3162306a36Sopenharmony_ci	 * Note that we are returning an int here. That means 0xffffffff, ie.
3262306a36Sopenharmony_ci	 * 32-bit negative 1, will be interpreted as -1 on a 64-bit kernel.
3362306a36Sopenharmony_ci	 * This is important for seccomp so that compat tasks can set r0 = -1
3462306a36Sopenharmony_ci	 * to reject the syscall.
3562306a36Sopenharmony_ci	 */
3662306a36Sopenharmony_ci	if (trap_is_syscall(regs))
3762306a36Sopenharmony_ci		return regs->gpr[0];
3862306a36Sopenharmony_ci	else
3962306a36Sopenharmony_ci		return -1;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic inline void syscall_rollback(struct task_struct *task,
4362306a36Sopenharmony_ci				    struct pt_regs *regs)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	regs->gpr[3] = regs->orig_gpr3;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic inline long syscall_get_error(struct task_struct *task,
4962306a36Sopenharmony_ci				     struct pt_regs *regs)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	if (trap_is_scv(regs)) {
5262306a36Sopenharmony_ci		unsigned long error = regs->gpr[3];
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		return IS_ERR_VALUE(error) ? error : 0;
5562306a36Sopenharmony_ci	} else {
5662306a36Sopenharmony_ci		/*
5762306a36Sopenharmony_ci		 * If the system call failed,
5862306a36Sopenharmony_ci		 * regs->gpr[3] contains a positive ERRORCODE.
5962306a36Sopenharmony_ci		 */
6062306a36Sopenharmony_ci		return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 0;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic inline long syscall_get_return_value(struct task_struct *task,
6562306a36Sopenharmony_ci					    struct pt_regs *regs)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	return regs->gpr[3];
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic inline void syscall_set_return_value(struct task_struct *task,
7162306a36Sopenharmony_ci					    struct pt_regs *regs,
7262306a36Sopenharmony_ci					    int error, long val)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	if (trap_is_scv(regs)) {
7562306a36Sopenharmony_ci		regs->gpr[3] = (long) error ?: val;
7662306a36Sopenharmony_ci	} else {
7762306a36Sopenharmony_ci		/*
7862306a36Sopenharmony_ci		 * In the general case it's not obvious that we must deal with
7962306a36Sopenharmony_ci		 * CCR here, as the syscall exit path will also do that for us.
8062306a36Sopenharmony_ci		 * However there are some places, eg. the signal code, which
8162306a36Sopenharmony_ci		 * check ccr to decide if the value in r3 is actually an error.
8262306a36Sopenharmony_ci		 */
8362306a36Sopenharmony_ci		if (error) {
8462306a36Sopenharmony_ci			regs->ccr |= 0x10000000L;
8562306a36Sopenharmony_ci			regs->gpr[3] = error;
8662306a36Sopenharmony_ci		} else {
8762306a36Sopenharmony_ci			regs->ccr &= ~0x10000000L;
8862306a36Sopenharmony_ci			regs->gpr[3] = val;
8962306a36Sopenharmony_ci		}
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic inline void syscall_get_arguments(struct task_struct *task,
9462306a36Sopenharmony_ci					 struct pt_regs *regs,
9562306a36Sopenharmony_ci					 unsigned long *args)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	unsigned long val, mask = -1UL;
9862306a36Sopenharmony_ci	unsigned int n = 6;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (is_tsk_32bit_task(task))
10162306a36Sopenharmony_ci		mask = 0xffffffff;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	while (n--) {
10462306a36Sopenharmony_ci		if (n == 0)
10562306a36Sopenharmony_ci			val = regs->orig_gpr3;
10662306a36Sopenharmony_ci		else
10762306a36Sopenharmony_ci			val = regs->gpr[3 + n];
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		args[n] = val & mask;
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic inline int syscall_get_arch(struct task_struct *task)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	if (is_tsk_32bit_task(task))
11662306a36Sopenharmony_ci		return AUDIT_ARCH_PPC;
11762306a36Sopenharmony_ci	else if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
11862306a36Sopenharmony_ci		return AUDIT_ARCH_PPC64LE;
11962306a36Sopenharmony_ci	else
12062306a36Sopenharmony_ci		return AUDIT_ARCH_PPC64;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci#endif	/* _ASM_SYSCALL_H */
123