1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * Exception Handler File: exchandler.c
6 * This is the "C" part of the exception handler and the
7 * associated setup routines. We call these routines from
8 * the assembly-language exception handler.
10 * Author: Mitch Lichtenberg (mpl@broadcom.com)
12 *********************************************************************
14 * Copyright 2000,2001,2002,2003
15 * Broadcom Corporation. All rights reserved.
17 * This software is furnished under license and may be used and
18 * copied only in accordance with the following terms and
19 * conditions. Subject to these conditions, you may download,
20 * copy, install, use, modify and distribute modified or unmodified
21 * copies of this software in source and/or binary form. No title
22 * or ownership is transferred hereby.
24 * 1) Any source code used, modified or distributed must reproduce
25 * and retain this copyright notice and list of conditions
26 * as they appear in the source file.
28 * 2) No right is granted to use any trade name, trademark, or
29 * logo of Broadcom Corporation. The "Broadcom Corporation"
30 * name may not be used to endorse or promote products derived
31 * from this software without the prior written permission of
32 * Broadcom Corporation.
34 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
35 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
36 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
37 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
38 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
39 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
40 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
42 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
44 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
45 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
46 * THE POSSIBILITY OF SUCH DAMAGE.
47 ********************************************************************* */
51 #include "lib_types.h"
52 #include "lib_string.h"
53 #include "lib_printf.h"
54 #include "lib_queue.h"
55 #include "lib_malloc.h"
56 #include "exception.h"
58 #include "cfe_error.h"
60 #include "exchandler.h"
61 #include "cpu_config.h"
62 #include "bsp_config.h"
64 /* *********************************************************************
66 ********************************************************************* */
69 * Temporary until all our CPU packages support a cache error handler
72 #ifndef CPUCFG_CERRHANDLER
73 #define CPUCFG_CERRHANDLER 0xBFC00000
75 extern void CPUCFG_CERRHANDLER(void);
78 /* *********************************************************************
80 ********************************************************************* */
82 exc_handler_t exc_handler
;
83 extern void _exc_entry(void);
84 extern void _exc_setup_locore(long);
85 extern void CPUCFG_TLBHANDLER(void);
86 extern void cfe_flushcache(uint32_t,long,long);
87 extern uint32_t _getstatus(void);
88 extern void _setstatus(uint32_t);
90 static const char *regnames
= "0 ATv0v1a0a1a2a3t0t1t2t3t4t5t6t7"
91 "s0s1s2s3s4s5s6s7t8t9k0k1gpspfpra";
92 static const char *excnames
=
128 /* *********************************************************************
129 * cfe_exception(code,info)
131 * Exception handler. This routine is called when any CPU
132 * exception that is handled by the assembly-language
133 * vectors is reached. The usual thing to do here is just to
137 * code - exception type
138 * info - exception stack frame
142 ********************************************************************* */
144 void cfe_exception(int code
,uint64_t *info
)
150 if(exc_handler
.catch_exc
== 1) {
151 /*Deal with exception without restarting CFE.*/
153 /*Clear relevant SR bits*/
158 exc_handler
.catch_exc
= 0;
160 exc_longjmp_handler();
165 xprintf("**Exception %d: EPC=%08X, Cause=%08X (%9s)\n",
166 code
,(uint32_t)info
[XCP0_EPC
],
167 (uint32_t)info
[XCP0_CAUSE
],
168 excnames
+ G_CAUSE_EXC((uint32_t)info
[XCP0_CAUSE
])*9);
169 xprintf(" RA=%08X, VAddr=%08X\n",
170 (uint32_t)info
[XGR_RA
],(uint32_t)info
[XCP0_VADDR
]);
172 for (idx
= 0;idx
< 32; idx
+= 2) {
173 xprintf(" %2s ($%2d) = %08X %2s ($%2d) = %08X\n",
175 idx
,(uint32_t)info
[XGR_ZERO
+idx
],
176 regnames
+((idx
+1)*2),
177 idx
+1,(uint32_t)info
[XGR_ZERO
+idx
+1]);
180 xprintf("**Exception %d: EPC=%016llX, Cause=%08X (%9s)\n",
181 code
,info
[XCP0_EPC
],info
[XCP0_CAUSE
],
182 excnames
+ G_CAUSE_EXC((uint32_t)info
[XCP0_CAUSE
])*9);
183 xprintf(" RA=%016llX, VAddr=%016llX\n",
184 info
[XGR_RA
],info
[XCP0_VADDR
]);
186 for (idx
= 0;idx
< 32; idx
+= 2) {
187 xprintf(" %2s ($%2d) = %016llX %2s ($%2d) = %016llX\n",
189 idx
,info
[XGR_ZERO
+idx
],
190 regnames
+((idx
+1)*2),
191 idx
+1,info
[XGR_ZERO
+idx
+1]);
199 #if !CFG_BOOTRAM && CFG_RUNFROMKSEG0
200 /* *********************************************************************
201 * exc_setup_hw_vector(vecoffset,target,k0code)
203 * Install a patch of code at the specified offset in low
204 * KSEG0 memory that will jump to 'target' and load k0
205 * with the specified code value. This is used when we
206 * run with RAM vectors.
209 * vecoffset - offset into KSEG0
210 * target - location where we should branch when vector is called
211 * k0code - value to load into K0 before branching
215 ********************************************************************* */
217 static void exc_setup_hw_vector(uint32_t vecoffset
,
223 uint32_t lower
,upper
;
225 new = (uint32_t) (intptr_t) target
; /* warning: assumes compatibility addresses! */
227 lower
= new & 0xffff;
228 upper
= (new >> 16) & 0xffff;
229 if ((lower
& 0x8000) != 0) {
234 * Get a KSEG0 version of the vector offset.
236 vec
= (uint32_t *) PHYS_TO_K0(vecoffset
);
239 * Patch in the vector. Note that we have to flush
240 * the L1 Dcache and invalidate the L1 Icache before
244 vec
[0] = 0x3c1b0000 | upper
; /* lui k1, HIGH(new) */
245 vec
[1] = 0x277b0000 | lower
; /* addiu k1, k1, LOW(new) */
246 vec
[2] = 0x03600008; /* jr k1 */
247 vec
[3] = 0x241a0000 | k0code
; /* li k0, code */
252 /* *********************************************************************
253 * exc_install_ram_vectors()
255 * Install all of the hardware vectors into low memory,
256 * flush the cache, and clear the BEV bit so we can start
264 ********************************************************************* */
266 static void exc_install_ram_vectors(void)
271 /* Debug: blow away the vector area so we can see what we did */
272 ptr
= (uint32_t *) PHYS_TO_K0(0);
273 for (idx
= 0; idx
< 0x1000/sizeof(uint32_t); idx
++) *ptr
++ = 0;
276 * Set up the vectors. The cache error handler is set up
280 exc_setup_hw_vector(MIPS_RAM_VEC_TLBFILL
, CPUCFG_TLBHANDLER
,XTYPE_TLBFILL
);
281 exc_setup_hw_vector(MIPS_RAM_VEC_XTLBFILL
, _exc_entry
,XTYPE_XTLBFILL
);
282 exc_setup_hw_vector(MIPS_RAM_VEC_CACHEERR
, _exc_entry
,XTYPE_CACHEERR
);
283 exc_setup_hw_vector(MIPS_RAM_VEC_EXCEPTION
,_exc_entry
,XTYPE_EXCEPTION
);
284 exc_setup_hw_vector(MIPS_RAM_VEC_INTERRUPT
,_exc_entry
,XTYPE_INTERRUPT
);
287 * Flush the D-cache and invalidate the I-cache so we can start
288 * using these vectors.
291 cfe_flushcache(CFE_CACHE_FLUSH_D
| CFE_CACHE_INVAL_I
,0,0);
294 * Write the handle into our low memory space. If we need to save
295 * other stuff down there, this is a good place to do it.
296 * This call uses uncached writes - we have not touched the
297 * memory in the handlers just yet, so they should not be
301 _exc_setup_locore((intptr_t) CPUCFG_CERRHANDLER
);
304 * Finally, clear BEV so we'll use the vectors in RAM.
307 _setstatus(_getstatus() & ~M_SR_BEV
);
312 /* *********************************************************************
313 * cfe_setup_exceptions()
315 * Set up the exception handlers.
322 ********************************************************************* */
323 void cfe_setup_exceptions(void)
325 _exc_setvector(XTYPE_TLBFILL
, (void *) cfe_exception
);
326 _exc_setvector(XTYPE_XTLBFILL
, (void *) cfe_exception
);
327 _exc_setvector(XTYPE_CACHEERR
, (void *) _exc_cache_crash_sim
);
328 _exc_setvector(XTYPE_EXCEPTION
,(void *) cfe_exception
);
329 _exc_setvector(XTYPE_INTERRUPT
,(void *) cfe_exception
);
330 _exc_setvector(XTYPE_EJTAG
, (void *) cfe_exception
);
332 exc_handler
.catch_exc
= 0;
333 q_init( &(exc_handler
.jmpbuf_stack
));
335 #if !CFG_BOOTRAM && CFG_RUNFROMKSEG0
337 * Install RAM vectors, and clear the BEV bit in the status
338 * register. Don't do this if we're running from PromICE RAM
340 exc_install_ram_vectors();
346 /* *********************************************************************
347 * exc_initialize_block()
349 * Set up the exception handler. Allow exceptions to be caught.
350 * Allocate memory for jmpbuf and store it away.
352 * Returns NULL if error in memory allocation.
358 * jmpbuf_t structure, or NULL if no memory
359 ********************************************************************* */
360 jmpbuf_t
*exc_initialize_block(void)
362 jmpbuf_t
*jmpbuf_local
;
364 exc_handler
.catch_exc
= 1;
366 /* Create the jmpbuf_t object */
367 jmpbuf_local
= (jmpbuf_t
*) KMALLOC((sizeof(jmpbuf_t
)),0);
369 if (jmpbuf_local
== NULL
) {
373 q_enqueue( &(exc_handler
.jmpbuf_stack
), &((*jmpbuf_local
).stack
));
378 /* *********************************************************************
379 * exc_cleanup_block(dq_jmpbuf)
381 * Remove dq_jmpbuf from the exception handler stack and free
385 * dq_jmpbuf - block to deallocate
389 ********************************************************************* */
391 void exc_cleanup_block(jmpbuf_t
*dq_jmpbuf
)
395 if (dq_jmpbuf
== NULL
) {
399 count
= q_count( &(exc_handler
.jmpbuf_stack
));
402 q_dequeue( &(*dq_jmpbuf
).stack
);
407 /* *********************************************************************
408 * exc_cleanup_handler(dq_jmpbuf,chain_exc)
410 * Clean a block, then chain to the next exception if required.
413 * dq_jmpbuf - current exception
414 * chain_exc - true if we should chain to the next handler
418 ********************************************************************* */
420 void exc_cleanup_handler(jmpbuf_t
*dq_jmpbuf
, int chain_exc
)
422 exc_cleanup_block(dq_jmpbuf
);
424 if( chain_exc
== EXC_CHAIN_EXC
) {
425 /*Go to next exception on stack */
426 exc_longjmp_handler();
432 /* *********************************************************************
433 * exc_longjmp_handler()
435 * This routine long jumps to the exception handler on the top
436 * of the exception stack.
443 ********************************************************************* */
444 void exc_longjmp_handler(void)
447 jmpbuf_t
*jmpbuf_local
;
449 count
= q_count( &(exc_handler
.jmpbuf_stack
));
452 jmpbuf_local
= (jmpbuf_t
*) q_getlast(&(exc_handler
.jmpbuf_stack
));
456 lib_longjmp( (*jmpbuf_local
).jmpbuf
, -1);
461 /* *********************************************************************
462 * mem_peek(d,addr,type)
464 * Read memory of the specified type at the specified address.
465 * Exceptions are caught in the case of a bad memory reference.
468 * d - pointer to where data should be placed
469 * addr - address to read
470 * type - type of read to do (MEM_BYTE, etc.)
475 ********************************************************************* */
477 int mem_peek(void *d
, long addr
, int type
)
482 jb
= exc_initialize_block();
484 return CFE_ERR_NOMEM
;
487 if (exc_try(jb
) == 0) {
491 *(uint8_t *)d
= *((volatile uint8_t *) addr
);
494 *(uint16_t *)d
= *((volatile uint16_t *) addr
);
497 *(uint32_t *)d
= *((volatile uint32_t *) addr
);
500 *(uint64_t *)d
= *((volatile uint64_t *) addr
);
503 return CFE_ERR_INV_PARAM
;
506 exc_cleanup_block(jb
);
509 /*Exception handler*/
511 exc_cleanup_handler(jb
, EXC_NORMAL_RETURN
);
512 return CFE_ERR_GETMEM
;
518 /* *********************************************************************
519 * Write memory of type at address addr with value val.
520 * Exceptions are caught, handled (error message) and function
525 ********************************************************************* */
527 int mem_poke(long addr
, uint64_t val
, int type
)
532 jb
= exc_initialize_block();
534 return CFE_ERR_NOMEM
;
537 if (exc_try(jb
) == 0) {
541 *((volatile uint8_t *) addr
) = (uint8_t) val
;
544 *((volatile uint16_t *) addr
) = (uint16_t) val
;
547 *((volatile uint32_t *) addr
) = (uint32_t) val
;
550 *((volatile uint64_t *) addr
) = (uint64_t) val
;
553 return CFE_ERR_INV_PARAM
;
556 exc_cleanup_block(jb
);
559 /*Exception handler*/
561 exc_cleanup_handler(jb
, EXC_NORMAL_RETURN
);
562 return CFE_ERR_SETMEM
;