allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / cfe / cfe / arch / mips / common / src / exchandler.c
blob452c84d1627028acc38994d6541c8092b471bfcd
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * Exception Handler File: exchandler.c
5 *
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.
9 *
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 ********************************************************************* */
50 #include "sbmips.h"
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"
57 #include "cfe.h"
58 #include "cfe_error.h"
59 #include "cfe_iocb.h"
60 #include "exchandler.h"
61 #include "cpu_config.h"
62 #include "bsp_config.h"
64 /* *********************************************************************
65 * Constants
66 ********************************************************************* */
68 /*
69 * Temporary until all our CPU packages support a cache error handler
72 #ifndef CPUCFG_CERRHANDLER
73 #define CPUCFG_CERRHANDLER 0xBFC00000
74 #else
75 extern void CPUCFG_CERRHANDLER(void);
76 #endif
78 /* *********************************************************************
79 * Globals
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 =
93 "Interrupt" /* 0 */
94 "TLBMod " /* 1 */
95 "TLBMissRd" /* 2 */
96 "TLBMissWr" /* 3 */
97 "AddrErrRd" /* 4 */
98 "AddrErrWr" /* 5 */
99 "BusErrRd " /* 6 */
100 "BusErrWr " /* 7 */
101 "Syscall " /* 8 */
102 "Breakpt " /* 9 */
103 "InvOpcode" /* 10 */
104 "CoProcUnu" /* 11 */
105 "ArithOvfl" /* 12 */
106 "TrapExc " /* 13 */
107 "VCEI " /* 14 */
108 "FPUExc " /* 15 */
109 "CP2Exc " /* 16 */
110 "Exc17 " /* 17 */
111 "Exc18 " /* 18 */
112 "Exc19 " /* 19 */
113 "Exc20 " /* 20 */
114 "Exc21 " /* 21 */
115 "Exc22 " /* 22 */
116 "Watchpt " /* 23 */
117 "Exc24 " /* 24 */
118 "Exc25 " /* 25 */
119 "Exc26 " /* 26 */
120 "Exc27 " /* 27 */
121 "Exc28 " /* 28 */
122 "Exc29 " /* 29 */
123 "Exc30 " /* 30 */
124 "VCED "; /* 31 */
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
134 * reboot.
136 * Input parameters:
137 * code - exception type
138 * info - exception stack frame
140 * Return value:
141 * usually reboots
142 ********************************************************************* */
144 void cfe_exception(int code,uint64_t *info)
146 int idx;
148 SETLEDS("EXC!");
150 if(exc_handler.catch_exc == 1) {
151 /*Deal with exception without restarting CFE.*/
153 /*Clear relevant SR bits*/
154 _exc_clear_sr_exl();
155 _exc_clear_sr_erl();
157 /*Reset flag*/
158 exc_handler.catch_exc = 0;
160 exc_longjmp_handler();
164 #ifdef _MIPSREGS32_
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]);
171 xprintf("\n");
172 for (idx = 0;idx < 32; idx+= 2) {
173 xprintf(" %2s ($%2d) = %08X %2s ($%2d) = %08X\n",
174 regnames+(idx*2),
175 idx,(uint32_t)info[XGR_ZERO+idx],
176 regnames+((idx+1)*2),
177 idx+1,(uint32_t)info[XGR_ZERO+idx+1]);
179 #else
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]);
185 xprintf("\n");
186 for (idx = 0;idx < 32; idx+= 2) {
187 xprintf(" %2s ($%2d) = %016llX %2s ($%2d) = %016llX\n",
188 regnames+(idx*2),
189 idx,info[XGR_ZERO+idx],
190 regnames+((idx+1)*2),
191 idx+1,info[XGR_ZERO+idx+1]);
193 #endif
195 xprintf("\n");
196 _exc_restart();
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.
208 * Input parameters:
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
213 * Return value:
214 * nothing
215 ********************************************************************* */
217 static void exc_setup_hw_vector(uint32_t vecoffset,
218 void *target,
219 uint32_t k0code)
221 uint32_t *vec;
222 uint32_t new;
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) {
230 upper++;
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
241 * we can use this.
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
257 * using them.
259 * Input parameters:
260 * nothing
262 * Return value:
263 * nothing
264 ********************************************************************* */
266 static void exc_install_ram_vectors(void)
268 uint32_t *ptr;
269 int idx;
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
277 * specially.
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
298 * in our caches.
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);
310 #endif
312 /* *********************************************************************
313 * cfe_setup_exceptions()
315 * Set up the exception handlers.
317 * Input parameters:
318 * nothing
320 * Return value:
321 * nothing
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();
341 #endif
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.
354 * Input parameters:
355 * nothing
357 * Return value:
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) {
370 return NULL;
373 q_enqueue( &(exc_handler.jmpbuf_stack), &((*jmpbuf_local).stack));
375 return jmpbuf_local;
378 /* *********************************************************************
379 * exc_cleanup_block(dq_jmpbuf)
381 * Remove dq_jmpbuf from the exception handler stack and free
382 * the memory.
384 * Input parameters:
385 * dq_jmpbuf - block to deallocate
387 * Return value:
388 * nothing
389 ********************************************************************* */
391 void exc_cleanup_block(jmpbuf_t *dq_jmpbuf)
393 int count;
395 if (dq_jmpbuf == NULL) {
396 return;
399 count = q_count( &(exc_handler.jmpbuf_stack));
401 if( count > 0 ) {
402 q_dequeue( &(*dq_jmpbuf).stack );
403 KFREE(dq_jmpbuf);
407 /* *********************************************************************
408 * exc_cleanup_handler(dq_jmpbuf,chain_exc)
410 * Clean a block, then chain to the next exception if required.
412 * Input parameters:
413 * dq_jmpbuf - current exception
414 * chain_exc - true if we should chain to the next handler
416 * Return value:
417 * nothing
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.
438 * Input parameters:
439 * nothing
441 * Return value:
442 * nothing
443 ********************************************************************* */
444 void exc_longjmp_handler(void)
446 int count;
447 jmpbuf_t *jmpbuf_local;
449 count = q_count( &(exc_handler.jmpbuf_stack));
451 if( count > 0 ) {
452 jmpbuf_local = (jmpbuf_t *) q_getlast(&(exc_handler.jmpbuf_stack));
454 SETLEDS("CFE ");
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.
467 * Input parameters:
468 * d - pointer to where data should be placed
469 * addr - address to read
470 * type - type of read to do (MEM_BYTE, etc.)
472 * Return value:
473 * 0 if ok
474 * else error code
475 ********************************************************************* */
477 int mem_peek(void *d, long addr, int type)
480 jmpbuf_t *jb;
482 jb = exc_initialize_block();
483 if( jb == NULL ) {
484 return CFE_ERR_NOMEM;
487 if (exc_try(jb) == 0) {
489 switch (type) {
490 case MEM_BYTE:
491 *(uint8_t *)d = *((volatile uint8_t *) addr);
492 break;
493 case MEM_HALFWORD:
494 *(uint16_t *)d = *((volatile uint16_t *) addr);
495 break;
496 case MEM_WORD:
497 *(uint32_t *)d = *((volatile uint32_t *) addr);
498 break;
499 case MEM_QUADWORD:
500 *(uint64_t *)d = *((volatile uint64_t *) addr);
501 break;
502 default:
503 return CFE_ERR_INV_PARAM;
506 exc_cleanup_block(jb);
508 else {
509 /*Exception handler*/
511 exc_cleanup_handler(jb, EXC_NORMAL_RETURN);
512 return CFE_ERR_GETMEM;
515 return 0;
518 /* *********************************************************************
519 * Write memory of type at address addr with value val.
520 * Exceptions are caught, handled (error message) and function
521 * returns with 0.
523 * 1 success
524 * 0 failure
525 ********************************************************************* */
527 int mem_poke(long addr, uint64_t val, int type)
530 jmpbuf_t *jb;
532 jb = exc_initialize_block();
533 if( jb == NULL ) {
534 return CFE_ERR_NOMEM;
537 if (exc_try(jb) == 0) {
539 switch (type) {
540 case MEM_BYTE:
541 *((volatile uint8_t *) addr) = (uint8_t) val;
542 break;
543 case MEM_HALFWORD:
544 *((volatile uint16_t *) addr) = (uint16_t) val;
545 break;
546 case MEM_WORD:
547 *((volatile uint32_t *) addr) = (uint32_t) val;
548 break;
549 case MEM_QUADWORD:
550 *((volatile uint64_t *) addr) = (uint64_t) val;
551 break;
552 default:
553 return CFE_ERR_INV_PARAM;
556 exc_cleanup_block(jb);
558 else {
559 /*Exception handler*/
561 exc_cleanup_handler(jb, EXC_NORMAL_RETURN);
562 return CFE_ERR_SETMEM;
565 return 0;