aboutsummaryrefslogtreecommitdiffstats
path: root/arch/xtensa/kernel/entry.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/xtensa/kernel/entry.S')
-rw-r--r--arch/xtensa/kernel/entry.S228
1 files changed, 150 insertions, 78 deletions
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index c0b56b17927f..9e271ba009bf 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -1004,13 +1004,10 @@ ENTRY(fast_syscall_kernel)
1004 1004
1005 rsr a0, DEPC # get syscall-nr 1005 rsr a0, DEPC # get syscall-nr
1006 _beqz a0, fast_syscall_spill_registers 1006 _beqz a0, fast_syscall_spill_registers
1007 1007 _beqi a0, __NR_xtensa, fast_syscall_xtensa
1008 addi a0, a0, -__NR_sysxtensa
1009 _beqz a0, fast_syscall_sysxtensa
1010 1008
1011 j kernel_exception 1009 j kernel_exception
1012 1010
1013
1014ENTRY(fast_syscall_user) 1011ENTRY(fast_syscall_user)
1015 1012
1016 /* Skip syscall. */ 1013 /* Skip syscall. */
@@ -1024,9 +1021,7 @@ ENTRY(fast_syscall_user)
1024 1021
1025 rsr a0, DEPC # get syscall-nr 1022 rsr a0, DEPC # get syscall-nr
1026 _beqz a0, fast_syscall_spill_registers 1023 _beqz a0, fast_syscall_spill_registers
1027 1024 _beqi a0, __NR_xtensa, fast_syscall_xtensa
1028 addi a0, a0, -__NR_sysxtensa
1029 _beqz a0, fast_syscall_sysxtensa
1030 1025
1031 j user_exception 1026 j user_exception
1032 1027
@@ -1047,18 +1042,19 @@ ENTRY(fast_syscall_unrecoverable)
1047/* 1042/*
1048 * sysxtensa syscall handler 1043 * sysxtensa syscall handler
1049 * 1044 *
1050 * int sysxtensa (XTENSA_ATOMIC_SET, ptr, val, unused); 1045 * int sysxtensa (SYS_XTENSA_ATOMIC_SET, ptr, val, unused);
1051 * int sysxtensa (XTENSA_ATOMIC_ADD, ptr, val, unused); 1046 * int sysxtensa (SYS_XTENSA_ATOMIC_ADD, ptr, val, unused);
1052 * int sysxtensa (XTENSA_ATOMIC_EXG_ADD, ptr, val, unused); 1047 * int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val, unused);
1053 * int sysxtensa (XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval); 1048 * int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
1054 * a2 a6 a3 a4 a5 1049 * a2 a6 a3 a4 a5
1055 * 1050 *
1056 * Entry condition: 1051 * Entry condition:
1057 * 1052 *
1058 * a0: trashed, original value saved on stack (PT_AREG0) 1053 * a0: a2 (syscall-nr), original value saved on stack (PT_AREG0)
1059 * a1: a1 1054 * a1: a1
1060 * a2: new stack pointer, original in DEPC 1055 * a2: new stack pointer, original in a0 and DEPC
1061 * a3: dispatch table 1056 * a3: dispatch table, original in excsave_1
1057 * a4..a15: unchanged
1062 * depc: a2, original value saved on stack (PT_DEPC) 1058 * depc: a2, original value saved on stack (PT_DEPC)
1063 * excsave_1: a3 1059 * excsave_1: a3
1064 * 1060 *
@@ -1091,59 +1087,62 @@ ENTRY(fast_syscall_unrecoverable)
1091#define CATCH \ 1087#define CATCH \
109267: 108867:
1093 1089
1094ENTRY(fast_syscall_sysxtensa) 1090ENTRY(fast_syscall_xtensa)
1095
1096 _beqz a6, 1f
1097 _blti a6, SYSXTENSA_COUNT, 2f
1098 1091
10991: j user_exception 1092 xsr a3, EXCSAVE_1 # restore a3, excsave1
1100
11012: xsr a3, EXCSAVE_1 # restore a3, excsave1
1102 s32i a7, a2, PT_AREG7
1103 1093
1094 s32i a7, a2, PT_AREG7 # we need an additional register
1104 movi a7, 4 # sizeof(unsigned int) 1095 movi a7, 4 # sizeof(unsigned int)
1105 access_ok a0, a3, a7, a2, .Leac 1096 access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp
1106 1097
1107 _beqi a6, SYSXTENSA_ATOMIC_SET, .Lset 1098 addi a6, a6, -1 # assuming SYS_XTENSA_ATOMIC_SET = 1
1108 _beqi a6, SYSXTENSA_ATOMIC_EXG_ADD, .Lexg 1099 _bgeui a6, SYS_XTENSA_COUNT - 1, .Lill
1109 _beqi a6, SYSXTENSA_ATOMIC_ADD, .Ladd 1100 _bnei a6, SYS_XTENSA_ATOMIC_CMP_SWP - 1, .Lnswp
1110 1101
1111 /* Fall through for SYSXTENSA_ATOMIC_CMP_SWP */ 1102 /* Fall through for ATOMIC_CMP_SWP. */
1112 1103
1113.Lswp: /* Atomic compare and swap */ 1104.Lswp: /* Atomic compare and swap */
1114 1105
1115TRY l32i a7, a3, 0 # read old value 1106TRY l32i a0, a3, 0 # read old value
1116 bne a7, a4, 1f # same as old value? jump 1107 bne a0, a4, 1f # same as old value? jump
1117 s32i a5, a3, 0 # different, modify value 1108TRY s32i a5, a3, 0 # different, modify value
1118 movi a7, 1 # and return 1 1109 l32i a7, a2, PT_AREG7 # restore a7
1119 j .Lret 1110 l32i a0, a2, PT_AREG0 # restore a0
1120 1111 movi a2, 1 # and return 1
11211: movi a7, 0 # same values: return 0 1112 addi a6, a6, 1 # restore a6 (really necessary?)
1122 j .Lret 1113 rfe
1123
1124.Ladd: /* Atomic add */
1125.Lexg: /* Atomic (exchange) add */
1126 1114
1127TRY l32i a7, a3, 0 11151: l32i a7, a2, PT_AREG7 # restore a7
1128 add a4, a4, a7 1116 l32i a0, a2, PT_AREG0 # restore a0
1129 s32i a4, a3, 0 1117 movi a2, 0 # return 0 (note that we cannot set
1130 j .Lret 1118 addi a6, a6, 1 # restore a6 (really necessary?)
1119 rfe
1131 1120
1132.Lset: /* Atomic set */ 1121.Lnswp: /* Atomic set, add, and exg_add. */
1133 1122
1134TRY l32i a7, a3, 0 # read old value as return value 1123TRY l32i a7, a3, 0 # orig
1135 s32i a4, a3, 0 # write new value 1124 add a0, a4, a7 # + arg
1125 moveqz a0, a4, a6 # set
1126TRY s32i a0, a3, 0 # write new value
1136 1127
1137.Lret: mov a0, a2 1128 mov a0, a2
1138 mov a2, a7 1129 mov a2, a7
1139 l32i a7, a0, PT_AREG7 1130 l32i a7, a0, PT_AREG7 # restore a7
1140 l32i a3, a0, PT_AREG3 1131 l32i a0, a0, PT_AREG0 # restore a0
1141 l32i a0, a0, PT_AREG0 1132 addi a6, a6, 1 # restore a6 (really necessary?)
1142 rfe 1133 rfe
1143 1134
1144CATCH 1135CATCH
1145.Leac: movi a7, -EFAULT 1136.Leac: l32i a7, a2, PT_AREG7 # restore a7
1146 j .Lret 1137 l32i a0, a2, PT_AREG0 # restore a0
1138 movi a2, -EFAULT
1139 rfe
1140
1141.Lill: l32i a7, a2, PT_AREG0 # restore a7
1142 l32i a0, a2, PT_AREG0 # restore a0
1143 movi a2, -EINVAL
1144 rfe
1145
1147 1146
1148 1147
1149 1148
@@ -1907,6 +1906,103 @@ ENTRY(fast_coprocessor)
1907#endif /* XCHAL_EXTRA_SA_SIZE */ 1906#endif /* XCHAL_EXTRA_SA_SIZE */
1908 1907
1909/* 1908/*
1909 * System Calls.
1910 *
1911 * void system_call (struct pt_regs* regs, int exccause)
1912 * a2 a3
1913 */
1914
1915ENTRY(system_call)
1916 entry a1, 32
1917
1918 /* regs->syscall = regs->areg[2] */
1919
1920 l32i a3, a2, PT_AREG2
1921 mov a6, a2
1922 movi a4, do_syscall_trace_enter
1923 s32i a3, a2, PT_SYSCALL
1924 callx4 a4
1925
1926 /* syscall = sys_call_table[syscall_nr] */
1927
1928 movi a4, sys_call_table;
1929 movi a5, __NR_syscall_count
1930 movi a6, -ENOSYS
1931 bgeu a3, a5, 1f
1932
1933 addx4 a4, a3, a4
1934 l32i a4, a4, 0
1935 movi a5, sys_ni_syscall;
1936 beq a4, a5, 1f
1937
1938 /* Load args: arg0 - arg5 are passed via regs. */
1939
1940 l32i a6, a2, PT_AREG6
1941 l32i a7, a2, PT_AREG3
1942 l32i a8, a2, PT_AREG4
1943 l32i a9, a2, PT_AREG5
1944 l32i a10, a2, PT_AREG8
1945 l32i a11, a2, PT_AREG9
1946
1947 /* Pass one additional argument to the syscall: pt_regs (on stack) */
1948 s32i a2, a1, 0
1949
1950 callx4 a4
1951
19521: /* regs->areg[2] = return_value */
1953
1954 s32i a6, a2, PT_AREG2
1955 movi a4, do_syscall_trace_leave
1956 mov a6, a2
1957 callx4 a4
1958 retw
1959
1960
1961/*
1962 * Create a kernel thread
1963 *
1964 * int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
1965 * a2 a2 a3 a4
1966 */
1967
1968ENTRY(kernel_thread)
1969 entry a1, 16
1970
1971 mov a5, a2 # preserve fn over syscall
1972 mov a7, a3 # preserve args over syscall
1973
1974 movi a3, _CLONE_VM | _CLONE_UNTRACED
1975 movi a2, __NR_clone
1976 or a6, a4, a3 # arg0: flags
1977 mov a3, a1 # arg1: sp
1978 syscall
1979
1980 beq a3, a1, 1f # branch if parent
1981 mov a6, a7 # args
1982 callx4 a5 # fn(args)
1983
1984 movi a2, __NR_exit
1985 syscall # return value of fn(args) still in a6
1986
19871: retw
1988
1989/*
1990 * Do a system call from kernel instead of calling sys_execve, so we end up
1991 * with proper pt_regs.
1992 *
1993 * int kernel_execve(const char *fname, char *const argv[], charg *const envp[])
1994 * a2 a2 a3 a4
1995 */
1996
1997ENTRY(kernel_execve)
1998 entry a1, 16
1999 mov a6, a2 # arg0 is in a6
2000 movi a2, __NR_execve
2001 syscall
2002
2003 retw
2004
2005/*
1910 * Task switch. 2006 * Task switch.
1911 * 2007 *
1912 * struct task* _switch_to (struct task* prev, struct task* next) 2008 * struct task* _switch_to (struct task* prev, struct task* next)
@@ -1964,33 +2060,9 @@ ENTRY(ret_from_fork)
1964 movi a4, schedule_tail 2060 movi a4, schedule_tail
1965 callx4 a4 2061 callx4 a4
1966 2062
1967 movi a4, do_syscall_trace 2063 movi a4, do_syscall_trace_leave
2064 mov a6, a1
1968 callx4 a4 2065 callx4 a4
1969 2066
1970 j common_exception_return 2067 j common_exception_return
1971 2068
1972
1973
1974/*
1975 * Table of syscalls
1976 */
1977
1978.data
1979.align 4
1980.global sys_call_table
1981sys_call_table:
1982
1983#define SYSCALL(call, narg) .word call
1984#include "syscalls.h"
1985
1986/*
1987 * Number of arguments of each syscall
1988 */
1989
1990.global sys_narg_table
1991sys_narg_table:
1992
1993#undef SYSCALL
1994#define SYSCALL(call, narg) .byte narg
1995#include "syscalls.h"
1996