Skip to content

Commit

Permalink
[PATCH] xtensa: fix system call interface
Browse files Browse the repository at this point in the history
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: Chris Zankel <chris@zankel.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Chris Zankel authored and Linus Torvalds committed Dec 10, 2006
1 parent 173d668 commit fc4fb2a
Show file tree
Hide file tree
Showing 14 changed files with 1,053 additions and 967 deletions.
5 changes: 5 additions & 0 deletions arch/xtensa/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
228 changes: 150 additions & 78 deletions arch/xtensa/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand All @@ -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

Expand All @@ -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);
* a2 a6 a3 a4 a5
* 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
*
Expand Down Expand Up @@ -1091,59 +1087,62 @@ ENTRY(fast_syscall_unrecoverable)
#define CATCH \
67:

ENTRY(fast_syscall_sysxtensa)

_beqz a6, 1f
_blti a6, SYSXTENSA_COUNT, 2f
ENTRY(fast_syscall_xtensa)

1: j user_exception

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




Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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"

71 changes: 41 additions & 30 deletions arch/xtensa/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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..
*/
Expand Down Expand Up @@ -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;
}

Loading

0 comments on commit fc4fb2a

Please sign in to comment.