]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * arch/v850/kernel/entry.S -- Low-level system-call handling, trap handlers, | |
3 | * and context-switching | |
4 | * | |
5 | * Copyright (C) 2001,02,03 NEC Electronics Corporation | |
6 | * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> | |
7 | * | |
8 | * This file is subject to the terms and conditions of the GNU General | |
9 | * Public License. See the file COPYING in the main directory of this | |
10 | * archive for more details. | |
11 | * | |
12 | * Written by Miles Bader <miles@gnu.org> | |
13 | */ | |
14 | ||
15 | #include <linux/sys.h> | |
16 | ||
17 | #include <asm/entry.h> | |
18 | #include <asm/current.h> | |
19 | #include <asm/thread_info.h> | |
20 | #include <asm/clinkage.h> | |
21 | #include <asm/processor.h> | |
22 | #include <asm/irq.h> | |
23 | #include <asm/errno.h> | |
24 | ||
fb61a861 | 25 | #include <asm/asm-offsets.h> |
1da177e4 LT |
26 | |
27 | ||
28 | /* Make a slightly more convenient alias for C_SYMBOL_NAME. */ | |
29 | #define CSYM C_SYMBOL_NAME | |
30 | ||
31 | ||
32 | /* The offset of the struct pt_regs in a state-save-frame on the stack. */ | |
33 | #define PTO STATE_SAVE_PT_OFFSET | |
34 | ||
35 | ||
36 | /* Save argument registers to the state-save-frame pointed to by EP. */ | |
37 | #define SAVE_ARG_REGS \ | |
38 | sst.w r6, PTO+PT_GPR(6)[ep]; \ | |
39 | sst.w r7, PTO+PT_GPR(7)[ep]; \ | |
40 | sst.w r8, PTO+PT_GPR(8)[ep]; \ | |
41 | sst.w r9, PTO+PT_GPR(9)[ep] | |
42 | /* Restore argument registers from the state-save-frame pointed to by EP. */ | |
43 | #define RESTORE_ARG_REGS \ | |
44 | sld.w PTO+PT_GPR(6)[ep], r6; \ | |
45 | sld.w PTO+PT_GPR(7)[ep], r7; \ | |
46 | sld.w PTO+PT_GPR(8)[ep], r8; \ | |
47 | sld.w PTO+PT_GPR(9)[ep], r9 | |
48 | ||
49 | /* Save value return registers to the state-save-frame pointed to by EP. */ | |
50 | #define SAVE_RVAL_REGS \ | |
51 | sst.w r10, PTO+PT_GPR(10)[ep]; \ | |
52 | sst.w r11, PTO+PT_GPR(11)[ep] | |
53 | /* Restore value return registers from the state-save-frame pointed to by EP. */ | |
54 | #define RESTORE_RVAL_REGS \ | |
55 | sld.w PTO+PT_GPR(10)[ep], r10; \ | |
56 | sld.w PTO+PT_GPR(11)[ep], r11 | |
57 | ||
58 | ||
59 | #define SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS \ | |
60 | sst.w r1, PTO+PT_GPR(1)[ep]; \ | |
61 | sst.w r5, PTO+PT_GPR(5)[ep] | |
62 | #define SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL \ | |
63 | sst.w r12, PTO+PT_GPR(12)[ep]; \ | |
64 | sst.w r13, PTO+PT_GPR(13)[ep]; \ | |
65 | sst.w r14, PTO+PT_GPR(14)[ep]; \ | |
66 | sst.w r15, PTO+PT_GPR(15)[ep]; \ | |
67 | sst.w r16, PTO+PT_GPR(16)[ep]; \ | |
68 | sst.w r17, PTO+PT_GPR(17)[ep]; \ | |
69 | sst.w r18, PTO+PT_GPR(18)[ep]; \ | |
70 | sst.w r19, PTO+PT_GPR(19)[ep] | |
71 | #define RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS \ | |
72 | sld.w PTO+PT_GPR(1)[ep], r1; \ | |
73 | sld.w PTO+PT_GPR(5)[ep], r5 | |
74 | #define RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL \ | |
75 | sld.w PTO+PT_GPR(12)[ep], r12; \ | |
76 | sld.w PTO+PT_GPR(13)[ep], r13; \ | |
77 | sld.w PTO+PT_GPR(14)[ep], r14; \ | |
78 | sld.w PTO+PT_GPR(15)[ep], r15; \ | |
79 | sld.w PTO+PT_GPR(16)[ep], r16; \ | |
80 | sld.w PTO+PT_GPR(17)[ep], r17; \ | |
81 | sld.w PTO+PT_GPR(18)[ep], r18; \ | |
82 | sld.w PTO+PT_GPR(19)[ep], r19 | |
83 | ||
84 | /* Save `call clobbered' registers to the state-save-frame pointed to by EP. */ | |
85 | #define SAVE_CALL_CLOBBERED_REGS \ | |
86 | SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ | |
87 | SAVE_ARG_REGS; \ | |
88 | SAVE_RVAL_REGS; \ | |
89 | SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL | |
90 | /* Restore `call clobbered' registers from the state-save-frame pointed to | |
91 | by EP. */ | |
92 | #define RESTORE_CALL_CLOBBERED_REGS \ | |
93 | RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ | |
94 | RESTORE_ARG_REGS; \ | |
95 | RESTORE_RVAL_REGS; \ | |
96 | RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL | |
97 | ||
98 | /* Save `call clobbered' registers except for the return-value registers | |
99 | to the state-save-frame pointed to by EP. */ | |
100 | #define SAVE_CALL_CLOBBERED_REGS_NO_RVAL \ | |
101 | SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ | |
102 | SAVE_ARG_REGS; \ | |
103 | SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL | |
104 | /* Restore `call clobbered' registers except for the return-value registers | |
105 | from the state-save-frame pointed to by EP. */ | |
106 | #define RESTORE_CALL_CLOBBERED_REGS_NO_RVAL \ | |
107 | RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ | |
108 | RESTORE_ARG_REGS; \ | |
109 | RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL | |
110 | ||
111 | /* Save `call saved' registers to the state-save-frame pointed to by EP. */ | |
112 | #define SAVE_CALL_SAVED_REGS \ | |
113 | sst.w r2, PTO+PT_GPR(2)[ep]; \ | |
114 | sst.w r20, PTO+PT_GPR(20)[ep]; \ | |
115 | sst.w r21, PTO+PT_GPR(21)[ep]; \ | |
116 | sst.w r22, PTO+PT_GPR(22)[ep]; \ | |
117 | sst.w r23, PTO+PT_GPR(23)[ep]; \ | |
118 | sst.w r24, PTO+PT_GPR(24)[ep]; \ | |
119 | sst.w r25, PTO+PT_GPR(25)[ep]; \ | |
120 | sst.w r26, PTO+PT_GPR(26)[ep]; \ | |
121 | sst.w r27, PTO+PT_GPR(27)[ep]; \ | |
122 | sst.w r28, PTO+PT_GPR(28)[ep]; \ | |
123 | sst.w r29, PTO+PT_GPR(29)[ep] | |
124 | /* Restore `call saved' registers from the state-save-frame pointed to by EP. */ | |
125 | #define RESTORE_CALL_SAVED_REGS \ | |
126 | sld.w PTO+PT_GPR(2)[ep], r2; \ | |
127 | sld.w PTO+PT_GPR(20)[ep], r20; \ | |
128 | sld.w PTO+PT_GPR(21)[ep], r21; \ | |
129 | sld.w PTO+PT_GPR(22)[ep], r22; \ | |
130 | sld.w PTO+PT_GPR(23)[ep], r23; \ | |
131 | sld.w PTO+PT_GPR(24)[ep], r24; \ | |
132 | sld.w PTO+PT_GPR(25)[ep], r25; \ | |
133 | sld.w PTO+PT_GPR(26)[ep], r26; \ | |
134 | sld.w PTO+PT_GPR(27)[ep], r27; \ | |
135 | sld.w PTO+PT_GPR(28)[ep], r28; \ | |
136 | sld.w PTO+PT_GPR(29)[ep], r29 | |
137 | ||
138 | ||
139 | /* Save the PC stored in the special register SAVEREG to the state-save-frame | |
140 | pointed to by EP. r19 is clobbered. */ | |
141 | #define SAVE_PC(savereg) \ | |
142 | stsr SR_ ## savereg, r19; \ | |
143 | sst.w r19, PTO+PT_PC[ep] | |
144 | /* Restore the PC from the state-save-frame pointed to by EP, to the special | |
145 | register SAVEREG. LP is clobbered (it is used as a scratch register | |
146 | because the POP_STATE macro restores it, and this macro is usually used | |
147 | inside POP_STATE). */ | |
148 | #define RESTORE_PC(savereg) \ | |
149 | sld.w PTO+PT_PC[ep], lp; \ | |
150 | ldsr lp, SR_ ## savereg | |
151 | /* Save the PSW register stored in the special register SAVREG to the | |
152 | state-save-frame pointed to by EP. r19 is clobbered. */ | |
153 | #define SAVE_PSW(savereg) \ | |
154 | stsr SR_ ## savereg, r19; \ | |
155 | sst.w r19, PTO+PT_PSW[ep] | |
156 | /* Restore the PSW register from the state-save-frame pointed to by EP, to | |
157 | the special register SAVEREG. LP is clobbered (it is used as a scratch | |
158 | register because the POP_STATE macro restores it, and this macro is | |
159 | usually used inside POP_STATE). */ | |
160 | #define RESTORE_PSW(savereg) \ | |
161 | sld.w PTO+PT_PSW[ep], lp; \ | |
162 | ldsr lp, SR_ ## savereg | |
163 | ||
164 | /* Save CTPC/CTPSW/CTBP registers to the state-save-frame pointed to by REG. | |
165 | r19 is clobbered. */ | |
166 | #define SAVE_CT_REGS \ | |
167 | stsr SR_CTPC, r19; \ | |
168 | sst.w r19, PTO+PT_CTPC[ep]; \ | |
169 | stsr SR_CTPSW, r19; \ | |
170 | sst.w r19, PTO+PT_CTPSW[ep]; \ | |
171 | stsr SR_CTBP, r19; \ | |
172 | sst.w r19, PTO+PT_CTBP[ep] | |
173 | /* Restore CTPC/CTPSW/CTBP registers from the state-save-frame pointed to by EP. | |
174 | LP is clobbered (it is used as a scratch register because the POP_STATE | |
175 | macro restores it, and this macro is usually used inside POP_STATE). */ | |
176 | #define RESTORE_CT_REGS \ | |
177 | sld.w PTO+PT_CTPC[ep], lp; \ | |
178 | ldsr lp, SR_CTPC; \ | |
179 | sld.w PTO+PT_CTPSW[ep], lp; \ | |
180 | ldsr lp, SR_CTPSW; \ | |
181 | sld.w PTO+PT_CTBP[ep], lp; \ | |
182 | ldsr lp, SR_CTBP | |
183 | ||
184 | ||
185 | /* Push register state, except for the stack pointer, on the stack in the | |
186 | form of a state-save-frame (plus some extra padding), in preparation for | |
187 | a system call. This macro makes sure that the EP, GP, and LP | |
188 | registers are saved, and TYPE identifies the set of extra registers to | |
189 | be saved as well. Also copies (the new value of) SP to EP. */ | |
190 | #define PUSH_STATE(type) \ | |
191 | addi -STATE_SAVE_SIZE, sp, sp; /* Make room on the stack. */ \ | |
192 | st.w ep, PTO+PT_GPR(GPR_EP)[sp]; \ | |
193 | mov sp, ep; \ | |
194 | sst.w gp, PTO+PT_GPR(GPR_GP)[ep]; \ | |
195 | sst.w lp, PTO+PT_GPR(GPR_LP)[ep]; \ | |
196 | type ## _STATE_SAVER | |
197 | /* Pop a register state pushed by PUSH_STATE, except for the stack pointer, | |
4b3f686d | 198 | from the stack. */ |
1da177e4 LT |
199 | #define POP_STATE(type) \ |
200 | mov sp, ep; \ | |
201 | type ## _STATE_RESTORER; \ | |
202 | sld.w PTO+PT_GPR(GPR_GP)[ep], gp; \ | |
203 | sld.w PTO+PT_GPR(GPR_LP)[ep], lp; \ | |
204 | sld.w PTO+PT_GPR(GPR_EP)[ep], ep; \ | |
205 | addi STATE_SAVE_SIZE, sp, sp /* Clean up our stack space. */ | |
206 | ||
207 | ||
208 | /* Switch to the kernel stack if necessary, and push register state on the | |
209 | stack in the form of a state-save-frame. Also load the current task | |
210 | pointer if switching from user mode. The stack-pointer (r3) should have | |
211 | already been saved to the memory location SP_SAVE_LOC (the reason for | |
212 | this is that the interrupt vectors may be beyond a 22-bit signed offset | |
213 | jump from the actual interrupt handler, and this allows them to save the | |
214 | stack-pointer and use that register to do an indirect jump). This macro | |
215 | makes sure that `special' registers, system registers, and the stack | |
216 | pointer are saved; TYPE identifies the set of extra registers to be | |
217 | saved as well. SYSCALL_NUM is the register in which the system-call | |
218 | number this state is for is stored (r0 if this isn't a system call). | |
219 | Interrupts should already be disabled when calling this. */ | |
220 | #define SAVE_STATE(type, syscall_num, sp_save_loc) \ | |
221 | tst1 0, KM; /* See if already in kernel mode. */ \ | |
222 | bz 1f; \ | |
223 | ld.w sp_save_loc, sp; /* ... yes, use saved SP. */ \ | |
224 | br 2f; \ | |
225 | 1: ld.w KSP, sp; /* ... no, switch to kernel stack. */ \ | |
226 | 2: PUSH_STATE(type); \ | |
227 | ld.b KM, r19; /* Remember old kernel-mode. */ \ | |
228 | sst.w r19, PTO+PT_KERNEL_MODE[ep]; \ | |
229 | ld.w sp_save_loc, r19; /* Remember old SP. */ \ | |
230 | sst.w r19, PTO+PT_GPR(GPR_SP)[ep]; \ | |
231 | mov 1, r19; /* Now definitely in kernel-mode. */ \ | |
232 | st.b r19, KM; \ | |
233 | GET_CURRENT_TASK(CURRENT_TASK); /* Fetch the current task pointer. */ \ | |
234 | /* Save away the syscall number. */ \ | |
235 | sst.w syscall_num, PTO+PT_CUR_SYSCALL[ep] | |
236 | ||
237 | ||
238 | /* Save register state not normally saved by PUSH_STATE for TYPE, to the | |
239 | state-save-frame on the stack; also copies SP to EP. r19 may be trashed. */ | |
240 | #define SAVE_EXTRA_STATE(type) \ | |
241 | mov sp, ep; \ | |
242 | type ## _EXTRA_STATE_SAVER | |
243 | /* Restore register state not normally restored by POP_STATE for TYPE, | |
244 | from the state-save-frame on the stack; also copies SP to EP. | |
245 | r19 may be trashed. */ | |
246 | #define RESTORE_EXTRA_STATE(type) \ | |
247 | mov sp, ep; \ | |
248 | type ## _EXTRA_STATE_RESTORER | |
249 | ||
250 | /* Save any call-clobbered registers not normally saved by PUSH_STATE for | |
251 | TYPE, to the state-save-frame on the stack. | |
252 | EP may be trashed, but is not guaranteed to contain a copy of SP | |
253 | (unlike after most SAVE_... macros). r19 may be trashed. */ | |
254 | #define SAVE_EXTRA_STATE_FOR_SCHEDULE(type) \ | |
255 | type ## _SCHEDULE_EXTRA_STATE_SAVER | |
256 | /* Restore any call-clobbered registers not normally restored by | |
257 | POP_STATE for TYPE, to the state-save-frame on the stack. | |
258 | EP may be trashed, but is not guaranteed to contain a copy of SP | |
259 | (unlike after most RESTORE_... macros). r19 may be trashed. */ | |
260 | #define RESTORE_EXTRA_STATE_FOR_SCHEDULE(type) \ | |
261 | type ## _SCHEDULE_EXTRA_STATE_RESTORER | |
262 | ||
263 | ||
264 | /* These are extra_state_saver/restorer values for a user trap. Note | |
265 | that we save the argument registers so that restarted syscalls will | |
266 | function properly (otherwise it wouldn't be necessary), and we must | |
267 | _not_ restore the return-value registers (so that traps can return a | |
268 | value!), but call-clobbered registers are not saved at all, as the | |
269 | caller of the syscall function should have saved them. */ | |
270 | ||
271 | #define TRAP_RET reti | |
272 | /* Traps don't save call-clobbered registers (but do still save arg regs). | |
273 | We preserve PSw to keep long-term state, namely interrupt status (for traps | |
274 | from kernel-mode), and the single-step flag (for user traps). */ | |
275 | #define TRAP_STATE_SAVER \ | |
276 | SAVE_ARG_REGS; \ | |
277 | SAVE_PC(EIPC); \ | |
278 | SAVE_PSW(EIPSW) | |
279 | /* When traps return, they just leave call-clobbered registers (except for arg | |
280 | regs) with whatever value they have from the kernel. Traps don't preserve | |
281 | the PSW, but we zero EIPSW to ensure it doesn't contain anything dangerous | |
282 | (in particular, the single-step flag). */ | |
283 | #define TRAP_STATE_RESTORER \ | |
284 | RESTORE_ARG_REGS; \ | |
285 | RESTORE_PC(EIPC); \ | |
286 | RESTORE_PSW(EIPSW) | |
287 | /* Save registers not normally saved by traps. We need to save r12, even | |
288 | though it's nominally call-clobbered, because it's used when restarting | |
289 | a system call (the signal-handling path uses SAVE_EXTRA_STATE, and | |
290 | expects r12 to be restored when the trap returns). */ | |
291 | #define TRAP_EXTRA_STATE_SAVER \ | |
292 | SAVE_RVAL_REGS; \ | |
293 | sst.w r12, PTO+PT_GPR(12)[ep]; \ | |
294 | SAVE_CALL_SAVED_REGS; \ | |
295 | SAVE_CT_REGS | |
296 | #define TRAP_EXTRA_STATE_RESTORER \ | |
297 | RESTORE_RVAL_REGS; \ | |
298 | sld.w PTO+PT_GPR(12)[ep], r12; \ | |
299 | RESTORE_CALL_SAVED_REGS; \ | |
300 | RESTORE_CT_REGS | |
301 | /* Save registers prior to calling scheduler (just before trap returns). | |
302 | We have to save the return-value registers to preserve the trap's return | |
303 | value. Note that ..._SCHEDULE_EXTRA_STATE_SAVER, unlike most ..._SAVER | |
304 | macros, is required to setup EP itself if EP is needed (this is because | |
305 | in many cases, the macro is empty). */ | |
306 | #define TRAP_SCHEDULE_EXTRA_STATE_SAVER \ | |
307 | mov sp, ep; \ | |
308 | SAVE_RVAL_REGS | |
309 | /* Note that ..._SCHEDULE_EXTRA_STATE_RESTORER, unlike most ..._RESTORER | |
310 | macros, is required to setup EP itself if EP is needed (this is because | |
311 | in many cases, the macro is empty). */ | |
312 | #define TRAP_SCHEDULE_EXTRA_STATE_RESTORER \ | |
313 | mov sp, ep; \ | |
314 | RESTORE_RVAL_REGS | |
315 | ||
316 | /* Register saving/restoring for maskable interrupts. */ | |
317 | #define IRQ_RET reti | |
318 | #define IRQ_STATE_SAVER \ | |
319 | SAVE_CALL_CLOBBERED_REGS; \ | |
320 | SAVE_PC(EIPC); \ | |
321 | SAVE_PSW(EIPSW) | |
322 | #define IRQ_STATE_RESTORER \ | |
323 | RESTORE_CALL_CLOBBERED_REGS; \ | |
324 | RESTORE_PC(EIPC); \ | |
325 | RESTORE_PSW(EIPSW) | |
326 | #define IRQ_EXTRA_STATE_SAVER \ | |
327 | SAVE_CALL_SAVED_REGS; \ | |
328 | SAVE_CT_REGS | |
329 | #define IRQ_EXTRA_STATE_RESTORER \ | |
330 | RESTORE_CALL_SAVED_REGS; \ | |
331 | RESTORE_CT_REGS | |
332 | #define IRQ_SCHEDULE_EXTRA_STATE_SAVER /* nothing */ | |
333 | #define IRQ_SCHEDULE_EXTRA_STATE_RESTORER /* nothing */ | |
334 | ||
335 | /* Register saving/restoring for non-maskable interrupts. */ | |
336 | #define NMI_RET reti | |
337 | #define NMI_STATE_SAVER \ | |
338 | SAVE_CALL_CLOBBERED_REGS; \ | |
339 | SAVE_PC(FEPC); \ | |
340 | SAVE_PSW(FEPSW); | |
341 | #define NMI_STATE_RESTORER \ | |
342 | RESTORE_CALL_CLOBBERED_REGS; \ | |
343 | RESTORE_PC(FEPC); \ | |
344 | RESTORE_PSW(FEPSW); | |
345 | #define NMI_EXTRA_STATE_SAVER \ | |
346 | SAVE_CALL_SAVED_REGS; \ | |
347 | SAVE_CT_REGS | |
348 | #define NMI_EXTRA_STATE_RESTORER \ | |
349 | RESTORE_CALL_SAVED_REGS; \ | |
350 | RESTORE_CT_REGS | |
351 | #define NMI_SCHEDULE_EXTRA_STATE_SAVER /* nothing */ | |
352 | #define NMI_SCHEDULE_EXTRA_STATE_RESTORER /* nothing */ | |
353 | ||
354 | /* Register saving/restoring for debug traps. */ | |
355 | #define DBTRAP_RET .long 0x014607E0 /* `dbret', but gas doesn't support it. */ | |
356 | #define DBTRAP_STATE_SAVER \ | |
357 | SAVE_CALL_CLOBBERED_REGS; \ | |
358 | SAVE_PC(DBPC); \ | |
359 | SAVE_PSW(DBPSW) | |
360 | #define DBTRAP_STATE_RESTORER \ | |
361 | RESTORE_CALL_CLOBBERED_REGS; \ | |
362 | RESTORE_PC(DBPC); \ | |
363 | RESTORE_PSW(DBPSW) | |
364 | #define DBTRAP_EXTRA_STATE_SAVER \ | |
365 | SAVE_CALL_SAVED_REGS; \ | |
366 | SAVE_CT_REGS | |
367 | #define DBTRAP_EXTRA_STATE_RESTORER \ | |
368 | RESTORE_CALL_SAVED_REGS; \ | |
369 | RESTORE_CT_REGS | |
370 | #define DBTRAP_SCHEDULE_EXTRA_STATE_SAVER /* nothing */ | |
371 | #define DBTRAP_SCHEDULE_EXTRA_STATE_RESTORER /* nothing */ | |
372 | ||
373 | /* Register saving/restoring for a context switch. We don't need to save | |
374 | too many registers, because context-switching looks like a function call | |
375 | (via the function `switch_thread'), so callers will save any | |
376 | call-clobbered registers themselves. We do need to save the CT regs, as | |
377 | they're normally not saved during kernel entry (the kernel doesn't use | |
378 | them). We save PSW so that interrupt-status state will correctly follow | |
379 | each thread (mostly NMI vs. normal-IRQ/trap), though for the most part | |
380 | it doesn't matter since threads are always in almost exactly the same | |
381 | processor state during a context switch. The stack pointer and return | |
382 | value are handled by switch_thread itself. */ | |
383 | #define SWITCH_STATE_SAVER \ | |
384 | SAVE_CALL_SAVED_REGS; \ | |
385 | SAVE_PSW(PSW); \ | |
386 | SAVE_CT_REGS | |
387 | #define SWITCH_STATE_RESTORER \ | |
388 | RESTORE_CALL_SAVED_REGS; \ | |
389 | RESTORE_PSW(PSW); \ | |
390 | RESTORE_CT_REGS | |
391 | ||
392 | ||
393 | /* Restore register state from the state-save-frame on the stack, switch back | |
394 | to the user stack if necessary, and return from the trap/interrupt. | |
395 | EXTRA_STATE_RESTORER is a sequence of assembly language statements to | |
396 | restore anything not restored by this macro. Only registers not saved by | |
397 | the C compiler are restored (that is, R3(sp), R4(gp), R31(lp), and | |
398 | anything restored by EXTRA_STATE_RESTORER). */ | |
399 | #define RETURN(type) \ | |
400 | ld.b PTO+PT_KERNEL_MODE[sp], r19; \ | |
401 | di; /* Disable interrupts */ \ | |
402 | cmp r19, r0; /* See if returning to kernel mode, */\ | |
403 | bne 2f; /* ... if so, skip resched &c. */ \ | |
404 | \ | |
405 | /* We're returning to user mode, so check for various conditions that \ | |
406 | trigger rescheduling. */ \ | |
407 | GET_CURRENT_THREAD(r18); \ | |
408 | ld.w TI_FLAGS[r18], r19; \ | |
409 | andi _TIF_NEED_RESCHED, r19, r0; \ | |
410 | bnz 3f; /* Call the scheduler. */ \ | |
411 | 5: andi _TIF_SIGPENDING, r19, r18; \ | |
412 | ld.w TASK_PTRACE[CURRENT_TASK], r19; /* ptrace flags */ \ | |
413 | or r18, r19; /* see if either is non-zero */ \ | |
414 | bnz 4f; /* if so, handle them */ \ | |
415 | \ | |
416 | /* Return to user state. */ \ | |
417 | 1: st.b r0, KM; /* Now officially in user state. */ \ | |
418 | \ | |
419 | /* Final return. The stack-pointer fiddling is not needed when returning \ | |
420 | to kernel-mode, but they don't hurt, and this way we can share the \ | |
421 | (sometimes rather lengthy) POP_STATE macro. */ \ | |
422 | 2: POP_STATE(type); \ | |
423 | st.w sp, KSP; /* Save the kernel stack pointer. */ \ | |
424 | ld.w PT_GPR(GPR_SP)-PT_SIZE[sp], sp; /* Restore stack pointer. */ \ | |
425 | type ## _RET; /* Return from the trap/interrupt. */ \ | |
426 | \ | |
427 | /* Call the scheduler before returning from a syscall/trap. */ \ | |
428 | 3: SAVE_EXTRA_STATE_FOR_SCHEDULE(type); /* Prepare to call scheduler. */ \ | |
429 | jarl call_scheduler, lp; /* Call scheduler */ \ | |
430 | di; /* The scheduler enables interrupts */\ | |
431 | RESTORE_EXTRA_STATE_FOR_SCHEDULE(type); \ | |
432 | GET_CURRENT_THREAD(r18); \ | |
433 | ld.w TI_FLAGS[r18], r19; \ | |
434 | br 5b; /* Continue with return path. */ \ | |
435 | \ | |
436 | /* Handle a signal or ptraced process return. \ | |
437 | r18 should be non-zero if there are pending signals. */ \ | |
438 | 4: /* Not all registers are saved by the normal trap/interrupt entry \ | |
439 | points (for instance, call-saved registers (because the normal \ | |
440 | C-compiler calling sequence in the kernel makes sure they're \ | |
441 | preserved), and call-clobbered registers in the case of \ | |
442 | traps), but signal handlers may want to examine or change the \ | |
443 | complete register state. Here we save anything not saved by \ | |
444 | the normal entry sequence, so that it may be safely restored \ | |
445 | (in a possibly modified form) after do_signal returns. */ \ | |
446 | SAVE_EXTRA_STATE(type); /* Save state not saved by entry. */ \ | |
447 | jarl handle_signal_or_ptrace_return, lp; \ | |
448 | RESTORE_EXTRA_STATE(type); /* Restore extra regs. */ \ | |
449 | br 1b | |
450 | ||
451 | ||
452 | /* Jump to the appropriate function for the system call number in r12 | |
453 | (r12 is not preserved), or return an error if r12 is not valid. The | |
454 | LP register should point to the location where the called function | |
455 | should return. [note that MAKE_SYS_CALL uses label 1] */ | |
456 | #define MAKE_SYS_CALL \ | |
457 | /* Figure out which function to use for this system call. */ \ | |
458 | shl 2, r12; \ | |
459 | /* See if the system call number is valid. */ \ | |
460 | addi lo(CSYM(sys_call_table) - sys_call_table_end), r12, r0; \ | |
461 | bnh 1f; \ | |
462 | mov hilo(CSYM(sys_call_table)), r19; \ | |
463 | add r19, r12; \ | |
464 | ld.w 0[r12], r12; \ | |
465 | /* Make the system call. */ \ | |
466 | jmp [r12]; \ | |
467 | /* The syscall number is invalid, return an error. */ \ | |
468 | 1: addi -ENOSYS, r0, r10; \ | |
469 | jmp [lp] | |
470 | ||
471 | ||
472 | .text | |
473 | ||
474 | /* | |
475 | * User trap. | |
476 | * | |
477 | * Trap 0 system calls are also handled here. | |
478 | * | |
479 | * The stack-pointer (r3) should have already been saved to the memory | |
480 | * location ENTRY_SP (the reason for this is that the interrupt vectors may be | |
481 | * beyond a 22-bit signed offset jump from the actual interrupt handler, and | |
482 | * this allows them to save the stack-pointer and use that register to do an | |
483 | * indirect jump). | |
484 | * | |
485 | * Syscall protocol: | |
486 | * Syscall number in r12, args in r6-r9 | |
487 | * Return value in r10 | |
488 | */ | |
489 | G_ENTRY(trap): | |
490 | SAVE_STATE (TRAP, r12, ENTRY_SP) // Save registers. | |
491 | stsr SR_ECR, r19 // Find out which trap it was. | |
492 | ei // Enable interrupts. | |
493 | mov hilo(ret_from_trap), lp // where the trap should return | |
494 | ||
495 | // The following two shifts (1) clear out extraneous NMI data in the | |
496 | // upper 16-bits, (2) convert the 0x40 - 0x5f range of trap ECR | |
497 | // numbers into the (0-31) << 2 range we want, (3) set the flags. | |
498 | shl 27, r19 // chop off all high bits | |
499 | shr 25, r19 // scale back down and then << 2 | |
500 | bnz 2f // See if not trap 0. | |
501 | ||
502 | // Trap 0 is a `short' system call, skip general trap table. | |
503 | MAKE_SYS_CALL // Jump to the syscall function. | |
504 | ||
505 | 2: // For other traps, use a table lookup. | |
506 | mov hilo(CSYM(trap_table)), r18 | |
507 | add r19, r18 | |
508 | ld.w 0[r18], r18 | |
509 | jmp [r18] // Jump to the trap handler. | |
510 | END(trap) | |
511 | ||
512 | /* This is just like ret_from_trap, but first restores extra registers | |
513 | saved by some wrappers. */ | |
514 | L_ENTRY(restore_extra_regs_and_ret_from_trap): | |
515 | RESTORE_EXTRA_STATE(TRAP) | |
516 | // fall through | |
517 | END(restore_extra_regs_and_ret_from_trap) | |
518 | ||
519 | /* Entry point used to return from a syscall/trap. */ | |
520 | L_ENTRY(ret_from_trap): | |
521 | RETURN(TRAP) | |
522 | END(ret_from_trap) | |
523 | ||
524 | ||
525 | /* This the initial entry point for a new child thread, with an appropriate | |
526 | stack in place that makes it look the the child is in the middle of an | |
527 | syscall. This function is actually `returned to' from switch_thread | |
528 | (copy_thread makes ret_from_fork the return address in each new thread's | |
529 | saved context). */ | |
530 | C_ENTRY(ret_from_fork): | |
531 | mov r10, r6 // switch_thread returns the prev task. | |
532 | jarl CSYM(schedule_tail), lp // ...which is schedule_tail's arg | |
533 | mov r0, r10 // Child's fork call should return 0. | |
534 | br ret_from_trap // Do normal trap return. | |
535 | C_END(ret_from_fork) | |
536 | ||
537 | ||
538 | /* | |
539 | * Trap 1: `long' system calls | |
540 | * `Long' syscall protocol: | |
541 | * Syscall number in r12, args in r6-r9, r13-r14 | |
542 | * Return value in r10 | |
543 | */ | |
544 | L_ENTRY(syscall_long): | |
545 | // Push extra arguments on the stack. Note that by default, the trap | |
546 | // handler reserves enough stack space for 6 arguments, so we don't | |
547 | // have to make any additional room. | |
548 | st.w r13, 16[sp] // arg 5 | |
549 | st.w r14, 20[sp] // arg 6 | |
550 | ||
551 | // Make sure r13 and r14 are preserved, in case we have to restart a | |
552 | // system call because of a signal (ep has already been set by caller). | |
553 | st.w r13, PTO+PT_GPR(13)[sp] | |
554 | st.w r14, PTO+PT_GPR(13)[sp] | |
555 | mov hilo(ret_from_long_syscall), lp | |
556 | ||
557 | MAKE_SYS_CALL // Jump to the syscall function. | |
558 | END(syscall_long) | |
559 | ||
560 | /* Entry point used to return from a long syscall. Only needed to restore | |
561 | r13/r14 if the general trap mechanism doesnt' do so. */ | |
562 | L_ENTRY(ret_from_long_syscall): | |
563 | ld.w PTO+PT_GPR(13)[sp], r13 // Restore the extra registers | |
564 | ld.w PTO+PT_GPR(13)[sp], r14 | |
565 | br ret_from_trap // The rest is the same as other traps | |
566 | END(ret_from_long_syscall) | |
567 | ||
568 | ||
569 | /* These syscalls need access to the struct pt_regs on the stack, so we | |
570 | implement them in assembly (they're basically all wrappers anyway). */ | |
571 | ||
572 | L_ENTRY(sys_fork_wrapper): | |
573 | #ifdef CONFIG_MMU | |
574 | addi SIGCHLD, r0, r6 // Arg 0: flags | |
575 | ld.w PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's) | |
576 | movea PTO, sp, r8 // Arg 2: parent context | |
577 | mov r0, r9 // Arg 3/4/5: 0 | |
578 | st.w r0, 16[sp] | |
579 | st.w r0, 20[sp] | |
580 | mov hilo(CSYM(do_fork)), r18 // Where the real work gets done | |
581 | br save_extra_state_tramp // Save state and go there | |
582 | #else | |
583 | // fork almost works, enough to trick you into looking elsewhere :-( | |
584 | addi -EINVAL, r0, r10 | |
585 | jmp [lp] | |
586 | #endif | |
587 | END(sys_fork_wrapper) | |
588 | ||
589 | L_ENTRY(sys_vfork_wrapper): | |
590 | addi CLONE_VFORK | CLONE_VM | SIGCHLD, r0, r6 // Arg 0: flags | |
591 | ld.w PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's) | |
592 | movea PTO, sp, r8 // Arg 2: parent context | |
593 | mov r0, r9 // Arg 3/4/5: 0 | |
594 | st.w r0, 16[sp] | |
595 | st.w r0, 20[sp] | |
596 | mov hilo(CSYM(do_fork)), r18 // Where the real work gets done | |
597 | br save_extra_state_tramp // Save state and go there | |
598 | END(sys_vfork_wrapper) | |
599 | ||
600 | L_ENTRY(sys_clone_wrapper): | |
601 | ld.w PTO+PT_GPR(GPR_SP)[sp], r19// parent's stack pointer | |
602 | cmp r7, r0 // See if child SP arg (arg 1) is 0. | |
603 | cmov z, r19, r7, r7 // ... and use the parent's if so. | |
604 | movea PTO, sp, r8 // Arg 2: parent context | |
605 | mov r0, r9 // Arg 3/4/5: 0 | |
606 | st.w r0, 16[sp] | |
607 | st.w r0, 20[sp] | |
608 | mov hilo(CSYM(do_fork)), r18 // Where the real work gets done | |
609 | br save_extra_state_tramp // Save state and go there | |
610 | END(sys_clone_wrapper) | |
611 | ||
612 | ||
613 | L_ENTRY(sys_execve_wrapper): | |
614 | movea PTO, sp, r9 // add user context as 4th arg | |
615 | jr CSYM(sys_execve) // Do real work (tail-call). | |
616 | END(sys_execve_wrapper) | |
617 | ||
618 | ||
619 | L_ENTRY(sys_sigsuspend_wrapper): | |
620 | movea PTO, sp, r7 // add user context as 2nd arg | |
621 | mov hilo(CSYM(sys_sigsuspend)), r18 // syscall function | |
622 | jarl save_extra_state_tramp, lp // Save state and do it | |
623 | br restore_extra_regs_and_ret_from_trap | |
624 | END(sys_sigsuspend_wrapper) | |
625 | L_ENTRY(sys_rt_sigsuspend_wrapper): | |
626 | movea PTO, sp, r8 // add user context as 3rd arg | |
627 | mov hilo(CSYM(sys_rt_sigsuspend)), r18 // syscall function | |
628 | jarl save_extra_state_tramp, lp // Save state and do it | |
629 | br restore_extra_regs_and_ret_from_trap | |
630 | END(sys_rt_sigsuspend_wrapper) | |
631 | ||
632 | L_ENTRY(sys_sigreturn_wrapper): | |
633 | movea PTO, sp, r6 // add user context as 1st arg | |
634 | mov hilo(CSYM(sys_sigreturn)), r18 // syscall function | |
635 | jarl save_extra_state_tramp, lp // Save state and do it | |
636 | br restore_extra_regs_and_ret_from_trap | |
637 | END(sys_sigreturn_wrapper) | |
638 | L_ENTRY(sys_rt_sigreturn_wrapper): | |
639 | movea PTO, sp, r6 // add user context as 1st arg | |
640 | mov hilo(CSYM(sys_rt_sigreturn)), r18// syscall function | |
641 | jarl save_extra_state_tramp, lp // Save state and do it | |
642 | br restore_extra_regs_and_ret_from_trap | |
643 | END(sys_rt_sigreturn_wrapper) | |
644 | ||
645 | ||
646 | /* Save any state not saved by SAVE_STATE(TRAP), and jump to r18. | |
647 | It's main purpose is to share the rather lengthy code sequence that | |
648 | SAVE_STATE expands into among the above wrapper functions. */ | |
649 | L_ENTRY(save_extra_state_tramp): | |
650 | SAVE_EXTRA_STATE(TRAP) // Save state not saved by entry. | |
651 | jmp [r18] // Do the work the caller wants | |
652 | END(save_extra_state_tramp) | |
653 | ||
654 | ||
655 | /* | |
656 | * Hardware maskable interrupts. | |
657 | * | |
658 | * The stack-pointer (r3) should have already been saved to the memory | |
659 | * location ENTRY_SP (the reason for this is that the interrupt vectors may be | |
660 | * beyond a 22-bit signed offset jump from the actual interrupt handler, and | |
661 | * this allows them to save the stack-pointer and use that register to do an | |
662 | * indirect jump). | |
663 | */ | |
664 | G_ENTRY(irq): | |
665 | SAVE_STATE (IRQ, r0, ENTRY_SP) // Save registers. | |
666 | ||
667 | stsr SR_ECR, r6 // Find out which interrupt it was. | |
668 | movea PTO, sp, r7 // User regs are arg2 | |
669 | ||
670 | // All v850 implementations I know about encode their interrupts as | |
671 | // multiples of 0x10, starting at 0x80 (after NMIs and software | |
672 | // interrupts). Convert this number into a simple IRQ index for the | |
673 | // rest of the kernel. We also clear the upper 16 bits, which hold | |
674 | // NMI info, and don't appear to be cleared when a NMI returns. | |
675 | shl 16, r6 // clear upper 16 bits | |
676 | shr 20, r6 // shift back, and remove lower nibble | |
677 | add -8, r6 // remove bias for irqs | |
678 | ||
679 | // Call the high-level interrupt handling code. | |
680 | jarl CSYM(handle_irq), lp | |
681 | ||
682 | RETURN(IRQ) | |
683 | END(irq) | |
684 | ||
685 | ||
686 | /* | |
687 | * Debug trap / illegal-instruction exception | |
688 | * | |
689 | * The stack-pointer (r3) should have already been saved to the memory | |
690 | * location ENTRY_SP (the reason for this is that the interrupt vectors may be | |
691 | * beyond a 22-bit signed offset jump from the actual interrupt handler, and | |
692 | * this allows them to save the stack-pointer and use that register to do an | |
693 | * indirect jump). | |
694 | */ | |
695 | G_ENTRY(dbtrap): | |
696 | SAVE_STATE (DBTRAP, r0, ENTRY_SP)// Save registers. | |
697 | ||
698 | /* First see if we came from kernel mode; if so, the dbtrap | |
699 | instruction has a special meaning, to set the DIR (`debug | |
700 | information register') register. This is because the DIR register | |
701 | can _only_ be manipulated/read while in `debug mode,' and debug | |
702 | mode is only active while we're inside the dbtrap handler. The | |
703 | exact functionality is: { DIR = (DIR | r6) & ~r7; return DIR; }. */ | |
704 | ld.b PTO+PT_KERNEL_MODE[sp], r19 | |
705 | cmp r19, r0 | |
706 | bz 1f | |
707 | ||
708 | stsr SR_DIR, r10 | |
709 | or r6, r10 | |
710 | not r7, r7 | |
711 | and r7, r10 | |
712 | ldsr r10, SR_DIR | |
713 | stsr SR_DIR, r10 // Confirm the value we set | |
714 | st.w r10, PTO+PT_GPR(10)[sp] // return it | |
715 | br 3f | |
716 | ||
717 | 1: ei // Enable interrupts. | |
718 | ||
719 | /* The default signal type we raise. */ | |
720 | mov SIGTRAP, r6 | |
721 | ||
722 | /* See if it's a single-step trap. */ | |
723 | stsr SR_DBPSW, r19 | |
724 | andi 0x0800, r19, r19 | |
725 | bnz 2f | |
726 | ||
727 | /* Look to see if the preceding instruction was is a dbtrap or not, | |
728 | to decide which signal we should use. */ | |
729 | stsr SR_DBPC, r19 // PC following trapping insn | |
730 | ld.hu -2[r19], r19 | |
731 | ori 0xf840, r0, r20 // DBTRAP insn | |
732 | cmp r19, r20 // Was this trap caused by DBTRAP? | |
733 | cmov ne, SIGILL, r6, r6 // Choose signal appropriately | |
734 | ||
735 | /* Raise the desired signal. */ | |
736 | 2: mov CURRENT_TASK, r7 // Arg 1: task | |
737 | jarl CSYM(send_sig), lp // tail call | |
738 | ||
739 | 3: RETURN(DBTRAP) | |
740 | END(dbtrap) | |
741 | ||
742 | ||
743 | /* | |
744 | * Hardware non-maskable interrupts. | |
745 | * | |
746 | * The stack-pointer (r3) should have already been saved to the memory | |
747 | * location ENTRY_SP (the reason for this is that the interrupt vectors may be | |
748 | * beyond a 22-bit signed offset jump from the actual interrupt handler, and | |
749 | * this allows them to save the stack-pointer and use that register to do an | |
750 | * indirect jump). | |
751 | */ | |
752 | G_ENTRY(nmi): | |
753 | SAVE_STATE (NMI, r0, NMI_ENTRY_SP); /* Save registers. */ | |
754 | ||
755 | stsr SR_ECR, r6; /* Find out which nmi it was. */ | |
756 | shr 20, r6; /* Extract NMI code in bits 20-24. */ | |
757 | movea PTO, sp, r7; /* User regs are arg2. */ | |
758 | ||
759 | /* Non-maskable interrupts always lie right after maskable interrupts. | |
760 | Call the generic IRQ handler, with two arguments, the IRQ number, | |
761 | and a pointer to the user registers, to handle the specifics. | |
762 | (we subtract one because the first NMI has code 1). */ | |
763 | addi FIRST_NMI - 1, r6, r6 | |
764 | jarl CSYM(handle_irq), lp | |
765 | ||
766 | RETURN(NMI) | |
767 | END(nmi) | |
768 | ||
769 | ||
770 | /* | |
771 | * Trap with no handler | |
772 | */ | |
773 | L_ENTRY(bad_trap_wrapper): | |
774 | mov r19, r6 // Arg 0: trap number | |
775 | movea PTO, sp, r7 // Arg 1: user regs | |
776 | jr CSYM(bad_trap) // tail call handler | |
777 | END(bad_trap_wrapper) | |
778 | ||
779 | ||
780 | /* | |
781 | * Invoke the scheduler, called from the trap/irq kernel exit path. | |
782 | * | |
783 | * This basically just calls `schedule', but also arranges for extra | |
784 | * registers to be saved for ptrace'd processes, so ptrace can modify them. | |
785 | */ | |
786 | L_ENTRY(call_scheduler): | |
787 | ld.w TASK_PTRACE[CURRENT_TASK], r19 // See if task is ptrace'd | |
788 | cmp r19, r0 | |
789 | bnz 1f // ... yes, do special stuff | |
790 | jr CSYM(schedule) // ... no, just tail-call scheduler | |
791 | ||
792 | // Save extra regs for ptrace'd task. We want to save anything | |
793 | // that would otherwise only be `implicitly' saved by the normal | |
794 | // compiler calling-convention. | |
795 | 1: mov sp, ep // Setup EP for SAVE_CALL_SAVED_REGS | |
796 | SAVE_CALL_SAVED_REGS // Save call-saved registers to stack | |
797 | mov lp, r20 // Save LP in a callee-saved register | |
798 | ||
799 | jarl CSYM(schedule), lp // Call scheduler | |
800 | ||
801 | mov r20, lp | |
802 | mov sp, ep // We can't rely on EP after return | |
803 | RESTORE_CALL_SAVED_REGS // Restore (possibly modified) regs | |
804 | jmp [lp] // Return to the return path | |
805 | END(call_scheduler) | |
806 | ||
807 | ||
808 | /* | |
809 | * This is an out-of-line handler for two special cases during the kernel | |
810 | * trap/irq exit sequence: | |
811 | * | |
812 | * (1) If r18 is non-zero then a signal needs to be handled, which is | |
813 | * done, and then the caller returned to. | |
814 | * | |
815 | * (2) If r18 is non-zero then we're returning to a ptraced process, which | |
816 | * has several special cases -- single-stepping and trap tracing, both | |
817 | * of which require using the `dbret' instruction to exit the kernel | |
818 | * instead of the normal `reti' (this is because the CPU not correctly | |
819 | * single-step after a reti). In this case, of course, this handler | |
820 | * never returns to the caller. | |
821 | * | |
822 | * In either case, all registers should have been saved to the current | |
823 | * state-save-frame on the stack, except for callee-saved registers. | |
824 | * | |
825 | * [These two different cases are combined merely to avoid bloating the | |
826 | * macro-inlined code, not because they really make much sense together!] | |
827 | */ | |
828 | L_ENTRY(handle_signal_or_ptrace_return): | |
829 | cmp r18, r0 // See if handling a signal | |
830 | bz 1f // ... nope, go do ptrace return | |
831 | ||
832 | // Handle a signal | |
833 | mov lp, r20 // Save link-pointer | |
834 | mov r10, r21 // Save return-values (for trap) | |
835 | mov r11, r22 | |
836 | ||
837 | movea PTO, sp, r6 // Arg 1: struct pt_regs *regs | |
838 | mov r0, r7 // Arg 2: sigset_t *oldset | |
839 | jarl CSYM(do_signal), lp // Handle the signal | |
840 | di // sig handling enables interrupts | |
841 | ||
842 | mov r20, lp // Restore link-pointer | |
843 | mov r21, r10 // Restore return-values (for trap) | |
844 | mov r22, r11 | |
845 | ld.w TASK_PTRACE[CURRENT_TASK], r19 // check ptrace flags too | |
846 | cmp r19, r0 | |
847 | bnz 1f // ... some set, so look more | |
848 | 2: jmp [lp] // ... none set, so return normally | |
849 | ||
850 | // ptrace return | |
851 | 1: ld.w PTO+PT_PSW[sp], r19 // Look at user-processes's flags | |
852 | andi 0x0800, r19, r19 // See if single-step flag is set | |
853 | bz 2b // ... nope, return normally | |
854 | ||
855 | // Return as if from a dbtrap insn | |
856 | st.b r0, KM // Now officially in user state. | |
857 | POP_STATE(DBTRAP) // Restore regs | |
858 | st.w sp, KSP // Save the kernel stack pointer. | |
859 | ld.w PT_GPR(GPR_SP)-PT_SIZE[sp], sp // Restore user stack pointer. | |
860 | DBTRAP_RET // Return from the trap/interrupt. | |
861 | END(handle_signal_or_ptrace_return) | |
862 | ||
863 | ||
864 | /* | |
865 | * This is where we switch between two threads. The arguments are: | |
866 | * r6 -- pointer to the struct thread for the `current' process | |
867 | * r7 -- pointer to the struct thread for the `new' process. | |
868 | * when this function returns, it will return to the new thread. | |
869 | */ | |
870 | C_ENTRY(switch_thread): | |
871 | // Return the previous task (r10 is not clobbered by restore below) | |
872 | mov CURRENT_TASK, r10 | |
873 | // First, push the current processor state on the stack | |
874 | PUSH_STATE(SWITCH) | |
875 | // Now save the location of the kernel stack pointer for this thread; | |
876 | // since we've pushed all other state on the stack, this is enough to | |
877 | // restore it all later. | |
878 | st.w sp, THREAD_KSP[r6] | |
879 | // Now restore the stack pointer from the new process | |
880 | ld.w THREAD_KSP[r7], sp | |
881 | // ... and restore all state from that | |
882 | POP_STATE(SWITCH) | |
883 | // Update the current task pointer | |
884 | GET_CURRENT_TASK(CURRENT_TASK) | |
885 | // Now return into the new thread | |
886 | jmp [lp] | |
887 | C_END(switch_thread) | |
888 | ||
889 | ||
890 | .data | |
891 | ||
892 | .align 4 | |
893 | C_DATA(trap_table): | |
894 | .long bad_trap_wrapper // trap 0, doesn't use trap table. | |
895 | .long syscall_long // trap 1, `long' syscall. | |
896 | .long bad_trap_wrapper | |
897 | .long bad_trap_wrapper | |
898 | .long bad_trap_wrapper | |
899 | .long bad_trap_wrapper | |
900 | .long bad_trap_wrapper | |
901 | .long bad_trap_wrapper | |
902 | .long bad_trap_wrapper | |
903 | .long bad_trap_wrapper | |
904 | .long bad_trap_wrapper | |
905 | .long bad_trap_wrapper | |
906 | .long bad_trap_wrapper | |
907 | .long bad_trap_wrapper | |
908 | .long bad_trap_wrapper | |
909 | .long bad_trap_wrapper | |
910 | C_END(trap_table) | |
911 | ||
912 | ||
913 | .section .rodata | |
914 | ||
915 | .align 4 | |
916 | C_DATA(sys_call_table): | |
917 | .long CSYM(sys_restart_syscall) // 0 | |
918 | .long CSYM(sys_exit) | |
919 | .long sys_fork_wrapper | |
920 | .long CSYM(sys_read) | |
921 | .long CSYM(sys_write) | |
922 | .long CSYM(sys_open) // 5 | |
923 | .long CSYM(sys_close) | |
924 | .long CSYM(sys_waitpid) | |
925 | .long CSYM(sys_creat) | |
926 | .long CSYM(sys_link) | |
927 | .long CSYM(sys_unlink) // 10 | |
928 | .long sys_execve_wrapper | |
929 | .long CSYM(sys_chdir) | |
930 | .long CSYM(sys_time) | |
931 | .long CSYM(sys_mknod) | |
932 | .long CSYM(sys_chmod) // 15 | |
933 | .long CSYM(sys_chown) | |
934 | .long CSYM(sys_ni_syscall) // was: break | |
935 | .long CSYM(sys_ni_syscall) // was: oldstat (aka stat) | |
936 | .long CSYM(sys_lseek) | |
937 | .long CSYM(sys_getpid) // 20 | |
938 | .long CSYM(sys_mount) | |
939 | .long CSYM(sys_oldumount) | |
940 | .long CSYM(sys_setuid) | |
941 | .long CSYM(sys_getuid) | |
942 | .long CSYM(sys_stime) // 25 | |
943 | .long CSYM(sys_ptrace) | |
944 | .long CSYM(sys_alarm) | |
945 | .long CSYM(sys_ni_syscall) // was: oldfstat (aka fstat) | |
946 | .long CSYM(sys_pause) | |
947 | .long CSYM(sys_utime) // 30 | |
948 | .long CSYM(sys_ni_syscall) // was: stty | |
949 | .long CSYM(sys_ni_syscall) // was: gtty | |
950 | .long CSYM(sys_access) | |
951 | .long CSYM(sys_nice) | |
952 | .long CSYM(sys_ni_syscall) // 35, was: ftime | |
953 | .long CSYM(sys_sync) | |
954 | .long CSYM(sys_kill) | |
955 | .long CSYM(sys_rename) | |
956 | .long CSYM(sys_mkdir) | |
957 | .long CSYM(sys_rmdir) // 40 | |
958 | .long CSYM(sys_dup) | |
959 | .long CSYM(sys_pipe) | |
960 | .long CSYM(sys_times) | |
961 | .long CSYM(sys_ni_syscall) // was: prof | |
962 | .long CSYM(sys_brk) // 45 | |
963 | .long CSYM(sys_setgid) | |
964 | .long CSYM(sys_getgid) | |
965 | .long CSYM(sys_signal) | |
966 | .long CSYM(sys_geteuid) | |
967 | .long CSYM(sys_getegid) // 50 | |
968 | .long CSYM(sys_acct) | |
969 | .long CSYM(sys_umount) // recycled never used phys() | |
970 | .long CSYM(sys_ni_syscall) // was: lock | |
971 | .long CSYM(sys_ioctl) | |
972 | .long CSYM(sys_fcntl) // 55 | |
973 | .long CSYM(sys_ni_syscall) // was: mpx | |
974 | .long CSYM(sys_setpgid) | |
975 | .long CSYM(sys_ni_syscall) // was: ulimit | |
976 | .long CSYM(sys_ni_syscall) | |
977 | .long CSYM(sys_umask) // 60 | |
978 | .long CSYM(sys_chroot) | |
979 | .long CSYM(sys_ustat) | |
980 | .long CSYM(sys_dup2) | |
981 | .long CSYM(sys_getppid) | |
982 | .long CSYM(sys_getpgrp) // 65 | |
983 | .long CSYM(sys_setsid) | |
984 | .long CSYM(sys_sigaction) | |
985 | .long CSYM(sys_sgetmask) | |
986 | .long CSYM(sys_ssetmask) | |
987 | .long CSYM(sys_setreuid) // 70 | |
988 | .long CSYM(sys_setregid) | |
989 | .long sys_sigsuspend_wrapper | |
990 | .long CSYM(sys_sigpending) | |
991 | .long CSYM(sys_sethostname) | |
992 | .long CSYM(sys_setrlimit) // 75 | |
993 | .long CSYM(sys_getrlimit) | |
994 | .long CSYM(sys_getrusage) | |
995 | .long CSYM(sys_gettimeofday) | |
996 | .long CSYM(sys_settimeofday) | |
997 | .long CSYM(sys_getgroups) // 80 | |
998 | .long CSYM(sys_setgroups) | |
999 | .long CSYM(sys_select) | |
1000 | .long CSYM(sys_symlink) | |
1001 | .long CSYM(sys_ni_syscall) // was: oldlstat (aka lstat) | |
1002 | .long CSYM(sys_readlink) // 85 | |
1003 | .long CSYM(sys_uselib) | |
1004 | .long CSYM(sys_swapon) | |
1005 | .long CSYM(sys_reboot) | |
1006 | .long CSYM(old_readdir) | |
1007 | .long CSYM(sys_mmap) // 90 | |
1008 | .long CSYM(sys_munmap) | |
1009 | .long CSYM(sys_truncate) | |
1010 | .long CSYM(sys_ftruncate) | |
1011 | .long CSYM(sys_fchmod) | |
1012 | .long CSYM(sys_fchown) // 95 | |
1013 | .long CSYM(sys_getpriority) | |
1014 | .long CSYM(sys_setpriority) | |
1015 | .long CSYM(sys_ni_syscall) // was: profil | |
1016 | .long CSYM(sys_statfs) | |
1017 | .long CSYM(sys_fstatfs) // 100 | |
1018 | .long CSYM(sys_ni_syscall) // i386: ioperm | |
1019 | .long CSYM(sys_socketcall) | |
1020 | .long CSYM(sys_syslog) | |
1021 | .long CSYM(sys_setitimer) | |
1022 | .long CSYM(sys_getitimer) // 105 | |
1023 | .long CSYM(sys_newstat) | |
1024 | .long CSYM(sys_newlstat) | |
1025 | .long CSYM(sys_newfstat) | |
1026 | .long CSYM(sys_ni_syscall) // was: olduname (aka uname) | |
1027 | .long CSYM(sys_ni_syscall) // 110, i386: iopl | |
1028 | .long CSYM(sys_vhangup) | |
1029 | .long CSYM(sys_ni_syscall) // was: idle | |
1030 | .long CSYM(sys_ni_syscall) // i386: vm86old | |
1031 | .long CSYM(sys_wait4) | |
1032 | .long CSYM(sys_swapoff) // 115 | |
1033 | .long CSYM(sys_sysinfo) | |
1034 | .long CSYM(sys_ipc) | |
1035 | .long CSYM(sys_fsync) | |
1036 | .long sys_sigreturn_wrapper | |
1037 | .long sys_clone_wrapper // 120 | |
1038 | .long CSYM(sys_setdomainname) | |
1039 | .long CSYM(sys_newuname) | |
1040 | .long CSYM(sys_ni_syscall) // i386: modify_ldt, m68k: cacheflush | |
1041 | .long CSYM(sys_adjtimex) | |
1042 | .long CSYM(sys_ni_syscall) // 125 - sys_mprotect | |
1043 | .long CSYM(sys_sigprocmask) | |
1044 | .long CSYM(sys_ni_syscall) // sys_create_module | |
1045 | .long CSYM(sys_init_module) | |
1046 | .long CSYM(sys_delete_module) | |
1047 | .long CSYM(sys_ni_syscall) // 130 - sys_get_kernel_syms | |
1048 | .long CSYM(sys_quotactl) | |
1049 | .long CSYM(sys_getpgid) | |
1050 | .long CSYM(sys_fchdir) | |
1051 | .long CSYM(sys_bdflush) | |
1052 | .long CSYM(sys_sysfs) // 135 | |
1053 | .long CSYM(sys_personality) | |
1054 | .long CSYM(sys_ni_syscall) // for afs_syscall | |
1055 | .long CSYM(sys_setfsuid) | |
1056 | .long CSYM(sys_setfsgid) | |
1057 | .long CSYM(sys_llseek) // 140 | |
1058 | .long CSYM(sys_getdents) | |
1059 | .long CSYM(sys_select) // for backward compat; remove someday | |
1060 | .long CSYM(sys_flock) | |
1061 | .long CSYM(sys_ni_syscall) // sys_msync | |
1062 | .long CSYM(sys_readv) // 145 | |
1063 | .long CSYM(sys_writev) | |
1064 | .long CSYM(sys_getsid) | |
1065 | .long CSYM(sys_fdatasync) | |
1066 | .long CSYM(sys_sysctl) | |
1067 | .long CSYM(sys_ni_syscall) // 150 - sys_mlock | |
1068 | .long CSYM(sys_ni_syscall) // sys_munlock | |
1069 | .long CSYM(sys_ni_syscall) // sys_mlockall | |
1070 | .long CSYM(sys_ni_syscall) // sys_munlockall | |
1071 | .long CSYM(sys_sched_setparam) | |
1072 | .long CSYM(sys_sched_getparam) // 155 | |
1073 | .long CSYM(sys_sched_setscheduler) | |
1074 | .long CSYM(sys_sched_getscheduler) | |
1075 | .long CSYM(sys_sched_yield) | |
1076 | .long CSYM(sys_sched_get_priority_max) | |
1077 | .long CSYM(sys_sched_get_priority_min) // 160 | |
1078 | .long CSYM(sys_sched_rr_get_interval) | |
1079 | .long CSYM(sys_nanosleep) | |
1080 | .long CSYM(sys_ni_syscall) // sys_mremap | |
1081 | .long CSYM(sys_setresuid) | |
1082 | .long CSYM(sys_getresuid) // 165 | |
1083 | .long CSYM(sys_ni_syscall) // for vm86 | |
1084 | .long CSYM(sys_ni_syscall) // sys_query_module | |
1085 | .long CSYM(sys_poll) | |
1086 | .long CSYM(sys_nfsservctl) | |
1087 | .long CSYM(sys_setresgid) // 170 | |
1088 | .long CSYM(sys_getresgid) | |
1089 | .long CSYM(sys_prctl) | |
1090 | .long sys_rt_sigreturn_wrapper | |
1091 | .long CSYM(sys_rt_sigaction) | |
1092 | .long CSYM(sys_rt_sigprocmask) // 175 | |
1093 | .long CSYM(sys_rt_sigpending) | |
1094 | .long CSYM(sys_rt_sigtimedwait) | |
1095 | .long CSYM(sys_rt_sigqueueinfo) | |
1096 | .long sys_rt_sigsuspend_wrapper | |
1097 | .long CSYM(sys_pread64) // 180 | |
1098 | .long CSYM(sys_pwrite64) | |
1099 | .long CSYM(sys_lchown) | |
1100 | .long CSYM(sys_getcwd) | |
1101 | .long CSYM(sys_capget) | |
1102 | .long CSYM(sys_capset) // 185 | |
1103 | .long CSYM(sys_sigaltstack) | |
1104 | .long CSYM(sys_sendfile) | |
1105 | .long CSYM(sys_ni_syscall) // streams1 | |
1106 | .long CSYM(sys_ni_syscall) // streams2 | |
1107 | .long sys_vfork_wrapper // 190 | |
1108 | .long CSYM(sys_ni_syscall) | |
1109 | .long CSYM(sys_mmap2) | |
1110 | .long CSYM(sys_truncate64) | |
1111 | .long CSYM(sys_ftruncate64) | |
1112 | .long CSYM(sys_stat64) // 195 | |
1113 | .long CSYM(sys_lstat64) | |
1114 | .long CSYM(sys_fstat64) | |
1115 | .long CSYM(sys_fcntl64) | |
1116 | .long CSYM(sys_getdents64) | |
1117 | .long CSYM(sys_pivot_root) // 200 | |
1118 | .long CSYM(sys_gettid) | |
1119 | .long CSYM(sys_tkill) | |
1120 | sys_call_table_end: | |
1121 | C_END(sys_call_table) |