Back to home page

LXR

 
 

    


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

0001 /**
0002  * @file
0003  *
0004  * @ingroup ppc_exc
0005  *
0006  * @brief PowerPC Exceptions implementation.
0007  */
0008 
0009 /*
0010  * Copyright (C) 2007 Till Straumann <strauman@slac.stanford.edu>
0011  *
0012  * Copyright (C) 2009, 2012 embedded brains GmbH & Co. KG
0013  *
0014  * The license and distribution terms for this file may be
0015  * found in the file LICENSE in this distribution or at
0016  * http://www.rtems.org/license/LICENSE.
0017  */
0018 
0019 #include <string.h>
0020 
0021 #include <bsp/vectors.h>
0022 
0023 /* Offset into minimal prolog where vector number is hardcoded */
0024 #define PPC_EXC_PROLOG_VEC_OFFSET 2
0025 
0026 /* Symbols are defined by the linker */
0027 extern const char ppc_exc_min_prolog_size [];
0028 extern const char ppc_exc_tgpr_clr_prolog_size [];
0029 
0030 /* Special prologue for handling register shadowing on 603-style CPUs */
0031 extern const uint32_t ppc_exc_tgpr_clr_prolog [];
0032 
0033 /*
0034  * Classic prologue which determines the vector dynamically from the offset
0035  * address. This must only be used for classic, synchronous exceptions with a
0036  * vector offset aligned on a 256-byte boundary.
0037  */
0038 extern const uint32_t ppc_exc_min_prolog_auto [];
0039 
0040 /* Minimal prologue templates */
0041 extern const uint32_t ppc_exc_min_prolog_async_tmpl_std [];
0042 extern const uint32_t ppc_exc_min_prolog_sync_tmpl_std [];
0043 extern const uint32_t ppc_exc_min_prolog_async_tmpl_p405_crit [];
0044 extern const uint32_t ppc_exc_min_prolog_sync_tmpl_p405_crit [];
0045 extern const uint32_t ppc_exc_min_prolog_async_tmpl_bookE_crit [];
0046 extern const uint32_t ppc_exc_min_prolog_sync_tmpl_bookE_crit [];
0047 extern const uint32_t ppc_exc_min_prolog_sync_tmpl_e500_mchk [];
0048 extern const uint32_t ppc_exc_min_prolog_async_tmpl_e500_mchk [];
0049 extern const uint32_t ppc_exc_min_prolog_tmpl_naked [];
0050 extern const uint32_t ppc_exc_min_prolog_async_tmpl_normal [];
0051 
0052 static const uint32_t *const ppc_exc_prologue_templates [] = {
0053   [PPC_EXC_CLASSIC] = ppc_exc_min_prolog_sync_tmpl_std,
0054   [PPC_EXC_CLASSIC_ASYNC] = ppc_exc_min_prolog_async_tmpl_std,
0055   [PPC_EXC_405_CRITICAL] = ppc_exc_min_prolog_sync_tmpl_p405_crit,
0056   [PPC_EXC_405_CRITICAL_ASYNC] = ppc_exc_min_prolog_async_tmpl_p405_crit,
0057   [PPC_EXC_BOOKE_CRITICAL] = ppc_exc_min_prolog_sync_tmpl_bookE_crit,
0058   [PPC_EXC_BOOKE_CRITICAL_ASYNC] = ppc_exc_min_prolog_async_tmpl_bookE_crit,
0059   [PPC_EXC_E500_MACHCHK] = ppc_exc_min_prolog_sync_tmpl_e500_mchk,
0060   [PPC_EXC_E500_MACHCHK_ASYNC] = ppc_exc_min_prolog_async_tmpl_e500_mchk,
0061   [PPC_EXC_NAKED] = ppc_exc_min_prolog_tmpl_naked
0062 };
0063 
0064 static bool ppc_exc_create_branch_op(
0065   unsigned vector,
0066   void *vector_base,
0067   uint32_t *prologue,
0068   size_t prologue_size
0069 )
0070 {
0071   static const uintptr_t BRANCH_OP_CODE = 18 << 26;
0072 /*  static const uintptr_t BRANCH_OP_LINK = 0x1; */
0073   static const uintptr_t BRANCH_OP_ABS = 0x2;
0074   static const uintptr_t BRANCH_OP_MSK = 0x3ffffff;
0075   size_t branch_op_index = prologue_size / 4 - 1;
0076   uintptr_t vector_address =
0077     (uintptr_t) ppc_exc_vector_address(vector, vector_base);
0078   uintptr_t branch_op_address = vector_address + 4 * branch_op_index;
0079 
0080   /* This value may have BRANCH_OP_LINK set */
0081   uintptr_t target_address = prologue [branch_op_index];
0082 
0083   uintptr_t branch_target_address = target_address - branch_op_address;
0084 
0085   /*
0086    * We prefer to use a relative branch.  This has the benefit that custom
0087    * minimal prologues in a read-only area are relocatable.
0088    */
0089   if ((branch_target_address & ~BRANCH_OP_MSK) != 0) {
0090     /* Target to far for relative branch (PC ± 32M) */
0091     if (target_address >= 0xfe000001 || target_address < 0x01fffffd) {
0092       /* Can use an absolute branch */
0093       branch_target_address = (target_address | BRANCH_OP_ABS) & BRANCH_OP_MSK;
0094     } else {
0095       return false;
0096     }
0097   }
0098 
0099   prologue [branch_op_index] = BRANCH_OP_CODE | branch_target_address;
0100 
0101   return true;
0102 }
0103 
0104 rtems_status_code ppc_exc_make_prologue(
0105   unsigned vector,
0106   void *vector_base,
0107   ppc_exc_category category,
0108   uint32_t *prologue,
0109   size_t *prologue_size
0110 )
0111 {
0112   const uint32_t *prologue_template = NULL;
0113   size_t prologue_template_size = 0;
0114   bool fixup_vector = false;
0115 
0116   if (!ppc_exc_is_valid_category(category)) {
0117     return RTEMS_INVALID_NUMBER;
0118   }
0119 
0120   if (
0121     ppc_cpu_has_shadowed_gprs()
0122       && (vector == ASM_60X_IMISS_VECTOR
0123         || vector == ASM_60X_DLMISS_VECTOR
0124         || vector == ASM_60X_DSMISS_VECTOR)
0125   ) {
0126     prologue_template = ppc_exc_tgpr_clr_prolog;
0127     prologue_template_size = (size_t) ppc_exc_tgpr_clr_prolog_size;
0128   } else if (
0129     category == PPC_EXC_CLASSIC
0130       && ppc_cpu_is_bookE() != PPC_BOOKE_STD
0131       && ppc_cpu_is_bookE() != PPC_BOOKE_E500
0132   ) {
0133     prologue_template = ppc_exc_min_prolog_auto;
0134     prologue_template_size = (size_t) ppc_exc_min_prolog_size;
0135 #ifdef PPC_EXC_CONFIG_USE_FIXED_HANDLER
0136   } else if (
0137     category == PPC_EXC_CLASSIC_ASYNC
0138       && ppc_cpu_is_bookE() == PPC_BOOKE_E500
0139       && (ppc_interrupt_get_disable_mask() & MSR_CE) == 0
0140   ) {
0141     prologue_template = ppc_exc_min_prolog_async_tmpl_normal;
0142     prologue_template_size = 16;
0143     fixup_vector = true;
0144 #endif /* PPC_EXC_CONFIG_USE_FIXED_HANDLER */
0145   } else {
0146     prologue_template = ppc_exc_prologue_templates [category];
0147     prologue_template_size = (size_t) ppc_exc_min_prolog_size;
0148     fixup_vector = true;
0149   }
0150 
0151   if (prologue_template_size <= *prologue_size) {
0152     *prologue_size = prologue_template_size;
0153 
0154     memcpy(prologue, prologue_template, prologue_template_size);
0155 
0156     if (
0157       !ppc_exc_create_branch_op(
0158         vector,
0159         vector_base,
0160         prologue,
0161         prologue_template_size
0162       )
0163     ) {
0164       return RTEMS_INVALID_ADDRESS;
0165     }
0166 
0167     if (fixup_vector) {
0168       if (vector <= 0x7fffU) {
0169         prologue [PPC_EXC_PROLOG_VEC_OFFSET] =
0170           (prologue [PPC_EXC_PROLOG_VEC_OFFSET] & 0xffff8000U)
0171             | (vector & 0x7fffU);
0172       } else {
0173         return RTEMS_INVALID_ID;
0174       }
0175     }
0176   } else {
0177     return RTEMS_INVALID_SIZE;
0178   }
0179 
0180   return RTEMS_SUCCESSFUL;
0181 }