]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/powerpc/arch/v2_0/src/vectors.S
unified MX27, MX25, MX37 trees
[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         sub     r5,r5,r3                # compute number of words to copy
307         srwi    r5,r5,2
308         mtctr   r5
309 0:      lwzu    r0,4(r3)
310         stwu    r0,4(r4)
311         bdnz    0b
312 #endif        
313
314         # set up stack
315         lwi     sp,__interrupt_stack
316         mtspr   SPRG0,sp        # save in sprg0 for later use
317
318         # Set up exception handlers and VSR table, taking care not to
319         # step on any ROM monitor''s toes.
320         hal_mon_init        
321
322 #if defined(CYG_HAL_STARTUP_ROM)
323         # Copy data from ROM to ram
324         lwi     r3,__rom_data_start     # r3 = rom start
325         lwi     r4,__ram_data_start     # r4 = ram start
326         lwi     r5,__ram_data_end       # r5 = ram end
327
328         cmplw   r4,r5                   # skip if no data
329         beq     2f
330         sub     r5,r5,r4                # compute number of words to copy
331         srwi    r5,r5,2
332         mtctr   r5
333         subi    r3,r3,4
334         subi    r4,r4,4
335 1:      lwzu    r0,4(r3)                # get word from ROM
336         stwu    r0,4(r4)                # store in RAM
337         bdnz    1b
338 2:
339 #endif
340
341         # clear BSS
342         lwi     r3,__bss_start  # r3 = start
343         lwi     r4,__bss_end    # r4 = end
344         li      r0,0            # r0 = 0
345         cmplw   r3,r4           # skip if no bss
346         beq     2f
347         sub     r4,r4,r3        # compute number of words to clear
348         srwi    r4,r4,2
349         mtctr   r4
350         subi    r3,r3,4
351         
352 1:      stwu    r0,4(r3)        # store zero & increment pointer
353         bdnz    1b
354 2:
355
356         # clear SBSS
357         lwi     r3,__sbss_start # r3 = start
358         lwi     r4,__sbss_end   # r4 = end
359         cmplw   r3,r4           # skip if no sbss
360         beq     2f
361         sub     r4,r4,r3        # compute number of words to clear
362         srwi    r4,r4,2
363         mtctr   r4
364         subi    r3,r3,4
365         
366 1:      stwu    r0,4(r3)        # store zero & increment pointer
367         bdnz    1b
368 2:
369
370         # It is now safe to call C functions which may rely on initialized
371         # data.
372         
373         # Set up stack for calls to C code.
374         subi    sp,sp,12                        # make space on stack
375         li      r0,0
376         stw     r0,0(sp)                        # clear back chain
377         stw     r0,8(sp)                        # zero return pc
378         stwu    sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame
379
380         # Variant HALs may need to do something special before we continue
381         bl      hal_variant_init
382
383         # Platform initialization
384         bl      hal_platform_init
385         
386         # MMU and cache are controlled by the same option since caching
387         # on the PPC [typically] does not make sense without the MMU to mark 
388         # regions which should not be cached.
389 #ifdef CYGHWR_HAL_POWERPC_ENABLE_MMU
390         # Initialize MMU.
391         bl      hal_MMU_init
392
393         # Enable MMU (if desired) so we can safely enable caches.
394         lwi     r3,CYG_MSR              # interrupts enabled later
395         sync
396         mtmsr   r3
397         sync
398         
399         # Enable caches
400         bl      hal_enable_caches
401 #endif // CYGHWR_HAL_POWERPC_ENABLE_MMU
402
403         # set up platform specific interrupt environment
404         bl      hal_IRQ_init
405
406         # call c++ constructors
407         bl      cyg_hal_invoke_constructors
408
409 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
410         bl      initialize_stub
411 #endif
412 #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \
413     || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
414         .extern hal_ctrlc_isr_init
415         bl     hal_ctrlc_isr_init
416 #endif
417         
418         bl      cyg_start                       # call cyg_start
419 9:      
420         b       9b              # if we return, loop
421
422 #---------------------------------------------------------------------------
423 # This code handles the common part of all exception handlers.
424 # It saves the machine state onto the stack  and then calls
425 # a "C" routine to do the rest of the work. This work may result
426 # in thread switches, and changes to the saved state. When we return
427 # here the saved state is restored and execution is continued.
428         
429         .text
430
431         .globl cyg_hal_default_exception_vsr
432 cyg_hal_default_exception_vsr:
433         
434         # We come here with all register containing their
435         # pre-exception values except:
436         # R3    = ls 16 bits of vector address
437         # R4    = saved CR
438         # R5    = saved LR
439         # LR    = VSR address
440         # SPRG1 = old R3
441         # SPRG2 = old R4
442         # SPRG3 = old R5
443         # SRR0  = old PC
444         # SRR1  = old MSR and the exception cause (the POW state is lost!)
445
446         subi    sp,sp,CYGARC_PPC_EXCEPTION_DECREMENT
447                                         # leave space for registers and
448                                         # a safety margin
449 #ifdef CYGPKG_HAL_POWERPC_PPC40x
450 // The caches on this processor are always enabled when the MMU is on
451 // (and disabled when off).  Thus we need to be careful about cache
452 // polution and staleness when changing the MMU state.
453 // At this point, the MMU is off due to the exception.  We need to
454 // flush the part of the cache which may be touched before the MMU
455 // is reenabled so that memory will be consistent when that happens.
456 // Of course, this is complicated by the fact that there are no "free"
457 // registers at this point in the code.
458         dcbf    0,sp                    // Flushes first line
459         stw     r3,0(sp)                // This is now safe
460         li      r3,CYGARC_PPCREG_VECTOR // Flush lines which will be changed
461         dcbf    r3,sp                   
462         li      r3,CYGARC_PPCREG_CR
463         dcbf    r3,sp                   
464         li      r3,CYGARC_PPCREG_LR
465         dcbf    r3,sp              
466         lwz     r3,0(sp)                // Restore register
467 #endif        
468
469         # First, save away some registers
470         stw     r3,CYGARC_PPCREG_VECTOR(sp)    # stash vector
471         stw     r4,CYGARC_PPCREG_CR(sp)        # stash CR
472         stw     r5,CYGARC_PPCREG_LR(sp)        # stash LR
473
474 #ifdef CYGDBG_HAL_POWERPC_FRAME_WALLS
475         # Mark this fram as an Exception frame
476         lwi     r3,0xDDDDDDE0
477         stw     r3,CYGARC_PPCREG_WALL_HEAD(sp)
478         lwi     r3,0xDDDDDDE1
479         stw     r3,CYGARC_PPCREG_WALL_TAIL(sp)
480 #endif
481
482         # Enable MMU & interrupt/FPU environment (as configured)
483         lwi     r3,CYG_MSR
484         sync
485         mtmsr   r3
486         sync
487                 
488         mfspr   r3,SPRG1                # save original R3
489         stw     r3,CYGARC_PPCREG_REGS+3*4(sp)
490         mfspr   r4,SPRG2                # save original R4
491         stw     r4,CYGARC_PPCREG_REGS+4*4(sp)
492         mfspr   r5,SPRG3                # save original R5
493         stw     r5,CYGARC_PPCREG_REGS+5*4(sp)
494
495         stw     r0,CYGARC_PPCREG_REGS+0*4(sp)  # save R0
496         stw     r2,CYGARC_PPCREG_REGS+2*4(sp)  # save R2
497         
498         mr      r3,sp                   # recreate original SP
499         addi    r3,r3,CYGARC_PPC_EXCEPTION_DECREMENT
500         stw     r3,CYGARC_PPCREG_REGS+1*4(sp)  # and save it in state
501         
502         # Save registers r6..r12/r31
503         .set    _reg,6
504         .rept   MAX_SAVE_REG+1-6
505         stw     _reg,(CYGARC_PPCREG_REGS+_reg*4)(sp)
506         .set    _reg,_reg+1
507         .endr
508
509         # Save registers used in vsr (r14+r15)
510         stw     r14,(CYGARC_PPCREG_REGS+14*4)(sp)
511         stw     r15,(CYGARC_PPCREG_REGS+15*4)(sp)
512         
513         # get remaining family CPU registers
514         mfxer   r3
515         mfctr   r4
516         mfsrr0  r5
517         mfsrr1  r6
518         # and store them
519         stw     r3,CYGARC_PPCREG_XER(sp)
520         stw     r4,CYGARC_PPCREG_CTR(sp)
521         stw     r5,CYGARC_PPCREG_PC(sp)
522         stw     r6,CYGARC_PPCREG_MSR(sp)
523
524         # Save variant registers
525         hal_variant_save sp
526
527         # Save FPU registers
528         hal_fpu_save sp
529
530         # The entire CPU state is now stashed on the stack,
531         # call into C to do something with it.
532
533         mr      r3,sp                           # R3 = register dump
534         
535         subi    sp,sp,CYGARC_PPC_STACK_FRAME_SIZE # make a null frame
536
537         li      r0,0                            # R0 = 0
538         stw     r0,0(sp)                        # backchain = 0
539         stw     r0,8(sp)                        # return pc = 0
540         
541         stwu    sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame
542                                                 # where C code can save LR
543
544         lwi     r5,restore_state                # get return link
545         mtlr    r5                              # to link register
546
547         .extern cyg_hal_exception_handler
548         b       cyg_hal_exception_handler       # call C code, r3 = registers
549
550         # When the call returns it will go to restore_state below.
551
552
553 ##--------------------------------------------------------------------------
554 ## The following macros are defined depending on whether the Interrupt
555 ## system is using isr tables or chaining, and depending on the interrupt
556 ## controller in the system.
557
558 #ifndef CYGPKG_HAL_POWERPC_INTC_DEFINED
559
560 ## This is the simple version. No interrupt controller, CYGARC_PPCREG_VECTOR 
561 ## is updated with the decoded interrupt vector. Isr tables/chaining
562 ## use same interrupt decoder.
563 ## Bit 21 biffers between decrementer (0) and external (1).
564
565         # decode the interrupt
566         .macro  hal_intc_decode dreg,state
567         lwz     \dreg,CYGARC_PPCREG_VECTOR(\state) # retrieve vector number,
568         rlwinm  \dreg,\dreg,22,31,31               # isolate bit 21 and update
569         stw     \dreg,CYGARC_PPCREG_VECTOR(\state) # vector in state frame.
570         slwi    \dreg,\dreg,2                      # convert to word offset.
571         .endm                              
572
573 #endif // CYGPKG_HAL_POWERPC_INTC_DEFINED
574
575 #---------------------------------------------------------------------------
576 # Common interrupt handling code.
577
578         .globl cyg_hal_default_interrupt_vsr
579 cyg_hal_default_interrupt_vsr:
580
581         # We come here with all register containing their
582         # pre-exception values except:
583         # R3    = ls 16 bits of vector address
584         # R4    = saved CR
585         # R5    = saved LR
586         # LR    = VSR address
587         # SPRG1 = old R3
588         # SPRG2 = old R4
589         # SPRG3 = old R5
590         # SRR0  = old PC
591         # SRR1  = old MSR
592
593
594         subi    sp,sp,CYGARC_PPC_EXCEPTION_DECREMENT
595                                         # leave space for registers and
596                                         # a safety margin
597 #ifdef CYGPKG_HAL_POWERPC_PPC40x
598 // The caches on this processor are always enabled when the MMU is on
599 // (and disabled when off).  Thus we need to be careful about cache
600 // polution and staleness when changing the MMU state.
601 // At this point, the MMU is off due to the exception.  We need to
602 // flush the part of the cache which may be touched before the MMU
603 // is reenabled so that memory will be consistent when that happens.
604 // Of course, this is complicated by the fact that there are no "free"
605 // registers at this point in the code.
606         dcbf    0,sp                    // Flushes first line
607         stw     r3,0(sp)                // This is now safe
608         li      r3,CYGARC_PPCREG_VECTOR // Flush lines which will be changed
609         dcbf    r3,sp                   
610         li      r3,CYGARC_PPCREG_CR
611         dcbf    r3,sp                   
612         li      r3,CYGARC_PPCREG_LR
613         dcbf    r3,sp              
614         lwz     r3,0(sp)                // Restore register
615 #endif        
616               
617         stw     r3,CYGARC_PPCREG_VECTOR(sp)    # stash vector
618         stw     r4,CYGARC_PPCREG_CR(sp)        # stash CR
619         stw     r5,CYGARC_PPCREG_LR(sp)        # stash LR
620
621 #ifdef CYGDBG_HAL_POWERPC_FRAME_WALLS
622         # Mark this fram as an 1nterrupt frame
623         lwi     r3,0xDDDDDD10
624         stw     r3,CYGARC_PPCREG_WALL_HEAD(sp)
625         lwi     r3,0xDDDDDD11
626         stw     r3,CYGARC_PPCREG_WALL_TAIL(sp)
627 #endif
628
629         # Enable MMU & interrupt/FPU environment as configured
630         lwi     r3,CYG_MSR
631         sync
632         mtmsr   r3
633         sync
634
635         mfspr   r3,SPRG1                # save original R3
636         stw     r3,CYGARC_PPCREG_REGS+3*4(sp)
637         mfspr   r4,SPRG2                # save original R4
638         stw     r4,CYGARC_PPCREG_REGS+4*4(sp)
639         mfspr   r5,SPRG3                # save original R5
640         stw     r5,CYGARC_PPCREG_REGS+5*4(sp)
641
642         stw     r0,CYGARC_PPCREG_REGS+0*4(sp)  # save R0
643         stw     r2,CYGARC_PPCREG_REGS+2*4(sp)  # save R2
644
645         mr      r3,sp                   # recreate original SP
646         addi    r3,r3,CYGARC_PPC_EXCEPTION_DECREMENT
647         stw     r3,CYGARC_PPCREG_REGS+1*4(sp)  # and save it in state
648         
649         # Save registers r6..r12/r31
650         .set    _reg,6
651         .rept   MAX_SAVE_REG+1-6
652         stw     _reg,(CYGARC_PPCREG_REGS+_reg*4)(sp)
653         .set    _reg,_reg+1
654         .endr
655
656         # Save registers used in vsr (r14+r15)
657         stw     r14,CYGARC_PPCREG_REGS+14*4(sp)
658         stw     r15,CYGARC_PPCREG_REGS+15*4(sp)
659
660         # get remaining family CPU registers
661         mfxer   r3
662         mfctr   r4
663         mfsrr0  r5
664         mfsrr1  r6
665
666         # and store them
667         stw     r3,CYGARC_PPCREG_XER(sp)
668         stw     r4,CYGARC_PPCREG_CTR(sp)
669         stw     r5,CYGARC_PPCREG_PC(sp)
670         stw     r6,CYGARC_PPCREG_MSR(sp)
671                 
672         # Save variant registers
673         hal_variant_save sp
674
675         # Save FPU registers
676         hal_fpu_save sp
677
678         # The entire CPU state is now stashed on the stack,
679         # increment the scheduler lock and call the ISR
680         # for this vector.
681
682 #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT                 
683         .extern cyg_scheduler_sched_lock
684         lwi     r3,cyg_scheduler_sched_lock
685         lwz     r4,0(r3)
686         addi    r4,r4,1
687         stw     r4,0(r3)
688 #endif
689         
690         mr      r14,sp                          # r14 = register dump
691         
692 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK 
693         lwi     r3,__interrupt_stack            # stack top
694         lwi     r4,__interrupt_stack_base       # stack base
695         sub.    r5,sp,r4                        # sp - base
696         blt     1f                              # if < 0 - not on istack
697         sub.    r5,r3,sp                        # top - sp
698         bgt     2f                              # if > 0 - already on istack
699
700 1:      mr      sp,r3                           # switch to istack
701
702 2:      stwu    r14,-4(sp)                      # save old SP on stack
703
704 #endif
705         
706         subi    sp,sp,CYGARC_PPC_STACK_FRAME_SIZE # make a null frame
707
708         li      r0,0                            # R0 = 0
709         stw     r0,0(sp)                        # backchain = 0
710         stw     r0,8(sp)                        # return pc = 0
711         
712         stwu    sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame
713                                                 # where C code can save LR
714         
715 #if defined(CYGPKG_KERNEL_INSTRUMENT) && defined(CYGDBG_KERNEL_INSTRUMENT_INTR)
716
717         lwi     r3,0x0301                       # r3 = type = INTR,RAISE
718         lwz     r4,CYGARC_PPCREG_VECTOR(r14)    # arg1 = vector address
719         srwi    r4,r4,8                         # arg1 = vector number
720         xor     r5,r5,r5                        # arg2 = 0
721         bl      cyg_instrument                  # call instrument function
722         
723 #endif
724
725         hal_intc_decode r15,r14                # get table index
726
727 #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \
728     || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
729         # If we are supporting Ctrl-C interrupts from GDB, we must squirrel
730         # away a pointer to the save interrupt state here so that we can
731         # plant a breakpoint at some later time.
732         
733         .extern hal_saved_interrupt_state
734         lwi     r3,hal_saved_interrupt_state
735         stw     r14,0(r3)
736         
737 #endif
738
739 #ifdef CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING
740
741 #ifdef CYGPKG_HAL_POWERPC_MPC8xx
742         # The CPM controller allows nested interrupts. However,
743         # it sits on the back of the SIU controller which has no
744         # HW support for this. In effect, SW masking of lower
745         # priority IRQs in the SIU would be required for this to work.
746 #endif
747
748 #endif
749
750         lwz     r3,CYGARC_PPCREG_VECTOR(r14)    # retrieve decoded vector #
751
752         lwi     r6,hal_interrupt_handlers       # get interrupt handler table
753         lwzx    r6,r6,r15                       # load routine pointer
754
755         lwi     r4,hal_interrupt_data           # get interrupt data table
756         lwzx    r4,r4,r15                       # load data pointer
757                                                 # R4 = data argument
758         mr      r5,r14                          # R5 = saved registers        
759         
760         mtctr   r6                              # put isr address in ctr
761
762         bctrl                                   # branch to ctr reg and link
763
764 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
765
766         # If we are returning from the last nested interrupt, move back
767         # to the thread stack. interrupt_end() must be called on the
768         # thread stack since it potentially causes a context switch.
769         # Since we have arranged for the top of stack location to
770         # contain the sp we need to go back to here, just pop it off
771         # and put it in SP.
772
773         
774         lwz     sp,CYGARC_PPC_STACK_FRAME_SIZE*2(sp) # sp = *sp
775
776         subi    sp,sp,CYGARC_PPC_STACK_FRAME_SIZE # make a null frame
777
778         li      r0,0                            # R0 = 0
779         stw     r0,0(sp)                        # backchain = 0
780         stw     r0,8(sp)                        # return pc = 0
781         
782         stwu    sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame
783                                                 # where C code can save LR
784 #endif  
785
786         # On return r3 bit 1 will indicate whether a DSR is
787         # to be posted. Pass this together with a pointer to
788         # the interrupt object we have just used to the
789         # interrupt tidy up routine.
790
791         # Note that r14 and r15 are defined to be preserved across
792         # calls by the calling convention, so they still contain
793         # the register dump and the vector number respectively.
794
795         lwi     r4,hal_interrupt_objects        # get interrupt object table
796         lwzx    r4,r4,r15                       # load object pointer
797         mr      r5,r14                          # arg3 = saved register dump
798
799         .extern interrupt_end
800         bl      interrupt_end                   # call into C to finish off 
801
802 restore_state:  
803         # All done, restore CPU state and continue
804
805         # retrieve CPU state pointer
806         addi    sp,sp,CYGARC_PPC_STACK_FRAME_SIZE*2
807
808         # Restore FPU registers
809         hal_fpu_load sp
810
811         # Restore variant registers
812         hal_variant_load sp
813
814         # get sprs we want to restore
815         # stuff some of them into the CPU
816         lwz     r3,CYGARC_PPCREG_XER(sp)
817         lwz     r4,CYGARC_PPCREG_LR(sp)
818         lwz     r5,CYGARC_PPCREG_CTR(sp)
819         mtxer   r3
820         mtlr    r4
821         mtctr   r5
822
823         # Restore registers used in vsr (r14+r15)
824         lwz     r14,CYGARC_PPCREG_REGS+14*4(r1)
825         lwz     r15,CYGARC_PPCREG_REGS+15*4(r1)
826
827         # restore registers r6..r12/r31
828         .set    _reg,6
829         .rept   MAX_SAVE_REG+1-6
830         lwz     _reg,(CYGARC_PPCREG_REGS+_reg*4)(sp)
831         .set    _reg,_reg+1
832         .endr
833
834         hal_cpu_int_disable
835         
836         # restore R0 and R2
837         lwz     r0,CYGARC_PPCREG_REGS+0*4(sp)
838         lwz     r2,CYGARC_PPCREG_REGS+2*4(sp)
839
840         # Here all the registers are loaded except
841         # sp = HAL_SavedRegisters
842         # r3 = ccr
843         # r4 = srr0 = pc
844         # r5 = srr1 = msr
845         #
846         # We have to disable interrupts while srr0 and
847         # srr1 are loaded, since another interrupt will
848         # destroy them.
849
850         lwz     r3,CYGARC_PPCREG_CR(sp)
851         lwz     r4,CYGARC_PPCREG_PC(sp)
852         lwz     r5,CYGARC_PPCREG_MSR(sp)
853         mtcr    r3                      # set ccr
854         mtsrr0  r4                      # load old pc
855         mtsrr1  r5                      # load old msr
856         
857 #ifdef CYGDBG_HAL_POWERPC_FRAME_WALLS
858         # Mark this frame as (almost) dead.
859         lwi     r3,0xDDDDDDD0
860         stw     r3,CYGARC_PPCREG_WALL_HEAD(sp)
861         lwi     r3,0xDDDDDDD1
862         stw     r3,CYGARC_PPCREG_WALL_TAIL(sp)
863 #endif
864
865         lwz     r3,CYGARC_PPCREG_REGS+3*4(sp)  # load r3 value
866         lwz     r4,CYGARC_PPCREG_REGS+4*4(sp)  # load r4 value
867         lwz     r5,CYGARC_PPCREG_REGS+5*4(sp)  # load r5 value
868         lwz     sp,CYGARC_PPCREG_REGS+1*4(sp)  # restore sp
869                 
870         sync                            # settle things down
871         isync   
872         rfi                             # and return
873
874
875
876 ##-----------------------------------------------------------------------------
877 ## Execute pending DSRs on the interrupt stack with interrupts enabled.
878 ## Note: this can only be called from code running on a thread stack
879
880 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
881         .extern cyg_interrupt_call_pending_DSRs
882
883 FUNC_START(hal_interrupt_stack_call_pending_DSRs)
884         # Change to interrupt stack, save state and set up stack for
885         # calls to C code.
886         mr      r3,sp
887         lwi     r4,__interrupt_stack
888         subi    r4,r4,24                        # make space on stack
889         mr      sp,r4
890         stw     r3,12(sp)                       # save old sp
891         mfmsr   r3
892         stw     r3,16(sp)                       # save old MSR
893         mflr    r3
894         stw     r3,20(sp)                       # save old LR
895
896         li      r0,0
897         stw     r0,0(sp)                        # clear back chain
898         stw     r0,8(sp)                        # zero return pc
899
900         hal_cpu_int_enable
901
902         # Call into kernel which will execute DSRs
903         stwu    sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp)
904         bl      cyg_interrupt_call_pending_DSRs
905         addi    sp,sp,CYGARC_PPC_STACK_FRAME_SIZE
906
907         lwz     r3,20(sp)                       # restore LR
908         mtlr    r3
909         lwz     r5,12(sp)                       # get SP from saved state
910         lwz     r3,16(sp)                       # restore interrupt setting
911         hal_cpu_int_merge r3
912
913         mr      sp,r5                           # restore stack pointer
914         blr                                     # and return to caller
915 #endif          
916
917 #---------------------------------------------------------------------------
918 ## Temporary interrupt stack
919         
920         .section ".bss"
921
922         .balign 16
923         .global cyg_interrupt_stack_base
924 cyg_interrupt_stack_base:
925 __interrupt_stack_base:
926         .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE
927         .byte 0
928         .endr
929         .balign 16
930         .global cyg_interrupt_stack
931 cyg_interrupt_stack:
932 __interrupt_stack:
933         
934         .long   0,0,0,0,0,0,0,0 
935
936 #---------------------------------------------------------------------------
937 # end of vectors.S