|
2
|
1 ##========================================================================== |
|
0
|
2 ## |
|
|
3 ## vectors.S |
|
|
4 ## |
|
|
5 ## PowerPC exception vectors |
|
|
6 ## |
|
2
|
7 ##========================================================================== |
|
0
|
8 #####COPYRIGHTBEGIN#### |
|
|
9 # |
|
|
10 # ------------------------------------------- |
|
|
11 # The contents of this file are subject to the Cygnus eCos Public License |
|
|
12 # Version 1.0 (the "License"); you may not use this file except in |
|
|
13 # compliance with the License. You may obtain a copy of the License at |
|
|
14 # http://sourceware.cygnus.com/ecos |
|
|
15 # |
|
|
16 # Software distributed under the License is distributed on an "AS IS" |
|
|
17 # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
|
18 # License for the specific language governing rights and limitations under |
|
|
19 # the License. |
|
|
20 # |
|
|
21 # The Original Code is eCos - Embedded Cygnus Operating System, released |
|
|
22 # September 30, 1998. |
|
|
23 # |
|
|
24 # The Initial Developer of the Original Code is Cygnus. Portions created |
|
2
|
25 # by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. |
|
0
|
26 # ------------------------------------------- |
|
|
27 # |
|
|
28 #####COPYRIGHTEND#### |
|
2
|
29 ##========================================================================== |
|
0
|
30 #######DESCRIPTIONBEGIN#### |
|
|
31 ## |
|
2
|
32 ## Author(s): nickg, jskov |
|
|
33 ## Contributors: nickg, jskov |
|
|
34 ## Date: 1999-02-20 |
|
|
35 ## Purpose: PowerPC exception vectors |
|
|
36 ## Description: This file defines the code placed into the exception |
|
|
37 ## vectors. It also contains the first level default VSRs |
|
|
38 ## that save and restore state for both exceptions and |
|
|
39 ## interrupts. |
|
0
|
40 ## |
|
|
41 ######DESCRIPTIONEND#### |
|
|
42 ## |
|
2
|
43 ##========================================================================== |
|
0
|
44 |
|
|
45 #include <pkgconf/hal.h> |
|
|
46 |
|
|
47 #ifdef CYGPKG_KERNEL |
|
|
48 #include <pkgconf/kernel.h> // CYGPKG_KERNEL_INSTRUMENT |
|
|
49 #endif |
|
2
|
50 |
|
|
51 #define CYGARC_HAL_COMMON_EXPORT_CPU_MACROS |
|
|
52 #include "cyg/hal/ppc_regs.h" |
|
0
|
53 #include "cyg/hal/ppc.inc" |
|
|
54 |
|
|
55 #define FUNC_START(name) \ |
|
|
56 .type name,@function; \ |
|
|
57 .globl name; \ |
|
|
58 name: |
|
|
59 |
|
2
|
60 #=========================================================================== |
|
0
|
61 |
|
|
62 .file "vectors.S" |
|
|
63 |
|
|
64 .extern hal_interrupt_handlers |
|
|
65 .extern hal_interrupt_data |
|
|
66 .extern hal_interrupt_objects |
|
|
67 |
|
|
68 .extern cyg_instrument |
|
|
69 |
|
|
70 .extern hal_hardware_init |
|
|
71 |
|
2
|
72 #=========================================================================== |
|
0
|
73 # MSR initialization value |
|
|
74 # zero all bits except: |
|
|
75 # FP = floating point available |
|
|
76 # ME = machine check enabled |
|
|
77 # IP = vectors at 0xFFFxxxxx (ROM startup only) |
|
2
|
78 # IR = instruction address translation |
|
|
79 # DR = data address translation |
|
0
|
80 # RI = recoverable interrupt |
|
|
81 |
|
2
|
82 #define CYG_MSR_COMMON (MSR_FP | MSR_ME | MSR_IR | MSR_DR | MSR_RI) |
|
|
83 #if defined(CYG_HAL_STARTUP_ROM) || defined(CYG_HAL_STARTUP_STUBS) |
|
|
84 #define CYG_MSR (CYG_MSR_COMMON | MSR_IP) |
|
0
|
85 #endif |
|
|
86 #ifdef CYG_HAL_STARTUP_RAM |
|
2
|
87 #define CYG_MSR CYG_MSR_COMMON |
|
|
88 #endif |
|
|
89 #ifdef CYG_HAL_POWERPC_SIM |
|
|
90 # When building for SIM, don't enable MMU -- it's not needed since caches |
|
|
91 # are disabled, and there is a runtime simulation overhead. |
|
|
92 #undef CYG_MSR |
|
|
93 #define CYG_MSR (CYG_MSR_COMMON & ~(MSR_IR | MSR_DR)) |
|
0
|
94 #endif |
|
|
95 |
|
2
|
96 #=========================================================================== |
|
0
|
97 # If the following option is enabled, we only save registers up to R12. |
|
|
98 # The PowerPC ABI defines registers 13..31 as callee saved and thus we do |
|
|
99 # not need to save them when calling C functions. |
|
|
100 |
|
|
101 #ifdef CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT |
|
|
102 |
|
2
|
103 #define MAX_SAVE_REG 12 |
|
0
|
104 |
|
|
105 #else |
|
|
106 |
|
|
107 #define MAX_SAVE_REG 31 |
|
|
108 |
|
|
109 #endif |
|
|
110 |
|
2
|
111 #=========================================================================== |
|
0
|
112 # Start by defining the exceptions vectors that must be placed at |
|
|
113 # locations 0xFFF00000 and 0x00000000. The following code will normally |
|
|
114 # be located at 0xFFF00000 in the ROM. It may optionally be copied out |
|
|
115 # to 0x00000000 if we want to use the RAM vectors. For this reason this code |
|
|
116 # MUST BE POSITION INDEPENDENT. In RAM loaded configurations, this code may |
|
|
117 # be placed at 0x00000000 during loading. |
|
|
118 |
|
|
119 .section ".vectors","ax" |
|
|
120 |
|
2
|
121 #--------------------------------------------------------------------------- |
|
0
|
122 # Unused first vector. |
|
|
123 |
|
|
124 rom_vectors: |
|
|
125 lwi r3,_start |
|
|
126 mtlr r3 |
|
|
127 blr |
|
|
128 |
|
|
129 .byte 0x11 |
|
|
130 .byte 0x22 |
|
|
131 .byte 0x33 |
|
|
132 .byte 0x44 |
|
|
133 |
|
2
|
134 #--------------------------------------------------------------------------- |
|
0
|
135 # Reset vector. |
|
|
136 |
|
|
137 .p2align 8 |
|
|
138 .globl reset_vector |
|
|
139 |
|
|
140 reset_vector: |
|
|
141 lwi r3,_start |
|
|
142 mtlr r3 |
|
|
143 blr |
|
|
144 |
|
2
|
145 #--------------------------------------------------------------------------- |
|
0
|
146 # Macro for generating an exception vector service routine |
|
|
147 |
|
|
148 .macro exception_vector name |
|
|
149 .p2align 8 |
|
|
150 .globl __exception_\name |
|
|
151 __exception_\name: |
|
2
|
152 mtspr SPRG1,r3 # stash some work registers away |
|
|
153 mtspr SPRG2,r4 |
|
|
154 mtspr SPRG3,r5 |
|
0
|
155 mfcr r4 # stash CR |
|
|
156 li r5,__exception_\name@L # load low half of vector address |
|
|
157 srwi r5,r5,6 # shift right by 6 |
|
|
158 lwi r3,hal_vsr_table # table base |
|
|
159 lwzx r3,r3,r5 # address of vsr |
|
|
160 mflr r5 # save link register |
|
|
161 mtlr r3 # put vsr address into it |
|
|
162 li r3,__exception_\name@L # reload low half of vector address |
|
|
163 blr # go to common code |
|
|
164 .endm |
|
|
165 |
|
2
|
166 #--------------------------------------------------------------------------- |
|
0
|
167 # Define the exception vectors. |
|
|
168 |
|
|
169 # These are the architecture defined vectors that |
|
|
170 # are always present. |
|
|
171 |
|
|
172 exception_vector machine_check |
|
|
173 exception_vector data_storage |
|
|
174 exception_vector instruction_storage |
|
|
175 exception_vector external |
|
|
176 exception_vector alignment |
|
2
|
177 #if defined(CYG_HAL_STARTUP_ROM) || defined(CYG_HAL_STARTUP_STUBS) \ |
|
|
178 || defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS) |
|
0
|
179 exception_vector program |
|
2
|
180 #else |
|
|
181 # Provide a crude hook to the GDB exception handler in ROM. |
|
|
182 # This allows the testing infrastructure to rely on breakpoints |
|
|
183 # to terminate tests, even when the tests are compiled without |
|
|
184 # the GDB stub. |
|
|
185 # It is _not_ a generic solution to the problem; in particular it |
|
|
186 # is not possible to continue after a breakpoint is hit. |
|
|
187 .p2align 8 |
|
|
188 .globl __exception_program |
|
|
189 __exception_program: |
|
|
190 bl _init_CPU # disable caches. |
|
|
191 lwi r3,0xfff00700 # address of trap handler |
|
|
192 mtlr r3 # in ROM. |
|
|
193 blr # jump to it. |
|
|
194 |
|
|
195 #endif |
|
0
|
196 exception_vector floatingpoint_unavailable |
|
|
197 exception_vector decrementer |
|
|
198 exception_vector reserved_00a00 |
|
|
199 exception_vector reserved_00b00 |
|
|
200 exception_vector system_call |
|
|
201 exception_vector trace |
|
|
202 exception_vector floatingpoint_assist |
|
|
203 exception_vector reserved_00f00 |
|
|
204 |
|
|
205 # There are some additional vectors defined |
|
|
206 # on various implementations. |
|
|
207 |
|
2
|
208 #ifdef CYG_HAL_POWERPC_MPC8xx |
|
|
209 # MPC8xx vectors |
|
0
|
210 |
|
|
211 exception_vector software_emu |
|
|
212 exception_vector instruction_tlb_miss |
|
|
213 exception_vector data_tlb_miss |
|
|
214 exception_vector instruction_tlb_error |
|
|
215 exception_vector data_tlb_error |
|
|
216 exception_vector reserved_01500 |
|
|
217 exception_vector reserved_01600 |
|
|
218 exception_vector reserved_01700 |
|
|
219 exception_vector reserved_01800 |
|
|
220 exception_vector reserved_01900 |
|
|
221 exception_vector reserved_01A00 |
|
|
222 exception_vector reserved_01B00 |
|
|
223 exception_vector data_breakpoint |
|
|
224 exception_vector instruction_breakpoint |
|
|
225 exception_vector peripheral_breakpoint |
|
|
226 exception_vector NMI_port |
|
|
227 |
|
2
|
228 #endif |
|
0
|
229 rom_vectors_end: |
|
|
230 |
|
2
|
231 #=========================================================================== |
|
|
232 # Real startup code. We jump here from the various reset vectors to set up |
|
|
233 # the world. |
|
0
|
234 |
|
|
235 .text |
|
|
236 .globl _start |
|
|
237 |
|
2
|
238 _start: |
|
|
239 # Initialize CPU |
|
|
240 bl _init_CPU |
|
0
|
241 |
|
2
|
242 #ifdef CYG_HAL_POWERPC_MPC8xx |
|
|
243 # Disable special MPC8xx "development support" which |
|
|
244 # suppresses trace exceptions. The CPU seems to hang, not |
|
|
245 # executing from offset 0x1e00(?) as expected. |
|
0
|
246 li r3,0 |
|
2
|
247 mtspr DER, r3 |
|
0
|
248 #endif |
|
|
249 |
|
|
250 # Set up global offset table |
|
|
251 lwi r2,_GLOBAL_OFFSET_TABLE_ |
|
|
252 |
|
|
253 # set up time base register to zero |
|
|
254 xor r3,r3,r3 |
|
2
|
255 mtspr TBL_W,r3 |
|
0
|
256 xor r4,r4,r4 |
|
2
|
257 mtspr TBU_W,r4 |
|
|
258 |
|
|
259 # Call platform specific hardware initialization |
|
|
260 # This may include memory controller initialization. It is not |
|
|
261 # safe to access RAM until after this point. |
|
|
262 bl hal_hardware_init |
|
0
|
263 |
|
|
264 # set up stack |
|
|
265 lwi sp,__interrupt_stack |
|
2
|
266 mtspr SPRG0,sp # save in sprg0 for later use |
|
0
|
267 |
|
2
|
268 #if defined(CYG_HAL_STARTUP_ROM) || defined(CYG_HAL_STARTUP_STUBS) |
|
0
|
269 |
|
|
270 # Copy data from ROM to ram |
|
|
271 lwi r3,__rom_data_start # r3 = rom start |
|
|
272 lwi r4,__ram_data_start # r4 = ram start |
|
|
273 lwi r5,__ram_data_end # r5 = ram end |
|
|
274 |
|
|
275 cmplw r4,r5 # skip if no data |
|
|
276 beq 2f |
|
|
277 |
|
|
278 1: |
|
|
279 lwz r0,0(r3) # get word from ROM |
|
|
280 stw r0,0(r4) # store in RAM |
|
|
281 addi r3,r3,4 # increment by 1 word |
|
|
282 addi r4,r4,4 # increment by 1 word |
|
|
283 cmplw r4,r5 # compare |
|
|
284 blt 1b # loop if not yet done |
|
|
285 2: |
|
|
286 |
|
|
287 #ifdef CYG_HAL_POWERPC_COPY_VECTORS |
|
|
288 # Copy RAM exception vectors from ROM to RAM |
|
|
289 lwi r3,rom_vectors # r3 = rom start |
|
|
290 lwi r4,0 # r4 = ram start |
|
|
291 lwi r5,rom_vectors_end # r5 = rom end |
|
|
292 |
|
|
293 cmplw r3,r5 # skip if no vectors |
|
|
294 beq 2f |
|
|
295 |
|
|
296 1: |
|
|
297 lwz r0,0(r3) # get word from ROM |
|
|
298 stw r0,0(r4) # store in RAM |
|
|
299 addi r3,r3,4 # increment by 1 word |
|
|
300 addi r4,r4,4 # increment by 1 word |
|
|
301 cmplw r3,r5 # compare |
|
|
302 blt 1b # loop if not yet done |
|
|
303 2: |
|
|
304 #endif |
|
|
305 |
|
|
306 #endif |
|
2
|
307 |
|
0
|
308 # clear BSS |
|
2
|
309 .extern __bss_start |
|
|
310 .extern __bss_end |
|
0
|
311 lwi r3,__bss_start # r3 = start |
|
2
|
312 lwi r4,__bss_end # r4 = end |
|
0
|
313 li r0,0 # r0 = 0 |
|
|
314 cmplw r3,r4 # skip if no bss |
|
|
315 beq 2f |
|
|
316 |
|
2
|
317 1: stw r0,0(r3) # store zero |
|
0
|
318 addi r3,r3,4 # increment by 1 word |
|
|
319 cmplw r3,r4 # compare |
|
|
320 blt 1b # loop if not yet done |
|
|
321 2: |
|
|
322 |
|
2
|
323 # clear SBSS |
|
|
324 .extern __sbss_start |
|
|
325 .extern __sbss_end |
|
|
326 lwi r3,__sbss_start # r3 = start |
|
|
327 lwi r4,__sbss_end # r4 = end |
|
|
328 cmplw r3,r4 # skip if no sbss |
|
|
329 beq 2f |
|
|
330 |
|
|
331 1: stw r0,0(r3) # store zero |
|
|
332 addi r3,r3,4 # increment by 1 word |
|
|
333 cmplw r3,r4 # compare |
|
|
334 blt 1b # loop if not yet done |
|
|
335 2: |
|
|
336 |
|
|
337 # It is now safe to call C functions which may rely on initialized |
|
|
338 # data. |
|
|
339 |
|
|
340 # Set up stack for calls to C code. |
|
0
|
341 subi sp,sp,12 # make space on stack |
|
|
342 li r0,0 |
|
|
343 stw r0,0(sp) # clear back chain |
|
|
344 stw r0,8(sp) # zero return pc |
|
|
345 stwu sp,-ppc_stack_frame_size(sp) # create new stack frame |
|
2
|
346 |
|
|
347 # Initialize MMU. |
|
|
348 .extern hal_MMU_init |
|
|
349 bl hal_MMU_init |
|
|
350 |
|
|
351 # Enable MMU it so we can safely enable caches. |
|
|
352 lwi r3,CYG_MSR |
|
|
353 sync |
|
|
354 mtmsr r3 |
|
|
355 sync |
|
0
|
356 |
|
2
|
357 # Enable caches |
|
|
358 .extern hal_enable_caches |
|
|
359 bl hal_enable_caches |
|
0
|
360 |
|
2
|
361 # call c++ constructors |
|
0
|
362 .extern cyg_hal_invoke_constructors |
|
2
|
363 bl cyg_hal_invoke_constructors |
|
0
|
364 |
|
2
|
365 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS |
|
|
366 .extern initialize_stub |
|
|
367 bl initialize_stub |
|
0
|
368 #endif |
|
|
369 |
|
|
370 .extern cyg_start |
|
|
371 bl cyg_start # call cyg_start |
|
|
372 9: |
|
|
373 b 9b # if we return, loop |
|
|
374 |
|
2
|
375 #--------------------------------------------------------------------------- |
|
0
|
376 # This code handles the common part of all exception handlers. |
|
|
377 # It saves the machine state onto the stack and then calls |
|
|
378 # a "C" routine to do the rest of the work. This work may result |
|
|
379 # in thread switches, and changes to the saved state. When we return |
|
|
380 # here the saved state is restored and execution is continued. |
|
|
381 |
|
|
382 .text |
|
|
383 |
|
|
384 .extern __default_exception_vsr |
|
|
385 __default_exception_vsr: |
|
|
386 |
|
|
387 # We come here with all register containing their |
|
|
388 # pre-exception values except: |
|
|
389 # R3 = ls 16 bits of vector address |
|
|
390 # R4 = saved CR |
|
|
391 # R5 = saved LR |
|
|
392 # LR = VSR address |
|
|
393 # SPRG1 = old R3 |
|
|
394 # SPRG2 = old R4 |
|
|
395 # SPRG3 = old R5 |
|
|
396 # SRR0 = old PC |
|
2
|
397 # SRR1 = old MSR and the exception cause (the POW state is lost!) |
|
0
|
398 |
|
|
399 subi r1,r1,ppc_exception_decrement |
|
|
400 # leave space for registers and |
|
|
401 # a safety margin |
|
|
402 |
|
|
403 # First, save away some registers |
|
|
404 stw r3,ppcreg_vector(r1) # stash vector |
|
|
405 stw r4,ppcreg_cr(r1) # stash CR |
|
|
406 stw r5,ppcreg_lr(r1) # stash LR |
|
2
|
407 |
|
|
408 # Enable MMU. |
|
|
409 lwi r3,CYG_MSR |
|
|
410 sync |
|
|
411 mtmsr r3 |
|
|
412 sync |
|
|
413 |
|
|
414 mfspr r3,SPRG1 # save original R3 |
|
0
|
415 stw r3,ppcreg_regs+3*4(r1) |
|
2
|
416 mfspr r4,SPRG2 # save original R4 |
|
0
|
417 stw r4,ppcreg_regs+4*4(r1) |
|
2
|
418 mfspr r5,SPRG3 # save original R5 |
|
0
|
419 stw r5,ppcreg_regs+5*4(r1) |
|
|
420 |
|
|
421 stw r0,ppcreg_regs(r1) # save R0 |
|
|
422 stw r2,ppcreg_regs+2*4(r1) # save R2 |
|
|
423 |
|
|
424 mr r3,r1 # recreate original R1 |
|
|
425 addi r3,r3,ppc_exception_decrement |
|
|
426 stw r3,ppcreg_regs+1*4(r1) # and save it in state |
|
|
427 |
|
2
|
428 # Save registers r6..r12/r31 |
|
0
|
429 .set _reg,6 |
|
|
430 .rept MAX_SAVE_REG+1-6 |
|
|
431 stw _reg,(ppcreg_regs+_reg*4)(r1) |
|
|
432 .set _reg,_reg+1 |
|
|
433 .endr |
|
|
434 |
|
2
|
435 # Save registers used in vsr (r14+r15) |
|
|
436 stw r14,(ppcreg_regs+14*4)(r1) |
|
|
437 stw r15,(ppcreg_regs+15*4)(r1) |
|
|
438 |
|
0
|
439 # get remaining CPU registers |
|
|
440 mfxer r3 |
|
|
441 mfctr r5 |
|
|
442 mfdar r6 |
|
|
443 mfdsisr r7 |
|
|
444 mfpvr r8 |
|
|
445 mfsrr0 r9 |
|
|
446 mfsrr1 r10 |
|
|
447 |
|
|
448 # and store them |
|
|
449 stw r3,ppcreg_xer(r1) |
|
|
450 stw r5,ppcreg_ctr(r1) |
|
|
451 stw r6,ppcreg_dar(r1) |
|
|
452 stw r7,ppcreg_dsisr(r1) |
|
|
453 stw r8,ppcreg_pvr(r1) |
|
|
454 stw r9,ppcreg_pc(r1) |
|
|
455 stw r10,ppcreg_msr(r1) |
|
|
456 |
|
|
457 # The entire CPU state is now stashed on the stack, |
|
|
458 # call into C to do something with it. |
|
|
459 |
|
|
460 mr r3,sp # R3 = register dump |
|
|
461 |
|
|
462 subi sp,sp,ppc_stack_frame_size # make a null frame |
|
|
463 |
|
|
464 li r0,0 # R0 = 0 |
|
|
465 stw r0,0(sp) # backchain = 0 |
|
|
466 stw r0,8(sp) # return pc = 0 |
|
|
467 |
|
|
468 stwu sp,-ppc_stack_frame_size(sp) # create new stack frame |
|
|
469 # where C code can save LR |
|
|
470 |
|
|
471 lwi r5,restore_state # get return link |
|
|
472 mtlr r5 # to link register |
|
|
473 |
|
2
|
474 .extern cyg_hal_exception_handler |
|
|
475 b cyg_hal_exception_handler # call C code, r3 = registers |
|
0
|
476 |
|
|
477 # When the call returns it will go to restore_state below. |
|
|
478 |
|
|
479 |
|
2
|
480 ##-------------------------------------------------------------------------- |
|
|
481 ## The following macros are defined depending on whether the Interrupt |
|
|
482 ## system is using isr tables or chaining, and depending on the interrupt |
|
|
483 ## controller in the system. |
|
|
484 |
|
|
485 ## Note: CYG_ISR_TABLE_SIZE must match CYG_ISR_COUNT defined in hal_intr.h. |
|
|
486 |
|
|
487 #ifdef CYG_HAL_POWERPC_MPC8xx |
|
|
488 |
|
|
489 ## First level decoding of MPC8xx SIU interrupt controller. |
|
|
490 |
|
|
491 #define CYG_ISR_TABLE_SIZE 59 |
|
|
492 |
|
|
493 # decode the interrupt |
|
|
494 .macro decode_interrupt dreg,state |
|
|
495 lwz \dreg,ppcreg_vector(\state) # retrieve vector number, |
|
|
496 rlwinm. \dreg,\dreg,22,31,31 # isolate bit 21 |
|
|
497 beq 0f # done if decrementer (vec 0) |
|
|
498 lwi \dreg,CYGARC_REG_IMM_SIVEC # if external, get SIU |
|
|
499 lbz \dreg,0(\dreg) # vector. |
|
|
500 srwi \dreg,\dreg,2 |
|
|
501 addi \dreg,\dreg,1 # Skip decrementer vector |
|
|
502 0: stw \dreg,ppcreg_vector(\state) # update vector in state frame. |
|
|
503 slwi \dreg,\dreg,2 # convert to byte offset. |
|
|
504 .endm |
|
|
505 |
|
|
506 #else |
|
|
507 |
|
|
508 ## This is the simple version. No interrupt controller, ppcreg_vector |
|
|
509 ## is updated with the decoded interrupt vector. Isr tables/chaining |
|
|
510 ## use same interrupt decoder. |
|
|
511 ## Bit 21 biffers between decrementer (0) and external (1). |
|
|
512 |
|
|
513 #define CYG_ISR_TABLE_SIZE 2 |
|
|
514 |
|
|
515 # decode the interrupt |
|
|
516 .macro decode_interrupt dreg,state |
|
|
517 lwz \dreg,ppcreg_vector(\state) # retrieve vector number, |
|
|
518 rlwinm \dreg,\dreg,22,31,31 # isolate bit 21 and update |
|
|
519 stw \dreg,ppcreg_vector(\state) # vector in state frame. |
|
|
520 slwi \dreg,\dreg,2 # convert to word offset. |
|
|
521 .endm |
|
|
522 |
|
|
523 #endif |
|
|
524 |
|
|
525 #--------------------------------------------------------------------------- |
|
0
|
526 # Common interrupt handling code. |
|
|
527 |
|
|
528 .extern __default_interrupt_vsr |
|
|
529 __default_interrupt_vsr: |
|
|
530 |
|
|
531 # We come here with all register containing their |
|
|
532 # pre-exception values except: |
|
|
533 # R3 = ls 16 bits of vector address |
|
|
534 # R4 = saved CR |
|
|
535 # R5 = saved LR |
|
|
536 # LR = VSR address |
|
|
537 # SPRG1 = old R3 |
|
|
538 # SPRG2 = old R4 |
|
|
539 # SPRG3 = old R5 |
|
|
540 # SRR0 = old PC |
|
|
541 # SRR1 = old MSR |
|
|
542 |
|
|
543 |
|
|
544 subi r1,r1,ppc_exception_decrement |
|
|
545 # leave space for registers and |
|
|
546 # a safety margin |
|
|
547 |
|
|
548 stw r3,ppcreg_vector(r1) # stash vector |
|
|
549 stw r4,ppcreg_cr(r1) # stash CR |
|
|
550 stw r5,ppcreg_lr(r1) # stash LR |
|
|
551 |
|
2
|
552 # Enable MMU. |
|
|
553 lwi r3,CYG_MSR |
|
|
554 sync |
|
|
555 mtmsr r3 |
|
|
556 sync |
|
|
557 |
|
|
558 mfspr r3,SPRG1 # save original R3 |
|
0
|
559 stw r3,ppcreg_regs+3*4(r1) |
|
2
|
560 mfspr r4,SPRG2 # save original R4 |
|
0
|
561 stw r4,ppcreg_regs+4*4(r1) |
|
2
|
562 mfspr r5,SPRG3 # save original R5 |
|
0
|
563 stw r5,ppcreg_regs+5*4(r1) |
|
|
564 |
|
|
565 stw r0,ppcreg_regs(r1) # save R0 |
|
|
566 stw r2,ppcreg_regs+2*4(r1) # save R2 |
|
|
567 |
|
|
568 mr r3,r1 # recreate original R1 |
|
|
569 addi r3,r3,ppc_exception_decrement |
|
|
570 stw r3,ppcreg_regs+1*4(r1) # and save it in state |
|
|
571 |
|
2
|
572 # Save registers r6..r12/r31 |
|
0
|
573 .set _reg,6 |
|
|
574 .rept MAX_SAVE_REG+1-6 |
|
|
575 stw _reg,(ppcreg_regs+_reg*4)(r1) |
|
|
576 .set _reg,_reg+1 |
|
|
577 .endr |
|
|
578 |
|
2
|
579 # Save registers used in vsr (r14+r15) |
|
|
580 stw r14,(ppcreg_regs+14*4)(r1) |
|
|
581 stw r15,(ppcreg_regs+15*4)(r1) |
|
|
582 |
|
0
|
583 # get remaining CPU registers |
|
|
584 mfxer r3 |
|
|
585 mfctr r5 |
|
|
586 mfsrr0 r6 |
|
|
587 mfsrr1 r7 |
|
|
588 |
|
|
589 # and store them |
|
|
590 stw r3,ppcreg_xer(r1) |
|
|
591 stw r5,ppcreg_ctr(r1) |
|
|
592 stw r6,ppcreg_pc(r1) |
|
|
593 stw r7,ppcreg_msr(r1) |
|
|
594 |
|
|
595 # The entire CPU state is now stashed on the stack, |
|
|
596 # increment the scheduler lock and call the ISR |
|
|
597 # for this vector. |
|
|
598 |
|
|
599 #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT |
|
2
|
600 .extern cyg_scheduler_sched_lock |
|
|
601 lwi r3,cyg_scheduler_sched_lock |
|
0
|
602 lwz r4,0(r3) |
|
|
603 addi r4,r4,1 |
|
|
604 stw r4,0(r3) |
|
|
605 #endif |
|
|
606 |
|
2
|
607 mr r14,sp # r14 = register dump |
|
0
|
608 |
|
|
609 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK |
|
|
610 lwi r3,__interrupt_stack # stack top |
|
|
611 lwi r4,__interrupt_stack_base # stack base |
|
|
612 sub. r5,sp,r4 # sp - base |
|
|
613 blt 1f # if < 0 - not on istack |
|
|
614 sub. r5,r3,sp # top - sp |
|
|
615 bgt 2f # if > 0 - already on istack |
|
|
616 |
|
|
617 1: mr sp,r3 # switch to istack |
|
|
618 |
|
2
|
619 2: stwu r14,-4(sp) # save old SP on stack |
|
0
|
620 |
|
|
621 #endif |
|
|
622 |
|
|
623 subi sp,sp,ppc_stack_frame_size # make a null frame |
|
|
624 |
|
|
625 li r0,0 # R0 = 0 |
|
|
626 stw r0,0(sp) # backchain = 0 |
|
|
627 stw r0,8(sp) # return pc = 0 |
|
|
628 |
|
|
629 stwu sp,-ppc_stack_frame_size(sp) # create new stack frame |
|
|
630 # where C code can save LR |
|
|
631 |
|
|
632 #if defined(CYGPKG_KERNEL_INSTRUMENT) && defined(CYGDBG_KERNEL_INSTRUMENT_INTR) |
|
|
633 |
|
|
634 lwi r3,0x0301 # r3 = type = INTR,RAISE |
|
2
|
635 lwz r4,ppcreg_vector(r14) # arg1 = vector address |
|
0
|
636 srwi r4,r4,8 # arg1 = vector number |
|
|
637 xor r5,r5,r5 # arg2 = 0 |
|
|
638 bl cyg_instrument # call instrument function |
|
|
639 |
|
|
640 #endif |
|
|
641 |
|
2
|
642 decode_interrupt r15,r14 # get table index |
|
|
643 |
|
0
|
644 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT |
|
|
645 .extern cyg_hal_gdb_isr |
|
2
|
646 lwz r3,ppcreg_pc(r14) # for serial receive irq. |
|
|
647 bl cyg_hal_gdb_isr # (arg1 is PC) |
|
0
|
648 cmpwi r3,0x0000 # Call ISR proper? |
|
|
649 beq 2f # (r3 is 0 when skipping |
|
|
650 # to avoid DSR call) |
|
|
651 1: |
|
|
652 #endif |
|
|
653 |
|
2
|
654 #ifdef CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING |
|
0
|
655 |
|
2
|
656 #ifdef CYG_HAL_POWERPC_MPC8xx |
|
|
657 # The CPM controller allows nested interrupts. However, |
|
|
658 # it sits on the back of the SIU controller which has no |
|
|
659 # HW support for this. In effect, SW masking of lower |
|
|
660 # priority IRQs in the SIU would be required for this to work. |
|
|
661 #endif |
|
|
662 |
|
|
663 #endif |
|
|
664 |
|
|
665 lwz r3,ppcreg_vector(r14) # retrieve decoded vector # |
|
0
|
666 |
|
|
667 lwi r6,hal_interrupt_handlers # get interrupt handler table |
|
|
668 lwzx r6,r6,r15 # load routine pointer |
|
|
669 |
|
|
670 lwi r4,hal_interrupt_data # get interrupt data table |
|
|
671 lwzx r4,r4,r15 # load data pointer |
|
|
672 # R4 = data argument |
|
|
673 |
|
|
674 mtctr r6 # put isr address in ctr |
|
|
675 |
|
|
676 bctrl # branch to ctr reg and link |
|
|
677 |
|
|
678 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT |
|
|
679 # If interrupt was caused by GDB, the ISR call above |
|
|
680 # is skipped by jumping here. |
|
|
681 2: |
|
|
682 #endif |
|
|
683 |
|
|
684 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK |
|
|
685 |
|
|
686 # If we are returning from the last nested interrupt, move back |
|
|
687 # to the thread stack. interrupt_end() must be called on the |
|
|
688 # thread stack since it potentially causes a context switch. |
|
|
689 # Since we have arranged for the top of stack location to |
|
|
690 # contain the sp we need to go back to here, just pop it off |
|
|
691 # and put it in SP. |
|
|
692 |
|
|
693 |
|
|
694 lwz sp,ppc_stack_frame_size*2(sp) # sp = *sp |
|
|
695 |
|
|
696 subi sp,sp,ppc_stack_frame_size # make a null frame |
|
|
697 |
|
|
698 li r0,0 # R0 = 0 |
|
|
699 stw r0,0(sp) # backchain = 0 |
|
|
700 stw r0,8(sp) # return pc = 0 |
|
|
701 |
|
|
702 stwu sp,-ppc_stack_frame_size(sp) # create new stack frame |
|
|
703 # where C code can save LR |
|
|
704 #endif |
|
|
705 |
|
|
706 #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT |
|
|
707 |
|
|
708 # We only need to call _interrupt_end() when there is a kernel |
|
|
709 # present to do any tidying up. |
|
|
710 |
|
|
711 # on return r3 bit 1 will indicate whether a DSR is |
|
|
712 # to be posted. Pass this together with a pointer to |
|
|
713 # the interrupt object we have just used to the |
|
|
714 # interrupt tidy up routine. |
|
|
715 |
|
2
|
716 # Note that r14 and r15 are defined to be preserved across |
|
0
|
717 # calls by the calling convention, so they still contain |
|
|
718 # the register dump and the vector number respectively. |
|
2
|
719 |
|
|
720 # Note: The instructions restoring the msr mask out the POW bit. |
|
|
721 # When eCos gets power management aware, this bit will have to be |
|
|
722 # set to the correct state rather than just cleared. |
|
0
|
723 |
|
|
724 lwi r4,hal_interrupt_objects # get interrupt object table |
|
|
725 lwzx r4,r4,r15 # load object pointer |
|
|
726 |
|
2
|
727 lwz r6,ppcreg_msr(r14) # restore msr, including |
|
|
728 lis r5,0xfffe # interrupt enable. |
|
|
729 andc r6,r6,r5 # mask out reserved bits |
|
|
730 sync # (and POW!) |
|
|
731 mtmsr r6 |
|
|
732 sync |
|
0
|
733 |
|
2
|
734 mr r5,r14 # arg3 = saved register dump |
|
0
|
735 |
|
|
736 .extern interrupt_end |
|
|
737 bl interrupt_end # call into C to finish off |
|
|
738 #endif |
|
|
739 |
|
|
740 restore_state: |
|
|
741 # All done, restore CPU state and continue |
|
|
742 |
|
|
743 addi sp,sp,ppc_stack_frame_size*2 # retrieve CPU state pointer |
|
|
744 |
|
|
745 # get sprs we want to restore |
|
|
746 lwz r3,ppcreg_cr(sp) |
|
|
747 lwz r4,ppcreg_pc(sp) |
|
|
748 lwz r5,ppcreg_msr(sp) |
|
|
749 lwz r6,ppcreg_xer(sp) |
|
|
750 lwz r7,ppcreg_lr(sp) |
|
|
751 lwz r8,ppcreg_ctr(sp) |
|
|
752 |
|
|
753 |
|
|
754 # stuff some of them into the CPU |
|
|
755 mtxer r6 |
|
|
756 mtlr r7 |
|
|
757 mtctr r8 |
|
|
758 |
|
|
759 # restore R0 and R2 |
|
|
760 lwz r0,ppcreg_regs(sp) |
|
|
761 lwz r2,ppcreg_regs+2*4(sp) |
|
|
762 |
|
2
|
763 # Restore registers used in vsr (r14+r15) |
|
|
764 lwz r14,(ppcreg_regs+14*4)(r1) |
|
|
765 lwz r15,(ppcreg_regs+15*4)(r1) |
|
|
766 |
|
|
767 # restore registers r6..r12/r31 |
|
0
|
768 .set _reg,6 |
|
|
769 .rept MAX_SAVE_REG+1-6 |
|
|
770 lwz _reg,(ppcreg_regs+_reg*4)(r1) |
|
|
771 .set _reg,_reg+1 |
|
|
772 .endr |
|
|
773 |
|
|
774 # Here all the registers are loaded except |
|
|
775 # r1 = ppcregs |
|
|
776 # r3 = ccr |
|
|
777 # r4 = srr0 = pc |
|
|
778 # r5 = srr1 = msr |
|
|
779 |
|
|
780 # We have to disable interrupts while srr0 and |
|
|
781 # srr1 are loaded, since another interrupt will |
|
|
782 # destroy them. |
|
|
783 |
|
|
784 mtcr r3 # set ccr |
|
|
785 |
|
2
|
786 lwi r3,CYG_MSR # do rest with ints disabled |
|
|
787 sync |
|
0
|
788 mtmsr r3 |
|
2
|
789 sync |
|
0
|
790 |
|
|
791 mtsrr0 r4 # load old pc |
|
|
792 mtsrr1 r5 # load old msr |
|
|
793 |
|
|
794 lwz r3,ppcreg_regs+3*4(r1) # load r3 value |
|
|
795 lwz r4,ppcreg_regs+4*4(r1) # load r4 value |
|
|
796 lwz r5,ppcreg_regs+5*4(r1) # load r5 value |
|
|
797 lwz r1,ppcreg_regs+1*4(r1) # restore r1 |
|
|
798 |
|
|
799 sync # settle things down |
|
|
800 isync |
|
|
801 rfi # and return |
|
|
802 |
|
2
|
803 #--------------------------------------------------------------------------- |
|
|
804 # Code for putting the CPU in a post-reset state; disabling MMU and caches. |
|
|
805 _init_CPU: |
|
|
806 #ifdef CYG_HAL_POWERPC_MPC8xx |
|
|
807 lwi r3,CYGARC_REG_DC_CMD_CD |
|
|
808 sync |
|
|
809 mtspr CYGARC_REG_DC_CST,r3 |
|
|
810 lwi r3,CYGARC_REG_IC_CMD_CD |
|
|
811 isync |
|
|
812 mtspr CYGARC_REG_IC_CST,r3 |
|
|
813 isync |
|
|
814 #endif |
|
|
815 |
|
|
816 # Set up MSR (disable MMU for now) |
|
|
817 lwi r3,(CYG_MSR & ~(MSR_IR | MSR_DR)) |
|
|
818 sync |
|
|
819 mtmsr r3 |
|
|
820 sync |
|
|
821 blr |
|
|
822 |
|
|
823 #--------------------------------------------------------------------------- |
|
0
|
824 # This table contains a VSR pointer for each defined exception. |
|
|
825 # All of these except 5 and 9 point to the __default_exception_vsr |
|
|
826 # above, 5 and 9 point to the __default_interrupt_vsr. Entries in |
|
|
827 # this table may be changed using Cyg_Interrupt::set_vsr(). |
|
|
828 |
|
|
829 .data |
|
|
830 |
|
|
831 .globl hal_vsr_table |
|
|
832 hal_vsr_table: |
|
|
833 # Architecture defined vectors |
|
|
834 .long __default_exception_vsr # reserved |
|
|
835 .long __default_exception_vsr # system reset |
|
|
836 .long __default_exception_vsr # machine check |
|
|
837 .long __default_exception_vsr # data storage |
|
|
838 .long __default_exception_vsr # instruction storage |
|
|
839 |
|
|
840 .long __default_interrupt_vsr # external interrupt |
|
|
841 |
|
|
842 .long __default_exception_vsr # alignment |
|
|
843 .long __default_exception_vsr # program |
|
|
844 .long __default_exception_vsr # floating point unavailable |
|
|
845 |
|
|
846 .long __default_interrupt_vsr # decrementer |
|
|
847 |
|
|
848 .long __default_exception_vsr # reserved 0x0a00 |
|
|
849 .long __default_exception_vsr # reserved 0x0b00 |
|
|
850 .long __default_exception_vsr # system call |
|
|
851 .long __default_exception_vsr # trace |
|
|
852 .long __default_exception_vsr # floating point assist |
|
|
853 .long __default_exception_vsr # reserved 0x0f00 |
|
|
854 |
|
2
|
855 #ifdef CYG_HAL_POWERPC_MPC8xx |
|
0
|
856 |
|
|
857 # Implementation defined vectors |
|
|
858 .long __default_exception_vsr # software emulation |
|
|
859 .long __default_exception_vsr # instruction TLB miss |
|
|
860 .long __default_exception_vsr # data TLB miss |
|
|
861 .long __default_exception_vsr # instruction TLB error |
|
|
862 .long __default_exception_vsr # data TLB error |
|
|
863 .long __default_exception_vsr # reserved 0x1500 |
|
|
864 .long __default_exception_vsr # reserved 0x1600 |
|
|
865 .long __default_exception_vsr # reserved 0x1700 |
|
|
866 .long __default_exception_vsr # reserved 0x1800 |
|
|
867 .long __default_exception_vsr # reserved 0x1900 |
|
|
868 .long __default_exception_vsr # reserved 0x1a00 |
|
|
869 .long __default_exception_vsr # reserved 0x1b00 |
|
|
870 .long __default_exception_vsr # data breakpoint |
|
|
871 .long __default_exception_vsr # instruction breakpoint |
|
|
872 .long __default_exception_vsr # peripheral breakpoint |
|
|
873 .long __default_exception_vsr # non maskable development port |
|
|
874 #endif |
|
|
875 |
|
2
|
876 #--------------------------------------------------------------------------- |
|
0
|
877 # Interrupt vector tables. |
|
|
878 # These tables contain the isr, data and object pointers used to deliver |
|
|
879 # interrupts to user code. |
|
2
|
880 |
|
|
881 #if (CYG_ISR_TABLE_SIZE > 2) |
|
0
|
882 .data |
|
2
|
883 #else |
|
|
884 .section ".sdata","aw" |
|
|
885 #endif |
|
0
|
886 |
|
|
887 .extern hal_default_isr |
|
|
888 |
|
|
889 .globl hal_interrupt_handlers |
|
|
890 hal_interrupt_handlers: |
|
2
|
891 .rept CYG_ISR_TABLE_SIZE |
|
0
|
892 .long hal_default_isr |
|
|
893 .endr |
|
|
894 |
|
|
895 .globl hal_interrupt_data |
|
|
896 hal_interrupt_data: |
|
2
|
897 .rept CYG_ISR_TABLE_SIZE |
|
0
|
898 .long 0 |
|
|
899 .endr |
|
|
900 |
|
|
901 .globl hal_interrupt_objects |
|
|
902 hal_interrupt_objects: |
|
2
|
903 .rept CYG_ISR_TABLE_SIZE |
|
0
|
904 .long 0 |
|
|
905 .endr |
|
|
906 |
|
2
|
907 #--------------------------------------------------------------------------- |
|
0
|
908 ## Temporary interrupt stack |
|
|
909 |
|
|
910 .section ".bss" |
|
|
911 |
|
|
912 .balign 16 |
|
|
913 __interrupt_stack_base: |
|
|
914 .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE |
|
|
915 .byte 0 |
|
|
916 .endr |
|
|
917 .balign 16 |
|
|
918 __interrupt_stack: |
|
|
919 |
|
|
920 .long 0,0,0,0,0,0,0,0 |
|
|
921 |
|
2
|
922 #--------------------------------------------------------------------------- |
|
0
|
923 # end of vectors.S |