blob: 5a5cb5842938c6291dc6d428a10ab03d6951bc2e [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
Michal Simek66f7de862010-06-22 17:52:47 +020051 msrclr r0, MSR_BIP
Michal Simekca545022009-05-26 16:30:21 +020052 .endm
53
54 .macro set_bip
Michal Simek66f7de862010-06-22 17:52:47 +020055 msrset r0, MSR_BIP
Michal Simekca545022009-05-26 16:30:21 +020056 .endm
57
58 .macro clear_eip
Michal Simek66f7de862010-06-22 17:52:47 +020059 msrclr r0, MSR_EIP
Michal Simekca545022009-05-26 16:30:21 +020060 .endm
61
62 .macro set_ee
Michal Simek66f7de862010-06-22 17:52:47 +020063 msrset r0, MSR_EE
Michal Simekca545022009-05-26 16:30:21 +020064 .endm
65
66 .macro disable_irq
Michal Simek66f7de862010-06-22 17:52:47 +020067 msrclr r0, MSR_IE
Michal Simekca545022009-05-26 16:30:21 +020068 .endm
69
70 .macro enable_irq
Michal Simek66f7de862010-06-22 17:52:47 +020071 msrset r0, MSR_IE
Michal Simekca545022009-05-26 16:30:21 +020072 .endm
73
74 .macro set_ums
Michal Simek66f7de862010-06-22 17:52:47 +020075 msrset r0, MSR_UMS
Michal Simek66f7de862010-06-22 17:52:47 +020076 msrclr r0, MSR_VMS
Michal Simekca545022009-05-26 16:30:21 +020077 .endm
78
79 .macro set_vms
Michal Simek66f7de862010-06-22 17:52:47 +020080 msrclr r0, MSR_UMS
Michal Simek66f7de862010-06-22 17:52:47 +020081 msrset r0, MSR_VMS
Michal Simekca545022009-05-26 16:30:21 +020082 .endm
83
Michal Simekb3180672010-06-22 17:46:27 +020084 .macro clear_ums
Michal Simek66f7de862010-06-22 17:52:47 +020085 msrclr r0, MSR_UMS
Michal Simekb3180672010-06-22 17:46:27 +020086 .endm
87
Michal Simekca545022009-05-26 16:30:21 +020088 .macro clear_vms_ums
Michal Simek66f7de862010-06-22 17:52:47 +020089 msrclr r0, MSR_VMS | MSR_UMS
Michal Simekca545022009-05-26 16:30:21 +020090 .endm
91#else
92 .macro clear_bip
93 mfs r11, rmsr
Michal Simekca545022009-05-26 16:30:21 +020094 andi r11, r11, ~MSR_BIP
95 mts rmsr, r11
Michal Simekca545022009-05-26 16:30:21 +020096 .endm
97
98 .macro set_bip
99 mfs r11, rmsr
Michal Simekca545022009-05-26 16:30:21 +0200100 ori r11, r11, MSR_BIP
101 mts rmsr, r11
Michal Simekca545022009-05-26 16:30:21 +0200102 .endm
103
104 .macro clear_eip
105 mfs r11, rmsr
Michal Simekca545022009-05-26 16:30:21 +0200106 andi r11, r11, ~MSR_EIP
107 mts rmsr, r11
Michal Simekca545022009-05-26 16:30:21 +0200108 .endm
109
110 .macro set_ee
111 mfs r11, rmsr
Michal Simekca545022009-05-26 16:30:21 +0200112 ori r11, r11, MSR_EE
113 mts rmsr, r11
Michal Simekca545022009-05-26 16:30:21 +0200114 .endm
115
116 .macro disable_irq
117 mfs r11, rmsr
Michal Simekca545022009-05-26 16:30:21 +0200118 andi r11, r11, ~MSR_IE
119 mts rmsr, r11
Michal Simekca545022009-05-26 16:30:21 +0200120 .endm
121
122 .macro enable_irq
123 mfs r11, rmsr
Michal Simekca545022009-05-26 16:30:21 +0200124 ori r11, r11, MSR_IE
125 mts rmsr, r11
Michal Simekca545022009-05-26 16:30:21 +0200126 .endm
127
128 .macro set_ums
129 mfs r11, rmsr
Michal Simekca545022009-05-26 16:30:21 +0200130 ori r11, r11, MSR_VMS
131 andni r11, r11, MSR_UMS
132 mts rmsr, r11
Michal Simekca545022009-05-26 16:30:21 +0200133 .endm
134
135 .macro set_vms
136 mfs r11, rmsr
Michal Simekca545022009-05-26 16:30:21 +0200137 ori r11, r11, MSR_VMS
138 andni r11, r11, MSR_UMS
139 mts rmsr, r11
Michal Simekca545022009-05-26 16:30:21 +0200140 .endm
141
Michal Simekb3180672010-06-22 17:46:27 +0200142 .macro clear_ums
143 mfs r11, rmsr
Michal Simekb3180672010-06-22 17:46:27 +0200144 andni r11, r11, MSR_UMS
145 mts rmsr,r11
Michal Simekb3180672010-06-22 17:46:27 +0200146 .endm
147
Michal Simekca545022009-05-26 16:30:21 +0200148 .macro clear_vms_ums
149 mfs r11, rmsr
Michal Simekca545022009-05-26 16:30:21 +0200150 andni r11, r11, (MSR_VMS|MSR_UMS)
151 mts rmsr,r11
Michal Simekca545022009-05-26 16:30:21 +0200152 .endm
153#endif
154
155/* Define how to call high-level functions. With MMU, virtual mode must be
156 * enabled when calling the high-level function. Clobbers R11.
157 * VM_ON, VM_OFF, DO_JUMP_BIPCLR, DO_CALL
158 */
159
160/* turn on virtual protected mode save */
161#define VM_ON \
Michal Simeka4a94db2010-06-22 13:15:53 +0200162 set_ums; \
Michal Simekca545022009-05-26 16:30:21 +0200163 rted r0, 2f; \
Michal Simeka4a94db2010-06-22 13:15:53 +0200164 nop; \
1652:
Michal Simekca545022009-05-26 16:30:21 +0200166
167/* turn off virtual protected mode save and user mode save*/
168#define VM_OFF \
Michal Simeka4a94db2010-06-22 13:15:53 +0200169 clear_vms_ums; \
Michal Simekca545022009-05-26 16:30:21 +0200170 rted r0, TOPHYS(1f); \
Michal Simeka4a94db2010-06-22 13:15:53 +0200171 nop; \
1721:
Michal Simekca545022009-05-26 16:30:21 +0200173
174#define SAVE_REGS \
175 swi r2, r1, PTO+PT_R2; /* Save SDA */ \
Michal Simek36f60952010-06-22 13:27:43 +0200176 swi r3, r1, PTO+PT_R3; \
177 swi r4, r1, PTO+PT_R4; \
Michal Simekca545022009-05-26 16:30:21 +0200178 swi r5, r1, PTO+PT_R5; \
179 swi r6, r1, PTO+PT_R6; \
180 swi r7, r1, PTO+PT_R7; \
181 swi r8, r1, PTO+PT_R8; \
182 swi r9, r1, PTO+PT_R9; \
183 swi r10, r1, PTO+PT_R10; \
184 swi r11, r1, PTO+PT_R11; /* save clobbered regs after rval */\
185 swi r12, r1, PTO+PT_R12; \
186 swi r13, r1, PTO+PT_R13; /* Save SDA2 */ \
187 swi r14, r1, PTO+PT_PC; /* PC, before IRQ/trap */ \
188 swi r15, r1, PTO+PT_R15; /* Save LP */ \
189 swi r18, r1, PTO+PT_R18; /* Save asm scratch reg */ \
190 swi r19, r1, PTO+PT_R19; \
191 swi r20, r1, PTO+PT_R20; \
192 swi r21, r1, PTO+PT_R21; \
193 swi r22, r1, PTO+PT_R22; \
194 swi r23, r1, PTO+PT_R23; \
195 swi r24, r1, PTO+PT_R24; \
196 swi r25, r1, PTO+PT_R25; \
197 swi r26, r1, PTO+PT_R26; \
198 swi r27, r1, PTO+PT_R27; \
199 swi r28, r1, PTO+PT_R28; \
200 swi r29, r1, PTO+PT_R29; \
201 swi r30, r1, PTO+PT_R30; \
202 swi r31, r1, PTO+PT_R31; /* Save current task reg */ \
203 mfs r11, rmsr; /* save MSR */ \
Michal Simekca545022009-05-26 16:30:21 +0200204 swi r11, r1, PTO+PT_MSR;
205
206#define RESTORE_REGS \
207 lwi r11, r1, PTO+PT_MSR; \
208 mts rmsr , r11; \
Michal Simekca545022009-05-26 16:30:21 +0200209 lwi r2, r1, PTO+PT_R2; /* restore SDA */ \
Michal Simek36f60952010-06-22 13:27:43 +0200210 lwi r3, r1, PTO+PT_R3; \
211 lwi r4, r1, PTO+PT_R4; \
Michal Simekca545022009-05-26 16:30:21 +0200212 lwi r5, r1, PTO+PT_R5; \
213 lwi r6, r1, PTO+PT_R6; \
214 lwi r7, r1, PTO+PT_R7; \
215 lwi r8, r1, PTO+PT_R8; \
216 lwi r9, r1, PTO+PT_R9; \
217 lwi r10, r1, PTO+PT_R10; \
218 lwi r11, r1, PTO+PT_R11; /* restore clobbered regs after rval */\
219 lwi r12, r1, PTO+PT_R12; \
220 lwi r13, r1, PTO+PT_R13; /* restore SDA2 */ \
221 lwi r14, r1, PTO+PT_PC; /* RESTORE_LINK PC, before IRQ/trap */\
222 lwi r15, r1, PTO+PT_R15; /* restore LP */ \
223 lwi r18, r1, PTO+PT_R18; /* restore asm scratch reg */ \
224 lwi r19, r1, PTO+PT_R19; \
225 lwi r20, r1, PTO+PT_R20; \
226 lwi r21, r1, PTO+PT_R21; \
227 lwi r22, r1, PTO+PT_R22; \
228 lwi r23, r1, PTO+PT_R23; \
229 lwi r24, r1, PTO+PT_R24; \
230 lwi r25, r1, PTO+PT_R25; \
231 lwi r26, r1, PTO+PT_R26; \
232 lwi r27, r1, PTO+PT_R27; \
233 lwi r28, r1, PTO+PT_R28; \
234 lwi r29, r1, PTO+PT_R29; \
235 lwi r30, r1, PTO+PT_R30; \
236 lwi r31, r1, PTO+PT_R31; /* Restore cur task reg */
237
Michal Simeke5d2af22010-06-22 17:58:26 +0200238#define SAVE_STATE \
239 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \
240 /* See if already in kernel mode.*/ \
241 mfs r1, rmsr; \
Michal Simeke5d2af22010-06-22 17:58:26 +0200242 andi r1, r1, MSR_UMS; \
243 bnei r1, 1f; \
244 /* Kernel-mode state save. */ \
245 /* Reload kernel stack-ptr. */ \
246 lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); \
Michal Simek287503f2010-06-22 18:16:07 +0200247 /* FIXME: I can add these two lines to one */ \
248 /* tophys(r1,r1); */ \
249 /* addik r1, r1, -STATE_SAVE_SIZE; */ \
250 addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \
Michal Simeke5d2af22010-06-22 17:58:26 +0200251 SAVE_REGS \
Michal Simeke5d2af22010-06-22 17:58:26 +0200252 brid 2f; \
Michal Simekda233552010-06-22 18:02:06 +0200253 swi r1, r1, PTO+PT_MODE; \
Michal Simeke5d2af22010-06-22 17:58:26 +02002541: /* User-mode state save. */ \
255 lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
256 tophys(r1,r1); \
257 lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \
Michal Simek287503f2010-06-22 18:16:07 +0200258 /* MS these three instructions can be added to one */ \
259 /* addik r1, r1, THREAD_SIZE; */ \
260 /* tophys(r1,r1); */ \
261 /* addik r1, r1, -STATE_SAVE_SIZE; */ \
262 addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \
Michal Simeke5d2af22010-06-22 17:58:26 +0200263 SAVE_REGS \
Michal Simeke5d2af22010-06-22 17:58:26 +0200264 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \
265 swi r11, r1, PTO+PT_R1; /* Store user SP. */ \
Michal Simeke7741072010-06-22 18:00:35 +0200266 swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ \
Michal Simeke5d2af22010-06-22 17:58:26 +0200267 /* MS: I am clearing UMS even in case when I come from kernel space */ \
268 clear_ums; \
2692: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
270
Michal Simekca545022009-05-26 16:30:21 +0200271.text
272
273/*
274 * User trap.
275 *
276 * System calls are handled here.
277 *
278 * Syscall protocol:
279 * Syscall number in r12, args in r5-r10
280 * Return value in r3
281 *
282 * Trap entered via brki instruction, so BIP bit is set, and interrupts
283 * are masked. This is nice, means we don't have to CLI before state save
284 */
285C_ENTRY(_user_exception):
Michal Simekca545022009-05-26 16:30:21 +0200286 addi r14, r14, 4 /* return address is 4 byte after call */
Michal Simek0e41c902010-06-22 21:11:49 +0200287 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
Michal Simekca545022009-05-26 16:30:21 +0200288
Michal Simekca545022009-05-26 16:30:21 +0200289 lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
290 tophys(r1,r1);
291 lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */
Michal Simek0e41c902010-06-22 21:11:49 +0200292 /* MS these three instructions can be added to one */
293 /* addik r1, r1, THREAD_SIZE; */
294 /* tophys(r1,r1); */
295 /* addik r1, r1, -STATE_SAVE_SIZE; */
296 addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE;
Michal Simekca545022009-05-26 16:30:21 +0200297 SAVE_REGS
298
Michal Simekca545022009-05-26 16:30:21 +0200299 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
300 swi r11, r1, PTO+PT_R1; /* Store user SP. */
Michal Simek25f6e592010-06-22 18:29:05 +0200301 clear_ums;
Michal Simek0e41c902010-06-22 21:11:49 +0200302 lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
Michal Simekca545022009-05-26 16:30:21 +0200303 /* Save away the syscall number. */
304 swi r12, r1, PTO+PT_R0;
305 tovirt(r1,r1)
306
Michal Simekca545022009-05-26 16:30:21 +0200307/* where the trap should return need -8 to adjust for rtsd r15, 8*/
308/* Jump to the appropriate function for the system call number in r12
309 * (r12 is not preserved), or return an error if r12 is not valid. The LP
310 * register should point to the location where
311 * the called function should return. [note that MAKE_SYS_CALL uses label 1] */
Michal Simek23575482009-08-24 13:26:04 +0200312
Michal Simek25f6e592010-06-22 18:29:05 +0200313 /* Step into virtual mode */
314 rtbd r0, 3f
Michal Simek23575482009-08-24 13:26:04 +0200315 nop
3163:
Michal Simekb1d70c62010-01-22 10:24:06 +0100317 lwi r11, CURRENT_TASK, TS_THREAD_INFO /* get thread info */
Michal Simek23575482009-08-24 13:26:04 +0200318 lwi r11, r11, TI_FLAGS /* get flags in thread info */
319 andi r11, r11, _TIF_WORK_SYSCALL_MASK
320 beqi r11, 4f
321
322 addik r3, r0, -ENOSYS
323 swi r3, r1, PTO + PT_R3
324 brlid r15, do_syscall_trace_enter
325 addik r5, r1, PTO + PT_R0
326
327 # do_syscall_trace_enter returns the new syscall nr.
328 addk r12, r0, r3
329 lwi r5, r1, PTO+PT_R5;
330 lwi r6, r1, PTO+PT_R6;
331 lwi r7, r1, PTO+PT_R7;
332 lwi r8, r1, PTO+PT_R8;
333 lwi r9, r1, PTO+PT_R9;
334 lwi r10, r1, PTO+PT_R10;
3354:
336/* Jump to the appropriate function for the system call number in r12
337 * (r12 is not preserved), or return an error if r12 is not valid.
338 * The LP register should point to the location where the called function
339 * should return. [note that MAKE_SYS_CALL uses label 1] */
340 /* See if the system call number is valid */
Michal Simekca545022009-05-26 16:30:21 +0200341 addi r11, r12, -__NR_syscalls;
Michal Simek23575482009-08-24 13:26:04 +0200342 bgei r11,5f;
Michal Simekca545022009-05-26 16:30:21 +0200343 /* Figure out which function to use for this system call. */
344 /* Note Microblaze barrel shift is optional, so don't rely on it */
345 add r12, r12, r12; /* convert num -> ptr */
346 add r12, r12, r12;
347
Michal Simek11d51362009-12-07 08:21:34 +0100348#ifdef DEBUG
Michal Simekca545022009-05-26 16:30:21 +0200349 /* Trac syscalls and stored them to r0_ram */
Michal Simek23575482009-08-24 13:26:04 +0200350 lwi r3, r12, 0x400 + r0_ram
Michal Simekca545022009-05-26 16:30:21 +0200351 addi r3, r3, 1
Michal Simek23575482009-08-24 13:26:04 +0200352 swi r3, r12, 0x400 + r0_ram
Michal Simek11d51362009-12-07 08:21:34 +0100353#endif
Michal Simekca545022009-05-26 16:30:21 +0200354
Michal Simek23575482009-08-24 13:26:04 +0200355 # Find and jump into the syscall handler.
356 lwi r12, r12, sys_call_table
357 /* where the trap should return need -8 to adjust for rtsd r15, 8 */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200358 addi r15, r0, ret_from_trap-8
Michal Simek23575482009-08-24 13:26:04 +0200359 bra r12
360
Michal Simekca545022009-05-26 16:30:21 +0200361 /* The syscall number is invalid, return an error. */
Michal Simek23575482009-08-24 13:26:04 +02003625:
Michal Simek9814cc12010-06-22 18:09:29 +0200363 rtsd r15, 8; /* looks like a normal subroutine return */
Michal Simekca545022009-05-26 16:30:21 +0200364 addi r3, r0, -ENOSYS;
Michal Simekca545022009-05-26 16:30:21 +0200365
Michal Simek23575482009-08-24 13:26:04 +0200366/* Entry point used to return from a syscall/trap */
Michal Simekca545022009-05-26 16:30:21 +0200367/* We re-enable BIP bit before state restore */
368C_ENTRY(ret_from_trap):
Michal Simekb1d70c62010-01-22 10:24:06 +0100369 swi r3, r1, PTO + PT_R3
370 swi r4, r1, PTO + PT_R4
371
Michal Simekca545022009-05-26 16:30:21 +0200372 /* We're returning to user mode, so check for various conditions that
373 * trigger rescheduling. */
Michal Simekb1d70c62010-01-22 10:24:06 +0100374 /* FIXME: Restructure all these flag checks. */
375 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simek23575482009-08-24 13:26:04 +0200376 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
377 andi r11, r11, _TIF_WORK_SYSCALL_MASK
378 beqi r11, 1f
379
Michal Simek23575482009-08-24 13:26:04 +0200380 brlid r15, do_syscall_trace_leave
381 addik r5, r1, PTO + PT_R0
Michal Simek23575482009-08-24 13:26:04 +02003821:
Michal Simek23575482009-08-24 13:26:04 +0200383 /* We're returning to user mode, so check for various conditions that
384 * trigger rescheduling. */
Michal Simekb1d70c62010-01-22 10:24:06 +0100385 /* get thread info from current task */
386 lwi r11, CURRENT_TASK, TS_THREAD_INFO;
Michal Simekca545022009-05-26 16:30:21 +0200387 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
388 andi r11, r11, _TIF_NEED_RESCHED;
389 beqi r11, 5f;
390
Michal Simekca545022009-05-26 16:30:21 +0200391 bralid r15, schedule; /* Call scheduler */
392 nop; /* delay slot */
Michal Simekca545022009-05-26 16:30:21 +0200393
394 /* Maybe handle a signal */
Michal Simekb1d70c62010-01-22 10:24:06 +01003955: /* get thread info from current task*/
396 lwi r11, CURRENT_TASK, TS_THREAD_INFO;
Michal Simekca545022009-05-26 16:30:21 +0200397 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
398 andi r11, r11, _TIF_SIGPENDING;
399 beqi r11, 1f; /* Signals to handle, handle them */
400
Michal Simekb9ea77e2010-07-28 12:40:02 +0200401 addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
Michal Simekca545022009-05-26 16:30:21 +0200402 addi r7, r0, 1; /* Arg 3: int in_syscall */
403 bralid r15, do_signal; /* Handle any signals */
Michal Simek841d6e82010-01-22 14:28:36 +0100404 add r6, r0, r0; /* Arg 2: sigset_t *oldset */
Michal Simekb1d70c62010-01-22 10:24:06 +0100405
406/* Finally, return to user state. */
Michal Simek96014cc2010-06-22 14:05:43 +02004071: set_bip; /* Ints masked for state restore */
Michal Simek8633beb2010-02-22 13:24:43 +0100408 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
Michal Simekca545022009-05-26 16:30:21 +0200409 VM_OFF;
410 tophys(r1,r1);
411 RESTORE_REGS;
412 addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
413 lwi r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
Michal Simekca545022009-05-26 16:30:21 +0200414TRAP_return: /* Make global symbol for debugging */
415 rtbd r14, 0; /* Instructions to return from an IRQ */
416 nop;
417
418
419/* These syscalls need access to the struct pt_regs on the stack, so we
420 implement them in assembly (they're basically all wrappers anyway). */
421
422C_ENTRY(sys_fork_wrapper):
423 addi r5, r0, SIGCHLD /* Arg 0: flags */
424 lwi r6, r1, PTO+PT_R1 /* Arg 1: child SP (use parent's) */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200425 addik r7, r1, PTO /* Arg 2: parent context */
Michal Simekca545022009-05-26 16:30:21 +0200426 add r8. r0, r0 /* Arg 3: (unused) */
427 add r9, r0, r0; /* Arg 4: (unused) */
Michal Simekca545022009-05-26 16:30:21 +0200428 brid do_fork /* Do real work (tail-call) */
Michal Simek9814cc12010-06-22 18:09:29 +0200429 add r10, r0, r0; /* Arg 5: (unused) */
Michal Simekca545022009-05-26 16:30:21 +0200430
431/* This the initial entry point for a new child thread, with an appropriate
432 stack in place that makes it look the the child is in the middle of an
433 syscall. This function is actually `returned to' from switch_thread
434 (copy_thread makes ret_from_fork the return address in each new thread's
435 saved context). */
436C_ENTRY(ret_from_fork):
437 bralid r15, schedule_tail; /* ...which is schedule_tail's arg */
438 add r3, r5, r0; /* switch_thread returns the prev task */
439 /* ( in the delay slot ) */
Michal Simekca545022009-05-26 16:30:21 +0200440 brid ret_from_trap; /* Do normal trap return */
Michal Simek9814cc12010-06-22 18:09:29 +0200441 add r3, r0, r0; /* Child's fork call should return 0. */
Michal Simekca545022009-05-26 16:30:21 +0200442
Arnd Bergmanne5135882009-06-18 19:55:30 +0200443C_ENTRY(sys_vfork):
444 brid microblaze_vfork /* Do real work (tail-call) */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200445 addik r5, r1, PTO
Michal Simekca545022009-05-26 16:30:21 +0200446
Arnd Bergmanne5135882009-06-18 19:55:30 +0200447C_ENTRY(sys_clone):
Michal Simekca545022009-05-26 16:30:21 +0200448 bnei r6, 1f; /* See if child SP arg (arg 1) is 0. */
Michal Simek570e3e22010-06-04 13:06:27 +0200449 lwi r6, r1, PTO + PT_R1; /* If so, use paret's stack ptr */
Michal Simekb9ea77e2010-07-28 12:40:02 +02004501: addik r7, r1, PTO; /* Arg 2: parent context */
451 add r8, r0, r0; /* Arg 3: (unused) */
452 add r9, r0, r0; /* Arg 4: (unused) */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200453 brid do_fork /* Do real work (tail-call) */
Michal Simek9814cc12010-06-22 18:09:29 +0200454 add r10, r0, r0; /* Arg 5: (unused) */
Michal Simekca545022009-05-26 16:30:21 +0200455
Arnd Bergmanne5135882009-06-18 19:55:30 +0200456C_ENTRY(sys_execve):
Arnd Bergmanne5135882009-06-18 19:55:30 +0200457 brid microblaze_execve; /* Do real work (tail-call).*/
Michal Simek9814cc12010-06-22 18:09:29 +0200458 addik r8, r1, PTO; /* add user context as 4th arg */
Michal Simekca545022009-05-26 16:30:21 +0200459
Michal Simekca545022009-05-26 16:30:21 +0200460C_ENTRY(sys_rt_sigreturn_wrapper):
461 swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
462 swi r4, r1, PTO+PT_R4;
Michal Simekca545022009-05-26 16:30:21 +0200463 brlid r15, sys_rt_sigreturn /* Do real work */
Michal Simek9814cc12010-06-22 18:09:29 +0200464 addik r5, r1, PTO; /* add user context as 1st arg */
Michal Simekca545022009-05-26 16:30:21 +0200465 lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
466 lwi r4, r1, PTO+PT_R4;
467 bri ret_from_trap /* fall through will not work here due to align */
468 nop;
469
470/*
471 * HW EXCEPTION rutine start
472 */
Michal Simekca545022009-05-26 16:30:21 +0200473C_ENTRY(full_exception_trap):
Michal Simekca545022009-05-26 16:30:21 +0200474 /* adjust exception address for privileged instruction
475 * for finding where is it */
476 addik r17, r17, -4
477 SAVE_STATE /* Save registers */
Michal Simek06a54602010-06-22 16:22:01 +0200478 /* PC, before IRQ/trap - this is one instruction above */
479 swi r17, r1, PTO+PT_PC;
480 tovirt(r1,r1)
Michal Simekca545022009-05-26 16:30:21 +0200481 /* FIXME this can be store directly in PT_ESR reg.
482 * I tested it but there is a fault */
483 /* where the trap should return need -8 to adjust for rtsd r15, 8 */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200484 addik r15, r0, ret_from_exc - 8
Michal Simekca545022009-05-26 16:30:21 +0200485 mfs r6, resr
Michal Simekca545022009-05-26 16:30:21 +0200486 mfs r7, rfsr; /* save FSR */
Michal Simek131e4e92009-09-28 08:50:53 +0200487 mts rfsr, r0; /* Clear sticky fsr */
Michal Simekc318d482010-06-22 16:25:31 +0200488 rted r0, full_exception
Michal Simek9814cc12010-06-22 18:09:29 +0200489 addik r5, r1, PTO /* parameter struct pt_regs * regs */
Michal Simekca545022009-05-26 16:30:21 +0200490
491/*
492 * Unaligned data trap.
493 *
494 * Unaligned data trap last on 4k page is handled here.
495 *
496 * Trap entered via exception, so EE bit is set, and interrupts
497 * are masked. This is nice, means we don't have to CLI before state save
498 *
499 * The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S"
500 */
501C_ENTRY(unaligned_data_trap):
Michal Simek8b110d12010-06-17 16:03:05 +0200502 /* MS: I have to save r11 value and then restore it because
503 * set_bit, clear_eip, set_ee use r11 as temp register if MSR
504 * instructions are not used. We don't need to do if MSR instructions
505 * are used and they use r0 instead of r11.
506 * I am using ENTRY_SP which should be primary used only for stack
507 * pointer saving. */
508 swi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
509 set_bip; /* equalize initial state for all possible entries */
510 clear_eip;
511 set_ee;
512 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
Michal Simekca545022009-05-26 16:30:21 +0200513 SAVE_STATE /* Save registers.*/
Michal Simek06a54602010-06-22 16:22:01 +0200514 /* PC, before IRQ/trap - this is one instruction above */
515 swi r17, r1, PTO+PT_PC;
516 tovirt(r1,r1)
Michal Simekca545022009-05-26 16:30:21 +0200517 /* where the trap should return need -8 to adjust for rtsd r15, 8 */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200518 addik r15, r0, ret_from_exc-8
Michal Simekca545022009-05-26 16:30:21 +0200519 mfs r3, resr /* ESR */
Michal Simekca545022009-05-26 16:30:21 +0200520 mfs r4, rear /* EAR */
Michal Simekc318d482010-06-22 16:25:31 +0200521 rtbd r0, _unaligned_data_exception
Michal Simekb9ea77e2010-07-28 12:40:02 +0200522 addik r7, r1, PTO /* parameter struct pt_regs * regs */
Michal Simekca545022009-05-26 16:30:21 +0200523
524/*
525 * Page fault traps.
526 *
527 * If the real exception handler (from hw_exception_handler.S) didn't find
528 * the mapping for the process, then we're thrown here to handle such situation.
529 *
530 * Trap entered via exceptions, so EE bit is set, and interrupts
531 * are masked. This is nice, means we don't have to CLI before state save
532 *
533 * Build a standard exception frame for TLB Access errors. All TLB exceptions
534 * will bail out to this point if they can't resolve the lightweight TLB fault.
535 *
536 * The C function called is in "arch/microblaze/mm/fault.c", declared as:
537 * void do_page_fault(struct pt_regs *regs,
538 * unsigned long address,
539 * unsigned long error_code)
540 */
541/* data and intruction trap - which is choose is resolved int fault.c */
542C_ENTRY(page_fault_data_trap):
Michal Simekca545022009-05-26 16:30:21 +0200543 SAVE_STATE /* Save registers.*/
Michal Simek06a54602010-06-22 16:22:01 +0200544 /* PC, before IRQ/trap - this is one instruction above */
545 swi r17, r1, PTO+PT_PC;
546 tovirt(r1,r1)
Michal Simekca545022009-05-26 16:30:21 +0200547 /* where the trap should return need -8 to adjust for rtsd r15, 8 */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200548 addik r15, r0, ret_from_exc-8
Michal Simekca545022009-05-26 16:30:21 +0200549 mfs r6, rear /* parameter unsigned long address */
Michal Simekca545022009-05-26 16:30:21 +0200550 mfs r7, resr /* parameter unsigned long error_code */
Michal Simekc318d482010-06-22 16:25:31 +0200551 rted r0, do_page_fault
Michal Simek9814cc12010-06-22 18:09:29 +0200552 addik r5, r1, PTO /* parameter struct pt_regs * regs */
Michal Simekca545022009-05-26 16:30:21 +0200553
554C_ENTRY(page_fault_instr_trap):
Michal Simekca545022009-05-26 16:30:21 +0200555 SAVE_STATE /* Save registers.*/
Michal Simek06a54602010-06-22 16:22:01 +0200556 /* PC, before IRQ/trap - this is one instruction above */
557 swi r17, r1, PTO+PT_PC;
558 tovirt(r1,r1)
Michal Simekca545022009-05-26 16:30:21 +0200559 /* where the trap should return need -8 to adjust for rtsd r15, 8 */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200560 addik r15, r0, ret_from_exc-8
Michal Simekca545022009-05-26 16:30:21 +0200561 mfs r6, rear /* parameter unsigned long address */
Michal Simekca545022009-05-26 16:30:21 +0200562 ori r7, r0, 0 /* parameter unsigned long error_code */
Michal Simek9814cc12010-06-22 18:09:29 +0200563 rted r0, do_page_fault
564 addik r5, r1, PTO /* parameter struct pt_regs * regs */
Michal Simekca545022009-05-26 16:30:21 +0200565
566/* Entry point used to return from an exception. */
567C_ENTRY(ret_from_exc):
Michal Simek77f6d222010-06-22 16:39:56 +0200568 lwi r11, r1, PTO + PT_MODE;
Michal Simekca545022009-05-26 16:30:21 +0200569 bnei r11, 2f; /* See if returning to kernel mode, */
570 /* ... if so, skip resched &c. */
571
572 /* We're returning to user mode, so check for various conditions that
573 trigger rescheduling. */
Michal Simekb1d70c62010-01-22 10:24:06 +0100574 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simekca545022009-05-26 16:30:21 +0200575 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
576 andi r11, r11, _TIF_NEED_RESCHED;
577 beqi r11, 5f;
578
579/* Call the scheduler before returning from a syscall/trap. */
580 bralid r15, schedule; /* Call scheduler */
581 nop; /* delay slot */
582
583 /* Maybe handle a signal */
Michal Simekb1d70c62010-01-22 10:24:06 +01005845: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simekca545022009-05-26 16:30:21 +0200585 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
586 andi r11, r11, _TIF_SIGPENDING;
587 beqi r11, 1f; /* Signals to handle, handle them */
588
589 /*
590 * Handle a signal return; Pending signals should be in r18.
591 *
592 * Not all registers are saved by the normal trap/interrupt entry
593 * points (for instance, call-saved registers (because the normal
594 * C-compiler calling sequence in the kernel makes sure they're
595 * preserved), and call-clobbered registers in the case of
596 * traps), but signal handlers may want to examine or change the
597 * complete register state. Here we save anything not saved by
598 * the normal entry sequence, so that it may be safely restored
Michal Simek36f60952010-06-22 13:27:43 +0200599 * (in a possibly modified form) after do_signal returns. */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200600 addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
Michal Simekca545022009-05-26 16:30:21 +0200601 addi r7, r0, 0; /* Arg 3: int in_syscall */
602 bralid r15, do_signal; /* Handle any signals */
Michal Simek841d6e82010-01-22 14:28:36 +0100603 add r6, r0, r0; /* Arg 2: sigset_t *oldset */
Michal Simekca545022009-05-26 16:30:21 +0200604
605/* Finally, return to user state. */
Michal Simek96014cc2010-06-22 14:05:43 +02006061: set_bip; /* Ints masked for state restore */
Michal Simek8633beb2010-02-22 13:24:43 +0100607 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
Michal Simekca545022009-05-26 16:30:21 +0200608 VM_OFF;
609 tophys(r1,r1);
610
Michal Simekca545022009-05-26 16:30:21 +0200611 RESTORE_REGS;
612 addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
613
614 lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */
615 bri 6f;
616/* Return to kernel state. */
Michal Simek96014cc2010-06-22 14:05:43 +02006172: set_bip; /* Ints masked for state restore */
618 VM_OFF;
Michal Simekca545022009-05-26 16:30:21 +0200619 tophys(r1,r1);
Michal Simekca545022009-05-26 16:30:21 +0200620 RESTORE_REGS;
621 addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
622
623 tovirt(r1,r1);
6246:
625EXC_return: /* Make global symbol for debugging */
626 rtbd r14, 0; /* Instructions to return from an IRQ */
627 nop;
628
629/*
630 * HW EXCEPTION rutine end
631 */
632
633/*
634 * Hardware maskable interrupts.
635 *
636 * The stack-pointer (r1) should have already been saved to the memory
637 * location PER_CPU(ENTRY_SP).
638 */
639C_ENTRY(_interrupt):
640/* MS: we are in physical address */
641/* Save registers, switch to proper stack, convert SP to virtual.*/
642 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
Michal Simekca545022009-05-26 16:30:21 +0200643 /* MS: See if already in kernel mode. */
Michal Simek653e4472010-06-22 14:51:45 +0200644 mfs r1, rmsr
Michal Simek5c0d72b2010-06-22 14:00:12 +0200645 nop
Michal Simek653e4472010-06-22 14:51:45 +0200646 andi r1, r1, MSR_UMS
647 bnei r1, 1f
Michal Simekca545022009-05-26 16:30:21 +0200648
649/* Kernel-mode state save. */
Michal Simek653e4472010-06-22 14:51:45 +0200650 lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
651 tophys(r1,r1); /* MS: I have in r1 physical address where stack is */
Michal Simekca545022009-05-26 16:30:21 +0200652 /* save registers */
653/* MS: Make room on the stack -> activation record */
654 addik r1, r1, -STATE_SAVE_SIZE;
Michal Simekca545022009-05-26 16:30:21 +0200655 SAVE_REGS
Michal Simekca545022009-05-26 16:30:21 +0200656 brid 2f;
Michal Simek0a6b08f2010-06-22 20:49:46 +0200657 swi r1, r1, PTO + PT_MODE; /* 0 - user mode, 1 - kernel mode */
Michal Simekca545022009-05-26 16:30:21 +02006581:
659/* User-mode state save. */
Michal Simekca545022009-05-26 16:30:21 +0200660 /* MS: get the saved current */
661 lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
662 tophys(r1,r1);
663 lwi r1, r1, TS_THREAD_INFO;
664 addik r1, r1, THREAD_SIZE;
665 tophys(r1,r1);
666 /* save registers */
667 addik r1, r1, -STATE_SAVE_SIZE;
Michal Simekca545022009-05-26 16:30:21 +0200668 SAVE_REGS
669 /* calculate mode */
670 swi r0, r1, PTO + PT_MODE;
671 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
672 swi r11, r1, PTO+PT_R1;
Michal Simek80c5ff62010-06-22 18:50:31 +0200673 clear_ums;
Michal Simekca545022009-05-26 16:30:21 +02006742:
Michal Simekb1d70c62010-01-22 10:24:06 +0100675 lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
Michal Simekca545022009-05-26 16:30:21 +0200676 tovirt(r1,r1)
Michal Simekb9ea77e2010-07-28 12:40:02 +0200677 addik r15, r0, irq_call;
Michal Simek80c5ff62010-06-22 18:50:31 +0200678irq_call:rtbd r0, do_IRQ;
679 addik r5, r1, PTO;
Michal Simekca545022009-05-26 16:30:21 +0200680
681/* MS: we are in virtual mode */
682ret_from_irq:
683 lwi r11, r1, PTO + PT_MODE;
684 bnei r11, 2f;
685
Michal Simekb1d70c62010-01-22 10:24:06 +0100686 lwi r11, CURRENT_TASK, TS_THREAD_INFO;
Michal Simekca545022009-05-26 16:30:21 +0200687 lwi r11, r11, TI_FLAGS; /* MS: get flags from thread info */
688 andi r11, r11, _TIF_NEED_RESCHED;
689 beqi r11, 5f
690 bralid r15, schedule;
691 nop; /* delay slot */
692
693 /* Maybe handle a signal */
Michal Simekb1d70c62010-01-22 10:24:06 +01006945: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */
Michal Simekca545022009-05-26 16:30:21 +0200695 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
696 andi r11, r11, _TIF_SIGPENDING;
697 beqid r11, no_intr_resched
698/* Handle a signal return; Pending signals should be in r18. */
699 addi r7, r0, 0; /* Arg 3: int in_syscall */
Michal Simekb9ea77e2010-07-28 12:40:02 +0200700 addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
Michal Simekca545022009-05-26 16:30:21 +0200701 bralid r15, do_signal; /* Handle any signals */
702 add r6, r0, r0; /* Arg 2: sigset_t *oldset */
703
704/* Finally, return to user state. */
705no_intr_resched:
706 /* Disable interrupts, we are now committed to the state restore */
707 disable_irq
Michal Simek8633beb2010-02-22 13:24:43 +0100708 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE);
Michal Simekca545022009-05-26 16:30:21 +0200709 VM_OFF;
710 tophys(r1,r1);
Michal Simekca545022009-05-26 16:30:21 +0200711 RESTORE_REGS
712 addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
713 lwi r1, r1, PT_R1 - PT_SIZE;
714 bri 6f;
715/* MS: Return to kernel state. */
Michal Simek77753792010-01-12 09:55:10 +01007162:
717#ifdef CONFIG_PREEMPT
Michal Simekb1d70c62010-01-22 10:24:06 +0100718 lwi r11, CURRENT_TASK, TS_THREAD_INFO;
Michal Simek77753792010-01-12 09:55:10 +0100719 /* MS: get preempt_count from thread info */
720 lwi r5, r11, TI_PREEMPT_COUNT;
721 bgti r5, restore;
722
723 lwi r5, r11, TI_FLAGS; /* get flags in thread info */
724 andi r5, r5, _TIF_NEED_RESCHED;
725 beqi r5, restore /* if zero jump over */
726
727preempt:
728 /* interrupts are off that's why I am calling preempt_chedule_irq */
729 bralid r15, preempt_schedule_irq
730 nop
Michal Simekb1d70c62010-01-22 10:24:06 +0100731 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simek77753792010-01-12 09:55:10 +0100732 lwi r5, r11, TI_FLAGS; /* get flags in thread info */
733 andi r5, r5, _TIF_NEED_RESCHED;
734 bnei r5, preempt /* if non zero jump to resched */
735restore:
736#endif
737 VM_OFF /* MS: turn off MMU */
Michal Simekca545022009-05-26 16:30:21 +0200738 tophys(r1,r1)
Michal Simekca545022009-05-26 16:30:21 +0200739 RESTORE_REGS
740 addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
741 tovirt(r1,r1);
7426:
743IRQ_return: /* MS: Make global symbol for debugging */
744 rtid r14, 0
745 nop
746
747/*
748 * `Debug' trap
749 * We enter dbtrap in "BIP" (breakpoint) mode.
750 * So we exit the breakpoint mode with an 'rtbd' and proceed with the
751 * original dbtrap.
752 * however, wait to save state first
753 */
754C_ENTRY(_debug_exception):
755 /* BIP bit is set on entry, no interrupts can occur */
756 swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
757
Michal Simek653e4472010-06-22 14:51:45 +0200758 mfs r1, rmsr
Michal Simek5c0d72b2010-06-22 14:00:12 +0200759 nop
Michal Simek653e4472010-06-22 14:51:45 +0200760 andi r1, r1, MSR_UMS
761 bnei r1, 1f
Michal Simekca545022009-05-26 16:30:21 +0200762 /* Kernel-mode state save. */
Michal Simek653e4472010-06-22 14:51:45 +0200763 lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
764 tophys(r1,r1);
Michal Simekca545022009-05-26 16:30:21 +0200765
766 addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
Michal Simekca545022009-05-26 16:30:21 +0200767 SAVE_REGS;
768
Michal Simek77f6d222010-06-22 16:39:56 +0200769 swi r1, r1, PTO + PT_MODE;
Michal Simekca545022009-05-26 16:30:21 +0200770 brid 2f;
771 nop; /* Fill delay slot */
7721: /* User-mode state save. */
Michal Simekca545022009-05-26 16:30:21 +0200773 lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
774 tophys(r1,r1);
775 lwi r1, r1, TS_THREAD_INFO; /* get the thread info */
776 addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */
777 tophys(r1,r1);
778
779 addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
Michal Simekca545022009-05-26 16:30:21 +0200780 SAVE_REGS;
Michal Simek751f1602010-08-03 11:26:51 +0200781 swi r17, r1, PTO+PT_R17;
782 swi r16, r1, PTO+PT_R16;
783 swi r16, r1, PTO+PT_PC; /* Save LP */
Michal Simekca545022009-05-26 16:30:21 +0200784
Michal Simek77f6d222010-06-22 16:39:56 +0200785 swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */
Michal Simekca545022009-05-26 16:30:21 +0200786 lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
787 swi r11, r1, PTO+PT_R1; /* Store user SP. */
Michal Simek751f1602010-08-03 11:26:51 +02007882: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
Michal Simekca545022009-05-26 16:30:21 +0200789 tovirt(r1,r1)
790
Michal Simek06b28642010-06-22 15:25:24 +0200791 set_vms;
Michal Simek751f1602010-08-03 11:26:51 +0200792 addik r5, r1, PTO;
Michal Simekb9ea77e2010-07-28 12:40:02 +0200793 addik r15, r0, dbtrap_call;
Michal Simek751f1602010-08-03 11:26:51 +0200794dbtrap_call: /* return point for kernel/user entry */
795 rtbd r0, sw_exception
796 nop
Michal Simekca545022009-05-26 16:30:21 +0200797
798 set_bip; /* Ints masked for state restore*/
Michal Simek77f6d222010-06-22 16:39:56 +0200799 lwi r11, r1, PTO + PT_MODE;
Michal Simekca545022009-05-26 16:30:21 +0200800 bnei r11, 2f;
801
802 /* Get current task ptr into r11 */
Michal Simekb1d70c62010-01-22 10:24:06 +0100803 lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simekca545022009-05-26 16:30:21 +0200804 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
805 andi r11, r11, _TIF_NEED_RESCHED;
806 beqi r11, 5f;
807
808/* Call the scheduler before returning from a syscall/trap. */
809
810 bralid r15, schedule; /* Call scheduler */
811 nop; /* delay slot */
812 /* XXX Is PT_DTRACE handling needed here? */
813 /* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here. */
814
815 /* Maybe handle a signal */
Michal Simekb1d70c62010-01-22 10:24:06 +01008165: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
Michal Simekca545022009-05-26 16:30:21 +0200817 lwi r11, r11, TI_FLAGS; /* get flags in thread info */
818 andi r11, r11, _TIF_SIGPENDING;
819 beqi r11, 1f; /* Signals to handle, handle them */
820
821/* Handle a signal return; Pending signals should be in r18. */
822 /* Not all registers are saved by the normal trap/interrupt entry
823 points (for instance, call-saved registers (because the normal
824 C-compiler calling sequence in the kernel makes sure they're
825 preserved), and call-clobbered registers in the case of
826 traps), but signal handlers may want to examine or change the
827 complete register state. Here we save anything not saved by
828 the normal entry sequence, so that it may be safely restored
829 (in a possibly modified form) after do_signal returns. */
830
Michal Simekb9ea77e2010-07-28 12:40:02 +0200831 addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
Michal Simekca545022009-05-26 16:30:21 +0200832 addi r7, r0, 0; /* Arg 3: int in_syscall */
833 bralid r15, do_signal; /* Handle any signals */
Michal Simek841d6e82010-01-22 14:28:36 +0100834 add r6, r0, r0; /* Arg 2: sigset_t *oldset */
Michal Simekca545022009-05-26 16:30:21 +0200835
836
837/* Finally, return to user state. */
Michal Simek5c0d72b2010-06-22 14:00:12 +02008381:
Michal Simek8633beb2010-02-22 13:24:43 +0100839 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
Michal Simekca545022009-05-26 16:30:21 +0200840 VM_OFF;
841 tophys(r1,r1);
842
Michal Simekca545022009-05-26 16:30:21 +0200843 RESTORE_REGS
Michal Simek751f1602010-08-03 11:26:51 +0200844 lwi r17, r1, PTO+PT_R17;
845 lwi r16, r1, PTO+PT_R16;
Michal Simekca545022009-05-26 16:30:21 +0200846 addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
847
848
849 lwi r1, r1, PT_R1 - PT_SIZE;
850 /* Restore user stack pointer. */
851 bri 6f;
852
853/* Return to kernel state. */
8542: VM_OFF;
855 tophys(r1,r1);
Michal Simekca545022009-05-26 16:30:21 +0200856 RESTORE_REGS
857 addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
858
859 tovirt(r1,r1);
8606:
861DBTRAP_return: /* Make global symbol for debugging */
Michal Simek751f1602010-08-03 11:26:51 +0200862 rtbd r16, 0; /* Instructions to return from an IRQ */
Michal Simekca545022009-05-26 16:30:21 +0200863 nop;
864
865
Michal Simekca545022009-05-26 16:30:21 +0200866ENTRY(_switch_to)
867 /* prepare return value */
Michal Simekb1d70c62010-01-22 10:24:06 +0100868 addk r3, r0, CURRENT_TASK
Michal Simekca545022009-05-26 16:30:21 +0200869
870 /* save registers in cpu_context */
871 /* use r11 and r12, volatile registers, as temp register */
872 /* give start of cpu_context for previous process */
873 addik r11, r5, TI_CPU_CONTEXT
874 swi r1, r11, CC_R1
875 swi r2, r11, CC_R2
876 /* skip volatile registers.
877 * they are saved on stack when we jumped to _switch_to() */
878 /* dedicated registers */
879 swi r13, r11, CC_R13
880 swi r14, r11, CC_R14
881 swi r15, r11, CC_R15
882 swi r16, r11, CC_R16
883 swi r17, r11, CC_R17
884 swi r18, r11, CC_R18
885 /* save non-volatile registers */
886 swi r19, r11, CC_R19
887 swi r20, r11, CC_R20
888 swi r21, r11, CC_R21
889 swi r22, r11, CC_R22
890 swi r23, r11, CC_R23
891 swi r24, r11, CC_R24
892 swi r25, r11, CC_R25
893 swi r26, r11, CC_R26
894 swi r27, r11, CC_R27
895 swi r28, r11, CC_R28
896 swi r29, r11, CC_R29
897 swi r30, r11, CC_R30
898 /* special purpose registers */
899 mfs r12, rmsr
Michal Simekca545022009-05-26 16:30:21 +0200900 swi r12, r11, CC_MSR
901 mfs r12, rear
Michal Simekca545022009-05-26 16:30:21 +0200902 swi r12, r11, CC_EAR
903 mfs r12, resr
Michal Simekca545022009-05-26 16:30:21 +0200904 swi r12, r11, CC_ESR
905 mfs r12, rfsr
Michal Simekca545022009-05-26 16:30:21 +0200906 swi r12, r11, CC_FSR
907
Michal Simekb1d70c62010-01-22 10:24:06 +0100908 /* update r31, the current-give me pointer to task which will be next */
909 lwi CURRENT_TASK, r6, TI_TASK
Michal Simekca545022009-05-26 16:30:21 +0200910 /* stored it to current_save too */
Michal Simekb1d70c62010-01-22 10:24:06 +0100911 swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE)
Michal Simekca545022009-05-26 16:30:21 +0200912
913 /* get new process' cpu context and restore */
914 /* give me start where start context of next task */
915 addik r11, r6, TI_CPU_CONTEXT
916
917 /* non-volatile registers */
918 lwi r30, r11, CC_R30
919 lwi r29, r11, CC_R29
920 lwi r28, r11, CC_R28
921 lwi r27, r11, CC_R27
922 lwi r26, r11, CC_R26
923 lwi r25, r11, CC_R25
924 lwi r24, r11, CC_R24
925 lwi r23, r11, CC_R23
926 lwi r22, r11, CC_R22
927 lwi r21, r11, CC_R21
928 lwi r20, r11, CC_R20
929 lwi r19, r11, CC_R19
930 /* dedicated registers */
931 lwi r18, r11, CC_R18
932 lwi r17, r11, CC_R17
933 lwi r16, r11, CC_R16
934 lwi r15, r11, CC_R15
935 lwi r14, r11, CC_R14
936 lwi r13, r11, CC_R13
937 /* skip volatile registers */
938 lwi r2, r11, CC_R2
939 lwi r1, r11, CC_R1
940
941 /* special purpose registers */
942 lwi r12, r11, CC_FSR
943 mts rfsr, r12
Michal Simekca545022009-05-26 16:30:21 +0200944 lwi r12, r11, CC_MSR
945 mts rmsr, r12
Michal Simekca545022009-05-26 16:30:21 +0200946
947 rtsd r15, 8
948 nop
949
950ENTRY(_reset)
951 brai 0x70; /* Jump back to FS-boot */
952
Michal Simekca545022009-05-26 16:30:21 +0200953 /* These are compiled and loaded into high memory, then
954 * copied into place in mach_early_setup */
955 .section .init.ivt, "ax"
956 .org 0x0
957 /* this is very important - here is the reset vector */
958 /* in current MMU branch you don't care what is here - it is
959 * used from bootloader site - but this is correct for FS-BOOT */
960 brai 0x70
961 nop
962 brai TOPHYS(_user_exception); /* syscall handler */
963 brai TOPHYS(_interrupt); /* Interrupt handler */
Michal Simek751f1602010-08-03 11:26:51 +0200964 brai TOPHYS(_debug_exception); /* debug trap handler */
Michal Simekca545022009-05-26 16:30:21 +0200965 brai TOPHYS(_hw_exception_handler); /* HW exception handler */
966
Michal Simekca545022009-05-26 16:30:21 +0200967.section .rodata,"a"
968#include "syscall_table.S"
969
970syscall_table_size=(.-sys_call_table)
971
Steven J. Magnanice3266c2010-04-27 12:37:54 -0500972type_SYSCALL:
973 .ascii "SYSCALL\0"
974type_IRQ:
975 .ascii "IRQ\0"
976type_IRQ_PREEMPT:
977 .ascii "IRQ (PREEMPTED)\0"
978type_SYSCALL_PREEMPT:
979 .ascii " SYSCALL (PREEMPTED)\0"
980
981 /*
982 * Trap decoding for stack unwinder
983 * Tuples are (start addr, end addr, string)
984 * If return address lies on [start addr, end addr],
985 * unwinder displays 'string'
986 */
987
988 .align 4
989.global microblaze_trap_handlers
990microblaze_trap_handlers:
991 /* Exact matches come first */
992 .word ret_from_trap; .word ret_from_trap ; .word type_SYSCALL
993 .word ret_from_irq ; .word ret_from_irq ; .word type_IRQ
994 /* Fuzzy matches go here */
995 .word ret_from_irq ; .word no_intr_resched ; .word type_IRQ_PREEMPT
996 .word ret_from_trap; .word TRAP_return ; .word type_SYSCALL_PREEMPT
997 /* End of table */
998 .word 0 ; .word 0 ; .word 0