mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-17 01:54:22 +00:00
Use secure timer to generate S-EL1 interrupts
This patch adds support in the TSP to program the secure physical generic timer to generate a EL-1 interrupt every half second. It also adds support for maintaining the timer state across power management operations. The TSPD ensures that S-EL1 can access the timer by programming the SCR_EL3.ST bit. This patch does not actually enable the timer. This will be done in a subsequent patch once the complete framework for handling S-EL1 interrupts is in place. Change-Id: I1b3985cfb50262f60824be3a51c6314ce90571bc
This commit is contained in:
parent
dce74b891e
commit
fa9c08b7d1
7 changed files with 186 additions and 2 deletions
|
@ -32,7 +32,8 @@ BL32_SOURCES += bl32/tsp/tsp_main.c \
|
|||
bl32/tsp/aarch64/tsp_entrypoint.S \
|
||||
bl32/tsp/aarch64/tsp_request.S \
|
||||
common/aarch64/early_exceptions.S \
|
||||
lib/locks/exclusive/spinlock.S
|
||||
lib/locks/exclusive/spinlock.S \
|
||||
bl32/tsp/tsp_timer.c
|
||||
|
||||
BL32_LINKERFILE := bl32/tsp/tsp.ld.S
|
||||
|
||||
|
|
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);
|
||||
}
|
|
@ -196,6 +196,13 @@ 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);
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __BL2_H__ */
|
||||
|
|
|
@ -265,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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue