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