Setting up repository
[linux-libre-firmware.git] / ath9k_htc / sboot / magpie_1_1 / sboot / athos / src / xtos / exc-syscall-handler.S
1 /* exc-syscall-handler.S - XTOS syscall instruction handler */
2
3 /*
4  * Copyright (c) 1999-2010 Tensilica Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 /*
27  * The SYSCALL instruction is typically used to implement system calls.
28  * By convention, register a2 identifies the requested system call.
29  * Typically, other parameters are passed in registers a3 and up,
30  * and results are returned in a2.
31  *
32  * The Xtensa windowed ABI reserves the value zero of register a2
33  * as a request to force register windows to the stack.  The call0 ABI,
34  * which has no equivalent operation, reserves this value as a no-op.
35  *
36  * Generally, only code that traverses the stack in unusual ways needs
37  * to force (spill) register windows to the stack.  In generic C or C++,
38  * there are four cases, and they all use the standard SYSCALL mechanism:
39  *
40  * 1. C++ exceptions
41  * 2. setjmp and longjmp
42  * 3. functions using the GNU extension "__builtin_return_address"
43  * 4. functions using the GNU extension "nonlocal goto"
44  *
45  * NOTE:  Specific operating systems often need to spill register windows
46  * to the stack in other situations such as context-switching, passing
47  * Unix-like signals to threads, displaying stack tracebacks, etc.
48  * They may choose to use the SYSCALL mechanism to do so, or use other
49  * means such as calling xthal_window_spill() or other methods.
50  *
51  * If you want to handle other system calls, you can modify this file, or
52  * use the C version of it in exc-syscall-handler.c .  The Xtensa ABIs only
53  * define system call zero; the behavior of other system calls is up to you.
54  */
55
56 #include <xtensa/coreasm.h>
57 #include "xtos-internal.h"
58
59
60 #if XCHAL_HAVE_EXCEPTIONS
61
62 //Vector:
63 //      addi    a1, a1, -ESF_TOTALSIZE  // allocate exception stack frame, etc.
64 //      s32i    a2, a1, UEXC_a2
65 //      s32i    a3, a1, UEXC_a3
66 //      movi    a3, _xtos_exc_handler_table
67 //      rsr     a2, EXCCAUSE
68 //      addx4   a2, a2, a3
69 //      l32i    a2, a2, 0
70 //      s32i    a4, a1, UEXC_a4
71 //      jx      a2              // jump to cause-specific handler
72
73         .global _need_user_vector_      // pull-in real user vector (tiny LSP)
74
75
76         /*
77          *  The SYSCALL handler is entered when the processor
78          *  executes the SYSCALL instruction.
79          *  By convention, the system call to execute is specified in a2.
80          */
81         .text
82         .align  4
83         .global _xtos_syscall_handler
84 _xtos_syscall_handler:
85         //  HERE:  a2, a3, a4 have been saved to the exception stack frame allocated with a1 (sp).
86         //  We ignore that a4 was saved, we don't clobber it.
87
88         rsr     a3, EPC_1
89 #if XCHAL_HAVE_LOOPS
90         // If the SYSCALL instruction was the last instruction in the body of
91         // a zero-overhead loop, and the loop will execute again, decrement
92         // the loop count and resume execution at the head of the loop:
93         //
94         rsr     a2, LEND
95         addi    a3, a3, 3       // increment EPC to skip the SYSCALL instruction
96         bne     a2, a3, 1f
97         rsr     a2, LCOUNT
98         beqz    a2, 1f
99         addi    a2, a2, -1
100         wsr     a2, LCOUNT
101         rsr     a3, LBEG
102 1:      l32i    a2, a1, UEXC_a2 // get the system call number
103 #else
104         //  No loop registers.
105         l32i    a2, a1, UEXC_a2 // get the system call number
106         addi    a3, a3, 3       // increment EPC to skip the SYSCALL instruction
107 #endif
108         wsr     a3, EPC_1       // update EPC1 past SYSCALL
109         l32i    a3, a1, UEXC_a3 // restore a3
110         //  If you want to handle other system calls, check a2 here.
111
112 #ifdef __XTENSA_WINDOWED_ABI__
113         bnez    a2, .Lnotzero   // is syscall number zero?
114
115         /*  Spill register windows to the stack.  */
116
117         // Save a2 thru a5 in the nested-C-function area, where an interrupt
118         // won't clobber them.  The pseudo-CALL's ENTRY below clobbers a4 and a5.
119         //s32i  a2, a1, (ESF_TOTALSIZE - 32) + 0        // a2 is zero, no need to save
120         s32i    a3, a1, (ESF_TOTALSIZE - 32) + 4
121         s32i    a4, a1, (ESF_TOTALSIZE - 32) + 8
122         s32i    a5, a1, (ESF_TOTALSIZE - 32) + 12
123
124         movi    a3, PS_WOE|PS_CALLINC(1)|PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL)  // CALL4 emulation
125         rsr     a2, PS                  // save PS in a2
126         wsr     a3, PS                  // PS.INTLEVEL=EXCMLEVEL (1 for XEA1)
127         //  HERE:  window overflows enabled but NOT SAFE yet, touch only a0..a3 until it's safe.
128         rsr     a3, EPC_1               // save EPC1 in a3
129         addi    a1, a1, ESF_TOTALSIZE   // restore sp (dealloc ESF) for sane stack again
130         rsync                           // wait for WSR to PS to complete
131         //  HERE:  Window overflows and interrupts are safe, we saved EPC1 and
132         //  restored a1, and a4-a15 are unmodified.
133         //  Pseudo-CALL:  make it look as if the code that executed SYSCALL
134         //  made a CALL4 to here.  See user exc. handler comments for details.
135         //  ENTRY cannot cause window overflow; touch a4 to ensure a4-a7
136         //  overflow if needed:
137         movi    a4, 0                   // clears pseudo-CALL's return PC
138         //  NOTE:  On XEA1 processors, return from window overflow re-enables
139         //  interrupts (by clearing PS.INTLEVEL).  This is okay even though SP
140         //  is unallocated because we saved state safe from interrupt dispatch.
141         .global _SyscallException
142 _SyscallException:                      // label makes tracebacks look nicer
143         _entry  a1, 64                  // as if after a CALL4 (PS.CALLINC==1)
144         //  Call deep enough to force spill of entire address register file.
145         _call12 .Ldeep
146 1:      movi    a14, 0x80000000 + .Ldelta_done
147         add     a0, a12, a14            // clear a0 msbit (per CALL4), offset
148 3:      retw                            // return from pseudo-CALL4
149
150         //  NOTE:  a5 still contains the exception window's exception stack frame pointer.
151 .LMdon: wsr     a2, PS          // for XEA2, this sets EXCM; for XEA1, this sets INTLEVEL to 1; ...
152         movi    a2, 0           // indicate successful SYSCALL (?)
153         l32i    a4, a5, 32 + 8
154         rsync                   // complete WSR to PS for safe write to EPC1
155         wsr     a3, EPC_1
156         l32i    a3, a5, 32 + 4
157         l32i    a5, a5, 32 + 12
158         rfe_rfue
159
160         .set    .Ldelta_retw, (3b - 1b)
161         .set    .Ldelta_done, (.LMdon - 1b)
162
163         .align  4
164 .Ldeep: entry   a1, 48
165 #if XCHAL_NUM_AREGS < 64
166         mov     a15, a15                // touch just far enough to overflow 32
167 #else
168         movi    a12, .Ldelta_retw       // use movi/add because of relocation
169         add     a12, a0, a12            // set return PC as per CALL12
170         _entry  a1, 48                  // last call was call12 so PS.CALLINC==3
171         mov     a12, a0                 // set return PC
172         _entry  a1, 48
173         mov     a12, a0                 // set return PC
174         _entry  a1, 16
175         mov     a11, a11                // touch just far enough to overflow 64
176 #endif
177         retw
178
179 #endif /* __XTENSA_WINDOWED_ABI__ */
180
181 .Lnotzero:
182         movi    a2, -1 /*ENOSYS*/       // system call not supported
183         addi    a1, a1, ESF_TOTALSIZE
184         rfe_rfue
185
186         .size   _xtos_syscall_handler, . - _xtos_syscall_handler
187
188
189 #endif /* XCHAL_HAVE_EXCEPTIONS */
190