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:
Achin Gupta 2014-05-09 12:00:17 +01:00
parent dce74b891e
commit fa9c08b7d1
7 changed files with 186 additions and 2 deletions

View File

@ -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
View 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);
}

View File

@ -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__ */

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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;