aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Thoelke <andrew.thoelke@arm.com>2014-05-23 11:00:04 +0100
committerAndrew Thoelke <andrew.thoelke@arm.com>2014-05-23 11:00:04 +0100
commit8545a8744b541cc6855e3218c4565e76697fb002 (patch)
tree96fdd4f46996c69897634eabd1e517ab83013f24
parent92535302791564e102150072d0e6152f9c4fde87 (diff)
parenta20a81e5b4a19969673f672523b946647f5d545d (diff)
downloadtrusted-firmware-a-8545a8744b541cc6855e3218c4565e76697fb002.tar.gz
Merge pull request #102 from achingupta:ag/tf-issues#104-v2
-rw-r--r--bl31/aarch64/bl31_entrypoint.S2
-rw-r--r--bl31/aarch64/runtime_exceptions.S114
-rw-r--r--bl31/bl31.mk9
-rw-r--r--bl31/context_mgmt.c71
-rw-r--r--bl31/interrupt_mgmt.c206
-rw-r--r--bl32/tsp/aarch64/tsp_entrypoint.S73
-rw-r--r--bl32/tsp/aarch64/tsp_exceptions.S200
-rw-r--r--bl32/tsp/tsp-fvp.mk8
-rw-r--r--bl32/tsp/tsp.mk3
-rw-r--r--bl32/tsp/tsp_interrupt.c109
-rw-r--r--bl32/tsp/tsp_main.c24
-rw-r--r--bl32/tsp/tsp_timer.c106
-rw-r--r--docs/user-guide.md9
-rw-r--r--drivers/arm/gic/gic_v2.c26
-rw-r--r--include/bl31/cm_macros.S57
-rw-r--r--include/bl31/context_mgmt.h7
-rw-r--r--include/bl31/interrupt_mgmt.h128
-rw-r--r--include/bl31/runtime_svc.h5
-rw-r--r--include/bl32/payloads/tsp.h54
-rw-r--r--include/drivers/arm/gic_v2.h13
-rw-r--r--include/lib/aarch64/arch.h23
-rw-r--r--include/lib/aarch64/arch_helpers.h7
-rw-r--r--lib/aarch64/sysreg_helpers.S37
-rw-r--r--plat/fvp/bl32_plat_setup.c3
-rw-r--r--plat/fvp/plat_gic.c132
-rw-r--r--plat/fvp/platform.h11
-rw-r--r--plat/fvp/platform.mk5
-rw-r--r--services/spd/tspd/tspd_common.c21
-rw-r--r--services/spd/tspd/tspd_main.c157
-rw-r--r--services/spd/tspd/tspd_pm.c22
-rw-r--r--services/spd/tspd/tspd_private.h54
-rw-r--r--services/std_svc/psci/psci_entry.S1
32 files changed, 1572 insertions, 125 deletions
diff --git a/bl31/aarch64/bl31_entrypoint.S b/bl31/aarch64/bl31_entrypoint.S
index f582e76405..3c9042b094 100644
--- a/bl31/aarch64/bl31_entrypoint.S
+++ b/bl31/aarch64/bl31_entrypoint.S
@@ -31,8 +31,6 @@
#include <arch.h>
#include <asm_macros.S>
#include <bl_common.h>
-#include <cm_macros.S>
-
.globl bl31_entrypoint
diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S
index b6dcccb756..4789b33ba3 100644
--- a/bl31/aarch64/runtime_exceptions.S
+++ b/bl31/aarch64/runtime_exceptions.S
@@ -30,14 +30,118 @@
#include <arch.h>
#include <asm_macros.S>
-#include <cm_macros.S>
#include <context.h>
+#include <interrupt_mgmt.h>
#include <platform.h>
#include <runtime_svc.h>
.globl runtime_exceptions
.globl el3_exit
+ /* -----------------------------------------------------
+ * Handle SMC exceptions seperately from other sync.
+ * exceptions.
+ * -----------------------------------------------------
+ */
+ .macro handle_sync_exception
+ str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+ mrs x30, esr_el3
+ ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+
+ cmp x30, #EC_AARCH32_SMC
+ b.eq smc_handler32
+
+ cmp x30, #EC_AARCH64_SMC
+ b.eq smc_handler64
+
+ /* -----------------------------------------------------
+ * The following code handles any synchronous exception
+ * that is not an SMC.
+ * -----------------------------------------------------
+ */
+
+ bl dump_state_and_die
+ .endm
+
+
+ /* -----------------------------------------------------
+ * This macro handles FIQ or IRQ interrupts i.e. EL3,
+ * S-EL1 and NS interrupts.
+ * -----------------------------------------------------
+ */
+ .macro handle_interrupt_exception label
+ str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+ bl save_gp_registers
+
+ /* Switch to the runtime stack i.e. SP_EL0 */
+ ldr x2, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
+ mov x20, sp
+ msr spsel, #0
+ mov sp, x2
+
+ /*
+ * Find out whether this is a valid interrupt type. If the
+ * interrupt controller reports a spurious interrupt then
+ * return to where we came from.
+ */
+ bl ic_get_pending_interrupt_type
+ cmp x0, #INTR_TYPE_INVAL
+ b.eq interrupt_exit_\label
+
+ /*
+ * Get the registered handler for this interrupt type. A
+ * NULL return value implies that an interrupt was generated
+ * for which there is no handler registered or the interrupt
+ * was routed incorrectly. This is a problem of the framework
+ * so report it as an error.
+ */
+ bl get_interrupt_type_handler
+ cbz x0, interrupt_error_\label
+ mov x21, x0
+
+ mov x0, #INTR_ID_UNAVAILABLE
+#if IMF_READ_INTERRUPT_ID
+ /*
+ * Read the id of the highest priority pending interrupt. If
+ * no interrupt is asserted then return to where we came from.
+ */
+ bl ic_get_pending_interrupt_id
+ cmp x0, #INTR_ID_UNAVAILABLE
+ b.eq interrupt_exit_\label
+#endif
+
+ /*
+ * Save the EL3 system registers needed to return from
+ * this exception.
+ */
+ mrs x3, spsr_el3
+ mrs x4, elr_el3
+ stp x3, x4, [x20, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
+
+ /* Set the current security state in the 'flags' parameter */
+ mrs x2, scr_el3
+ ubfx x1, x2, #0, #1
+
+ /* Restore the reference to the 'handle' i.e. SP_EL3 */
+ mov x2, x20
+
+ /* Call the interrupt type handler */
+ blr x21
+
+interrupt_exit_\label:
+ /* Return from exception, possibly in a different security state */
+ b el3_exit
+
+ /*
+ * This label signifies a problem with the interrupt management
+ * framework where it is not safe to go back to the instruction
+ * where the interrupt was generated.
+ */
+interrupt_error_\label:
+ bl dump_intr_state_and_die
+ .endm
+
+
.macro save_x18_to_x29_sp_el0
stp x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18]
stp x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20]
@@ -140,12 +244,12 @@ sync_exception_aarch64:
* -----------------------------------------------------
*/
irq_aarch64:
- bl dump_intr_state_and_die
+ handle_interrupt_exception irq_aarch64
check_vector_size irq_aarch64
.align 7
fiq_aarch64:
- bl dump_intr_state_and_die
+ handle_interrupt_exception fiq_aarch64
check_vector_size fiq_aarch64
.align 7
@@ -177,12 +281,12 @@ sync_exception_aarch32:
* -----------------------------------------------------
*/
irq_aarch32:
- bl dump_intr_state_and_die
+ handle_interrupt_exception irq_aarch32
check_vector_size irq_aarch32
.align 7
fiq_aarch32:
- bl dump_intr_state_and_die
+ handle_interrupt_exception fiq_aarch32
check_vector_size fiq_aarch32
.align 7
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 6c9650f034..8155f3dd66 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -31,6 +31,7 @@
BL31_SOURCES += bl31/bl31_main.c \
bl31/context_mgmt.c \
bl31/runtime_svc.c \
+ bl31/interrupt_mgmt.c \
bl31/aarch64/bl31_arch_setup.c \
bl31/aarch64/bl31_entrypoint.S \
bl31/aarch64/context.S \
@@ -50,3 +51,11 @@ BL31_SOURCES += bl31/bl31_main.c \
services/std_svc/psci/psci_setup.c
BL31_LINKERFILE := bl31/bl31.ld.S
+
+# Flag used by the generic interrupt management framework to determine if
+# upon the assertion of an interrupt, it should pass the interrupt id or not
+IMF_READ_INTERRUPT_ID := 0
+
+$(eval $(call assert_boolean,IMF_READ_INTERRUPT_ID))
+$(eval $(call add_define,IMF_READ_INTERRUPT_ID))
+
diff --git a/bl31/context_mgmt.c b/bl31/context_mgmt.c
index eae608c5f9..2e7e62d7bb 100644
--- a/bl31/context_mgmt.c
+++ b/bl31/context_mgmt.c
@@ -28,12 +28,14 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <bl_common.h>
#include <bl31.h>
#include <context.h>
#include <context_mgmt.h>
+#include <interrupt_mgmt.h>
#include <platform.h>
#include <runtime_svc.h>
@@ -145,10 +147,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)
@@ -159,6 +161,11 @@ void cm_set_el3_eret_context(uint32_t security_state, uint64_t entrypoint,
ctx = cm_get_context(read_mpidr(), security_state);
assert(ctx);
+ /* Program the interrupt routing model for this security state */
+ scr &= ~SCR_FIQ_BIT;
+ scr &= ~SCR_IRQ_BIT;
+ scr |= get_scr_el3_from_routing_model(security_state);
+
/* Populate EL3 state so that we've the right context before doing ERET */
state = get_el3state_ctx(ctx);
write_ctx_reg(state, CTX_SPSR_EL3, spsr);
@@ -167,10 +174,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;
@@ -184,6 +191,56 @@ void cm_set_el3_elr(uint32_t security_state, uint64_t 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
* the required security state
diff --git a/bl31/interrupt_mgmt.c b/bl31/interrupt_mgmt.c
new file mode 100644
index 0000000000..2b0c797065
--- /dev/null
+++ b/bl31/interrupt_mgmt.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 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 <assert.h>
+#include <bl_common.h>
+#include <context_mgmt.h>
+#include <errno.h>
+#include <interrupt_mgmt.h>
+#include <platform.h>
+#include <stdio.h>
+
+/*******************************************************************************
+ * Local structure and corresponding array to keep track of the state of the
+ * registered interrupt handlers for each interrupt type.
+ * The field descriptions are:
+ *
+ * 'flags' : Bit[0], Routing model for this interrupt type when execution is
+ * not in EL3 in the secure state. '1' implies that this
+ * interrupt will be routed to EL3. '0' implies that this
+ * interrupt will be routed to the current exception level.
+ *
+ * Bit[1], Routing model for this interrupt type when execution is
+ * not in EL3 in the non-secure state. '1' implies that this
+ * interrupt will be routed to EL3. '0' implies that this
+ * interrupt will be routed to the current exception level.
+ *
+ * All other bits are reserved and SBZ.
+ *
+ * 'scr_el3[2]' : Mapping of the routing model in the 'flags' field to the
+ * value of the SCR_EL3.IRQ or FIQ bit for each security state.
+ * There are two instances of this field corresponding to the
+ * two security states.
+ ******************************************************************************/
+typedef struct intr_type_desc {
+ interrupt_type_handler_t handler;
+ uint32_t flags;
+ uint32_t scr_el3[2];
+} intr_type_desc_t;
+
+static intr_type_desc_t intr_type_descs[MAX_INTR_TYPES];
+
+/*******************************************************************************
+ * This function validates the interrupt type. EL3 interrupts are currently not
+ * supported.
+ ******************************************************************************/
+static int32_t validate_interrupt_type(uint32_t type)
+{
+ if (type == INTR_TYPE_EL3)
+ return -ENOTSUP;
+
+ if (type != INTR_TYPE_S_EL1 && type != INTR_TYPE_NS)
+ return -EINVAL;
+
+ return 0;
+}
+
+/*******************************************************************************
+* This function validates the routing model for this type of interrupt
+ ******************************************************************************/
+static int32_t validate_routing_model(uint32_t type, uint32_t flags)
+{
+ flags >>= INTR_RM_FLAGS_SHIFT;
+ flags &= INTR_RM_FLAGS_MASK;
+
+ if (type == INTR_TYPE_S_EL1)
+ return validate_sel1_interrupt_rm(flags);
+
+ if (type == INTR_TYPE_NS)
+ return validate_ns_interrupt_rm(flags);
+
+ return -EINVAL;
+}
+
+/*******************************************************************************
+ * This function returns the cached copy of the SCR_EL3 which contains the
+ * routing model (expressed through the IRQ and FIQ bits) for a security state
+ * which was stored through a call to 'set_routing_model()' earlier.
+ ******************************************************************************/
+uint32_t get_scr_el3_from_routing_model(uint32_t security_state)
+{
+ uint32_t scr_el3;
+
+ assert(security_state <= NON_SECURE);
+ scr_el3 = intr_type_descs[INTR_TYPE_NS].scr_el3[security_state];
+ scr_el3 |= intr_type_descs[INTR_TYPE_S_EL1].scr_el3[security_state];
+ scr_el3 |= intr_type_descs[INTR_TYPE_EL3].scr_el3[security_state];
+ return scr_el3;
+}
+
+/*******************************************************************************
+ * This function uses the 'interrupt_type_flags' parameter to obtain the value
+ * of the trap bit (IRQ/FIQ) in the SCR_EL3 for a security state for this
+ * interrupt type. It uses it to update the SCR_EL3 in the cpu context and the
+ * 'intr_type_desc' for that security state.
+ ******************************************************************************/
+static void set_scr_el3_from_rm(uint32_t type,
+ uint32_t interrupt_type_flags,
+ uint32_t security_state)
+{
+ uint32_t flag, bit_pos;
+
+ flag = get_interrupt_rm_flag(interrupt_type_flags, security_state);
+ bit_pos = plat_interrupt_type_to_line(type, security_state);
+ intr_type_descs[type].scr_el3[security_state] = flag << bit_pos;
+ cm_write_scr_el3_bit(security_state, bit_pos, flag);
+}
+
+/*******************************************************************************
+ * This function validates the routing model specified in the 'flags' and
+ * updates internal data structures to reflect the new routing model. It also
+ * updates the copy of SCR_EL3 for each security state with the new routing
+ * model in the 'cpu_context' structure for this cpu.
+ ******************************************************************************/
+int32_t set_routing_model(uint32_t type, uint32_t flags)
+{
+ int32_t rc;
+
+ rc = validate_interrupt_type(type);
+ if (rc)
+ return rc;
+
+ rc = validate_routing_model(type, flags);
+ if (rc)
+ return rc;
+
+ /* Update the routing model in internal data structures */
+ intr_type_descs[type].flags = flags;
+ set_scr_el3_from_rm(type, flags, SECURE);
+ set_scr_el3_from_rm(type, flags, NON_SECURE);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * This function registers a handler for the 'type' of interrupt specified. It
+ * also validates the routing model specified in the 'flags' for this type of
+ * interrupt.
+ ******************************************************************************/
+int32_t register_interrupt_type_handler(uint32_t type,
+ interrupt_type_handler_t handler,
+ uint32_t flags)
+{
+ int32_t rc;
+
+ /* Validate the 'handler' parameter */
+ if (!handler)
+ return -EINVAL;
+
+ /* Validate the 'flags' parameter */
+ if (flags & INTR_TYPE_FLAGS_MASK)
+ return -EINVAL;
+
+ /* Check if a handler has already been registered */
+ if (intr_type_descs[type].handler)
+ return -EALREADY;
+
+ rc = set_routing_model(type, flags);
+ if (rc)
+ return rc;
+
+ /* Save the handler */
+ intr_type_descs[type].handler = handler;
+
+ return 0;
+}
+
+/*******************************************************************************
+ * This function is called when an interrupt is generated and returns the
+ * handler for the interrupt type (if registered). It returns NULL if the
+ * interrupt type is not supported or its handler has not been registered.
+ ******************************************************************************/
+interrupt_type_handler_t get_interrupt_type_handler(uint32_t type)
+{
+ if (validate_interrupt_type(type))
+ return NULL;
+
+ return intr_type_descs[type].handler;
+}
+
diff --git a/bl32/tsp/aarch64/tsp_entrypoint.S b/bl32/tsp/aarch64/tsp_entrypoint.S
index fab64cf52c..54276f2c6e 100644
--- a/bl32/tsp/aarch64/tsp_entrypoint.S
+++ b/bl32/tsp/aarch64/tsp_entrypoint.S
@@ -39,6 +39,7 @@
.globl tsp_cpu_suspend_entry
.globl tsp_cpu_resume_entry
.globl tsp_fast_smc_entry
+ .globl tsp_fiq_entry
/* ---------------------------------------------
* Populate the params in x0-x7 from the pointer
@@ -53,6 +54,22 @@
smc #0
.endm
+ .macro save_eret_context reg1 reg2
+ mrs \reg1, elr_el1
+ mrs \reg2, spsr_el1
+ stp \reg1, \reg2, [sp, #-0x10]!
+ stp x30, x18, [sp, #-0x10]!
+ .endm
+
+ .macro restore_eret_context reg1 reg2
+ ldp x30, x18, [sp], #0x10
+ ldp \reg1, \reg2, [sp], #0x10
+ msr elr_el1, \reg1
+ msr spsr_el1, \reg2
+ .endm
+
+ .section .text, "ax"
+ .align 3
func tsp_entrypoint
@@ -70,7 +87,7 @@ func tsp_entrypoint
* Set the exception vector to something sane.
* ---------------------------------------------
*/
- adr x0, early_exceptions
+ adr x0, tsp_exceptions
msr vbar_el1, x0
/* ---------------------------------------------
@@ -167,7 +184,7 @@ func tsp_cpu_on_entry
* Set the exception vector to something sane.
* ---------------------------------------------
*/
- adr x0, early_exceptions
+ adr x0, tsp_exceptions
msr vbar_el1, x0
/* ---------------------------------------------
@@ -227,6 +244,58 @@ func tsp_cpu_suspend_entry
restore_args_call_smc
/*---------------------------------------------
+ * This entrypoint is used by the TSPD to pass
+ * control for handling a pending S-EL1 FIQ.
+ * 'x0' contains a magic number which indicates
+ * this. TSPD expects control to be handed back
+ * at the end of FIQ processing. This is done
+ * through an SMC. The handover agreement is:
+ *
+ * 1. PSTATE.DAIF are set upon entry. 'x1' has
+ * the ELR_EL3 from the non-secure state.
+ * 2. TSP has to preserve the callee saved
+ * general purpose registers, SP_EL1/EL0 and
+ * LR.
+ * 3. TSP has to preserve the system and vfp
+ * registers (if applicable).
+ * 4. TSP can use 'x0-x18' to enable its C
+ * runtime.
+ * 5. TSP returns to TSPD using an SMC with
+ * 'x0' = TSP_HANDLED_S_EL1_FIQ
+ * ---------------------------------------------
+ */
+func tsp_fiq_entry
+#if DEBUG
+ mov x2, #(TSP_HANDLE_FIQ_AND_RETURN & ~0xffff)
+ movk x2, #(TSP_HANDLE_FIQ_AND_RETURN & 0xffff)
+ cmp x0, x2
+ b.ne tsp_fiq_entry_panic
+#endif
+ /*---------------------------------------------
+ * Save any previous context needed to perform
+ * an exception return from S-EL1 e.g. context
+ * from a previous IRQ. Update statistics and
+ * handle the FIQ before returning to the TSPD.
+ * IRQ/FIQs are not enabled since that will
+ * complicate the implementation. Execution
+ * will be transferred back to the normal world
+ * in any case. A non-zero return value from the
+ * fiq handler is an error.
+ * ---------------------------------------------
+ */
+ save_eret_context x2 x3
+ bl tsp_update_sync_fiq_stats
+ bl tsp_fiq_handler
+ cbnz x0, tsp_fiq_entry_panic
+ restore_eret_context x2 x3
+ mov x0, #(TSP_HANDLED_S_EL1_FIQ & ~0xffff)
+ movk x0, #(TSP_HANDLED_S_EL1_FIQ & 0xffff)
+ smc #0
+
+tsp_fiq_entry_panic:
+ b tsp_fiq_entry_panic
+
+ /*---------------------------------------------
* This entrypoint is used by the TSPD when this
* cpu resumes execution after an earlier
* CPU_SUSPEND psci call to ask the TSP to
diff --git a/bl32/tsp/aarch64/tsp_exceptions.S b/bl32/tsp/aarch64/tsp_exceptions.S
new file mode 100644
index 0000000000..ccb4cddddd
--- /dev/null
+++ b/bl32/tsp/aarch64/tsp_exceptions.S
@@ -0,0 +1,200 @@
+/*
+ * 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 <bl_common.h>
+#include <arch.h>
+#include <tsp.h>
+#include <asm_macros.S>
+
+
+ /* ----------------------------------------------------
+ * The caller-saved registers x0-x18 and LR are saved
+ * here.
+ * ----------------------------------------------------
+ */
+
+#define SCRATCH_REG_SIZE #(20 * 8)
+
+ .macro save_caller_regs_and_lr
+ sub sp, sp, SCRATCH_REG_SIZE
+ stp x0, x1, [sp]
+ stp x2, x3, [sp, #0x10]
+ stp x4, x5, [sp, #0x20]
+ stp x6, x7, [sp, #0x30]
+ stp x8, x9, [sp, #0x40]
+ stp x10, x11, [sp, #0x50]
+ stp x12, x13, [sp, #0x60]
+ stp x14, x15, [sp, #0x70]
+ stp x16, x17, [sp, #0x80]
+ stp x18, x30, [sp, #0x90]
+ .endm
+
+ .macro restore_caller_regs_and_lr
+ ldp x0, x1, [sp]
+ ldp x2, x3, [sp, #0x10]
+ ldp x4, x5, [sp, #0x20]
+ ldp x6, x7, [sp, #0x30]
+ ldp x8, x9, [sp, #0x40]
+ ldp x10, x11, [sp, #0x50]
+ ldp x12, x13, [sp, #0x60]
+ ldp x14, x15, [sp, #0x70]
+ ldp x16, x17, [sp, #0x80]
+ ldp x18, x30, [sp, #0x90]
+ add sp, sp, SCRATCH_REG_SIZE
+ .endm
+
+ .globl tsp_exceptions
+
+ /* -----------------------------------------------------
+ * TSP exception handlers.
+ * -----------------------------------------------------
+ */
+ .section .vectors, "ax"; .align 11
+
+ .align 7
+tsp_exceptions:
+ /* -----------------------------------------------------
+ * Current EL with _sp_el0 : 0x0 - 0x180. No exceptions
+ * are expected and treated as irrecoverable errors.
+ * -----------------------------------------------------
+ */
+sync_exception_sp_el0:
+ wfi
+ b sync_exception_sp_el0
+ check_vector_size sync_exception_sp_el0
+
+ .align 7
+
+irq_sp_el0:
+ b irq_sp_el0
+ check_vector_size irq_sp_el0
+
+ .align 7
+fiq_sp_el0:
+ b fiq_sp_el0
+ check_vector_size fiq_sp_el0
+
+ .align 7
+serror_sp_el0:
+ b serror_sp_el0
+ check_vector_size serror_sp_el0
+
+
+ /* -----------------------------------------------------
+ * Current EL with SPx: 0x200 - 0x380. Only IRQs/FIQs
+ * are expected and handled
+ * -----------------------------------------------------
+ */
+ .align 7
+sync_exception_sp_elx:
+ wfi
+ b sync_exception_sp_elx
+ check_vector_size sync_exception_sp_elx
+
+ .align 7
+irq_sp_elx:
+ b irq_sp_elx
+ check_vector_size irq_sp_elx
+
+ .align 7
+fiq_sp_elx:
+ save_caller_regs_and_lr
+ bl tsp_fiq_handler
+ cbz x0, fiq_sp_elx_done
+
+ /*
+ * This FIQ was not targetted to S-EL1 so send it to
+ * the monitor and wait for execution to resume.
+ */
+ smc #0
+fiq_sp_elx_done:
+ restore_caller_regs_and_lr
+ eret
+ check_vector_size fiq_sp_elx
+
+ .align 7
+serror_sp_elx:
+ b serror_sp_elx
+ check_vector_size serror_sp_elx
+
+
+ /* -----------------------------------------------------
+ * Lower EL using AArch64 : 0x400 - 0x580. No exceptions
+ * are handled since TSP does not implement a lower EL
+ * -----------------------------------------------------
+ */
+ .align 7
+sync_exception_aarch64:
+ wfi
+ b sync_exception_aarch64
+ check_vector_size sync_exception_aarch64
+
+ .align 7
+irq_aarch64:
+ b irq_aarch64
+ check_vector_size irq_aarch64
+
+ .align 7
+fiq_aarch64:
+ b fiq_aarch64
+ check_vector_size fiq_aarch64
+
+ .align 7
+serror_aarch64:
+ b serror_aarch64
+ check_vector_size serror_aarch64
+
+
+ /* -----------------------------------------------------
+ * Lower EL using AArch32 : 0x600 - 0x780. No exceptions
+ * handled since the TSP does not implement a lower EL.
+ * -----------------------------------------------------
+ */
+ .align 7
+sync_exception_aarch32:
+ wfi
+ b sync_exception_aarch32
+ check_vector_size sync_exception_aarch32
+
+ .align 7
+irq_aarch32:
+ b irq_aarch32
+ check_vector_size irq_aarch32
+
+ .align 7
+fiq_aarch32:
+ b fiq_aarch32
+ check_vector_size fiq_aarch32
+
+ .align 7
+serror_aarch32:
+ b serror_aarch32
+ check_vector_size serror_aarch32
+ .align 7
diff --git a/bl32/tsp/tsp-fvp.mk b/bl32/tsp/tsp-fvp.mk
index 5d8a0e3449..b1d0afef1b 100644
--- a/bl32/tsp/tsp-fvp.mk
+++ b/bl32/tsp/tsp-fvp.mk
@@ -29,7 +29,9 @@
#
# TSP source files specific to FVP platform
-BL32_SOURCES += plat/common/aarch64/platform_mp_stack.S \
- plat/fvp/bl32_plat_setup.c \
+BL32_SOURCES += drivers/arm/gic/gic_v2.c \
+ plat/common/aarch64/platform_mp_stack.S \
plat/fvp/aarch64/plat_common.c \
- plat/fvp/aarch64/plat_helpers.S
+ plat/fvp/aarch64/plat_helpers.S \
+ plat/fvp/bl32_plat_setup.c \
+ plat/fvp/plat_gic.c
diff --git a/bl32/tsp/tsp.mk b/bl32/tsp/tsp.mk
index c478b435f8..b9084d549e 100644
--- a/bl32/tsp/tsp.mk
+++ b/bl32/tsp/tsp.mk
@@ -30,7 +30,10 @@
BL32_SOURCES += bl32/tsp/tsp_main.c \
bl32/tsp/aarch64/tsp_entrypoint.S \
+ bl32/tsp/aarch64/tsp_exceptions.S \
bl32/tsp/aarch64/tsp_request.S \
+ bl32/tsp/tsp_interrupt.c \
+ bl32/tsp/tsp_timer.c \
common/aarch64/early_exceptions.S \
lib/locks/exclusive/spinlock.S
diff --git a/bl32/tsp/tsp_interrupt.c b/bl32/tsp/tsp_interrupt.c
new file mode 100644
index 0000000000..d5d02c3047
--- /dev/null
+++ b/bl32/tsp/tsp_interrupt.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 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 <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <gic_v2.h>
+#include <tsp.h>
+#include <platform.h>
+
+/*******************************************************************************
+ * This function updates the TSP statistics for FIQs handled synchronously i.e
+ * the ones that have been handed over by the TSPD. It also keeps count of the
+ * number of times control was passed back to the TSPD after handling an FIQ.
+ * In the future it will be possible that the TSPD hands over an FIQ to the TSP
+ * but does not expect it to return execution. This statistic will be useful to
+ * distinguish between these two models of synchronous FIQ handling.
+ * The 'elr_el3' parameter contains the address of the instruction in normal
+ * world where this FIQ was generated.
+ ******************************************************************************/
+void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3)
+{
+ uint64_t mpidr = read_mpidr();
+ uint32_t linear_id = platform_get_core_pos(mpidr);
+
+ tsp_stats[linear_id].sync_fiq_count++;
+ if (type == TSP_HANDLE_FIQ_AND_RETURN)
+ tsp_stats[linear_id].sync_fiq_ret_count++;
+
+ spin_lock(&console_lock);
+ printf("TSP: cpu 0x%x sync fiq request from 0x%llx \n\r",
+ mpidr, elr_el3);
+ INFO("cpu 0x%x: %d sync fiq requests, %d sync fiq returns\n",
+ mpidr,
+ tsp_stats[linear_id].sync_fiq_count,
+ tsp_stats[linear_id].sync_fiq_ret_count);
+ spin_unlock(&console_lock);
+}
+
+/*******************************************************************************
+ * TSP FIQ handler called as a part of both synchronous and asynchronous
+ * handling of FIQ interrupts. It returns 0 upon successfully handling a S-EL1
+ * FIQ and treats all other FIQs as EL3 interrupts. It assumes that the GIC
+ * architecture version in v2.0 and the secure physical timer interrupt is the
+ * only S-EL1 interrupt that it needs to handle.
+ ******************************************************************************/
+int32_t tsp_fiq_handler()
+{
+ uint64_t mpidr = read_mpidr();
+ uint32_t linear_id = platform_get_core_pos(mpidr), id;
+
+ /*
+ * Get the highest priority pending interrupt id and see if it is the
+ * secure physical generic timer interrupt in which case, handle it.
+ * Otherwise throw this interrupt at the EL3 firmware.
+ */
+ id = ic_get_pending_interrupt_id();
+
+ /* TSP can only handle the secure physical timer interrupt */
+ if (id != IRQ_SEC_PHY_TIMER)
+ return TSP_EL3_FIQ;
+
+ /*
+ * Handle the interrupt. Also sanity check if it has been preempted by
+ * another secure interrupt through an assertion.
+ */
+ id = ic_acknowledge_interrupt();
+ assert(id == IRQ_SEC_PHY_TIMER);
+ tsp_generic_timer_handler();
+ ic_end_of_interrupt(id);
+
+ /* Update the statistics and print some messages */
+ tsp_stats[linear_id].fiq_count++;
+ spin_lock(&console_lock);
+ printf("TSP: cpu 0x%x handled fiq %d \n\r",
+ mpidr, id);
+ INFO("cpu 0x%x: %d fiq requests \n",
+ mpidr, tsp_stats[linear_id].fiq_count);
+ spin_unlock(&console_lock);
+
+ return 0;
+}
diff --git a/bl32/tsp/tsp_main.c b/bl32/tsp/tsp_main.c
index a7c7386580..ec74db428e 100644
--- a/bl32/tsp/tsp_main.c
+++ b/bl32/tsp/tsp_main.c
@@ -58,7 +58,7 @@ static tsp_args_t tsp_smc_args[PLATFORM_CORE_COUNT];
/*******************************************************************************
* Per cpu data structure to keep track of TSP activity
******************************************************************************/
-static work_statistics_t tsp_stats[PLATFORM_CORE_COUNT];
+work_statistics_t tsp_stats[PLATFORM_CORE_COUNT];
/*******************************************************************************
* Single reference to the various entry points exported by the test secure
@@ -71,6 +71,7 @@ static const entry_info_t tsp_entry_info = {
tsp_cpu_off_entry,
tsp_cpu_resume_entry,
tsp_cpu_suspend_entry,
+ tsp_fiq_entry,
};
@@ -127,6 +128,7 @@ uint64_t tsp_main(void)
bl32_platform_setup();
/* Initialize secure/applications state here */
+ tsp_generic_timer_start();
/* Update this cpu's statistics */
tsp_stats[linear_id].smc_count++;
@@ -162,6 +164,9 @@ tsp_args_t *tsp_cpu_on_main(void)
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
+ /* Initialize secure/applications state here */
+ tsp_generic_timer_start();
+
/* Update this cpu's statistics */
tsp_stats[linear_id].smc_count++;
tsp_stats[linear_id].eret_count++;
@@ -195,6 +200,13 @@ tsp_args_t *tsp_cpu_off_main(uint64_t arg0,
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
+ /*
+ * This cpu is being turned off, so disable the timer to prevent the
+ * secure timer interrupt from interfering with power down. A pending
+ * interrupt will be lost but we do not care as we are turning off.
+ */
+ tsp_generic_timer_stop();
+
/* Update this cpu's statistics */
tsp_stats[linear_id].smc_count++;
tsp_stats[linear_id].eret_count++;
@@ -230,6 +242,13 @@ tsp_args_t *tsp_cpu_suspend_main(uint64_t power_state,
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
+ /*
+ * Save the time context and disable it to prevent the secure timer
+ * interrupt from interfering with wakeup from the suspend state.
+ */
+ tsp_generic_timer_save();
+ tsp_generic_timer_stop();
+
/* Update this cpu's statistics */
tsp_stats[linear_id].smc_count++;
tsp_stats[linear_id].eret_count++;
@@ -265,6 +284,9 @@ tsp_args_t *tsp_cpu_resume_main(uint64_t suspend_level,
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
+ /* Restore the generic timer context */
+ tsp_generic_timer_restore();
+
/* Update this cpu's statistics */
tsp_stats[linear_id].smc_count++;
tsp_stats[linear_id].eret_count++;
diff --git a/bl32/tsp/tsp_timer.c b/bl32/tsp/tsp_timer.c
new file mode 100644
index 0000000000..f66ff9fa5a
--- /dev/null
+++ b/bl32/tsp/tsp_timer.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 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 <arch_helpers.h>
+#include <assert.h>
+#include <tsp.h>
+
+/*******************************************************************************
+ * Data structure to keep track of per-cpu secure generic timer context across
+ * power management operations.
+ ******************************************************************************/
+typedef struct timer_context {
+ uint64_t cval;
+ uint32_t ctl;
+} timer_context_t;
+
+static timer_context_t pcpu_timer_context[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * This function initializes the generic timer to fire every 0.5 second
+ ******************************************************************************/
+void tsp_generic_timer_start()
+{
+ uint64_t cval;
+ uint32_t ctl = 0;
+
+ /* The timer will fire every 0.5 second */
+ cval = read_cntpct_el0() + (read_cntfrq_el0() >> 1);
+ write_cntps_cval_el1(cval);
+
+ /* Enable the secure physical timer */
+ set_cntp_ctl_enable(ctl);
+ write_cntps_ctl_el1(ctl);
+}
+
+/*******************************************************************************
+ * This function deasserts the timer interrupt and sets it up again
+ ******************************************************************************/
+void tsp_generic_timer_handler()
+{
+ /* Ensure that the timer did assert the interrupt */
+ assert(get_cntp_ctl_istatus(read_cntps_ctl_el1()));
+
+ /* Disable the timer and reprogram it */
+ write_cntps_ctl_el1(0);
+ tsp_generic_timer_start();
+}
+
+/*******************************************************************************
+ * This function deasserts the timer interrupt prior to cpu power down
+ ******************************************************************************/
+void tsp_generic_timer_stop()
+{
+ /* Disable the timer */
+ write_cntps_ctl_el1(0);
+}
+
+/*******************************************************************************
+ * This function saves the timer context prior to cpu suspension
+ ******************************************************************************/
+void tsp_generic_timer_save()
+{
+ uint32_t linear_id = platform_get_core_pos(read_mpidr());
+
+ pcpu_timer_context[linear_id].cval = read_cntps_cval_el1();
+ pcpu_timer_context[linear_id].ctl = read_cntps_ctl_el1();
+ flush_dcache_range((uint64_t) &pcpu_timer_context[linear_id],
+ sizeof(pcpu_timer_context[linear_id]));
+}
+
+/*******************************************************************************
+ * This function restores the timer context post cpu resummption
+ ******************************************************************************/
+void tsp_generic_timer_restore()
+{
+ uint32_t linear_id = platform_get_core_pos(read_mpidr());
+
+ write_cntps_cval_el1(pcpu_timer_context[linear_id].cval);
+ write_cntps_ctl_el1(pcpu_timer_context[linear_id].ctl);
+}
diff --git a/docs/user-guide.md b/docs/user-guide.md
index 6050831f46..484ffebd4e 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -158,6 +158,15 @@ performed.
* `V`: Verbose build. If assigned anything other than 0, the build commands
are printed. Default is 0
+* `FVP_GIC_ARCH`: Choice of ARM GIC architecture version used by the FVP port
+ for implementing the platform GIC API. This API is used by the interrupt
+ management framework. Default is 2 i.e. version 2.0
+
+* `IMF_READ_INTERRUPT_ID`: Boolean flag used by the interrupt management
+ framework to enable passing of the interrupt id to its handler. The id is
+ read using a platform GIC API. `INTR_ID_UNAVAILABLE` is passed instead if
+ this option set to 0. Default is 0.
+
### Creating a Firmware Image Package
FIPs are automatically created as part of the build instructions described in
diff --git a/drivers/arm/gic/gic_v2.c b/drivers/arm/gic/gic_v2.c
index 00464cbd2f..27a39b9c73 100644
--- a/drivers/arm/gic/gic_v2.c
+++ b/drivers/arm/gic/gic_v2.c
@@ -28,8 +28,10 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <arch.h>
#include <assert.h>
#include <gic_v2.h>
+#include <interrupt_mgmt.h>
#include <mmio.h>
/*******************************************************************************
@@ -290,3 +292,27 @@ void gicd_set_itargetsr(unsigned int base, unsigned int id, unsigned int iface)
(1 << iface) << (byte_off << 3));
}
+/*******************************************************************************
+ * This function allows the interrupt management framework to determine (through
+ * the platform) which interrupt line (IRQ/FIQ) to use for an interrupt type to
+ * route it to EL3. The interrupt line is represented as the bit position of the
+ * IRQ or FIQ bit in the SCR_EL3.
+ ******************************************************************************/
+uint32_t gicv2_interrupt_type_to_line(uint32_t cpuif_base, uint32_t type)
+{
+ uint32_t gicc_ctlr;
+
+ /* Non-secure interrupts are signalled on the IRQ line always */
+ if (type == INTR_TYPE_NS)
+ return __builtin_ctz(SCR_IRQ_BIT);
+
+ /*
+ * Secure interrupts are signalled using the IRQ line if the FIQ_EN
+ * bit is not set else they are signalled using the FIQ line.
+ */
+ gicc_ctlr = gicc_read_ctlr(cpuif_base);
+ if (gicc_ctlr & FIQ_EN)
+ return __builtin_ctz(SCR_FIQ_BIT);
+ else
+ return __builtin_ctz(SCR_IRQ_BIT);
+}
diff --git a/include/bl31/cm_macros.S b/include/bl31/cm_macros.S
deleted file mode 100644
index f12f8c3069..0000000000
--- a/include/bl31/cm_macros.S
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 <arch.h>
-#include <context.h>
-
- /* -----------------------------------------------------
- * Handle SMC exceptions seperately from other sync.
- * exceptions.
- * -----------------------------------------------------
- */
- .macro handle_sync_exception
- str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
- mrs x30, esr_el3
- ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
-
- cmp x30, #EC_AARCH32_SMC
- b.eq smc_handler32
-
- cmp x30, #EC_AARCH64_SMC
- b.eq smc_handler64
-
- /* -----------------------------------------------------
- * The following code handles any synchronous exception
- * that is not an SMC.
- * -----------------------------------------------------
- */
-
- bl dump_state_and_die
- .endm
-
diff --git a/include/bl31/context_mgmt.h b/include/bl31/context_mgmt.h
index d2598eef77..ad9d785650 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/bl31/interrupt_mgmt.h b/include/bl31/interrupt_mgmt.h
new file mode 100644
index 0000000000..0b24f39a54
--- /dev/null
+++ b/include/bl31/interrupt_mgmt.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#ifndef __INTERRUPT_MGMT_H__
+#define __INTERRUPT_MGMT_H__
+
+#include <arch.h>
+
+/*******************************************************************************
+ * Constants for the types of interrupts recognised by the IM framework
+ ******************************************************************************/
+#define INTR_TYPE_S_EL1 0
+#define INTR_TYPE_EL3 1
+#define INTR_TYPE_NS 2
+#define MAX_INTR_TYPES 3
+#define INTR_TYPE_INVAL MAX_INTR_TYPES
+/*
+ * Constant passed to the interrupt handler in the 'id' field when the
+ * framework does not read the gic registers to determine the interrupt id.
+ */
+#define INTR_ID_UNAVAILABLE 0xFFFFFFFF
+
+
+/*******************************************************************************
+ * Mask for _both_ the routing model bits in the 'flags' parameter and
+ * constants to define the valid routing models for each supported interrupt
+ * type
+ ******************************************************************************/
+#define INTR_RM_FLAGS_SHIFT 0x0
+#define INTR_RM_FLAGS_MASK 0x3
+/* Routed to EL3 from NS. Taken to S-EL1 from Secure */
+#define INTR_SEL1_VALID_RM0 0x2
+/* Routed to EL3 from NS and Secure */
+#define INTR_SEL1_VALID_RM1 0x3
+/* Routed to EL1/EL2 from NS and to S-EL1 from Secure */
+#define INTR_NS_VALID_RM0 0x0
+/* Routed to EL1/EL2 from NS and to EL3 from Secure */
+#define INTR_NS_VALID_RM1 0x1
+
+
+/*******************************************************************************
+ * Constants for the _individual_ routing model bits in the 'flags' field for
+ * each interrupt type and mask to validate the 'flags' parameter while
+ * registering an interrupt handler
+ ******************************************************************************/
+#define INTR_TYPE_FLAGS_MASK 0xFFFFFFFC
+
+#define INTR_RM_FROM_SEC_SHIFT SECURE /* BIT[0] */
+#define INTR_RM_FROM_NS_SHIFT NON_SECURE /* BIT[1] */
+#define INTR_RM_FROM_FLAG_MASK 1
+#define get_interrupt_rm_flag(flag, ss) (((flag >> INTR_RM_FLAGS_SHIFT) >> ss) \
+ & INTR_RM_FROM_FLAG_MASK)
+#define set_interrupt_rm_flag(flag, ss) (flag |= 1 << ss)
+#define clr_interrupt_rm_flag(flag, ss) (flag &= ~(1 << ss))
+
+
+/*******************************************************************************
+ * Macros to validate the routing model bits in the 'flags' for a type
+ * of interrupt. If the model does not match one of the valid masks
+ * -EINVAL is returned.
+ ******************************************************************************/
+#define validate_sel1_interrupt_rm(x) (x == INTR_SEL1_VALID_RM0 ? 0 : \
+ (x == INTR_SEL1_VALID_RM1 ? 0 :\
+ -EINVAL))
+
+#define validate_ns_interrupt_rm(x) (x == INTR_NS_VALID_RM0 ? 0 : \
+ (x == INTR_NS_VALID_RM1 ? 0 :\
+ -EINVAL))
+
+/*******************************************************************************
+ * Macros to set the 'flags' parameter passed to an interrupt type handler. Only
+ * the flag to indicate the security state when the exception was generated is
+ * supported.
+ ******************************************************************************/
+#define INTR_SRC_SS_FLAG_SHIFT 0 /* BIT[0] */
+#define INTR_SRC_SS_FLAG_MASK 1
+#define set_interrupt_src_ss(flag, val) (flag |= val << INTR_SRC_SS_FLAG_SHIFT)
+#define clr_interrupt_src_ss(flag) (flag &= ~(1 << INTR_SRC_SS_FLAG_SHIFT))
+#define get_interrupt_src_ss(flag) ((flag >> INTR_SRC_SS_FLAG_SHIFT) & \
+ INTR_SRC_SS_FLAG_MASK)
+
+#ifndef __ASSEMBLY__
+
+/* Prototype for defining a handler for an interrupt type */
+typedef uint64_t (*interrupt_type_handler_t)(uint32_t id,
+ uint32_t flags,
+ void *handle,
+ void *cookie);
+
+/*******************************************************************************
+ * Function & variable prototypes
+ ******************************************************************************/
+extern uint32_t get_scr_el3_from_routing_model(uint32_t security_state);
+extern int32_t set_routing_model(uint32_t type, uint32_t flags);
+extern int32_t register_interrupt_type_handler(uint32_t type,
+ interrupt_type_handler_t handler,
+ uint32_t flags);
+extern interrupt_type_handler_t get_interrupt_type_handler(uint32_t interrupt_type);
+
+#endif /*__ASSEMBLY__*/
+#endif /* __INTERRUPT_MGMT_H__ */
diff --git a/include/bl31/runtime_svc.h b/include/bl31/runtime_svc.h
index 6d7089678c..0f510f7606 100644
--- a/include/bl31/runtime_svc.h
+++ b/include/bl31/runtime_svc.h
@@ -135,9 +135,12 @@
typedef int32_t (*rt_svc_init_t)(void);
/* Convenience macros to return from SMC handler */
+#define SMC_RET0(_h) { \
+ return (uint64_t) (_h); \
+}
#define SMC_RET1(_h, _x0) { \
write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X0, (_x0)); \
- return _x0; \
+ SMC_RET0(_h); \
}
#define SMC_RET2(_h, _x0, _x1) { \
write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X1, (_x1)); \
diff --git a/include/bl32/payloads/tsp.h b/include/bl32/payloads/tsp.h
index 1f542d5366..3aa3e8c19d 100644
--- a/include/bl32/payloads/tsp.h
+++ b/include/bl32/payloads/tsp.h
@@ -42,7 +42,16 @@
#define TSP_RESUME_DONE 0xf2000004
#define TSP_WORK_DONE 0xf2000005
-/* SMC function ID that TSP uses to request service from secure montior */
+/*
+ * Function identifiers to handle FIQs through the synchronous handling model.
+ * If the TSP was previously interrupted then control has to be returned to
+ * the TSPD after handling the interrupt else execution can remain in the TSP.
+ */
+#define TSP_HANDLED_S_EL1_FIQ 0xf2000006
+#define TSP_EL3_FIQ 0xf2000007
+#define TSP_HANDLE_FIQ_AND_RETURN 0x2004
+
+/* SMC function ID that TSP uses to request service from secure monitor */
#define TSP_GET_ARGS 0xf2001000
/* Function IDs for various TSP services */
@@ -86,16 +95,17 @@
#include <cassert.h>
#include <platform.h> /* For CACHE_WRITEBACK_GRANULE */
+#include <spinlock.h>
#include <stdint.h>
typedef void (*tsp_generic_fptr_t)(uint64_t arg0,
- uint64_t arg1,
- uint64_t arg2,
- uint64_t arg3,
- uint64_t arg4,
- uint64_t arg5,
- uint64_t arg6,
- uint64_t arg7);
+ uint64_t arg1,
+ uint64_t arg2,
+ uint64_t arg3,
+ uint64_t arg4,
+ uint64_t arg5,
+ uint64_t arg6,
+ uint64_t arg7);
typedef struct entry_info {
tsp_generic_fptr_t fast_smc_entry;
@@ -103,9 +113,13 @@ typedef struct entry_info {
tsp_generic_fptr_t cpu_off_entry;
tsp_generic_fptr_t cpu_resume_entry;
tsp_generic_fptr_t cpu_suspend_entry;
+ tsp_generic_fptr_t fiq_entry;
} entry_info_t;
typedef struct work_statistics {
+ uint32_t fiq_count; /* Number of FIQs on this cpu */
+ uint32_t sync_fiq_count; /* Number of sync. fiqs on this cpu */
+ uint32_t sync_fiq_ret_count; /* Number of fiq returns on this cpu */
uint32_t smc_count; /* Number of returns on this cpu */
uint32_t eret_count; /* Number of entries on this cpu */
uint32_t cpu_on_count; /* Number of cpu on requests */
@@ -120,7 +134,7 @@ typedef struct tsp_args {
/* Macros to access members of the above structure using their offsets */
#define read_sp_arg(args, offset) ((args)->_regs[offset >> 3])
-#define write_sp_arg(args, offset, val)(((args)->_regs[offset >> 3]) \
+#define write_sp_arg(args, offset, val) (((args)->_regs[offset >> 3]) \
= val)
/*
@@ -131,6 +145,14 @@ CASSERT(TSP_ARGS_SIZE == sizeof(tsp_args_t), assert_sp_args_size_mismatch);
extern void tsp_get_magic(uint64_t args[4]);
+extern void tsp_fiq_entry(uint64_t arg0,
+ uint64_t arg1,
+ uint64_t arg2,
+ uint64_t arg3,
+ uint64_t arg4,
+ uint64_t arg5,
+ uint64_t arg6,
+ uint64_t arg7);
extern void tsp_fast_smc_entry(uint64_t arg0,
uint64_t arg1,
uint64_t arg2,
@@ -196,6 +218,20 @@ extern tsp_args_t *tsp_cpu_off_main(uint64_t arg0,
uint64_t arg5,
uint64_t arg6,
uint64_t arg7);
+
+/* Generic Timer functions */
+extern void tsp_generic_timer_start(void);
+extern void tsp_generic_timer_handler(void);
+extern void tsp_generic_timer_stop(void);
+extern void tsp_generic_timer_save(void);
+extern void tsp_generic_timer_restore(void);
+
+/* FIQ management functions */
+extern void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3);
+
+/* Data structure to keep track of TSP statistics */
+extern spinlock_t console_lock;
+extern work_statistics_t tsp_stats[PLATFORM_CORE_COUNT];
#endif /* __ASSEMBLY__ */
#endif /* __BL2_H__ */
diff --git a/include/drivers/arm/gic_v2.h b/include/drivers/arm/gic_v2.h
index ccf3d32c45..e81967638a 100644
--- a/include/drivers/arm/gic_v2.h
+++ b/include/drivers/arm/gic_v2.h
@@ -43,6 +43,7 @@
#define GIC_LOWEST_SEC_PRIORITY 127
#define GIC_HIGHEST_NS_PRIORITY 128
#define GIC_LOWEST_NS_PRIORITY 254 /* 255 would disable an interrupt */
+#define GIC_SPURIOUS_INTERRUPT 1023
#define ENABLE_GRP0 (1 << 0)
#define ENABLE_GRP1 (1 << 1)
@@ -88,6 +89,7 @@
#define GICC_EOIR 0x10
#define GICC_RPR 0x14
#define GICC_HPPIR 0x18
+#define GICC_AHPPIR 0x28
#define GICC_IIDR 0xFC
#define GICC_DIR 0x1000
#define GICC_PRIODROP GICC_EOIR
@@ -247,6 +249,11 @@ static inline unsigned int gicc_read_hppir(unsigned int base)
return mmio_read_32(base + GICC_HPPIR);
}
+static inline unsigned int gicc_read_ahppir(unsigned int base)
+{
+ return mmio_read_32(base + GICC_AHPPIR);
+}
+
static inline unsigned int gicc_read_dir(unsigned int base)
{
return mmio_read_32(base + GICC_DIR);
@@ -298,6 +305,12 @@ static inline void gicc_write_dir(unsigned int base, unsigned int val)
mmio_write_32(base + GICC_DIR, val);
}
+/*******************************************************************************
+ * Prototype of function to map an interrupt type to the interrupt line used to
+ * signal it.
+ ******************************************************************************/
+uint32_t gicv2_interrupt_type_to_line(uint32_t cpuif_base, uint32_t type);
+
#endif /*__ASSEMBLY__*/
#endif /* __GIC_V2_H__ */
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 1c11af3f58..920dfc9bbc 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)
@@ -264,6 +265,28 @@
((aif) & SPSR_AIF_MASK) << SPSR_AIF_SHIFT)
+/* Physical timer control register bit fields shifts and masks */
+#define CNTP_CTL_ENABLE_SHIFT 0
+#define CNTP_CTL_IMASK_SHIFT 1
+#define CNTP_CTL_ISTATUS_SHIFT 2
+
+#define CNTP_CTL_ENABLE_MASK 1
+#define CNTP_CTL_IMASK_MASK 1
+#define CNTP_CTL_ISTATUS_MASK 1
+
+#define get_cntp_ctl_enable(x) ((x >> CNTP_CTL_ENABLE_SHIFT) & \
+ CNTP_CTL_ENABLE_MASK)
+#define get_cntp_ctl_imask(x) ((x >> CNTP_CTL_IMASK_SHIFT) & \
+ CNTP_CTL_IMASK_MASK)
+#define get_cntp_ctl_istatus(x) ((x >> CNTP_CTL_ISTATUS_SHIFT) & \
+ CNTP_CTL_ISTATUS_MASK)
+
+#define set_cntp_ctl_enable(x) (x |= 1 << CNTP_CTL_ENABLE_SHIFT)
+#define set_cntp_ctl_imask(x) (x |= 1 << CNTP_CTL_IMASK_SHIFT)
+
+#define clr_cntp_ctl_enable(x) (x &= ~(1 << CNTP_CTL_ENABLE_SHIFT))
+#define clr_cntp_ctl_imask(x) (x &= ~(1 << CNTP_CTL_IMASK_SHIFT))
+
/* Miscellaneous MMU related constants */
#define NUM_2MB_IN_GB (1 << 9)
#define NUM_4K_IN_2MB (1 << 9)
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index 0a398d0816..f30301d179 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -202,6 +202,10 @@ extern unsigned long read_cptr_el3(void);
extern unsigned long read_cpacr(void);
extern unsigned long read_cpuectlr(void);
extern unsigned int read_cntfrq_el0(void);
+extern unsigned int read_cntps_ctl_el1(void);
+extern unsigned int read_cntps_tval_el1(void);
+extern unsigned long read_cntps_cval_el1(void);
+extern unsigned long read_cntpct_el0(void);
extern unsigned long read_cnthctl_el2(void);
extern unsigned long read_tpidr_el3(void);
@@ -210,6 +214,9 @@ extern void write_scr(unsigned long);
extern void write_hcr(unsigned long);
extern void write_cpacr(unsigned long);
extern void write_cntfrq_el0(unsigned int);
+extern void write_cntps_ctl_el1(unsigned int);
+extern void write_cntps_tval_el1(unsigned int);
+extern void write_cntps_cval_el1(unsigned long);
extern void write_cnthctl_el2(unsigned long);
extern void write_vbar_el1(unsigned long);
diff --git a/lib/aarch64/sysreg_helpers.S b/lib/aarch64/sysreg_helpers.S
index c86fdba058..925e93e379 100644
--- a/lib/aarch64/sysreg_helpers.S
+++ b/lib/aarch64/sysreg_helpers.S
@@ -142,6 +142,15 @@
.globl read_cntfrq_el0
.globl write_cntfrq_el0
+ .globl read_cntps_ctl_el1
+ .globl write_cntps_ctl_el1
+
+ .globl read_cntps_cval_el1
+ .globl write_cntps_cval_el1
+
+ .globl read_cntps_tval_el1
+ .globl write_cntps_tval_el1
+
.globl read_scr
.globl write_scr
@@ -151,6 +160,7 @@
.globl read_midr
.globl read_mpidr
+ .globl read_cntpct_el0
.globl read_current_el
.globl read_id_pfr1_el1
.globl read_id_aa64pfr0_el1
@@ -672,6 +682,33 @@ func write_cntfrq_el0
msr cntfrq_el0, x0
ret
+func read_cntps_ctl_el1
+ mrs x0, cntps_ctl_el1
+ ret
+
+func write_cntps_ctl_el1
+ msr cntps_ctl_el1, x0
+ ret
+
+func read_cntps_cval_el1
+ mrs x0, cntps_cval_el1
+ ret
+
+func write_cntps_cval_el1
+ msr cntps_cval_el1, x0
+ ret
+
+func read_cntps_tval_el1
+ mrs x0, cntps_tval_el1
+ ret
+
+func write_cntps_tval_el1
+ msr cntps_tval_el1, x0
+ ret
+
+func read_cntpct_el0
+ mrs x0, cntpct_el0
+ ret
func read_cpuectlr
mrs x0, CPUECTLR_EL1
diff --git a/plat/fvp/bl32_plat_setup.c b/plat/fvp/bl32_plat_setup.c
index 8406d313cf..772e972fa0 100644
--- a/plat/fvp/bl32_plat_setup.c
+++ b/plat/fvp/bl32_plat_setup.c
@@ -73,6 +73,9 @@ void bl32_early_platform_setup(void)
* messages from TSP
*/
console_init(PL011_UART1_BASE);
+
+ /* Initialize the platform config for future decision making */
+ platform_config_setup();
}
/*******************************************************************************
diff --git a/plat/fvp/plat_gic.c b/plat/fvp/plat_gic.c
index db3c9cf6fd..7dec404f8e 100644
--- a/plat/fvp/plat_gic.c
+++ b/plat/fvp/plat_gic.c
@@ -29,18 +29,15 @@
*/
#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
#include <debug.h>
#include <gic_v2.h>
#include <gic_v3.h>
+#include <interrupt_mgmt.h>
#include <platform.h>
#include <stdint.h>
-
-/*******************************************************************************
- * TODO: Revisit if priorities are being set such that no non-secure interrupt
- * can have a higher priority than a secure one as recommended in the GICv2 spec
- ******************************************************************************/
-
/*******************************************************************************
* This function does some minimal GICv3 configuration. The Firmware itself does
* not fully support GICv3 at this time and relies on GICv2 emulation as
@@ -284,3 +281,126 @@ void gic_setup(void)
gic_cpuif_setup(gicc_base);
gic_distif_setup(gicd_base);
}
+
+/*******************************************************************************
+ * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
+ * The interrupt controller knows which pin/line it uses to signal a type of
+ * interrupt. The platform knows which interrupt controller type is being used
+ * in a particular security state e.g. with an ARM GIC, normal world could use
+ * the GICv2 features while the secure world could use GICv3 features and vice
+ * versa.
+ * This function is exported by the platform to let the interrupt management
+ * framework determine for a type of interrupt and security state, which line
+ * should be used in the SCR_EL3 to control its routing to EL3. The interrupt
+ * line is represented as the bit position of the IRQ or FIQ bit in the SCR_EL3.
+ ******************************************************************************/
+uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state)
+{
+ uint32_t gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
+
+ assert(type == INTR_TYPE_S_EL1 ||
+ type == INTR_TYPE_EL3 ||
+ type == INTR_TYPE_NS);
+
+ assert(security_state == NON_SECURE || security_state == SECURE);
+
+ /*
+ * We ignore the security state parameter under the assumption that
+ * both normal and secure worlds are using ARM GICv2. This parameter
+ * will be used when the secure world starts using GICv3.
+ */
+#if FVP_GIC_ARCH == 2
+ return gicv2_interrupt_type_to_line(gicc_base, type);
+#else
+#error "Invalid GIC architecture version specified for FVP port"
+#endif
+}
+
+#if FVP_GIC_ARCH == 2
+/*******************************************************************************
+ * This function returns the type of the highest priority pending interrupt at
+ * the GIC cpu interface. INTR_TYPE_INVAL is returned when there is no
+ * interrupt pending.
+ ******************************************************************************/
+uint32_t ic_get_pending_interrupt_type()
+{
+ uint32_t id, gicc_base;
+
+ gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
+ id = gicc_read_hppir(gicc_base);
+
+ /* Assume that all secure interrupts are S-EL1 interrupts */
+ if (id < 1022)
+ return INTR_TYPE_S_EL1;
+
+ if (id == GIC_SPURIOUS_INTERRUPT)
+ return INTR_TYPE_INVAL;
+
+ return INTR_TYPE_NS;
+}
+
+/*******************************************************************************
+ * This function returns the id of the highest priority pending interrupt at
+ * the GIC cpu interface. INTR_ID_UNAVAILABLE is returned when there is no
+ * interrupt pending.
+ ******************************************************************************/
+uint32_t ic_get_pending_interrupt_id()
+{
+ uint32_t id, gicc_base;
+
+ gicc_base = platform_get_cfgvar(CONFIG_GICC_ADDR);
+ id = gicc_read_hppir(gicc_base);
+
+ if (id < 1022)
+ return id;
+
+ if (id == 1023)
+ return INTR_ID_UNAVAILABLE;
+
+ /*
+ * Find out which non-secure interrupt it is under the assumption that
+ * the GICC_CTLR.AckCtl bit is 0.
+ */
+ return gicc_read_ahppir(gicc_base);
+}
+
+/*******************************************************************************
+ * This functions reads the GIC cpu interface Interrupt Acknowledge register
+ * to start handling the pending interrupt. It returns the contents of the IAR.
+ ******************************************************************************/
+uint32_t ic_acknowledge_interrupt()
+{
+ return gicc_read_IAR(platform_get_cfgvar(CONFIG_GICC_ADDR));
+}
+
+/*******************************************************************************
+ * This functions writes the GIC cpu interface End Of Interrupt register with
+ * the passed value to finish handling the active interrupt
+ ******************************************************************************/
+void ic_end_of_interrupt(uint32_t id)
+{
+ gicc_write_EOIR(platform_get_cfgvar(CONFIG_GICC_ADDR), id);
+ return;
+}
+
+/*******************************************************************************
+ * This function returns the type of the interrupt id depending upon the group
+ * this interrupt has been configured under by the interrupt controller i.e.
+ * group0 or group1.
+ ******************************************************************************/
+uint32_t ic_get_interrupt_type(uint32_t id)
+{
+ uint32_t group;
+
+ group = gicd_get_igroupr(platform_get_cfgvar(CONFIG_GICD_ADDR), id);
+
+ /* Assume that all secure interrupts are S-EL1 interrupts */
+ if (group == GRP0)
+ return INTR_TYPE_S_EL1;
+ else
+ return INTR_TYPE_NS;
+}
+
+#else
+#error "Invalid GIC architecture version specified for FVP port"
+#endif
diff --git a/plat/fvp/platform.h b/plat/fvp/platform.h
index 6ab68629a9..4c0f38f5de 100644
--- a/plat/fvp/platform.h
+++ b/plat/fvp/platform.h
@@ -452,13 +452,20 @@ extern void plat_get_entry_point_info(unsigned long target_security,
extern void fvp_cci_setup(void);
-/* Declarations for fvp_gic.c */
+/* Declarations for plat_gic.c */
+extern uint32_t ic_get_pending_interrupt_id(void);
+extern uint32_t ic_get_pending_interrupt_type(void);
+extern uint32_t ic_acknowledge_interrupt(void);
+extern uint32_t ic_get_interrupt_type(uint32_t id);
+extern void ic_end_of_interrupt(uint32_t id);
extern void gic_cpuif_deactivate(unsigned int);
extern void gic_cpuif_setup(unsigned int);
extern void gic_pcpu_distif_setup(unsigned int);
extern void gic_setup(void);
+extern uint32_t plat_interrupt_type_to_line(uint32_t type,
+ uint32_t security_state);
-/* Declarations for fvp_topology.c */
+/* Declarations for plat_topology.c */
extern int plat_setup_topology(void);
extern int plat_get_max_afflvl(void);
extern unsigned int plat_get_aff_count(unsigned int, unsigned long);
diff --git a/plat/fvp/platform.mk b/plat/fvp/platform.mk
index 82bafed6f7..f1d6f878d6 100644
--- a/plat/fvp/platform.mk
+++ b/plat/fvp/platform.mk
@@ -86,3 +86,8 @@ ifeq (${RESET_TO_BL31}, 1)
BL31_SOURCES += drivers/arm/tzc400/tzc400.c \
plat/fvp/plat_security.c
endif
+
+# Flag used by the FVP port to determine the version of ARM GIC architecture
+# to use for interrupt management in EL3.
+FVP_GIC_ARCH := 2
+$(eval $(call add_define,FVP_GIC_ARCH))
diff --git a/services/spd/tspd/tspd_common.c b/services/spd/tspd/tspd_common.c
index d3fe5ddf58..2ca6a56af2 100644
--- a/services/spd/tspd/tspd_common.c
+++ b/services/spd/tspd/tspd_common.c
@@ -42,9 +42,9 @@
* programming an entry into the secure payload.
******************************************************************************/
int32_t tspd_init_secure_context(uint64_t entrypoint,
- uint32_t rw,
- uint64_t mpidr,
- tsp_context_t *tsp_ctx)
+ uint32_t rw,
+ uint64_t mpidr,
+ tsp_context_t *tsp_ctx)
{
uint32_t scr, sctlr;
el1_sys_regs_t *el1_state;
@@ -65,10 +65,14 @@ int32_t tspd_init_secure_context(uint64_t entrypoint,
*/
memset(tsp_ctx, 0, sizeof(*tsp_ctx));
- /* Set the right security state and register width for the SP */
+ /*
+ * Set the right security state, register width and enable access to
+ * the secure physical timer for the SP.
+ */
scr = read_scr();
scr &= ~SCR_NS_BIT;
scr &= ~SCR_RW_BIT;
+ scr |= SCR_ST_BIT;
if (rw == TSP_AARCH64)
scr |= SCR_RW_BIT;
@@ -85,7 +89,14 @@ int32_t tspd_init_secure_context(uint64_t entrypoint,
write_ctx_reg(el1_state, CTX_SCTLR_EL1, sctlr);
/* Set this context as ready to be initialised i.e OFF */
- tsp_ctx->state = TSP_STATE_OFF;
+ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF);
+
+ /*
+ * This context has not been used yet. It will become valid
+ * when the TSP is interrupted and wants the TSPD to preserve
+ * the context.
+ */
+ clr_std_smc_active_flag(tsp_ctx->state);
/* Associate this context with the cpu specified */
tsp_ctx->mpidr = mpidr;
diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c
index 21ff7ffe38..74e2af0fe3 100644
--- a/services/spd/tspd/tspd_main.c
+++ b/services/spd/tspd/tspd_main.c
@@ -43,6 +43,9 @@
#include <bl_common.h>
#include <bl31.h>
#include <context_mgmt.h>
+#include <debug.h>
+#include <errno.h>
+#include <platform.h>
#include <runtime_svc.h>
#include <stddef.h>
#include <tsp.h>
@@ -68,6 +71,75 @@ DEFINE_SVC_UUID(tsp_uuid,
int32_t tspd_init(void);
+/*******************************************************************************
+ * This function is the handler registered for S-EL1 interrupts by the TSPD. It
+ * validates the interrupt and upon success arranges entry into the TSP at
+ * 'tsp_fiq_entry()' for handling the interrupt.
+ ******************************************************************************/
+static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
+ uint32_t flags,
+ void *handle,
+ void *cookie)
+{
+ uint32_t linear_id;
+ uint64_t mpidr;
+ tsp_context_t *tsp_ctx;
+
+ /* Check the security state when the exception was generated */
+ assert(get_interrupt_src_ss(flags) == NON_SECURE);
+
+#if IMF_READ_INTERRUPT_ID
+ /* Check the security status of the interrupt */
+ assert(ic_get_interrupt_group(id) == SECURE);
+#endif
+
+ /* Sanity check the pointer to this cpu's context */
+ mpidr = read_mpidr();
+ assert(handle == cm_get_context(mpidr, NON_SECURE));
+
+ /* Save the non-secure context before entering the TSP */
+ cm_el1_sysregs_context_save(NON_SECURE);
+
+ /* Get a reference to this cpu's TSP context */
+ linear_id = platform_get_core_pos(mpidr);
+ tsp_ctx = &tspd_sp_context[linear_id];
+ assert(&tsp_ctx->cpu_ctx == cm_get_context(mpidr, SECURE));
+
+ /*
+ * Determine if the TSP was previously preempted. Its last known
+ * context has to be preserved in this case.
+ * The TSP should return control to the TSPD after handling this
+ * FIQ. Preserve essential EL3 context to allow entry into the
+ * TSP at the FIQ entry point using the 'cpu_context' structure.
+ * There is no need to save the secure system register context
+ * since the TSP is supposed to preserve it during S-EL1 interrupt
+ * handling.
+ */
+ if (get_std_smc_active_flag(tsp_ctx->state)) {
+ tsp_ctx->saved_spsr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
+ CTX_SPSR_EL3);
+ tsp_ctx->saved_elr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
+ CTX_ELR_EL3);
+ }
+
+ SMC_SET_EL3(&tsp_ctx->cpu_ctx,
+ CTX_SPSR_EL3,
+ SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
+ SMC_SET_EL3(&tsp_ctx->cpu_ctx,
+ CTX_ELR_EL3,
+ (uint64_t) tsp_entry_info->fiq_entry);
+ cm_el1_sysregs_context_restore(SECURE);
+ cm_set_next_eret_context(SECURE);
+
+ /*
+ * Tell the TSP that it has to handle an FIQ synchronously. Also the
+ * instruction in normal world where the interrupt was generated is
+ * passed for debugging purposes. It is safe to retrieve this address
+ * from ELR_EL3 as the secure context will not take effect until
+ * el3_exit().
+ */
+ SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_FIQ_AND_RETURN, read_elr_el3());
+}
/*******************************************************************************
* Secure Payload Dispatcher setup. The SPD finds out the SP entrypoint and type
@@ -131,7 +203,7 @@ int32_t tspd_setup(void)
int32_t tspd_init(void)
{
uint64_t mpidr = read_mpidr();
- uint32_t linear_id = platform_get_core_pos(mpidr);
+ uint32_t linear_id = platform_get_core_pos(mpidr), flags;
uint64_t rc;
tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
@@ -142,7 +214,7 @@ int32_t tspd_init(void)
rc = tspd_synchronous_sp_entry(tsp_ctx);
assert(rc != 0);
if (rc) {
- tsp_ctx->state = TSP_STATE_ON;
+ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
/*
* TSP has been successfully initialized. Register power
@@ -151,6 +223,18 @@ int32_t tspd_init(void)
psci_register_spd_pm_hook(&tspd_pm);
}
+ /*
+ * Register an interrupt handler for S-EL1 interrupts when generated
+ * during code executing in the non-secure state.
+ */
+ flags = 0;
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+ tspd_sel1_interrupt_handler,
+ flags);
+ if (rc)
+ panic();
+
return rc;
}
@@ -184,6 +268,73 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
switch (smc_fid) {
/*
+ * This function ID is used only by the TSP to indicate that it has
+ * finished handling a S-EL1 FIQ interrupt. Execution should resume
+ * in the normal world.
+ */
+ case TSP_HANDLED_S_EL1_FIQ:
+ if (ns)
+ SMC_RET1(handle, SMC_UNK);
+
+ assert(handle == cm_get_context(mpidr, SECURE));
+
+ /*
+ * Restore the relevant EL3 state which saved to service
+ * this SMC.
+ */
+ if (get_std_smc_active_flag(tsp_ctx->state)) {
+ SMC_SET_EL3(&tsp_ctx->cpu_ctx,
+ CTX_SPSR_EL3,
+ tsp_ctx->saved_spsr_el3);
+ SMC_SET_EL3(&tsp_ctx->cpu_ctx,
+ CTX_ELR_EL3,
+ tsp_ctx->saved_elr_el3);
+ }
+
+ /* Get a reference to the non-secure context */
+ ns_cpu_context = cm_get_context(mpidr, NON_SECURE);
+ assert(ns_cpu_context);
+
+ /*
+ * Restore non-secure state. There is no need to save the
+ * secure system register context since the TSP was supposed
+ * to preserve it during S-EL1 interrupt handling.
+ */
+ cm_el1_sysregs_context_restore(NON_SECURE);
+ cm_set_next_eret_context(NON_SECURE);
+
+ SMC_RET0((uint64_t) ns_cpu_context);
+
+
+ /*
+ * This function ID is used only by the TSP to indicate that it was
+ * interrupted due to a EL3 FIQ interrupt. Execution should resume
+ * in the normal world.
+ */
+ case TSP_EL3_FIQ:
+ if (ns)
+ SMC_RET1(handle, SMC_UNK);
+
+ assert(handle == cm_get_context(mpidr, SECURE));
+
+ /* Assert that standard SMC execution has been preempted */
+ assert(get_std_smc_active_flag(tsp_ctx->state));
+
+ /* Save the secure system register state */
+ cm_el1_sysregs_context_save(SECURE);
+
+ /* Get a reference to the non-secure context */
+ ns_cpu_context = cm_get_context(mpidr, NON_SECURE);
+ assert(ns_cpu_context);
+
+ /* Restore non-secure state */
+ cm_el1_sysregs_context_restore(NON_SECURE);
+ cm_set_next_eret_context(NON_SECURE);
+
+ SMC_RET1(ns_cpu_context, TSP_EL3_FIQ);
+
+
+ /*
* This function ID is used only by the SP to indicate it has
* finished initialising itself after a cold boot
*/
@@ -282,7 +433,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 2447d9e837..d99aa2224c 100644
--- a/services/spd/tspd/tspd_pm.c
+++ b/services/spd/tspd/tspd_pm.c
@@ -56,10 +56,10 @@ static int32_t tspd_cpu_off_handler(uint64_t cookie)
tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
assert(tsp_entry_info);
- assert(tsp_ctx->state == TSP_STATE_ON);
+ 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);
/*
@@ -73,7 +73,7 @@ static int32_t tspd_cpu_off_handler(uint64_t cookie)
* Reset TSP's context for a fresh start when this cpu is turned on
* subsequently.
*/
- tsp_ctx->state = TSP_STATE_OFF;
+ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF);
return 0;
}
@@ -90,13 +90,13 @@ static void tspd_cpu_suspend_handler(uint64_t power_state)
tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
assert(tsp_entry_info);
- assert(tsp_ctx->state == TSP_STATE_ON);
+ assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
/* Program the entry point, power_state parameter and enter the TSP */
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);
/*
@@ -107,7 +107,7 @@ static void tspd_cpu_suspend_handler(uint64_t power_state)
panic();
/* Update its context to reflect the state the TSP is in */
- tsp_ctx->state = TSP_STATE_SUSPEND;
+ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_SUSPEND);
}
/*******************************************************************************
@@ -124,7 +124,7 @@ static void tspd_cpu_on_finish_handler(uint64_t cookie)
tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
assert(tsp_entry_info);
- assert(tsp_ctx->state == TSP_STATE_OFF);
+ assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_OFF);
/* Initialise this cpu's secure context */
tspd_init_secure_context((uint64_t) tsp_entry_info->cpu_on_entry,
@@ -143,7 +143,7 @@ static void tspd_cpu_on_finish_handler(uint64_t cookie)
panic();
/* Update its context to reflect the state the SP is in */
- tsp_ctx->state = TSP_STATE_ON;
+ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
}
/*******************************************************************************
@@ -159,13 +159,13 @@ static void tspd_cpu_suspend_finish_handler(uint64_t suspend_level)
tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
assert(tsp_entry_info);
- assert(tsp_ctx->state == TSP_STATE_SUSPEND);
+ assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_SUSPEND);
/* Program the entry point, suspend_level and enter the SP */
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);
/*
@@ -176,7 +176,7 @@ static void tspd_cpu_suspend_finish_handler(uint64_t suspend_level)
panic();
/* Update its context to reflect the state the SP is in */
- tsp_ctx->state = TSP_STATE_ON;
+ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
}
/*******************************************************************************
diff --git a/services/spd/tspd/tspd_private.h b/services/spd/tspd/tspd_private.h
index 81484e1cf3..b9cf496d47 100644
--- a/services/spd/tspd/tspd_private.h
+++ b/services/spd/tspd/tspd_private.h
@@ -33,15 +33,47 @@
#include <arch.h>
#include <context.h>
+#include <interrupt_mgmt.h>
#include <platform.h>
#include <psci.h>
/*******************************************************************************
* Secure Payload PM state information e.g. SP is suspended, uninitialised etc
+ * and macros to access the state information in the per-cpu 'state' flags
******************************************************************************/
-#define TSP_STATE_OFF 0
-#define TSP_STATE_ON 1
-#define TSP_STATE_SUSPEND 2
+#define TSP_PSTATE_OFF 0
+#define TSP_PSTATE_ON 1
+#define TSP_PSTATE_SUSPEND 2
+#define TSP_PSTATE_SHIFT 0
+#define TSP_PSTATE_MASK 0x3
+#define get_tsp_pstate(state) ((state >> TSP_PSTATE_SHIFT) & TSP_PSTATE_MASK)
+#define clr_tsp_pstate(state) (state &= ~(TSP_PSTATE_MASK \
+ << TSP_PSTATE_SHIFT))
+#define set_tsp_pstate(st, pst) do { \
+ clr_tsp_pstate(st); \
+ st |= (pst & TSP_PSTATE_MASK) << \
+ TSP_PSTATE_SHIFT; \
+ } while (0);
+
+
+/*
+ * This flag is used by the TSPD to determine if the TSP is servicing a standard
+ * SMC request prior to programming the next entry into the TSP e.g. if TSP
+ * execution is preempted by a non-secure interrupt and handed control to the
+ * normal world. If another request which is distinct from what the TSP was
+ * previously doing arrives, then this flag will be help the TSPD to either
+ * reject the new request or service it while ensuring that the previous context
+ * is not corrupted.
+ */
+#define STD_SMC_ACTIVE_FLAG_SHIFT 2
+#define STD_SMC_ACTIVE_FLAG_MASK 1
+#define get_std_smc_active_flag(state) ((state >> STD_SMC_ACTIVE_FLAG_SHIFT) \
+ & STD_SMC_ACTIVE_FLAG_MASK)
+#define set_std_smc_active_flag(state) (state |= \
+ 1 << STD_SMC_ACTIVE_FLAG_SHIFT)
+#define clr_std_smc_active_flag(state) (state &= \
+ ~(STD_SMC_ACTIVE_FLAG_MASK \
+ << STD_SMC_ACTIVE_FLAG_SHIFT))
/*******************************************************************************
* Secure Payload execution state information i.e. aarch32 or aarch64
@@ -106,13 +138,19 @@ CASSERT(TSPD_C_RT_CTX_SIZE == sizeof(c_rt_regs_t), \
/*******************************************************************************
* Structure which helps the SPD to maintain the per-cpu state of the SP.
- * 'state' - collection of flags to track SP state e.g. on/off
- * 'mpidr' - mpidr to associate a context with a cpu
- * 'c_rt_ctx' - stack address to restore C runtime context from after returning
- * from a synchronous entry into the SP.
- * 'cpu_ctx' - space to maintain SP architectural state
+ * 'saved_spsr_el3' - temporary copy to allow FIQ handling when the TSP has been
+ * preempted.
+ * 'saved_elr_el3' - temporary copy to allow FIQ handling when the TSP has been
+ * preempted.
+ * 'state' - collection of flags to track SP state e.g. on/off
+ * 'mpidr' - mpidr to associate a context with a cpu
+ * 'c_rt_ctx' - stack address to restore C runtime context from after
+ * returning from a synchronous entry into the SP.
+ * 'cpu_ctx' - space to maintain SP architectural state
******************************************************************************/
typedef struct tsp_context {
+ uint64_t saved_elr_el3;
+ uint32_t saved_spsr_el3;
uint32_t state;
uint64_t mpidr;
uint64_t c_rt_ctx;
diff --git a/services/std_svc/psci/psci_entry.S b/services/std_svc/psci/psci_entry.S
index 3d0181a8ed..bc8d90041e 100644
--- a/services/std_svc/psci/psci_entry.S
+++ b/services/std_svc/psci/psci_entry.S
@@ -30,7 +30,6 @@
#include <arch.h>
#include <asm_macros.S>
-#include <cm_macros.S>
#include <psci.h>
.globl psci_aff_on_finish_entry