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