2008-07-27 14:51:35 +08:00
|
|
|
/*
|
|
|
|
* Access to user system call parameters and results
|
|
|
|
*
|
|
|
|
* Copyright (C) 2008 Red Hat, Inc. All rights reserved.
|
|
|
|
*
|
|
|
|
* This copyrighted material is made available to anyone wishing to use,
|
|
|
|
* modify, copy, or redistribute it subject to the terms and conditions
|
|
|
|
* of the GNU General Public License v.2.
|
|
|
|
*
|
|
|
|
* See asm-generic/syscall.h for descriptions of what we must do here.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _ASM_SYSCALL_H
|
|
|
|
#define _ASM_SYSCALL_H 1
|
|
|
|
|
2014-03-12 01:50:46 +08:00
|
|
|
#include <uapi/linux/audit.h>
|
2008-07-27 14:51:35 +08:00
|
|
|
#include <linux/sched.h>
|
2014-04-23 00:07:30 +08:00
|
|
|
#include <linux/thread_info.h>
|
2008-07-27 14:51:35 +08:00
|
|
|
|
2011-02-03 01:27:24 +08:00
|
|
|
/* ftrace syscalls requires exporting the sys_call_table */
|
|
|
|
#ifdef CONFIG_FTRACE_SYSCALLS
|
powerpc: Fix sys_call_table declaration to enable syscall tracing
Declaring sys_call_table as a pointer causes the compiler to generate
the wrong lookup code in arch_syscall_addr().
<arch_syscall_addr>:
lis r9,-16384
rlwinm r3,r3,2,0,29
- lwz r11,30640(r9)
- lwzx r3,r11,r3
+ addi r9,r9,30640
+ lwzx r3,r9,r3
blr
The actual sys_call_table symbol, declared in assembler, is an
array. If we lie about that to the compiler we get the wrong code
generated, as above.
This definition seems only to be used by the syscall tracing code in
kernel/trace/trace_syscalls.c. With this patch I can successfully use
the syscall tracepoints:
bash-3815 [002] .... 333.239082: sys_write -> 0x2
bash-3815 [002] .... 333.239087: sys_dup2(oldfd: a, newfd: 1)
bash-3815 [002] .... 333.239088: sys_dup2 -> 0x1
bash-3815 [002] .... 333.239092: sys_fcntl(fd: a, cmd: 1, arg: 0)
bash-3815 [002] .... 333.239093: sys_fcntl -> 0x1
bash-3815 [002] .... 333.239094: sys_close(fd: a)
bash-3815 [002] .... 333.239094: sys_close -> 0x0
Signed-off-by: Romeo Cane <romeo.cane.ext@coriant.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2014-10-02 22:41:39 +08:00
|
|
|
extern const unsigned long sys_call_table[];
|
2011-02-03 01:27:24 +08:00
|
|
|
#endif /* CONFIG_FTRACE_SYSCALLS */
|
|
|
|
|
2008-07-27 14:51:35 +08:00
|
|
|
static inline long syscall_get_nr(struct task_struct *task,
|
|
|
|
struct pt_regs *regs)
|
|
|
|
{
|
|
|
|
return TRAP(regs) == 0xc00 ? regs->gpr[0] : -1L;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void syscall_rollback(struct task_struct *task,
|
|
|
|
struct pt_regs *regs)
|
|
|
|
{
|
|
|
|
regs->gpr[3] = regs->orig_gpr3;
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2015-07-23 18:21:04 +08:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2008-07-27 14:51:35 +08:00
|
|
|
if (error) {
|
2010-03-12 21:16:02 +08:00
|
|
|
regs->ccr |= 0x10000000L;
|
2015-07-23 18:21:04 +08:00
|
|
|
regs->gpr[3] = error;
|
2008-07-27 14:51:35 +08:00
|
|
|
} else {
|
2010-03-12 21:16:02 +08:00
|
|
|
regs->ccr &= ~0x10000000L;
|
2008-07-27 14:51:35 +08:00
|
|
|
regs->gpr[3] = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void syscall_get_arguments(struct task_struct *task,
|
|
|
|
struct pt_regs *regs,
|
|
|
|
unsigned int i, unsigned int n,
|
|
|
|
unsigned long *args)
|
|
|
|
{
|
|
|
|
BUG_ON(i + n > 6);
|
|
|
|
#ifdef CONFIG_PPC64
|
|
|
|
if (test_tsk_thread_flag(task, TIF_32BIT)) {
|
|
|
|
/*
|
|
|
|
* Zero-extend 32-bit argument values. The high bits are
|
|
|
|
* garbage ignored by the actual syscall dispatch.
|
|
|
|
*/
|
|
|
|
while (n-- > 0)
|
|
|
|
args[n] = (u32) regs->gpr[3 + i + n];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
memcpy(args, ®s->gpr[3 + i], n * sizeof(args[0]));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void syscall_set_arguments(struct task_struct *task,
|
|
|
|
struct pt_regs *regs,
|
|
|
|
unsigned int i, unsigned int n,
|
|
|
|
const unsigned long *args)
|
|
|
|
{
|
|
|
|
BUG_ON(i + n > 6);
|
|
|
|
memcpy(®s->gpr[3 + i], args, n * sizeof(args[0]));
|
|
|
|
}
|
|
|
|
|
2014-03-12 01:50:46 +08:00
|
|
|
static inline int syscall_get_arch(void)
|
|
|
|
{
|
2014-12-10 04:37:07 +08:00
|
|
|
int arch = is_32bit_task() ? AUDIT_ARCH_PPC : AUDIT_ARCH_PPC64;
|
|
|
|
#ifdef __LITTLE_ENDIAN__
|
|
|
|
arch |= __AUDIT_ARCH_LE;
|
|
|
|
#endif
|
|
|
|
return arch;
|
2014-03-12 01:50:46 +08:00
|
|
|
}
|
2008-07-27 14:51:35 +08:00
|
|
|
#endif /* _ASM_SYSCALL_H */
|