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) 11 * 12 ********************************************************************* 13 * 14 * Copyright 2000,2001,2002,2003 15 * Broadcom Corporation. All rights reserved. 16 * 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. 23 * 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. 27 * 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. 33 * 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 ********************************************************************* */ 48 49 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" 63 64/* ********************************************************************* 65 * Constants 66 ********************************************************************* */ 67 68/* 69 * Temporary until all our CPU packages support a cache error handler 70 */ 71 72#ifndef CPUCFG_CERRHANDLER 73#define CPUCFG_CERRHANDLER 0xBFC00000 74#else 75extern void CPUCFG_CERRHANDLER(void); 76#endif 77 78/* ********************************************************************* 79 * Globals 80 ********************************************************************* */ 81 82exc_handler_t exc_handler; 83extern void _exc_entry(void); 84extern void _exc_setup_locore(long); 85extern void CPUCFG_TLBHANDLER(void); 86extern void cfe_flushcache(uint32_t,long,long); 87extern uint32_t _getstatus(void); 88extern void _setstatus(uint32_t); 89 90static const char *regnames = "0 ATv0v1a0a1a2a3t0t1t2t3t4t5t6t7" 91 "s0s1s2s3s4s5s6s7t8t9k0k1gpspfpra"; 92static 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 */ 125 126 127 128/* ********************************************************************* 129 * cfe_exception(code,info) 130 * 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. 135 * 136 * Input parameters: 137 * code - exception type 138 * info - exception stack frame 139 * 140 * Return value: 141 * usually reboots 142 ********************************************************************* */ 143 144void cfe_exception(int code,uint64_t *info) 145{ 146 int idx; 147 148 SETLEDS("EXC!"); 149 150 if(exc_handler.catch_exc == 1) { 151 /*Deal with exception without restarting CFE.*/ 152 153 /*Clear relevant SR bits*/ 154 _exc_clear_sr_exl(); 155 _exc_clear_sr_erl(); 156 157 /*Reset flag*/ 158 exc_handler.catch_exc = 0; 159 160 exc_longjmp_handler(); 161 } 162 163 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]); 178 } 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]); 192 } 193#endif 194 195 xprintf("\n"); 196 _exc_restart(); 197} 198 199#if (!CFG_BOOTRAM) && (CFG_RUNFROMKSEG0) 200/* ********************************************************************* 201 * exc_setup_hw_vector(vecoffset,target,k0code) 202 * 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. 207 * 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 212 * 213 * Return value: 214 * nothing 215 ********************************************************************* */ 216 217static void exc_setup_hw_vector(uint32_t vecoffset, 218 void *target, 219 uint32_t k0code) 220{ 221 uint32_t *vec; 222 uint32_t new; 223 uint32_t lower,upper; 224 225 new = (uint32_t) (intptr_t) target; /* warning: assumes compatibility addresses! */ 226 227 lower = new & 0xffff; 228 upper = (new >> 16) & 0xffff; 229 if ((lower & 0x8000) != 0) { 230 upper++; 231 } 232 233 /* 234 * Get a KSEG0 version of the vector offset. 235 */ 236 vec = (uint32_t *) PHYS_TO_K0(vecoffset); 237 238 /* 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. 242 */ 243 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 */ 248 249} 250 251 252/* ********************************************************************* 253 * exc_install_ram_vectors() 254 * 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. 258 * 259 * Input parameters: 260 * nothing 261 * 262 * Return value: 263 * nothing 264 ********************************************************************* */ 265 266static void exc_install_ram_vectors(void) 267{ 268 uint32_t *ptr; 269 int idx; 270 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; 274 275 /* 276 * Set up the vectors. The cache error handler is set up 277 * specially. 278 */ 279 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); 285 286 /* 287 * Flush the D-cache and invalidate the I-cache so we can start 288 * using these vectors. 289 */ 290 291 cfe_flushcache(CFE_CACHE_FLUSH_D | CFE_CACHE_INVAL_I,0,0); 292 293 /* 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. 299 */ 300 301 _exc_setup_locore((intptr_t) CPUCFG_CERRHANDLER); 302 303 /* 304 * Finally, clear BEV so we'll use the vectors in RAM. 305 */ 306 307 _setstatus(_getstatus() & ~M_SR_BEV); 308 309} 310#endif 311 312/* ********************************************************************* 313 * cfe_setup_exceptions() 314 * 315 * Set up the exception handlers. 316 * 317 * Input parameters: 318 * nothing 319 * 320 * Return value: 321 * nothing 322 ********************************************************************* */ 323void cfe_setup_exceptions(void) 324{ 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); 331 332 exc_handler.catch_exc = 0; 333 q_init( &(exc_handler.jmpbuf_stack)); 334 335#if (!CFG_BOOTRAM) && (CFG_RUNFROMKSEG0) 336 /* 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 339 */ 340 exc_install_ram_vectors(); 341#endif 342} 343 344 345 346/* ********************************************************************* 347 * exc_initialize_block() 348 * 349 * Set up the exception handler. Allow exceptions to be caught. 350 * Allocate memory for jmpbuf and store it away. 351 * 352 * Returns NULL if error in memory allocation. 353 * 354 * Input parameters: 355 * nothing 356 * 357 * Return value: 358 * jmpbuf_t structure, or NULL if no memory 359 ********************************************************************* */ 360jmpbuf_t *exc_initialize_block(void) 361{ 362 jmpbuf_t *jmpbuf_local; 363 364 exc_handler.catch_exc = 1; 365 366 /* Create the jmpbuf_t object */ 367 jmpbuf_local = (jmpbuf_t *) KMALLOC((sizeof(jmpbuf_t)),0); 368 369 if (jmpbuf_local == NULL) { 370 return NULL; 371 } 372 373 q_enqueue( &(exc_handler.jmpbuf_stack), &((*jmpbuf_local).stack)); 374 375 return jmpbuf_local; 376} 377 378/* ********************************************************************* 379 * exc_cleanup_block(dq_jmpbuf) 380 * 381 * Remove dq_jmpbuf from the exception handler stack and free 382 * the memory. 383 * 384 * Input parameters: 385 * dq_jmpbuf - block to deallocate 386 * 387 * Return value: 388 * nothing 389 ********************************************************************* */ 390 391void exc_cleanup_block(jmpbuf_t *dq_jmpbuf) 392{ 393 int count; 394 395 if (dq_jmpbuf == NULL) { 396 return; 397 } 398 399 count = q_count( &(exc_handler.jmpbuf_stack)); 400 401 if( count > 0 ) { 402 q_dequeue( &(*dq_jmpbuf).stack ); 403 KFREE(dq_jmpbuf); 404 } 405} 406 407/* ********************************************************************* 408 * exc_cleanup_handler(dq_jmpbuf,chain_exc) 409 * 410 * Clean a block, then chain to the next exception if required. 411 * 412 * Input parameters: 413 * dq_jmpbuf - current exception 414 * chain_exc - true if we should chain to the next handler 415 * 416 * Return value: 417 * nothing 418 ********************************************************************* */ 419 420void exc_cleanup_handler(jmpbuf_t *dq_jmpbuf, int chain_exc) 421{ 422 exc_cleanup_block(dq_jmpbuf); 423 424 if( chain_exc == EXC_CHAIN_EXC ) { 425 /*Go to next exception on stack */ 426 exc_longjmp_handler(); 427 } 428} 429 430 431 432/* ********************************************************************* 433 * exc_longjmp_handler() 434 * 435 * This routine long jumps to the exception handler on the top 436 * of the exception stack. 437 * 438 * Input parameters: 439 * nothing 440 * 441 * Return value: 442 * nothing 443 ********************************************************************* */ 444void exc_longjmp_handler(void) 445{ 446 int count; 447 jmpbuf_t *jmpbuf_local; 448 449 count = q_count( &(exc_handler.jmpbuf_stack)); 450 451 if( count > 0 ) { 452 jmpbuf_local = (jmpbuf_t *) q_getlast(&(exc_handler.jmpbuf_stack)); 453 454 SETLEDS("CFE "); 455 456 lib_longjmp( (*jmpbuf_local).jmpbuf, -1); 457 } 458} 459 460 461/* ********************************************************************* 462 * mem_peek(d,addr,type) 463 * 464 * Read memory of the specified type at the specified address. 465 * Exceptions are caught in the case of a bad memory reference. 466 * 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.) 471 * 472 * Return value: 473 * 0 if ok 474 * else error code 475 ********************************************************************* */ 476 477int mem_peek(void *d, long addr, int type) 478{ 479 480 jmpbuf_t *jb; 481 482 jb = exc_initialize_block(); 483 if( jb == NULL ) { 484 return CFE_ERR_NOMEM; 485 } 486 487 if (exc_try(jb) == 0) { 488 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; 504 } 505 506 exc_cleanup_block(jb); 507 } 508 else { 509 /*Exception handler*/ 510 511 exc_cleanup_handler(jb, EXC_NORMAL_RETURN); 512 return CFE_ERR_GETMEM; 513 } 514 515 return 0; 516} 517 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. 522 * 523 * 1 success 524 * 0 failure 525 ********************************************************************* */ 526 527int mem_poke(long addr, uint64_t val, int type) 528{ 529 530 jmpbuf_t *jb; 531 532 jb = exc_initialize_block(); 533 if( jb == NULL ) { 534 return CFE_ERR_NOMEM; 535 } 536 537 if (exc_try(jb) == 0) { 538 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; 554 } 555 556 exc_cleanup_block(jb); 557 } 558 else { 559 /*Exception handler*/ 560 561 exc_cleanup_handler(jb, EXC_NORMAL_RETURN); 562 return CFE_ERR_SETMEM; 563 } 564 565 return 0; 566} 567 568 569 570 571 572 573 574 575 576 577