2 * linux/arch/arm/kernel/entry-armv.S
4 * Copyright (C) 1996,1997,1998 Russell King.
5 * ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * Low-level vector interface routines
13 * Note: there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes
14 * it to save wrong values... Be aware!
16 #include <linux/config.h>
17 #include "entry-header.S"
21 /* IOC / IOMD based hardware */
22 #include <asm/hardware/iomd.h>
24 .equ ioc_base_high, IOC_BASE & 0xff000000
25 .equ ioc_base_low, IOC_BASE & 0x00ff0000
27 mov r12, #ioc_base_high
29 orr r12, r12, #ioc_base_low
31 strb r12, [r12, #0x38] @ Disable FIQ register
34 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
35 mov r4, #ioc_base_high @ point at IOC
37 orr r4, r4, #ioc_base_low
39 ldrb \irqstat, [r4, #IOMD_IRQREQB] @ get high priority first
40 ldr \base, =irq_prio_h
43 ldreqb \irqstat, [r4, #IOMD_DMAREQ] @ get dma
44 addeq \base, \base, #256 @ irq_prio_h table size
48 ldreqb \irqstat, [r4, #IOMD_IRQREQA] @ get low priority
49 addeq \base, \base, #256 @ irq_prio_d table size
52 ldreqb \irqstat, [r4, #IOMD_IRQREQC]
53 addeq \base, \base, #256 @ irq_prio_l table size
57 ldreqb \irqstat, [r4, #IOMD_IRQREQD]
58 addeq \base, \base, #256 @ irq_prio_lc table size
61 2406: ldrneb \irqnr, [\base, \irqstat] @ get IRQ number
65 * Interrupt table (incorporates priority). Please note that we
66 * rely on the order of these tables (see above code).
69 irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
70 .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
71 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
72 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
73 .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
74 .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
75 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
76 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
77 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
78 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
79 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
80 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
81 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
82 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
83 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
84 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
86 irq_prio_d: .byte 0,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
87 .byte 20,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
88 .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
89 .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
90 .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
91 .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
92 .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
93 .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
94 .byte 23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
95 .byte 23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
96 .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
97 .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
98 .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
99 .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
100 .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
101 .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16
103 irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
104 .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
105 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
106 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
107 .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
108 .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
109 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
110 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
111 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
112 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
113 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
114 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
115 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
116 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
117 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
118 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
120 irq_prio_lc: .byte 24,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27
121 .byte 28,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27
122 .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
123 .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
124 .byte 30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27
125 .byte 30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27
126 .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
127 .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29
128 .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
129 .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
130 .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
131 .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
132 .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
133 .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
134 .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
135 .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
138 irq_prio_ld: .byte 40,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43
139 .byte 44,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43
140 .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
141 .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
142 .byte 46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43
143 .byte 46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43
144 .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
145 .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45
146 .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
147 .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
148 .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
149 .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
150 .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
151 .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
152 .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
153 .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
157 #elif defined(CONFIG_ARCH_EBSA110)
159 #define IRQ_STAT 0xff000000 /* read */
164 .macro get_irqnr_and_base, irqnr, stat, base, tmp
166 ldrb \stat, [\base] @ get interrupts
169 addeq \irqnr, \irqnr, #4
170 moveq \stat, \stat, lsr #4
172 addeq \irqnr, \irqnr, #2
173 moveq \stat, \stat, lsr #2
175 addeq \irqnr, \irqnr, #1
176 moveq \stat, \stat, lsr #1
177 tst \stat, #1 @ bit 0 should be set
180 .macro irq_prio_table
183 #elif defined(CONFIG_ARCH_SHARK)
188 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
192 strb \irqstat, [r4, #0x20] @outb(0x0C, 0x20) /* Poll command */
193 ldrb \irqnr, [r4, #0x20] @irq = inb(0x20) & 7
194 and \irqstat, \irqnr, #0x80
197 and \irqnr, \irqnr, #7
200 43: mov \irqstat, #0x0C
201 strb \irqstat, [r4, #0xa0] @outb(0x0C, 0xA0) /* Poll command */
202 ldrb \irqnr, [r4, #0xa0] @irq = (inb(0xA0) & 7) + 8
203 and \irqstat, \irqnr, #0x80
206 and \irqnr, \irqnr, #7
207 add \irqnr, \irqnr, #8
211 .macro irq_prio_table
214 #elif defined(CONFIG_FOOTBRIDGE)
215 #include <asm/hardware/dec21285.h>
220 .equ dc21285_high, ARMCSR_BASE & 0xff000000
221 .equ dc21285_low, ARMCSR_BASE & 0x00ffffff
223 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
224 mov r4, #dc21285_high
226 orr r4, r4, #dc21285_low
228 ldr \irqstat, [r4, #0x180] @ get interrupts
230 mov \irqnr, #IRQ_SDRAMPARITY
231 tst \irqstat, #IRQ_MASK_SDRAMPARITY
234 tst \irqstat, #IRQ_MASK_UART_RX
235 movne \irqnr, #IRQ_CONRX
238 tst \irqstat, #IRQ_MASK_DMA1
239 movne \irqnr, #IRQ_DMA1
242 tst \irqstat, #IRQ_MASK_DMA2
243 movne \irqnr, #IRQ_DMA2
246 tst \irqstat, #IRQ_MASK_IN0
247 movne \irqnr, #IRQ_IN0
250 tst \irqstat, #IRQ_MASK_IN1
251 movne \irqnr, #IRQ_IN1
254 tst \irqstat, #IRQ_MASK_IN2
255 movne \irqnr, #IRQ_IN2
258 tst \irqstat, #IRQ_MASK_IN3
259 movne \irqnr, #IRQ_IN3
262 tst \irqstat, #IRQ_MASK_PCI
263 movne \irqnr, #IRQ_PCI
266 tst \irqstat, #IRQ_MASK_DOORBELLHOST
267 movne \irqnr, #IRQ_DOORBELLHOST
270 tst \irqstat, #IRQ_MASK_I2OINPOST
271 movne \irqnr, #IRQ_I2OINPOST
274 tst \irqstat, #IRQ_MASK_TIMER1
275 movne \irqnr, #IRQ_TIMER1
278 tst \irqstat, #IRQ_MASK_TIMER2
279 movne \irqnr, #IRQ_TIMER2
282 tst \irqstat, #IRQ_MASK_TIMER3
283 movne \irqnr, #IRQ_TIMER3
286 tst \irqstat, #IRQ_MASK_UART_TX
287 movne \irqnr, #IRQ_CONTX
290 tst \irqstat, #IRQ_MASK_PCI_ABORT
291 movne \irqnr, #IRQ_PCI_ABORT
294 tst \irqstat, #IRQ_MASK_PCI_SERR
295 movne \irqnr, #IRQ_PCI_SERR
298 tst \irqstat, #IRQ_MASK_DISCARD_TIMER
299 movne \irqnr, #IRQ_DISCARD_TIMER
302 tst \irqstat, #IRQ_MASK_PCI_DPERR
303 movne \irqnr, #IRQ_PCI_DPERR
306 tst \irqstat, #IRQ_MASK_PCI_PERR
307 movne \irqnr, #IRQ_PCI_PERR
311 .macro irq_prio_table
314 #elif defined(CONFIG_ARCH_NEXUSPCI)
319 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
320 ldr \irqstat, =INTCONT_BASE
321 ldr \base, =soft_irq_mask
322 ldr \irqstat, [\irqstat] @ get interrupts
325 and \irqstat, \irqstat, \base @ mask out disabled ones
326 1001: tst \irqstat, #1
327 addeq \irqnr, \irqnr, #1
328 moveq \irqstat, \irqstat, lsr #1
334 .macro irq_prio_table
342 #elif defined(CONFIG_ARCH_TBOX)
347 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
348 ldr \irqstat, =0xffff7000
349 ldr \irqstat, [\irqstat] @ get interrupts
350 ldr \base, =soft_irq_mask
353 and \irqstat, \irqstat, \base @ mask out disabled ones
354 1001: tst \irqstat, #1
355 addeq \irqnr, \irqnr, #1
356 moveq \irqstat, \irqstat, lsr #1
362 .macro irq_prio_table
370 #elif defined(CONFIG_ARCH_SA1100)
375 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
376 mov r4, #0xfa000000 @ ICIP = 0xfa050000
377 add r4, r4, #0x00050000
378 ldr \irqstat, [r4] @ get irqs
379 ldr \irqnr, [r4, #4] @ ICMR = 0xfa050004
380 ands \irqstat, \irqstat, \irqnr
384 moveq \irqstat, \irqstat, lsr #8
385 addeq \irqnr, \irqnr, #8
386 tsteq \irqstat, #0xff
387 moveq \irqstat, \irqstat, lsr #8
388 addeq \irqnr, \irqnr, #8
389 tsteq \irqstat, #0xff
390 moveq \irqstat, \irqstat, lsr #8
391 addeq \irqnr, \irqnr, #8
393 moveq \irqstat, \irqstat, lsr #4
394 addeq \irqnr, \irqnr, #4
396 moveq \irqstat, \irqstat, lsr #2
397 addeq \irqnr, \irqnr, #2
399 addeqs \irqnr, \irqnr, #1
403 .macro irq_prio_table
406 #elif defined(CONFIG_ARCH_L7200)
407 #include <asm/hardware.h>
409 .equ irq_base_addr, IO_BASE_2
414 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
415 mov \irqstat, #irq_base_addr @ Virt addr IRQ regs
416 add \irqstat, \irqstat, #0x00001000 @ Status reg
417 ldr \irqstat, [\irqstat, #0] @ get interrupts
419 1001: tst \irqstat, #1
420 addeq \irqnr, \irqnr, #1
421 moveq \irqstat, \irqstat, lsr #1
427 .macro irq_prio_table
430 #elif defined(CONFIG_ARCH_INTEGRATOR)
435 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
436 /* FIXME: should not be using soo many LDRs here */
437 ldr \irqnr, =IO_ADDRESS(INTEGRATOR_IC_BASE)
438 ldr \irqstat, [\irqnr, #IRQ_STATUS] @ get masked status
439 ldr \irqnr, =IO_ADDRESS(INTEGRATOR_HDR_BASE)
440 ldr \irqnr, [\irqnr, #(INTEGRATOR_HDR_IC_OFFSET+IRQ_STATUS)]
441 orr \irqstat, \irqstat, \irqnr, lsl #INTEGRATOR_CM_INT0
444 1001: tst \irqstat, #1
446 add \irqnr, \irqnr, #1
447 mov \irqstat, \irqstat, lsr #1
450 1002: /* EQ will be set if we reach 22 */
453 .macro irq_prio_table
456 #elif defined(CONFIG_ARCH_AT91RM9200)
457 #include <asm/hardware.h>
462 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
463 ldr \base, =(AT91C_VA_BASE_SYS) @ base virtual address of SYS peripherals
464 ldr \irqnr, [\base, #AIC_IVR] @ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
465 ldr \irqstat, [\base, #AIC_ISR] @ read interrupt source number
466 teq \irqstat, #0 @ ISR is 0 when no current interrupt, or spurious interrupt
467 streq \tmp, [\base, #AIC_EOICR] @ not going to be handled further, then ACK it now.
470 .macro irq_prio_table
473 #elif defined(CONFIG_ARCH_MX1ADS)
477 #define AITC_NIVECSR 0x40
478 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
479 ldr \irqstat, =IO_ADDRESS(MX1ADS_AITC_BASE)
480 @ Load offset & priority of the highest priority
482 ldr \irqnr, [\irqstat, #AITC_NIVECSR]
483 @ Shift off the priority leaving the offset or
485 mov \irqnr, \irqnr, lsr #16
486 ldr \irqstat, =1 @ dummy compare
487 ldr \base, =0xFFFF // invalid interrupt
492 tst \irqstat, #1 @ to make the condition code = TRUE
495 .macro irq_prio_table
498 #elif defined(CONFIG_ARCH_OMAHA)
503 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
505 /* Read all interrupts pending... */
506 ldr \irqnr, =IO_ADDRESS(PLAT_PERIPHERAL_BASE) + OMAHA_INTPND
507 ldr \irqstat, [\irqnr] /* INTPND */
509 /* All pending irqs are now in \irqstat */
511 1001: tst \irqstat, #1
513 add \irqnr, \irqnr, #1
514 mov \irqstat, \irqstat, lsr #1
515 cmp \irqnr, #MAXIRQNUM
517 1002: /* EQ will be set if we reach MAXIRQNUM */
521 .macro irq_prio_table
524 #elif defined(CONFIG_ARCH_CLPS711X)
526 #include <asm/hardware/clps7111.h>
531 #if (INTSR2 - INTSR1) != (INTMR2 - INTMR1)
532 #error INTSR stride != INTMR stride
535 .macro get_irqnr_and_base, irqnr, stat, base, mask
536 mov \base, #CLPS7111_BASE
537 ldr \stat, [\base, #INTSR1]
538 ldr \mask, [\base, #INTMR1]
540 mov \mask, \mask, lsl #16
541 and \stat, \stat, \mask, lsr #16
542 movs \stat, \stat, lsr #4
545 add \base, \base, #INTSR2 - INTSR1
546 ldr \stat, [\base, #INTSR1]
547 ldr \mask, [\base, #INTMR1]
549 mov \mask, \mask, lsl #16
550 and \stat, \stat, \mask, lsr #16
552 1001: tst \stat, #255
553 addeq \irqnr, \irqnr, #8
554 moveq \stat, \stat, lsr #8
556 addeq \irqnr, \irqnr, #4
557 moveq \stat, \stat, lsr #4
559 addeq \irqnr, \irqnr, #2
560 moveq \stat, \stat, lsr #2
562 addeq \irqnr, \irqnr, #1
563 moveq \stat, \stat, lsr #1
564 tst \stat, #1 @ bit 0 should be set
567 .macro irq_prio_table
570 #elif defined (CONFIG_ARCH_CAMELOT)
571 #include <asm/arch/platform.h>
572 #undef IRQ_MODE /* same name defined in asm/proc/ptrace.h */
573 #include <asm/arch/int_ctrl00.h>
578 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
580 ldr \irqstat, =INT_ID(IO_ADDRESS(EXC_INT_CTRL00_BASE))
581 ldr \irqnr,[\irqstat]
583 subne \irqnr,\irqnr,#1
588 .macro irq_prio_table
591 #elif defined(CONFIG_ARCH_ANAKIN)
596 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
598 mov \irqstat, #INTERRUPT_CONTROLLER
599 ldr \tmp, =anakin_irq_mask
600 ldr \irqstat, [\base, \irqstat]
602 ands \irqstat, \irqstat, \tmp
603 ldrne \tmp, =anakin_active_irqs
604 strne \irqstat, [\tmp]
605 movne \irqnr, #IRQ_ANAKIN
608 .macro irq_prio_table
611 ENTRY(anakin_irq_mask)
613 ENTRY(anakin_active_irqs)
619 #error Unknown architecture
623 * Invalid mode handlers
625 __pabt_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
626 stmia sp, {r0 - lr} @ Save XXX r0 - lr
628 mov r1, #BAD_PREFETCH
631 __dabt_invalid: sub sp, sp, #S_FRAME_SIZE
632 stmia sp, {r0 - lr} @ Save SVC r0 - lr [lr *should* be intact]
637 __irq_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate space on stack for frame
638 stmfd sp, {r0 - lr} @ Save r0 - lr
643 __und_invalid: sub sp, sp, #S_FRAME_SIZE
646 mov r1, #BAD_UNDEFINSTR @ int reason
649 ldmia r4, {r5 - r7} @ Get XXX pc, cpsr, old_r0
651 stmia r4, {r5 - r7} @ Save XXX pc, cpsr, old_r0
653 and r2, r6, #31 @ int mode
654 b SYMBOL_NAME(bad_mode)
656 /* We get here if an undefined instruction happens and the floating
657 * point emulator is not present. If the offending instruction was
658 * a WFS, we just perform a normal return as if we had emulated the
659 * operation. This is a hack to allow some basic userland binaries
660 * to run so that the emulator module proper can be loaded. --philb
669 __dabt_svc: sub sp, sp, #S_FRAME_SIZE
670 stmia sp, {r0 - r12} @ save r0 - r12
672 add r0, sp, #S_FRAME_SIZE
673 ldmia r2, {r2 - r4} @ get pc, cpsr
676 stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
677 mrs r9, cpsr @ Enable interrupts if they were
679 biceq r9, r9, #I_BIT @ previously
680 mov r0, r2 @ *** remove once everyones in sync
682 * This routine must not corrupt r9
685 ldr r4, .LCprocfns @ pass r0, r3 to
686 mov lr, pc @ processor code
687 ldr pc, [r4] @ call processor specific code
693 bl SYMBOL_NAME(do_DataAbort)
694 mov r0, #I_BIT | MODE_SVC
698 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
701 __irq_svc: sub sp, sp, #S_FRAME_SIZE
702 stmia sp, {r0 - r12} @ save r0 - r12
704 add r5, sp, #S_FRAME_SIZE
708 stmia r4, {r5, r6, r7, r8, r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
709 1: get_irqnr_and_base r0, r6, r5, lr
712 @ routine called with r0 = irq number, r1 = struct pt_regs *
716 ldr r0, [sp, #S_PSR] @ irqs are already disabled
718 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
723 __und_svc: sub sp, sp, #S_FRAME_SIZE
724 stmia sp, {r0 - r12} @ save r0 - r12
728 add r5, sp, #S_FRAME_SIZE
730 stmia r4, {r5 - r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
732 adrsvc al, r9, 1f @ r9 = normal FP return
733 bl call_fpe @ lr = undefined instr return
735 mov r0, r5 @ unsigned long pc
736 mov r1, sp @ struct pt_regs *regs
737 bl SYMBOL_NAME(do_undefinstr)
739 1: mov r0, #I_BIT | MODE_SVC
741 ldr lr, [sp, #S_PSR] @ Get SVC cpsr
743 ldmia sp, {r0 - pc}^ @ Restore SVC registers
746 __pabt_svc: sub sp, sp, #S_FRAME_SIZE
747 stmia sp, {r0 - r12} @ save r0 - r12
749 add r0, sp, #S_FRAME_SIZE
750 ldmia r2, {r2 - r4} @ get pc, cpsr
753 stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
754 mrs r9, cpsr @ Enable interrupts if they were
756 biceq r9, r9, #I_BIT @ previously
758 mov r0, r2 @ address (pc)
760 bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler
761 mov r0, #I_BIT | MODE_SVC
765 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
768 .LCirq: .word __temp_irq
769 .LCund: .word __temp_und
770 .LCabt: .word __temp_abt
772 .LCprocfns: .word SYMBOL_NAME(processor)
774 .LCfp: .word SYMBOL_NAME(fp_enter)
782 __dabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
783 stmia sp, {r0 - r12} @ save r0 - r12
786 ldmia r7, {r2 - r4} @ Get USR pc, cpsr
787 stmia r5, {r2 - r4} @ Save USR pc, cpsr, old_r0
789 alignment_trap r7, r7, __temp_abt
791 mov r0, r2 @ remove once everyones in sync
793 ldr r4, .LCprocfns @ pass r0, r3 to
794 mov lr, pc @ processor code
795 ldr pc, [r4] @ call processor specific code
800 msr cpsr_c, r2 @ Enable interrupts
802 adrsvc al, lr, ret_from_exception
803 b SYMBOL_NAME(do_DataAbort)
806 __irq_usr: sub sp, sp, #S_FRAME_SIZE
807 stmia sp, {r0 - r12} @ save r0 - r12
810 ldmia r4, {r5 - r7} @ get saved PC, SPSR
811 stmia r8, {r5 - r7} @ save pc, psr, old_r0
813 alignment_trap r4, r7, __temp_irq
815 1: get_irqnr_and_base r0, r6, r5, lr
819 @ routine called with r0 = irq number, r1 = struct pt_regs *
829 __und_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
830 stmia sp, {r0 - r12} @ Save r0 - r12
834 stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0
835 stmdb r8, {sp, lr}^ @ Save user sp, lr
836 alignment_trap r4, r7, __temp_und
838 tst r6, #T_BIT @ Thumb mode
840 adrsvc al, r9, ret_from_exception @ r9 = normal FP return
841 adrsvc al, lr, fpundefinstr @ lr = undefined instr return
843 call_fpe: get_current_task r10
845 strb r8, [r10, #TSK_USED_MATH] @ set current->used_math
847 add r10, r10, #TSS_FPESAVE @ r10 = workspace
848 ldr pc, [r4] @ Call FP module USR entry point
850 fpundefinstr: mov r0, #MODE_SVC
851 msr cpsr_c, r0 @ Enable interrupts
854 adrsvc al, lr, ret_from_exception
855 b SYMBOL_NAME(do_undefinstr)
858 __pabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
859 stmia sp, {r0 - r12} @ Save r0 - r12
862 ldmia r4, {r5 - r7} @ Get USR pc, cpsr
863 stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0
864 stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr
865 alignment_trap r4, r7, __temp_abt
868 msr cpsr_c, r0 @ Enable interrupts
869 mov r0, r5 @ address (pc)
871 bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler
874 * This is the return code to user mode for abort handlers
876 ENTRY(ret_from_exception)
884 .word fpe_not_present
887 * Register switch for ARMv3 and ARMv4 processors
888 * r0 = previous, r1 = next, return previous.
889 * previous and next are guaranteed not to be the same.
892 stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack
894 str ip, [sp, #-4]! @ Save cpsr_SVC
895 str sp, [r0, #TSS_SAVE] @ Save sp_SVC
896 ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
897 ldr r2, [r1, #TSS_DOMAIN]
899 mcr p15, 0, r2, c3, c0 @ Set domain register
900 msr spsr, ip @ Save tasks CPSR into SPSR for this return
901 ldmfd sp!, {r4 - sl, fp, pc}^ @ Load all regs saved previously
903 .section ".text.init",#alloc,#execinstr
905 * Vector stubs. NOTE that we only align 'vector_IRQ' to a cache line boundary,
906 * and we rely on each stub being exactly 48 (1.5 cache lines) in size. This
907 * means that we only ever load two cache lines for this code, or one if we're
908 * lucky. We also copy this code to 0x200 so that we can use branches in the
909 * vectors, rather than ldr's.
914 * Interrupt dispatcher
915 * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
918 @ save mode specific registers
922 str lr, [r13] @ save lr_IRQ
924 str lr, [r13, #4] @ save spsr_IRQ
926 @ now branch to the relevent MODE handling routine
929 bic r13, r13, #MODE_MASK
930 orr r13, r13, #I_BIT | MODE_SVC
931 msr spsr_c, r13 @ switch to SVC_32 mode
934 ldr lr, [pc, lr, lsl #2]
935 movs pc, lr @ Changes mode and branches
937 .LCtab_irq: .word __irq_usr @ 0 (USR_26 / USR_32)
938 .word __irq_invalid @ 1 (FIQ_26 / FIQ_32)
939 .word __irq_invalid @ 2 (IRQ_26 / IRQ_32)
940 .word __irq_svc @ 3 (SVC_26 / SVC_32)
941 .word __irq_invalid @ 4
942 .word __irq_invalid @ 5
943 .word __irq_invalid @ 6
944 .word __irq_invalid @ 7
945 .word __irq_invalid @ 8
946 .word __irq_invalid @ 9
947 .word __irq_invalid @ a
948 .word __irq_invalid @ b
949 .word __irq_invalid @ c
950 .word __irq_invalid @ d
951 .word __irq_invalid @ e
952 .word __irq_invalid @ f
957 * Data abort dispatcher - dispatches it to the correct handler for the processor mode
958 * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
961 @ save mode specific registers
969 @ now branch to the relevent MODE handling routine
972 bic r13, r13, #MODE_MASK
973 orr r13, r13, #I_BIT | MODE_SVC
974 msr spsr_c, r13 @ switch to SVC_32 mode
977 ldr lr, [pc, lr, lsl #2]
978 movs pc, lr @ Changes mode and branches
980 .LCtab_dabt: .word __dabt_usr @ 0 (USR_26 / USR_32)
981 .word __dabt_invalid @ 1 (FIQ_26 / FIQ_32)
982 .word __dabt_invalid @ 2 (IRQ_26 / IRQ_32)
983 .word __dabt_svc @ 3 (SVC_26 / SVC_32)
984 .word __dabt_invalid @ 4
985 .word __dabt_invalid @ 5
986 .word __dabt_invalid @ 6
987 .word __dabt_invalid @ 7
988 .word __dabt_invalid @ 8
989 .word __dabt_invalid @ 9
990 .word __dabt_invalid @ a
991 .word __dabt_invalid @ b
992 .word __dabt_invalid @ c
993 .word __dabt_invalid @ d
994 .word __dabt_invalid @ e
995 .word __dabt_invalid @ f
1000 * Prefetch abort dispatcher - dispatches it to the correct handler for the processor mode
1001 * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
1005 @ save mode specific registers
1009 str lr, [r13] @ save lr_ABT
1011 str lr, [r13, #4] @ save spsr_ABT
1013 @ now branch to the relevent MODE handling routine
1016 bic r13, r13, #MODE_MASK
1017 orr r13, r13, #I_BIT | MODE_SVC
1018 msr spsr_c, r13 @ switch to SVC_32 mode
1021 ldr lr, [pc, lr, lsl #2]
1024 .LCtab_pabt: .word __pabt_usr @ 0 (USR_26 / USR_32)
1025 .word __pabt_invalid @ 1 (FIQ_26 / FIQ_32)
1026 .word __pabt_invalid @ 2 (IRQ_26 / IRQ_32)
1027 .word __pabt_svc @ 3 (SVC_26 / SVC_32)
1028 .word __pabt_invalid @ 4
1029 .word __pabt_invalid @ 5
1030 .word __pabt_invalid @ 6
1031 .word __pabt_invalid @ 7
1032 .word __pabt_invalid @ 8
1033 .word __pabt_invalid @ 9
1034 .word __pabt_invalid @ a
1035 .word __pabt_invalid @ b
1036 .word __pabt_invalid @ c
1037 .word __pabt_invalid @ d
1038 .word __pabt_invalid @ e
1039 .word __pabt_invalid @ f
1044 * Undef instr entry dispatcher - dispatches it to the correct handler for the processor mode
1045 * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
1049 @ save mode specific registers
1052 str lr, [r13] @ save lr_UND
1054 str lr, [r13, #4] @ save spsr_UND
1056 @ now branch to the relevent MODE handling routine
1059 bic r13, r13, #MODE_MASK
1060 orr r13, r13, #I_BIT | MODE_SVC
1061 msr spsr_c, r13 @ switch to SVC_32 mode
1064 ldr lr, [pc, lr, lsl #2]
1065 movs pc, lr @ Changes mode and branches
1067 .LCtab_und: .word __und_usr @ 0 (USR_26 / USR_32)
1068 .word __und_invalid @ 1 (FIQ_26 / FIQ_32)
1069 .word __und_invalid @ 2 (IRQ_26 / IRQ_32)
1070 .word __und_svc @ 3 (SVC_26 / SVC_32)
1071 .word __und_invalid @ 4
1072 .word __und_invalid @ 5
1073 .word __und_invalid @ 6
1074 .word __und_invalid @ 7
1075 .word __und_invalid @ 8
1076 .word __und_invalid @ 9
1077 .word __und_invalid @ a
1078 .word __und_invalid @ b
1079 .word __und_invalid @ c
1080 .word __und_invalid @ d
1081 .word __und_invalid @ e
1082 .word __und_invalid @ f
1086 /*=============================================================================
1088 *-----------------------------------------------------------------------------
1089 * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
1090 * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
1091 * Basically to switch modes, we *HAVE* to clobber one register... brain
1092 * damage alert! I don't think that we can execute any code in here in any
1093 * other mode than FIQ... Ok you can switch to another mode, but you can't
1094 * get out of that mode without clobbering one register.
1096 vector_FIQ: disable_fiq
1099 /*=============================================================================
1100 * Address exception handler
1101 *-----------------------------------------------------------------------------
1102 * These aren't too critical.
1103 * (they're not supposed to happen, and won't happen in 32-bit data mode).
1110 * We group all the following data together to optimise
1111 * for CPUs with separate I & D caches.
1115 .LCvswi: .word vector_swi
1117 .LCsirq: .word __temp_irq
1118 .LCsund: .word __temp_und
1119 .LCsabt: .word __temp_abt
1123 .equ __real_stubs_start, .LCvectors + 0x200
1125 .LCvectors: swi SYS_ERROR0
1126 b __real_stubs_start + (vector_undefinstr - __stubs_start)
1127 ldr pc, __real_stubs_start + (.LCvswi - __stubs_start)
1128 b __real_stubs_start + (vector_prefetch - __stubs_start)
1129 b __real_stubs_start + (vector_data - __stubs_start)
1130 b __real_stubs_start + (vector_addrexcptn - __stubs_start)
1131 b __real_stubs_start + (vector_IRQ - __stubs_start)
1132 b __real_stubs_start + (vector_FIQ - __stubs_start)
1135 stmfd sp!, {r4 - r6, lr}
1137 adr r1, .LCvectors @ set up the vectors
1138 ldmia r1, {r1, r2, r3, r4, r5, r6, ip, lr}
1139 stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr}
1142 adr r0, __stubs_start @ copy stubs to 0x200
1148 LOADREGS(fd, sp!, {r4 - r6, pc})
1153 * Do not reorder these, and do not insert extra data between...
1156 __temp_irq: .word 0 @ saved lr_irq
1157 .word 0 @ saved spsr_irq
1159 __temp_und: .word 0 @ Saved lr_und
1160 .word 0 @ Saved spsr_und
1162 __temp_abt: .word 0 @ Saved lr_abt
1163 .word 0 @ Saved spsr_abt
1166 .globl SYMBOL_NAME(cr_alignment)
1167 .globl SYMBOL_NAME(cr_no_alignment)
1168 SYMBOL_NAME(cr_alignment):
1170 SYMBOL_NAME(cr_no_alignment):