summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_prologue.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_prologue.c')
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_prologue.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_prologue.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_prologue.c
new file mode 100644
index 0000000000..b259589aa6
--- /dev/null
+++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_prologue.c
@@ -0,0 +1,127 @@
+/**
+ * @file
+ *
+ * @ingroup ppc_exc
+ *
+ * @brief PowerPC Exceptions implementation.
+ */
+
+/*
+ * Copyright (C) 2007 Till Straumann <strauman@slac.stanford.edu>
+ *
+ * Copyright (C) 2009 embedded brains GmbH.
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <string.h>
+
+#include <bsp/vectors.h>
+
+/* Offset into minimal prolog where vector number is hardcoded */
+#define PPC_EXC_PROLOG_VEC_OFFSET 2
+
+/* Symbols are defined by the linker */
+extern const char ppc_exc_min_prolog_size [];
+extern const char ppc_exc_tgpr_clr_prolog_size [];
+
+/* Special prologue for handling register shadowing on 603-style CPUs */
+extern const uint32_t ppc_exc_tgpr_clr_prolog [];
+
+/*
+ * Classic prologue which determines the vector dynamically from the offset
+ * address. This must only be used for classic, synchronous exceptions with a
+ * vector offset aligned on a 256-byte boundary.
+ */
+extern const uint32_t ppc_exc_min_prolog_auto [];
+
+extern const uint32_t ppc_exc_min_prolog_auto_packed [];
+
+/* Minimal prologue templates */
+extern const uint32_t ppc_exc_min_prolog_async_tmpl_std [];
+extern const uint32_t ppc_exc_min_prolog_sync_tmpl_std [];
+extern const uint32_t ppc_exc_min_prolog_async_tmpl_p405_crit [];
+extern const uint32_t ppc_exc_min_prolog_sync_tmpl_p405_crit [];
+extern const uint32_t ppc_exc_min_prolog_async_tmpl_bookE_crit [];
+extern const uint32_t ppc_exc_min_prolog_sync_tmpl_bookE_crit [];
+extern const uint32_t ppc_exc_min_prolog_sync_tmpl_e500_mchk [];
+extern const uint32_t ppc_exc_min_prolog_async_tmpl_e500_mchk [];
+extern const uint32_t ppc_exc_min_prolog_tmpl_naked [];
+
+static const uint32_t *const ppc_exc_prologue_templates [] = {
+ [PPC_EXC_CLASSIC] = ppc_exc_min_prolog_sync_tmpl_std,
+ [PPC_EXC_CLASSIC_ASYNC] = ppc_exc_min_prolog_async_tmpl_std,
+ [PPC_EXC_405_CRITICAL] = ppc_exc_min_prolog_sync_tmpl_p405_crit,
+ [PPC_EXC_405_CRITICAL_ASYNC] = ppc_exc_min_prolog_async_tmpl_p405_crit,
+ [PPC_EXC_BOOKE_CRITICAL] = ppc_exc_min_prolog_sync_tmpl_bookE_crit,
+ [PPC_EXC_BOOKE_CRITICAL_ASYNC] = ppc_exc_min_prolog_async_tmpl_bookE_crit,
+ [PPC_EXC_E500_MACHCHK] = ppc_exc_min_prolog_sync_tmpl_e500_mchk,
+ [PPC_EXC_E500_MACHCHK_ASYNC] = ppc_exc_min_prolog_async_tmpl_e500_mchk,
+ [PPC_EXC_NAKED] = ppc_exc_min_prolog_tmpl_naked
+};
+
+rtems_status_code ppc_exc_make_prologue(
+ unsigned vector,
+ ppc_exc_category category,
+ uint32_t *prologue,
+ size_t *prologue_size
+)
+{
+ const uint32_t *prologue_template = NULL;
+ size_t prologue_template_size = 0;
+ uintptr_t vector_address = (uintptr_t) ppc_exc_vector_address(vector);
+ bool fixup_vector = false;
+
+ if (!ppc_exc_is_valid_category(category)) {
+ return RTEMS_INVALID_NUMBER;
+ }
+
+ if (
+ ppc_cpu_has_shadowed_gprs()
+ && (vector == ASM_60X_IMISS_VECTOR
+ || vector == ASM_60X_DLMISS_VECTOR
+ || vector == ASM_60X_DSMISS_VECTOR)
+ ) {
+ prologue_template = ppc_exc_tgpr_clr_prolog;
+ prologue_template_size = (size_t) ppc_exc_tgpr_clr_prolog_size;
+ } else if (
+ category == PPC_EXC_CLASSIC
+ && ((vector_address & 0xffU) == 0
+ || (ppc_cpu_has_ivpr_and_ivor() && (vector_address & 0xfU) == 0))
+ ) {
+ if (ppc_cpu_has_ivpr_and_ivor()) {
+ prologue_template = ppc_exc_min_prolog_auto_packed;
+ } else {
+ prologue_template = ppc_exc_min_prolog_auto;
+ }
+ prologue_template_size = (size_t) ppc_exc_min_prolog_size;
+ } else {
+ prologue_template = ppc_exc_prologue_templates [category];
+ prologue_template_size = (size_t) ppc_exc_min_prolog_size;
+ fixup_vector = true;
+ }
+
+ if (prologue_template_size <= *prologue_size) {
+ *prologue_size = prologue_template_size;
+
+ memcpy(prologue, prologue_template, prologue_template_size);
+
+ if (fixup_vector) {
+ if (vector <= 0x7fffU) {
+ prologue [PPC_EXC_PROLOG_VEC_OFFSET] =
+ (prologue [PPC_EXC_PROLOG_VEC_OFFSET] & 0xffff8000U)
+ | (vector & 0x7fffU);
+ } else {
+ return RTEMS_INVALID_ID;
+ }
+ }
+ } else {
+ return RTEMS_INVALID_SIZE;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}