linux/arch/nds32/include/asm/syscall.h
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (C) 2008-2009 Red Hat, Inc.  All rights reserved.
   3// Copyright (C) 2005-2017 Andes Technology Corporation
   4
   5#ifndef _ASM_NDS32_SYSCALL_H
   6#define _ASM_NDS32_SYSCALL_H    1
   7
   8#include <linux/err.h>
   9struct task_struct;
  10struct pt_regs;
  11
  12/**
  13 * syscall_get_nr - find what system call a task is executing
  14 * @task:       task of interest, must be blocked
  15 * @regs:       task_pt_regs() of @task
  16 *
  17 * If @task is executing a system call or is at system call
  18 * tracing about to attempt one, returns the system call number.
  19 * If @task is not executing a system call, i.e. it's blocked
  20 * inside the kernel for a fault or signal, returns -1.
  21 *
  22 * Note this returns int even on 64-bit machines.  Only 32 bits of
  23 * system call number can be meaningful.  If the actual arch value
  24 * is 64 bits, this truncates to 32 bits so 0xffffffff means -1.
  25 *
  26 * It's only valid to call this when @task is known to be blocked.
  27 */
  28int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
  29{
  30        return regs->syscallno;
  31}
  32
  33/**
  34 * syscall_rollback - roll back registers after an aborted system call
  35 * @task:       task of interest, must be in system call exit tracing
  36 * @regs:       task_pt_regs() of @task
  37 *
  38 * It's only valid to call this when @task is stopped for system
  39 * call exit tracing (due to TIF_SYSCALL_TRACE or TIF_SYSCALL_AUDIT),
  40 * after tracehook_report_syscall_entry() returned nonzero to prevent
  41 * the system call from taking place.
  42 *
  43 * This rolls back the register state in @regs so it's as if the
  44 * system call instruction was a no-op.  The registers containing
  45 * the system call number and arguments are as they were before the
  46 * system call instruction.  This may not be the same as what the
  47 * register state looked like at system call entry tracing.
  48 */
  49void syscall_rollback(struct task_struct *task, struct pt_regs *regs)
  50{
  51        regs->uregs[0] = regs->orig_r0;
  52}
  53
  54/**
  55 * syscall_get_error - check result of traced system call
  56 * @task:       task of interest, must be blocked
  57 * @regs:       task_pt_regs() of @task
  58 *
  59 * Returns 0 if the system call succeeded, or -ERRORCODE if it failed.
  60 *
  61 * It's only valid to call this when @task is stopped for tracing on exit
  62 * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
  63 */
  64long syscall_get_error(struct task_struct *task, struct pt_regs *regs)
  65{
  66        unsigned long error = regs->uregs[0];
  67        return IS_ERR_VALUE(error) ? error : 0;
  68}
  69
  70/**
  71 * syscall_get_return_value - get the return value of a traced system call
  72 * @task:       task of interest, must be blocked
  73 * @regs:       task_pt_regs() of @task
  74 *
  75 * Returns the return value of the successful system call.
  76 * This value is meaningless if syscall_get_error() returned nonzero.
  77 *
  78 * It's only valid to call this when @task is stopped for tracing on exit
  79 * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
  80 */
  81long syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
  82{
  83        return regs->uregs[0];
  84}
  85
  86/**
  87 * syscall_set_return_value - change the return value of a traced system call
  88 * @task:       task of interest, must be blocked
  89 * @regs:       task_pt_regs() of @task
  90 * @error:      negative error code, or zero to indicate success
  91 * @val:        user return value if @error is zero
  92 *
  93 * This changes the results of the system call that user mode will see.
  94 * If @error is zero, the user sees a successful system call with a
  95 * return value of @val.  If @error is nonzero, it's a negated errno
  96 * code; the user sees a failed system call with this errno code.
  97 *
  98 * It's only valid to call this when @task is stopped for tracing on exit
  99 * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
 100 */
 101void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
 102                              int error, long val)
 103{
 104        regs->uregs[0] = (long)error ? error : val;
 105}
 106
 107/**
 108 * syscall_get_arguments - extract system call parameter values
 109 * @task:       task of interest, must be blocked
 110 * @regs:       task_pt_regs() of @task
 111 * @i:          argument index [0,5]
 112 * @n:          number of arguments; n+i must be [1,6].
 113 * @args:       array filled with argument values
 114 *
 115 * Fetches @n arguments to the system call starting with the @i'th argument
 116 * (from 0 through 5).  Argument @i is stored in @args[0], and so on.
 117 * An arch inline version is probably optimal when @i and @n are constants.
 118 *
 119 * It's only valid to call this when @task is stopped for tracing on
 120 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
 121 * It's invalid to call this with @i + @n > 6; we only support system calls
 122 * taking up to 6 arguments.
 123 */
 124#define SYSCALL_MAX_ARGS 6
 125void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
 126                           unsigned int i, unsigned int n, unsigned long *args)
 127{
 128        if (n == 0)
 129                return;
 130        if (i + n > SYSCALL_MAX_ARGS) {
 131                unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
 132                unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
 133                pr_warning("%s called with max args %d, handling only %d\n",
 134                           __func__, i + n, SYSCALL_MAX_ARGS);
 135                memset(args_bad, 0, n_bad * sizeof(args[0]));
 136                memset(args_bad, 0, n_bad * sizeof(args[0]));
 137        }
 138
 139        if (i == 0) {
 140                args[0] = regs->orig_r0;
 141                args++;
 142                i++;
 143                n--;
 144        }
 145
 146        memcpy(args, &regs->uregs[0] + i, n * sizeof(args[0]));
 147}
 148
 149/**
 150 * syscall_set_arguments - change system call parameter value
 151 * @task:       task of interest, must be in system call entry tracing
 152 * @regs:       task_pt_regs() of @task
 153 * @i:          argument index [0,5]
 154 * @n:          number of arguments; n+i must be [1,6].
 155 * @args:       array of argument values to store
 156 *
 157 * Changes @n arguments to the system call starting with the @i'th argument.
 158 * Argument @i gets value @args[0], and so on.
 159 * An arch inline version is probably optimal when @i and @n are constants.
 160 *
 161 * It's only valid to call this when @task is stopped for tracing on
 162 * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
 163 * It's invalid to call this with @i + @n > 6; we only support system calls
 164 * taking up to 6 arguments.
 165 */
 166void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
 167                           unsigned int i, unsigned int n,
 168                           const unsigned long *args)
 169{
 170        if (n == 0)
 171                return;
 172
 173        if (i + n > SYSCALL_MAX_ARGS) {
 174                pr_warn("%s called with max args %d, handling only %d\n",
 175                        __func__, i + n, SYSCALL_MAX_ARGS);
 176                n = SYSCALL_MAX_ARGS - i;
 177        }
 178
 179        if (i == 0) {
 180                regs->orig_r0 = args[0];
 181                args++;
 182                i++;
 183                n--;
 184        }
 185
 186        memcpy(&regs->uregs[0] + i, args, n * sizeof(args[0]));
 187}
 188#endif /* _ASM_NDS32_SYSCALL_H */
 189