]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/powerpc/arch/v2_0/src/vectors.S
2cc1d8d77b3cec1cfc4b4b67aec88d190e951298
[karo-tx-redboot.git] / packages / hal / powerpc / arch / v2_0 / src / vectors.S
1 ##==========================================================================
2 ##
3 ##      vectors.S
4 ##
5 ##      PowerPC 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 Red Hat, Inc.
12 ## Copyright (C) 2002 Gary Thomas
13 ##
14 ## eCos is free software; you can redistribute it and/or modify it under
15 ## the terms of the GNU General Public License as published by the Free
16 ## Software Foundation; either version 2 or (at your option) any later version.
17 ##
18 ## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 ## WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 ## FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 ## for more details.
22 ##
23 ## You should have received a copy of the GNU General Public License along
24 ## with eCos; if not, write to the Free Software Foundation, Inc.,
25 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 ##
27 ## As a special exception, if other files instantiate templates or use macros
28 ## or inline functions from this file, or you compile this file and link it
29 ## with other works to produce a work based on this file, this file does not
30 ## by itself cause the resulting work to be covered by the GNU General Public
31 ## License. However the source code for this file must still be made available
32 ## in accordance with section (3) of the GNU General Public License.
33 ##
34 ## This exception does not invalidate any other reasons why a work based on
35 ## this file might be covered by the GNU General Public License.
36 ##
37 ## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 ## at http://sources.redhat.com/ecos/ecos-license/
39 ## -------------------------------------------
40 #####ECOSGPLCOPYRIGHTEND####
41 ##==========================================================================
42 #######DESCRIPTIONBEGIN####
43 ##
44 ## Author(s):    nickg, jskov
45 ## Contributors: nickg, jskov
46 ## Date:         1999-02-20
47 ## Purpose:      PowerPC exception vectors
48 ## Description:  This file defines the code placed into the exception
49 ##               vectors. It also contains the first level default VSRs
50 ##               that save and restore state for both exceptions and
51 ##               interrupts.
52 ##
53 ######DESCRIPTIONEND####
54 ##
55 ##==========================================================================
56
57 #===========================================================================
58 #
59 #       The PowerPC exception handling has changed as of version 1.3.1.
60 #       The primary motivation for rewriting the code was to bring it more
61 #       in line with the other HALs, in particular to allow a RAM application
62 #       to cleanly take over only a subset of vectors from a running ROM
63 #       monitor.
64 #
65 #       GDB stubs (and CygMon, should it be ported to PPC) copies
66 #       exception vector entry handler code to address 0. These vector entry
67 #       handlers (defined by the exception_vector macro below) compute
68 #       a vector index into the hal_vsr_table, fetch the pointer, and
69 #       jump to the HAL vector service routine (VSR).
70 #
71 #       The hal_vsr_table is located immediately after the vector
72 #       handlers (at address 0x3000), allowing RAM applications to
73 #       change VSRs as necessary, while still keeping desired ROM
74 #       monitor functionality available for debugging.
75 #
76 #       ROM applications can still be configured to leave the vector entry
77 #       handlers at 0xff000000, but there is at the moment no
78 #       provision for reclaiming the reserved vector space in RAM to
79 #       application usage.
80 #
81 #       RAM applications can also be configured to provide exception
82 #       handlers which are copied to address 0 on startup, thus taking
83 #       full control of the target.
84 #
85 #
86 #       Default configuration is for RAM applications to rely on an
87 #       existing ROM monitor to provide debugging functionality, and
88 #       for ROM applications to copy vectors to address 0.
89 #
90 #
91 #       Unfortunately the new exception scheme is not compatible with the
92 #       old scheme. Stubs and applications must be compiled using the same
93 #       scheme (i.e., old binaries will not run with new stubs, and new
94 #       binaries will not run with old stubs).
95 #
96 #===========================================================================
97
98 #include <pkgconf/hal.h>
99
100 #ifdef CYGPKG_KERNEL
101 #include <pkgconf/kernel.h>     // CYGPKG_KERNEL_INSTRUMENT
102 #endif
103
104 #define CYGARC_HAL_COMMON_EXPORT_CPU_MACROS
105 #include <cyg/hal/ppc_regs.h>
106
107 #===========================================================================
108                 
109 //        .file   "vectors.S"
110         
111         .extern hal_interrupt_data
112         .extern hal_interrupt_handlers
113         .extern hal_interrupt_objects
114         .extern hal_vsr_table
115
116         .extern cyg_hal_invoke_constructors
117         .extern cyg_instrument
118         .extern cyg_start
119         .extern hal_IRQ_init
120         .extern hal_MMU_init
121         .extern hal_enable_caches
122         .extern hal_hardware_init
123         .extern initialize_stub
124
125         .extern __bss_start
126         .extern __bss_end
127         .extern __sbss_start
128         .extern __sbss_end
129
130 #===========================================================================
131 # MSR initialization value
132 # zero all bits except:
133 # FP = floating point available
134 # ME = machine check enabled
135 # IP = vectors at 0xFFFxxxxx (ROM startup only)
136 # IR = instruction address translation
137 # DR = data address translation
138 # RI = recoverable interrupt
139
140 #define CYG_MSR_COMMON (MSR_FP | MSR_ME | MSR_RI)
141
142 #if (CYGHWR_HAL_POWERPC_VECTOR_BASE == 0xfff00000)
143 # define IP_BIT MSR_IP
144 #else
145 # define IP_BIT 0
146 #endif
147
148 #ifdef CYGHWR_HAL_POWERPC_ENABLE_MMU
149 # define IR_DR_BITS (MSR_IR | MSR_DR)
150 #else
151 # define IR_DR_BITS 0
152 #endif
153
154 #define CYG_MSR (CYG_MSR_COMMON | IP_BIT | IR_DR_BITS)
155
156 # Include variant macros after MSR definition.        
157 #include <cyg/hal/arch.inc>
158 #include <cyg/hal/ppc_offsets.inc>
159
160
161 #===========================================================================
162 # If the following option is enabled, we only save registers up to R12.
163 # The PowerPC ABI defines registers 13..31 as callee saved and thus we do
164 # not need to save them when calling C functions.
165
166 #ifdef CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT
167 # define MAX_SAVE_REG    12
168 #else
169 # define MAX_SAVE_REG    31
170 #endif                  
171         
172
173 #if defined(CYGHWR_HAL_POWERPC_NEED_VECTORS)
174
175 #===========================================================================
176 # Start by defining the exceptions vectors that must be placed at
177 # locations 0xFFF00000 or 0x00000000. The following code will normally
178 # be located at 0xFFF00000 in the ROM. It may optionally be copied out
179 # to 0x00000000 if we want to use the RAM vectors. For this reason this code
180 # MUST BE POSITION INDEPENDENT.
181         
182         .section ".vectors","ax"
183
184 #---------------------------------------------------------------------------
185 # Macros for generating an exception vector service routine
186
187 # Reset vector macro
188
189         .macro  reset_vector name
190         .p2align 8
191         .globl  __exception_\name
192 __exception_\name:
193 #ifdef CYGSEM_HAL_POWERPC_RESET_USES_JUMP        
194         bl      _start               
195 #else
196         lwi     r3,_start
197         mtlr    r3
198         blr
199 #endif                
200
201         .endm
202         
203 # Generic vector macro
204                 
205         .macro  exception_vector name
206         .p2align 8
207         .globl  __exception_\name
208 __exception_\name:
209         mtspr   SPRG1,r3                     # stash some work registers away
210         mtspr   SPRG2,r4                    
211         mtspr   SPRG3,r5                    
212         mfcr    r4                           # stash CR
213         li      r5,__exception_\name-rom_vectors       # load low half of vector addr
214         srwi    r5,r5,6                      # shift right by 6      
215         lwi     r3,hal_vsr_table             # table base
216         lwzx    r3,r3,r5                     # address of vsr
217         mflr    r5                           # save link register
218         mtlr    r3                           # put vsr address into it
219         li      r3,__exception_\name-rom_vectors       # reload low half of vector addr
220         blr                                  # go to common code
221         .endm
222         
223 #---------------------------------------------------------------------------
224 # Define the exception vectors.
225
226 // Some platforms won't let us put the vector code just where we want
227 // This macro introduces some lattitude in vector placement
228                         
229 #ifdef CYG_HAL_FUDGE_VECTOR_ALIGNMENT        
230         hal_fudge_vector_alignment
231 #endif
232                 
233 rom_vectors:
234         # These are the architecture defined vectors that
235         # are always present.
236 #ifdef CYG_HAL_RESERVED_VECTOR_00000
237         hal_reserved_vector_00000                
238 #else                
239         exception_vector        reserved_00000
240 #endif        
241         reset_vector            reset
242         exception_vector        machine_check
243         exception_vector        data_storage
244         exception_vector        instruction_storage
245         exception_vector        external
246         exception_vector        alignment
247         exception_vector        program
248         exception_vector        floatingpoint_unavailable
249         exception_vector        decrementer
250         exception_vector        reserved_00a00
251         exception_vector        reserved_00b00
252         exception_vector        system_call
253         exception_vector        trace
254         exception_vector        floatingpoint_assist
255         exception_vector        reserved_00f00
256
257         # Variants may define extra vectors.
258         hal_extra_vectors
259
260 rom_vectors_end:   
261
262 #else //  CYGHWR_HAL_POWERPC_NEED_VECTORS
263
264         # When vectors are not included this is the primary entry point.
265         .globl  __exception_reset
266 __exception_reset:
267         lwi     r3,_start
268         mtlr    r3
269         blr
270         
271 #endif //  CYGHWR_HAL_POWERPC_NEED_VECTORS
272
273
274
275 #===========================================================================
276 # Real startup code. We jump here from the various reset vectors to set up
277 # the world.
278         
279         .text   
280         .globl  _start
281 _start:
282         # Initialize CPU to a post-reset state, ensuring the ground doesn''t
283         # shift under us while we try to set things up.
284         hal_cpu_init
285
286         # Set up global offset table
287         lwi     r2,_GLOBAL_OFFSET_TABLE_
288
289         # set up time base register to zero
290         xor     r3,r3,r3
291         mtspr   TBL_W,r3
292         xor     r4,r4,r4
293         mtspr   TBU_W,r4
294
295         # Call platform specific hardware initialization
296         # This may include memory controller initialization. It is not
297         # safe to access RAM until after this point.
298         bl      hal_hardware_init       # this is platform dependent
299         .globl  _hal_hardware_init_done
300 _hal_hardware_init_done:
301
302 #if !defined(CYG_HAL_STARTUP_ROM) && defined(CYGSEM_HAL_POWERPC_COPY_VECTORS)
303         lwi     r3,rom_vectors-4
304         lwi     r4,((CYGHWR_HAL_POWERPC_VECTOR_BASE)-4)
305         lwi     r5,rom_vectors_end-4
306 0:      lwzu    r0,4(r3)
307         stwu    r0,4(r4)
308         cmplw   r3,r5
309         bne     0b
310 #endif        
311
312         # set up stack
313         lwi     sp,__interrupt_stack
314         mtspr   SPRG0,sp        # save in sprg0 for later use
315
316         # Set up exception handlers and VSR table, taking care not to
317         # step on any ROM monitor''s toes.
318         hal_mon_init        
319
320 #if defined(CYG_HAL_STARTUP_ROM)
321
322         # Copy data from ROM to ram
323         lwi     r3,__rom_data_start     # r3 = rom start
324         lwi     r4,__ram_data_start     # r4 = ram start
325         lwi     r5,__ram_data_end       # r5 = ram end
326
327         cmplw   r4,r5                   # skip if no data
328         beq     2f
329         
330 1:
331         lwz     r0,0(r3)                # get word from ROM
332         stw     r0,0(r4)                # store in RAM
333         addi    r3,r3,4                 # increment by 1 word
334         addi    r4,r4,4                 # increment by 1 word
335         cmplw   r4,r5                   # compare
336         blt     1b                      # loop if not yet done
337 2:
338 #endif
339
340         # clear BSS
341         lwi     r3,__bss_start  # r3 = start
342         lwi     r4,__bss_end    # r4 = end
343         li      r0,0            # r0 = 0
344         cmplw   r3,r4           # skip if no bss
345         beq     2f
346         
347 1:      stw     r0,0(r3)        # store zero
348         addi    r3,r3,4         # increment by 1 word
349         cmplw   r3,r4           # compare
350         blt     1b              # loop if not yet done
351 2:
352
353         # clear SBSS
354         lwi     r3,__sbss_start # r3 = start
355         lwi     r4,__sbss_end   # r4 = end
356         cmplw   r3,r4           # skip if no sbss
357         beq     2f
358         
359 1:      stw     r0,0(r3)        # store zero
360         addi    r3,r3,4         # increment by 1 word
361         cmplw   r3,r4           # compare
362         blt     1b              # loop if not yet done
363 2:
364
365         # It is now safe to call C functions which may rely on initialized
366         # data.
367         
368         # Set up stack for calls to C code.
369         subi    sp,sp,12                        # make space on stack
370         li      r0,0
371         stw     r0,0(sp)                        # clear back chain
372         stw     r0,8(sp)                        # zero return pc
373         stwu    sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame
374
375         # Variant HALs may need to do something special before we continue
376         bl      hal_variant_init
377
378         # Platform initialization
379         bl      hal_platform_init
380         
381         # MMU and cache are controlled by the same option since caching
382         # on the PPC [typically] does not make sense without the MMU to mark 
383         # regions which should not be cached.
384 #ifdef CYGHWR_HAL_POWERPC_ENABLE_MMU
385         # Initialize MMU.
386         bl      hal_MMU_init
387
388         # Enable MMU (if desired) so we can safely enable caches.
389         lwi     r3,CYG_MSR              # interrupts enabled later
390         sync
391         mtmsr   r3
392         sync
393         
394         # Enable caches
395         bl      hal_enable_caches
396 #endif // CYGHWR_HAL_POWERPC_ENABLE_MMU
397
398         # set up platform specific interrupt environment
399         bl      hal_IRQ_init
400
401         # call c++ constructors
402         bl      cyg_hal_invoke_constructors
403
404 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
405         bl      initialize_stub
406 #endif
407 #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \
408     || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
409         .extern hal_ctrlc_isr_init
410         bl     hal_ctrlc_isr_init
411 #endif
412         
413         bl      cyg_start                       # call cyg_start
414 9:      
415         b       9b              # if we return, loop
416
417 #---------------------------------------------------------------------------
418 # This code handles the common part of all exception handlers.
419 # It saves the machine state onto the stack  and then calls
420 # a "C" routine to do the rest of the work. This work may result
421 # in thread switches, and changes to the saved state. When we return
422 # here the saved state is restored and execution is continued.
423         
424         .text
425
426         .globl cyg_hal_default_exception_vsr
427 cyg_hal_default_exception_vsr:
428         
429         # We come here with all register containing their
430         # pre-exception values except:
431         # R3    = ls 16 bits of vector address
432         # R4    = saved CR
433         # R5    = saved LR
434         # LR    = VSR address
435         # SPRG1 = old R3
436         # SPRG2 = old R4
437         # SPRG3 = old R5
438         # SRR0  = old PC
439         # SRR1  = old MSR and the exception cause (the POW state is lost!)
440
441         subi    sp,sp,CYGARC_PPC_EXCEPTION_DECREMENT
442                                         # leave space for registers and
443                                         # a safety margin
444 #ifdef CYGPKG_HAL_POWERPC_PPC40x
445 // The caches on this processor are always enabled when the MMU is on
446 // (and disabled when off).  Thus we need to be careful about cache
447 // polution and staleness when changing the MMU state.
448 // At this point, the MMU is off due to the exception.  We need to
449 // flush the part of the cache which may be touched before the MMU
450 // is reenabled so that memory will be consistent when that happens.
451 // Of course, this is complicated by the fact that there are no "free"
452 // registers at this point in the code.
453         dcbf    0,sp                    // Flushes first line
454         stw     r3,0(sp)                // This is now safe
455         li      r3,CYGARC_PPCREG_VECTOR // Flush lines which will be changed
456         dcbf    r3,sp                   
457         li      r3,CYGARC_PPCREG_CR
458         dcbf    r3,sp                   
459         li      r3,CYGARC_PPCREG_LR
460         dcbf    r3,sp              
461         lwz     r3,0(sp)                // Restore register
462 #endif        
463
464         # First, save away some registers
465         stw     r3,CYGARC_PPCREG_VECTOR(sp)    # stash vector
466         stw     r4,CYGARC_PPCREG_CR(sp)        # stash CR
467         stw     r5,CYGARC_PPCREG_LR(sp)        # stash LR
468
469 #ifdef CYGDBG_HAL_POWERPC_FRAME_WALLS
470         # Mark this fram as an Exception frame
471         lwi     r3,0xDDDDDDE0
472         stw     r3,CYGARC_PPCREG_WALL_HEAD(sp)
473         lwi     r3,0xDDDDDDE1
474         stw     r3,CYGARC_PPCREG_WALL_TAIL(sp)
475 #endif
476
477         # Enable MMU & interrupt/FPU environment (as configured)
478         lwi     r3,CYG_MSR
479         sync
480         mtmsr   r3
481         sync
482                 
483         mfspr   r3,SPRG1                # save original R3
484         stw     r3,CYGARC_PPCREG_REGS+3*4(sp)
485         mfspr   r4,SPRG2                # save original R4
486         stw     r4,CYGARC_PPCREG_REGS+4*4(sp)
487         mfspr   r5,SPRG3                # save original R5
488         stw     r5,CYGARC_PPCREG_REGS+5*4(sp)
489
490         stw     r0,CYGARC_PPCREG_REGS+0*4(sp)  # save R0
491         stw     r2,CYGARC_PPCREG_REGS+2*4(sp)  # save R2
492         
493         mr      r3,sp                   # recreate original SP
494         addi    r3,r3,CYGARC_PPC_EXCEPTION_DECREMENT
495         stw     r3,CYGARC_PPCREG_REGS+1*4(sp)  # and save it in state
496         
497         # Save registers r6..r12/r31
498         .set    _reg,6
499         .rept   MAX_SAVE_REG+1-6
500         stw     _reg,(CYGARC_PPCREG_REGS+_reg*4)(sp)
501         .set    _reg,_reg+1
502         .endr
503
504         # Save registers used in vsr (r14+r15)
505         stw     r14,(CYGARC_PPCREG_REGS+14*4)(sp)
506         stw     r15,(CYGARC_PPCREG_REGS+15*4)(sp)
507         
508         # get remaining family CPU registers
509         mfxer   r3
510         mfctr   r4
511         mfsrr0  r5
512         mfsrr1  r6
513         # and store them
514         stw     r3,CYGARC_PPCREG_XER(sp)
515         stw     r4,CYGARC_PPCREG_CTR(sp)
516         stw     r5,CYGARC_PPCREG_PC(sp)
517         stw     r6,CYGARC_PPCREG_MSR(sp)
518
519         # Save variant registers
520         hal_variant_save sp
521
522         # Save FPU registers
523         hal_fpu_save sp
524
525         # The entire CPU state is now stashed on the stack,
526         # call into C to do something with it.
527
528         mr      r3,sp                           # R3 = register dump
529         
530         subi    sp,sp,CYGARC_PPC_STACK_FRAME_SIZE # make a null frame
531
532         li      r0,0                            # R0 = 0
533         stw     r0,0(sp)                        # backchain = 0
534         stw     r0,8(sp)                        # return pc = 0
535         
536         stwu    sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame
537                                                 # where C code can save LR
538
539         lwi     r5,restore_state                # get return link
540         mtlr    r5                              # to link register
541
542         .extern cyg_hal_exception_handler
543         b       cyg_hal_exception_handler       # call C code, r3 = registers
544
545         # When the call returns it will go to restore_state below.
546
547
548 ##--------------------------------------------------------------------------
549 ## The following macros are defined depending on whether the Interrupt
550 ## system is using isr tables or chaining, and depending on the interrupt
551 ## controller in the system.
552
553 #ifndef CYGPKG_HAL_POWERPC_INTC_DEFINED
554
555 ## This is the simple version. No interrupt controller, CYGARC_PPCREG_VECTOR 
556 ## is updated with the decoded interrupt vector. Isr tables/chaining
557 ## use same interrupt decoder.
558 ## Bit 21 biffers between decrementer (0) and external (1).
559
560         # decode the interrupt
561         .macro  hal_intc_decode dreg,state
562         lwz     \dreg,CYGARC_PPCREG_VECTOR(\state) # retrieve vector number,
563         rlwinm  \dreg,\dreg,22,31,31               # isolate bit 21 and update
564         stw     \dreg,CYGARC_PPCREG_VECTOR(\state) # vector in state frame.
565         slwi    \dreg,\dreg,2                      # convert to word offset.
566         .endm                              
567
568 #endif // CYGPKG_HAL_POWERPC_INTC_DEFINED
569
570 #---------------------------------------------------------------------------
571 # Common interrupt handling code.
572
573         .globl cyg_hal_default_interrupt_vsr
574 cyg_hal_default_interrupt_vsr:
575
576         # We come here with all register containing their
577         # pre-exception values except:
578         # R3    = ls 16 bits of vector address
579         # R4    = saved CR
580         # R5    = saved LR
581         # LR    = VSR address
582         # SPRG1 = old R3
583         # SPRG2 = old R4
584         # SPRG3 = old R5
585         # SRR0  = old PC
586         # SRR1  = old MSR
587
588
589         subi    sp,sp,CYGARC_PPC_EXCEPTION_DECREMENT
590                                         # leave space for registers and
591                                         # a safety margin
592 #ifdef CYGPKG_HAL_POWERPC_PPC40x
593 // The caches on this processor are always enabled when the MMU is on
594 // (and disabled when off).  Thus we need to be careful about cache
595 // polution and staleness when changing the MMU state.
596 // At this point, the MMU is off due to the exception.  We need to
597 // flush the part of the cache which may be touched before the MMU
598 // is reenabled so that memory will be consistent when that happens.
599 // Of course, this is complicated by the fact that there are no "free"
600 // registers at this point in the code.
601         dcbf    0,sp                    // Flushes first line
602         stw     r3,0(sp)                // This is now safe
603         li      r3,CYGARC_PPCREG_VECTOR // Flush lines which will be changed
604         dcbf    r3,sp                   
605         li      r3,CYGARC_PPCREG_CR
606         dcbf    r3,sp                   
607         li      r3,CYGARC_PPCREG_LR
608         dcbf    r3,sp              
609         lwz     r3,0(sp)                // Restore register
610 #endif        
611               
612         stw     r3,CYGARC_PPCREG_VECTOR(sp)    # stash vector
613         stw     r4,CYGARC_PPCREG_CR(sp)        # stash CR
614         stw     r5,CYGARC_PPCREG_LR(sp)        # stash LR
615
616 #ifdef CYGDBG_HAL_POWERPC_FRAME_WALLS
617         # Mark this fram as an 1nterrupt frame
618         lwi     r3,0xDDDDDD10
619         stw     r3,CYGARC_PPCREG_WALL_HEAD(sp)
620         lwi     r3,0xDDDDDD11
621         stw     r3,CYGARC_PPCREG_WALL_TAIL(sp)
622 #endif
623
624         # Enable MMU & interrupt/FPU environment as configured
625         lwi     r3,CYG_MSR
626         sync
627         mtmsr   r3
628         sync
629
630         mfspr   r3,SPRG1                # save original R3
631         stw     r3,CYGARC_PPCREG_REGS+3*4(sp)
632         mfspr   r4,SPRG2                # save original R4
633         stw     r4,CYGARC_PPCREG_REGS+4*4(sp)
634         mfspr   r5,SPRG3                # save original R5
635         stw     r5,CYGARC_PPCREG_REGS+5*4(sp)
636
637         stw     r0,CYGARC_PPCREG_REGS+0*4(sp)  # save R0
638         stw     r2,CYGARC_PPCREG_REGS+2*4(sp)  # save R2
639
640         mr      r3,sp                   # recreate original SP
641         addi    r3,r3,CYGARC_PPC_EXCEPTION_DECREMENT
642         stw     r3,CYGARC_PPCREG_REGS+1*4(sp)  # and save it in state
643         
644         # Save registers r6..r12/r31
645         .set    _reg,6
646         .rept   MAX_SAVE_REG+1-6
647         stw     _reg,(CYGARC_PPCREG_REGS+_reg*4)(sp)
648         .set    _reg,_reg+1
649         .endr
650
651         # Save registers used in vsr (r14+r15)
652         stw     r14,CYGARC_PPCREG_REGS+14*4(sp)
653         stw     r15,CYGARC_PPCREG_REGS+15*4(sp)
654
655         # get remaining family CPU registers
656         mfxer   r3
657         mfctr   r4
658         mfsrr0  r5
659         mfsrr1  r6
660
661         # and store them
662         stw     r3,CYGARC_PPCREG_XER(sp)
663         stw     r4,CYGARC_PPCREG_CTR(sp)
664         stw     r5,CYGARC_PPCREG_PC(sp)
665         stw     r6,CYGARC_PPCREG_MSR(sp)
666                 
667         # Save variant registers
668         hal_variant_save sp
669
670         # Save FPU registers
671         hal_fpu_save sp
672
673         # The entire CPU state is now stashed on the stack,
674         # increment the scheduler lock and call the ISR
675         # for this vector.
676
677 #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT                 
678         .extern cyg_scheduler_sched_lock
679         lwi     r3,cyg_scheduler_sched_lock
680         lwz     r4,0(r3)
681         addi    r4,r4,1
682         stw     r4,0(r3)
683 #endif
684         
685         mr      r14,sp                          # r14 = register dump
686         
687 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK 
688         lwi     r3,__interrupt_stack            # stack top
689         lwi     r4,__interrupt_stack_base       # stack base
690         sub.    r5,sp,r4                        # sp - base
691         blt     1f                              # if < 0 - not on istack
692         sub.    r5,r3,sp                        # top - sp
693         bgt     2f                              # if > 0 - already on istack
694
695 1:      mr      sp,r3                           # switch to istack
696
697 2:      stwu    r14,-4(sp)                      # save old SP on stack
698
699 #endif
700         
701         subi    sp,sp,CYGARC_PPC_STACK_FRAME_SIZE # make a null frame
702
703         li      r0,0                            # R0 = 0
704         stw     r0,0(sp)                        # backchain = 0
705         stw     r0,8(sp)                        # return pc = 0
706         
707         stwu    sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame
708                                                 # where C code can save LR
709         
710 #if defined(CYGPKG_KERNEL_INSTRUMENT) && defined(CYGDBG_KERNEL_INSTRUMENT_INTR)
711
712         lwi     r3,0x0301                       # r3 = type = INTR,RAISE
713         lwz     r4,CYGARC_PPCREG_VECTOR(r14)    # arg1 = vector address
714         srwi    r4,r4,8                         # arg1 = vector number
715         xor     r5,r5,r5                        # arg2 = 0
716         bl      cyg_instrument                  # call instrument function
717         
718 #endif
719
720         hal_intc_decode r15,r14                # get table index
721
722 #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \
723     || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
724         # If we are supporting Ctrl-C interrupts from GDB, we must squirrel
725         # away a pointer to the save interrupt state here so that we can
726         # plant a breakpoint at some later time.
727         
728         .extern hal_saved_interrupt_state
729         lwi     r3,hal_saved_interrupt_state
730         stw     r14,0(r3)
731         
732 #endif
733
734 #ifdef CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING
735
736 #ifdef CYGPKG_HAL_POWERPC_MPC8xx
737         # The CPM controller allows nested interrupts. However,
738         # it sits on the back of the SIU controller which has no
739         # HW support for this. In effect, SW masking of lower
740         # priority IRQs in the SIU would be required for this to work.
741 #endif
742
743 #endif
744
745         lwz     r3,CYGARC_PPCREG_VECTOR(r14)    # retrieve decoded vector #
746
747         lwi     r6,hal_interrupt_handlers       # get interrupt handler table
748         lwzx    r6,r6,r15                       # load routine pointer
749
750         lwi     r4,hal_interrupt_data           # get interrupt data table
751         lwzx    r4,r4,r15                       # load data pointer
752                                                 # R4 = data argument
753         mr      r5,r14                          # R5 = saved registers        
754         
755         mtctr   r6                              # put isr address in ctr
756
757         bctrl                                   # branch to ctr reg and link
758
759 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
760
761         # If we are returning from the last nested interrupt, move back
762         # to the thread stack. interrupt_end() must be called on the
763         # thread stack since it potentially causes a context switch.
764         # Since we have arranged for the top of stack location to
765         # contain the sp we need to go back to here, just pop it off
766         # and put it in SP.
767
768         
769         lwz     sp,CYGARC_PPC_STACK_FRAME_SIZE*2(sp) # sp = *sp
770
771         subi    sp,sp,CYGARC_PPC_STACK_FRAME_SIZE # make a null frame
772
773         li      r0,0                            # R0 = 0
774         stw     r0,0(sp)                        # backchain = 0
775         stw     r0,8(sp)                        # return pc = 0
776         
777         stwu    sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame
778                                                 # where C code can save LR
779 #endif  
780
781         # On return r3 bit 1 will indicate whether a DSR is
782         # to be posted. Pass this together with a pointer to
783         # the interrupt object we have just used to the
784         # interrupt tidy up routine.
785
786         # Note that r14 and r15 are defined to be preserved across
787         # calls by the calling convention, so they still contain
788         # the register dump and the vector number respectively.
789
790         lwi     r4,hal_interrupt_objects        # get interrupt object table
791         lwzx    r4,r4,r15                       # load object pointer
792         mr      r5,r14                          # arg3 = saved register dump
793
794         .extern interrupt_end
795         bl      interrupt_end                   # call into C to finish off 
796
797 restore_state:  
798         # All done, restore CPU state and continue
799
800         # retrieve CPU state pointer
801         addi    sp,sp,CYGARC_PPC_STACK_FRAME_SIZE*2
802
803         # Restore FPU registers
804         hal_fpu_load sp
805
806         # Restore variant registers
807         hal_variant_load sp
808
809         # get sprs we want to restore
810         # stuff some of them into the CPU
811         lwz     r3,CYGARC_PPCREG_XER(sp)
812         lwz     r4,CYGARC_PPCREG_LR(sp)
813         lwz     r5,CYGARC_PPCREG_CTR(sp)
814         mtxer   r3
815         mtlr    r4
816         mtctr   r5
817
818         # Restore registers used in vsr (r14+r15)
819         lwz     r14,CYGARC_PPCREG_REGS+14*4(r1)
820         lwz     r15,CYGARC_PPCREG_REGS+15*4(r1)
821
822         # restore registers r6..r12/r31
823         .set    _reg,6
824         .rept   MAX_SAVE_REG+1-6
825         lwz     _reg,(CYGARC_PPCREG_REGS+_reg*4)(sp)
826         .set    _reg,_reg+1
827         .endr
828
829         hal_cpu_int_disable
830         
831         # restore R0 and R2
832         lwz     r0,CYGARC_PPCREG_REGS+0*4(sp)
833         lwz     r2,CYGARC_PPCREG_REGS+2*4(sp)
834
835         # Here all the registers are loaded except
836         # sp = HAL_SavedRegisters
837         # r3 = ccr
838         # r4 = srr0 = pc
839         # r5 = srr1 = msr
840         #
841         # We have to disable interrupts while srr0 and
842         # srr1 are loaded, since another interrupt will
843         # destroy them.
844
845         lwz     r3,CYGARC_PPCREG_CR(sp)
846         lwz     r4,CYGARC_PPCREG_PC(sp)
847         lwz     r5,CYGARC_PPCREG_MSR(sp)
848         mtcr    r3                      # set ccr
849         mtsrr0  r4                      # load old pc
850         mtsrr1  r5                      # load old msr
851         
852 #ifdef CYGDBG_HAL_POWERPC_FRAME_WALLS
853         # Mark this frame as (almost) dead.
854         lwi     r3,0xDDDDDDD0
855         stw     r3,CYGARC_PPCREG_WALL_HEAD(sp)
856         lwi     r3,0xDDDDDDD1
857         stw     r3,CYGARC_PPCREG_WALL_TAIL(sp)
858 #endif
859
860         lwz     r3,CYGARC_PPCREG_REGS+3*4(sp)  # load r3 value
861         lwz     r4,CYGARC_PPCREG_REGS+4*4(sp)  # load r4 value
862         lwz     r5,CYGARC_PPCREG_REGS+5*4(sp)  # load r5 value
863         lwz     sp,CYGARC_PPCREG_REGS+1*4(sp)  # restore sp
864                 
865         sync                            # settle things down
866         isync   
867         rfi                             # and return
868
869
870
871 ##-----------------------------------------------------------------------------
872 ## Execute pending DSRs on the interrupt stack with interrupts enabled.
873 ## Note: this can only be called from code running on a thread stack
874
875 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
876         .extern cyg_interrupt_call_pending_DSRs
877
878 FUNC_START(hal_interrupt_stack_call_pending_DSRs)
879         # Change to interrupt stack, save state and set up stack for
880         # calls to C code.
881         mr      r3,sp
882         lwi     r4,__interrupt_stack
883         subi    r4,r4,24                        # make space on stack
884         mr      sp,r4
885         stw     r3,12(sp)                       # save old sp
886         mfmsr   r3
887         stw     r3,16(sp)                       # save old MSR
888         mflr    r3
889         stw     r3,20(sp)                       # save old LR
890
891         li      r0,0
892         stw     r0,0(sp)                        # clear back chain
893         stw     r0,8(sp)                        # zero return pc
894
895         hal_cpu_int_enable
896
897         # Call into kernel which will execute DSRs
898         stwu    sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp)
899         bl      cyg_interrupt_call_pending_DSRs
900         addi    sp,sp,CYGARC_PPC_STACK_FRAME_SIZE
901
902         lwz     r3,20(sp)                       # restore LR
903         mtlr    r3
904         lwz     r5,12(sp)                       # get SP from saved state
905         lwz     r3,16(sp)                       # restore interrupt setting
906         hal_cpu_int_merge r3
907
908         mr      sp,r5                           # restore stack pointer
909         blr                                     # and return to caller
910 #endif          
911
912 #---------------------------------------------------------------------------
913 ## Temporary interrupt stack
914         
915         .section ".bss"
916
917         .balign 16
918         .global cyg_interrupt_stack_base
919 cyg_interrupt_stack_base:
920 __interrupt_stack_base:
921         .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
922         .byte 0
923         .endr
924         .balign 16
925         .global cyg_interrupt_stack
926 cyg_interrupt_stack:
927 __interrupt_stack:
928         
929         .long   0,0,0,0,0,0,0,0 
930
931 #---------------------------------------------------------------------------
932 # end of vectors.S