Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fc4fb2ad authored by Chris Zankel's avatar Chris Zankel Committed by Linus Torvalds
Browse files

[PATCH] xtensa: fix system call interface



This is a long outstanding patch to finally fix the syscall interface.  The
constants used for the system calls are those we have provided in our libc
patches.  This patch also fixes the shmbuf and stat structure, and fcntl
definitions.

Signed-off-by: default avatarChris Zankel <chris@zankel.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 173d6681
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -87,6 +87,11 @@ int main(void)
	DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context));
	BLANK();
	DEFINE(PT_SINGLESTEP_BIT, PT_SINGLESTEP_BIT);

	/* constants */
	DEFINE(_CLONE_VM, CLONE_VM);
	DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED);

	return 0;
}

+150 −78
Original line number Diff line number Diff line
@@ -1004,13 +1004,10 @@ ENTRY(fast_syscall_kernel)

	rsr	a0, DEPC			# get syscall-nr
	_beqz	a0, fast_syscall_spill_registers

	addi	a0, a0, -__NR_sysxtensa
	_beqz	a0, fast_syscall_sysxtensa
	_beqi	a0, __NR_xtensa, fast_syscall_xtensa

	j	kernel_exception


ENTRY(fast_syscall_user)

	/* Skip syscall. */
@@ -1024,9 +1021,7 @@ ENTRY(fast_syscall_user)

	rsr	a0, DEPC			# get syscall-nr
	_beqz	a0, fast_syscall_spill_registers

	addi	a0, a0, -__NR_sysxtensa
	_beqz	a0, fast_syscall_sysxtensa
	_beqi	a0, __NR_xtensa, fast_syscall_xtensa

	j	user_exception

@@ -1047,18 +1042,19 @@ ENTRY(fast_syscall_unrecoverable)
/*
 * sysxtensa syscall handler
 *
 * int sysxtensa (XTENSA_ATOMIC_SET, ptr, val, unused);
 * int sysxtensa (XTENSA_ATOMIC_ADD, ptr, val, unused);
 * int sysxtensa (XTENSA_ATOMIC_EXG_ADD, ptr, val, unused);
 * int sysxtensa (XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
 * int sysxtensa (SYS_XTENSA_ATOMIC_SET,     ptr, val,    unused);
 * int sysxtensa (SYS_XTENSA_ATOMIC_ADD,     ptr, val,    unused);
 * int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val,    unused);
 * int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
 *        a2            a6                   a3    a4      a5
 *
 * Entry condition:
 *
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a0:	a2 (syscall-nr), original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a2:	new stack pointer, original in DEPC
 *   a3:	dispatch table
 *   a2:	new stack pointer, original in a0 and DEPC
 *   a3:	dispatch table, original in excsave_1
 *   a4..a15:	unchanged
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave_1:	a3
 *
@@ -1091,59 +1087,62 @@ ENTRY(fast_syscall_unrecoverable)
#define CATCH								\
67:

ENTRY(fast_syscall_sysxtensa)

	_beqz	a6, 1f
	_blti	a6, SYSXTENSA_COUNT, 2f

1:	j	user_exception
ENTRY(fast_syscall_xtensa)

2:	xsr	a3, EXCSAVE_1		# restore a3, excsave1
	s32i	a7, a2, PT_AREG7
	xsr	a3, EXCSAVE_1		# restore a3, excsave1

	s32i	a7, a2, PT_AREG7	# we need an additional register
	movi	a7, 4			# sizeof(unsigned int)
	access_ok a0, a3, a7, a2, .Leac
	access_ok a3, a7, a0, a2, .Leac	# a0: scratch reg, a2: sp

	_beqi	a6, SYSXTENSA_ATOMIC_SET, .Lset
	_beqi	a6, SYSXTENSA_ATOMIC_EXG_ADD, .Lexg
	_beqi	a6, SYSXTENSA_ATOMIC_ADD, .Ladd
	addi	a6, a6, -1		# assuming SYS_XTENSA_ATOMIC_SET = 1
	_bgeui	a6, SYS_XTENSA_COUNT - 1, .Lill
	_bnei	a6, SYS_XTENSA_ATOMIC_CMP_SWP - 1, .Lnswp

	/* Fall through for SYSXTENSA_ATOMIC_CMP_SWP */
	/* Fall through for ATOMIC_CMP_SWP. */

.Lswp:	/* Atomic compare and swap */

TRY	l32i	a7, a3, 0		# read old value
	bne	a7, a4, 1f		# same as old value? jump
	s32i	a5, a3, 0		# different, modify value
	movi	a7, 1			# and return 1
	j	.Lret

1:	movi	a7, 0			# same values: return 0
	j	.Lret

.Ladd:	/* Atomic add */
.Lexg:	/* Atomic (exchange) add */
TRY	l32i	a0, a3, 0		# read old value
	bne	a0, a4, 1f		# same as old value? jump
TRY	s32i	a5, a3, 0		# different, modify value
	l32i	a7, a2, PT_AREG7	# restore a7
	l32i	a0, a2, PT_AREG0	# restore a0
	movi	a2, 1			# and return 1
	addi	a6, a6, 1		# restore a6 (really necessary?)
	rfe

TRY	l32i	a7, a3, 0
	add	a4, a4, a7
	s32i	a4, a3, 0
	j	.Lret
1:	l32i	a7, a2, PT_AREG7	# restore a7
	l32i	a0, a2, PT_AREG0	# restore a0
	movi	a2, 0			# return 0 (note that we cannot set
	addi	a6, a6, 1		# restore a6 (really necessary?)
	rfe

.Lset:	/* Atomic set */
.Lnswp:	/* Atomic set, add, and exg_add. */

TRY	l32i	a7, a3, 0		# read old value as return value
	s32i	a4, a3, 0		# write new value
TRY	l32i	a7, a3, 0		# orig
	add	a0, a4, a7		# + arg
	moveqz	a0, a4, a6		# set
TRY	s32i	a0, a3, 0		# write new value

.Lret:	mov	a0, a2
	mov	a0, a2
	mov	a2, a7
	l32i	a7, a0, PT_AREG7
	l32i	a3, a0, PT_AREG3
	l32i	a0, a0, PT_AREG0
	l32i	a7, a0, PT_AREG7	# restore a7
	l32i	a0, a0, PT_AREG0	# restore a0
	addi	a6, a6, 1		# restore a6 (really necessary?)
	rfe

CATCH
.Leac:	movi	a7, -EFAULT
	j	.Lret
.Leac:	l32i	a7, a2, PT_AREG7	# restore a7
	l32i	a0, a2, PT_AREG0	# restore a0
	movi	a2, -EFAULT
	rfe

.Lill:	l32i	a7, a2, PT_AREG0	# restore a7
	l32i	a0, a2, PT_AREG0	# restore a0
	movi	a2, -EINVAL
	rfe




@@ -1906,6 +1905,103 @@ ENTRY(fast_coprocessor)

#endif /* XCHAL_EXTRA_SA_SIZE */

/*
 * System Calls.
 *
 * void system_call (struct pt_regs* regs, int exccause)
 *                            a2                 a3
 */

ENTRY(system_call)
	entry	a1, 32

	/* regs->syscall = regs->areg[2] */

	l32i	a3, a2, PT_AREG2
	mov	a6, a2
	movi	a4, do_syscall_trace_enter
	s32i	a3, a2, PT_SYSCALL
	callx4	a4

	/* syscall = sys_call_table[syscall_nr] */

	movi	a4, sys_call_table;
	movi	a5, __NR_syscall_count
	movi	a6, -ENOSYS
	bgeu	a3, a5, 1f

	addx4	a4, a3, a4
	l32i	a4, a4, 0
	movi	a5, sys_ni_syscall;
	beq	a4, a5, 1f

	/* Load args: arg0 - arg5 are passed via regs. */

	l32i	a6, a2, PT_AREG6
	l32i	a7, a2, PT_AREG3
	l32i	a8, a2, PT_AREG4
	l32i	a9, a2, PT_AREG5
	l32i	a10, a2, PT_AREG8
	l32i	a11, a2, PT_AREG9

	/* Pass one additional argument to the syscall: pt_regs (on stack) */
	s32i	a2, a1, 0

	callx4	a4

1:	/* regs->areg[2] = return_value */

	s32i	a6, a2, PT_AREG2
	movi	a4, do_syscall_trace_leave
	mov	a6, a2
	callx4	a4
	retw


/*
 * Create a kernel thread
 *
 * int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 * a2                    a2                 a3             a4
 */

ENTRY(kernel_thread)
	entry	a1, 16

	mov	a5, a2			# preserve fn over syscall
	mov	a7, a3			# preserve args over syscall

	movi	a3, _CLONE_VM | _CLONE_UNTRACED
	movi	a2, __NR_clone
	or	a6, a4, a3		# arg0: flags
	mov	a3, a1			# arg1: sp
	syscall

	beq	a3, a1, 1f		# branch if parent
	mov	a6, a7			# args
	callx4	a5			# fn(args)

	movi	a2, __NR_exit
	syscall				# return value of fn(args) still in a6

1:	retw

/*
 * Do a system call from kernel instead of calling sys_execve, so we end up
 * with proper pt_regs.
 *
 * int kernel_execve(const char *fname, char *const argv[], charg *const envp[])
 * a2                        a2               a3                  a4
 */

ENTRY(kernel_execve)
	entry	a1, 16
	mov	a6, a2			# arg0 is in a6
	movi	a2, __NR_execve
	syscall

	retw

/*
 * Task switch.
 *
@@ -1964,33 +2060,9 @@ ENTRY(ret_from_fork)
	movi	a4, schedule_tail
	callx4	a4

	movi	a4, do_syscall_trace
	movi	a4, do_syscall_trace_leave
	mov	a6, a1
	callx4	a4

	j	common_exception_return


/*
 * Table of syscalls
 */

.data
.align  4
.global sys_call_table
sys_call_table:

#define SYSCALL(call, narg) .word call
#include "syscalls.h"

/*
 * Number of arguments of each syscall
 */

.global sys_narg_table
sys_narg_table:

#undef SYSCALL
#define SYSCALL(call, narg) .byte narg
#include "syscalls.h"
+41 −30
Original line number Diff line number Diff line
@@ -160,36 +160,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
}


/*
 * Create a kernel thread
 */

int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
	long retval;
	__asm__ __volatile__
		("mov           a5, %4\n\t" /* preserve fn in a5 */
		 "mov           a6, %3\n\t" /* preserve and setup arg in a6 */
		 "movi		a2, %1\n\t" /* load __NR_clone for syscall*/
		 "mov		a3, sp\n\t" /* sp check and sys_clone */
		 "mov		a4, %5\n\t" /* load flags for syscall */
		 "syscall\n\t"
		 "beq		a3, sp, 1f\n\t" /* branch if parent */
		 "callx4	a5\n\t"     /* call fn */
		 "movi		a2, %2\n\t" /* load __NR_exit for syscall */
		 "mov		a3, a6\n\t" /* load fn return value */
		 "syscall\n"
		 "1:\n\t"
		 "mov		%0, a2\n\t" /* parent returns zero */
		 :"=r" (retval)
		 :"i" (__NR_clone), "i" (__NR_exit),
		 "r" (arg), "r" (fn),
		 "r" (flags | CLONE_VM)
		 : "a2", "a3", "a4", "a5", "a6" );
	return retval;
}


/*
 * These bracket the sleeping functions..
 */
@@ -452,3 +422,44 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
{
	return dump_task_fpu(regs, current, r);
}

asmlinkage
long xtensa_clone(unsigned long clone_flags, unsigned long newsp,
                  void __user *parent_tid, void *child_tls,
                  void __user *child_tid, long a5,
                  struct pt_regs *regs)
{
        if (!newsp)
                newsp = regs->areg[1];
        return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
}

/*
 *  * xtensa_execve() executes a new program.
 *   */

asmlinkage
long xtensa_execve(char __user *name, char __user * __user *argv,
                   char __user * __user *envp,
                   long a3, long a4, long a5,
                   struct pt_regs *regs)
{
	long error;
	char * filename;

	filename = getname(name);
	error = PTR_ERR(filename);
	if (IS_ERR(filename))
		goto out;
	// FIXME: release coprocessor??
	error = do_execve(filename, argv, envp, regs);
	if (error == 0) {
		task_lock(current);
		current->ptrace &= ~PT_DTRACE;
		task_unlock(current);
	}
	putname(filename);
out:
	return error;
}
+20 −6
Original line number Diff line number Diff line
@@ -332,12 +332,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)

void do_syscall_trace(void)
{
	if (!test_thread_flag(TIF_SYSCALL_TRACE))
		return;

	if (!(current->ptrace & PT_PTRACED))
		return;

	/*
	 * The 0x80 provides a way for the tracing parent to distinguish
	 * between a syscall stop and SIGTRAP delivery
@@ -354,3 +348,23 @@ void do_syscall_trace(void)
		current->exit_code = 0;
	}
}

void do_syscall_trace_enter(struct pt_regs *regs)
{
	if (test_thread_flag(TIF_SYSCALL_TRACE)
			&& (current->ptrace & PT_PTRACED))
		do_syscall_trace();

#if 0
	if (unlikely(current->audit_context))
		audit_syscall_entry(current, AUDIT_ARCH_XTENSA..);
#endif
}

void do_syscall_trace_leave(struct pt_regs *regs)
{
	if ((test_thread_flag(TIF_SYSCALL_TRACE))
			&& (current->ptrace & PT_PTRACED))
		do_syscall_trace();
}
+6 −6
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ extern struct task_struct *coproc_owners[];
 * Atomically swap in the new signal mask, and wait for a signal.
 */

int sys_sigsuspend(struct pt_regs *regs)
int xtensa_sigsuspend(struct pt_regs *regs)
{
	old_sigset_t mask = (old_sigset_t) regs->areg[3];
	sigset_t saveset;
@@ -68,7 +68,7 @@ int sys_sigsuspend(struct pt_regs *regs)
}

asmlinkage int
sys_rt_sigsuspend(struct pt_regs *regs)
xtensa_rt_sigsuspend(struct pt_regs *regs)
{
	sigset_t *unewset = (sigset_t *) regs->areg[4];
	size_t sigsetsize = (size_t) regs->areg[3];
@@ -96,7 +96,7 @@ sys_rt_sigsuspend(struct pt_regs *regs)
}

asmlinkage int
sys_sigaction(int sig, const struct old_sigaction *act,
xtensa_sigaction(int sig, const struct old_sigaction *act,
	      struct old_sigaction *oact)
{
	struct k_sigaction new_ka, old_ka;
@@ -128,7 +128,7 @@ sys_sigaction(int sig, const struct old_sigaction *act,
}

asmlinkage int
sys_sigaltstack(struct pt_regs *regs)
xtensa_sigaltstack(struct pt_regs *regs)
{
	const stack_t *uss = (stack_t *) regs->areg[4];
	stack_t *uoss = (stack_t *) regs->areg[3];
@@ -350,7 +350,7 @@ setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate,
	return err;
}

asmlinkage int sys_sigreturn(struct pt_regs *regs)
asmlinkage int xtensa_sigreturn(struct pt_regs *regs)
{
	struct sigframe *frame = (struct sigframe *)regs->areg[1];
	sigset_t set;
@@ -382,7 +382,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
	return 0;
}

asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
asmlinkage int xtensa_rt_sigreturn(struct pt_regs *regs)
{
	struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1];
	sigset_t set;
Loading