Add context management library
This patch adds support for a cpu context management library. This
library will be used to:
1. Share pointers to secure and non-secure state cpu contexts between
runtime services e.g. PSCI and Secure Payload Dispatcher services
2. Set SP_EL3 to a context structure which will be used for
programming an ERET into a lower EL
3. Provide wrapper functions to save and restore EL3 & EL1
state. These functions will in turn use the helper functions in
context.S
Change-Id: I655eeef83dcd2a0c6f2eb2ac23efab866ac83ca0
diff --git a/bl31/context_mgmt.c b/bl31/context_mgmt.c
new file mode 100644
index 0000000..bbdbad2
--- /dev/null
+++ b/bl31/context_mgmt.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <arch_helpers.h>
+#include <platform.h>
+#include <bl_common.h>
+#include <runtime_svc.h>
+#include <context_mgmt.h>
+
+/*******************************************************************************
+ * Data structure which holds the pointers to non-secure and secure security
+ * state contexts for each cpu. It is aligned to the cache line boundary to
+ * allow efficient concurrent manipulation of these pointers on different cpus
+ ******************************************************************************/
+typedef struct {
+ void *ptr[2];
+} __aligned (CACHE_WRITEBACK_GRANULE) context_info;
+
+static context_info cm_context_info[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * Context management library initialisation routine. This library is used by
+ * runtime services to share pointers to 'cpu_context' structures for the secure
+ * and non-secure states. Management of the structures and their associated
+ * memory is not done by the context management library e.g. the PSCI service
+ * manages the cpu context used for entry from and exit to the non-secure state.
+ * The Secure payload dispatcher service manages the context(s) corresponding to
+ * the secure state. It also uses this library to get access to the non-secure
+ * state cpu context pointers.
+ * Lastly, this library provides the api to make SP_EL3 point to the cpu context
+ * which will used for programming an entry into a lower EL. The same context
+ * will used to save state upon exception entry from that EL.
+ ******************************************************************************/
+void cm_init()
+{
+ /*
+ * The context management library has only global data to intialize, but
+ * that will be done when the BSS is zeroed out
+ */
+}
+
+/*******************************************************************************
+ * This function returns a pointer to the most recent 'cpu_context' structure
+ * that was set as the context for the specified security state. NULL is
+ * returned if no such structure has been specified.
+ ******************************************************************************/
+void *cm_get_context(uint64_t mpidr, uint32_t security_state)
+{
+ uint32_t linear_id = platform_get_core_pos(mpidr);
+
+ assert(security_state <= NON_SECURE);
+
+ return cm_context_info[linear_id].ptr[security_state];
+}
+
+/*******************************************************************************
+ * This function sets the pointer to the current 'cpu_context' structure for the
+ * specified security state.
+ ******************************************************************************/
+void cm_set_context(uint64_t mpidr, void *context, uint32_t security_state)
+{
+ uint32_t linear_id = platform_get_core_pos(mpidr);
+
+ assert(security_state <= NON_SECURE);
+
+ cm_context_info[linear_id].ptr[security_state] = context;
+}
+
+/*******************************************************************************
+ * The next four functions are used by runtime services to save and restore EL3
+ * and EL1 contexts on the 'cpu_context' structure for the specified security
+ * state.
+ ******************************************************************************/
+void cm_el3_sysregs_context_save(uint32_t security_state)
+{
+ cpu_context *ctx;
+
+ ctx = cm_get_context(read_mpidr(), security_state);
+ assert(ctx);
+
+ el3_sysregs_context_save(get_el3state_ctx(ctx));
+}
+
+void cm_el3_sysregs_context_restore(uint32_t security_state)
+{
+ cpu_context *ctx;
+
+ ctx = cm_get_context(read_mpidr(), security_state);
+ assert(ctx);
+
+ el3_sysregs_context_restore(get_el3state_ctx(ctx));
+}
+
+void cm_el1_sysregs_context_save(uint32_t security_state)
+{
+ cpu_context *ctx;
+
+ ctx = cm_get_context(read_mpidr(), security_state);
+ assert(ctx);
+
+ el1_sysregs_context_save(get_sysregs_ctx(ctx));
+}
+
+void cm_el1_sysregs_context_restore(uint32_t security_state)
+{
+ cpu_context *ctx;
+
+ ctx = cm_get_context(read_mpidr(), security_state);
+ assert(ctx);
+
+ el1_sysregs_context_restore(get_sysregs_ctx(ctx));
+}
+
+/*******************************************************************************
+ * This function is used to program SP_EL3 to point to the 'cpu_context'
+ * structure which will be used for programming the EL3 architectural state to
+ * enable an ERET into a lower EL e.g. general purpose registers and system
+ * registers like SCR_EL3, SPSR_EL3, SCR_EL3 etc. The same structure will be
+ * used to save the same registers after an exception entry from the lower EL.
+ ******************************************************************************/
+void cm_set_next_eret_context(uint32_t security_state)
+{
+ cpu_context *ctx;
+#if DEBUG
+ uint64_t sp_mode;
+#endif
+ ctx = cm_get_context(read_mpidr(), security_state);
+ assert(ctx);
+
+#if DEBUG
+ /*
+ * Check that this function is called with SP_EL0 as the stack
+ * pointer
+ */
+ __asm__ volatile("mrs %0, SPSel\n"
+ : "=r" (sp_mode));
+
+ assert(sp_mode == MODE_SP_EL0);
+#endif
+
+ __asm__ volatile("msr spsel, #1\n"
+ "mov sp, %0\n"
+ "msr spsel, #0\n"
+ : : "r" (ctx));
+}