From c429b5e93202d6fed7b374c32f2ab0f1a139581d Mon Sep 17 00:00:00 2001
From: Achin Gupta <achin.gupta@arm.com>
Date: Sun, 4 May 2014 18:38:28 +0100
Subject: [PATCH] Add context library API to change a bit in SCR_EL3

This patch adds an API to write to any bit in the SCR_EL3 member of
the 'cpu_context' structure of the current CPU for a specified
security state. This API will be used in subsequent patches which
introduce interrupt management in EL3 to specify the interrupt routing
model when execution is not in EL3.

It also renames the cm_set_el3_elr() function to cm_set_elr_el3()
which is more in line with the system register name being targeted by
the API.

Change-Id: I310fa7d8f827ad3f350325eca2fb28cb350a85ed
---
 bl31/context_mgmt.c           | 65 +++++++++++++++++++++++++++++++----
 include/bl31/context_mgmt.h   |  7 ++--
 include/lib/aarch64/arch.h    |  1 +
 services/spd/tspd/tspd_main.c |  2 +-
 services/spd/tspd/tspd_pm.c   |  6 ++--
 5 files changed, 68 insertions(+), 13 deletions(-)

diff --git a/bl31/context_mgmt.c b/bl31/context_mgmt.c
index eae608c5f..41418372f 100644
--- a/bl31/context_mgmt.c
+++ b/bl31/context_mgmt.c
@@ -28,6 +28,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <arch.h>
 #include <arch_helpers.h>
 #include <assert.h>
 #include <bl_common.h>
@@ -145,10 +146,10 @@ void cm_el1_sysregs_context_restore(uint32_t security_state)
 }
 
 /*******************************************************************************
- * This function function populates 'cpu_context' pertaining to the given
- * security state with the entrypoint, SPSR and SCR values so that an ERET from
- * this securit state correctly restores corresponding values to drop the CPU to
- * the next exception level
+ * This function populates 'cpu_context' pertaining to the given security state
+ * with the entrypoint, SPSR and SCR values so that an ERET from this security
+ * state correctly restores corresponding values to drop the CPU to the next
+ * exception level
  ******************************************************************************/
 void cm_set_el3_eret_context(uint32_t security_state, uint64_t entrypoint,
 		uint32_t spsr, uint32_t scr)
@@ -167,10 +168,10 @@ void cm_set_el3_eret_context(uint32_t security_state, uint64_t entrypoint,
 }
 
 /*******************************************************************************
- * This function function populates ELR_EL3 member of 'cpu_context' pertaining
- * to the given security state with the given entrypoint
+ * This function populates ELR_EL3 member of 'cpu_context' pertaining to the
+ * given security state with the given entrypoint
  ******************************************************************************/
-void cm_set_el3_elr(uint32_t security_state, uint64_t entrypoint)
+void cm_set_elr_el3(uint32_t security_state, uint64_t entrypoint)
 {
 	cpu_context_t *ctx;
 	el3_state_t *state;
@@ -183,6 +184,56 @@ void cm_set_el3_elr(uint32_t security_state, uint64_t entrypoint)
 	write_ctx_reg(state, CTX_ELR_EL3, entrypoint);
 }
 
+/*******************************************************************************
+ * This function updates a single bit in the SCR_EL3 member of the 'cpu_context'
+ * pertaining to the given security state using the value and bit position
+ * specified in the parameters. It preserves all other bits.
+ ******************************************************************************/
+void cm_write_scr_el3_bit(uint32_t security_state,
+			  uint32_t bit_pos,
+			  uint32_t value)
+{
+	cpu_context_t *ctx;
+	el3_state_t *state;
+	uint32_t scr_el3;
+
+	ctx = cm_get_context(read_mpidr(), security_state);
+	assert(ctx);
+
+	/* Ensure that the bit position is a valid one */
+	assert((1 << bit_pos) & SCR_VALID_BIT_MASK);
+
+	/* Ensure that the 'value' is only a bit wide */
+	assert(value <= 1);
+
+	/*
+	 * Get the SCR_EL3 value from the cpu context, clear the desired bit
+	 * and set it to its new value.
+	 */
+	state = get_el3state_ctx(ctx);
+	scr_el3 = read_ctx_reg(state, CTX_SCR_EL3);
+	scr_el3 &= ~(1 << bit_pos);
+	scr_el3 |= value << bit_pos;
+	write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
+}
+
+/*******************************************************************************
+ * This function retrieves SCR_EL3 member of 'cpu_context' pertaining to the
+ * given security state.
+ ******************************************************************************/
+uint32_t cm_get_scr_el3(uint32_t security_state)
+{
+	cpu_context_t *ctx;
+	el3_state_t *state;
+
+	ctx = cm_get_context(read_mpidr(), security_state);
+	assert(ctx);
+
+	/* Populate EL3 state so that ERET jumps to the correct entry */
+	state = get_el3state_ctx(ctx);
+	return read_ctx_reg(state, CTX_SCR_EL3);
+}
+
 /*******************************************************************************
  * This function is used to program the context that's used for exception
  * return. This initializes the SP_EL3 to a pointer to a 'cpu_context' set for
diff --git a/include/bl31/context_mgmt.h b/include/bl31/context_mgmt.h
index d2598eef7..ad9d78565 100644
--- a/include/bl31/context_mgmt.h
+++ b/include/bl31/context_mgmt.h
@@ -47,10 +47,13 @@ extern void cm_el1_sysregs_context_save(uint32_t security_state);
 extern void cm_el1_sysregs_context_restore(uint32_t security_state);
 extern void cm_set_el3_eret_context(uint32_t security_state, uint64_t entrypoint,
 		uint32_t spsr, uint32_t scr);
-extern void cm_set_el3_elr(uint32_t security_state, uint64_t entrypoint);
+extern void cm_set_elr_el3(uint32_t security_state, uint64_t entrypoint);
+extern void cm_write_scr_el3_bit(uint32_t security_state,
+				 uint32_t bit_pos,
+				 uint32_t value);
 extern void cm_set_next_eret_context(uint32_t security_state);
 extern void cm_init_pcpu_ptr_cache();
 extern void cm_set_pcpu_ptr_cache(const void *pcpu_ptr);
 extern void *cm_get_pcpu_ptr_cache(void);
-
+extern uint32_t cm_get_scr_el3(uint32_t security_state);
 #endif /* __CM_H__ */
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 1c11af3f5..68bab36ad 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -148,6 +148,7 @@
 #define SCR_FIQ_BIT		(1 << 2)
 #define SCR_IRQ_BIT		(1 << 1)
 #define SCR_NS_BIT		(1 << 0)
+#define SCR_VALID_BIT_MASK	0x2f8f
 
 /* HCR definitions */
 #define HCR_RW_BIT		(1ull << 31)
diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c
index f192d3488..6909cf65e 100644
--- a/services/spd/tspd/tspd_main.c
+++ b/services/spd/tspd/tspd_main.c
@@ -282,7 +282,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
 			assert(&tsp_ctx->cpu_ctx == cm_get_context(mpidr, SECURE));
 			set_aapcs_args7(&tsp_ctx->cpu_ctx, smc_fid, x1, x2, 0, 0,
 					0, 0, 0);
-			cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->fast_smc_entry);
+			cm_set_elr_el3(SECURE, (uint64_t) tsp_entry_info->fast_smc_entry);
 			cm_el1_sysregs_context_restore(SECURE);
 			cm_set_next_eret_context(SECURE);
 
diff --git a/services/spd/tspd/tspd_pm.c b/services/spd/tspd/tspd_pm.c
index 75b4b3008..d99aa2224 100644
--- a/services/spd/tspd/tspd_pm.c
+++ b/services/spd/tspd/tspd_pm.c
@@ -59,7 +59,7 @@ static int32_t tspd_cpu_off_handler(uint64_t cookie)
 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
 
 	/* Program the entry point and enter the TSP */
-	cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->cpu_off_entry);
+	cm_set_elr_el3(SECURE, (uint64_t) tsp_entry_info->cpu_off_entry);
 	rc = tspd_synchronous_sp_entry(tsp_ctx);
 
 	/*
@@ -96,7 +96,7 @@ static void tspd_cpu_suspend_handler(uint64_t power_state)
 	write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx),
 		      CTX_GPREG_X0,
 		      power_state);
-	cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->cpu_suspend_entry);
+	cm_set_elr_el3(SECURE, (uint64_t) tsp_entry_info->cpu_suspend_entry);
 	rc = tspd_synchronous_sp_entry(tsp_ctx);
 
 	/*
@@ -165,7 +165,7 @@ static void tspd_cpu_suspend_finish_handler(uint64_t suspend_level)
 	write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx),
 		      CTX_GPREG_X0,
 		      suspend_level);
-	cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->cpu_resume_entry);
+	cm_set_elr_el3(SECURE, (uint64_t) tsp_entry_info->cpu_resume_entry);
 	rc = tspd_synchronous_sp_entry(tsp_ctx);
 
 	/*
-- 
GitLab