Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:53

0001 /**
0002  * @file
0003  *
0004  * @ingroup ppc_exc
0005  * @ingroup ppc_exc_frame
0006  *
0007  * @brief PowerPC Exceptions API.
0008  */
0009 
0010 /*
0011  * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr)
0012  *                    Canon Centre Recherche France.
0013  *
0014  * Copyright (C) 2007 Till Straumann <strauman@slac.stanford.edu>
0015  *
0016  * Copyright (C) 2009 embedded brains GmbH & Co. KG
0017  *
0018  * Enhanced by Jay Kulpinski <jskulpin@eng01.gdds.com>
0019  * to support 603, 603e, 604, 604e exceptions
0020  *
0021  * Moved to "libcpu/powerpc/new-exceptions" and consolidated
0022  * by Thomas Doerfler <Thomas.Doerfler@embedded-brains.de>
0023  * to be common for all PPCs with new exceptions.
0024  *
0025  * Derived from file "libcpu/powerpc/new-exceptions/raw_exception.h".
0026  * Derived from file "libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_bspsupp.h".
0027  *
0028  * The license and distribution terms for this file may be
0029  * found in the file LICENSE in this distribution or at
0030  * http://www.rtems.org/license/LICENSE.
0031  */
0032 
0033 /* DO NOT INTRODUCE #ifdef <cpu_flavor> in this file */
0034 
0035 #ifndef LIBCPU_VECTORS_H
0036 #define LIBCPU_VECTORS_H
0037 
0038 #include <bspopts.h>
0039 #include <rtems/score/cpuimpl.h>
0040 #include <libcpu/powerpc-utility.h>
0041 
0042 #ifdef __cplusplus
0043 extern "C" {
0044 #endif
0045 
0046 /**
0047  * @defgroup ppc_exc PowerPC Exceptions
0048  *
0049  * @ingroup RTEMSBSPsPowerPCShared
0050  *
0051  * @{
0052  */
0053 
0054 #define ASM_RESET_VECTOR                     0x01
0055 #define ASM_MACH_VECTOR                      0x02
0056 #define ASM_PROT_VECTOR                      0x03
0057 #define ASM_ISI_VECTOR                       0x04
0058 #define ASM_EXT_VECTOR                       0x05
0059 #define ASM_ALIGN_VECTOR                     0x06
0060 #define ASM_PROG_VECTOR                      0x07
0061 #define ASM_FLOAT_VECTOR                     0x08
0062 #define ASM_DEC_VECTOR                       0x09
0063 #define ASM_SYS_VECTOR                       0x0C
0064 #define ASM_TRACE_VECTOR                     0x0D
0065 
0066 #define ASM_PPC405_APU_UNAVAIL_VECTOR        ASM_60X_VEC_ASSIST_VECTOR
0067 
0068 #define ASM_8XX_FLOATASSIST_VECTOR           0x0E
0069 #define ASM_8XX_SOFTEMUL_VECTOR              0x10
0070 #define ASM_8XX_ITLBMISS_VECTOR              0x11
0071 #define ASM_8XX_DTLBMISS_VECTOR              0x12
0072 #define ASM_8XX_ITLBERROR_VECTOR             0x13
0073 #define ASM_8XX_DTLBERROR_VECTOR             0x14
0074 #define ASM_8XX_DBREAK_VECTOR                0x1C
0075 #define ASM_8XX_IBREAK_VECTOR                0x1D
0076 #define ASM_8XX_PERIFBREAK_VECTOR            0x1E
0077 #define ASM_8XX_DEVPORT_VECTOR               0x1F
0078 
0079 #define ASM_5XX_FLOATASSIST_VECTOR           0x0E
0080 #define ASM_5XX_SOFTEMUL_VECTOR              0x10
0081 #define ASM_5XX_IPROT_VECTOR                 0x13
0082 #define ASM_5XX_DPROT_VECTOR                 0x14
0083 #define ASM_5XX_DBREAK_VECTOR                0x1C
0084 #define ASM_5XX_IBREAK_VECTOR                0x1D
0085 #define ASM_5XX_MEBREAK_VECTOR               0x1E
0086 #define ASM_5XX_NMEBREAK_VECTOR              0x1F
0087 
0088 #define ASM_60X_VEC_VECTOR                   0x0A
0089 #define ASM_60X_PERFMON_VECTOR               0x0F
0090 #define ASM_60X_IMISS_VECTOR                 0x10
0091 #define ASM_60X_DLMISS_VECTOR                0x11
0092 #define ASM_60X_DSMISS_VECTOR                0x12
0093 #define ASM_60X_ADDR_VECTOR                  0x13
0094 #define ASM_60X_SYSMGMT_VECTOR               0x14
0095 #define ASM_60X_VEC_ASSIST_VECTOR            0x16
0096 #define ASM_60X_ITM_VECTOR                   0x17
0097 
0098 /* Book E */
0099 #define ASM_BOOKE_CRIT_VECTOR                0x01
0100 /* We could use the std. decrementer vector # on bookE, too,
0101  * but the bookE decrementer has slightly different semantics
0102  * so we use a different vector (which happens to be
0103  * the PIT vector on the 405 which is like the booke decrementer)
0104  */
0105 #define ASM_BOOKE_DEC_VECTOR                 0x10
0106 #define ASM_BOOKE_ITLBMISS_VECTOR            0x11
0107 #define ASM_BOOKE_DTLBMISS_VECTOR            0x12
0108 #define ASM_BOOKE_FIT_VECTOR                 0x13
0109 #define ASM_BOOKE_WDOG_VECTOR                0x14
0110 #define ASM_BOOKE_APU_VECTOR                 0x18
0111 #define ASM_BOOKE_DEBUG_VECTOR               ASM_TRACE_VECTOR
0112 
0113 /* e200 and e500 */
0114 #define ASM_E500_SPE_UNAVAILABLE_VECTOR      ASM_60X_VEC_VECTOR
0115 #define ASM_E500_EMB_FP_DATA_VECTOR          0x19
0116 #define ASM_E500_EMB_FP_ROUND_VECTOR         0x1A
0117 #define ASM_E500_PERFMON_VECTOR              ASM_60X_PERFMON_VECTOR
0118 
0119 /* e300 */
0120 #define ASM_E300_CRIT_VECTOR                 0x0A
0121 #define ASM_E300_PERFMON_VECTOR              ASM_60X_PERFMON_VECTOR
0122 #define ASM_E300_IMISS_VECTOR                ASM_60X_IMISS_VECTOR  /* Special case: Shadowed GPRs */
0123 #define ASM_E300_DLMISS_VECTOR               ASM_60X_DLMISS_VECTOR /* Special case: Shadowed GPRs */
0124 #define ASM_E300_DSMISS_VECTOR               ASM_60X_DSMISS_VECTOR /* Special case: Shadowed GPRs */
0125 #define ASM_E300_ADDR_VECTOR                 ASM_60X_ADDR_VECTOR
0126 #define ASM_E300_SYSMGMT_VECTOR              ASM_60X_SYSMGMT_VECTOR
0127 
0128 /*
0129  * If you change that number make sure to adjust the wrapper code in ppc_exc.S
0130  * and that ppc_exc_handler_table will be correctly initialized.
0131  */
0132 #define LAST_VALID_EXC                       0x1F
0133 
0134 /* DO NOT USE -- this symbol is DEPRECATED
0135  * (only used by libbsp/shared/vectors/vectors.S
0136  * which should not be used by new BSPs).
0137  */
0138 #define ASM_60X_VEC_VECTOR_OFFSET            0xf20
0139 
0140 #define ASM_PPC405_FIT_VECTOR_OFFSET         0x1010
0141 #define ASM_PPC405_WDOG_VECTOR_OFFSET        0x1020
0142 #define ASM_PPC405_TRACE_VECTOR_OFFSET       0x2000
0143 
0144 /** @} */
0145 
0146 /**
0147  * @defgroup ppc_exc_frame PowerPC Exception Frame
0148  *
0149  * @ingroup ppc_exc
0150  *
0151  * @{
0152  */
0153 
0154 /*
0155  * The callee (high level exception code written in C)
0156  * will store the Link Registers (return address) at entry r1 + 4 !!!.
0157  * So let room for it!!!.
0158  */
0159 #define LINK_REGISTER_CALLEE_UPDATE_ROOM 4
0160 
0161 #define EXC_GENERIC_SIZE (PPC_EXC_FRAME_SIZE + PPC_STACK_RED_ZONE_SIZE)
0162 
0163 #define PPC_EXC_INTERRUPT_FRAME_SIZE CPU_INTERRUPT_FRAME_SIZE
0164 
0165 #if defined(__ALTIVEC__) && !defined(PPC_MULTILIB_ALTIVEC)
0166 #define EXC_VEC_OFFSET EXC_GENERIC_SIZE
0167 #ifndef PPC_CACHE_ALIGNMENT
0168 #error "Missing include file!"
0169 #endif
0170 /*   20 volatile registers
0171  * + cache-aligned area for vcsr, vrsave
0172  * + area for alignment
0173  */
0174 #define EXC_VEC_SIZE   (16*20 + 2*PPC_CACHE_ALIGNMENT)
0175 #else
0176 #define EXC_VEC_SIZE   (0)
0177 #endif
0178 
0179 /*
0180  * maintain the EABI requested 8 bytes aligment
0181  * As SVR4 ABI requires 16, make it 16 (as some
0182  * exception may need more registers to be processed...)
0183  */
0184 #define EXCEPTION_FRAME_END (EXC_GENERIC_SIZE + EXC_VEC_SIZE)
0185 
0186 /** @} */
0187 
0188 #ifndef ASM
0189 
0190 /**
0191  * @addtogroup ppc_exc_frame
0192  *
0193  * @{
0194  */
0195 
0196 typedef CPU_Exception_frame BSP_Exception_frame;
0197 
0198 /** @} */
0199 
0200 /**
0201  * @addtogroup ppc_exc
0202  *
0203  * @{
0204  */
0205 
0206 /**
0207  * @brief Global exception handler type.
0208  */
0209 typedef void (*exception_handler_t)(BSP_Exception_frame*);
0210 
0211 /**
0212  * @brief Default global exception handler.
0213  */
0214 void C_exception_handler(BSP_Exception_frame* excPtr);
0215 
0216 void BSP_printStackTrace(const BSP_Exception_frame *excPtr);
0217 
0218 /**
0219  * @brief Exception categories.
0220  *
0221  * Exceptions of different categories use different SRR registers to save the
0222  * machine state and do different things in the prologue and epilogue.
0223  *
0224  * For now, the CPU descriptions assume this fits into 8 bits.
0225  */
0226 typedef enum {
0227   PPC_EXC_INVALID = 0,
0228   PPC_EXC_ASYNC = 1,
0229   PPC_EXC_CLASSIC = 2,
0230   PPC_EXC_CLASSIC_ASYNC = PPC_EXC_CLASSIC | PPC_EXC_ASYNC,
0231   PPC_EXC_405_CRITICAL = 4,
0232   PPC_EXC_405_CRITICAL_ASYNC = PPC_EXC_405_CRITICAL | PPC_EXC_ASYNC,
0233   PPC_EXC_BOOKE_CRITICAL = 6,
0234   PPC_EXC_BOOKE_CRITICAL_ASYNC = PPC_EXC_BOOKE_CRITICAL | PPC_EXC_ASYNC,
0235   PPC_EXC_E500_MACHCHK  = 8,
0236   PPC_EXC_E500_MACHCHK_ASYNC = PPC_EXC_E500_MACHCHK | PPC_EXC_ASYNC,
0237   PPC_EXC_NAKED = 10
0238 } ppc_exc_category;
0239 
0240 /**
0241  * @brief Categorie set type.
0242  */
0243 typedef uint8_t ppc_exc_categories [LAST_VALID_EXC + 1];
0244 
0245 static inline bool ppc_exc_is_valid_category(ppc_exc_category category)
0246 {
0247   return (unsigned) category <= (unsigned) PPC_EXC_NAKED;
0248 }
0249 
0250 /**
0251  * @brief Returns the entry address of the vector.
0252  *
0253  * @param[in] vector The vector number.
0254  * @param[in] vector_base The vector table base address.
0255  */
0256 void *ppc_exc_vector_address(unsigned vector, void *vector_base);
0257 
0258 /**
0259  * @brief Returns the category set for a CPU of type @a cpu, or @c NULL if
0260  * there is no category set available for this CPU.
0261  */
0262 const ppc_exc_categories *ppc_exc_categories_for_cpu(ppc_cpu_id_t cpu);
0263 
0264 /**
0265  * @brief Returns the category set for the current CPU, or @c NULL if there is
0266  * no category set available for this CPU.
0267  */
0268 static inline const ppc_exc_categories *ppc_exc_current_categories(void)
0269 {
0270   return ppc_exc_categories_for_cpu(ppc_cpu_current());
0271 }
0272 
0273 /**
0274  * @brief Returns the category for the vector @a vector using the category set
0275  * @a categories.
0276  */
0277 ppc_exc_category ppc_exc_category_for_vector(
0278   const ppc_exc_categories *categories,
0279   unsigned vector
0280 );
0281 
0282 /**
0283  * @brief Makes a minimal prologue for the vector @a vector with the category
0284  * @a category.
0285  *
0286  * The minimal prologue will be copied to @a prologue.  Not more than
0287  * @a prologue_size bytes will be copied.  Returns the actual minimal prologue
0288  * size in bytes in @a prologue_size.
0289  *
0290  * @retval RTEMS_SUCCESSFUL Minimal prologue successfully made.
0291  * @retval RTEMS_INVALID_ID Invalid vector number.
0292  * @retval RTEMS_INVALID_NUMBER Invalid category.
0293  * @retval RTEMS_INVALID_SIZE Prologue size to small.
0294  */
0295 rtems_status_code ppc_exc_make_prologue(
0296   unsigned vector,
0297   void *vector_base,
0298   ppc_exc_category category,
0299   uint32_t *prologue,
0300   size_t *prologue_size
0301 );
0302 
0303 static inline void ppc_exc_initialize_interrupt_stack(uintptr_t stack_begin)
0304 {
0305   uintptr_t stack_size = rtems_configuration_get_interrupt_stack_size();
0306   uintptr_t stack_end = stack_begin + stack_size;
0307   uintptr_t stack_pointer = stack_end - PPC_MINIMUM_STACK_FRAME_SIZE;
0308 
0309   /* Ensure proper interrupt stack alignment */
0310   stack_pointer &= ~((uintptr_t) CPU_STACK_ALIGNMENT - 1);
0311 
0312   /* Tag interrupt stack bottom */
0313   *(uint32_t *) stack_pointer = 0;
0314 
0315   /* Move interrupt stack values to special purpose registers */
0316   PPC_SET_SPECIAL_PURPOSE_REGISTER(SPRG1, stack_pointer);
0317   PPC_SET_SPECIAL_PURPOSE_REGISTER(SPRG2, stack_begin);
0318 }
0319 
0320 /**
0321  * @brief Initializes the exception handling.
0322  *
0323  * @see ppc_exc_initialize().
0324  */
0325 void ppc_exc_initialize_with_vector_base(
0326   uintptr_t interrupt_stack_begin,
0327   void *vector_base
0328 );
0329 
0330 /**
0331  * @brief Initializes the exception handling.
0332  *
0333  * If the initialization fails, then this is a fatal error.  The fatal error
0334  * source is RTEMS_FATAL_SOURCE_BSP and the fatal error code is
0335  * PPC_FATAL_EXCEPTION_INITIALIZATION.
0336  *
0337  * Possible error reasons are
0338  * - no category set available for the current CPU,
0339  * - the register r13 does not point to the small data area anchor required by
0340  *   SVR4/EABI, or
0341  * - the minimal prologue creation failed.
0342  */
0343 static inline void ppc_exc_initialize(void)
0344 {
0345   ppc_exc_initialize_with_vector_base(
0346     (uintptr_t) _ISR_Stack_area_begin,
0347     NULL
0348   );
0349 }
0350 
0351 /**
0352  * @brief High-level exception handler type.
0353  *
0354  * @retval 0 The exception was handled and normal execution may resume.
0355  * @retval -1 Reject the exception resulting in a call of the global exception
0356  * handler.
0357  * @retval other Reserved, do not use.
0358  */
0359 typedef int (*ppc_exc_handler_t)(BSP_Exception_frame *f, unsigned vector);
0360 
0361 /**
0362  * @brief Default high-level exception handler.
0363  *
0364  * @retval -1 Always.
0365  */
0366 int ppc_exc_handler_default(BSP_Exception_frame *f, unsigned int vector);
0367 
0368 #ifndef PPC_EXC_CONFIG_BOOKE_ONLY
0369 
0370 /**
0371  * @brief Bits for MSR update.
0372  *
0373  * Bits in MSR that are enabled during execution of exception handlers / ISRs
0374  * (on classic PPC these are DR/IR/RI [default], on bookE-style CPUs they should
0375  * be set to 0 during initialization)
0376  *
0377  * By default, the setting of these bits that is in effect when exception
0378  * handling is initialized is used.
0379  */
0380 extern uint32_t ppc_exc_msr_bits;
0381 
0382 #endif /* PPC_EXC_CONFIG_BOOKE_ONLY */
0383 
0384 /**
0385  * @brief Cache write back check flag.
0386  *
0387  * (See README under CAVEATS). During initialization
0388  * a check is performed to assert that write-back
0389  * caching is enabled for memory accesses. If a BSP
0390  * runs entirely without any caching then it should
0391  * set this variable to zero prior to initializing
0392  * exceptions in order to skip the test.
0393  * NOTE: The code does NOT support mapping memory
0394  *       with cache-attributes other than write-back
0395  *       (unless the entire cache is physically disabled)
0396  */
0397 extern uint32_t ppc_exc_cache_wb_check;
0398 
0399 #ifndef PPC_EXC_CONFIG_USE_FIXED_HANDLER
0400   /**
0401    * @brief High-level exception handler table.
0402    */
0403   extern ppc_exc_handler_t ppc_exc_handler_table [LAST_VALID_EXC + 1];
0404 
0405   /**
0406    * @brief Global exception handler.
0407    */
0408   extern exception_handler_t globalExceptHdl;
0409 #else /* PPC_EXC_CONFIG_USE_FIXED_HANDLER */
0410   /**
0411    * @brief High-level exception handler table.
0412    */
0413   extern const ppc_exc_handler_t ppc_exc_handler_table [LAST_VALID_EXC + 1];
0414 
0415   /**
0416    * @brief Interrupt dispatch routine provided by BSP.
0417    */
0418   void bsp_interrupt_dispatch(uintptr_t exception_number);
0419 #endif /* PPC_EXC_CONFIG_USE_FIXED_HANDLER */
0420 
0421 /**
0422  * @brief Set high-level exception handler.
0423  *
0424  * Hook C exception handlers.
0425  *  - handlers for asynchronous exceptions run on the ISR stack
0426  *    with thread-dispatching disabled.
0427  *  - handlers for synchronous exceptions run on the task stack
0428  *    with thread-dispatching enabled.
0429  *
0430  * If a particular slot is NULL then the traditional 'globalExcHdl' is used.
0431  *
0432  * ppc_exc_set_handler() registers a handler (returning 0 on success,
0433  * -1 if the vector argument is too big).
0434  *
0435  * It is legal to set a NULL handler. This leads to the globalExcHdl
0436  * being called if an exception for 'vector' occurs.
0437  *
0438  * @retval RTEMS_SUCCESSFUL Successful operation.
0439  * @retval RTEMS_INVALID_ID Invalid vector number.
0440  * @retval RTEMS_RESOURCE_IN_USE Handler table is read-only and handler does
0441  * not match.
0442  */
0443 rtems_status_code ppc_exc_set_handler(unsigned vector, ppc_exc_handler_t hdl);
0444 
0445 /**
0446  * @brief Returns the currently active high-level exception handler.
0447  */
0448 ppc_exc_handler_t ppc_exc_get_handler(unsigned vector);
0449 
0450 /**
0451  * @brief Function for DAR access.
0452  *
0453  * CPU support may store the address of a function here
0454  * that can be used by the default exception handler to
0455  * obtain fault-address info which is helpful. Unfortunately,
0456  * the SPR holding this information is not uniform
0457  * across PPC families so we need assistance from
0458  * CPU support
0459  */
0460 extern uint32_t (*ppc_exc_get_DAR)(void);
0461 
0462 void
0463 ppc_exc_wrapup(BSP_Exception_frame *f);
0464 
0465 /**
0466  * @brief Standard aligment handler.
0467  *
0468  * @retval 0 Performed a dcbz instruction.
0469  * @retval -1 Otherwise.
0470  */
0471 int ppc_exc_alignment_handler(BSP_Exception_frame *frame, unsigned excNum);
0472 
0473 /** @} */
0474 
0475 /*
0476  * Compatibility with pc386
0477  */
0478 typedef exception_handler_t cpuExcHandlerType;
0479 
0480 #endif /* ASM */
0481 
0482 #ifdef __cplusplus
0483 }
0484 #endif
0485 
0486 #endif /* LIBCPU_VECTORS_H */