diff mbox series

[15/31] nds32: System calls handling

Message ID 61b5cd5e7f2cf2f485a990cdf238788b817a1d53.1510118606.git.green.hu@gmail.com
State Not Applicable, archived
Delegated to: David Miller
Headers show
Series Andes(nds32) Linux Kernel Port | expand

Commit Message

Greentime Hu Nov. 8, 2017, 5:55 a.m. UTC
From: Greentime Hu <greentime@andestech.com>

Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
---
 arch/nds32/include/asm/syscall.h     |  203 ++++++++++++++++++++++++++++++++++
 arch/nds32/include/asm/syscalls.h    |   27 +++++
 arch/nds32/include/asm/unistd.h      |   21 ++++
 arch/nds32/include/uapi/asm/unistd.h |   36 ++++++
 arch/nds32/kernel/ex-scall.S         |  146 ++++++++++++++++++++++++
 arch/nds32/kernel/sys_nds32.c        |   63 +++++++++++
 arch/nds32/kernel/syscall_table.c    |   28 +++++
 7 files changed, 524 insertions(+)
 create mode 100644 arch/nds32/include/asm/syscall.h
 create mode 100644 arch/nds32/include/asm/syscalls.h
 create mode 100644 arch/nds32/include/asm/unistd.h
 create mode 100644 arch/nds32/include/uapi/asm/unistd.h
 create mode 100644 arch/nds32/kernel/ex-scall.S
 create mode 100644 arch/nds32/kernel/sys_nds32.c
 create mode 100644 arch/nds32/kernel/syscall_table.c

Comments

Arnd Bergmann Nov. 8, 2017, 9:30 a.m. UTC | #1
On Wed, Nov 8, 2017 at 6:55 AM, Greentime Hu <green.hu@gmail.com> wrote:
> From: Greentime Hu <greentime@andestech.com>

> +#endif /* __ASM_NDS32_SYSCALLS_H */
> diff --git a/arch/nds32/include/asm/unistd.h b/arch/nds32/include/asm/unistd.h
> new file mode 100644
> index 0000000..b30adca
> --- /dev/null
> +++ b/arch/nds32/include/asm/unistd.h
> @@ -0,0 +1,21 @@

> +#define __ARCH_WANT_SYS_LLSEEK

This gets set from include/asm-generic/unistd.h if you include that file.

> +#define __ARCH_WANT_SYS_CLONE

This seems ok, though it would be nice to have the reverse logic and have
architectures opt-out of the generic version when they need to provide their
own, rather than having most architectures set it.

> +#define __ARCH_WANT_SYS_OLD_MMAP

I don't see why you need this, can it be dropped?

> diff --git a/arch/nds32/include/uapi/asm/unistd.h b/arch/nds32/include/uapi/asm/unistd.h
> new file mode 100644
> index 0000000..01b466d
> --- /dev/null
> +++ b/arch/nds32/include/uapi/asm/unistd.h

> +#define __NR_ipc               (__NR_arch_specific_syscall + 2)
> +#define __NR_sysfs             (__NR_arch_specific_syscall + 3)
> +#define __NR__llseek             __NR_llseek



> +__SYSCALL(__NR_cacheflush, sys_cacheflush)
> +__SYSCALL(__NR_syscall, sys_syscall)
> +__SYSCALL(__NR_ipc, sys_ipc)
> +__SYSCALL(__NR_sysfs, sys_sysfs)
> +
> +__SYSCALL(__NR_fadvise64_64, sys_fadvise64_64_wrapper)
> +__SYSCALL(__NR_rt_sigreturn, sys_rt_sigreturn_wrapper)
> +__SYSCALL(__NR_mmap, sys_old_mmap)

Usually we handle those overrides by defining the macros in asm/unistd.h
before including the asm-generic version. Can you do that as well for
consistency?

I don't see a reason for sys_ipc, sys_sysfs or sys_old_mmap() here
in a new architecture. Can you drop those or explain why you need them?

> +/*
> + * Special system call wrappers
> + *
> + * $r0 = syscall number
> + * $r8 = syscall table
> + */
> +       .type   sys_syscall, #function
> +ENTRY(sys_syscall)
> +       addi    $p1, $r0, #-__NR_syscalls
> +       bgtz    $p1, 3f
> +       move    $p1, $r0
> +       move    $r0, $r1
> +       move    $r1, $r2
> +       move    $r2, $r3
> +       move    $r3, $r4
> +       move    $r4, $r5
> +! add for syscall 6 args
> +       lwi     $r5, [$sp + #SP_OFFSET ]
> +       lwi     $r5, [$r5]
> +! ~add for syscall 6 args
> +
> +       lw      $p1, [tbl+$p1<<2]
> +       jr      $p1
> +3:     b       sys_ni_syscall
> +ENDPROC(sys_syscall)

Can you explain what this is used for?

> --- /dev/null
> +++ b/arch/nds32/kernel/sys_nds32.c
> +
> +long sys_mmap2(unsigned long addr, unsigned long len,
> +              unsigned long prot, unsigned long flags,
> +              unsigned long fd, unsigned long pgoff)
> +{
> +       if (pgoff & (~PAGE_MASK >> 12))
> +               return -EINVAL;
> +
> +       return sys_mmap_pgoff(addr, len, prot, flags, fd,
> +                             pgoff >> (PAGE_SHIFT - 12));
> +}
> +
> +asmlinkage long sys_fadvise64_64_wrapper(int fd, int advice, loff_t offset,
> +                                        loff_t len)
> +{
> +       return sys_fadvise64_64(fd, offset, len, advice);
> +}

You should always use SYSCALL_DEFINE*() macros to define entry points
for your own syscalls in C code for consistency. I also wonder if we should
just move those two into common code, a lot of architectures need the first
one in particular.

        Arnd
Vincent Chen Nov. 13, 2017, 2:51 a.m. UTC | #2
>>On Wed, Nov 8, 2017 at 6:55 AM, Greentime Hu <green.hu@gmail.com> wrote:
>> From: Greentime Hu <greentime@andestech.com>
>
>> +#endif /* __ASM_NDS32_SYSCALLS_H */
>> diff --git a/arch/nds32/include/asm/unistd.h
>> b/arch/nds32/include/asm/unistd.h new file mode 100644 index
>> 0000000..b30adca
>> --- /dev/null
>> +++ b/arch/nds32/include/asm/unistd.h
>> @@ -0,0 +1,21 @@
>
>> +#define __ARCH_WANT_SYS_LLSEEK
>
>This gets set from include/asm-generic/unistd.h if you include that file.
>
Dear Arnd:

Thanks
I will remove it in the next version patch.


>> +#define __ARCH_WANT_SYS_CLONE
>
>This seems ok, though it would be nice to have the reverse logic and have architectures opt-out of the generic version when they need to provide their own, rather than having most architectures set it.
>

Thanks
I will provide nds32 SYSCALL_DEFINE_5(clone) in the next version patch.

>> +#define __ARCH_WANT_SYS_OLD_MMAP
>
>I don't see why you need this, can it be dropped?

Thanks
I will remove it in the next version patch.

>
>> diff --git a/arch/nds32/include/uapi/asm/unistd.h
>> b/arch/nds32/include/uapi/asm/unistd.h
>> new file mode 100644
>> index 0000000..01b466d
>> --- /dev/null
>> +++ b/arch/nds32/include/uapi/asm/unistd.h
>
>> +#define __NR_ipc               (__NR_arch_specific_syscall + 2)
>> +#define __NR_sysfs             (__NR_arch_specific_syscall + 3)
>> +#define __NR__llseek             __NR_llseek
>
>
>
>> +__SYSCALL(__NR_cacheflush, sys_cacheflush) __SYSCALL(__NR_syscall,
>> +sys_syscall) __SYSCALL(__NR_ipc, sys_ipc) __SYSCALL(__NR_sysfs,
>> +sys_sysfs)
>> +
>> +__SYSCALL(__NR_fadvise64_64, sys_fadvise64_64_wrapper)
>> +__SYSCALL(__NR_rt_sigreturn, sys_rt_sigreturn_wrapper)
>> +__SYSCALL(__NR_mmap, sys_old_mmap)
>
>Usually we handle those overrides by defining the macros in asm/unistd.h before including the asm-generic version. Can you do that as well for consistency?
>

Thanks
Ok, I will modify it in the next version patch

>I don't see a reason for sys_ipc, sys_sysfs or sys_old_mmap() here in a new architecture. Can you drop those or explain why you need them?
>

Thanks
 I will remove them in the next version patch

>> +/*
>> + * Special system call wrappers
>> + *
>> + * $r0 = syscall number
>> + * $r8 = syscall table
>> + */
>> +       .type   sys_syscall, #function
>> +ENTRY(sys_syscall)
>> +       addi    $p1, $r0, #-__NR_syscalls
>> +       bgtz    $p1, 3f
>> +       move    $p1, $r0
>> +       move    $r0, $r1
>> +       move    $r1, $r2
>> +       move    $r2, $r3
>> +       move    $r3, $r4
>> +       move    $r4, $r5
>> +! add for syscall 6 args
>> +       lwi     $r5, [$sp + #SP_OFFSET ]
>> +       lwi     $r5, [$r5]
>> +! ~add for syscall 6 args
>> +
>> +       lw      $p1, [tbl+$p1<<2]
>> .+       jr      $p1
>> +3:     b       sys_ni_syscall
>> +ENDPROC(sys_syscall)
>
>Can you explain what this is used for?
>

This is used to handle syscall(int number, ....).
Unlike other architectures,  the system number shall be determined in
compile time when issuing system call in nds32.
Therefore, we  only can parse the content of syscall(int number, ....)
and distribute it to destination handler in kernel space
(Other architecture can handle it in user space by glibc's syscall wrapper)

>> --- /dev/null
>> +++ b/arch/nds32/kernel/sys_nds32.c
>> +
>> +long sys_mmap2(unsigned long addr, unsigned long len,
>> +              unsigned long prot, unsigned long flags,
>> +              unsigned long fd, unsigned long pgoff) {
>> +       if (pgoff & (~PAGE_MASK >> 12))
>> +               return -EINVAL;
>> +
>> +       return sys_mmap_pgoff(addr, len, prot, flags, fd,
>> +                             pgoff >> (PAGE_SHIFT - 12)); }
>> +
>> +asmlinkage long sys_fadvise64_64_wrapper(int fd, int advice, loff_t offset,
>> +                                        loff_t len) {
>> +       return sys_fadvise64_64(fd, offset, len, advice); }
>
>You should always use SYSCALL_DEFINE*() macros to define entry points for your own syscalls in C code for consistency. I also wonder if we should just move those two into common code, a lot of architectures need the first one in particular.
>

The sys_fadvise64_64_wrapper is used to reorder the input parameter.

In order to solve register alignment problem, we adjust the input
parameter order of fadvise64_64 while issuing this syscall.
Therefore, we need this wrapper to reorder the input parameter to fit
sys_fadvise64_64's API in kernel.

>       Arnd


Best regard
Vincent
Arnd Bergmann Nov. 13, 2017, 11:42 a.m. UTC | #3
On Mon, Nov 13, 2017 at 3:51 AM, Vincent Chen <deanbo422@gmail.com> wrote:
>>>On Wed, Nov 8, 2017 at 6:55 AM, Greentime Hu <green.hu@gmail.com> wrote:
>>> From: Greentime Hu <greentime@andestech.com>

>
>>> +#define __ARCH_WANT_SYS_CLONE
>>
>>This seems ok, though it would be nice to have the reverse logic and have architectures opt-out of the generic version when they need to provide their own, rather than having most architectures set it.
>>
>
> Thanks
> I will provide nds32 SYSCALL_DEFINE_5(clone) in the next version patch.

That's not what I meant, my suggestion is to create a new patch to remove the
__ARCH_WANT_SYS_CLONE symbol from all architectures, and instead use
something like __ARCH_HAVE_SYS_CLONE on architectures that do *not*
want the generic implementation.

nds32 clearly wants the generic implementation here, it just shouldn't have to
select that symbol to get it.

>>> +/*
>>> + * Special system call wrappers
>>> + *
>>> + * $r0 = syscall number
>>> + * $r8 = syscall table
>>> + */
>>> +       .type   sys_syscall, #function
>>> +ENTRY(sys_syscall)
>>> +       addi    $p1, $r0, #-__NR_syscalls
>>> +       bgtz    $p1, 3f
>>> +       move    $p1, $r0
>>> +       move    $r0, $r1
>>> +       move    $r1, $r2
>>> +       move    $r2, $r3
>>> +       move    $r3, $r4
>>> +       move    $r4, $r5
>>> +! add for syscall 6 args
>>> +       lwi     $r5, [$sp + #SP_OFFSET ]
>>> +       lwi     $r5, [$r5]
>>> +! ~add for syscall 6 args
>>> +
>>> +       lw      $p1, [tbl+$p1<<2]
>>> .+       jr      $p1
>>> +3:     b       sys_ni_syscall
>>> +ENDPROC(sys_syscall)
>>
>>Can you explain what this is used for?
>>
>
> This is used to handle syscall(int number, ....).
> Unlike other architectures,  the system number shall be determined in
> compile time when issuing system call in nds32.
> Therefore, we  only can parse the content of syscall(int number, ....)
> and distribute it to destination handler in kernel space
> (Other architecture can handle it in user space by glibc's syscall wrapper)

Hmm, I think other architectures that run into this problem use self-modifying
code for syscall(), but that is also ugly as it requires having a page that
is both writable and executable.

I think your approach can be tricky for things like seccomp(). It's possible
that you get all of it right, but if you can come up with a different solution,
that might be better.

How much would it cost to simply always pass the syscall number
in a register, and not use the immediate argument at all?

>>> --- /dev/null
>>> +++ b/arch/nds32/kernel/sys_nds32.c
>>> +
>>> +long sys_mmap2(unsigned long addr, unsigned long len,
>>> +              unsigned long prot, unsigned long flags,
>>> +              unsigned long fd, unsigned long pgoff) {
>>> +       if (pgoff & (~PAGE_MASK >> 12))
>>> +               return -EINVAL;
>>> +
>>> +       return sys_mmap_pgoff(addr, len, prot, flags, fd,
>>> +                             pgoff >> (PAGE_SHIFT - 12)); }
>>> +
>>> +asmlinkage long sys_fadvise64_64_wrapper(int fd, int advice, loff_t offset,
>>> +                                        loff_t len) {
>>> +       return sys_fadvise64_64(fd, offset, len, advice); }
>>
>>You should always use SYSCALL_DEFINE*() macros to define entry points for your own syscalls in C code for consistency. I also wonder if we should just move those two into common code, a lot of architectures need the first one in particular.
>>
>
> The sys_fadvise64_64_wrapper is used to reorder the input parameter.
>
> In order to solve register alignment problem, we adjust the input
> parameter order of fadvise64_64 while issuing this syscall.
> Therefore, we need this wrapper to reorder the input parameter to fit
> sys_fadvise64_64's API in kernel.

I understand what it's used for, it's just that I would recommend writing it
differently, as

SYSCALL_DEFINE4(fadvise64_64_wrapper, int, fd, int, advice, loff_t,
offset, loff_t, len)
{
       return sys_fadvise64_64(fd, offset, len, advice);
}

      Arnd
Vincent Chen Nov. 22, 2017, 3:13 a.m. UTC | #4
2017-11-13 19:42 GMT+08:00 Arnd Bergmann <arnd@arndb.de>:
> On Mon, Nov 13, 2017 at 3:51 AM, Vincent Chen <deanbo422@gmail.com> wrote:
>>>>On Wed, Nov 8, 2017 at 6:55 AM, Greentime Hu <green.hu@gmail.com> wrote:
>>>> From: Greentime Hu <greentime@andestech.com>
>
>>
>>>> +#define __ARCH_WANT_SYS_CLONE
>>>
>>>This seems ok, though it would be nice to have the reverse logic and have architectures opt-out of the generic version when they need to provide their own, rather than having most architectures set it.
>>>
>>
>> Thanks
>> I will provide nds32 SYSCALL_DEFINE_5(clone) in the next version patch.
>
> That's not what I meant, my suggestion is to create a new patch to remove the
> __ARCH_WANT_SYS_CLONE symbol from all architectures, and instead use
> something like __ARCH_HAVE_SYS_CLONE on architectures that do *not*
> want the generic implementation.
>
> nds32 clearly wants the generic implementation here, it just shouldn't have to
> select that symbol to get it.
>
>>>> +/*
>>>> + * Special system call wrappers
>>>> + *
>>>> + * $r0 = syscall number
>>>> + * $r8 = syscall table
>>>> + */
>>>> +       .type   sys_syscall, #function
>>>> +ENTRY(sys_syscall)
>>>> +       addi    $p1, $r0, #-__NR_syscalls
>>>> +       bgtz    $p1, 3f
>>>> +       move    $p1, $r0
>>>> +       move    $r0, $r1
>>>> +       move    $r1, $r2
>>>> +       move    $r2, $r3
>>>> +       move    $r3, $r4
>>>> +       move    $r4, $r5
>>>> +! add for syscall 6 args
>>>> +       lwi     $r5, [$sp + #SP_OFFSET ]
>>>> +       lwi     $r5, [$r5]
>>>> +! ~add for syscall 6 args
>>>> +
>>>> +       lw      $p1, [tbl+$p1<<2]
>>>> .+       jr      $p1
>>>> +3:     b       sys_ni_syscall
>>>> +ENDPROC(sys_syscall)
>>>
>>>Can you explain what this is used for?
>>>
>>
>> This is used to handle syscall(int number, ....).
>> Unlike other architectures,  the system number shall be determined in
>> compile time when issuing system call in nds32.
>> Therefore, we  only can parse the content of syscall(int number, ....)
>> and distribute it to destination handler in kernel space
>> (Other architecture can handle it in user space by glibc's syscall wrapper)
>
> Hmm, I think other architectures that run into this problem use self-modifying
> code for syscall(), but that is also ugly as it requires having a page that
> is both writable and executable.
>
> I think your approach can be tricky for things like seccomp(). It's possible
> that you get all of it right, but if you can come up with a different solution,
> that might be better.
>
> How much would it cost to simply always pass the syscall number
> in a register, and not use the immediate argument at all?
>

After re-evaluating the performance, we decide to use a particular
register to transfer syscall number
instead of immediate argument. So, above sys_syscall will be removed
in the next version patch

Thanks


>>>> --- /dev/null
>>>> +++ b/arch/nds32/kernel/sys_nds32.c
>>>> +
>>>> +long sys_mmap2(unsigned long addr, unsigned long len,
>>>> +              unsigned long prot, unsigned long flags,
>>>> +              unsigned long fd, unsigned long pgoff) {
>>>> +       if (pgoff & (~PAGE_MASK >> 12))
>>>> +               return -EINVAL;
>>>> +
>>>> +       return sys_mmap_pgoff(addr, len, prot, flags, fd,
>>>> +                             pgoff >> (PAGE_SHIFT - 12)); }
>>>> +
>>>> +asmlinkage long sys_fadvise64_64_wrapper(int fd, int advice, loff_t offset,
>>>> +                                        loff_t len) {
>>>> +       return sys_fadvise64_64(fd, offset, len, advice); }
>>>
>>>You should always use SYSCALL_DEFINE*() macros to define entry points for your own syscalls in C code for consistency. I also wonder if we should just move those two into common code, a lot of architectures need the first one in particular.
>>>
>>
>> The sys_fadvise64_64_wrapper is used to reorder the input parameter.
>>
>> In order to solve register alignment problem, we adjust the input
>> parameter order of fadvise64_64 while issuing this syscall.
>> Therefore, we need this wrapper to reorder the input parameter to fit
>> sys_fadvise64_64's API in kernel.
>
> I understand what it's used for, it's just that I would recommend writing it
> differently, as
>
> SYSCALL_DEFINE4(fadvise64_64_wrapper, int, fd, int, advice, loff_t,
> offset, loff_t, len)
> {
>        return sys_fadvise64_64(fd, offset, len, advice);
> }
>
>       Arnd
diff mbox series

Patch

diff --git a/arch/nds32/include/asm/syscall.h b/arch/nds32/include/asm/syscall.h
new file mode 100644
index 0000000..3066bae
--- /dev/null
+++ b/arch/nds32/include/asm/syscall.h
@@ -0,0 +1,203 @@ 
+/*
+ * Access to user system call parameters and results
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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.
+ *
+ * This file is a stub providing documentation for what functions
+ * asm-ARCH/syscall.h files need to define.  Most arch definitions
+ * will be simple inlines.
+ *
+ * All of these functions expect to be called with no locks,
+ * and only when the caller is sure that the task of interest
+ * cannot return to user mode while we are looking at it.
+ */
+
+#ifndef _ASM_NDS32_SYSCALL_H
+#define _ASM_NDS32_SYSCALL_H	1
+
+#include <linux/err.h>
+struct task_struct;
+struct pt_regs;
+
+/**
+ * syscall_get_nr - find what system call a task is executing
+ * @task:	task of interest, must be blocked
+ * @regs:	task_pt_regs() of @task
+ *
+ * If @task is executing a system call or is at system call
+ * tracing about to attempt one, returns the system call number.
+ * If @task is not executing a system call, i.e. it's blocked
+ * inside the kernel for a fault or signal, returns -1.
+ *
+ * Note this returns int even on 64-bit machines.  Only 32 bits of
+ * system call number can be meaningful.  If the actual arch value
+ * is 64 bits, this truncates to 32 bits so 0xffffffff means -1.
+ *
+ * It's only valid to call this when @task is known to be blocked.
+ */
+int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
+{
+	return regs->syscallno;
+}
+
+/**
+ * syscall_rollback - roll back registers after an aborted system call
+ * @task:	task of interest, must be in system call exit tracing
+ * @regs:	task_pt_regs() of @task
+ *
+ * It's only valid to call this when @task is stopped for system
+ * call exit tracing (due to TIF_SYSCALL_TRACE or TIF_SYSCALL_AUDIT),
+ * after tracehook_report_syscall_entry() returned nonzero to prevent
+ * the system call from taking place.
+ *
+ * This rolls back the register state in @regs so it's as if the
+ * system call instruction was a no-op.  The registers containing
+ * the system call number and arguments are as they were before the
+ * system call instruction.  This may not be the same as what the
+ * register state looked like at system call entry tracing.
+ */
+void syscall_rollback(struct task_struct *task, struct pt_regs *regs)
+{
+	regs->uregs[0] = regs->orig_r0;
+}
+
+/**
+ * syscall_get_error - check result of traced system call
+ * @task:	task of interest, must be blocked
+ * @regs:	task_pt_regs() of @task
+ *
+ * Returns 0 if the system call succeeded, or -ERRORCODE if it failed.
+ *
+ * It's only valid to call this when @task is stopped for tracing on exit
+ * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
+ */
+long syscall_get_error(struct task_struct *task, struct pt_regs *regs)
+{
+	unsigned long error = regs->uregs[0];
+	return IS_ERR_VALUE(error) ? error : 0;
+}
+
+/**
+ * syscall_get_return_value - get the return value of a traced system call
+ * @task:	task of interest, must be blocked
+ * @regs:	task_pt_regs() of @task
+ *
+ * Returns the return value of the successful system call.
+ * This value is meaningless if syscall_get_error() returned nonzero.
+ *
+ * It's only valid to call this when @task is stopped for tracing on exit
+ * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
+ */
+long syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
+{
+	return regs->uregs[0];
+}
+
+/**
+ * syscall_set_return_value - change the return value of a traced system call
+ * @task:	task of interest, must be blocked
+ * @regs:	task_pt_regs() of @task
+ * @error:	negative error code, or zero to indicate success
+ * @val:	user return value if @error is zero
+ *
+ * This changes the results of the system call that user mode will see.
+ * If @error is zero, the user sees a successful system call with a
+ * return value of @val.  If @error is nonzero, it's a negated errno
+ * code; the user sees a failed system call with this errno code.
+ *
+ * It's only valid to call this when @task is stopped for tracing on exit
+ * from a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
+ */
+void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
+			      int error, long val)
+{
+	regs->uregs[0] = (long)error ? error : val;
+}
+
+/**
+ * syscall_get_arguments - extract system call parameter values
+ * @task:	task of interest, must be blocked
+ * @regs:	task_pt_regs() of @task
+ * @i:		argument index [0,5]
+ * @n:		number of arguments; n+i must be [1,6].
+ * @args:	array filled with argument values
+ *
+ * Fetches @n arguments to the system call starting with the @i'th argument
+ * (from 0 through 5).  Argument @i is stored in @args[0], and so on.
+ * An arch inline version is probably optimal when @i and @n are constants.
+ *
+ * It's only valid to call this when @task is stopped for tracing on
+ * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
+ * It's invalid to call this with @i + @n > 6; we only support system calls
+ * taking up to 6 arguments.
+ */
+#define SYSCALL_MAX_ARGS 6
+void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+			   unsigned int i, unsigned int n, unsigned long *args)
+{
+	if (n == 0)
+		return;
+	if (i + n > SYSCALL_MAX_ARGS) {
+		unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i;
+		unsigned int n_bad = n + i - SYSCALL_MAX_ARGS;
+		pr_warning("%s called with max args %d, handling only %d\n",
+			   __func__, i + n, SYSCALL_MAX_ARGS);
+		memset(args_bad, 0, n_bad * sizeof(args[0]));
+		memset(args_bad, 0, n_bad * sizeof(args[0]));
+	}
+
+	if (i == 0) {
+		args[0] = regs->orig_r0;
+		args++;
+		i++;
+		n--;
+	}
+
+	memcpy(args, &regs->uregs[0] + i, n * sizeof(args[0]));
+}
+
+/**
+ * syscall_set_arguments - change system call parameter value
+ * @task:	task of interest, must be in system call entry tracing
+ * @regs:	task_pt_regs() of @task
+ * @i:		argument index [0,5]
+ * @n:		number of arguments; n+i must be [1,6].
+ * @args:	array of argument values to store
+ *
+ * Changes @n arguments to the system call starting with the @i'th argument.
+ * Argument @i gets value @args[0], and so on.
+ * An arch inline version is probably optimal when @i and @n are constants.
+ *
+ * It's only valid to call this when @task is stopped for tracing on
+ * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT.
+ * It's invalid to call this with @i + @n > 6; we only support system calls
+ * taking up to 6 arguments.
+ */
+void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
+			   unsigned int i, unsigned int n,
+			   const unsigned long *args)
+{
+	if (n == 0)
+		return;
+
+	if (i + n > SYSCALL_MAX_ARGS) {
+		pr_warn("%s called with max args %d, handling only %d\n",
+			__func__, i + n, SYSCALL_MAX_ARGS);
+		n = SYSCALL_MAX_ARGS - i;
+	}
+
+	if (i == 0) {
+		regs->orig_r0 = args[0];
+		args++;
+		i++;
+		n--;
+	}
+
+	memcpy(&regs->uregs[0] + i, args, n * sizeof(args[0]));
+}
+#endif /* _ASM_NDS32_SYSCALL_H */
diff --git a/arch/nds32/include/asm/syscalls.h b/arch/nds32/include/asm/syscalls.h
new file mode 100644
index 0000000..741ccdc
--- /dev/null
+++ b/arch/nds32/include/asm/syscalls.h
@@ -0,0 +1,27 @@ 
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASM_NDS32_SYSCALLS_H
+#define __ASM_NDS32_SYSCALLS_H
+
+int sys_cacheflush(unsigned long addr, unsigned long len, unsigned int op);
+long sys_fadvise64_64_wrapper(int fd, int advice, loff_t offset, loff_t len);
+asmlinkage int sys_syscall(void);
+asmlinkage int sys_rt_sigreturn_wrapper(void);
+
+#include <asm-generic/syscalls.h>
+
+#endif /* __ASM_NDS32_SYSCALLS_H */
diff --git a/arch/nds32/include/asm/unistd.h b/arch/nds32/include/asm/unistd.h
new file mode 100644
index 0000000..b30adca
--- /dev/null
+++ b/arch/nds32/include/asm/unistd.h
@@ -0,0 +1,21 @@ 
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __ARCH_WANT_SYS_LLSEEK
+#define __ARCH_WANT_SYS_CLONE
+#define __ARCH_WANT_SYS_OLD_MMAP
+
+#include <uapi/asm/unistd.h>
diff --git a/arch/nds32/include/uapi/asm/unistd.h b/arch/nds32/include/uapi/asm/unistd.h
new file mode 100644
index 0000000..01b466d
--- /dev/null
+++ b/arch/nds32/include/uapi/asm/unistd.h
@@ -0,0 +1,36 @@ 
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define __ARCH_WANT_RENAMEAT
+#define __ARCH_WANT_SYSCALL_OFF_T
+
+/* Use the standard ABI for syscalls */
+#include <asm-generic/unistd.h>
+
+/* Additional NDS32 specific syscalls. */
+#define __NR_cacheflush		(__NR_arch_specific_syscall)
+#define __NR_syscall		(__NR_arch_specific_syscall + 1)
+#define __NR_ipc		(__NR_arch_specific_syscall + 2)
+#define __NR_sysfs		(__NR_arch_specific_syscall + 3)
+#define __NR__llseek             __NR_llseek
+__SYSCALL(__NR_cacheflush, sys_cacheflush)
+__SYSCALL(__NR_syscall, sys_syscall)
+__SYSCALL(__NR_ipc, sys_ipc)
+__SYSCALL(__NR_sysfs, sys_sysfs)
+
+__SYSCALL(__NR_fadvise64_64, sys_fadvise64_64_wrapper)
+__SYSCALL(__NR_rt_sigreturn, sys_rt_sigreturn_wrapper)
+__SYSCALL(__NR_mmap, sys_old_mmap)
diff --git a/arch/nds32/kernel/ex-scall.S b/arch/nds32/kernel/ex-scall.S
new file mode 100644
index 0000000..52691ce
--- /dev/null
+++ b/arch/nds32/kernel/ex-scall.S
@@ -0,0 +1,146 @@ 
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/unistd.h>
+#include <asm/assembler.h>
+#include <asm/nds32.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/current.h>
+
+/*
+ * $r0 = previous task_struct,
+ * $r1 = next task_struct,
+ * previous and next are guaranteed not to be the same.
+ */
+
+ENTRY(__switch_to)
+
+	la	$p0, __entry_task
+	sw	$r1, [$p0]
+	move	$p1, $r0
+	addi	$p1, $p1, #THREAD_CPU_CONTEXT
+	smw.bi 	$r6, [$p1], $r14, #0xb		! push r6~r14, fp, lp, sp
+	move	$r25, $r1
+	addi	$r1, $r1, #THREAD_CPU_CONTEXT
+	lmw.bi 	$r6, [$r1], $r14, #0xb		! pop r6~r14, fp, lp, sp
+	ret
+
+/*
+ * These are the registers used in the syscall handler, and allow us
+ * to have in theory up to 6 arguments to a function - $r0 to $r5.
+ *
+ * We must set at least "tsk" and "tbl" when calling ret_with_reschedule.
+ */
+#define tbl	$r8            //  syscall table pointer
+
+/*
+ * $r7 will be writen as syscall nr
+ * by retrieving from $ITYPE 'SWID' bitfiled
+ */
+	.macro	get_scno
+	mfsr	$r7, $ITYPE
+	srli	$r7, $r7, #ITYPE_offSWID
+	swi	$r7, [$sp + SYSCALLNO_OFFSET]
+	.endm
+
+	.macro	updateipc
+	addi	$r17, $r13, #4				! $r13 is $IPC
+	swi	$r17, [$sp + IPC_OFFSET]
+	.endm
+
+ENTRY(eh_syscall)
+	updateipc
+
+	get_scno
+	gie_enable
+
+ENTRY(eh_syscall_phase_2)
+	lwi	$p0, [tsk+#TSK_TI_FLAGS]		! check for syscall tracing
+
+	andi	$p1, $p0, #_TIF_WORK_SYSCALL_ENTRY	! are we tracing syscalls?
+	bnez	$p1, __sys_trace
+
+	la	$lp, ret_fast_syscall		! return address
+jmp_systbl:
+	addi	$p1, $r7, #-__NR_syscalls	! syscall number of syscall instruction is guarded by addembler
+	bgez	$p1, _SCNO_EXCEED		! call sys_* routine
+	la	tbl, sys_call_table		! load syscall table pointer
+	slli	$p1, $r7, #2
+	add	$p1, tbl, $p1
+	lwi	$p1, [$p1]
+	jr	$p1				! no return
+
+_SCNO_EXCEED:
+	ori	$r0, $r7, #0
+        ori	$r1, $sp, #0
+	b	bad_syscall
+
+/*
+ * This is the really slow path.  We're going to be doing
+ * context switches, and waiting for our parent to respond.
+ */
+__sys_trace:
+	move	$r1, $sp
+	move	$r0, $r7			! trace entry [IP = 0]
+	bal	syscall_trace_enter
+	move	$r7, $r0
+	la	$lp, __sys_trace_return		! return address
+
+	addi    $p1, $r7, #1
+	beqz    $p1, ret_slow_syscall		! fatal signal is pending
+
+	addi	$p1, $sp, #R0_OFFSET		! pointer to regs
+	lmw.bi	$r0, [$p1], $r5			! have to reload $r0 - $r5
+	b	jmp_systbl
+
+__sys_trace_return:
+	swi	$r0, [$sp+#R0_OFFSET]		! T: save returned $r0
+	move	$r0, $sp			! set pt_regs for syscall_trace_leave
+	bal	syscall_trace_leave
+	b	ret_slow_syscall
+
+/*
+ * Special system call wrappers
+ *
+ * $r0 = syscall number
+ * $r8 = syscall table
+ */
+       .type   sys_syscall, #function
+ENTRY(sys_syscall)
+	addi	$p1, $r0, #-__NR_syscalls
+	bgtz	$p1, 3f
+	move	$p1, $r0
+	move	$r0, $r1
+	move	$r1, $r2
+	move	$r2, $r3
+	move	$r3, $r4
+	move	$r4, $r5
+! add for syscall 6 args
+	lwi	$r5, [$sp + #SP_OFFSET ]
+	lwi	$r5, [$r5]
+! ~add for syscall 6 args
+
+	lw	$p1, [tbl+$p1<<2]
+	jr	$p1
+3:	b	sys_ni_syscall
+ENDPROC(sys_syscall)
+
+ENTRY(sys_rt_sigreturn_wrapper)
+	addi	$r0, $sp, #0
+	b	sys_rt_sigreturn
+ENDPROC(sys_rt_sigreturn_wrapper)
diff --git a/arch/nds32/kernel/sys_nds32.c b/arch/nds32/kernel/sys_nds32.c
new file mode 100644
index 0000000..39110fe
--- /dev/null
+++ b/arch/nds32/kernel/sys_nds32.c
@@ -0,0 +1,63 @@ 
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/syscalls.h>
+
+#include <asm/uaccess.h>
+#include <asm/cachectl.h>
+#include <asm/proc-fns.h>
+
+long sys_mmap2(unsigned long addr, unsigned long len,
+	       unsigned long prot, unsigned long flags,
+	       unsigned long fd, unsigned long pgoff)
+{
+	if (pgoff & (~PAGE_MASK >> 12))
+		return -EINVAL;
+
+	return sys_mmap_pgoff(addr, len, prot, flags, fd,
+			      pgoff >> (PAGE_SHIFT - 12));
+}
+
+asmlinkage long sys_fadvise64_64_wrapper(int fd, int advice, loff_t offset,
+					 loff_t len)
+{
+	return sys_fadvise64_64(fd, offset, len, advice);
+}
+
+int sys_cacheflush(unsigned int start, unsigned int end, int cache)
+{
+	struct vm_area_struct *vma;
+	bool flushi = true, wbd = true;
+
+	vma = find_vma(current->mm, start);
+	if (!vma)
+		return -EFAULT;
+	switch (cache) {
+	case ICACHE:
+		wbd = false;
+		break;
+	case DCACHE:
+		flushi = false;
+		break;
+	case BCACHE:
+		break;
+	default:
+		return -EINVAL;
+	}
+	cpu_cache_wbinval_range_check(vma, start, end, flushi, wbd);
+
+	return 0;
+}
diff --git a/arch/nds32/kernel/syscall_table.c b/arch/nds32/kernel/syscall_table.c
new file mode 100644
index 0000000..bafd896
--- /dev/null
+++ b/arch/nds32/kernel/syscall_table.c
@@ -0,0 +1,28 @@ 
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/syscalls.h>
+#include <linux/signal.h>
+#include <linux/unistd.h>
+#include <asm/syscalls.h>
+
+#undef __SYSCALL
+#define __SYSCALL(nr, call) [nr] = (call),
+
+void *sys_call_table[__NR_syscalls] __aligned(8192) = {
+	[0 ... __NR_syscalls - 1] = sys_ni_syscall,
+#include <asm/unistd.h>
+};