2 * linux/arch/arm/kernel/entry-armo.S
4 * Copyright (C) 1995,1996,1997,1998 Russell King.
6 * Low-level vector interface routines
9 * - We have several modes that each vector can be called from,
10 * each with its own set of registers. On entry to any vector,
11 * we *must* save the registers used in *that* mode.
13 * - This code must be as fast as possible.
15 * There are a few restrictions on the vectors:
16 * - the SWI vector cannot be called from *any* non-user mode
18 * - the FP emulator is *never* called from *any* non-user mode undefined
21 * Ok, so this file may be a mess, but its as efficient as possible while
22 * adhering to the above criteria.
24 #include <linux/linkage.h>
26 #include <asm/assembler.h>
27 #include <asm/errno.h>
28 #include <asm/hardware.h>
30 #include "../lib/constants.h"
34 @ Offsets into task structure
35 @ ---------------------------
43 #define PF_TRACESYS 0x20
48 #define BAD_PREFETCH 0
50 #define BAD_ADDREXCPTN 2
52 #define BAD_UNDEFINSTR 4
54 @ OS version number used in SWIs
61 @ Stack format (ensured by USER_* and SVC_*)
83 /* IOC / IOMD based hardware */
84 .equ ioc_base_high, IOC_BASE & 0xff000000
85 .equ ioc_base_low, IOC_BASE & 0x00ff0000
87 mov r12, #ioc_base_high
89 orr r12, r12, #ioc_base_low
91 strb r12, [r12, #0x38] @ Disable FIQ register
94 .macro get_irqnr_and_base, irqnr, base
95 mov r4, #ioc_base_high @ point at IOC
97 orr r4, r4, #ioc_base_low
99 ldrb \irqnr, [r4, #0x24] @ get high priority first
100 adr \base, irq_prio_h
102 ldreqb \irqnr, [r4, #0x14] @ get low priority
103 adreq \base, irq_prio_l
107 * Interrupt table (incorporates priority)
109 .macro irq_prio_table
110 irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
111 .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
112 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
113 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
114 .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
115 .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
116 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
117 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
118 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
119 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
120 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
121 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
122 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
123 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
124 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
125 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
126 irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
127 .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
128 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
129 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
130 .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
131 .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
132 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
133 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
134 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
135 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
136 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
137 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
138 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
139 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
140 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
141 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
144 #error Unknown architecture
147 /*=============================================================================
151 .macro save_user_regs
159 .macro restore_user_regs
167 .macro mask_pc, rd, rm
168 bic \rd, \rm, #PCMASK
171 .macro arm700_bug_check, instr, temp
174 .macro enable_irqs, temp
178 .macro initialise_traps_extra
181 .macro get_current_task, rd
183 mov \rd, \rd, lsl #13
187 * Like adr, but force SVC mode (if required)
189 .macro adrsvc, cond, reg, label
190 adr\cond \reg, \label
191 orr\cond \reg, \reg, #0x08000003
196 * Uncomment these if you wish to get more debugging into about data aborts.
198 #define FAULT_CODE_LDRSTRPOST 0x80
199 #define FAULT_CODE_LDRSTRPRE 0x40
200 #define FAULT_CODE_LDRSTRREG 0x20
201 #define FAULT_CODE_LDMSTM 0x10
202 #define FAULT_CODE_LDCSTC 0x08
204 #define FAULT_CODE_PREFETCH 0x04
205 #define FAULT_CODE_WRITE 0x02
206 #define FAULT_CODE_USER 0x01
209 #define SVC_SAVE_ALL \
210 str sp, [sp, #-16]! ;\
213 stmfd sp!, {r0 - r12} ;\
215 str r0, [sp, #S_OLD_R0] ;\
218 #define SVC_IRQ_SAVE_ALL \
219 str sp, [sp, #-16]! ;\
224 stmfd sp!, {r0 - r12} ;\
226 str r0, [sp, #S_OLD_R0] ;\
229 #define USER_RESTORE_ALL \
230 ldmia sp, {r0 - lr}^ ;\
236 #define SVC_RESTORE_ALL \
239 /*=============================================================================
241 *-----------------------------------------------------------------------------
243 _unexp_fiq: ldr sp, .LCfiq
245 strb r12, [r12, #0x38] @ Disable FIQ register
248 stmfd sp!, {r0 - r3, ip, lr}
250 bl SYMBOL_NAME(printk)
251 ldmfd sp!, {r0 - r3, ip, lr}
256 Lfiqmsg: .ascii "*** Unexpeced FIQ\n\0"
259 .LCfiq: .word __temp_fiq
260 .LCirq: .word __temp_irq
262 /*=============================================================================
263 * Undefined instruction handler
264 *-----------------------------------------------------------------------------
265 * Handles floating point instructions
272 teqp pc, #I_BIT | MODE_SVC
275 ldr pc, [r4] @ Call FP module USR entry point
277 .globl SYMBOL_NAME(fpundefinstr)
278 SYMBOL_NAME(fpundefinstr): @ Called by FP module on undefined instr
282 bl SYMBOL_NAME(do_undefinstr)
283 b ret_from_exception @ Normal FP exit
285 __und_svc: SVC_SAVE_ALL @ Non-user mode
290 bl SYMBOL_NAME(do_undefinstr)
293 /* We get here if an undefined instruction happens and the floating
294 * point emulator is not present. If the offending instruction was
295 * a WFS, we just perform a normal return as if we had emulated the
296 * operation. This is a hack to allow some basic userland binaries
297 * to run so that the emulator module proper can be loaded. --philb
300 adr r10, wfs_mask_data
301 ldmia r10, {r4, r5, r6, r7, r8}
302 ldr r10, [sp, #S_PC] @ Load PC
305 ldrt r10, [r10] @ get instruction
307 teq r5, r4 @ Is it WFS?
308 beq ret_from_exception
310 teq r5, r6 @ Is it LDF/STF on sp or fp?
313 tst r10, #0x00200000 @ Does it have WB
314 beq ret_from_exception
315 and r4, r10, #255 @ get offset
316 and r6, r10, #0x000f0000
317 tst r10, #0x00800000 @ +/-
319 ldr r5, [sp, r6, lsr #14] @ Load reg
320 add r5, r5, r4, lsl #2
321 str r5, [sp, r6, lsr #14] @ Save reg
324 wfs_mask_data: .word 0x0e200110 @ WFS
326 .word 0x0d0d0100 @ LDF [sp]/STF [sp]
327 .word 0x0d0b0100 @ LDF [fp]/STF [fp]
330 .LC2: .word SYMBOL_NAME(fp_enter)
332 /*=============================================================================
333 * Prefetch abort handler
334 *-----------------------------------------------------------------------------
342 teqp pc, #0x00000003 @ NOT a problem - doesnt change mode
343 mask_pc r0, lr @ Address of abort
344 mov r1, #FAULT_CODE_PREFETCH|FAULT_CODE_USER @ Error code
345 mov r2, sp @ Tasks registers
346 bl SYMBOL_NAME(do_PrefetchAbort)
347 teq r0, #0 @ If non-zero, we believe this abort..
348 bne ret_from_sys_call
351 bl SYMBOL_NAME(printk)
353 ldr lr, [sp,#S_PC] @ program to test this on. I think its
354 b .Lbug_undef @ broken at the moment though!)
356 __pabt_invalid: SVC_SAVE_ALL
357 mov r0, sp @ Prefetch aborts are definitely *not*
358 mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant
359 and r2, lr, #3 @ recover from this problem.
360 b SYMBOL_NAME(bad_mode)
363 t: .ascii "*** undef ***\r\n\0"
367 /*=============================================================================
368 * Address exception handler
369 *-----------------------------------------------------------------------------
370 * These aren't too critical.
371 * (they're not supposed to happen).
372 * In order to debug the reason for address exceptions in non-user modes,
373 * we have to obtain all the registers so that we can see what's going on.
379 bne Laddrexcptn_not_user
382 mask_pc r0, lr @ Point to instruction
383 mov r1, sp @ Point to registers
386 bl SYMBOL_NAME(do_excpt)
389 Laddrexcptn_not_user:
393 bne Laddrexcptn_illegal_mode
394 teqp pc, #0x00000003 @ NOT a problem - doesnt change mode
398 bl SYMBOL_NAME(do_excpt)
399 ldmia sp, {r0 - lr} @ I cant remember the reason I changed this...
403 Laddrexcptn_illegal_mode:
406 orr r1, r2, #0x0c000000
407 teqp r1, #0 @ change into mode (wont be user mode)
409 mov r1, r8 @ Any register from r8 - r14 can be banked
416 teqp pc, #0x04000003 @ back to svc
422 mov r1, #BAD_ADDREXCPTN
423 b SYMBOL_NAME(bad_mode)
425 /*=============================================================================
426 * Interrupt (IRQ) handler
427 *-----------------------------------------------------------------------------
428 * Note: if in user mode, then *no* kernel routine is running, so do not have
430 * (r13 points to irq temp save area)
433 vector_IRQ: ldr r13, .LCirq @ I will leave this one in just in case...
444 1: get_irqnr_and_base r6, r5
446 ldrneb r0, [r5, r6] @ get IRQ number
449 @ routine called with r0 = irq number, r1 = struct pt_regs *
452 orr lr, lr, #0x08000003 @ Force SVC
454 b ret_with_reschedule
458 __irq_svc: teqp pc, #0x08000003
464 1: get_irqnr_and_base r6, r5
466 ldrneb r0, [r5, r6] @ get IRQ number
469 @ routine called with r0 = irq number, r1 = struct pt_regs *
472 orr lr, lr, #0x08000003 @ Force SVC
473 bne do_IRQ @ Returns to 1b
476 __irq_invalid: mov r0, sp
478 b SYMBOL_NAME(bad_mode)
480 /*=============================================================================
481 * Data abort handler code
482 *-----------------------------------------------------------------------------
484 * This handles both exceptions from user and SVC modes, computes the address
485 * range of the problem, and does any correction that is required. It then
486 * calls the kernel data abort routine.
488 * This is where I wish that the ARM would tell you which address aborted.
491 vector_data: sub lr, lr, #8 @ Correct lr
495 teqp pc, #0x00000003 @ NOT a problem - doesnt change mode
497 mov r2, #FAULT_CODE_USER
505 bne Ldata_illegal_mode
507 teqeqp pc, #0x00000003 @ NOT a problem - doesnt change mode
516 b SYMBOL_NAME(bad_mode)
519 ldr r4, [r0] @ Get instruction
520 tst r4, #1 << 20 @ Check to see if it is a write instruction
521 orreq r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction
522 mov r1, r4, lsr #22 @ Now branch to the relevent processing routine
530 b Ldata_ldrstr_post @ ldr rd, [rn], #m
531 b Ldata_ldrstr_numindex @ ldr rd, [rn, #m] @ RegVal
532 b Ldata_ldrstr_post @ ldr rd, [rn], rm
533 b Ldata_ldrstr_regindex @ ldr rd, [rn, rm]
534 b Ldata_ldmstm @ ldm*a rn, <rlist>
535 b Ldata_ldmstm @ ldm*b rn, <rlist>
538 b Ldata_ldrstr_post @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
539 b Ldata_ldcstc_pre @ ldc rd, [rn, #m]
541 Ldata_unknown: @ Part of jumptable
549 mov r0, r4, lsr #14 @ Get Rn
550 and r0, r0, #15 << 2 @ Mask out reg.
552 ldr r0, [r3, r0] @ Get register
553 biceq r0, r0, #PCMASK
555 #ifdef FAULT_CODE_LDRSTRPOST
556 orr r2, r2, #FAULT_CODE_LDRSTRPOST
558 b SYMBOL_NAME(do_DataAbort)
560 Ldata_ldrstr_numindex:
561 mov r0, r4, lsr #14 @ Get Rn
562 and r0, r0, #15 << 2 @ Mask out reg.
564 ldr r0, [r3, r0] @ Get register
565 biceq r0, r0, #PCMASK
568 addne r0, r0, r1, lsr #20
569 subeq r0, r0, r1, lsr #20
571 #ifdef FAULT_CODE_LDRSTRPRE
572 orr r2, r2, #FAULT_CODE_LDRSTRPRE
574 b SYMBOL_NAME(do_DataAbort)
576 Ldata_ldrstr_regindex:
577 mov r0, r4, lsr #14 @ Get Rn
578 and r0, r0, #15 << 2 @ Mask out reg.
580 ldr r0, [r3, r0] @ Get register
581 biceq r0, r0, #PCMASK
583 teq r7, #15 @ Check for PC
584 ldr r7, [r3, r7, lsl #2] @ Get Rm
585 biceq r7, r7, #PCMASK
586 and r8, r4, #0x60 @ Get shift types
587 mov r9, r4, lsr #7 @ Get shift amount
591 teq r8, #0x20 @ LSR shift
593 teq r8, #0x40 @ ASR shift
595 teq r8, #0x60 @ ROR shift
599 subeq r0, r0, r7 @ Apply correction
601 #ifdef FAULT_CODE_LDRSTRREG
602 orr r2, r2, #FAULT_CODE_LDRSTRREG
604 b SYMBOL_NAME(do_DataAbort)
608 orr r7, r7, r7, lsl #8
610 and r1, r4, r7, lsl #1
611 add r0, r0, r1, lsr #1
612 and r1, r4, r7, lsl #2
613 add r0, r0, r1, lsr #2
614 and r1, r4, r7, lsl #3
615 add r0, r0, r1, lsr #3
616 add r0, r0, r0, lsr #8
617 add r0, r0, r0, lsr #4
618 and r7, r0, #15 @ r7 = no. of registers to transfer.
619 mov r5, r4, lsr #14 @ Get Rn
621 ldr r0, [r3, r5] @ Get reg
622 eor r6, r4, r4, lsl #2
623 tst r6, #1 << 23 @ Check inc/dec ^ writeback
625 add r7, r0, r7, lsl #2 @ Do correction (signed)
629 tst r4, #1 << 21 @ Check writeback
631 eor r6, r4, r4, lsl #1
632 tst r6, #1 << 24 @ Check Pre/Post ^ inc/dec
635 teq r5, #15*4 @ CHECK FOR PC
636 biceq r1, r1, #PCMASK
637 biceq r0, r0, #PCMASK
638 #ifdef FAULT_CODE_LDMSTM
639 orr r2, r2, #FAULT_CODE_LDMSTM
641 b SYMBOL_NAME(do_DataAbort)
644 mov r0, r4, lsr #14 @ Get Rn
645 and r0, r0, #15 << 2 @ Mask out reg.
647 ldr r0, [r3, r0] @ Get register
648 biceq r0, r0, #PCMASK
649 mov r1, r4, lsl #24 @ Get offset
651 addne r0, r0, r1, lsr #24
652 subeq r0, r0, r1, lsr #24
654 #ifdef FAULT_CODE_LDCSTC
655 orr r2, r2, #FAULT_CODE_LDCSTC
657 b SYMBOL_NAME(do_DataAbort)
659 #include "entry-common.S"
663 __temp_irq: .word 0 @ saved lr_irq
664 __temp_fiq: .space 128