mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 09:34:18 +00:00
Merge pull request #102 from achingupta:ag/tf-issues#104-v2
This commit is contained in:
commit
8545a8744b
32 changed files with 1572 additions and 125 deletions
|
@ -31,8 +31,6 @@
|
|||
#include <arch.h>
|
||||
#include <asm_macros.S>
|
||||
#include <bl_common.h>
|
||||
#include <cm_macros.S>
|
||||
|
||||
|
||||
.globl bl31_entrypoint
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -183,6 +190,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
|
||||
|
|
206
bl31/interrupt_mgmt.c
Normal file
206
bl31/interrupt_mgmt.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
/* ---------------------------------------------
|
||||
|
@ -226,6 +243,58 @@ func tsp_cpu_suspend_entry
|
|||
bl tsp_cpu_suspend_main
|
||||
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
|
||||
|
|
200
bl32/tsp/aarch64/tsp_exceptions.S
Normal file
200
bl32/tsp/aarch64/tsp_exceptions.S
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
109
bl32/tsp/tsp_interrupt.c
Normal file
109
bl32/tsp/tsp_interrupt.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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++;
|
||||
|
|
106
bl32/tsp/tsp_timer.c
Normal file
106
bl32/tsp/tsp_timer.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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__ */
|
||||
|
|
128
include/bl31/interrupt_mgmt.h
Normal file
128
include/bl31/interrupt_mgmt.h
Normal file
|
@ -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__ */
|
|
@ -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)); \
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -183,6 +267,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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include <arch.h>
|
||||
#include <asm_macros.S>
|
||||
#include <cm_macros.S>
|
||||
#include <psci.h>
|
||||
|
||||
.globl psci_aff_on_finish_entry
|
||||
|
|
Loading…
Add table
Reference in a new issue