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

4.104.114.95
Last change on this file since 25a92bc1 was 25a92bc1, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 07/11/08 at 10:02:12

adapted powerpc exception code

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