aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm26/kernel/entry.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm26/kernel/entry.S')
-rw-r--r--arch/arm26/kernel/entry.S951
1 files changed, 0 insertions, 951 deletions
diff --git a/arch/arm26/kernel/entry.S b/arch/arm26/kernel/entry.S
deleted file mode 100644
index 7ffcc6e4770e..000000000000
--- a/arch/arm26/kernel/entry.S
+++ /dev/null
@@ -1,951 +0,0 @@
1/* arch/arm26/kernel/entry.S
2 *
3 * Assembled from chunks of code in arch/arm
4 *
5 * Copyright (C) 2003 Ian Molton
6 * Based on the work of RMK.
7 *
8 */
9
10#include <linux/linkage.h>
11
12#include <asm/assembler.h>
13#include <asm/asm-offsets.h>
14#include <asm/errno.h>
15#include <asm/hardware.h>
16#include <asm/sysirq.h>
17#include <asm/thread_info.h>
18#include <asm/page.h>
19#include <asm/ptrace.h>
20
21 .macro zero_fp
22#ifndef CONFIG_NO_FRAME_POINTER
23 mov fp, #0
24#endif
25 .endm
26
27 .text
28
29@ Bad Abort numbers
30@ -----------------
31@
32#define BAD_PREFETCH 0
33#define BAD_DATA 1
34#define BAD_ADDREXCPTN 2
35#define BAD_IRQ 3
36#define BAD_UNDEFINSTR 4
37
38@ OS version number used in SWIs
39@ RISC OS is 0
40@ RISC iX is 8
41@
42#define OS_NUMBER 9
43#define ARMSWI_OFFSET 0x000f0000
44
45@
46@ Stack format (ensured by USER_* and SVC_*)
47@ PSR and PC are comined on arm26
48@
49
50#define S_OFF 8
51
52#define S_OLD_R0 64
53#define S_PC 60
54#define S_LR 56
55#define S_SP 52
56#define S_IP 48
57#define S_FP 44
58#define S_R10 40
59#define S_R9 36
60#define S_R8 32
61#define S_R7 28
62#define S_R6 24
63#define S_R5 20
64#define S_R4 16
65#define S_R3 12
66#define S_R2 8
67#define S_R1 4
68#define S_R0 0
69
70 .macro save_user_regs
71 str r0, [sp, #-4]! @ Store SVC r0
72 str lr, [sp, #-4]! @ Store user mode PC
73 sub sp, sp, #15*4
74 stmia sp, {r0 - lr}^ @ Store the other user-mode regs
75 mov r0, r0
76 .endm
77
78 .macro slow_restore_user_regs
79 ldmia sp, {r0 - lr}^ @ restore the user regs not including PC
80 mov r0, r0
81 ldr lr, [sp, #15*4] @ get user PC
82 add sp, sp, #15*4+8 @ free stack
83 movs pc, lr @ return
84 .endm
85
86 .macro fast_restore_user_regs
87 add sp, sp, #S_OFF
88 ldmib sp, {r1 - lr}^
89 mov r0, r0
90 ldr lr, [sp, #15*4]
91 add sp, sp, #15*4+8
92 movs pc, lr
93 .endm
94
95 .macro save_svc_regs
96 str sp, [sp, #-16]!
97 str lr, [sp, #8]
98 str lr, [sp, #4]
99 stmfd sp!, {r0 - r12}
100 mov r0, #-1
101 str r0, [sp, #S_OLD_R0]
102 zero_fp
103 .endm
104
105 .macro save_svc_regs_irq
106 str sp, [sp, #-16]!
107 str lr, [sp, #4]
108 ldr lr, .LCirq
109 ldr lr, [lr]
110 str lr, [sp, #8]
111 stmfd sp!, {r0 - r12}
112 mov r0, #-1
113 str r0, [sp, #S_OLD_R0]
114 zero_fp
115 .endm
116
117 .macro restore_svc_regs
118 ldmfd sp, {r0 - pc}^
119 .endm
120
121 .macro mask_pc, rd, rm
122 bic \rd, \rm, #PCMASK
123 .endm
124
125 .macro disable_irqs, temp
126 mov \temp, pc
127 orr \temp, \temp, #PSR_I_BIT
128 teqp \temp, #0
129 .endm
130
131 .macro enable_irqs, temp
132 mov \temp, pc
133 and \temp, \temp, #~PSR_I_BIT
134 teqp \temp, #0
135 .endm
136
137 .macro initialise_traps_extra
138 .endm
139
140 .macro get_thread_info, rd
141 mov \rd, sp, lsr #13
142 mov \rd, \rd, lsl #13
143 .endm
144
145/*
146 * These are the registers used in the syscall handler, and allow us to
147 * have in theory up to 7 arguments to a function - r0 to r6.
148 *
149 * Note that tbl == why is intentional.
150 *
151 * We must set at least "tsk" and "why" when calling ret_with_reschedule.
152 */
153scno .req r7 @ syscall number
154tbl .req r8 @ syscall table pointer
155why .req r8 @ Linux syscall (!= 0)
156tsk .req r9 @ current thread_info
157
158/*
159 * Get the system call number.
160 */
161 .macro get_scno
162 mask_pc lr, lr
163 ldr scno, [lr, #-4] @ get SWI instruction
164 .endm
165/*
166 * -----------------------------------------------------------------------
167 */
168
169/*
170 * We rely on the fact that R0 is at the bottom of the stack (due to
171 * slow/fast restore user regs).
172 */
173#if S_R0 != 0
174#error "Please fix"
175#endif
176
177/*
178 * This is the fast syscall return path. We do as little as
179 * possible here, and this includes saving r0 back into the SVC
180 * stack.
181 */
182ret_fast_syscall:
183 disable_irqs r1 @ disable interrupts
184 ldr r1, [tsk, #TI_FLAGS]
185 tst r1, #_TIF_WORK_MASK
186 bne fast_work_pending
187 fast_restore_user_regs
188
189/*
190 * Ok, we need to do extra processing, enter the slow path.
191 */
192fast_work_pending:
193 str r0, [sp, #S_R0+S_OFF]! @ returned r0
194work_pending:
195 tst r1, #_TIF_NEED_RESCHED
196 bne work_resched
197 tst r1, #_TIF_SIGPENDING
198 beq no_work_pending
199 mov r0, sp @ 'regs'
200 mov r2, why @ 'syscall'
201 bl do_notify_resume
202 disable_irqs r1 @ disable interrupts
203 b no_work_pending
204
205work_resched:
206 bl schedule
207/*
208 * "slow" syscall return path. "why" tells us if this was a real syscall.
209 */
210ENTRY(ret_to_user)
211ret_slow_syscall:
212 disable_irqs r1 @ disable interrupts
213 ldr r1, [tsk, #TI_FLAGS]
214 tst r1, #_TIF_WORK_MASK
215 bne work_pending
216no_work_pending:
217 slow_restore_user_regs
218
219/*
220 * This is how we return from a fork.
221 */
222ENTRY(ret_from_fork)
223 bl schedule_tail
224 get_thread_info tsk
225 ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing
226 mov why, #1
227 tst r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
228 beq ret_slow_syscall
229 mov r1, sp
230 mov r0, #1 @ trace exit [IP = 1]
231 bl syscall_trace
232 b ret_slow_syscall
233
234// FIXME - is this strictly necessary?
235#include "calls.S"
236
237/*=============================================================================
238 * SWI handler
239 *-----------------------------------------------------------------------------
240 */
241
242 .align 5
243ENTRY(vector_swi)
244 save_user_regs
245 zero_fp
246 get_scno
247
248 enable_irqs ip
249
250 str r4, [sp, #-S_OFF]! @ push fifth arg
251
252 get_thread_info tsk
253 ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing
254 bic scno, scno, #0xff000000 @ mask off SWI op-code
255 eor scno, scno, #OS_NUMBER << 20 @ check OS number
256 adr tbl, sys_call_table @ load syscall table pointer
257 tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
258 bne __sys_trace
259
260 adral lr, ret_fast_syscall @ set return address
261 orral lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC mode on return
262 cmp scno, #NR_syscalls @ check upper syscall limit
263 ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
264
265 add r1, sp, #S_OFF
2662: mov why, #0 @ no longer a real syscall
267 cmp scno, #ARMSWI_OFFSET
268 eor r0, scno, #OS_NUMBER << 20 @ put OS number back
269 bcs arm_syscall
270 b sys_ni_syscall @ not private func
271
272 /*
273 * This is the really slow path. We're going to be doing
274 * context switches, and waiting for our parent to respond.
275 */
276__sys_trace:
277 add r1, sp, #S_OFF
278 mov r0, #0 @ trace entry [IP = 0]
279 bl syscall_trace
280
281 adral lr, __sys_trace_return @ set return address
282 orral lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC mode on return
283 add r1, sp, #S_R0 + S_OFF @ pointer to regs
284 cmp scno, #NR_syscalls @ check upper syscall limit
285 ldmccia r1, {r0 - r3} @ have to reload r0 - r3
286 ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
287 b 2b
288
289__sys_trace_return:
290 str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
291 mov r1, sp
292 mov r0, #1 @ trace exit [IP = 1]
293 bl syscall_trace
294 b ret_slow_syscall
295
296 .align 5
297
298 .type sys_call_table, #object
299ENTRY(sys_call_table)
300#include "calls.S"
301
302/*============================================================================
303 * Special system call wrappers
304 */
305@ r0 = syscall number
306@ r5 = syscall table
307 .type sys_syscall, #function
308sys_syscall:
309 eor scno, r0, #OS_NUMBER << 20
310 cmp scno, #NR_syscalls @ check range
311 stmleia sp, {r5, r6} @ shuffle args
312 movle r0, r1
313 movle r1, r2
314 movle r2, r3
315 movle r3, r4
316 ldrle pc, [tbl, scno, lsl #2]
317 b sys_ni_syscall
318
319sys_fork_wrapper:
320 add r0, sp, #S_OFF
321 b sys_fork
322
323sys_vfork_wrapper:
324 add r0, sp, #S_OFF
325 b sys_vfork
326
327sys_execve_wrapper:
328 add r3, sp, #S_OFF
329 b sys_execve
330
331sys_clone_wapper:
332 add r2, sp, #S_OFF
333 b sys_clone
334
335sys_sigsuspend_wrapper:
336 add r3, sp, #S_OFF
337 b sys_sigsuspend
338
339sys_rt_sigsuspend_wrapper:
340 add r2, sp, #S_OFF
341 b sys_rt_sigsuspend
342
343sys_sigreturn_wrapper:
344 add r0, sp, #S_OFF
345 b sys_sigreturn
346
347sys_rt_sigreturn_wrapper:
348 add r0, sp, #S_OFF
349 b sys_rt_sigreturn
350
351sys_sigaltstack_wrapper:
352 ldr r2, [sp, #S_OFF + S_SP]
353 b do_sigaltstack
354
355/*
356 * Note: off_4k (r5) is always units of 4K. If we can't do the requested
357 * offset, we return EINVAL. FIXME - this lost some stuff from arm32 to
358 * ifdefs. check it out.
359 */
360sys_mmap2:
361 tst r5, #((1 << (PAGE_SHIFT - 12)) - 1)
362 moveq r5, r5, lsr #PAGE_SHIFT - 12
363 streq r5, [sp, #4]
364 beq do_mmap2
365 mov r0, #-EINVAL
366 RETINSTR(mov,pc, lr)
367
368/*
369 * Design issues:
370 * - We have several modes that each vector can be called from,
371 * each with its own set of registers. On entry to any vector,
372 * we *must* save the registers used in *that* mode.
373 *
374 * - This code must be as fast as possible.
375 *
376 * There are a few restrictions on the vectors:
377 * - the SWI vector cannot be called from *any* non-user mode
378 *
379 * - the FP emulator is *never* called from *any* non-user mode undefined
380 * instruction.
381 *
382 */
383
384 .text
385
386 .macro handle_irq
3871: mov r4, #IOC_BASE
388 ldrb r6, [r4, #0x24] @ get high priority first
389 adr r5, irq_prio_h
390 teq r6, #0
391 ldreqb r6, [r4, #0x14] @ get low priority
392 adreq r5, irq_prio_l
393
394 teq r6, #0 @ If an IRQ happened...
395 ldrneb r0, [r5, r6] @ get IRQ number
396 movne r1, sp @ get struct pt_regs
397 adrne lr, 1b @ Set return address to 1b
398 orrne lr, lr, #PSR_I_BIT | MODE_SVC26 @ (and force SVC mode)
399 bne asm_do_IRQ @ process IRQ (if asserted)
400 .endm
401
402
403/*
404 * Interrupt table (incorporates priority)
405 */
406 .macro irq_prio_table
407irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
408 .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
409 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
410 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
411 .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
412 .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
413 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
414 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
415 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
416 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
417 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
418 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
419 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
420 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
421 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
422 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
423irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
424 .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
425 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
426 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
427 .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
428 .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
429 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
430 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
431 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
432 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
433 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
434 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
435 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
436 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
437 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
438 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
439 .endm
440
441#if 1
442/*
443 * Uncomment these if you wish to get more debugging into about data aborts.
444 * FIXME - I bet we can find a way to encode these and keep performance.
445 */
446#define FAULT_CODE_LDRSTRPOST 0x80
447#define FAULT_CODE_LDRSTRPRE 0x40
448#define FAULT_CODE_LDRSTRREG 0x20
449#define FAULT_CODE_LDMSTM 0x10
450#define FAULT_CODE_LDCSTC 0x08
451#endif
452#define FAULT_CODE_PREFETCH 0x04
453#define FAULT_CODE_WRITE 0x02
454#define FAULT_CODE_FORCECOW 0x01
455
456/*=============================================================================
457 * Undefined FIQs
458 *-----------------------------------------------------------------------------
459 */
460_unexp_fiq: ldr sp, .LCfiq
461 mov r12, #IOC_BASE
462 strb r12, [r12, #0x38] @ Disable FIQ register
463 teqp pc, #PSR_I_BIT | PSR_F_BIT | MODE_SVC26
464 mov r0, r0
465 stmfd sp!, {r0 - r3, ip, lr}
466 adr r0, Lfiqmsg
467 bl printk
468 ldmfd sp!, {r0 - r3, ip, lr}
469 teqp pc, #PSR_I_BIT | PSR_F_BIT | MODE_FIQ26
470 mov r0, r0
471 movs pc, lr
472
473Lfiqmsg: .ascii "*** Unexpected FIQ\n\0"
474 .align
475
476.LCfiq: .word __temp_fiq
477.LCirq: .word __temp_irq
478
479/*=============================================================================
480 * Undefined instruction handler
481 *-----------------------------------------------------------------------------
482 * Handles floating point instructions
483 */
484vector_undefinstr:
485 tst lr, #MODE_SVC26 @ did we come from a non-user mode?
486 bne __und_svc @ yes - deal with it.
487/* Otherwise, fall through for the user-space (common) case. */
488 save_user_regs
489 zero_fp @ zero frame pointer
490 teqp pc, #PSR_I_BIT | MODE_SVC26 @ disable IRQs
491.Lbug_undef:
492 ldr r4, .LC2
493 ldr pc, [r4] @ Call FP module entry point
494/* FIXME - should we trap for a null pointer here? */
495
496/* The SVC mode case */
497__und_svc: save_svc_regs @ Non-user mode
498 mask_pc r0, lr
499 and r2, lr, #3
500 sub r0, r0, #4
501 mov r1, sp
502 bl do_undefinstr
503 restore_svc_regs
504
505/* We get here if the FP emulator doesnt handle the undef instr.
506 * If the insn WAS handled, the emulator jumps to ret_from_exception by itself/
507 */
508 .globl fpundefinstr
509fpundefinstr:
510 mov r0, lr
511 mov r1, sp
512 teqp pc, #MODE_SVC26
513 bl do_undefinstr
514 b ret_from_exception @ Normal FP exit
515
516#if defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE
517 /* The FPE is always present */
518 .equ fpe_not_present, 0
519#else
520/* We get here if an undefined instruction happens and the floating
521 * point emulator is not present. If the offending instruction was
522 * a WFS, we just perform a normal return as if we had emulated the
523 * operation. This is a hack to allow some basic userland binaries
524 * to run so that the emulator module proper can be loaded. --philb
525 * FIXME - probably a broken useless hack...
526 */
527fpe_not_present:
528 adr r10, wfs_mask_data
529 ldmia r10, {r4, r5, r6, r7, r8}
530 ldr r10, [sp, #S_PC] @ Load PC
531 sub r10, r10, #4
532 mask_pc r10, r10
533 ldrt r10, [r10] @ get instruction
534 and r5, r10, r5
535 teq r5, r4 @ Is it WFS?
536 beq ret_from_exception
537 and r5, r10, r8
538 teq r5, r6 @ Is it LDF/STF on sp or fp?
539 teqne r5, r7
540 bne fpundefinstr
541 tst r10, #0x00200000 @ Does it have WB
542 beq ret_from_exception
543 and r4, r10, #255 @ get offset
544 and r6, r10, #0x000f0000
545 tst r10, #0x00800000 @ +/-
546 ldr r5, [sp, r6, lsr #14] @ Load reg
547 rsbeq r4, r4, #0
548 add r5, r5, r4, lsl #2
549 str r5, [sp, r6, lsr #14] @ Save reg
550 b ret_from_exception
551
552wfs_mask_data: .word 0x0e200110 @ WFS/RFS
553 .word 0x0fef0fff
554 .word 0x0d0d0100 @ LDF [sp]/STF [sp]
555 .word 0x0d0b0100 @ LDF [fp]/STF [fp]
556 .word 0x0f0f0f00
557#endif
558
559.LC2: .word fp_enter
560
561/*=============================================================================
562 * Prefetch abort handler
563 *-----------------------------------------------------------------------------
564 */
565#define DEBUG_UNDEF
566/* remember: lr = USR pc */
567vector_prefetch:
568 sub lr, lr, #4
569 tst lr, #MODE_SVC26
570 bne __pabt_invalid
571 save_user_regs
572 teqp pc, #MODE_SVC26 @ Enable IRQs...
573 mask_pc r0, lr @ Address of abort
574 mov r1, sp @ Tasks registers
575 bl do_PrefetchAbort
576 teq r0, #0 @ If non-zero, we believe this abort..
577 bne ret_from_exception
578#ifdef DEBUG_UNDEF
579 adr r0, t
580 bl printk
581#endif
582 ldr lr, [sp,#S_PC] @ FIXME program to test this on. I think its
583 b .Lbug_undef @ broken at the moment though!)
584
585__pabt_invalid: save_svc_regs
586 mov r0, sp @ Prefetch aborts are definitely *not*
587 mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant
588 and r2, lr, #3 @ recover from this problem.
589 b bad_mode
590
591#ifdef DEBUG_UNDEF
592t: .ascii "*** undef ***\r\n\0"
593 .align
594#endif
595
596/*=============================================================================
597 * Address exception handler
598 *-----------------------------------------------------------------------------
599 * These aren't too critical.
600 * (they're not supposed to happen).
601 * In order to debug the reason for address exceptions in non-user modes,
602 * we have to obtain all the registers so that we can see what's going on.
603 */
604
605vector_addrexcptn:
606 sub lr, lr, #8
607 tst lr, #3
608 bne Laddrexcptn_not_user
609 save_user_regs
610 teq pc, #MODE_SVC26
611 mask_pc r0, lr @ Point to instruction
612 mov r1, sp @ Point to registers
613 mov r2, #0x400
614 mov lr, pc
615 bl do_excpt
616 b ret_from_exception
617
618Laddrexcptn_not_user:
619 save_svc_regs
620 and r2, lr, #3
621 teq r2, #3
622 bne Laddrexcptn_illegal_mode
623 teqp pc, #MODE_SVC26
624 mask_pc r0, lr
625 mov r1, sp
626 orr r2, r2, #0x400
627 bl do_excpt
628 ldmia sp, {r0 - lr} @ I cant remember the reason I changed this...
629 add sp, sp, #15*4
630 movs pc, lr
631
632Laddrexcptn_illegal_mode:
633 mov r0, sp
634 str lr, [sp, #-4]!
635 orr r1, r2, #PSR_I_BIT | PSR_F_BIT
636 teqp r1, #0 @ change into mode (wont be user mode)
637 mov r0, r0
638 mov r1, r8 @ Any register from r8 - r14 can be banked
639 mov r2, r9
640 mov r3, r10
641 mov r4, r11
642 mov r5, r12
643 mov r6, r13
644 mov r7, r14
645 teqp pc, #PSR_F_BIT | MODE_SVC26 @ back to svc
646 mov r0, r0
647 stmfd sp!, {r1-r7}
648 ldmia r0, {r0-r7}
649 stmfd sp!, {r0-r7}
650 mov r0, sp
651 mov r1, #BAD_ADDREXCPTN
652 b bad_mode
653
654/*=============================================================================
655 * Interrupt (IRQ) handler
656 *-----------------------------------------------------------------------------
657 * Note: if the IRQ was taken whilst in user mode, then *no* kernel routine
658 * is running, so do not have to save svc lr.
659 *
660 * Entered in IRQ mode.
661 */
662
663vector_IRQ: ldr sp, .LCirq @ Setup some temporary stack
664 sub lr, lr, #4
665 str lr, [sp] @ push return address
666
667 tst lr, #3
668 bne __irq_non_usr
669
670__irq_usr: teqp pc, #PSR_I_BIT | MODE_SVC26 @ Enter SVC mode
671 mov r0, r0
672
673 ldr lr, .LCirq
674 ldr lr, [lr] @ Restore lr for jump back to USR
675
676 save_user_regs
677
678 handle_irq
679
680 mov why, #0
681 get_thread_info tsk
682 b ret_to_user
683
684@ Place the IRQ priority table here so that the handle_irq macros above
685@ and below here can access it.
686
687 irq_prio_table
688
689__irq_non_usr: teqp pc, #PSR_I_BIT | MODE_SVC26 @ Enter SVC mode
690 mov r0, r0
691
692 save_svc_regs_irq
693
694 and r2, lr, #3
695 teq r2, #3
696 bne __irq_invalid @ IRQ not from SVC mode
697
698 handle_irq
699
700 restore_svc_regs
701
702__irq_invalid: mov r0, sp
703 mov r1, #BAD_IRQ
704 b bad_mode
705
706/*=============================================================================
707 * Data abort handler code
708 *-----------------------------------------------------------------------------
709 *
710 * This handles both exceptions from user and SVC modes, computes the address
711 * range of the problem, and does any correction that is required. It then
712 * calls the kernel data abort routine.
713 *
714 * This is where I wish that the ARM would tell you which address aborted.
715 */
716
717vector_data: sub lr, lr, #8 @ Correct lr
718 tst lr, #3
719 bne Ldata_not_user
720 save_user_regs
721 teqp pc, #MODE_SVC26
722 mask_pc r0, lr
723 bl Ldata_do
724 b ret_from_exception
725
726Ldata_not_user:
727 save_svc_regs
728 and r2, lr, #3
729 teq r2, #3
730 bne Ldata_illegal_mode
731 tst lr, #PSR_I_BIT
732 teqeqp pc, #MODE_SVC26
733 mask_pc r0, lr
734 bl Ldata_do
735 restore_svc_regs
736
737Ldata_illegal_mode:
738 mov r0, sp
739 mov r1, #BAD_DATA
740 b bad_mode
741
742Ldata_do: mov r3, sp
743 ldr r4, [r0] @ Get instruction
744 mov r2, #0
745 tst r4, #1 << 20 @ Check to see if it is a write instruction
746 orreq r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction
747 mov r1, r4, lsr #22 @ Now branch to the relevent processing routine
748 and r1, r1, #15 << 2
749 add pc, pc, r1
750 movs pc, lr
751 b Ldata_unknown
752 b Ldata_unknown
753 b Ldata_unknown
754 b Ldata_unknown
755 b Ldata_ldrstr_post @ ldr rd, [rn], #m
756 b Ldata_ldrstr_numindex @ ldr rd, [rn, #m] @ RegVal
757 b Ldata_ldrstr_post @ ldr rd, [rn], rm
758 b Ldata_ldrstr_regindex @ ldr rd, [rn, rm]
759 b Ldata_ldmstm @ ldm*a rn, <rlist>
760 b Ldata_ldmstm @ ldm*b rn, <rlist>
761 b Ldata_unknown
762 b Ldata_unknown
763 b Ldata_ldrstr_post @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
764 b Ldata_ldcstc_pre @ ldc rd, [rn, #m]
765 b Ldata_unknown
766Ldata_unknown: @ Part of jumptable
767 mov r0, r1
768 mov r1, r4
769 mov r2, r3
770 b baddataabort
771
772Ldata_ldrstr_post:
773 mov r0, r4, lsr #14 @ Get Rn
774 and r0, r0, #15 << 2 @ Mask out reg.
775 teq r0, #15 << 2
776 ldr r0, [r3, r0] @ Get register
777 biceq r0, r0, #PCMASK
778 mov r1, r0
779#ifdef FAULT_CODE_LDRSTRPOST
780 orr r2, r2, #FAULT_CODE_LDRSTRPOST
781#endif
782 b do_DataAbort
783
784Ldata_ldrstr_numindex:
785 mov r0, r4, lsr #14 @ Get Rn
786 and r0, r0, #15 << 2 @ Mask out reg.
787 teq r0, #15 << 2
788 ldr r0, [r3, r0] @ Get register
789 mov r1, r4, lsl #20
790 biceq r0, r0, #PCMASK
791 tst r4, #1 << 23
792 addne r0, r0, r1, lsr #20
793 subeq r0, r0, r1, lsr #20
794 mov r1, r0
795#ifdef FAULT_CODE_LDRSTRPRE
796 orr r2, r2, #FAULT_CODE_LDRSTRPRE
797#endif
798 b do_DataAbort
799
800Ldata_ldrstr_regindex:
801 mov r0, r4, lsr #14 @ Get Rn
802 and r0, r0, #15 << 2 @ Mask out reg.
803 teq r0, #15 << 2
804 ldr r0, [r3, r0] @ Get register
805 and r7, r4, #15
806 biceq r0, r0, #PCMASK
807 teq r7, #15 @ Check for PC
808 ldr r7, [r3, r7, lsl #2] @ Get Rm
809 and r8, r4, #0x60 @ Get shift types
810 biceq r7, r7, #PCMASK
811 mov r9, r4, lsr #7 @ Get shift amount
812 and r9, r9, #31
813 teq r8, #0
814 moveq r7, r7, lsl r9
815 teq r8, #0x20 @ LSR shift
816 moveq r7, r7, lsr r9
817 teq r8, #0x40 @ ASR shift
818 moveq r7, r7, asr r9
819 teq r8, #0x60 @ ROR shift
820 moveq r7, r7, ror r9
821 tst r4, #1 << 23
822 addne r0, r0, r7
823 subeq r0, r0, r7 @ Apply correction
824 mov r1, r0
825#ifdef FAULT_CODE_LDRSTRREG
826 orr r2, r2, #FAULT_CODE_LDRSTRREG
827#endif
828 b do_DataAbort
829
830Ldata_ldmstm:
831 mov r7, #0x11
832 orr r7, r7, r7, lsl #8
833 and r0, r4, r7
834 and r1, r4, r7, lsl #1
835 add r0, r0, r1, lsr #1
836 and r1, r4, r7, lsl #2
837 add r0, r0, r1, lsr #2
838 and r1, r4, r7, lsl #3
839 add r0, r0, r1, lsr #3
840 add r0, r0, r0, lsr #8
841 add r0, r0, r0, lsr #4
842 and r7, r0, #15 @ r7 = no. of registers to transfer.
843 mov r5, r4, lsr #14 @ Get Rn
844 and r5, r5, #15 << 2
845 ldr r0, [r3, r5] @ Get reg
846 eor r6, r4, r4, lsl #2
847 tst r6, #1 << 23 @ Check inc/dec ^ writeback
848 rsbeq r7, r7, #0
849 add r7, r0, r7, lsl #2 @ Do correction (signed)
850 subne r1, r7, #1
851 subeq r1, r0, #1
852 moveq r0, r7
853 tst r4, #1 << 21 @ Check writeback
854 strne r7, [r3, r5]
855 eor r6, r4, r4, lsl #1
856 tst r6, #1 << 24 @ Check Pre/Post ^ inc/dec
857 addeq r0, r0, #4
858 addeq r1, r1, #4
859 teq r5, #15*4 @ CHECK FOR PC
860 biceq r1, r1, #PCMASK
861 biceq r0, r0, #PCMASK
862#ifdef FAULT_CODE_LDMSTM
863 orr r2, r2, #FAULT_CODE_LDMSTM
864#endif
865 b do_DataAbort
866
867Ldata_ldcstc_pre:
868 mov r0, r4, lsr #14 @ Get Rn
869 and r0, r0, #15 << 2 @ Mask out reg.
870 teq r0, #15 << 2
871 ldr r0, [r3, r0] @ Get register
872 mov r1, r4, lsl #24 @ Get offset
873 biceq r0, r0, #PCMASK
874 tst r4, #1 << 23
875 addne r0, r0, r1, lsr #24
876 subeq r0, r0, r1, lsr #24
877 mov r1, r0
878#ifdef FAULT_CODE_LDCSTC
879 orr r2, r2, #FAULT_CODE_LDCSTC
880#endif
881 b do_DataAbort
882
883
884/*
885 * This is the return code to user mode for abort handlers
886 */
887ENTRY(ret_from_exception)
888 get_thread_info tsk
889 mov why, #0
890 b ret_to_user
891
892 .data
893ENTRY(fp_enter)
894 .word fpe_not_present
895 .text
896/*
897 * Register switch for older 26-bit only ARMs
898 */
899ENTRY(__switch_to)
900 add r0, r0, #TI_CPU_SAVE
901 stmia r0, {r4 - sl, fp, sp, lr}
902 add r1, r1, #TI_CPU_SAVE
903 ldmia r1, {r4 - sl, fp, sp, pc}^
904
905/*
906 *=============================================================================
907 * Low-level interface code
908 *-----------------------------------------------------------------------------
909 * Trap initialisation
910 *-----------------------------------------------------------------------------
911 *
912 * Note - FIQ code has changed. The default is a couple of words in 0x1c, 0x20
913 * that call _unexp_fiq. Nowever, we now copy the FIQ routine to 0x1c (removes
914 * some excess cycles).
915 *
916 * What we need to put into 0-0x1c are branches to branch to the kernel.
917 */
918
919 .section ".init.text",#alloc,#execinstr
920
921.Ljump_addresses:
922 swi SYS_ERROR0
923 .word vector_undefinstr - 12
924 .word vector_swi - 16
925 .word vector_prefetch - 20
926 .word vector_data - 24
927 .word vector_addrexcptn - 28
928 .word vector_IRQ - 32
929 .word _unexp_fiq - 36
930 b . + 8
931/*
932 * initialise the trap system
933 */
934ENTRY(__trap_init)
935 stmfd sp!, {r4 - r7, lr}
936 adr r1, .Ljump_addresses
937 ldmia r1, {r1 - r7, ip, lr}
938 orr r2, lr, r2, lsr #2
939 orr r3, lr, r3, lsr #2
940 orr r4, lr, r4, lsr #2
941 orr r5, lr, r5, lsr #2
942 orr r6, lr, r6, lsr #2
943 orr r7, lr, r7, lsr #2
944 orr ip, lr, ip, lsr #2
945 mov r0, #0
946 stmia r0, {r1 - r7, ip}
947 ldmfd sp!, {r4 - r7, pc}^
948
949 .bss
950__temp_irq: .space 4 @ saved lr_irq
951__temp_fiq: .space 128