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
127
lwi r6, r31, TS_THREAD_INFO /* get thread info */
128
lwi r19, r6, TI_FLAGS /* get flags in thread info */
129
/* do an extra work if any bits are set */
131
andi r11, r19, _TIF_NEED_RESCHED
135
1: andi r11, r19, _TIF_SIGPENDING
136
beqid r11, no_intr_resched
139
bralid r15, do_signal
143
/* Disable interrupts, we are now committed to the state restore */
146
/* save mode indicator */
148
swi r11, r0, PER_CPU(KM)
151
swi r31, r0, PER_CPU(CURRENT_SAVE)
153
/* special purpose registers */
200
ENTRY(_user_exception)
201
swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
202
swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
203
lwi r11, r0, PER_CPU(KM) /* load mode indicator */
204
beqid r11, 1f /* Already in kernel mode? */
206
brid 2f /* jump over */
207
addik r1, r1, (-PT_SIZE) /* Room for pt_regs (delay slot) */
208
1: /* Switch to kernel stack */
209
lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */
210
lwi r1, r1, TS_THREAD_INFO /* get the thread info */
211
/* calculate kernel stack pointer */
212
addik r1, r1, THREAD_SIZE - PT_SIZE
214
swi r11, r1, PT_MODE /* store the mode */
215
lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
216
/* save them on stack */
218
swi r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */
219
swi r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */
227
/* r12: _always_ in clobber list; see unistd.h */
230
/* r14: _always_ in clobber list; see unistd.h */
232
/* but we want to return to the next inst. */
234
swi r14, r1, PT_PC /* increment by 4 and store in pc */
254
nop /* make sure IE bit is in effect */
255
clear_bip /* once IE is in effect it is safe to clear BIP */
258
/* special purpose registers */
267
/* reload original stack pointer and save it */
268
lwi r11, r0, PER_CPU(ENTRY_SP)
270
/* update mode indicator we are in kernel mode */
272
swi r11, r0, PER_CPU(KM)
274
lwi r31, r0, PER_CPU(CURRENT_SAVE)
275
/* re-enable interrupts now we are in kernel mode */
278
/* See if the system call number is valid. */
279
addi r11, r12, -__NR_syscalls
280
bgei r11, 1f /* return to user if not valid */
281
/* Figure out which function to use for this system call. */
282
/* Note Microblaze barrel shift is optional, so don't rely on it */
283
add r12, r12, r12 /* convert num -> ptr */
285
lwi r12, r12, sys_call_table /* Get function pointer */
286
addik r15, r0, ret_to_user-8 /* set return address */
287
bra r12 /* Make the system call. */
288
bri 0 /* won't reach here */
290
brid ret_to_user /* jump to syscall epilogue */
291
addi r3, r0, -ENOSYS /* set errno in delay slot */
294
* Debug traps are like a system call, but entered via brki r14, 0x60
295
* All we need to do is send the SIGTRAP signal to current, ptrace and do_signal
296
* will handle the rest
298
ENTRY(_debug_exception)
299
swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
300
lwi r1, r0, PER_CPU(CURRENT_SAVE) /* get the saved current */
301
lwi r1, r1, TS_THREAD_INFO /* get the thread info */
302
addik r1, r1, THREAD_SIZE - PT_SIZE /* get the kernel stack */
303
swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */
304
lwi r11, r0, PER_CPU(KM) /* load mode indicator */
306
swi r11, r1, PT_MODE /* store the mode */
307
lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
308
/* save them on stack */
310
swi r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */
311
swi r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */
319
/* r12: _always_ in clobber list; see unistd.h */
322
/* r14: _always_ in clobber list; see unistd.h */
324
swi r14, r1, PT_PC /* Will return to interrupted instruction */
344
nop /* make sure IE bit is in effect */
345
clear_bip /* once IE is in effect it is safe to clear BIP */
348
/* special purpose registers */
357
/* reload original stack pointer and save it */
358
lwi r11, r0, PER_CPU(ENTRY_SP)
360
/* update mode indicator we are in kernel mode */
362
swi r11, r0, PER_CPU(KM)
364
lwi r31, r0, PER_CPU(CURRENT_SAVE)
365
/* re-enable interrupts now we are in kernel mode */
368
addi r5, r0, SIGTRAP /* sending the trap signal */
369
add r6, r0, r31 /* to current */
371
add r7, r0, r0 /* 3rd param zero */
373
/* Restore r3/r4 to work around how ret_to_user works */
381
/* struct task_struct *_switch_to(struct thread_info *prev,
382
struct thread_info *next); */
384
/* prepare return value */
387
/* save registers in cpu_context */
388
/* use r11 and r12, volatile registers, as temp register */
389
addik r11, r5, TI_CPU_CONTEXT
392
/* skip volatile registers.
393
* they are saved on stack when we jumped to _switch_to() */
394
/* dedicated registers */
401
/* save non-volatile registers */
414
/* special purpose registers */
424
/* update r31, the current */
426
swi r31, r0, PER_CPU(CURRENT_SAVE)
428
/* get new process' cpu context and restore */
429
addik r11, r6, TI_CPU_CONTEXT
431
/* special purpose registers */
440
/* non-volatile registers */
453
/* dedicated registers */
460
/* skip volatile registers */
470
brlid r15, schedule_tail
472
swi r31, r1, PT_R31 /* save r31 in user context. */
473
/* will soon be restored to r31 in ret_to_user */
481
andi r11, r19, _TIF_NEED_RESCHED
485
1: andi r11, r19, _TIF_SIGPENDING
486
beqi r11, no_work_pending
489
bralid r15, do_signal
496
swi r4, r1, PT_R4 /* return val */
497
swi r3, r1, PT_R3 /* return val */
499
lwi r6, r31, TS_THREAD_INFO /* get thread info */
500
lwi r19, r6, TI_FLAGS /* get flags in thread info */
501
bnei r19, work_pending /* do an extra work if any bits are set */
506
swi r31, r0, PER_CPU(CURRENT_SAVE)
507
/* save mode indicator */
509
swi r18, r0, PER_CPU(KM)
511
/* special purpose registers */
548
lwi r4, r1, PT_R4 /* return val */
549
lwi r3, r1, PT_R3 /* return val */
557
brid microblaze_vfork
561
brid microblaze_clone
565
brid microblaze_execve
568
sys_rt_sigreturn_wrapper:
569
brid sys_rt_sigreturn
572
sys_rt_sigsuspend_wrapper:
573
brid sys_rt_sigsuspend
576
/* Interrupt vector table */
577
.section .init.ivt, "ax"
583
brai _hw_exception_handler
585
brai _debug_exception
588
#include "syscall_table.S"
590
syscall_table_size=(.-sys_call_table)
597
.ascii "IRQ (PREEMPTED)\0"
598
type_SYSCALL_PREEMPT:
599
.ascii " SYSCALL (PREEMPTED)\0"
602
* Trap decoding for stack unwinder
603
* Tuples are (start addr, end addr, string)
604
* If return address lies on [start addr, end addr],
605
* unwinder displays 'string'
609
.global microblaze_trap_handlers
610
microblaze_trap_handlers:
611
/* Exact matches come first */
612
.word ret_to_user ; .word ret_to_user ; .word type_SYSCALL
613
.word ret_from_intr; .word ret_from_intr ; .word type_IRQ
614
/* Fuzzy matches go here */
615
.word ret_from_intr; .word no_intr_resched; .word type_IRQ_PREEMPT
616
.word work_pending ; .word no_work_pending; .word type_SYSCALL_PREEMPT
618
.word 0 ; .word 0 ; .word 0