blob: 9b8e072d828df8dd6fe8ed057c3d026e8203d353 [file] [log] [blame]
Michal Simekca545022009-05-26 16:30:21 +02001/*
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
Michal Simek11d51362009-12-07 08:21:34 +010034#undef DEBUG
35
Michal Simekca545022009-05-26 16:30:21 +020036/* The size of a state save frame. */
37#define STATE_SAVE_SIZE (PT_SIZE + STATE_SAVE_ARG_SPACE)
38
39/* The offset of the struct pt_regs in a `state save frame' on the stack. */
40#define PTO STATE_SAVE_ARG_SPACE /* 24 the space for args */
41
42#define C_ENTRY(name) .globl name; .align 4; name
43
44/*
45 * Various ways of setting and clearing BIP in flags reg.
46 * This is mucky, but necessary using microblaze version that
47 * allows msr ops to write to BIP
48 */
49#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
50 .macro clear_bip
51 msrclr r11, MSR_BIP
52 nop
53 .endm
54
55 .macro set_bip
56 msrset r11, MSR_BIP
57 nop
58 .endm
59
60 .macro clear_eip
61 msrclr r11, MSR_EIP
62 nop
63 .endm
64
65 .macro set_ee
66 msrset r11, MSR_EE
67 nop
68 .endm
69
70 .macro disable_irq
71 msrclr r11, MSR_IE
72 nop
73 .endm
74
75 .macro enable_irq
76 msrset r11, MSR_IE
77 nop
78 .endm
79
80 .macro set_ums
81 msrset r11, MSR_UMS
82 nop
83 msrclr r11, MSR_VMS
84 nop
85 .endm
86
87 .macro set_vms
88 msrclr r11, MSR_UMS
89 nop
90 msrset r11, MSR_VMS
91 nop
92 .endm
93
94 .macro clear_vms_ums
Michal Simek3fbd93e2010-06-22 13:51:50 +020095 msrclr r11, MSR_VMS | MSR_UMS
Michal Simekca545022009-05-26 16:30:21 +020096 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 \
Michal Simeka4a94db2010-06-22 13:15:53 +0200181 set_ums; \
Michal Simekca545022009-05-26 16:30:21 +0200182 rted r0, 2f; \
Michal Simeka4a94db2010-06-22 13:15:53 +0200183 nop; \
1842:
Michal Simekca545022009-05-26 16:30:21 +0200185
186/* turn off virtual protected mode save and user mode save*/
187#define VM_OFF \
Michal Simeka4a94db2010-06-22 13:15:53 +0200188 clear_vms_ums; \
Michal Simekca545022009-05-26 16:30:21 +0200189 rted r0, TOPHYS(1f); \
Michal Simeka4a94db2010-06-22 13:15:53 +0200190 nop; \
1911:
Michal Simekca545022009-05-26 16:30:21 +0200192
193#define SAVE_REGS \
194 swi r2, r1, PTO+PT_R2; /* Save SDA */ \
Michal Simek36f60952010-06-22 13:27:43 +0200195 swi r3, r1, PTO+PT_R3; \
196 swi r4, r1, PTO+PT_R4; \
Michal Simekca545022009-05-26 16:30:21 +0200197 swi r5, r1, PTO+PT_R5; \
198 swi r6, r1, PTO+PT_R6; \
199 swi r7, r1, PTO+PT_R7; \
200 swi r8, r1, PTO+PT_R8; \
201 swi r9, r1, PTO+PT_R9; \
202 swi r10, r1, PTO+PT_R10; \
203 swi r11, r1, PTO+PT_R11; /* save clobbered regs after rval */\
204 swi r12, r1, PTO+PT_R12; \
205 swi r13, r1, PTO+PT_R13; /* Save SDA2 */ \
206 swi r14, r1, PTO+PT_PC; /* PC, before IRQ/trap */ \
207 swi r15, r1, PTO+PT_R15; /* Save LP */ \
208 swi r18, r1, PTO+PT_R18; /* Save asm scratch reg */ \
209 swi r19, r1, PTO+PT_R19; \
210 swi r20, r1, PTO+PT_R20; \
211 swi r21, r1, PTO+PT_R21; \
212 swi r22, r1, PTO+PT_R22; \
213 swi r23, r1, PTO+PT_R23; \
214 swi r24, r1, PTO+PT_R24; \
215 swi r25, r1, PTO+PT_R25; \
216 swi r26, r1, PTO+PT_R26; \
217 swi r27, r1, PTO+PT_R27; \
218 swi r28, r1, PTO+PT_R28; \
219 swi r29, r1, PTO+PT_R29; \
220 swi r30, r1, PTO+PT_R30; \
221 swi r31, r1, PTO+PT_R31; /* Save current task reg */ \
222 mfs r11, rmsr; /* save MSR */ \
223 nop; \
224 swi r11, r1, PTO+PT_MSR;
225
226#define RESTORE_REGS \
227 lwi r11, r1, PTO+PT_MSR; \
228 mts rmsr , r11; \
229 nop; \
230 lwi r2, r1, PTO+PT_R2; /* restore SDA */ \
Michal Simek36f60952010-06-22 13:27:43 +0200231 lwi r3, r1, PTO+PT_R3; \
232 lwi r4, r1, PTO+PT_R4; \
Michal Simekca545022009-05-26 16:30:21 +0200233 lwi r5, r1, PTO+PT_R5; \
234 lwi r6, r1, PTO+PT_R6; \
235 lwi r7, r1, PTO+PT_R7; \
236 lwi r8, r1, PTO+PT_R8; \
237 lwi r9, r1, PTO+PT_R9; \
238 lwi r10, r1, PTO+PT_R10; \
239 lwi r11, r1, PTO+PT_R11; /* restore clobbered regs after rval */\
240 lwi r12, r1, PTO+PT_R12; \
241 lwi r13, r1, PTO+PT_R13; /* restore SDA2 */ \
242 lwi r14, r1, PTO+PT_PC; /* RESTORE_LINK PC, before IRQ/trap */\
243 lwi r15, r1, PTO+PT_R15; /* restore LP */ \
244 lwi r18, r1, PTO+PT_R18; /* restore asm scratch reg */ \
245 lwi r19, r1, PTO+PT_R19; \
246 lwi r20, r1, PTO+PT_R20; \
247 lwi r21, r1, PTO+PT_R21; \
248 lwi r22, r1, PTO+PT_R22; \
249 lwi r23, r1, PTO+PT_R23; \
250 lwi r24, r1, PTO+PT_R24; \
251 lwi r25, r1, PTO+PT_R25; \
252 lwi r26, r1, PTO+PT_R26; \
253 lwi r27, r1, PTO+PT_R27; \
254 lwi r28, r1, PTO+PT_R28; \
255 lwi r29, r1, PTO+PT_R29; \
256 lwi r30, r1, PTO+PT_R30; \
257 lwi r31, r1, PTO+PT_R31; /* Restore cur task reg */
258
259.text
260
261/*
262 * User trap.
263 *
264 * System calls are handled here.
265 *
266 * Syscall protocol:
267 * Syscall number in r12, args in r5-r10
268 * Return value in r3
269 *
270 * Trap entered via brki instruction, so BIP bit is set, and interrupts
271 * are masked. This is nice, means we don't have to CLI before state save
272 */
273C_ENTRY(_user_exception):
274 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
275 addi r14, r14, 4 /* return address is 4 byte after call */
Michal Simekca545022009-05-26 16:30:21 +0200276
Michal Simek653e4472010-06-22 14:51:45 +0200277 mfs r1, rmsr
Michal Simek5c0d72b2010-06-22 14:00:12 +0200278 nop
Michal Simek653e4472010-06-22 14:51:45 +0200279 andi r1, r1, MSR_UMS
280 bnei r1, 1f
Michal Simek5c0d72b2010-06-22 14:00:12 +0200281
282/* Kernel-mode state save - kernel execve */
Michal Simek653e4472010-06-22 14:51:45 +0200283 lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
284 tophys(r1,r1);
Michal Simekca545022009-05-26 16:30:21 +0200285
286 addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
287 SAVE_REGS
288
289 addi r11, r0, 1; /* Was in kernel-mode. */
290 swi r11, r1, PTO+PT_MODE; /* pt_regs -> kernel mode */
291 brid 2f;
292 nop; /* Fill delay slot */
293
294/* User-mode state save. */
2951:
Michal Simekca545022009-05-26 16:30:21 +0200296 lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
297 tophys(r1,r1);
298 lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */
299/* calculate kernel stack pointer from task struct 8k */
300 addik r1, r1, THREAD_SIZE;
301 tophys(r1,r1);
302
303 addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
304 SAVE_REGS
305
306 swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */
307 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
308 swi r11, r1, PTO+PT_R1; /* Store user SP. */
Michal Simekb1d70c62010-01-22 10:24:06 +01003092: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
Michal Simekca545022009-05-26 16:30:21 +0200310 /* Save away the syscall number. */
311 swi r12, r1, PTO+PT_R0;
312 tovirt(r1,r1)
313
Michal Simekca545022009-05-26 16:30:21 +0200314/* where the trap should return need -8 to adjust for rtsd r15, 8*/
315/* Jump to the appropriate function for the system call number in r12
316 * (r12 is not preserved), or return an error if r12 is not valid. The LP
317 * register should point to the location where
318 * the called function should return. [note that MAKE_SYS_CALL uses label 1] */
Michal Simek23575482009-08-24 13:26:04 +0200319
320 # Step into virtual mode.
321 set_vms;
322 addik r11, r0, 3f
323 rtid r11, 0
324 nop
3253:
Michal Simekb1d70c62010-01-22 10:24:06 +0100326 lwi r11, CURRENT_TASK, TS_THREAD_INFO /* get thread info */
Michal Simek23575482009-08-24 13:26:04 +0200327 lwi r11, r11, TI_FLAGS /* get flags in thread info */
328 andi r11, r11, _TIF_WORK_SYSCALL_MASK
329 beqi r11, 4f
330
331 addik r3, r0, -ENOSYS
332 swi r3, r1, PTO + PT_R3
333 brlid r15, do_syscall_trace_enter
334 addik r5, r1, PTO + PT_R0
335
336 # do_syscall_trace_enter returns the new syscall nr.
337 addk r12, r0, r3
338 lwi r5, r1, PTO+PT_R5;
339 lwi r6, r1, PTO+PT_R6;
340 lwi r7, r1, PTO+PT_R7;
341 lwi r8, r1, PTO+PT_R8;
342 lwi r9, r1, PTO+PT_R9;
343 lwi r10, r1, PTO+PT_R10;
3444:
345/* Jump to the appropriate function for the system call number in r12
346 * (r12 is not preserved), or return an error if r12 is not valid.
347 * The LP register should point to the location where the called function
348 * should return. [note that MAKE_SYS_CALL uses label 1] */
349 /* See if the system call number is valid */
Michal Simekca545022009-05-26 16:30:21 +0200350 addi r11, r12, -__NR_syscalls;
Michal Simek23575482009-08-24 13:26:04 +0200351 bgei r11,5f;
Michal Simekca545022009-05-26 16:30:21 +0200352 /* Figure out which function to use for this system call. */
353 /* Note Microblaze barrel shift is optional, so don't rely on it */
354 add r12, r12, r12; /* convert num -> ptr */
355 add r12, r12, r12;
356
Michal Simek11d51362009-12-07 08:21:34 +0100357#ifdef DEBUG
Michal Simekca545022009-05-26 16:30:21 +0200358 /* Trac syscalls and stored them to r0_ram */
Michal Simek23575482009-08-24 13:26:04 +0200359 lwi r3, r12, 0x400 + r0_ram
Michal Simekca545022009-05-26 16:30:21 +0200360 addi r3, r3, 1
Michal Simek23575482009-08-24 13:26:04 +0200361 swi r3, r12, 0x400 + r0_ram
Michal Simek11d51362009-12-07 08:21:34 +0100362#endif
Michal Simekca545022009-05-26 16:30:21 +0200363
Michal Simek23575482009-08-24 13:26:04 +0200364 # Find and jump into the syscall handler.
365 lwi r12, r12, sys_call_table
366 /* where the trap should return need -8 to adjust for rtsd r15, 8 */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200367 addi r15, r0, ret_from_trap-8
Michal Simek23575482009-08-24 13:26:04 +0200368 bra r12
369
Michal Simekca545022009-05-26 16:30:21 +0200370 /* The syscall number is invalid, return an error. */
Michal Simek23575482009-08-24 13:26:04 +02003715:
Michal Simekca545022009-05-26 16:30:21 +0200372 addi r3, r0, -ENOSYS;
373 rtsd r15,8; /* looks like a normal subroutine return */
374 or r0, r0, r0
375
376
Michal Simek23575482009-08-24 13:26:04 +0200377/* Entry point used to return from a syscall/trap */
Michal Simekca545022009-05-26 16:30:21 +0200378/* We re-enable BIP bit before state restore */
379C_ENTRY(ret_from_trap):
Michal Simekb1d70c62010-01-22 10:24:06 +0100380 swi r3, r1, PTO + PT_R3
381 swi r4, r1, PTO + PT_R4
382
Michal Simek36f60952010-06-22 13:27:43 +0200383 lwi r11, r1, PTO+PT_MODE;
384/* See if returning to kernel mode, if so, skip resched &c. */
385 bnei r11, 2f;
Michal Simekca545022009-05-26 16:30:21 +0200386 /* We're returning to user mode, so check for various conditions that
387 * trigger rescheduling. */
Michal Simekb1d70c62010-01-22 10:24:06 +0100388 /* FIXME: Restructure all these flag checks. */
389 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simek23575482009-08-24 13:26:04 +0200390 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
391 andi r11, r11, _TIF_WORK_SYSCALL_MASK
392 beqi r11, 1f
393
Michal Simek23575482009-08-24 13:26:04 +0200394 brlid r15, do_syscall_trace_leave
395 addik r5, r1, PTO + PT_R0
Michal Simek23575482009-08-24 13:26:04 +02003961:
Michal Simek23575482009-08-24 13:26:04 +0200397 /* We're returning to user mode, so check for various conditions that
398 * trigger rescheduling. */
Michal Simekb1d70c62010-01-22 10:24:06 +0100399 /* get thread info from current task */
400 lwi r11, CURRENT_TASK, TS_THREAD_INFO;
Michal Simekca545022009-05-26 16:30:21 +0200401 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
402 andi r11, r11, _TIF_NEED_RESCHED;
403 beqi r11, 5f;
404
Michal Simekca545022009-05-26 16:30:21 +0200405 bralid r15, schedule; /* Call scheduler */
406 nop; /* delay slot */
Michal Simekca545022009-05-26 16:30:21 +0200407
408 /* Maybe handle a signal */
Michal Simekb1d70c62010-01-22 10:24:06 +01004095: /* get thread info from current task*/
410 lwi r11, CURRENT_TASK, TS_THREAD_INFO;
Michal Simekca545022009-05-26 16:30:21 +0200411 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
412 andi r11, r11, _TIF_SIGPENDING;
413 beqi r11, 1f; /* Signals to handle, handle them */
414
Michal Simekb9ea77e2010-07-28 12:40:02 +0200415 addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
Michal Simekca545022009-05-26 16:30:21 +0200416 addi r7, r0, 1; /* Arg 3: int in_syscall */
417 bralid r15, do_signal; /* Handle any signals */
Michal Simek841d6e82010-01-22 14:28:36 +0100418 add r6, r0, r0; /* Arg 2: sigset_t *oldset */
Michal Simekb1d70c62010-01-22 10:24:06 +0100419
420/* Finally, return to user state. */
Michal Simek96014cc2010-06-22 14:05:43 +02004211: set_bip; /* Ints masked for state restore */
Michal Simek8633beb2010-02-22 13:24:43 +0100422 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
Michal Simekca545022009-05-26 16:30:21 +0200423 VM_OFF;
424 tophys(r1,r1);
425 RESTORE_REGS;
426 addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
427 lwi r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
428 bri 6f;
429
430/* Return to kernel state. */
Michal Simek96014cc2010-06-22 14:05:43 +02004312: set_bip; /* Ints masked for state restore */
432 VM_OFF;
Michal Simekca545022009-05-26 16:30:21 +0200433 tophys(r1,r1);
434 RESTORE_REGS;
435 addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
436 tovirt(r1,r1);
4376:
438TRAP_return: /* Make global symbol for debugging */
439 rtbd r14, 0; /* Instructions to return from an IRQ */
440 nop;
441
442
443/* These syscalls need access to the struct pt_regs on the stack, so we
444 implement them in assembly (they're basically all wrappers anyway). */
445
446C_ENTRY(sys_fork_wrapper):
447 addi r5, r0, SIGCHLD /* Arg 0: flags */
448 lwi r6, r1, PTO+PT_R1 /* Arg 1: child SP (use parent's) */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200449 addik r7, r1, PTO /* Arg 2: parent context */
Michal Simekca545022009-05-26 16:30:21 +0200450 add r8. r0, r0 /* Arg 3: (unused) */
451 add r9, r0, r0; /* Arg 4: (unused) */
452 add r10, r0, r0; /* Arg 5: (unused) */
453 brid do_fork /* Do real work (tail-call) */
454 nop;
455
456/* This the initial entry point for a new child thread, with an appropriate
457 stack in place that makes it look the the child is in the middle of an
458 syscall. This function is actually `returned to' from switch_thread
459 (copy_thread makes ret_from_fork the return address in each new thread's
460 saved context). */
461C_ENTRY(ret_from_fork):
462 bralid r15, schedule_tail; /* ...which is schedule_tail's arg */
463 add r3, r5, r0; /* switch_thread returns the prev task */
464 /* ( in the delay slot ) */
465 add r3, r0, r0; /* Child's fork call should return 0. */
466 brid ret_from_trap; /* Do normal trap return */
467 nop;
468
Arnd Bergmanne5135882009-06-18 19:55:30 +0200469C_ENTRY(sys_vfork):
470 brid microblaze_vfork /* Do real work (tail-call) */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200471 addik r5, r1, PTO
Michal Simekca545022009-05-26 16:30:21 +0200472
Arnd Bergmanne5135882009-06-18 19:55:30 +0200473C_ENTRY(sys_clone):
Michal Simekca545022009-05-26 16:30:21 +0200474 bnei r6, 1f; /* See if child SP arg (arg 1) is 0. */
Michal Simek570e3e22010-06-04 13:06:27 +0200475 lwi r6, r1, PTO + PT_R1; /* If so, use paret's stack ptr */
Michal Simekb9ea77e2010-07-28 12:40:02 +02004761: addik r7, r1, PTO; /* Arg 2: parent context */
477 add r8, r0, r0; /* Arg 3: (unused) */
478 add r9, r0, r0; /* Arg 4: (unused) */
479 add r10, r0, r0; /* Arg 5: (unused) */
480 brid do_fork /* Do real work (tail-call) */
481 nop;
Michal Simekca545022009-05-26 16:30:21 +0200482
Arnd Bergmanne5135882009-06-18 19:55:30 +0200483C_ENTRY(sys_execve):
Michal Simekb9ea77e2010-07-28 12:40:02 +0200484 addik r8, r1, PTO; /* add user context as 4th arg */
Arnd Bergmanne5135882009-06-18 19:55:30 +0200485 brid microblaze_execve; /* Do real work (tail-call).*/
Michal Simekca545022009-05-26 16:30:21 +0200486 nop;
487
Michal Simekca545022009-05-26 16:30:21 +0200488C_ENTRY(sys_rt_sigreturn_wrapper):
489 swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
490 swi r4, r1, PTO+PT_R4;
Michal Simekb9ea77e2010-07-28 12:40:02 +0200491 addik r5, r1, PTO; /* add user context as 1st arg */
Michal Simekca545022009-05-26 16:30:21 +0200492 brlid r15, sys_rt_sigreturn /* Do real work */
493 nop;
494 lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
495 lwi r4, r1, PTO+PT_R4;
496 bri ret_from_trap /* fall through will not work here due to align */
497 nop;
498
499/*
500 * HW EXCEPTION rutine start
501 */
502
503#define SAVE_STATE \
Michal Simek63708f62010-06-22 14:13:09 +0200504 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \
Michal Simekca545022009-05-26 16:30:21 +0200505 /* See if already in kernel mode.*/ \
Michal Simek653e4472010-06-22 14:51:45 +0200506 mfs r1, rmsr; \
Michal Simek5c0d72b2010-06-22 14:00:12 +0200507 nop; \
Michal Simek653e4472010-06-22 14:51:45 +0200508 andi r1, r1, MSR_UMS; \
509 bnei r1, 1f; \
Michal Simekca545022009-05-26 16:30:21 +0200510 /* Kernel-mode state save. */ \
511 /* Reload kernel stack-ptr. */ \
Michal Simek653e4472010-06-22 14:51:45 +0200512 lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); \
513 tophys(r1,r1); \
Michal Simekca545022009-05-26 16:30:21 +0200514 addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\
Michal Simekca545022009-05-26 16:30:21 +0200515 SAVE_REGS \
516 /* PC, before IRQ/trap - this is one instruction above */ \
517 swi r17, r1, PTO+PT_PC; \
518 \
519 addi r11, r0, 1; /* Was in kernel-mode. */ \
520 swi r11, r1, PTO+PT_MODE; \
521 brid 2f; \
522 nop; /* Fill delay slot */ \
5231: /* User-mode state save. */ \
Michal Simekca545022009-05-26 16:30:21 +0200524 lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
525 tophys(r1,r1); \
526 lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \
527 addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */\
528 tophys(r1,r1); \
Michal Simekca545022009-05-26 16:30:21 +0200529 addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\
Michal Simekca545022009-05-26 16:30:21 +0200530 SAVE_REGS \
531 /* PC, before IRQ/trap - this is one instruction above FIXME*/ \
532 swi r17, r1, PTO+PT_PC; \
533 \
534 swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ \
535 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \
536 swi r11, r1, PTO+PT_R1; /* Store user SP. */ \
Michal Simekb1d70c62010-01-22 10:24:06 +01005372: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); \
Michal Simekca545022009-05-26 16:30:21 +0200538 /* Save away the syscall number. */ \
539 swi r0, r1, PTO+PT_R0; \
540 tovirt(r1,r1)
541
542C_ENTRY(full_exception_trap):
Michal Simekca545022009-05-26 16:30:21 +0200543 /* adjust exception address for privileged instruction
544 * for finding where is it */
545 addik r17, r17, -4
546 SAVE_STATE /* Save registers */
547 /* FIXME this can be store directly in PT_ESR reg.
548 * I tested it but there is a fault */
549 /* where the trap should return need -8 to adjust for rtsd r15, 8 */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200550 addik r15, r0, ret_from_exc - 8
551 addik r5, r1, PTO /* parameter struct pt_regs * regs */
Michal Simekca545022009-05-26 16:30:21 +0200552 mfs r6, resr
553 nop
554 mfs r7, rfsr; /* save FSR */
555 nop
Michal Simek131e4e92009-09-28 08:50:53 +0200556 mts rfsr, r0; /* Clear sticky fsr */
557 nop
Michal Simekb9ea77e2010-07-28 12:40:02 +0200558 addik r12, r0, full_exception
Michal Simekca545022009-05-26 16:30:21 +0200559 set_vms;
Michal Simek8b110d12010-06-17 16:03:05 +0200560 rted r12, 0;
Michal Simekca545022009-05-26 16:30:21 +0200561 nop;
562
563/*
564 * Unaligned data trap.
565 *
566 * Unaligned data trap last on 4k page is handled here.
567 *
568 * Trap entered via exception, so EE bit is set, and interrupts
569 * are masked. This is nice, means we don't have to CLI before state save
570 *
571 * The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S"
572 */
573C_ENTRY(unaligned_data_trap):
Michal Simek8b110d12010-06-17 16:03:05 +0200574 /* MS: I have to save r11 value and then restore it because
575 * set_bit, clear_eip, set_ee use r11 as temp register if MSR
576 * instructions are not used. We don't need to do if MSR instructions
577 * are used and they use r0 instead of r11.
578 * I am using ENTRY_SP which should be primary used only for stack
579 * pointer saving. */
580 swi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
581 set_bip; /* equalize initial state for all possible entries */
582 clear_eip;
583 set_ee;
584 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
Michal Simekca545022009-05-26 16:30:21 +0200585 SAVE_STATE /* Save registers.*/
586 /* where the trap should return need -8 to adjust for rtsd r15, 8 */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200587 addik r15, r0, ret_from_exc-8
Michal Simekca545022009-05-26 16:30:21 +0200588 mfs r3, resr /* ESR */
589 nop
590 mfs r4, rear /* EAR */
591 nop
Michal Simekb9ea77e2010-07-28 12:40:02 +0200592 addik r7, r1, PTO /* parameter struct pt_regs * regs */
593 addik r12, r0, _unaligned_data_exception
Michal Simekca545022009-05-26 16:30:21 +0200594 set_vms;
595 rtbd r12, 0; /* interrupts enabled */
596 nop;
597
598/*
599 * Page fault traps.
600 *
601 * If the real exception handler (from hw_exception_handler.S) didn't find
602 * the mapping for the process, then we're thrown here to handle such situation.
603 *
604 * Trap entered via exceptions, so EE bit is set, and interrupts
605 * are masked. This is nice, means we don't have to CLI before state save
606 *
607 * Build a standard exception frame for TLB Access errors. All TLB exceptions
608 * will bail out to this point if they can't resolve the lightweight TLB fault.
609 *
610 * The C function called is in "arch/microblaze/mm/fault.c", declared as:
611 * void do_page_fault(struct pt_regs *regs,
612 * unsigned long address,
613 * unsigned long error_code)
614 */
615/* data and intruction trap - which is choose is resolved int fault.c */
616C_ENTRY(page_fault_data_trap):
Michal Simekca545022009-05-26 16:30:21 +0200617 SAVE_STATE /* Save registers.*/
618 /* where the trap should return need -8 to adjust for rtsd r15, 8 */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200619 addik r15, r0, ret_from_exc-8
620 addik r5, r1, PTO /* parameter struct pt_regs * regs */
Michal Simekca545022009-05-26 16:30:21 +0200621 mfs r6, rear /* parameter unsigned long address */
622 nop
623 mfs r7, resr /* parameter unsigned long error_code */
624 nop
Michal Simekb9ea77e2010-07-28 12:40:02 +0200625 addik r12, r0, do_page_fault
Michal Simekca545022009-05-26 16:30:21 +0200626 set_vms;
Michal Simek8b110d12010-06-17 16:03:05 +0200627 rted r12, 0; /* interrupts enabled */
Michal Simekca545022009-05-26 16:30:21 +0200628 nop;
629
630C_ENTRY(page_fault_instr_trap):
Michal Simekca545022009-05-26 16:30:21 +0200631 SAVE_STATE /* Save registers.*/
632 /* where the trap should return need -8 to adjust for rtsd r15, 8 */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200633 addik r15, r0, ret_from_exc-8
634 addik r5, r1, PTO /* parameter struct pt_regs * regs */
Michal Simekca545022009-05-26 16:30:21 +0200635 mfs r6, rear /* parameter unsigned long address */
636 nop
637 ori r7, r0, 0 /* parameter unsigned long error_code */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200638 addik r12, r0, do_page_fault
Michal Simekca545022009-05-26 16:30:21 +0200639 set_vms;
Michal Simek8b110d12010-06-17 16:03:05 +0200640 rted r12, 0; /* interrupts enabled */
Michal Simekca545022009-05-26 16:30:21 +0200641 nop;
642
643/* Entry point used to return from an exception. */
644C_ENTRY(ret_from_exc):
Michal Simekca545022009-05-26 16:30:21 +0200645 lwi r11, r1, PTO+PT_MODE;
646 bnei r11, 2f; /* See if returning to kernel mode, */
647 /* ... if so, skip resched &c. */
648
649 /* We're returning to user mode, so check for various conditions that
650 trigger rescheduling. */
Michal Simekb1d70c62010-01-22 10:24:06 +0100651 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simekca545022009-05-26 16:30:21 +0200652 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
653 andi r11, r11, _TIF_NEED_RESCHED;
654 beqi r11, 5f;
655
656/* Call the scheduler before returning from a syscall/trap. */
657 bralid r15, schedule; /* Call scheduler */
658 nop; /* delay slot */
659
660 /* Maybe handle a signal */
Michal Simekb1d70c62010-01-22 10:24:06 +01006615: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simekca545022009-05-26 16:30:21 +0200662 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
663 andi r11, r11, _TIF_SIGPENDING;
664 beqi r11, 1f; /* Signals to handle, handle them */
665
666 /*
667 * Handle a signal return; Pending signals should be in r18.
668 *
669 * Not all registers are saved by the normal trap/interrupt entry
670 * points (for instance, call-saved registers (because the normal
671 * C-compiler calling sequence in the kernel makes sure they're
672 * preserved), and call-clobbered registers in the case of
673 * traps), but signal handlers may want to examine or change the
674 * complete register state. Here we save anything not saved by
675 * the normal entry sequence, so that it may be safely restored
Michal Simek36f60952010-06-22 13:27:43 +0200676 * (in a possibly modified form) after do_signal returns. */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200677 addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
Michal Simekca545022009-05-26 16:30:21 +0200678 addi r7, r0, 0; /* Arg 3: int in_syscall */
679 bralid r15, do_signal; /* Handle any signals */
Michal Simek841d6e82010-01-22 14:28:36 +0100680 add r6, r0, r0; /* Arg 2: sigset_t *oldset */
Michal Simekca545022009-05-26 16:30:21 +0200681
682/* Finally, return to user state. */
Michal Simek96014cc2010-06-22 14:05:43 +02006831: set_bip; /* Ints masked for state restore */
Michal Simek8633beb2010-02-22 13:24:43 +0100684 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
Michal Simekca545022009-05-26 16:30:21 +0200685 VM_OFF;
686 tophys(r1,r1);
687
Michal Simekca545022009-05-26 16:30:21 +0200688 RESTORE_REGS;
689 addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
690
691 lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */
692 bri 6f;
693/* Return to kernel state. */
Michal Simek96014cc2010-06-22 14:05:43 +02006942: set_bip; /* Ints masked for state restore */
695 VM_OFF;
Michal Simekca545022009-05-26 16:30:21 +0200696 tophys(r1,r1);
Michal Simekca545022009-05-26 16:30:21 +0200697 RESTORE_REGS;
698 addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
699
700 tovirt(r1,r1);
7016:
702EXC_return: /* Make global symbol for debugging */
703 rtbd r14, 0; /* Instructions to return from an IRQ */
704 nop;
705
706/*
707 * HW EXCEPTION rutine end
708 */
709
710/*
711 * Hardware maskable interrupts.
712 *
713 * The stack-pointer (r1) should have already been saved to the memory
714 * location PER_CPU(ENTRY_SP).
715 */
716C_ENTRY(_interrupt):
717/* MS: we are in physical address */
718/* Save registers, switch to proper stack, convert SP to virtual.*/
719 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
Michal Simekca545022009-05-26 16:30:21 +0200720 /* MS: See if already in kernel mode. */
Michal Simek653e4472010-06-22 14:51:45 +0200721 mfs r1, rmsr
Michal Simek5c0d72b2010-06-22 14:00:12 +0200722 nop
Michal Simek653e4472010-06-22 14:51:45 +0200723 andi r1, r1, MSR_UMS
724 bnei r1, 1f
Michal Simekca545022009-05-26 16:30:21 +0200725
726/* Kernel-mode state save. */
Michal Simek653e4472010-06-22 14:51:45 +0200727 lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
728 tophys(r1,r1); /* MS: I have in r1 physical address where stack is */
Michal Simekca545022009-05-26 16:30:21 +0200729 /* save registers */
730/* MS: Make room on the stack -> activation record */
731 addik r1, r1, -STATE_SAVE_SIZE;
Michal Simekca545022009-05-26 16:30:21 +0200732 SAVE_REGS
733 /* MS: store mode */
734 addi r11, r0, 1; /* MS: Was in kernel-mode. */
735 swi r11, r1, PTO + PT_MODE; /* MS: and save it */
736 brid 2f;
737 nop; /* MS: Fill delay slot */
738
7391:
740/* User-mode state save. */
Michal Simekca545022009-05-26 16:30:21 +0200741 /* MS: get the saved current */
742 lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
743 tophys(r1,r1);
744 lwi r1, r1, TS_THREAD_INFO;
745 addik r1, r1, THREAD_SIZE;
746 tophys(r1,r1);
747 /* save registers */
748 addik r1, r1, -STATE_SAVE_SIZE;
Michal Simekca545022009-05-26 16:30:21 +0200749 SAVE_REGS
750 /* calculate mode */
751 swi r0, r1, PTO + PT_MODE;
752 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
753 swi r11, r1, PTO+PT_R1;
Michal Simekca545022009-05-26 16:30:21 +02007542:
Michal Simekb1d70c62010-01-22 10:24:06 +0100755 lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
Michal Simekca545022009-05-26 16:30:21 +0200756 swi r0, r1, PTO + PT_R0;
757 tovirt(r1,r1)
Michal Simekb9ea77e2010-07-28 12:40:02 +0200758 addik r5, r1, PTO;
Michal Simekca545022009-05-26 16:30:21 +0200759 set_vms;
Michal Simekb9ea77e2010-07-28 12:40:02 +0200760 addik r11, r0, do_IRQ;
761 addik r15, r0, irq_call;
Michal Simekca545022009-05-26 16:30:21 +0200762irq_call:rtbd r11, 0;
763 nop;
764
765/* MS: we are in virtual mode */
766ret_from_irq:
767 lwi r11, r1, PTO + PT_MODE;
768 bnei r11, 2f;
769
Michal Simekb1d70c62010-01-22 10:24:06 +0100770 lwi r11, CURRENT_TASK, TS_THREAD_INFO;
Michal Simekca545022009-05-26 16:30:21 +0200771 lwi r11, r11, TI_FLAGS; /* MS: get flags from thread info */
772 andi r11, r11, _TIF_NEED_RESCHED;
773 beqi r11, 5f
774 bralid r15, schedule;
775 nop; /* delay slot */
776
777 /* Maybe handle a signal */
Michal Simekb1d70c62010-01-22 10:24:06 +01007785: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */
Michal Simekca545022009-05-26 16:30:21 +0200779 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
780 andi r11, r11, _TIF_SIGPENDING;
781 beqid r11, no_intr_resched
782/* Handle a signal return; Pending signals should be in r18. */
783 addi r7, r0, 0; /* Arg 3: int in_syscall */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200784 addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
Michal Simekca545022009-05-26 16:30:21 +0200785 bralid r15, do_signal; /* Handle any signals */
786 add r6, r0, r0; /* Arg 2: sigset_t *oldset */
787
788/* Finally, return to user state. */
789no_intr_resched:
790 /* Disable interrupts, we are now committed to the state restore */
791 disable_irq
Michal Simek8633beb2010-02-22 13:24:43 +0100792 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE);
Michal Simekca545022009-05-26 16:30:21 +0200793 VM_OFF;
794 tophys(r1,r1);
Michal Simekca545022009-05-26 16:30:21 +0200795 RESTORE_REGS
796 addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
797 lwi r1, r1, PT_R1 - PT_SIZE;
798 bri 6f;
799/* MS: Return to kernel state. */
Michal Simek77753792010-01-12 09:55:10 +01008002:
801#ifdef CONFIG_PREEMPT
Michal Simekb1d70c62010-01-22 10:24:06 +0100802 lwi r11, CURRENT_TASK, TS_THREAD_INFO;
Michal Simek77753792010-01-12 09:55:10 +0100803 /* MS: get preempt_count from thread info */
804 lwi r5, r11, TI_PREEMPT_COUNT;
805 bgti r5, restore;
806
807 lwi r5, r11, TI_FLAGS; /* get flags in thread info */
808 andi r5, r5, _TIF_NEED_RESCHED;
809 beqi r5, restore /* if zero jump over */
810
811preempt:
812 /* interrupts are off that's why I am calling preempt_chedule_irq */
813 bralid r15, preempt_schedule_irq
814 nop
Michal Simekb1d70c62010-01-22 10:24:06 +0100815 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simek77753792010-01-12 09:55:10 +0100816 lwi r5, r11, TI_FLAGS; /* get flags in thread info */
817 andi r5, r5, _TIF_NEED_RESCHED;
818 bnei r5, preempt /* if non zero jump to resched */
819restore:
820#endif
821 VM_OFF /* MS: turn off MMU */
Michal Simekca545022009-05-26 16:30:21 +0200822 tophys(r1,r1)
Michal Simekca545022009-05-26 16:30:21 +0200823 RESTORE_REGS
824 addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
825 tovirt(r1,r1);
8266:
827IRQ_return: /* MS: Make global symbol for debugging */
828 rtid r14, 0
829 nop
830
831/*
832 * `Debug' trap
833 * We enter dbtrap in "BIP" (breakpoint) mode.
834 * So we exit the breakpoint mode with an 'rtbd' and proceed with the
835 * original dbtrap.
836 * however, wait to save state first
837 */
838C_ENTRY(_debug_exception):
839 /* BIP bit is set on entry, no interrupts can occur */
840 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
841
Michal Simek653e4472010-06-22 14:51:45 +0200842 mfs r1, rmsr
Michal Simek5c0d72b2010-06-22 14:00:12 +0200843 nop
Michal Simek653e4472010-06-22 14:51:45 +0200844 andi r1, r1, MSR_UMS
845 bnei r1, 1f
Michal Simekca545022009-05-26 16:30:21 +0200846 /* Kernel-mode state save. */
Michal Simek653e4472010-06-22 14:51:45 +0200847 lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
848 tophys(r1,r1);
Michal Simekca545022009-05-26 16:30:21 +0200849
850 addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
Michal Simekca545022009-05-26 16:30:21 +0200851 SAVE_REGS;
852
853 addi r11, r0, 1; /* Was in kernel-mode. */
854 swi r11, r1, PTO + PT_MODE;
855 brid 2f;
856 nop; /* Fill delay slot */
8571: /* User-mode state save. */
Michal Simekca545022009-05-26 16:30:21 +0200858 lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
859 tophys(r1,r1);
860 lwi r1, r1, TS_THREAD_INFO; /* get the thread info */
861 addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */
862 tophys(r1,r1);
863
864 addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
Michal Simekca545022009-05-26 16:30:21 +0200865 SAVE_REGS;
866
867 swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */
868 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
869 swi r11, r1, PTO+PT_R1; /* Store user SP. */
Michal Simek653e4472010-06-22 14:51:45 +02008702:
Michal Simekca545022009-05-26 16:30:21 +0200871 /* Save away the syscall number. */
872 swi r0, r1, PTO+PT_R0;
873 tovirt(r1,r1)
874
Michal Simek06b28642010-06-22 15:25:24 +0200875 set_vms;
Michal Simekca545022009-05-26 16:30:21 +0200876 addi r5, r0, SIGTRAP /* send the trap signal */
877 add r6, r0, CURRENT_TASK; /* Get current task ptr into r11 */
878 addk r7, r0, r0 /* 3rd param zero */
Michal Simek06b28642010-06-22 15:25:24 +0200879dbtrap_call: rtbd r0, send_sig;
Michal Simekb9ea77e2010-07-28 12:40:02 +0200880 addik r15, r0, dbtrap_call;
Michal Simekca545022009-05-26 16:30:21 +0200881
882 set_bip; /* Ints masked for state restore*/
883 lwi r11, r1, PTO+PT_MODE;
884 bnei r11, 2f;
885
886 /* Get current task ptr into r11 */
Michal Simekb1d70c62010-01-22 10:24:06 +0100887 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simekca545022009-05-26 16:30:21 +0200888 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
889 andi r11, r11, _TIF_NEED_RESCHED;
890 beqi r11, 5f;
891
892/* Call the scheduler before returning from a syscall/trap. */
893
894 bralid r15, schedule; /* Call scheduler */
895 nop; /* delay slot */
896 /* XXX Is PT_DTRACE handling needed here? */
897 /* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here. */
898
899 /* Maybe handle a signal */
Michal Simekb1d70c62010-01-22 10:24:06 +01009005: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simekca545022009-05-26 16:30:21 +0200901 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
902 andi r11, r11, _TIF_SIGPENDING;
903 beqi r11, 1f; /* Signals to handle, handle them */
904
905/* Handle a signal return; Pending signals should be in r18. */
906 /* Not all registers are saved by the normal trap/interrupt entry
907 points (for instance, call-saved registers (because the normal
908 C-compiler calling sequence in the kernel makes sure they're
909 preserved), and call-clobbered registers in the case of
910 traps), but signal handlers may want to examine or change the
911 complete register state. Here we save anything not saved by
912 the normal entry sequence, so that it may be safely restored
913 (in a possibly modified form) after do_signal returns. */
914
Michal Simekb9ea77e2010-07-28 12:40:02 +0200915 addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
Michal Simekca545022009-05-26 16:30:21 +0200916 addi r7, r0, 0; /* Arg 3: int in_syscall */
917 bralid r15, do_signal; /* Handle any signals */
Michal Simek841d6e82010-01-22 14:28:36 +0100918 add r6, r0, r0; /* Arg 2: sigset_t *oldset */
Michal Simekca545022009-05-26 16:30:21 +0200919
920
921/* Finally, return to user state. */
Michal Simek5c0d72b2010-06-22 14:00:12 +02009221:
Michal Simek8633beb2010-02-22 13:24:43 +0100923 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
Michal Simekca545022009-05-26 16:30:21 +0200924 VM_OFF;
925 tophys(r1,r1);
926
Michal Simekca545022009-05-26 16:30:21 +0200927 RESTORE_REGS
928 addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
929
930
931 lwi r1, r1, PT_R1 - PT_SIZE;
932 /* Restore user stack pointer. */
933 bri 6f;
934
935/* Return to kernel state. */
9362: VM_OFF;
937 tophys(r1,r1);
Michal Simekca545022009-05-26 16:30:21 +0200938 RESTORE_REGS
939 addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
940
941 tovirt(r1,r1);
9426:
943DBTRAP_return: /* Make global symbol for debugging */
944 rtbd r14, 0; /* Instructions to return from an IRQ */
945 nop;
946
947
948
949ENTRY(_switch_to)
950 /* prepare return value */
Michal Simekb1d70c62010-01-22 10:24:06 +0100951 addk r3, r0, CURRENT_TASK
Michal Simekca545022009-05-26 16:30:21 +0200952
953 /* save registers in cpu_context */
954 /* use r11 and r12, volatile registers, as temp register */
955 /* give start of cpu_context for previous process */
956 addik r11, r5, TI_CPU_CONTEXT
957 swi r1, r11, CC_R1
958 swi r2, r11, CC_R2
959 /* skip volatile registers.
960 * they are saved on stack when we jumped to _switch_to() */
961 /* dedicated registers */
962 swi r13, r11, CC_R13
963 swi r14, r11, CC_R14
964 swi r15, r11, CC_R15
965 swi r16, r11, CC_R16
966 swi r17, r11, CC_R17
967 swi r18, r11, CC_R18
968 /* save non-volatile registers */
969 swi r19, r11, CC_R19
970 swi r20, r11, CC_R20
971 swi r21, r11, CC_R21
972 swi r22, r11, CC_R22
973 swi r23, r11, CC_R23
974 swi r24, r11, CC_R24
975 swi r25, r11, CC_R25
976 swi r26, r11, CC_R26
977 swi r27, r11, CC_R27
978 swi r28, r11, CC_R28
979 swi r29, r11, CC_R29
980 swi r30, r11, CC_R30
981 /* special purpose registers */
982 mfs r12, rmsr
983 nop
984 swi r12, r11, CC_MSR
985 mfs r12, rear
986 nop
987 swi r12, r11, CC_EAR
988 mfs r12, resr
989 nop
990 swi r12, r11, CC_ESR
991 mfs r12, rfsr
992 nop
993 swi r12, r11, CC_FSR
994
Michal Simekb1d70c62010-01-22 10:24:06 +0100995 /* update r31, the current-give me pointer to task which will be next */
996 lwi CURRENT_TASK, r6, TI_TASK
Michal Simekca545022009-05-26 16:30:21 +0200997 /* stored it to current_save too */
Michal Simekb1d70c62010-01-22 10:24:06 +0100998 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE)
Michal Simekca545022009-05-26 16:30:21 +0200999
1000 /* get new process' cpu context and restore */
1001 /* give me start where start context of next task */
1002 addik r11, r6, TI_CPU_CONTEXT
1003
1004 /* non-volatile registers */
1005 lwi r30, r11, CC_R30
1006 lwi r29, r11, CC_R29
1007 lwi r28, r11, CC_R28
1008 lwi r27, r11, CC_R27
1009 lwi r26, r11, CC_R26
1010 lwi r25, r11, CC_R25
1011 lwi r24, r11, CC_R24
1012 lwi r23, r11, CC_R23
1013 lwi r22, r11, CC_R22
1014 lwi r21, r11, CC_R21
1015 lwi r20, r11, CC_R20
1016 lwi r19, r11, CC_R19
1017 /* dedicated registers */
1018 lwi r18, r11, CC_R18
1019 lwi r17, r11, CC_R17
1020 lwi r16, r11, CC_R16
1021 lwi r15, r11, CC_R15
1022 lwi r14, r11, CC_R14
1023 lwi r13, r11, CC_R13
1024 /* skip volatile registers */
1025 lwi r2, r11, CC_R2
1026 lwi r1, r11, CC_R1
1027
1028 /* special purpose registers */
1029 lwi r12, r11, CC_FSR
1030 mts rfsr, r12
1031 nop
1032 lwi r12, r11, CC_MSR
1033 mts rmsr, r12
1034 nop
1035
1036 rtsd r15, 8
1037 nop
1038
1039ENTRY(_reset)
1040 brai 0x70; /* Jump back to FS-boot */
1041
1042ENTRY(_break)
1043 mfs r5, rmsr
1044 nop
1045 swi r5, r0, 0x250 + TOPHYS(r0_ram)
1046 mfs r5, resr
1047 nop
1048 swi r5, r0, 0x254 + TOPHYS(r0_ram)
1049 bri 0
1050
1051 /* These are compiled and loaded into high memory, then
1052 * copied into place in mach_early_setup */
1053 .section .init.ivt, "ax"
1054 .org 0x0
1055 /* this is very important - here is the reset vector */
1056 /* in current MMU branch you don't care what is here - it is
1057 * used from bootloader site - but this is correct for FS-BOOT */
1058 brai 0x70
1059 nop
1060 brai TOPHYS(_user_exception); /* syscall handler */
1061 brai TOPHYS(_interrupt); /* Interrupt handler */
1062 brai TOPHYS(_break); /* nmi trap handler */
1063 brai TOPHYS(_hw_exception_handler); /* HW exception handler */
1064
1065 .org 0x60
1066 brai TOPHYS(_debug_exception); /* debug trap handler*/
1067
1068.section .rodata,"a"
1069#include "syscall_table.S"
1070
1071syscall_table_size=(.-sys_call_table)
1072
Steven J. Magnanice3266c2010-04-27 12:37:54 -05001073type_SYSCALL:
1074 .ascii "SYSCALL\0"
1075type_IRQ:
1076 .ascii "IRQ\0"
1077type_IRQ_PREEMPT:
1078 .ascii "IRQ (PREEMPTED)\0"
1079type_SYSCALL_PREEMPT:
1080 .ascii " SYSCALL (PREEMPTED)\0"
1081
1082 /*
1083 * Trap decoding for stack unwinder
1084 * Tuples are (start addr, end addr, string)
1085 * If return address lies on [start addr, end addr],
1086 * unwinder displays 'string'
1087 */
1088
1089 .align 4
1090.global microblaze_trap_handlers
1091microblaze_trap_handlers:
1092 /* Exact matches come first */
1093 .word ret_from_trap; .word ret_from_trap ; .word type_SYSCALL
1094 .word ret_from_irq ; .word ret_from_irq ; .word type_IRQ
1095 /* Fuzzy matches go here */
1096 .word ret_from_irq ; .word no_intr_resched ; .word type_IRQ_PREEMPT
1097 .word ret_from_trap; .word TRAP_return ; .word type_SYSCALL_PREEMPT
1098 /* End of table */
1099 .word 0 ; .word 0 ; .word 0