2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
11 #include <linux/linkage.h>
12 #include <asm/thread_info.h>
13 #include <linux/errno.h>
14 #include <asm/entry.h>
15 #include <asm/asm-offsets.h>
16 #include <asm/registers.h>
17 #include <asm/unistd.h>
18 #include <asm/percpu.h>
19 #include <asm/signal.h>
21 #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
36 andi r11, r11, ~MSR_IE
48 andi r11, r11, ~MSR_BIP
54 swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
55 swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
56 lwi r11, r0, PER_CPU(KM) /* load mode indicator */
59 brid 2f /* jump over */
60 addik r1, r1, (-PT_SIZE) /* room for pt_regs (delay slot) */
61 1: /* switch to kernel stack */
62 lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */
63 lwi r1, r1, TS_THREAD_INFO /* get the thread info */
64 /* calculate kernel stack pointer */
65 addik r1, r1, THREAD_SIZE - PT_SIZE
67 swi r11, r1, PT_MODE /* store the mode */
68 lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
100 /* special purpose registers */
109 /* reload original stack pointer and save it */
110 lwi r11, r0, PER_CPU(ENTRY_SP)
112 /* update mode indicator we are in kernel mode */
114 swi r11, r0, PER_CPU(KM)
116 lwi r31, r0, PER_CPU(CURRENT_SAVE)
117 /* prepare the link register, the argument and jump */
118 addik r15, r0, ret_from_intr - 8
125 bneid r11, no_intr_resched
128 lwi r6, r31, TS_THREAD_INFO /* get thread info */
129 lwi r19, r6, TI_FLAGS /* get flags in thread info */
130 /* do an extra work if any bits are set */
132 andi r11, r19, _TIF_NEED_RESCHED
137 1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
138 beqid r11, no_intr_resched
140 bralid r15, do_notify_resume
145 /* Disable interrupts, we are now committed to the state restore */
148 /* save mode indicator */
150 swi r11, r0, PER_CPU(KM)
153 swi r31, r0, PER_CPU(CURRENT_SAVE)
155 /* special purpose registers */
202 ENTRY(_user_exception)
203 swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
204 swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
205 lwi r11, r0, PER_CPU(KM) /* load mode indicator */
206 beqid r11, 1f /* Already in kernel mode? */
208 brid 2f /* jump over */
209 addik r1, r1, (-PT_SIZE) /* Room for pt_regs (delay slot) */
210 1: /* Switch to kernel stack */
211 lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */
212 lwi r1, r1, TS_THREAD_INFO /* get the thread info */
213 /* calculate kernel stack pointer */
214 addik r1, r1, THREAD_SIZE - PT_SIZE
216 swi r11, r1, PT_MODE /* store the mode */
217 lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
218 /* save them on stack */
220 swi r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */
221 swi r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */
229 /* r12: _always_ in clobber list; see unistd.h */
232 /* r14: _always_ in clobber list; see unistd.h */
234 /* but we want to return to the next inst. */
236 swi r14, r1, PT_PC /* increment by 4 and store in pc */
256 nop /* make sure IE bit is in effect */
257 clear_bip /* once IE is in effect it is safe to clear BIP */
260 /* special purpose registers */
269 /* reload original stack pointer and save it */
270 lwi r11, r0, PER_CPU(ENTRY_SP)
272 /* update mode indicator we are in kernel mode */
274 swi r11, r0, PER_CPU(KM)
276 lwi r31, r0, PER_CPU(CURRENT_SAVE)
277 /* re-enable interrupts now we are in kernel mode */
280 /* See if the system call number is valid. */
281 addi r11, r12, -__NR_syscalls
282 bgei r11, 1f /* return to user if not valid */
283 /* Figure out which function to use for this system call. */
284 /* Note Microblaze barrel shift is optional, so don't rely on it */
285 add r12, r12, r12 /* convert num -> ptr */
286 addik r30, r0, 1 /* restarts allowed */
288 lwi r12, r12, sys_call_table /* Get function pointer */
289 addik r15, r0, ret_to_user-8 /* set return address */
290 bra r12 /* Make the system call. */
291 bri 0 /* won't reach here */
293 brid ret_to_user /* jump to syscall epilogue */
294 addi r3, r0, -ENOSYS /* set errno in delay slot */
297 * Debug traps are like a system call, but entered via brki r14, 0x60
298 * All we need to do is send the SIGTRAP signal to current, ptrace and
299 * do_notify_resume will handle the rest
301 ENTRY(_debug_exception)
302 swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
303 lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */
304 lwi r1, r1, TS_THREAD_INFO /* get the thread info */
305 addik r1, r1, THREAD_SIZE - PT_SIZE /* get the kernel stack */
306 swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
307 lwi r11, r0, PER_CPU(KM) /* load mode indicator */
309 swi r11, r1, PT_MODE /* store the mode */
310 lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
311 /* save them on stack */
313 swi r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */
314 swi r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */
322 /* r12: _always_ in clobber list; see unistd.h */
325 /* r14: _always_ in clobber list; see unistd.h */
327 swi r14, r1, PT_PC /* Will return to interrupted instruction */
347 nop /* make sure IE bit is in effect */
348 clear_bip /* once IE is in effect it is safe to clear BIP */
351 /* special purpose registers */
360 /* reload original stack pointer and save it */
361 lwi r11, r0, PER_CPU(ENTRY_SP)
363 /* update mode indicator we are in kernel mode */
365 swi r11, r0, PER_CPU(KM)
367 lwi r31, r0, PER_CPU(CURRENT_SAVE)
368 /* re-enable interrupts now we are in kernel mode */
371 addi r5, r0, SIGTRAP /* sending the trap signal */
372 add r6, r0, r31 /* to current */
374 add r7, r0, r0 /* 3rd param zero */
376 addik r30, r0, 1 /* restarts allowed ??? */
377 /* Restore r3/r4 to work around how ret_to_user works */
385 /* struct task_struct *_switch_to(struct thread_info *prev,
386 struct thread_info *next); */
388 /* prepare return value */
391 /* save registers in cpu_context */
392 /* use r11 and r12, volatile registers, as temp register */
393 addik r11, r5, TI_CPU_CONTEXT
396 /* skip volatile registers.
397 * they are saved on stack when we jumped to _switch_to() */
398 /* dedicated registers */
405 /* save non-volatile registers */
418 /* special purpose registers */
428 /* update r31, the current */
430 swi r31, r0, PER_CPU(CURRENT_SAVE)
432 /* get new process' cpu context and restore */
433 addik r11, r6, TI_CPU_CONTEXT
435 /* special purpose registers */
444 /* non-volatile registers */
457 /* dedicated registers */
464 /* skip volatile registers */
473 brlid r15, schedule_tail
475 swi r31, r1, PT_R31 /* save r31 in user context. */
476 /* will soon be restored to r31 in ret_to_user */
481 ENTRY(ret_from_kernel_thread)
482 brlid r15, schedule_tail
494 andi r11, r19, _TIF_NEED_RESCHED
499 1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
500 beqi r11, no_work_pending
502 bralid r15, do_notify_resume
504 addk r30, r0, r0 /* no restarts from now on */
507 lwi r6, r31, TS_THREAD_INFO /* get thread info */
508 lwi r19, r6, TI_FLAGS /* get flags in thread info */
514 swi r4, r1, PT_R4 /* return val */
515 swi r3, r1, PT_R3 /* return val */
517 lwi r6, r31, TS_THREAD_INFO /* get thread info */
518 lwi r19, r6, TI_FLAGS /* get flags in thread info */
519 bnei r19, work_pending /* do an extra work if any bits are set */
525 swi r31, r0, PER_CPU(CURRENT_SAVE)
526 /* save mode indicator */
528 swi r18, r0, PER_CPU(KM)
530 /* special purpose registers */
567 lwi r4, r1, PT_R4 /* return val */
568 lwi r3, r1, PT_R3 /* return val */
575 sys_rt_sigreturn_wrapper:
576 addk r30, r0, r0 /* no restarts for this one */
577 brid sys_rt_sigreturn
580 /* Interrupt vector table */
581 .section .init.ivt, "ax"
587 brai _hw_exception_handler
589 brai _debug_exception
592 #include "syscall_table.S"
594 syscall_table_size=(.-sys_call_table)
601 .ascii "IRQ (PREEMPTED)\0"
602 type_SYSCALL_PREEMPT:
603 .ascii " SYSCALL (PREEMPTED)\0"
606 * Trap decoding for stack unwinder
607 * Tuples are (start addr, end addr, string)
608 * If return address lies on [start addr, end addr],
609 * unwinder displays 'string'
613 .global microblaze_trap_handlers
614 microblaze_trap_handlers:
615 /* Exact matches come first */
616 .word ret_to_user ; .word ret_to_user ; .word type_SYSCALL
617 .word ret_from_intr; .word ret_from_intr ; .word type_IRQ
618 /* Fuzzy matches go here */
619 .word ret_from_intr; .word no_intr_resched; .word type_IRQ_PREEMPT
620 .word work_pending ; .word no_work_pending; .word type_SYSCALL_PREEMPT
622 .word 0 ; .word 0 ; .word 0