1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. |
3 | |
4 | #include <linux/linkage.h> |
5 | #include <abi/entry.h> |
6 | #include <abi/pgtable-bits.h> |
7 | #include <asm/errno.h> |
8 | #include <asm/setup.h> |
9 | #include <asm/unistd.h> |
10 | #include <asm/asm-offsets.h> |
11 | #include <linux/threads.h> |
12 | #include <asm/page.h> |
13 | #include <asm/thread_info.h> |
14 | |
15 | .macro zero_fp |
16 | #ifdef CONFIG_STACKTRACE |
17 | movi r8, 0 |
18 | #endif |
19 | .endm |
20 | |
21 | .macro context_tracking |
22 | #ifdef CONFIG_CONTEXT_TRACKING_USER |
23 | mfcr a0, epsr |
24 | btsti a0, 31 |
25 | bt 1f |
26 | jbsr user_exit_callable |
27 | ldw a0, (sp, LSAVE_A0) |
28 | ldw a1, (sp, LSAVE_A1) |
29 | ldw a2, (sp, LSAVE_A2) |
30 | ldw a3, (sp, LSAVE_A3) |
31 | #if defined(__CSKYABIV1__) |
32 | ldw r6, (sp, LSAVE_A4) |
33 | ldw r7, (sp, LSAVE_A5) |
34 | #endif |
35 | 1: |
36 | #endif |
37 | .endm |
38 | |
39 | .text |
40 | ENTRY(csky_pagefault) |
41 | SAVE_ALL 0 |
42 | zero_fp |
43 | context_tracking |
44 | psrset ee |
45 | mov a0, sp |
46 | jbsr do_page_fault |
47 | jmpi ret_from_exception |
48 | |
49 | ENTRY(csky_systemcall) |
50 | SAVE_ALL TRAP0_SIZE |
51 | zero_fp |
52 | context_tracking |
53 | psrset ee, ie |
54 | |
55 | lrw r9, __NR_syscalls |
56 | cmphs syscallid, r9 /* Check nr of syscall */ |
57 | bt ret_from_exception |
58 | |
59 | lrw r9, sys_call_table |
60 | ixw r9, syscallid |
61 | ldw syscallid, (r9) |
62 | cmpnei syscallid, 0 |
63 | bf ret_from_exception |
64 | |
65 | mov r9, sp |
66 | bmaski r10, THREAD_SHIFT |
67 | andn r9, r10 |
68 | ldw r10, (r9, TINFO_FLAGS) |
69 | lrw r9, _TIF_SYSCALL_WORK |
70 | and r10, r9 |
71 | cmpnei r10, 0 |
72 | bt csky_syscall_trace |
73 | #if defined(__CSKYABIV2__) |
74 | subi sp, 8 |
75 | stw r5, (sp, 0x4) |
76 | stw r4, (sp, 0x0) |
77 | jsr syscallid /* Do system call */ |
78 | addi sp, 8 |
79 | #else |
80 | jsr syscallid |
81 | #endif |
82 | stw a0, (sp, LSAVE_A0) /* Save return value */ |
83 | jmpi ret_from_exception |
84 | |
85 | csky_syscall_trace: |
86 | mov a0, sp /* sp = pt_regs pointer */ |
87 | jbsr syscall_trace_enter |
88 | cmpnei a0, 0 |
89 | bt 1f |
90 | /* Prepare args before do system call */ |
91 | ldw a0, (sp, LSAVE_A0) |
92 | ldw a1, (sp, LSAVE_A1) |
93 | ldw a2, (sp, LSAVE_A2) |
94 | ldw a3, (sp, LSAVE_A3) |
95 | #if defined(__CSKYABIV2__) |
96 | subi sp, 8 |
97 | ldw r9, (sp, LSAVE_A4) |
98 | stw r9, (sp, 0x0) |
99 | ldw r9, (sp, LSAVE_A5) |
100 | stw r9, (sp, 0x4) |
101 | jsr syscallid /* Do system call */ |
102 | addi sp, 8 |
103 | #else |
104 | ldw r6, (sp, LSAVE_A4) |
105 | ldw r7, (sp, LSAVE_A5) |
106 | jsr syscallid /* Do system call */ |
107 | #endif |
108 | stw a0, (sp, LSAVE_A0) /* Save return value */ |
109 | |
110 | 1: |
111 | mov a0, sp /* right now, sp --> pt_regs */ |
112 | jbsr syscall_trace_exit |
113 | br ret_from_exception |
114 | |
115 | ENTRY(ret_from_kernel_thread) |
116 | jbsr schedule_tail |
117 | mov a0, r10 |
118 | jsr r9 |
119 | jbsr ret_from_exception |
120 | |
121 | ENTRY(ret_from_fork) |
122 | jbsr schedule_tail |
123 | mov r9, sp |
124 | bmaski r10, THREAD_SHIFT |
125 | andn r9, r10 |
126 | ldw r10, (r9, TINFO_FLAGS) |
127 | lrw r9, _TIF_SYSCALL_WORK |
128 | and r10, r9 |
129 | cmpnei r10, 0 |
130 | bf ret_from_exception |
131 | mov a0, sp /* sp = pt_regs pointer */ |
132 | jbsr syscall_trace_exit |
133 | |
134 | ret_from_exception: |
135 | psrclr ie |
136 | ld r9, (sp, LSAVE_PSR) |
137 | btsti r9, 31 |
138 | |
139 | bt 1f |
140 | /* |
141 | * Load address of current->thread_info, Then get address of task_struct |
142 | * Get task_needreshed in task_struct |
143 | */ |
144 | mov r9, sp |
145 | bmaski r10, THREAD_SHIFT |
146 | andn r9, r10 |
147 | |
148 | ldw r10, (r9, TINFO_FLAGS) |
149 | lrw r9, _TIF_WORK_MASK |
150 | and r10, r9 |
151 | cmpnei r10, 0 |
152 | bt exit_work |
153 | #ifdef CONFIG_CONTEXT_TRACKING_USER |
154 | jbsr user_enter_callable |
155 | #endif |
156 | 1: |
157 | #ifdef CONFIG_PREEMPTION |
158 | mov r9, sp |
159 | bmaski r10, THREAD_SHIFT |
160 | andn r9, r10 |
161 | |
162 | ldw r10, (r9, TINFO_PREEMPT) |
163 | cmpnei r10, 0 |
164 | bt 2f |
165 | jbsr preempt_schedule_irq /* irq en/disable is done inside */ |
166 | 2: |
167 | #endif |
168 | |
169 | #ifdef CONFIG_TRACE_IRQFLAGS |
170 | ld r10, (sp, LSAVE_PSR) |
171 | btsti r10, 6 |
172 | bf 2f |
173 | jbsr trace_hardirqs_on |
174 | 2: |
175 | #endif |
176 | RESTORE_ALL |
177 | |
178 | exit_work: |
179 | lrw r9, ret_from_exception |
180 | mov lr, r9 |
181 | |
182 | btsti r10, TIF_NEED_RESCHED |
183 | bt work_resched |
184 | |
185 | psrset ie |
186 | mov a0, sp |
187 | mov a1, r10 |
188 | jmpi do_notify_resume |
189 | |
190 | work_resched: |
191 | jmpi schedule |
192 | |
193 | ENTRY(csky_trap) |
194 | SAVE_ALL 0 |
195 | zero_fp |
196 | context_tracking |
197 | psrset ee |
198 | mov a0, sp /* Push Stack pointer arg */ |
199 | jbsr trap_c /* Call C-level trap handler */ |
200 | jmpi ret_from_exception |
201 | |
202 | /* |
203 | * Prototype from libc for abiv1: |
204 | * register unsigned int __result asm("a0"); |
205 | * asm( "trap 3" :"=r"(__result)::); |
206 | */ |
207 | ENTRY(csky_get_tls) |
208 | USPTOKSP |
209 | |
210 | RD_MEH a0 |
211 | WR_MEH a0 |
212 | |
213 | /* increase epc for continue */ |
214 | mfcr a0, epc |
215 | addi a0, TRAP0_SIZE |
216 | mtcr a0, epc |
217 | |
218 | /* get current task thread_info with kernel 8K stack */ |
219 | bmaski a0, THREAD_SHIFT |
220 | not a0 |
221 | subi sp, 1 |
222 | and a0, sp |
223 | addi sp, 1 |
224 | |
225 | /* get tls */ |
226 | ldw a0, (a0, TINFO_TP_VALUE) |
227 | |
228 | KSPTOUSP |
229 | rte |
230 | |
231 | ENTRY(csky_irq) |
232 | SAVE_ALL 0 |
233 | zero_fp |
234 | context_tracking |
235 | psrset ee |
236 | |
237 | #ifdef CONFIG_TRACE_IRQFLAGS |
238 | jbsr trace_hardirqs_off |
239 | #endif |
240 | |
241 | |
242 | mov a0, sp |
243 | jbsr generic_handle_arch_irq |
244 | |
245 | jmpi ret_from_exception |
246 | |
247 | /* |
248 | * a0 = prev task_struct * |
249 | * a1 = next task_struct * |
250 | * a0 = return next |
251 | */ |
252 | ENTRY(__switch_to) |
253 | lrw a3, TASK_THREAD |
254 | addu a3, a0 |
255 | |
256 | SAVE_SWITCH_STACK |
257 | |
258 | stw sp, (a3, THREAD_KSP) |
259 | |
260 | /* Set up next process to run */ |
261 | lrw a3, TASK_THREAD |
262 | addu a3, a1 |
263 | |
264 | ldw sp, (a3, THREAD_KSP) /* Set next kernel sp */ |
265 | |
266 | #if defined(__CSKYABIV2__) |
267 | addi a3, a1, TASK_THREAD_INFO |
268 | ldw tls, (a3, TINFO_TP_VALUE) |
269 | #endif |
270 | |
271 | RESTORE_SWITCH_STACK |
272 | |
273 | rts |
274 | ENDPROC(__switch_to) |
275 | |