diff options
author | Michal Simek <monstr@monstr.eu> | 2009-05-26 10:30:21 -0400 |
---|---|---|
committer | Michal Simek <monstr@monstr.eu> | 2009-05-26 10:45:20 -0400 |
commit | ca54502bd52a5d483f7ba076b613ad2ee43941da (patch) | |
tree | 645da3c42fd63b9cd76ec27871beca2d055daf2f /arch/microblaze | |
parent | 23cfc369337fa106d08cbed0dc86527c67966ff2 (diff) |
microblaze_mmu_v2: entry.S, entry.h
Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch/microblaze')
-rw-r--r-- | arch/microblaze/include/asm/entry.h | 37 | ||||
-rw-r--r-- | arch/microblaze/kernel/entry.S | 1116 |
2 files changed, 1151 insertions, 2 deletions
diff --git a/arch/microblaze/include/asm/entry.h b/arch/microblaze/include/asm/entry.h index e4c3aef884df..61abbd232640 100644 --- a/arch/microblaze/include/asm/entry.h +++ b/arch/microblaze/include/asm/entry.h | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Definitions used by low-level trap handlers | 2 | * Definitions used by low-level trap handlers |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Michal Simek | 4 | * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> |
5 | * Copyright (C) 2007 - 2008 PetaLogix | 5 | * Copyright (C) 2007-2009 PetaLogix |
6 | * Copyright (C) 2007 John Williams <john.williams@petalogix.com> | 6 | * Copyright (C) 2007 John Williams <john.williams@petalogix.com> |
7 | * | 7 | * |
8 | * This file is subject to the terms and conditions of the GNU General | 8 | * This file is subject to the terms and conditions of the GNU General |
@@ -31,7 +31,40 @@ DECLARE_PER_CPU(unsigned int, R11_SAVE); /* Temp variable for entry */ | |||
31 | DECLARE_PER_CPU(unsigned int, CURRENT_SAVE); /* Saved current pointer */ | 31 | DECLARE_PER_CPU(unsigned int, CURRENT_SAVE); /* Saved current pointer */ |
32 | # endif /* __ASSEMBLY__ */ | 32 | # endif /* __ASSEMBLY__ */ |
33 | 33 | ||
34 | #ifndef CONFIG_MMU | ||
35 | |||
34 | /* noMMU hasn't any space for args */ | 36 | /* noMMU hasn't any space for args */ |
35 | # define STATE_SAVE_ARG_SPACE (0) | 37 | # define STATE_SAVE_ARG_SPACE (0) |
36 | 38 | ||
39 | #else /* CONFIG_MMU */ | ||
40 | |||
41 | /* If true, system calls save and restore all registers (except result | ||
42 | * registers, of course). If false, then `call clobbered' registers | ||
43 | * will not be preserved, on the theory that system calls are basically | ||
44 | * function calls anyway, and the caller should be able to deal with it. | ||
45 | * This is a security risk, of course, as `internal' values may leak out | ||
46 | * after a system call, but that certainly doesn't matter very much for | ||
47 | * a processor with no MMU protection! For a protected-mode kernel, it | ||
48 | * would be faster to just zero those registers before returning. | ||
49 | * | ||
50 | * I can not rely on the glibc implementation. If you turn it off make | ||
51 | * sure that r11/r12 is saved in user-space. --KAA | ||
52 | * | ||
53 | * These are special variables using by the kernel trap/interrupt code | ||
54 | * to save registers in, at a time when there are no spare registers we | ||
55 | * can use to do so, and we can't depend on the value of the stack | ||
56 | * pointer. This means that they must be within a signed 16-bit | ||
57 | * displacement of 0x00000000. | ||
58 | */ | ||
59 | |||
60 | /* A `state save frame' is a struct pt_regs preceded by some extra space | ||
61 | * suitable for a function call stack frame. */ | ||
62 | |||
63 | /* Amount of room on the stack reserved for arguments and to satisfy the | ||
64 | * C calling conventions, in addition to the space used by the struct | ||
65 | * pt_regs that actually holds saved values. */ | ||
66 | #define STATE_SAVE_ARG_SPACE (6*4) /* Up to six arguments */ | ||
67 | |||
68 | #endif /* CONFIG_MMU */ | ||
69 | |||
37 | #endif /* _ASM_MICROBLAZE_ENTRY_H */ | 70 | #endif /* _ASM_MICROBLAZE_ENTRY_H */ |
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S new file mode 100644 index 000000000000..91a0e7b185dd --- /dev/null +++ b/arch/microblaze/kernel/entry.S | |||
@@ -0,0 +1,1116 @@ | |||
1 | /* | ||
2 | * Low-level system-call handling, trap handlers and context-switching | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> | ||
5 | * Copyright (C) 2008-2009 PetaLogix | ||
6 | * Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au> | ||
7 | * Copyright (C) 2001,2002 NEC Corporation | ||
8 | * Copyright (C) 2001,2002 Miles Bader <miles@gnu.org> | ||
9 | * | ||
10 | * This file is subject to the terms and conditions of the GNU General | ||
11 | * Public License. See the file COPYING in the main directory of this | ||
12 | * archive for more details. | ||
13 | * | ||
14 | * Written by Miles Bader <miles@gnu.org> | ||
15 | * Heavily modified by John Williams for Microblaze | ||
16 | */ | ||
17 | |||
18 | #include <linux/sys.h> | ||
19 | #include <linux/linkage.h> | ||
20 | |||
21 | #include <asm/entry.h> | ||
22 | #include <asm/current.h> | ||
23 | #include <asm/processor.h> | ||
24 | #include <asm/exceptions.h> | ||
25 | #include <asm/asm-offsets.h> | ||
26 | #include <asm/thread_info.h> | ||
27 | |||
28 | #include <asm/page.h> | ||
29 | #include <asm/unistd.h> | ||
30 | |||
31 | #include <linux/errno.h> | ||
32 | #include <asm/signal.h> | ||
33 | |||
34 | /* The size of a state save frame. */ | ||
35 | #define STATE_SAVE_SIZE (PT_SIZE + STATE_SAVE_ARG_SPACE) | ||
36 | |||
37 | /* The offset of the struct pt_regs in a `state save frame' on the stack. */ | ||
38 | #define PTO STATE_SAVE_ARG_SPACE /* 24 the space for args */ | ||
39 | |||
40 | #define C_ENTRY(name) .globl name; .align 4; name | ||
41 | |||
42 | /* | ||
43 | * Various ways of setting and clearing BIP in flags reg. | ||
44 | * This is mucky, but necessary using microblaze version that | ||
45 | * allows msr ops to write to BIP | ||
46 | */ | ||
47 | #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR | ||
48 | .macro clear_bip | ||
49 | msrclr r11, MSR_BIP | ||
50 | nop | ||
51 | .endm | ||
52 | |||
53 | .macro set_bip | ||
54 | msrset r11, MSR_BIP | ||
55 | nop | ||
56 | .endm | ||
57 | |||
58 | .macro clear_eip | ||
59 | msrclr r11, MSR_EIP | ||
60 | nop | ||
61 | .endm | ||
62 | |||
63 | .macro set_ee | ||
64 | msrset r11, MSR_EE | ||
65 | nop | ||
66 | .endm | ||
67 | |||
68 | .macro disable_irq | ||
69 | msrclr r11, MSR_IE | ||
70 | nop | ||
71 | .endm | ||
72 | |||
73 | .macro enable_irq | ||
74 | msrset r11, MSR_IE | ||
75 | nop | ||
76 | .endm | ||
77 | |||
78 | .macro set_ums | ||
79 | msrset r11, MSR_UMS | ||
80 | nop | ||
81 | msrclr r11, MSR_VMS | ||
82 | nop | ||
83 | .endm | ||
84 | |||
85 | .macro set_vms | ||
86 | msrclr r11, MSR_UMS | ||
87 | nop | ||
88 | msrset r11, MSR_VMS | ||
89 | nop | ||
90 | .endm | ||
91 | |||
92 | .macro clear_vms_ums | ||
93 | msrclr r11, MSR_VMS | ||
94 | nop | ||
95 | msrclr r11, MSR_UMS | ||
96 | nop | ||
97 | .endm | ||
98 | #else | ||
99 | .macro clear_bip | ||
100 | mfs r11, rmsr | ||
101 | nop | ||
102 | andi r11, r11, ~MSR_BIP | ||
103 | mts rmsr, r11 | ||
104 | nop | ||
105 | .endm | ||
106 | |||
107 | .macro set_bip | ||
108 | mfs r11, rmsr | ||
109 | nop | ||
110 | ori r11, r11, MSR_BIP | ||
111 | mts rmsr, r11 | ||
112 | nop | ||
113 | .endm | ||
114 | |||
115 | .macro clear_eip | ||
116 | mfs r11, rmsr | ||
117 | nop | ||
118 | andi r11, r11, ~MSR_EIP | ||
119 | mts rmsr, r11 | ||
120 | nop | ||
121 | .endm | ||
122 | |||
123 | .macro set_ee | ||
124 | mfs r11, rmsr | ||
125 | nop | ||
126 | ori r11, r11, MSR_EE | ||
127 | mts rmsr, r11 | ||
128 | nop | ||
129 | .endm | ||
130 | |||
131 | .macro disable_irq | ||
132 | mfs r11, rmsr | ||
133 | nop | ||
134 | andi r11, r11, ~MSR_IE | ||
135 | mts rmsr, r11 | ||
136 | nop | ||
137 | .endm | ||
138 | |||
139 | .macro enable_irq | ||
140 | mfs r11, rmsr | ||
141 | nop | ||
142 | ori r11, r11, MSR_IE | ||
143 | mts rmsr, r11 | ||
144 | nop | ||
145 | .endm | ||
146 | |||
147 | .macro set_ums | ||
148 | mfs r11, rmsr | ||
149 | nop | ||
150 | ori r11, r11, MSR_VMS | ||
151 | andni r11, r11, MSR_UMS | ||
152 | mts rmsr, r11 | ||
153 | nop | ||
154 | .endm | ||
155 | |||
156 | .macro set_vms | ||
157 | mfs r11, rmsr | ||
158 | nop | ||
159 | ori r11, r11, MSR_VMS | ||
160 | andni r11, r11, MSR_UMS | ||
161 | mts rmsr, r11 | ||
162 | nop | ||
163 | .endm | ||
164 | |||
165 | .macro clear_vms_ums | ||
166 | mfs r11, rmsr | ||
167 | nop | ||
168 | andni r11, r11, (MSR_VMS|MSR_UMS) | ||
169 | mts rmsr,r11 | ||
170 | nop | ||
171 | .endm | ||
172 | #endif | ||
173 | |||
174 | /* Define how to call high-level functions. With MMU, virtual mode must be | ||
175 | * enabled when calling the high-level function. Clobbers R11. | ||
176 | * VM_ON, VM_OFF, DO_JUMP_BIPCLR, DO_CALL | ||
177 | */ | ||
178 | |||
179 | /* turn on virtual protected mode save */ | ||
180 | #define VM_ON \ | ||
181 | set_ums; \ | ||
182 | rted r0, 2f; \ | ||
183 | 2: nop; | ||
184 | |||
185 | /* turn off virtual protected mode save and user mode save*/ | ||
186 | #define VM_OFF \ | ||
187 | clear_vms_ums; \ | ||
188 | rted r0, TOPHYS(1f); \ | ||
189 | 1: nop; | ||
190 | |||
191 | #define SAVE_REGS \ | ||
192 | swi r2, r1, PTO+PT_R2; /* Save SDA */ \ | ||
193 | swi r5, r1, PTO+PT_R5; \ | ||
194 | swi r6, r1, PTO+PT_R6; \ | ||
195 | swi r7, r1, PTO+PT_R7; \ | ||
196 | swi r8, r1, PTO+PT_R8; \ | ||
197 | swi r9, r1, PTO+PT_R9; \ | ||
198 | swi r10, r1, PTO+PT_R10; \ | ||
199 | swi r11, r1, PTO+PT_R11; /* save clobbered regs after rval */\ | ||
200 | swi r12, r1, PTO+PT_R12; \ | ||
201 | swi r13, r1, PTO+PT_R13; /* Save SDA2 */ \ | ||
202 | swi r14, r1, PTO+PT_PC; /* PC, before IRQ/trap */ \ | ||
203 | swi r15, r1, PTO+PT_R15; /* Save LP */ \ | ||
204 | swi r18, r1, PTO+PT_R18; /* Save asm scratch reg */ \ | ||
205 | swi r19, r1, PTO+PT_R19; \ | ||
206 | swi r20, r1, PTO+PT_R20; \ | ||
207 | swi r21, r1, PTO+PT_R21; \ | ||
208 | swi r22, r1, PTO+PT_R22; \ | ||
209 | swi r23, r1, PTO+PT_R23; \ | ||
210 | swi r24, r1, PTO+PT_R24; \ | ||
211 | swi r25, r1, PTO+PT_R25; \ | ||
212 | swi r26, r1, PTO+PT_R26; \ | ||
213 | swi r27, r1, PTO+PT_R27; \ | ||
214 | swi r28, r1, PTO+PT_R28; \ | ||
215 | swi r29, r1, PTO+PT_R29; \ | ||
216 | swi r30, r1, PTO+PT_R30; \ | ||
217 | swi r31, r1, PTO+PT_R31; /* Save current task reg */ \ | ||
218 | mfs r11, rmsr; /* save MSR */ \ | ||
219 | nop; \ | ||
220 | swi r11, r1, PTO+PT_MSR; | ||
221 | |||
222 | #define RESTORE_REGS \ | ||
223 | lwi r11, r1, PTO+PT_MSR; \ | ||
224 | mts rmsr , r11; \ | ||
225 | nop; \ | ||
226 | lwi r2, r1, PTO+PT_R2; /* restore SDA */ \ | ||
227 | lwi r5, r1, PTO+PT_R5; \ | ||
228 | lwi r6, r1, PTO+PT_R6; \ | ||
229 | lwi r7, r1, PTO+PT_R7; \ | ||
230 | lwi r8, r1, PTO+PT_R8; \ | ||
231 | lwi r9, r1, PTO+PT_R9; \ | ||
232 | lwi r10, r1, PTO+PT_R10; \ | ||
233 | lwi r11, r1, PTO+PT_R11; /* restore clobbered regs after rval */\ | ||
234 | lwi r12, r1, PTO+PT_R12; \ | ||
235 | lwi r13, r1, PTO+PT_R13; /* restore SDA2 */ \ | ||
236 | lwi r14, r1, PTO+PT_PC; /* RESTORE_LINK PC, before IRQ/trap */\ | ||
237 | lwi r15, r1, PTO+PT_R15; /* restore LP */ \ | ||
238 | lwi r18, r1, PTO+PT_R18; /* restore asm scratch reg */ \ | ||
239 | lwi r19, r1, PTO+PT_R19; \ | ||
240 | lwi r20, r1, PTO+PT_R20; \ | ||
241 | lwi r21, r1, PTO+PT_R21; \ | ||
242 | lwi r22, r1, PTO+PT_R22; \ | ||
243 | lwi r23, r1, PTO+PT_R23; \ | ||
244 | lwi r24, r1, PTO+PT_R24; \ | ||
245 | lwi r25, r1, PTO+PT_R25; \ | ||
246 | lwi r26, r1, PTO+PT_R26; \ | ||
247 | lwi r27, r1, PTO+PT_R27; \ | ||
248 | lwi r28, r1, PTO+PT_R28; \ | ||
249 | lwi r29, r1, PTO+PT_R29; \ | ||
250 | lwi r30, r1, PTO+PT_R30; \ | ||
251 | lwi r31, r1, PTO+PT_R31; /* Restore cur task reg */ | ||
252 | |||
253 | .text | ||
254 | |||
255 | /* | ||
256 | * User trap. | ||
257 | * | ||
258 | * System calls are handled here. | ||
259 | * | ||
260 | * Syscall protocol: | ||
261 | * Syscall number in r12, args in r5-r10 | ||
262 | * Return value in r3 | ||
263 | * | ||
264 | * Trap entered via brki instruction, so BIP bit is set, and interrupts | ||
265 | * are masked. This is nice, means we don't have to CLI before state save | ||
266 | */ | ||
267 | C_ENTRY(_user_exception): | ||
268 | swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ | ||
269 | addi r14, r14, 4 /* return address is 4 byte after call */ | ||
270 | swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ | ||
271 | |||
272 | lwi r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/ | ||
273 | beqi r11, 1f; /* Jump ahead if coming from user */ | ||
274 | /* Kernel-mode state save. */ | ||
275 | lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ | ||
276 | tophys(r1,r11); | ||
277 | swi r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */ | ||
278 | lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */ | ||
279 | |||
280 | addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ | ||
281 | SAVE_REGS | ||
282 | |||
283 | addi r11, r0, 1; /* Was in kernel-mode. */ | ||
284 | swi r11, r1, PTO+PT_MODE; /* pt_regs -> kernel mode */ | ||
285 | brid 2f; | ||
286 | nop; /* Fill delay slot */ | ||
287 | |||
288 | /* User-mode state save. */ | ||
289 | 1: | ||
290 | lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */ | ||
291 | lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ | ||
292 | tophys(r1,r1); | ||
293 | lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */ | ||
294 | /* calculate kernel stack pointer from task struct 8k */ | ||
295 | addik r1, r1, THREAD_SIZE; | ||
296 | tophys(r1,r1); | ||
297 | |||
298 | addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ | ||
299 | SAVE_REGS | ||
300 | |||
301 | swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ | ||
302 | lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); | ||
303 | swi r11, r1, PTO+PT_R1; /* Store user SP. */ | ||
304 | addi r11, r0, 1; | ||
305 | swi r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode. */ | ||
306 | 2: lwi r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ | ||
307 | /* Save away the syscall number. */ | ||
308 | swi r12, r1, PTO+PT_R0; | ||
309 | tovirt(r1,r1) | ||
310 | |||
311 | la r15, r0, ret_from_trap-8 | ||
312 | /* where the trap should return need -8 to adjust for rtsd r15, 8*/ | ||
313 | /* Jump to the appropriate function for the system call number in r12 | ||
314 | * (r12 is not preserved), or return an error if r12 is not valid. The LP | ||
315 | * register should point to the location where | ||
316 | * the called function should return. [note that MAKE_SYS_CALL uses label 1] */ | ||
317 | /* See if the system call number is valid. */ | ||
318 | addi r11, r12, -__NR_syscalls; | ||
319 | bgei r11,1f; | ||
320 | /* Figure out which function to use for this system call. */ | ||
321 | /* Note Microblaze barrel shift is optional, so don't rely on it */ | ||
322 | add r12, r12, r12; /* convert num -> ptr */ | ||
323 | add r12, r12, r12; | ||
324 | |||
325 | /* Trac syscalls and stored them to r0_ram */ | ||
326 | lwi r3, r12, 0x400 + TOPHYS(r0_ram) | ||
327 | addi r3, r3, 1 | ||
328 | swi r3, r12, 0x400 + TOPHYS(r0_ram) | ||
329 | |||
330 | lwi r12, r12, TOPHYS(sys_call_table); /* Function ptr */ | ||
331 | /* Make the system call. to r12*/ | ||
332 | set_vms; | ||
333 | rtid r12, 0; | ||
334 | nop; | ||
335 | /* The syscall number is invalid, return an error. */ | ||
336 | 1: VM_ON; /* RETURN() expects virtual mode*/ | ||
337 | addi r3, r0, -ENOSYS; | ||
338 | rtsd r15,8; /* looks like a normal subroutine return */ | ||
339 | or r0, r0, r0 | ||
340 | |||
341 | |||
342 | /* Entry point used to return from a syscall/trap. */ | ||
343 | /* We re-enable BIP bit before state restore */ | ||
344 | C_ENTRY(ret_from_trap): | ||
345 | set_bip; /* Ints masked for state restore*/ | ||
346 | lwi r11, r1, PTO+PT_MODE; | ||
347 | /* See if returning to kernel mode, if so, skip resched &c. */ | ||
348 | bnei r11, 2f; | ||
349 | |||
350 | /* We're returning to user mode, so check for various conditions that | ||
351 | * trigger rescheduling. */ | ||
352 | /* Get current task ptr into r11 */ | ||
353 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
354 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ | ||
355 | lwi r11, r11, TI_FLAGS; /* get flags in thread info */ | ||
356 | andi r11, r11, _TIF_NEED_RESCHED; | ||
357 | beqi r11, 5f; | ||
358 | |||
359 | swi r3, r1, PTO + PT_R3; /* store syscall result */ | ||
360 | swi r4, r1, PTO + PT_R4; | ||
361 | bralid r15, schedule; /* Call scheduler */ | ||
362 | nop; /* delay slot */ | ||
363 | lwi r3, r1, PTO + PT_R3; /* restore syscall result */ | ||
364 | lwi r4, r1, PTO + PT_R4; | ||
365 | |||
366 | /* Maybe handle a signal */ | ||
367 | 5: add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
368 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ | ||
369 | lwi r11, r11, TI_FLAGS; /* get flags in thread info */ | ||
370 | andi r11, r11, _TIF_SIGPENDING; | ||
371 | beqi r11, 1f; /* Signals to handle, handle them */ | ||
372 | |||
373 | swi r3, r1, PTO + PT_R3; /* store syscall result */ | ||
374 | swi r4, r1, PTO + PT_R4; | ||
375 | la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ | ||
376 | add r6, r0, r0; /* Arg 2: sigset_t *oldset */ | ||
377 | addi r7, r0, 1; /* Arg 3: int in_syscall */ | ||
378 | bralid r15, do_signal; /* Handle any signals */ | ||
379 | nop; | ||
380 | lwi r3, r1, PTO + PT_R3; /* restore syscall result */ | ||
381 | lwi r4, r1, PTO + PT_R4; | ||
382 | |||
383 | /* Finally, return to user state. */ | ||
384 | 1: swi r0, r0, PER_CPU(KM); /* Now officially in user state. */ | ||
385 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
386 | swi r11, r0, PER_CPU(CURRENT_SAVE); /* save current */ | ||
387 | VM_OFF; | ||
388 | tophys(r1,r1); | ||
389 | RESTORE_REGS; | ||
390 | addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ | ||
391 | lwi r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */ | ||
392 | bri 6f; | ||
393 | |||
394 | /* Return to kernel state. */ | ||
395 | 2: VM_OFF; | ||
396 | tophys(r1,r1); | ||
397 | RESTORE_REGS; | ||
398 | addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ | ||
399 | tovirt(r1,r1); | ||
400 | 6: | ||
401 | TRAP_return: /* Make global symbol for debugging */ | ||
402 | rtbd r14, 0; /* Instructions to return from an IRQ */ | ||
403 | nop; | ||
404 | |||
405 | |||
406 | /* These syscalls need access to the struct pt_regs on the stack, so we | ||
407 | implement them in assembly (they're basically all wrappers anyway). */ | ||
408 | |||
409 | C_ENTRY(sys_fork_wrapper): | ||
410 | addi r5, r0, SIGCHLD /* Arg 0: flags */ | ||
411 | lwi r6, r1, PTO+PT_R1 /* Arg 1: child SP (use parent's) */ | ||
412 | la r7, r1, PTO /* Arg 2: parent context */ | ||
413 | add r8. r0, r0 /* Arg 3: (unused) */ | ||
414 | add r9, r0, r0; /* Arg 4: (unused) */ | ||
415 | add r10, r0, r0; /* Arg 5: (unused) */ | ||
416 | brid do_fork /* Do real work (tail-call) */ | ||
417 | nop; | ||
418 | |||
419 | /* This the initial entry point for a new child thread, with an appropriate | ||
420 | stack in place that makes it look the the child is in the middle of an | ||
421 | syscall. This function is actually `returned to' from switch_thread | ||
422 | (copy_thread makes ret_from_fork the return address in each new thread's | ||
423 | saved context). */ | ||
424 | C_ENTRY(ret_from_fork): | ||
425 | bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ | ||
426 | add r3, r5, r0; /* switch_thread returns the prev task */ | ||
427 | /* ( in the delay slot ) */ | ||
428 | add r3, r0, r0; /* Child's fork call should return 0. */ | ||
429 | brid ret_from_trap; /* Do normal trap return */ | ||
430 | nop; | ||
431 | |||
432 | C_ENTRY(sys_vfork_wrapper): | ||
433 | la r5, r1, PTO | ||
434 | brid sys_vfork /* Do real work (tail-call) */ | ||
435 | nop | ||
436 | |||
437 | C_ENTRY(sys_clone_wrapper): | ||
438 | bnei r6, 1f; /* See if child SP arg (arg 1) is 0. */ | ||
439 | lwi r6, r1, PTO+PT_R1; /* If so, use paret's stack ptr */ | ||
440 | 1: la r7, r1, PTO; /* Arg 2: parent context */ | ||
441 | add r8, r0, r0; /* Arg 3: (unused) */ | ||
442 | add r9, r0, r0; /* Arg 4: (unused) */ | ||
443 | add r10, r0, r0; /* Arg 5: (unused) */ | ||
444 | brid do_fork /* Do real work (tail-call) */ | ||
445 | nop; | ||
446 | |||
447 | C_ENTRY(sys_execve_wrapper): | ||
448 | la r8, r1, PTO; /* add user context as 4th arg */ | ||
449 | brid sys_execve; /* Do real work (tail-call).*/ | ||
450 | nop; | ||
451 | |||
452 | C_ENTRY(sys_sigsuspend_wrapper): | ||
453 | swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
454 | swi r4, r1, PTO+PT_R4; | ||
455 | la r6, r1, PTO; /* add user context as 2nd arg */ | ||
456 | bralid r15, sys_sigsuspend; /* Do real work.*/ | ||
457 | nop; | ||
458 | lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
459 | lwi r4, r1, PTO+PT_R4; | ||
460 | bri ret_from_trap /* fall through will not work here due to align */ | ||
461 | nop; | ||
462 | |||
463 | C_ENTRY(sys_rt_sigsuspend_wrapper): | ||
464 | swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
465 | swi r4, r1, PTO+PT_R4; | ||
466 | la r7, r1, PTO; /* add user context as 3rd arg */ | ||
467 | brlid r15, sys_rt_sigsuspend; /* Do real work.*/ | ||
468 | nop; | ||
469 | lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
470 | lwi r4, r1, PTO+PT_R4; | ||
471 | bri ret_from_trap /* fall through will not work here due to align */ | ||
472 | nop; | ||
473 | |||
474 | |||
475 | C_ENTRY(sys_sigreturn_wrapper): | ||
476 | swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
477 | swi r4, r1, PTO+PT_R4; | ||
478 | la r5, r1, PTO; /* add user context as 1st arg */ | ||
479 | brlid r15, sys_sigreturn; /* Do real work.*/ | ||
480 | nop; | ||
481 | lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
482 | lwi r4, r1, PTO+PT_R4; | ||
483 | bri ret_from_trap /* fall through will not work here due to align */ | ||
484 | nop; | ||
485 | |||
486 | C_ENTRY(sys_rt_sigreturn_wrapper): | ||
487 | swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
488 | swi r4, r1, PTO+PT_R4; | ||
489 | la r5, r1, PTO; /* add user context as 1st arg */ | ||
490 | brlid r15, sys_rt_sigreturn /* Do real work */ | ||
491 | nop; | ||
492 | lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
493 | lwi r4, r1, PTO+PT_R4; | ||
494 | bri ret_from_trap /* fall through will not work here due to align */ | ||
495 | nop; | ||
496 | |||
497 | /* | ||
498 | * HW EXCEPTION rutine start | ||
499 | */ | ||
500 | |||
501 | #define SAVE_STATE \ | ||
502 | swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ \ | ||
503 | set_bip; /*equalize initial state for all possible entries*/\ | ||
504 | clear_eip; \ | ||
505 | enable_irq; \ | ||
506 | set_ee; \ | ||
507 | /* See if already in kernel mode.*/ \ | ||
508 | lwi r11, r0, TOPHYS(PER_CPU(KM)); \ | ||
509 | beqi r11, 1f; /* Jump ahead if coming from user */\ | ||
510 | /* Kernel-mode state save. */ \ | ||
511 | /* Reload kernel stack-ptr. */ \ | ||
512 | lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ | ||
513 | tophys(r1,r11); \ | ||
514 | swi r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */ \ | ||
515 | lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\ | ||
516 | addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ | ||
517 | /* store return registers separately because \ | ||
518 | * this macros is use for others exceptions */ \ | ||
519 | swi r3, r1, PTO + PT_R3; \ | ||
520 | swi r4, r1, PTO + PT_R4; \ | ||
521 | SAVE_REGS \ | ||
522 | /* PC, before IRQ/trap - this is one instruction above */ \ | ||
523 | swi r17, r1, PTO+PT_PC; \ | ||
524 | \ | ||
525 | addi r11, r0, 1; /* Was in kernel-mode. */ \ | ||
526 | swi r11, r1, PTO+PT_MODE; \ | ||
527 | brid 2f; \ | ||
528 | nop; /* Fill delay slot */ \ | ||
529 | 1: /* User-mode state save. */ \ | ||
530 | lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\ | ||
531 | lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\ | ||
532 | tophys(r1,r1); \ | ||
533 | lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \ | ||
534 | addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */\ | ||
535 | tophys(r1,r1); \ | ||
536 | \ | ||
537 | addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ | ||
538 | /* store return registers separately because this macros \ | ||
539 | * is use for others exceptions */ \ | ||
540 | swi r3, r1, PTO + PT_R3; \ | ||
541 | swi r4, r1, PTO + PT_R4; \ | ||
542 | SAVE_REGS \ | ||
543 | /* PC, before IRQ/trap - this is one instruction above FIXME*/ \ | ||
544 | swi r17, r1, PTO+PT_PC; \ | ||
545 | \ | ||
546 | swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ \ | ||
547 | lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ | ||
548 | swi r11, r1, PTO+PT_R1; /* Store user SP. */ \ | ||
549 | addi r11, r0, 1; \ | ||
550 | swi r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode.*/\ | ||
551 | 2: lwi r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\ | ||
552 | /* Save away the syscall number. */ \ | ||
553 | swi r0, r1, PTO+PT_R0; \ | ||
554 | tovirt(r1,r1) | ||
555 | |||
556 | C_ENTRY(full_exception_trap): | ||
557 | swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ | ||
558 | /* adjust exception address for privileged instruction | ||
559 | * for finding where is it */ | ||
560 | addik r17, r17, -4 | ||
561 | SAVE_STATE /* Save registers */ | ||
562 | /* FIXME this can be store directly in PT_ESR reg. | ||
563 | * I tested it but there is a fault */ | ||
564 | /* where the trap should return need -8 to adjust for rtsd r15, 8 */ | ||
565 | la r15, r0, ret_from_exc - 8 | ||
566 | la r5, r1, PTO /* parameter struct pt_regs * regs */ | ||
567 | mfs r6, resr | ||
568 | nop | ||
569 | mfs r7, rfsr; /* save FSR */ | ||
570 | nop | ||
571 | la r12, r0, full_exception | ||
572 | set_vms; | ||
573 | rtbd r12, 0; | ||
574 | nop; | ||
575 | |||
576 | /* | ||
577 | * Unaligned data trap. | ||
578 | * | ||
579 | * Unaligned data trap last on 4k page is handled here. | ||
580 | * | ||
581 | * Trap entered via exception, so EE bit is set, and interrupts | ||
582 | * are masked. This is nice, means we don't have to CLI before state save | ||
583 | * | ||
584 | * The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S" | ||
585 | */ | ||
586 | C_ENTRY(unaligned_data_trap): | ||
587 | swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ | ||
588 | SAVE_STATE /* Save registers.*/ | ||
589 | /* where the trap should return need -8 to adjust for rtsd r15, 8 */ | ||
590 | la r15, r0, ret_from_exc-8 | ||
591 | mfs r3, resr /* ESR */ | ||
592 | nop | ||
593 | mfs r4, rear /* EAR */ | ||
594 | nop | ||
595 | la r7, r1, PTO /* parameter struct pt_regs * regs */ | ||
596 | la r12, r0, _unaligned_data_exception | ||
597 | set_vms; | ||
598 | rtbd r12, 0; /* interrupts enabled */ | ||
599 | nop; | ||
600 | |||
601 | /* | ||
602 | * Page fault traps. | ||
603 | * | ||
604 | * If the real exception handler (from hw_exception_handler.S) didn't find | ||
605 | * the mapping for the process, then we're thrown here to handle such situation. | ||
606 | * | ||
607 | * Trap entered via exceptions, so EE bit is set, and interrupts | ||
608 | * are masked. This is nice, means we don't have to CLI before state save | ||
609 | * | ||
610 | * Build a standard exception frame for TLB Access errors. All TLB exceptions | ||
611 | * will bail out to this point if they can't resolve the lightweight TLB fault. | ||
612 | * | ||
613 | * The C function called is in "arch/microblaze/mm/fault.c", declared as: | ||
614 | * void do_page_fault(struct pt_regs *regs, | ||
615 | * unsigned long address, | ||
616 | * unsigned long error_code) | ||
617 | */ | ||
618 | /* data and intruction trap - which is choose is resolved int fault.c */ | ||
619 | C_ENTRY(page_fault_data_trap): | ||
620 | swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ | ||
621 | SAVE_STATE /* Save registers.*/ | ||
622 | /* where the trap should return need -8 to adjust for rtsd r15, 8 */ | ||
623 | la r15, r0, ret_from_exc-8 | ||
624 | la r5, r1, PTO /* parameter struct pt_regs * regs */ | ||
625 | mfs r6, rear /* parameter unsigned long address */ | ||
626 | nop | ||
627 | mfs r7, resr /* parameter unsigned long error_code */ | ||
628 | nop | ||
629 | la r12, r0, do_page_fault | ||
630 | set_vms; | ||
631 | rtbd r12, 0; /* interrupts enabled */ | ||
632 | nop; | ||
633 | |||
634 | C_ENTRY(page_fault_instr_trap): | ||
635 | swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ | ||
636 | SAVE_STATE /* Save registers.*/ | ||
637 | /* where the trap should return need -8 to adjust for rtsd r15, 8 */ | ||
638 | la r15, r0, ret_from_exc-8 | ||
639 | la r5, r1, PTO /* parameter struct pt_regs * regs */ | ||
640 | mfs r6, rear /* parameter unsigned long address */ | ||
641 | nop | ||
642 | ori r7, r0, 0 /* parameter unsigned long error_code */ | ||
643 | la r12, r0, do_page_fault | ||
644 | set_vms; | ||
645 | rtbd r12, 0; /* interrupts enabled */ | ||
646 | nop; | ||
647 | |||
648 | /* Entry point used to return from an exception. */ | ||
649 | C_ENTRY(ret_from_exc): | ||
650 | set_bip; /* Ints masked for state restore*/ | ||
651 | lwi r11, r1, PTO+PT_MODE; | ||
652 | bnei r11, 2f; /* See if returning to kernel mode, */ | ||
653 | /* ... if so, skip resched &c. */ | ||
654 | |||
655 | /* We're returning to user mode, so check for various conditions that | ||
656 | trigger rescheduling. */ | ||
657 | /* Get current task ptr into r11 */ | ||
658 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
659 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ | ||
660 | lwi r11, r11, TI_FLAGS; /* get flags in thread info */ | ||
661 | andi r11, r11, _TIF_NEED_RESCHED; | ||
662 | beqi r11, 5f; | ||
663 | |||
664 | /* Call the scheduler before returning from a syscall/trap. */ | ||
665 | bralid r15, schedule; /* Call scheduler */ | ||
666 | nop; /* delay slot */ | ||
667 | |||
668 | /* Maybe handle a signal */ | ||
669 | 5: add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
670 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ | ||
671 | lwi r11, r11, TI_FLAGS; /* get flags in thread info */ | ||
672 | andi r11, r11, _TIF_SIGPENDING; | ||
673 | beqi r11, 1f; /* Signals to handle, handle them */ | ||
674 | |||
675 | /* | ||
676 | * Handle a signal return; Pending signals should be in r18. | ||
677 | * | ||
678 | * Not all registers are saved by the normal trap/interrupt entry | ||
679 | * points (for instance, call-saved registers (because the normal | ||
680 | * C-compiler calling sequence in the kernel makes sure they're | ||
681 | * preserved), and call-clobbered registers in the case of | ||
682 | * traps), but signal handlers may want to examine or change the | ||
683 | * complete register state. Here we save anything not saved by | ||
684 | * the normal entry sequence, so that it may be safely restored | ||
685 | * (in a possibly modified form) after do_signal returns. | ||
686 | * store return registers separately because this macros is use | ||
687 | * for others exceptions */ | ||
688 | swi r3, r1, PTO + PT_R3; | ||
689 | swi r4, r1, PTO + PT_R4; | ||
690 | la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ | ||
691 | add r6, r0, r0; /* Arg 2: sigset_t *oldset */ | ||
692 | addi r7, r0, 0; /* Arg 3: int in_syscall */ | ||
693 | bralid r15, do_signal; /* Handle any signals */ | ||
694 | nop; | ||
695 | lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
696 | lwi r4, r1, PTO+PT_R4; | ||
697 | |||
698 | /* Finally, return to user state. */ | ||
699 | 1: swi r0, r0, PER_CPU(KM); /* Now officially in user state. */ | ||
700 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
701 | swi r11, r0, PER_CPU(CURRENT_SAVE); /* save current */ | ||
702 | VM_OFF; | ||
703 | tophys(r1,r1); | ||
704 | |||
705 | lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
706 | lwi r4, r1, PTO+PT_R4; | ||
707 | RESTORE_REGS; | ||
708 | addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ | ||
709 | |||
710 | lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */ | ||
711 | bri 6f; | ||
712 | /* Return to kernel state. */ | ||
713 | 2: VM_OFF; | ||
714 | tophys(r1,r1); | ||
715 | lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
716 | lwi r4, r1, PTO+PT_R4; | ||
717 | RESTORE_REGS; | ||
718 | addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ | ||
719 | |||
720 | tovirt(r1,r1); | ||
721 | 6: | ||
722 | EXC_return: /* Make global symbol for debugging */ | ||
723 | rtbd r14, 0; /* Instructions to return from an IRQ */ | ||
724 | nop; | ||
725 | |||
726 | /* | ||
727 | * HW EXCEPTION rutine end | ||
728 | */ | ||
729 | |||
730 | /* | ||
731 | * Hardware maskable interrupts. | ||
732 | * | ||
733 | * The stack-pointer (r1) should have already been saved to the memory | ||
734 | * location PER_CPU(ENTRY_SP). | ||
735 | */ | ||
736 | C_ENTRY(_interrupt): | ||
737 | /* MS: we are in physical address */ | ||
738 | /* Save registers, switch to proper stack, convert SP to virtual.*/ | ||
739 | swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) | ||
740 | swi r11, r0, TOPHYS(PER_CPU(R11_SAVE)); | ||
741 | /* MS: See if already in kernel mode. */ | ||
742 | lwi r11, r0, TOPHYS(PER_CPU(KM)); | ||
743 | beqi r11, 1f; /* MS: Jump ahead if coming from user */ | ||
744 | |||
745 | /* Kernel-mode state save. */ | ||
746 | or r11, r1, r0 | ||
747 | tophys(r1,r11); /* MS: I have in r1 physical address where stack is */ | ||
748 | /* MS: Save original SP - position PT_R1 to next stack frame 4 *1 - 152*/ | ||
749 | swi r11, r1, (PT_R1 - PT_SIZE); | ||
750 | /* MS: restore r11 because of saving in SAVE_REGS */ | ||
751 | lwi r11, r0, TOPHYS(PER_CPU(R11_SAVE)); | ||
752 | /* save registers */ | ||
753 | /* MS: Make room on the stack -> activation record */ | ||
754 | addik r1, r1, -STATE_SAVE_SIZE; | ||
755 | /* MS: store return registers separately because | ||
756 | * this macros is use for others exceptions */ | ||
757 | swi r3, r1, PTO + PT_R3; | ||
758 | swi r4, r1, PTO + PT_R4; | ||
759 | SAVE_REGS | ||
760 | /* MS: store mode */ | ||
761 | addi r11, r0, 1; /* MS: Was in kernel-mode. */ | ||
762 | swi r11, r1, PTO + PT_MODE; /* MS: and save it */ | ||
763 | brid 2f; | ||
764 | nop; /* MS: Fill delay slot */ | ||
765 | |||
766 | 1: | ||
767 | /* User-mode state save. */ | ||
768 | /* MS: restore r11 -> FIXME move before SAVE_REG */ | ||
769 | lwi r11, r0, TOPHYS(PER_CPU(R11_SAVE)); | ||
770 | /* MS: get the saved current */ | ||
771 | lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); | ||
772 | tophys(r1,r1); | ||
773 | lwi r1, r1, TS_THREAD_INFO; | ||
774 | addik r1, r1, THREAD_SIZE; | ||
775 | tophys(r1,r1); | ||
776 | /* save registers */ | ||
777 | addik r1, r1, -STATE_SAVE_SIZE; | ||
778 | swi r3, r1, PTO+PT_R3; | ||
779 | swi r4, r1, PTO+PT_R4; | ||
780 | SAVE_REGS | ||
781 | /* calculate mode */ | ||
782 | swi r0, r1, PTO + PT_MODE; | ||
783 | lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); | ||
784 | swi r11, r1, PTO+PT_R1; | ||
785 | /* setup kernel mode to KM */ | ||
786 | addi r11, r0, 1; | ||
787 | swi r11, r0, TOPHYS(PER_CPU(KM)); | ||
788 | |||
789 | 2: | ||
790 | lwi r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); | ||
791 | swi r0, r1, PTO + PT_R0; | ||
792 | tovirt(r1,r1) | ||
793 | la r5, r1, PTO; | ||
794 | set_vms; | ||
795 | la r11, r0, do_IRQ; | ||
796 | la r15, r0, irq_call; | ||
797 | irq_call:rtbd r11, 0; | ||
798 | nop; | ||
799 | |||
800 | /* MS: we are in virtual mode */ | ||
801 | ret_from_irq: | ||
802 | lwi r11, r1, PTO + PT_MODE; | ||
803 | bnei r11, 2f; | ||
804 | |||
805 | add r11, r0, CURRENT_TASK; | ||
806 | lwi r11, r11, TS_THREAD_INFO; | ||
807 | lwi r11, r11, TI_FLAGS; /* MS: get flags from thread info */ | ||
808 | andi r11, r11, _TIF_NEED_RESCHED; | ||
809 | beqi r11, 5f | ||
810 | bralid r15, schedule; | ||
811 | nop; /* delay slot */ | ||
812 | |||
813 | /* Maybe handle a signal */ | ||
814 | 5: add r11, r0, CURRENT_TASK; | ||
815 | lwi r11, r11, TS_THREAD_INFO; /* MS: get thread info */ | ||
816 | lwi r11, r11, TI_FLAGS; /* get flags in thread info */ | ||
817 | andi r11, r11, _TIF_SIGPENDING; | ||
818 | beqid r11, no_intr_resched | ||
819 | /* Handle a signal return; Pending signals should be in r18. */ | ||
820 | addi r7, r0, 0; /* Arg 3: int in_syscall */ | ||
821 | la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ | ||
822 | bralid r15, do_signal; /* Handle any signals */ | ||
823 | add r6, r0, r0; /* Arg 2: sigset_t *oldset */ | ||
824 | |||
825 | /* Finally, return to user state. */ | ||
826 | no_intr_resched: | ||
827 | /* Disable interrupts, we are now committed to the state restore */ | ||
828 | disable_irq | ||
829 | swi r0, r0, PER_CPU(KM); /* MS: Now officially in user state. */ | ||
830 | add r11, r0, CURRENT_TASK; | ||
831 | swi r11, r0, PER_CPU(CURRENT_SAVE); | ||
832 | VM_OFF; | ||
833 | tophys(r1,r1); | ||
834 | lwi r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */ | ||
835 | lwi r4, r1, PTO + PT_R4; | ||
836 | RESTORE_REGS | ||
837 | addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */ | ||
838 | lwi r1, r1, PT_R1 - PT_SIZE; | ||
839 | bri 6f; | ||
840 | /* MS: Return to kernel state. */ | ||
841 | 2: VM_OFF /* MS: turn off MMU */ | ||
842 | tophys(r1,r1) | ||
843 | lwi r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */ | ||
844 | lwi r4, r1, PTO + PT_R4; | ||
845 | RESTORE_REGS | ||
846 | addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */ | ||
847 | tovirt(r1,r1); | ||
848 | 6: | ||
849 | IRQ_return: /* MS: Make global symbol for debugging */ | ||
850 | rtid r14, 0 | ||
851 | nop | ||
852 | |||
853 | /* | ||
854 | * `Debug' trap | ||
855 | * We enter dbtrap in "BIP" (breakpoint) mode. | ||
856 | * So we exit the breakpoint mode with an 'rtbd' and proceed with the | ||
857 | * original dbtrap. | ||
858 | * however, wait to save state first | ||
859 | */ | ||
860 | C_ENTRY(_debug_exception): | ||
861 | /* BIP bit is set on entry, no interrupts can occur */ | ||
862 | swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) | ||
863 | |||
864 | swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ | ||
865 | set_bip; /*equalize initial state for all possible entries*/ | ||
866 | clear_eip; | ||
867 | enable_irq; | ||
868 | lwi r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/ | ||
869 | beqi r11, 1f; /* Jump ahead if coming from user */ | ||
870 | /* Kernel-mode state save. */ | ||
871 | lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ | ||
872 | tophys(r1,r11); | ||
873 | swi r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */ | ||
874 | lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */ | ||
875 | |||
876 | addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ | ||
877 | swi r3, r1, PTO + PT_R3; | ||
878 | swi r4, r1, PTO + PT_R4; | ||
879 | SAVE_REGS; | ||
880 | |||
881 | addi r11, r0, 1; /* Was in kernel-mode. */ | ||
882 | swi r11, r1, PTO + PT_MODE; | ||
883 | brid 2f; | ||
884 | nop; /* Fill delay slot */ | ||
885 | 1: /* User-mode state save. */ | ||
886 | lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */ | ||
887 | lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ | ||
888 | tophys(r1,r1); | ||
889 | lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ | ||
890 | addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */ | ||
891 | tophys(r1,r1); | ||
892 | |||
893 | addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ | ||
894 | swi r3, r1, PTO + PT_R3; | ||
895 | swi r4, r1, PTO + PT_R4; | ||
896 | SAVE_REGS; | ||
897 | |||
898 | swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ | ||
899 | lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); | ||
900 | swi r11, r1, PTO+PT_R1; /* Store user SP. */ | ||
901 | addi r11, r0, 1; | ||
902 | swi r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode. */ | ||
903 | 2: lwi r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ | ||
904 | /* Save away the syscall number. */ | ||
905 | swi r0, r1, PTO+PT_R0; | ||
906 | tovirt(r1,r1) | ||
907 | |||
908 | addi r5, r0, SIGTRAP /* send the trap signal */ | ||
909 | add r6, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
910 | addk r7, r0, r0 /* 3rd param zero */ | ||
911 | |||
912 | set_vms; | ||
913 | la r11, r0, send_sig; | ||
914 | la r15, r0, dbtrap_call; | ||
915 | dbtrap_call: rtbd r11, 0; | ||
916 | nop; | ||
917 | |||
918 | set_bip; /* Ints masked for state restore*/ | ||
919 | lwi r11, r1, PTO+PT_MODE; | ||
920 | bnei r11, 2f; | ||
921 | |||
922 | /* Get current task ptr into r11 */ | ||
923 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
924 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ | ||
925 | lwi r11, r11, TI_FLAGS; /* get flags in thread info */ | ||
926 | andi r11, r11, _TIF_NEED_RESCHED; | ||
927 | beqi r11, 5f; | ||
928 | |||
929 | /* Call the scheduler before returning from a syscall/trap. */ | ||
930 | |||
931 | bralid r15, schedule; /* Call scheduler */ | ||
932 | nop; /* delay slot */ | ||
933 | /* XXX Is PT_DTRACE handling needed here? */ | ||
934 | /* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here. */ | ||
935 | |||
936 | /* Maybe handle a signal */ | ||
937 | 5: add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
938 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ | ||
939 | lwi r11, r11, TI_FLAGS; /* get flags in thread info */ | ||
940 | andi r11, r11, _TIF_SIGPENDING; | ||
941 | beqi r11, 1f; /* Signals to handle, handle them */ | ||
942 | |||
943 | /* Handle a signal return; Pending signals should be in r18. */ | ||
944 | /* Not all registers are saved by the normal trap/interrupt entry | ||
945 | points (for instance, call-saved registers (because the normal | ||
946 | C-compiler calling sequence in the kernel makes sure they're | ||
947 | preserved), and call-clobbered registers in the case of | ||
948 | traps), but signal handlers may want to examine or change the | ||
949 | complete register state. Here we save anything not saved by | ||
950 | the normal entry sequence, so that it may be safely restored | ||
951 | (in a possibly modified form) after do_signal returns. */ | ||
952 | |||
953 | la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ | ||
954 | add r6, r0, r0; /* Arg 2: sigset_t *oldset */ | ||
955 | addi r7, r0, 0; /* Arg 3: int in_syscall */ | ||
956 | bralid r15, do_signal; /* Handle any signals */ | ||
957 | nop; | ||
958 | |||
959 | |||
960 | /* Finally, return to user state. */ | ||
961 | 1: swi r0, r0, PER_CPU(KM); /* Now officially in user state. */ | ||
962 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
963 | swi r11, r0, PER_CPU(CURRENT_SAVE); /* save current */ | ||
964 | VM_OFF; | ||
965 | tophys(r1,r1); | ||
966 | |||
967 | lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
968 | lwi r4, r1, PTO+PT_R4; | ||
969 | RESTORE_REGS | ||
970 | addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ | ||
971 | |||
972 | |||
973 | lwi r1, r1, PT_R1 - PT_SIZE; | ||
974 | /* Restore user stack pointer. */ | ||
975 | bri 6f; | ||
976 | |||
977 | /* Return to kernel state. */ | ||
978 | 2: VM_OFF; | ||
979 | tophys(r1,r1); | ||
980 | lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
981 | lwi r4, r1, PTO+PT_R4; | ||
982 | RESTORE_REGS | ||
983 | addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ | ||
984 | |||
985 | tovirt(r1,r1); | ||
986 | 6: | ||
987 | DBTRAP_return: /* Make global symbol for debugging */ | ||
988 | rtbd r14, 0; /* Instructions to return from an IRQ */ | ||
989 | nop; | ||
990 | |||
991 | |||
992 | |||
993 | ENTRY(_switch_to) | ||
994 | /* prepare return value */ | ||
995 | addk r3, r0, r31 | ||
996 | |||
997 | /* save registers in cpu_context */ | ||
998 | /* use r11 and r12, volatile registers, as temp register */ | ||
999 | /* give start of cpu_context for previous process */ | ||
1000 | addik r11, r5, TI_CPU_CONTEXT | ||
1001 | swi r1, r11, CC_R1 | ||
1002 | swi r2, r11, CC_R2 | ||
1003 | /* skip volatile registers. | ||
1004 | * they are saved on stack when we jumped to _switch_to() */ | ||
1005 | /* dedicated registers */ | ||
1006 | swi r13, r11, CC_R13 | ||
1007 | swi r14, r11, CC_R14 | ||
1008 | swi r15, r11, CC_R15 | ||
1009 | swi r16, r11, CC_R16 | ||
1010 | swi r17, r11, CC_R17 | ||
1011 | swi r18, r11, CC_R18 | ||
1012 | /* save non-volatile registers */ | ||
1013 | swi r19, r11, CC_R19 | ||
1014 | swi r20, r11, CC_R20 | ||
1015 | swi r21, r11, CC_R21 | ||
1016 | swi r22, r11, CC_R22 | ||
1017 | swi r23, r11, CC_R23 | ||
1018 | swi r24, r11, CC_R24 | ||
1019 | swi r25, r11, CC_R25 | ||
1020 | swi r26, r11, CC_R26 | ||
1021 | swi r27, r11, CC_R27 | ||
1022 | swi r28, r11, CC_R28 | ||
1023 | swi r29, r11, CC_R29 | ||
1024 | swi r30, r11, CC_R30 | ||
1025 | /* special purpose registers */ | ||
1026 | mfs r12, rmsr | ||
1027 | nop | ||
1028 | swi r12, r11, CC_MSR | ||
1029 | mfs r12, rear | ||
1030 | nop | ||
1031 | swi r12, r11, CC_EAR | ||
1032 | mfs r12, resr | ||
1033 | nop | ||
1034 | swi r12, r11, CC_ESR | ||
1035 | mfs r12, rfsr | ||
1036 | nop | ||
1037 | swi r12, r11, CC_FSR | ||
1038 | |||
1039 | /* update r31, the current */ | ||
1040 | lwi r31, r6, TI_TASK/* give me pointer to task which will be next */ | ||
1041 | /* stored it to current_save too */ | ||
1042 | swi r31, r0, PER_CPU(CURRENT_SAVE) | ||
1043 | |||
1044 | /* get new process' cpu context and restore */ | ||
1045 | /* give me start where start context of next task */ | ||
1046 | addik r11, r6, TI_CPU_CONTEXT | ||
1047 | |||
1048 | /* non-volatile registers */ | ||
1049 | lwi r30, r11, CC_R30 | ||
1050 | lwi r29, r11, CC_R29 | ||
1051 | lwi r28, r11, CC_R28 | ||
1052 | lwi r27, r11, CC_R27 | ||
1053 | lwi r26, r11, CC_R26 | ||
1054 | lwi r25, r11, CC_R25 | ||
1055 | lwi r24, r11, CC_R24 | ||
1056 | lwi r23, r11, CC_R23 | ||
1057 | lwi r22, r11, CC_R22 | ||
1058 | lwi r21, r11, CC_R21 | ||
1059 | lwi r20, r11, CC_R20 | ||
1060 | lwi r19, r11, CC_R19 | ||
1061 | /* dedicated registers */ | ||
1062 | lwi r18, r11, CC_R18 | ||
1063 | lwi r17, r11, CC_R17 | ||
1064 | lwi r16, r11, CC_R16 | ||
1065 | lwi r15, r11, CC_R15 | ||
1066 | lwi r14, r11, CC_R14 | ||
1067 | lwi r13, r11, CC_R13 | ||
1068 | /* skip volatile registers */ | ||
1069 | lwi r2, r11, CC_R2 | ||
1070 | lwi r1, r11, CC_R1 | ||
1071 | |||
1072 | /* special purpose registers */ | ||
1073 | lwi r12, r11, CC_FSR | ||
1074 | mts rfsr, r12 | ||
1075 | nop | ||
1076 | lwi r12, r11, CC_MSR | ||
1077 | mts rmsr, r12 | ||
1078 | nop | ||
1079 | |||
1080 | rtsd r15, 8 | ||
1081 | nop | ||
1082 | |||
1083 | ENTRY(_reset) | ||
1084 | brai 0x70; /* Jump back to FS-boot */ | ||
1085 | |||
1086 | ENTRY(_break) | ||
1087 | mfs r5, rmsr | ||
1088 | nop | ||
1089 | swi r5, r0, 0x250 + TOPHYS(r0_ram) | ||
1090 | mfs r5, resr | ||
1091 | nop | ||
1092 | swi r5, r0, 0x254 + TOPHYS(r0_ram) | ||
1093 | bri 0 | ||
1094 | |||
1095 | /* These are compiled and loaded into high memory, then | ||
1096 | * copied into place in mach_early_setup */ | ||
1097 | .section .init.ivt, "ax" | ||
1098 | .org 0x0 | ||
1099 | /* this is very important - here is the reset vector */ | ||
1100 | /* in current MMU branch you don't care what is here - it is | ||
1101 | * used from bootloader site - but this is correct for FS-BOOT */ | ||
1102 | brai 0x70 | ||
1103 | nop | ||
1104 | brai TOPHYS(_user_exception); /* syscall handler */ | ||
1105 | brai TOPHYS(_interrupt); /* Interrupt handler */ | ||
1106 | brai TOPHYS(_break); /* nmi trap handler */ | ||
1107 | brai TOPHYS(_hw_exception_handler); /* HW exception handler */ | ||
1108 | |||
1109 | .org 0x60 | ||
1110 | brai TOPHYS(_debug_exception); /* debug trap handler*/ | ||
1111 | |||
1112 | .section .rodata,"a" | ||
1113 | #include "syscall_table.S" | ||
1114 | |||
1115 | syscall_table_size=(.-sys_call_table) | ||
1116 | |||