source: rtems/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c @ 59a4066

4.104.114.95
Last change on this file since 59a4066 was 59a4066, checked in by Till Straumann <strauman@…>, on 12/11/07 at 05:18:06

2007-12-10 Till Straumann <strauman@…>

  • new-exceptions/bspsupport/README, new-exceptions/bspsupport/ppc_exc_bspsupp.h new-exceptions/bspsupport/vectors_init.c: added crude test to make sure MMU maps memory as write-back enabled.
  • Property mode set to 100644
File size: 11.1 KB
Line 
1/*
2 * vectors_init.c Exception hanlding initialisation (and generic handler).
3 *
4 *  This include file describe the data structure and the functions implemented
5 *  by rtems to handle exceptions.
6 *
7 *  CopyRight (C) 1999 valette@crf.canon.fr
8 *
9 *  The license and distribution terms for this file may be
10 *  found in found in the file LICENSE in this distribution or at
11 *  http://www.rtems.com/license/LICENSE.
12 *
13 *  $Id$
14 */
15#include <rtems.h>
16#include <rtems/bspIo.h>
17#include <rtems/error.h>
18
19#include <libcpu/raw_exception.h>
20#include <libcpu/spr.h>
21#include <libcpu/cpuIdent.h>
22
23#include "vectors.h"
24#include "ppc_exc_bspsupp.h"
25
26static rtems_raw_except_global_settings exception_config;
27static rtems_raw_except_connect_data    exception_table[LAST_VALID_EXC + 1];
28
29uint32_t ppc_exc_cache_wb_check = 1;
30
31#if 0
32typedef struct ppc_exc_connect_data_ {
33        rtems_raw_except_connect_data   raw;
34        ppc_exc_handler_t                               c_hdl;                 
35} ppc_exc_connect_data;
36#endif
37
38exception_handler_t globalExceptHdl;
39
40/* T. Straumann: provide a stack trace
41 * <strauman@slac.stanford.edu>, 6/26/2001
42 */
43typedef struct LRFrameRec_ {
44        struct LRFrameRec_ *frameLink;
45        unsigned long *lr;
46} LRFrameRec, *LRFrame;
47
48#define STACK_CLAMP 50  /* in case we have a corrupted bottom */
49
50SPR_RO(LR)
51SPR_RO(DAR)
52#define DEAR_BOOKE 61
53#define DEAR_405   0x3d5
54SPR_RO(DEAR_BOOKE)
55SPR_RO(DEAR_405)
56
57uint32_t ppc_exc_get_DAR_dflt()
58{
59        if ( ppc_cpu_is_60x() )
60                return _read_DAR();
61        else switch ( ppc_cpu_is_bookE() ) {
62                default: break;
63                case PPC_BOOKE_STD:
64                case PPC_BOOKE_E500:
65                        return _read_DEAR_BOOKE();
66                case PPC_BOOKE_405:
67                        return _read_DEAR_405();
68        }
69        return 0xdeadbeef;
70}
71
72uint32_t (*ppc_exc_get_DAR)() = ppc_exc_get_DAR_dflt;
73
74void
75BSP_printStackTrace(BSP_Exception_frame* excPtr)
76{
77LRFrame f;
78int             i;
79LRFrame sp;
80void    *lr;
81
82        printk("Stack Trace: \n  ");
83        if (excPtr) {
84                printk("IP: 0x%08x, ",excPtr->EXC_SRR0);
85                sp=(LRFrame)excPtr->GPR1;
86                lr=(void*)excPtr->EXC_LR;
87        } else {
88                /* there's no macro for this */
89                __asm__ __volatile__("mr %0, 1":"=r"(sp));
90                lr=(LRFrame)_read_LR();
91        }
92        printk("LR: 0x%08x\n",lr);
93        for (f=(LRFrame)sp, i=0; f->frameLink && i<STACK_CLAMP; f=f->frameLink) {
94                printk("--^ 0x%08x", (long)(f->frameLink->lr));
95                if (!(++i%5))
96                        printk("\n");
97        }
98        if (i>=STACK_CLAMP) {
99                printk("Too many stack frames (stack possibly corrupted), giving up...\n");
100        } else {
101                if (i%5)
102                        printk("\n");
103        }
104}
105
106void C_exception_handler(BSP_Exception_frame* excPtr)
107{
108  int recoverable = 0;
109  int synch       = (int)excPtr->_EXC_number >= 0 ;
110  unsigned n      = excPtr->_EXC_number & 0x7fff;
111
112  printk("Exception handler called for exception %d (0x%x)\n", n, n);
113  printk("\t Next PC or Address of fault = %08x\n", excPtr->EXC_SRR0);
114  printk("\t Saved MSR = %08x\n", excPtr->EXC_SRR1);
115  printk("\t R0  = %08x", excPtr->GPR0);
116  if ( synch ) {
117    printk(" R1  = %08x", excPtr->GPR1);
118    printk(" R2  = %08x", excPtr->GPR2);
119  } else {
120    printk("              ");
121    printk("              ");
122  }
123  printk(" R3  = %08x\n", excPtr->GPR3);
124  printk("\t R4  = %08x", excPtr->GPR4);
125  printk(" R5  = %08x",   excPtr->GPR5);
126  printk(" R6  = %08x",   excPtr->GPR6);
127  printk(" R7  = %08x\n", excPtr->GPR7);
128  printk("\t R8  = %08x", excPtr->GPR8);
129  printk(" R9  = %08x",   excPtr->GPR9);
130  printk(" R10 = %08x",   excPtr->GPR10);
131  printk(" R11 = %08x\n", excPtr->GPR11);
132  printk("\t R12 = %08x", excPtr->GPR12);
133  if ( synch ) {
134          printk(" R13 = %08x",   excPtr->GPR13);
135          printk(" R14 = %08x",   excPtr->GPR14);
136          printk(" R15 = %08x\n", excPtr->GPR15);
137          printk("\t R16 = %08x", excPtr->GPR16);
138          printk(" R17 = %08x",   excPtr->GPR17);
139          printk(" R18 = %08x",   excPtr->GPR18);
140          printk(" R19 = %08x\n", excPtr->GPR19);
141          printk("\t R20 = %08x", excPtr->GPR20);
142          printk(" R21 = %08x",   excPtr->GPR21);
143          printk(" R22 = %08x",   excPtr->GPR22);
144          printk(" R23 = %08x\n", excPtr->GPR23);
145          printk("\t R24 = %08x", excPtr->GPR24);
146          printk(" R25 = %08x",   excPtr->GPR25);
147          printk(" R26 = %08x",   excPtr->GPR26);
148          printk(" R27 = %08x\n", excPtr->GPR27);
149          printk("\t R28 = %08x", excPtr->GPR28);
150          printk(" R29 = %08x",   excPtr->GPR29);
151          printk(" R30 = %08x",   excPtr->GPR30);
152          printk(" R31 = %08x\n", excPtr->GPR31);
153  } else {
154      printk("\n");
155  }
156  printk("\t CR  = %08x\n", excPtr->EXC_CR);
157  printk("\t CTR = %08x\n", excPtr->EXC_CTR);
158  printk("\t XER = %08x\n", excPtr->EXC_XER);
159  printk("\t LR  = %08x\n", excPtr->EXC_LR);
160
161  /* Would be great to print DAR but unfortunately,
162   * that is not portable across different CPUs.
163   * AFAIK on classic PPC DAR is SPR 19, on the
164   * 405 we have DEAR = SPR 0x3d5 and booE says
165   * DEAR = SPR 61 :-(
166   */
167  if ( ppc_exc_get_DAR ) {
168        printk("\t DAR = %08x\n",  ppc_exc_get_DAR());
169  }
170
171  BSP_printStackTrace(excPtr);
172
173  if (excPtr->_EXC_number == ASM_DEC_VECTOR)
174       recoverable = 1;
175  if (excPtr->_EXC_number == ASM_SYS_VECTOR)
176#ifdef TEST_RAW_EXCEPTION_CODE
177    recoverable = 1;
178#else
179    recoverable = 0;
180#endif
181    if (!recoverable) {
182      printk("unrecoverable exception!!! Push reset button\n");
183      while(1);
184    }
185}
186
187/***********************************************************
188 * dummy functions for on/off/isOn calls
189 * these functions just do nothing fulfill the semantic
190 * requirements to enable/disable a certain exception
191 */
192void exception_nop_enable(const rtems_raw_except_connect_data* ptr)
193{
194}
195
196int exception_always_enabled(const rtems_raw_except_connect_data* ptr)
197{
198  return 1;
199}
200
201/* Raw exception framework wants to keep a pointer to
202 * the prologue so we must keep the ones we generate
203 * from templates around...
204 */
205#define NUM_PROLOG      8       /* just a reasonable limit */
206static int                  n_prolog = 0;
207static ppc_exc_min_prolog_t prologues[NUM_PROLOG];
208
209static ppc_exc_min_prolog_template_t prolog_templates[][2] = {
210        [ PPC_EXC_CLASSIC ] =
211                {
212                ppc_exc_min_prolog_sync_tmpl_std,
213                ppc_exc_min_prolog_async_tmpl_std,
214                },
215        [ PPC_EXC_405_CRITICAL ] =
216                {
217                ppc_exc_min_prolog_sync_tmpl_p405_crit,
218                ppc_exc_min_prolog_async_tmpl_p405_crit,
219                },
220        [ PPC_EXC_BOOKE_CRITICAL ] =
221                {
222                ppc_exc_min_prolog_sync_tmpl_bookE_crit,
223                ppc_exc_min_prolog_async_tmpl_bookE_crit,
224                },
225        [ PPC_EXC_E500_MACHCHK ] =
226                {
227                ppc_exc_min_prolog_sync_tmpl_e500_mchk,
228                ppc_exc_min_prolog_async_tmpl_e500_mchk,
229                },
230};
231
232static rtems_raw_except_func
233make_prologue(int vector, ppc_raw_exception_category cat)
234{
235int                           async = (cat & PPC_EXC_ASYNC) ? 1 : 0 ;
236ppc_exc_min_prolog_template_t tmpl;
237
238        cat &= ~PPC_EXC_ASYNC;
239
240        if ( n_prolog >= NUM_PROLOG ) {
241                rtems_panic("Not enough exception prologue slots; increase NUM_PROLOG (%s)\n",__FILE__);
242        }
243
244        if ( ! (tmpl = prolog_templates[cat][async]) ) {
245                rtems_panic("No exception prologue template for category 0x%02x found\n", cat);
246        }
247
248        ppc_exc_min_prolog_expand(prologues[n_prolog], tmpl, vector);
249
250        return (rtems_raw_except_func)prologues[n_prolog++];
251}
252
253void ppc_exc_init(
254        rtems_raw_except_connect_data    *exception_table,
255        int                               nEntries)
256{
257int i,v;
258ppc_raw_exception_category cat;
259uintptr_t vaddr;
260
261        /*
262         * Initialize pointer used by low level execption handling
263         */
264        globalExceptHdl                                 = C_exception_handler;
265        /*
266         * Put  default_exception_vector_code_prolog at relevant exception
267         * code entry addresses
268         */
269        exception_config.exceptSize                     = nEntries;
270        exception_config.rawExceptHdlTbl                = exception_table;
271        exception_config.defaultRawEntry.exceptIndex    = 0;
272        exception_config.defaultRawEntry.hdl.vector     = 0;
273        /* Note that the 'auto' handler cannot be used for everything; in particular,
274         * it assumes classic exceptions with a vector offset aligned on a 256-byte
275         * boundary.
276         */
277        exception_config.defaultRawEntry.hdl.raw_hdl    = ppc_exc_min_prolog_auto;
278
279        /*
280         * Note that the cast of an array address to an unsigned
281         * is not a bug as it is defined by a .set directly in asm...
282         */
283        exception_config.defaultRawEntry.hdl.raw_hdl_size = (unsigned)ppc_exc_min_prolog_size;
284
285        for (i=0; i < exception_config.exceptSize; i++) {
286
287                if ( PPC_EXC_INVALID == (cat = ppc_vector_is_valid ((v=exception_table[i].hdl.vector))) ) {
288                        continue;
289                }
290
291                exception_table[i].exceptIndex  = i;
292                exception_table[v].hdl.raw_hdl_size = (unsigned)ppc_exc_min_prolog_size;
293
294                /* special cases */
295                if ( ppc_cpu_has_shadowed_gprs()
296                                && (   ASM_60X_IMISS_VECTOR  == v
297                                        || ASM_60X_DLMISS_VECTOR == v
298                                        || ASM_60X_DSMISS_VECTOR == v ) ) {
299                        exception_table[i].hdl.raw_hdl    = ppc_exc_tgpr_clr_prolog;
300                        exception_table[i].hdl.raw_hdl_size = (unsigned)ppc_exc_tgpr_clr_prolog_size;
301                } else {
302
303                        vaddr = (uintptr_t)ppc_get_vector_addr( v );
304
305                        /*
306                         * default prolog can handle classic, synchronous exceptions
307                         * with a vector offset aligned on a 256-byte boundary.
308                         */
309                        if ( PPC_EXC_CLASSIC == cat && 0 == ( vaddr & 0xff ) ) {
310                                exception_table[i].hdl.raw_hdl_size = exception_config.defaultRawEntry.hdl.raw_hdl_size;
311                                exception_table[i].hdl.raw_hdl      = exception_config.defaultRawEntry.hdl.raw_hdl;
312                        } else {
313                                exception_table[i].hdl.raw_hdl_size = (unsigned)ppc_exc_min_prolog_size;
314                                exception_table[i].hdl.raw_hdl      = make_prologue( v, cat );
315                        }
316
317                }
318                exception_table[i].on           = exception_nop_enable;
319                exception_table[i].off          = exception_nop_enable;
320                exception_table[i].isOn         = exception_always_enabled;
321        }
322        if (!ppc_init_exceptions(&exception_config)) {
323                BSP_panic("Exception handling initialization failed\n");
324        }
325#ifdef RTEMS_DEBUG
326        else {
327                printk("Exception handling initialization done\n");
328        }
329#endif
330}
331
332void initialize_exceptions()
333{
334int i;
335int n = sizeof(exception_table)/sizeof(exception_table[0]);
336
337        /* Use current MMU / RI settings when running C exception handlers */
338        ppc_exc_msr_bits = _read_MSR() & ( MSR_DR | MSR_IR | MSR_RI );
339
340        /* Copy into a SDA variable that is easy to access from
341         * assembly code
342         */
343        if ( ppc_cpu_is_bookE() ) {
344                ppc_exc_msr_irq_mask = MSR_EE | MSR_CE | MSR_DE ;
345        } else {
346                ppc_exc_msr_irq_mask = MSR_EE ;
347        }
348
349        for ( i=0; i<n; i++ )
350                exception_table[i].hdl.vector = i;
351        ppc_exc_init(exception_table, n);
352
353        /* If we are on a classic PPC with MSR_DR enabled then
354         * assert that the mapping for at least this task's
355         * stack is write-back-caching enabled (see README/CAVEATS)
356         * Do this only if the cache is physically enabled.
357         * Since it is not easy to figure that out in a
358         * generic way we need help from the BSP: BSPs
359         * which run entirely w/o the cache may set
360         * ppc_exc_cache_wb_check to zero prior to calling
361         * this routine.
362         *
363         * We run this check only after exception handling is
364         * initialized so that we have some chance to get
365         * information printed if it fails.
366         *
367         * Note that it is unsafe to ignore this issue; if
368         * the check fails, do NOT disable it unless caches
369         * are always physically disabled.
370         */
371        if ( ppc_exc_cache_wb_check && (MSR_DR & ppc_exc_msr_bits) ) {
372                /* The size of 63 assumes cache lines are at most 32 bytes */
373                uint8_t   dummy[63];
374                uintptr_t p = (uintptr_t)dummy;
375                /* If the dcbz instruction raises an alignment exception
376                 * then the stack is mapped as write-thru or caching-disabled.
377                 * The low-level code is not capable of dealing with this
378                 * ATM.
379                 */
380                p = (p + 31) & ~31;
381                asm volatile("dcbz 0, %0"::"b"(p));
382                /* If we make it thru here then things seem to be OK */
383        }
384
385}
Note: See TracBrowser for help on using the repository browser.