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 SVC_RESTORE_ALL \
232 /*=============================================================================
234 *-----------------------------------------------------------------------------
236 _unexp_fiq: ldr sp, .LCfiq
238 strb r12, [r12, #0x38] @ Disable FIQ register
241 stmfd sp!, {r0 - r3, ip, lr}
243 bl SYMBOL_NAME(printk)
244 ldmfd sp!, {r0 - r3, ip, lr}
249 Lfiqmsg: .ascii "*** Unexpected FIQ\n\0"
252 .LCfiq: .word __temp_fiq
253 .LCirq: .word __temp_irq
255 /*=============================================================================
256 * Undefined instruction handler
257 *-----------------------------------------------------------------------------
258 * Handles floating point instructions
265 teqp pc, #I_BIT | MODE_SVC
268 ldr pc, [r4] @ Call FP module USR entry point
270 .globl SYMBOL_NAME(fpundefinstr)
271 SYMBOL_NAME(fpundefinstr): @ Called by FP module on undefined instr
275 bl SYMBOL_NAME(do_undefinstr)
276 b ret_from_exception @ Normal FP exit
278 __und_svc: SVC_SAVE_ALL @ Non-user mode
283 bl SYMBOL_NAME(do_undefinstr)
286 /* We get here if an undefined instruction happens and the floating
287 * point emulator is not present. If the offending instruction was
288 * a WFS, we just perform a normal return as if we had emulated the
289 * operation. This is a hack to allow some basic userland binaries
290 * to run so that the emulator module proper can be loaded. --philb
293 adr r10, wfs_mask_data
294 ldmia r10, {r4, r5, r6, r7, r8}
295 ldr r10, [sp, #S_PC] @ Load PC
298 ldrt r10, [r10] @ get instruction
300 teq r5, r4 @ Is it WFS?
301 beq ret_from_exception
303 teq r5, r6 @ Is it LDF/STF on sp or fp?
306 tst r10, #0x00200000 @ Does it have WB
307 beq ret_from_exception
308 and r4, r10, #255 @ get offset
309 and r6, r10, #0x000f0000
310 tst r10, #0x00800000 @ +/-
311 ldr r5, [sp, r6, lsr #14] @ Load reg
313 add r5, r5, r4, lsl #2
314 str r5, [sp, r6, lsr #14] @ Save reg
317 wfs_mask_data: .word 0x0e200110 @ WFS/RFS
319 .word 0x0d0d0100 @ LDF [sp]/STF [sp]
320 .word 0x0d0b0100 @ LDF [fp]/STF [fp]
323 .LC2: .word SYMBOL_NAME(fp_enter)
325 /*=============================================================================
326 * Prefetch abort handler
327 *-----------------------------------------------------------------------------
335 teqp pc, #0x00000003 @ NOT a problem - doesnt change mode
336 mask_pc r0, lr @ Address of abort
337 mov r1, sp @ Tasks registers
338 bl SYMBOL_NAME(do_PrefetchAbort)
339 teq r0, #0 @ If non-zero, we believe this abort..
340 bne ret_from_sys_call
343 bl SYMBOL_NAME(printk)
345 ldr lr, [sp,#S_PC] @ program to test this on. I think its
346 b .Lbug_undef @ broken at the moment though!)
348 __pabt_invalid: SVC_SAVE_ALL
349 mov r0, sp @ Prefetch aborts are definitely *not*
350 mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant
351 and r2, lr, #3 @ recover from this problem.
352 b SYMBOL_NAME(bad_mode)
355 t: .ascii "*** undef ***\r\n\0"
359 /*=============================================================================
360 * Address exception handler
361 *-----------------------------------------------------------------------------
362 * These aren't too critical.
363 * (they're not supposed to happen).
364 * In order to debug the reason for address exceptions in non-user modes,
365 * we have to obtain all the registers so that we can see what's going on.
371 bne Laddrexcptn_not_user
374 mask_pc r0, lr @ Point to instruction
375 mov r1, sp @ Point to registers
378 bl SYMBOL_NAME(do_excpt)
381 Laddrexcptn_not_user:
385 bne Laddrexcptn_illegal_mode
386 teqp pc, #0x00000003 @ NOT a problem - doesnt change mode
390 bl SYMBOL_NAME(do_excpt)
391 ldmia sp, {r0 - lr} @ I cant remember the reason I changed this...
395 Laddrexcptn_illegal_mode:
398 orr r1, r2, #0x0c000000
399 teqp r1, #0 @ change into mode (wont be user mode)
401 mov r1, r8 @ Any register from r8 - r14 can be banked
408 teqp pc, #0x04000003 @ back to svc
414 mov r1, #BAD_ADDREXCPTN
415 b SYMBOL_NAME(bad_mode)
417 /*=============================================================================
418 * Interrupt (IRQ) handler
419 *-----------------------------------------------------------------------------
420 * Note: if in user mode, then *no* kernel routine is running, so do not have
422 * (r13 points to irq temp save area)
425 vector_IRQ: ldr r13, .LCirq @ I will leave this one in just in case...
436 1: get_irqnr_and_base r6, r5
438 ldrneb r0, [r5, r6] @ get IRQ number
441 @ routine called with r0 = irq number, r1 = struct pt_regs *
444 orr lr, lr, #0x08000003 @ Force SVC
447 b ret_with_reschedule
451 __irq_svc: teqp pc, #0x08000003
457 1: get_irqnr_and_base r6, r5
459 ldrneb r0, [r5, r6] @ get IRQ number
462 @ routine called with r0 = irq number, r1 = struct pt_regs *
465 orr lr, lr, #0x08000003 @ Force SVC
466 bne do_IRQ @ Returns to 1b
469 __irq_invalid: mov r0, sp
471 b SYMBOL_NAME(bad_mode)
473 /*=============================================================================
474 * Data abort handler code
475 *-----------------------------------------------------------------------------
477 * This handles both exceptions from user and SVC modes, computes the address
478 * range of the problem, and does any correction that is required. It then
479 * calls the kernel data abort routine.
481 * This is where I wish that the ARM would tell you which address aborted.
484 vector_data: sub lr, lr, #8 @ Correct lr
488 teqp pc, #0x00000003 @ NOT a problem - doesnt change mode
490 mov r2, #FAULT_CODE_USER
498 bne Ldata_illegal_mode
500 teqeqp pc, #0x00000003 @ NOT a problem - doesnt change mode
509 b SYMBOL_NAME(bad_mode)
512 ldr r4, [r0] @ Get instruction
513 tst r4, #1 << 20 @ Check to see if it is a write instruction
514 orreq r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction
515 mov r1, r4, lsr #22 @ Now branch to the relevent processing routine
523 b Ldata_ldrstr_post @ ldr rd, [rn], #m
524 b Ldata_ldrstr_numindex @ ldr rd, [rn, #m] @ RegVal
525 b Ldata_ldrstr_post @ ldr rd, [rn], rm
526 b Ldata_ldrstr_regindex @ ldr rd, [rn, rm]
527 b Ldata_ldmstm @ ldm*a rn, <rlist>
528 b Ldata_ldmstm @ ldm*b rn, <rlist>
531 b Ldata_ldrstr_post @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
532 b Ldata_ldcstc_pre @ ldc rd, [rn, #m]
534 Ldata_unknown: @ Part of jumptable
542 mov r0, r4, lsr #14 @ Get Rn
543 and r0, r0, #15 << 2 @ Mask out reg.
545 ldr r0, [r3, r0] @ Get register
546 biceq r0, r0, #PCMASK
548 #ifdef FAULT_CODE_LDRSTRPOST
549 orr r2, r2, #FAULT_CODE_LDRSTRPOST
551 b SYMBOL_NAME(do_DataAbort)
553 Ldata_ldrstr_numindex:
554 mov r0, r4, lsr #14 @ Get Rn
555 and r0, r0, #15 << 2 @ Mask out reg.
557 ldr r0, [r3, r0] @ Get register
559 biceq r0, r0, #PCMASK
561 addne r0, r0, r1, lsr #20
562 subeq r0, r0, r1, lsr #20
564 #ifdef FAULT_CODE_LDRSTRPRE
565 orr r2, r2, #FAULT_CODE_LDRSTRPRE
567 b SYMBOL_NAME(do_DataAbort)
569 Ldata_ldrstr_regindex:
570 mov r0, r4, lsr #14 @ Get Rn
571 and r0, r0, #15 << 2 @ Mask out reg.
573 ldr r0, [r3, r0] @ Get register
575 biceq r0, r0, #PCMASK
576 teq r7, #15 @ Check for PC
577 ldr r7, [r3, r7, lsl #2] @ Get Rm
578 and r8, r4, #0x60 @ Get shift types
579 biceq r7, r7, #PCMASK
580 mov r9, r4, lsr #7 @ Get shift amount
584 teq r8, #0x20 @ LSR shift
586 teq r8, #0x40 @ ASR shift
588 teq r8, #0x60 @ ROR shift
592 subeq r0, r0, r7 @ Apply correction
594 #ifdef FAULT_CODE_LDRSTRREG
595 orr r2, r2, #FAULT_CODE_LDRSTRREG
597 b SYMBOL_NAME(do_DataAbort)
601 orr r7, r7, r7, lsl #8
603 and r1, r4, r7, lsl #1
604 add r0, r0, r1, lsr #1
605 and r1, r4, r7, lsl #2
606 add r0, r0, r1, lsr #2
607 and r1, r4, r7, lsl #3
608 add r0, r0, r1, lsr #3
609 add r0, r0, r0, lsr #8
610 add r0, r0, r0, lsr #4
611 and r7, r0, #15 @ r7 = no. of registers to transfer.
612 mov r5, r4, lsr #14 @ Get Rn
614 ldr r0, [r3, r5] @ Get reg
615 eor r6, r4, r4, lsl #2
616 tst r6, #1 << 23 @ Check inc/dec ^ writeback
618 add r7, r0, r7, lsl #2 @ Do correction (signed)
622 tst r4, #1 << 21 @ Check writeback
624 eor r6, r4, r4, lsl #1
625 tst r6, #1 << 24 @ Check Pre/Post ^ inc/dec
628 teq r5, #15*4 @ CHECK FOR PC
629 biceq r1, r1, #PCMASK
630 biceq r0, r0, #PCMASK
631 #ifdef FAULT_CODE_LDMSTM
632 orr r2, r2, #FAULT_CODE_LDMSTM
634 b SYMBOL_NAME(do_DataAbort)
637 mov r0, r4, lsr #14 @ Get Rn
638 and r0, r0, #15 << 2 @ Mask out reg.
640 ldr r0, [r3, r0] @ Get register
641 mov r1, r4, lsl #24 @ Get offset
642 biceq r0, r0, #PCMASK
644 addne r0, r0, r1, lsr #24
645 subeq r0, r0, r1, lsr #24
647 #ifdef FAULT_CODE_LDCSTC
648 orr r2, r2, #FAULT_CODE_LDCSTC
650 b SYMBOL_NAME(do_DataAbort)
653 * Register switch for older 26-bit only ARMs
656 stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack
657 str sp, [r0, #TSS_SAVE] @ Save sp_SVC
658 ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
659 ldmfd sp!, {r4 - sl, fp, pc}^ @ Load all regs saved previously
662 *=============================================================================
663 * Low-level interface code
664 *-----------------------------------------------------------------------------
665 * Trap initialisation
666 *-----------------------------------------------------------------------------
668 * Note - FIQ code has changed. The default is a couple of words in 0x1c, 0x20
669 * that call _unexp_fiq. Nowever, we now copy the FIQ routine to 0x1c (removes
670 * some excess cycles).
672 * What we need to put into 0-0x1c are branches to branch to the kernel.
675 .section ".text.init",#alloc,#execinstr
679 .word vector_undefinstr - 12
680 .word vector_swi - 16
681 .word vector_prefetch - 20
682 .word vector_data - 24
683 .word vector_addrexcptn - 28
684 .word vector_IRQ - 32
685 .word _unexp_fiq - 36
688 * initialise the trap system
691 stmfd sp!, {r4 - r7, lr}
692 adr r1, .Ljump_addresses
693 ldmia r1, {r1 - r7, ip, lr}
694 orr r2, lr, r2, lsr #2
695 orr r3, lr, r3, lsr #2
696 orr r4, lr, r4, lsr #2
697 orr r5, lr, r5, lsr #2
698 orr r6, lr, r6, lsr #2
699 orr r7, lr, r7, lsr #2
700 orr ip, lr, ip, lsr #2
702 stmia r0, {r1 - r7, ip}
703 ldmfd sp!, {r4 - r7, pc}^
707 #include "entry-common.S"
710 __temp_irq: .space 4 @ saved lr_irq
711 __temp_fiq: .space 128