]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/arch/v2_0/src/vectors.S
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / hal / arm / arch / v2_0 / src / vectors.S
1 // #========================================================================
2 // #
3 // #    vectors.S
4 // #
5 // #    ARM exception vectors
6 // #
7 // #========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 // #========================================================================
41 // ######DESCRIPTIONBEGIN####
42 // #
43 // # Author(s):     nickg, gthomas
44 // # Contributors:  nickg, gthomas
45 // # Date:          1999-02-20
46 // # Purpose:       ARM exception vectors
47 // # Description:   This file defines the code placed into the exception
48 // #                vectors. It also contains the first level default VSRs
49 // #                that save and restore state for both exceptions and
50 // #                interrupts.
51 // #
52 // #####DESCRIPTIONEND####
53 // #
54 // #========================================================================
55
56 #include <pkgconf/hal.h>
57 #include <pkgconf/hal_arm.h>
58 #ifdef CYGPKG_KERNEL  // no CDL yet
59 #include <pkgconf/kernel.h>
60 #else
61 # undef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
62 # undef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
63 #endif
64 #include <cyg/hal/hal_platform_setup.h>
65
66 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
67 // The CDL should enforce this
68 #undef  CYGHWR_HAL_ARM_DUMP_EXCEPTIONS
69 #endif
70
71 #include "arm.inc"
72
73 #ifdef __thumb__
74 // Switch to thumb mode
75 #define THUMB_MODE(_r_, _l_)                     \
76         ldr     _r_,=_l_ ## f+1                 ;\
77         bx      _r_                             ;\
78         .pool                                   ;\
79         .code   16                              ;\
80         .thumb_func                             ;\
81  _l_:
82
83 // Call thumb function from ARM mode, return to ARM
84 // mode afterwards
85 #define THUMB_CALL(_r_, _l_, _f_)                \
86         ldr     _r_,=_f_+1                      ;\
87         mov     lr,pc                           ;\
88         bx      _r_                             ;\
89         .pool                                   ;\
90         .code   16                              ;\
91         .thumb_func                             ;\
92         ldr     _r_,=_l_  ## f                  ;\
93         bx      _r_                             ;\
94         .pool                                   ;\
95         .code   32                              ;\
96  _l_:
97
98 // Switch to ARM mode
99 #define ARM_MODE(_r_, _l_)                       \
100         ldr     _r_,=_l_ ## f                   ;\
101         bx      _r_                             ;\
102         .pool                                   ;\
103         .code   32                              ;\
104  _l_:
105
106 // Function definition, start executing body in ARM mode
107 #define FUNC_START_ARM(_name_, _r_)              \
108         .code   16                              ;\
109         .thumb_func                             ;\
110         .globl _name_                           ;\
111 _name_:                                         ;\
112         ldr     _r_,=_name_ ## _ARM             ;\
113         bx      _r_                             ;\
114         .code   32                              ;\
115 _name_ ## _ARM:
116
117 #else
118
119 // Switch to thumb mode
120 #define THUMB_MODE(_r_, _l_)
121
122 // Call ARM function
123 #define THUMB_CALL(_r_, _l_, _f_) \
124         bl      _f_
125
126 // Switch to ARM mode
127 #define ARM_MODE(_r_, _l_)
128
129 // Function definition, start executing body in ARM mode
130 #define FUNC_START_ARM(_name_, _r_) \
131         .globl _name_; \
132 _name_:
133
134 #endif
135
136
137
138 #define PTR(name)               \
139 .##name: .word  name
140
141 // CYGHWR_HAL_ROM_VADDR is used when compiling for a different location
142 // from the base of ROM.  hal_platform_setup.h might define it.  For
143 // example, if flash is from 0x50000000 upwards (as on SA11x0), and we are
144 // to execute at 0x50040000, then we want the reset vector to point to
145 // 0x0004pqrs - the unmapped ROM address of the code - rather than
146 // 0x0000pqrs, which is the offset into our flash block.
147 //
148 // But usually it's not defined, so the behaviour is the obvious.
149
150 #ifndef UNMAPPED
151 #ifdef CYGHWR_HAL_ARM_HAS_MMU
152 # ifndef CYGHWR_HAL_ROM_VADDR
153 #  define CYGHWR_HAL_ROM_VADDR __exception_handlers
154 # endif
155 # define UNMAPPED(x) ((x)-CYGHWR_HAL_ROM_VADDR)
156 #else
157 # define UNMAPPED(x) (x)
158 #endif
159 #endif
160
161 #define UNMAPPED_PTR(name)              \
162 .##name: .word  UNMAPPED(name)
163
164 //        .file   "vectors.S"
165
166
167 // CYGHWR_LED_MACRO can be defined in hal_platform_setup.h. It's free to
168 // use r0+r1. Argument is in "\x" - cannot use macro arguments since the
169 // macro may contain #-chars and use of arguments cause these to be
170 // interpreted as CPP stringify operators.
171 // See example in PID hal_platform_setup.h.
172 #ifndef CYGHWR_LED_MACRO
173 #define CYGHWR_LED_MACRO
174 #endif
175
176 .macro LED x
177     CYGHWR_LED_MACRO
178 .endm
179
180
181 //==========================================================================
182 // Hardware exception vectors.
183 //   This entire section will be copied to location 0x0000 at startup time.
184 //
185         .code   32
186         .section ".vectors","ax"
187
188 // This macro allows platforms to add their own code at the very start of
189 // the image.  This may be required in some circumstances where eCos ROM
190 // based code does not run immediately upon reset and/or when some sort of
191 // special header is required at the start of the image.
192 #ifdef PLATFORM_PREAMBLE
193         PLATFORM_PREAMBLE
194 #endif
195
196         .global __exception_handlers
197 __exception_handlers:
198 #ifdef CYGSEM_HAL_ROM_RESET_USES_JUMP
199 // Assumption:  ROM code has these vectors at the hardware reset address.
200 // A simple jump removes any address-space dependencies [i.e. safer]
201         b       reset_vector                    // 0x00
202 #else
203         ldr     pc,.reset_vector                // 0x00
204 #endif
205         ldr     pc,.undefined_instruction       // 0x04
206         ldr     pc,.software_interrupt          // 0x08 start && software int
207         ldr     pc,.abort_prefetch              // 0x0C
208         ldr     pc,.abort_data                  // 0x10
209 #ifdef CYGNUM_HAL_ARM_VECTOR_0x14
210         .word   CYGNUM_HAL_ARM_VECTOR_0x14
211 #else
212         .word   0                               // unused
213 #endif
214         ldr     pc,.IRQ                         // 0x18
215         ldr     pc,.FIQ                         // 0x1C
216
217 // The layout of these pointers should match the vector table above since
218 // they are copied in pairs.
219         .global vectors
220 vectors:
221 UNMAPPED_PTR(reset_vector)                      // 0x20
222 PTR(undefined_instruction)                      // 0x24
223 PTR(software_interrupt)                         // 0x28
224 PTR(abort_prefetch)                             // 0x2C
225 PTR(abort_data)                                 // 0x30
226         .word   0                               // 0x34
227 PTR(IRQ)                                        // 0x38
228 PTR(FIQ)                                        // 0x3c
229 #ifdef CYGSEM_HAL_ARM_PID_ANGEL_BOOT
230 PTR(start) // This is copied to 0x28 for bootup // 0x40
231 #endif
232            // location 0x40 is used for storing DRAM size if known
233            // for some platforms.
234
235 //
236 // "Vectors" - fixed location data items
237 //    This section contains any data which might be shared between
238 // an eCos application and any other environment, e.g. the debug
239 // ROM.
240 //
241         .section ".fixed_vectors"
242         // Interrupt/exception VSR pointers
243         .globl  hal_vsr_table
244 hal_vsr_table:
245         .rept   8
246         .long   0
247         .endr
248
249         .globl  hal_dram_size
250 hal_dram_size:
251         .long   0
252         // what, if anything, hal_dram_type means is up to the platform
253         .globl  hal_dram_type
254 hal_dram_type:
255         .long   0
256
257         .balign 16
258 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
259         // Vectors used to communicate between eCos and ROM environments
260         .globl  hal_virtual_vector_table
261 hal_virtual_vector_table:
262         .rept   CYGNUM_CALL_IF_TABLE_SIZE
263         .long   0
264         .endr
265 #endif
266
267 #ifdef CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT
268         .balign 16      // Should be at 0x50
269 ice_thread_vector:
270         .long   0       // Must be 'MICE'
271         .long   0       // Pointer to thread support vector
272         .long   0       // eCos executing flag
273         .long   0       // Must be 'GDB '
274 #endif // CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT
275         .balign 32
276
277 // Other vectors - this may include "fixed" locations
278 #ifdef PLATFORM_VECTORS
279         PLATFORM_VECTORS
280 #endif
281
282         .text
283 // Startup code which will get the machine into supervisor mode
284         .global reset_vector
285         .type   reset_vector,function
286 reset_vector:
287         PLATFORM_SETUP1         // Early stage platform initialization
288                                 // which can set DRAM size at 0x40
289                                 // see <cyg/hal/hal_platform_setup.h>
290
291         // Come here to reset board
292 warm_reset:
293
294 #if defined(CYG_HAL_STARTUP_RAM) && \
295     !defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
296         mrs     r7,cpsr                 // move back to IRQ mode
297         and     r7,r7,#CPSR_MODE_BITS
298         cmp     r7,#CPSR_SUPERVISOR_MODE
299         beq     start
300 #endif
301
302         // We cannot access any LED registers until after PLATFORM_SETUP1
303         LED 7
304
305         mov     r0,#0           // move vectors
306         ldr     r1,=__exception_handlers
307 #ifndef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
308         // Wait with this if stubs are included (see further down).
309         ldr     r2,[r1,#0x04]   // undefined instruction
310         str     r2,[r0,#0x04]
311         ldr     r2,[r1,#0x24]
312         str     r2,[r0,#0x24]
313 #endif
314         ldr     r2,[r1,#0x08]   // software interrupt
315         str     r2,[r0,#0x08]
316
317 #ifdef CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT
318         ldr     r2,=ice_thread_vector
319         sub     r2,r2,r1        // compute fixed (low memory) address
320         ldr     r3,=0x4D494345  // 'MICE'
321         str     r3,[r2],#4
322         ldr     r3,=hal_arm_ice_thread_handler
323         str     r3,[r2],#4
324         mov     r3,#1
325         str     r3,[r2],#4
326         ldr     r3,=0x47444220  // 'GDB '
327         str     r3,[r2],#4
328 #endif // CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT
329
330 #if defined(CYGSEM_HAL_ARM_PID_ANGEL_BOOT)
331 // Ugly hack to get into supervisor mode
332         ldr     r2,[r1,#0x40]
333         str     r2,[r0,#0x28]
334
335         LED 6
336
337         swi                     // switch to supervisor mode
338 #endif
339
340 // =========================================================================
341 // Real startup code. We jump here from the reset vector to set up the world.
342         .globl  start
343 start:
344
345         LED 5
346
347 #if defined(CYG_HAL_STARTUP_RAM) && \
348     !defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
349 // If we get restarted, hang here to avoid corrupting memory
350         ldr     r0,.init_flag
351         ldr     r1,[r0]
352 1:      cmp     r1,#0
353         bne     1b
354         ldr     r1,init_done
355         str     r1,[r0]
356 #endif
357
358         // Reset software interrupt pointer
359         mov     r0,#0           // move vectors
360         ldr     r1,.__exception_handlers
361 #if defined(CYG_HAL_STARTUP_RAM) && \
362     !defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
363         cmp     r7,#CPSR_SUPERVISOR_MODE
364         beq     10f
365 #endif
366         ldr     r2,[r1,#0x28]   // software interrupt
367         str     r2,[r0,#0x28]
368 10:
369         ldr     r2,[r1,#0x18]   // IRQ
370         str     r2,[r0,#0x18]
371         ldr     r2,[r1,#0x38]
372         str     r2,[r0,#0x38]
373         ldr     r2,[r1,#0x1C]   // FIQ
374         str     r2,[r0,#0x1C]
375         ldr     r2,[r1,#0x3C]
376         str     r2,[r0,#0x3C]
377         ldr     r2,[r1,#0x0C]   // abort (prefetch)
378         str     r2,[r0,#0x0C]
379         ldr     r2,[r1,#0x2C]
380         str     r2,[r0,#0x2C]
381         ldr     r2,[r1,#0x10]   // abort (data)
382         str     r2,[r0,#0x10]
383         ldr     r2,[r1,#0x30]
384         str     r2,[r0,#0x30]
385
386         LED 4
387
388 #if defined(CYG_HAL_STARTUP_ROM) || defined(CYG_HAL_STARTUP_ROMRAM)
389         // Set up reset vector
390         mov     r0,#0
391         ldr     r1,.__exception_handlers
392         ldr     r2,[r1,#0x00]    // reset vector intstruction
393         str     r2,[r0,#0x00]
394         ldr     r2,=warm_reset
395         str     r2,[r0,#0x20]
396         // Relocate [copy] data from ROM to RAM
397         ldr     r3,.__rom_data_start
398         ldr     r4,.__ram_data_start
399         ldr     r5,.__ram_data_end
400         cmp     r4,r5           // jump if no data to move
401         beq     2f
402         sub     r3,r3,#4        // loop adjustments
403         sub     r4,r4,#4
404 1:      ldr     r0,[r3,#4]!     // copy info
405         str     r0,[r4,#4]!
406         cmp     r4,r5
407         bne     1b
408 2:
409 #endif
410
411         // initialize interrupt/exception environments
412         ldr     sp,.__startup_stack
413         mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_IRQ_MODE)
414         msr     cpsr,r0
415         ldr     sp,.__exception_stack
416         mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_UNDEF_MODE)
417         msr     cpsr,r0
418         ldr     sp,.__exception_stack
419
420         // initialize CPSR (machine state register)
421         mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SUPERVISOR_MODE)
422         msr     cpsr,r0
423
424         // Note: some functions in LIBGCC1 will cause a "restore from SPSR"!!
425         msr     spsr,r0
426
427         // initialize stack
428 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
429         // use interrupt stack for system initialization since it's bigger
430         // than the "startup" stack in this configuration
431         ldr     sp,.__interrupt_stack
432 #else
433         ldr     sp,.__startup_stack
434 #endif
435
436         // clear BSS
437         ldr     r1,.__bss_start
438         ldr     r2,.__bss_end
439         mov     r0,#0
440         cmp     r1,r2
441         beq     2f
442 1:      str     r0,[r1],#4
443         cmp     r1,r2
444         bls     1b
445 2:
446
447         // Run kernel + application in THUMB mode
448         THUMB_MODE(r1,10)
449
450         LED 3
451
452         // Call platform specific hardware initialization
453         bl      hal_hardware_init
454
455 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
456         bl      initialize_stub
457
458         // Now that stub is initialized, change vector. It is possible
459         // to single-step through most of the init code, except the below.
460         // Put a breakpoint at the call to cyg_hal_invoke_constructors to
461         // pass over this bit (s-s depends on internal state in the stub).
462 #endif
463
464 #if defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS) || \
465     defined(CYGIMP_HAL_PROCESS_ALL_EXCEPTIONS)
466         mov     r0,#0           // move vectors
467         ldr     r1,=__exception_handlers
468         ldr     r2,[r1,#0x04]   // undefined instruction
469         str     r2,[r0,#0x04]
470         ldr     r2,[r1,#0x24]
471         str     r2,[r0,#0x24]
472 #endif
473
474 #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \
475     || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
476         .extern hal_ctrlc_isr_init
477         bl      hal_ctrlc_isr_init
478 #endif
479
480         LED 2
481
482         // Run through static constructors
483         bl      cyg_hal_invoke_constructors
484
485         LED 1
486
487         // This starts up the eCos kernel
488 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
489         ldr     r1,=__startup_stack
490         mov     sp,r1
491 #endif
492         bl      cyg_start
493 _start_hang:
494         b       _start_hang
495         .code   32
496
497         .global reset_platform
498         .type   reset_platform,function
499 reset_platform:
500 #ifdef CYGSEM_HAL_ROM_MONITOR
501         // initialize CPSR (machine state register)
502         mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SUPERVISOR_MODE)
503         msr     cpsr,r0
504         b       warm_reset
505 #else
506         mov     r0,#0
507         mov     pc,r0           // Jump to reset vector
508 #endif
509
510 init_done:
511         .long   0xDEADB00B
512
513 //
514 // Exception handlers
515 // Assumption: get here from a non-user context [mode]
516 //             except in case of standalone app. running in user mode
517 //             (CYGOPT_HAL_ARM_WITH_USER_MODE should have been defined)
518 //
519         .code   32
520 undefined_instruction:
521         ldr     sp,.__undef_exception_stack     // get good stack
522         stmfd   sp!,{r0-r5}                     // save some supervisor regs
523         mrs     r1,spsr
524         tst     r1,#CPSR_THUMB_ENABLE
525         subeq   r0,lr,#4                // PC at time of interrupt (ARM)
526         subne   r0,lr,#2                // PC at time of interrupt (thumb)
527         mov     r2,#CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION
528         mov     r3,sp
529         b       call_exception_handler
530
531         .code   32
532 software_interrupt:
533         stmfd   sp!,{r8}
534         ldr     r8,.__undef_exception_stack     // get good stack
535         stmfd   r8!,{r0-r5}                     // save some supervisor regs
536         mov     r3,r8
537         ldmfd   sp!,{r8}
538         mrs     r1,spsr
539         tst     r1,#CPSR_THUMB_ENABLE
540         subeq   r0,lr,#4                // PC at time of SWI (ARM)
541         subne   r0,lr,#2                // PC at time of SWI (thumb)
542         mov     r2,#CYGNUM_HAL_EXCEPTION_INTERRUPT
543         b       call_exception_handler
544
545         .code   32
546 abort_prefetch:
547         ldr     sp,.__undef_exception_stack     // get good stack
548         stmfd   sp!,{r0-r5}                     // save some supervisor regs
549         sub     r0,lr,#4                        // PC at time of interrupt
550         mrs     r1,spsr
551         mov     r2,#CYGNUM_HAL_EXCEPTION_CODE_ACCESS
552         mov     r3,sp
553         b       call_exception_handler
554
555         .code   32
556 abort_data:
557         ldr     sp,.__undef_exception_stack     // get good stack
558         stmfd   sp!,{r0-r5}                     // save some supervisor regs
559         sub     r0,lr,#4                        // PC at time of interrupt
560         mrs     r1,spsr
561         mov     r2,#CYGNUM_HAL_EXCEPTION_DATA_ACCESS
562         mov     r3,sp
563         b       call_exception_handler
564
565 //
566 // Dispatch an exception handler.
567
568         .code   32
569 call_exception_handler:
570         //
571         // On Entry:
572         //
573         // r4,r5 = scratch
574         // r3 = pointer to temp save area
575         // r2 = vector number
576         // r1 = exception psr
577         // r0 = exception pc
578         //
579         // [r3+20]: exception r5
580         // [r3+16]: exception r4
581         // [r3+12]: exception r3
582         // [r3+8] : exception r2
583         // [r3+4] : exception r1
584         // [r3]   : exception r0
585
586         mrs     r4,cpsr                 // switch to Supervisor Mode
587         bic     r4,r4,#CPSR_MODE_BITS
588         orr     r4,r4,#CPSR_SUPERVISOR_MODE
589         msr     cpsr,r4
590
591         mov     r5,sp                   // save original svc sp
592         mov     r4,lr                   // and original svc lr
593 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
594         // Make sure we use the GDB stack.
595         ldr     sp,.__GDB_stack
596         cmp     r5,sp                   // already on GDB stack?
597         bhi     10f
598         ldr     r4,.__GDB_stack_base
599         cmp     r5,r4
600         movhi   sp,r5
601 10:
602 #endif
603         //
604         // r5 holds original svc sp, current sp is stack to use
605         // r4 holds original svc lr, which must also be preserved
606         //
607
608         stmfd   sp!,{r0-r2,r4,r5}       // push svc_sp, svc_lr, vector, psr, pc
609
610 #ifdef CYGOPT_HAL_ARM_WITH_USER_MODE
611         // did exception occur in user mode ?
612         and     r2, r1, #CPSR_MODE_BITS
613         cmp     r2, #CPSR_USER_MODE
614         bne     1f
615         stmfd   sp, {r8-r12, sp, lr}^   // get user mode regs
616         nop
617         sub     sp, sp, #4*7
618         bal     2f
619 1:
620 #endif
621         // switch to pre-exception mode to get banked regs
622         mov     r0,sp                   // r0 survives mode switch
623         mrs     r2,cpsr                 // Save current psr for return
624         orr     r1,r1,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
625         bic     r1,r1,#CPSR_THUMB_ENABLE
626         msr     cpsr,r1
627         stmfd   r0!,{r8-r12,sp,lr}
628         msr     cpsr,r2                 // back to svc mode
629         mov     sp,r0                   // update stack pointer
630 2:
631         // now save pre-exception r0-r7 on current stack
632         ldmfd   r3,{r0-r5}
633         stmfd   sp!,{r0-r7}
634
635         // SP needs fixing if exception occured in SVC mode.
636         // The original SVC LR is still in place so that
637         // does not need to be fixed here.
638         ldr     r1,[sp,#armreg_cpsr]
639         and     r1,r1,#CPSR_MODE_BITS
640         cmp     r1,#CPSR_SUPERVISOR_MODE
641         ldreq   r1,[sp,#armreg_svcsp]
642         streq   r1,[sp,#armreg_sp]
643
644 #ifdef  CYGHWR_HAL_ARM_DUMP_EXCEPTIONS
645         mov     r0,sp
646         ldr     r1,.__dump_procs
647         ldr     r2,[sp,#armreg_vector]
648         ldr     r1,[r1,r2,lsl #2]
649         THUMB_MODE(r9,10)
650         mov     lr,pc
651         mov     pc,r1
652 #else
653         THUMB_MODE(r9,10)
654 #endif
655
656         // call exception handler
657         mov     r0,sp
658         bl      exception_handler
659
660 #ifdef  CYGHWR_HAL_ARM_DUMP_EXCEPTIONS
661         mov     r0,sp
662         bl      cyg_hal_report_exception_handler_returned
663 #endif
664
665         ARM_MODE(r1,10)
666
667         //
668         // Return from exception
669         //
670 return_from_exception:
671
672         ldr     r0,[sp,#armreg_cpsr]
673
674         // return to supervisor mode is simple
675         and     r1,r0,#CPSR_MODE_BITS
676         cmp     r1,#CPSR_SUPERVISOR_MODE
677
678 #ifndef CYGOPT_HAL_ARM_PRESERVE_SVC_SPSR
679         msr     spsr,r0
680         ldmeqfd sp,{r0-r14,pc}^
681 #else
682         // we must take care of not corrupting the current (svc)
683         // spsr which happens to be also the pre-exception spsr
684         bne     1f
685         tst     r0, #CPSR_THUMB_ENABLE
686
687         // when returning to thumb/svc mode, there is no easy way to preserve
688         // spsr. It is possible to do so, but would add a lot of instructions.
689         // The purpose of CYGOPT_HAL_ARM_PRESERVE_SVC_SPSR is to allow stepping
690         // through SWI exception handling code, so not preserving spsr in this
691         // case should be okay.
692         msrne   spsr,r0
693         ldmnefd sp,{r0-r14,pc}^
694
695         // we are returning to arm/svc mode thus we must restore the
696         // pre-exception cpsr before returning to interrupted code
697         msr     cpsr, r0
698         ldmfd   sp, {r0-r14, pc}
699 1:
700         // we are not returning to svc mode thus we can safely restore
701         // svc spsr
702         msr     spsr, r0
703 #endif
704
705 #ifdef CYGOPT_HAL_ARM_WITH_USER_MODE
706         // are we returning to user mode ?
707         and     r2, r1, #CPSR_MODE_BITS
708         cmp     r2, #CPSR_USER_MODE
709         add     r2, sp, #armreg_r8
710         bne     1f
711         ldmfd   r2, {r8-r14}^           // restore user mode regs
712         nop
713         bal     2f
714 1:
715 #else
716         add     r2, sp, #armreg_r8
717 #endif
718         //
719         // return to other non-user modes is a little trickier
720         //
721
722         // switch to pre-exception mode and restore r8-r14
723         mrs     r1,cpsr
724         orr     r0,r0,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
725         bic     r0,r0,#CPSR_THUMB_ENABLE
726         msr     cpsr,r0
727         ldmfd   r2,{r8-r14}
728         msr     cpsr, r1        // back to svc mode
729
730 2:
731         // move sp,lr and pc for final load
732         ldr     r0,[sp,#armreg_svcsp]
733         str     r0,[sp,#armreg_r8]
734         ldr     r0,[sp,#armreg_svclr]
735         str     r0,[sp,#armreg_r9]
736         ldr     r0,[sp,#armreg_pc]
737         str     r0,[sp,#armreg_r10]
738
739         // restore r0-r7,sp,lr and return from exception
740         ldmfd   sp,{r0-r7,sp,lr,pc}^
741
742 #ifdef  CYGHWR_HAL_ARM_DUMP_EXCEPTIONS
743 __dump_procs:
744         .word  0    // placeholder for reset
745         .word  cyg_hal_report_undefined_instruction
746         .word  cyg_hal_report_software_interrupt
747         .word  cyg_hal_report_abort_prefetch
748         .word  cyg_hal_report_abort_data
749         .word  0    // reserved
750 #endif
751
752
753 // Handle device interrupts
754 // This is slightly more complicated than the other exception handlers because
755 // it needs to interface with the kernel (if present).
756 // Assumption: can get here from any mode, including user mode
757 // (spurious interrupt while standalone app. is running in user mode)
758
759         .code   32
760 FIQ:
761         // We can get here from any non-user mode.
762         mrs     r8,spsr                 // CPSR at time of interrupt
763         and     r9,r8,#CPSR_MODE_BITS   // isolate pre-interrupt mode
764         cmp     r9,#CPSR_IRQ_MODE
765         bne     1f
766         // If FIQ interrupted IRQ mode, just return with FIQ disabled.
767         // The common interrupt handling takes care of the rest.
768         orr     r8,r8,#CPSR_FIQ_DISABLE
769         msr     spsr,r8
770         subs    pc,lr,#4
771     1:
772         // If FIQ interrupted other non-user mode, switch to IRQ mode and
773         // fall through to IRQ handler.
774         ldr     sp,.__exception_stack   // get good stack to save lr and spsr
775         stmdb   sp,{r8,lr}
776         mov     r8,#CPSR_IRQ_MODE|CPSR_FIQ_DISABLE|CPSR_IRQ_DISABLE
777         msr     cpsr,r8                 // switch to IRQ mode
778         ldr     sp,.__exception_stack   // get regs saved in FIQ mode
779         ldmdb   sp,{sp,lr}
780         msr     spsr,sp
781
782         // now it looks like we got an IRQ instead of an FIQ except that
783         // FIQ is disabled so we don't recurse.
784 IRQ:
785         // Note: I use this exception stack while saving the context because
786         // the current SP does not seem to be always valid in this CPU mode.
787         ldr     sp,.__exception_stack   // get good stack
788         stmfd   sp!,{r0-r5}             // save some supervisor regs
789         sub     r0,lr,#4                // PC at time of interrupt
790         mrs     r1,spsr
791         mov     r2,#CYGNUM_HAL_VECTOR_IRQ
792         mov     r3,sp
793
794         mrs     r4,cpsr                 // switch to Supervisor Mode
795         bic     r4,r4,#CPSR_MODE_BITS
796         // When handling an IRQ we must disable FIQ unless the current
797         // mode in CPSR is IRQ. If we were to get a FIQ while in another
798         // mode, the FIQ handling code would transform the FIQ into an
799         // IRQ and call the non-reentrant IRQ handler again. As a result,
800         // for example, the stack pointer would be set to the beginning
801         // of the exception_stack clobbering the registers we have just
802         // saved.
803         orr     r4,r4,#CPSR_SUPERVISOR_MODE|CPSR_FIQ_DISABLE
804         msr     cpsr,r4
805
806         mov     r5,sp                   // save original svc sp
807         mov     r4,lr                   // save original svc lr
808         stmfd   sp!,{r0-r2,r4,r5}       // push svc_sp, svc_lr, vector, psr, pc
809
810 #ifdef CYGOPT_HAL_ARM_WITH_USER_MODE
811         // did exception occur in user mode ?
812         and     r2, r1, #CPSR_MODE_BITS
813         cmp     r2, #CPSR_USER_MODE
814         bne     1f
815         stmfd   sp, {r8-r12, sp, lr}^   // get user mode regs
816         nop
817         sub     sp, sp, #4*7
818         bal     2f
819 1:
820 #endif
821         // switch to pre-exception mode to get banked regs
822         mov     r0,sp                   // r0 survives mode switch
823         mrs     r2,cpsr                 // Save current psr for return
824         orr     r1,r1,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
825         bic     r1,r1,#CPSR_THUMB_ENABLE
826         msr     cpsr,r1
827         stmfd   r0!,{r8-r12,sp,lr}
828         msr     cpsr,r2                 // back to svc mode
829         mov     sp,r0                   // update stack pointer
830
831 2:
832         // now save pre-exception r0-r7 on current stack
833         ldmfd   r3,{r0-r5}
834         stmfd   sp!,{r0-r7}
835
836         // sp needs fixing if exception occured in SVC mode.
837         ldr     r1,[sp,#armreg_cpsr]
838         and     r1,r1,#CPSR_MODE_BITS
839         cmp     r1,#CPSR_SUPERVISOR_MODE
840         ldreq   r1,[sp,#armreg_svcsp]
841         streq   r1,[sp,#armreg_sp]
842
843         mov     v6,sp                   // Save pointer to register frame
844
845 //      mov     r0,sp
846 //      bl      _show_frame_in
847
848 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
849         // Switch to interrupt stack
850         ldr     r2,.irq_level           // current number of nested interrupts
851         ldr     r0,[r2]
852         add     r1,r0,#1
853         str     r1,[r2]                 // if was zero, switch stacks
854         cmp     r0,#0
855         moveq   r1,sp                   // save old stack pointer
856         ldreq   sp,.__interrupt_stack
857         stmeqfd sp!,{r1}
858 10:
859 #endif
860
861         // The entire CPU state is now stashed on the stack,
862         // increment the scheduler lock and handle the interrupt
863
864 #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
865         .extern cyg_scheduler_sched_lock
866         ldr     r3,.cyg_scheduler_sched_lock
867         ldr     r4,[r3]
868         add     r4,r4,#1
869         str     r4,[r3]
870 #endif
871
872         THUMB_MODE(r3,10)
873
874         mov     r0,v6
875         bl      hal_IRQ_handler         // determine interrupt source
876         mov     v1,r0                   // returned vector #
877
878 #if defined(CYGPKG_KERNEL_INSTRUMENT) && \
879     defined(CYGDBG_KERNEL_INSTRUMENT_INTR)
880         ldr     r0,=RAISE_INTR          // arg0 = type = INTR,RAISE
881         mov     r1,v1                   // arg1 = vector
882         mov     r2,#0                   // arg2 = 0
883         bl      cyg_instrument          // call instrument function
884 #endif
885
886         ARM_MODE(r0,10)
887
888         mov     r0,v1                   // vector #
889
890 #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \
891     || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
892         // If we are supporting Ctrl-C interrupts from GDB, we must squirrel
893         // away a pointer to the save interrupt state here so that we can
894         // plant a breakpoint at some later time.
895
896        .extern  hal_saved_interrupt_state
897         ldr     r2,=hal_saved_interrupt_state
898         str     v6,[r2]
899 #endif
900
901         cmp     r0,#CYGNUM_HAL_INTERRUPT_NONE   // spurious interrupt
902         bne     10f
903
904 #ifdef  CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS
905         // Acknowledge the interrupt
906         THUMB_CALL(r1,12,hal_interrupt_acknowledge)
907 #else
908         mov     r0,v6                   // register frame
909         THUMB_CALL(r1,12,hal_spurious_IRQ)
910 #endif // CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS
911         b       spurious_IRQ
912
913 10:     ldr     r1,.hal_interrupt_data
914         ldr     r1,[r1,v1,lsl #2]       // handler data
915         ldr     r2,.hal_interrupt_handlers
916         ldr     v3,[r2,v1,lsl #2]       // handler (indexed by vector #)
917         mov     r2,v6                   // register frame (this is necessary
918                                         // for the ISR too, for ^C detection)
919
920 #ifdef __thumb__
921         ldr     lr,=10f
922         bx      v3                      // invoke handler (thumb mode)
923         .pool
924         .code   16
925         .thumb_func
926 IRQ_10T:
927 10:     ldr     r2,=15f
928         bx      r2                      // switch back to ARM mode
929         .pool
930         .code   32
931 15:
932 IRQ_15A:
933 #else
934         mov     lr,pc                   // invoke handler (call indirect
935         mov     pc,v3                   // thru v3)
936 #endif
937
938 spurious_IRQ:
939
940 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
941         // If we are returning from the last nested interrupt, move back
942         // to the thread stack. interrupt_end() must be called on the
943         // thread stack since it potentially causes a context switch.
944         ldr     r2,.irq_level
945         ldr     r3,[r2]
946         subs    r1,r3,#1
947         str     r1,[r2]
948         ldreq   sp,[sp]         // This should be the saved stack pointer
949 #endif
950         // The return value from the handler (in r0) will indicate whether a
951         // DSR is to be posted. Pass this together with a pointer to the
952         // interrupt object we have just used to the interrupt tidy up routine.
953
954                               // don't run this for spurious interrupts!
955         cmp     v1,#CYGNUM_HAL_INTERRUPT_NONE
956         beq     17f
957         ldr     r1,.hal_interrupt_objects
958         ldr     r1,[r1,v1,lsl #2]
959         mov     r2,v6           // register frame
960
961         THUMB_MODE(r3,10)
962
963         bl      interrupt_end   // post any bottom layer handler
964                                 // threads and call scheduler
965         ARM_MODE(r1,10)
966 17:
967
968 //      mov     r0,sp
969 //      bl      show_frame_out
970
971         // return from IRQ is same as return from exception
972         b       return_from_exception
973
974 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
975 // Execute pending DSRs the interrupt stack
976 // Note: this can only be called from code running on a thread stack
977 FUNC_START_ARM(hal_interrupt_stack_call_pending_DSRs, r1)
978         stmfd   sp!,{r4,r5,lr}
979         // Disable interrupts
980         mrs     r4,cpsr                 // disable IRQ's
981         orr     r2,r4,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
982         bic     r5,r4,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
983         msr     cpsr,r2
984         // Switch to interrupt stack
985         mov     r3,sp                   // save old stack pointer
986         ldr     sp,.__interrupt_stack
987         stmfd   sp!,{r3}                // stored at top of interrupt stack
988         ldr     r2,.irq_level           // current number of nested interrupts
989         ldr     r3,[r2]
990         add     r3,r3,#1                // bump nesting level
991         str     r3,[r2]
992         msr     cpsr,r5                 // enable interrupts
993
994         THUMB_MODE(r1,20)
995
996         bl      cyg_interrupt_call_pending_DSRs
997
998
999         ARM_MODE(r1,22)
1000
1001         // Disable interrupts
1002         mrs     r1,cpsr                 // disable IRQ's
1003         orr     r2,r1,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
1004         msr     cpsr,r2
1005
1006         // Move back to the thread stack.
1007         ldr     r2,.irq_level
1008         ldr     r3,[r2]
1009         sub     r3,r3,#1                // decrement nesting level
1010         str     r3,[r2]
1011         ldr     sp,[sp]                 // This should be the saved stack pointer
1012         msr     cpsr,r4                 // restore interrupts to original state
1013
1014 #ifdef __thumb__
1015         ldmfd   sp!,{r4,r5,lr}          // return
1016         bx      lr
1017 #else
1018         ldmfd   sp!,{r4,r5,pc}          // return
1019 #endif // __thumb__
1020 #endif // CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
1021
1022 // Thumb-only support functions
1023 #ifdef __thumb__
1024
1025 FUNC_START_ARM(hal_disable_interrupts, r1)
1026         mrs     r0,cpsr                 // current state
1027         orr     r1,r0,#0xC0             // mask both FIQ and IRQ
1028         msr     cpsr,r1
1029         bx      lr                      // exit, _old_ in r0
1030
1031 FUNC_START_ARM(hal_enable_interrupts, r1)
1032         mrs     r0,cpsr                 // current state
1033         bic     r1,r0,#0xC0             // mask both FIQ and IRQ
1034         msr     cpsr,r1
1035         bx      lr                      // exit
1036
1037 FUNC_START_ARM(hal_restore_interrupts, r1)
1038         mrs     r1,cpsr                 // current state
1039         bic     r1,r1,#0xC0             // mask out FIQ/IRQ bits
1040         and     r0,r0,#0xC0             // keep only FIQ/IRQ
1041         orr     r1,r1,r0                // mask both FIQ and IRQ
1042         msr     cpsr,r1
1043         bx      lr                      // exit
1044
1045 FUNC_START_ARM(hal_query_interrupts, r1)
1046         mrs     r0,cpsr                 // current state
1047         bx      lr                      // exit, state in r0
1048
1049 #endif // __thumb__
1050
1051 // Dummy/support functions
1052
1053         .global __gccmain
1054         .global _psr
1055         .global _sp
1056
1057 #ifdef __thumb__
1058         .code   16
1059         .thumb_func
1060 __gccmain:
1061         bx      lr
1062
1063         .code   16
1064         .thumb_func
1065 _psr:
1066         ARM_MODE(r1,10)
1067         mrs     r0,cpsr
1068         bx      lr
1069
1070         .code   16
1071         .thumb_func
1072 _sp:
1073         mov     r0,sp
1074         bx      lr
1075 #else
1076 __gccmain:
1077         mov     pc,lr
1078
1079 _psr:
1080         mrs     r0,cpsr
1081         mov     pc,lr
1082
1083 _sp:
1084         mov     r0,sp
1085         mov     pc,lr
1086 #endif
1087
1088 \f
1089 //
1090 // Pointers to various objects.
1091 //
1092 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
1093 PTR(__GDB_stack_base)
1094 PTR(__GDB_stack)
1095 #endif
1096 PTR(__startup_stack)
1097 PTR(__exception_stack)
1098 PTR(__undef_exception_stack)
1099 PTR(__bss_start)
1100 PTR(__bss_end)
1101 PTR(_end)
1102 PTR(__rom_data_start)
1103 PTR(__ram_data_start)
1104 PTR(__ram_data_end)
1105 PTR(hal_interrupt_handlers)
1106 PTR(hal_interrupt_data)
1107 PTR(hal_interrupt_objects)
1108 PTR(__exception_handlers)
1109 PTR(init_flag)
1110 #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
1111 PTR(cyg_scheduler_sched_lock)
1112 #endif
1113 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
1114 PTR(irq_level)
1115 PTR(__interrupt_stack)
1116 #endif
1117 #ifdef  CYGHWR_HAL_ARM_DUMP_EXCEPTIONS
1118 PTR(__dump_procs)
1119 #endif
1120
1121 //
1122 // Identification - useful to find out when a system was configured
1123 _eCos_id:
1124         .asciz  "eCos : " __DATE__
1125
1126 \f
1127 // -------------------------------------------------------------------------
1128 // Interrupt vector tables.
1129 // These tables contain the isr, data and object pointers used to deliver
1130 // interrupts to user code.
1131
1132 // Despite appearances, their sizes are not #defines, but .equ symbols
1133 // generated by magic without proper dependencies in arm.inc
1134 // Recompiling will not DTRT without manual intervention.
1135
1136         .data
1137
1138 init_flag:
1139         .balign 4
1140         .long   0
1141
1142         .extern hal_default_isr
1143
1144         .globl  hal_interrupt_handlers
1145 hal_interrupt_handlers:
1146         .rept   CYGNUM_HAL_ISR_COUNT
1147         .long   hal_default_isr
1148         .endr
1149
1150         .globl  hal_interrupt_data
1151 hal_interrupt_data:
1152         .rept   CYGNUM_HAL_ISR_COUNT
1153         .long   0
1154         .endr
1155
1156         .globl  hal_interrupt_objects
1157 hal_interrupt_objects:
1158         .rept   CYGNUM_HAL_ISR_COUNT
1159         .long   0
1160         .endr
1161
1162 // -------------------------------------------------------------------------
1163 // Temporary interrupt stack
1164
1165         .section ".bss"
1166
1167 // Small stacks, only used for saving information between CPU modes
1168 __exception_stack_base:
1169         .rept   32
1170         .long   0
1171         .endr
1172 __exception_stack:
1173         .rept   32
1174         .long   0
1175         .endr
1176 __undef_exception_stack:
1177
1178 // Runtime stack used during all interrupt processing
1179 #ifndef CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
1180 #define CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE 4096
1181 #endif
1182 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
1183         .balign 16
1184         .global cyg_interrupt_stack_base
1185 cyg_interrupt_stack_base:
1186 __interrupt_stack_base:
1187         .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
1188         .byte 0
1189         .endr
1190         .balign 16
1191         .global cyg_interrupt_stack
1192 cyg_interrupt_stack:
1193 __interrupt_stack:
1194 irq_level:
1195         .long   0
1196 #endif
1197
1198 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
1199         .balign 16
1200 __GDB_stack_base:
1201         .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE // rather than 1k
1202         .byte 0
1203         .endr
1204 __GDB_stack:
1205 #endif
1206         .balign 16
1207 __startup_stack_base:
1208 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
1209         .rept 512
1210 #else
1211         .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
1212 #endif
1213         .byte 0
1214         .endr
1215         .balign 16
1216 __startup_stack:
1217
1218 #ifdef PLATFORM_EXTRAS
1219 #include PLATFORM_EXTRAS
1220 #endif
1221
1222 // --------------------------------------------------------------------------
1223 //  end of vectors.S