Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
9d212557
Commit
9d212557
authored
Jan 26, 2015
by
danh-arm
Browse files
Merge pull request #246 from soby-mathew/sm/route_IRQ_EL3
Demonstrate model for routing IRQs to EL3
parents
07ddb33a
f4f1ae77
Changes
7
Hide whitespace changes
Inline
Side-by-side
bl31/interrupt_mgmt.c
View file @
9d212557
...
...
@@ -158,6 +158,45 @@ int32_t set_routing_model(uint32_t type, uint32_t flags)
return
0
;
}
/******************************************************************************
* This function disables the routing model of interrupt 'type' from the
* specified 'security_state' on the local core. The disable is in effect
* till the core powers down or till the next enable for that interrupt
* type.
*****************************************************************************/
int
disable_intr_rm_local
(
uint32_t
type
,
uint32_t
security_state
)
{
uint32_t
bit_pos
,
flag
;
assert
(
intr_type_descs
[
type
].
handler
);
flag
=
get_interrupt_rm_flag
(
INTR_DEFAULT_RM
,
security_state
);
bit_pos
=
plat_interrupt_type_to_line
(
type
,
security_state
);
cm_write_scr_el3_bit
(
security_state
,
bit_pos
,
flag
);
return
0
;
}
/******************************************************************************
* This function enables the routing model of interrupt 'type' from the
* specified 'security_state' on the local core.
*****************************************************************************/
int
enable_intr_rm_local
(
uint32_t
type
,
uint32_t
security_state
)
{
uint32_t
bit_pos
,
flag
;
assert
(
intr_type_descs
[
type
].
handler
);
flag
=
get_interrupt_rm_flag
(
intr_type_descs
[
type
].
flags
,
security_state
);
bit_pos
=
plat_interrupt_type_to_line
(
type
,
security_state
);
cm_write_scr_el3_bit
(
security_state
,
bit_pos
,
flag
);
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
...
...
docs/user-guide.md
View file @
9d212557
...
...
@@ -251,6 +251,11 @@ performed.
(Coherent memory region is included) or 0 (Coherent memory region is
excluded). Default is 1.
*
`TSPD_ROUTE_IRQ_TO_EL3`
: A non zero value enables the routing model
for non-secure interrupts in which they are routed to EL3 (TSPD). The
default model (when the value is 0) is to route non-secure interrupts
to S-EL1 (TSP).
#### FVP specific build options
*
`FVP_TSP_RAM_LOCATION`
: location of the TSP binary. Options:
...
...
include/bl31/interrupt_mgmt.h
View file @
9d212557
...
...
@@ -63,7 +63,8 @@
#define INTR_NS_VALID_RM0 0x0
/* Routed to EL1/EL2 from NS and to EL3 from Secure */
#define INTR_NS_VALID_RM1 0x1
/* This is the default routing model */
#define INTR_DEFAULT_RM 0x0
/*******************************************************************************
* Constants for the _individual_ routing model bits in the 'flags' field for
...
...
@@ -123,6 +124,8 @@ int32_t register_interrupt_type_handler(uint32_t type,
interrupt_type_handler_t
handler
,
uint32_t
flags
);
interrupt_type_handler_t
get_interrupt_type_handler
(
uint32_t
interrupt_type
);
int
disable_intr_rm_local
(
uint32_t
type
,
uint32_t
security_state
);
int
enable_intr_rm_local
(
uint32_t
type
,
uint32_t
security_state
);
#endif
/*__ASSEMBLY__*/
#endif
/* __INTERRUPT_MGMT_H__ */
services/spd/tspd/tspd.mk
View file @
9d212557
...
...
@@ -52,3 +52,10 @@ include ${BL32_ROOT}/tsp.mk
# Let the top-level Makefile know that we intend to build the SP from source
NEED_BL32
:=
yes
# Flag used to enable routing of non-secure interrupts to EL3 when they are
# generated while the code is executing in S-EL1/0.
TSPD_ROUTE_IRQ_TO_EL3
:=
0
$(eval
$(call
assert_boolean,TSPD_ROUTE_IRQ_TO_EL3))
$(eval
$(call
add_define,TSPD_ROUTE_IRQ_TO_EL3))
services/spd/tspd/tspd_main.c
View file @
9d212557
...
...
@@ -48,6 +48,7 @@
#include <platform.h>
#include <runtime_svc.h>
#include <stddef.h>
#include <string.h>
#include <tsp.h>
#include <uuid.h>
#include "tspd_private.h"
...
...
@@ -71,6 +72,24 @@ DEFINE_SVC_UUID(tsp_uuid,
int32_t
tspd_init
(
void
);
uint64_t
tspd_handle_sp_preemption
(
void
*
handle
)
{
cpu_context_t
*
ns_cpu_context
;
assert
(
handle
==
cm_get_context
(
SECURE
));
cm_el1_sysregs_context_save
(
SECURE
);
/* Get a reference to the non-secure context */
ns_cpu_context
=
cm_get_context
(
NON_SECURE
);
assert
(
ns_cpu_context
);
/*
* Restore non-secure state. The secure system
* register context will be saved when required.
*/
cm_el1_sysregs_context_restore
(
NON_SECURE
);
cm_set_next_eret_context
(
NON_SECURE
);
SMC_RET1
(
ns_cpu_context
,
SMC_PREEMPTED
);
}
/*******************************************************************************
* 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
...
...
@@ -120,11 +139,16 @@ static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
CTX_SPSR_EL3
);
tsp_ctx
->
saved_elr_el3
=
SMC_GET_EL3
(
&
tsp_ctx
->
cpu_ctx
,
CTX_ELR_EL3
);
#if TSPD_ROUTE_IRQ_TO_EL3
/*Need to save the previously interrupted secure context */
memcpy
(
&
tsp_ctx
->
sp_ctx
,
&
tsp_ctx
->
cpu_ctx
,
TSPD_SP_CTX_SIZE
);
#endif
}
cm_el1_sysregs_context_restore
(
SECURE
);
cm_set_elr_spsr_el3
(
SECURE
,
(
uint64_t
)
&
tsp_vectors
->
fiq_entry
,
SPSR_64
(
MODE_EL1
,
MODE_SP_ELX
,
DISABLE_ALL_EXCEPTIONS
));
cm_set_next_eret_context
(
SECURE
);
/*
...
...
@@ -137,6 +161,34 @@ static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
SMC_RET2
(
&
tsp_ctx
->
cpu_ctx
,
TSP_HANDLE_FIQ_AND_RETURN
,
read_elr_el3
());
}
#if TSPD_ROUTE_IRQ_TO_EL3
/*******************************************************************************
* 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_ns_interrupt_handler
(
uint32_t
id
,
uint32_t
flags
,
void
*
handle
,
void
*
cookie
)
{
/* Check the security state when the exception was generated */
assert
(
get_interrupt_src_ss
(
flags
)
==
SECURE
);
#if IMF_READ_INTERRUPT_ID
/* Check the security status of the interrupt */
assert
(
plat_ic_get_interrupt_type
(
id
)
==
INTR_TYPE_NS
);
#endif
/*
* Disable the routing of NS interrupts from secure world to EL3 while
* interrupted on this core.
*/
disable_intr_rm_local
(
INTR_TYPE_NS
,
SECURE
);
return
tspd_handle_sp_preemption
(
handle
);
}
#endif
/*******************************************************************************
* Secure Payload Dispatcher setup. The SPD finds out the SP entrypoint and type
* (aarch32/aarch64) if not already known and initialises the context for entry
...
...
@@ -270,21 +322,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
if
(
ns
)
SMC_RET1
(
handle
,
SMC_UNK
);
assert
(
handle
==
cm_get_context
(
SECURE
));
cm_el1_sysregs_context_save
(
SECURE
);
/* Get a reference to the non-secure context */
ns_cpu_context
=
cm_get_context
(
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_RET1
(
ns_cpu_context
,
SMC_PREEMPTED
);
return
tspd_handle_sp_preemption
(
handle
);
/*
* This function ID is used only by the TSP to indicate that it has
...
...
@@ -308,6 +346,14 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
SMC_SET_EL3
(
&
tsp_ctx
->
cpu_ctx
,
CTX_ELR_EL3
,
tsp_ctx
->
saved_elr_el3
);
#if TSPD_ROUTE_IRQ_TO_EL3
/*
* Need to restore the previously interrupted
* secure context.
*/
memcpy
(
&
tsp_ctx
->
cpu_ctx
,
&
tsp_ctx
->
sp_ctx
,
TSPD_SP_CTX_SIZE
);
#endif
}
/* Get a reference to the non-secure context */
...
...
@@ -389,6 +435,28 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
flags
);
if
(
rc
)
panic
();
#if TSPD_ROUTE_IRQ_TO_EL3
/*
* Register an interrupt handler for NS interrupts when
* generated during code executing in secure state are
* routed to EL3.
*/
flags
=
0
;
set_interrupt_rm_flag
(
flags
,
SECURE
);
rc
=
register_interrupt_type_handler
(
INTR_TYPE_NS
,
tspd_ns_interrupt_handler
,
flags
);
if
(
rc
)
panic
();
/*
* Disable the interrupt NS locally since it will be enabled globally
* within cm_init_context.
*/
disable_intr_rm_local
(
INTR_TYPE_NS
,
SECURE
);
#endif
}
...
...
@@ -507,6 +575,13 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
set_std_smc_active_flag
(
tsp_ctx
->
state
);
cm_set_elr_el3
(
SECURE
,
(
uint64_t
)
&
tsp_vectors
->
std_smc_entry
);
#if TSPD_ROUTE_IRQ_TO_EL3
/*
* Enable the routing of NS interrupts to EL3
* during STD SMC processing on this core.
*/
enable_intr_rm_local
(
INTR_TYPE_NS
,
SECURE
);
#endif
}
cm_el1_sysregs_context_restore
(
SECURE
);
...
...
@@ -529,8 +604,18 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
/* Restore non-secure state */
cm_el1_sysregs_context_restore
(
NON_SECURE
);
cm_set_next_eret_context
(
NON_SECURE
);
if
(
GET_SMC_TYPE
(
smc_fid
)
==
SMC_TYPE_STD
)
if
(
GET_SMC_TYPE
(
smc_fid
)
==
SMC_TYPE_STD
)
{
clr_std_smc_active_flag
(
tsp_ctx
->
state
);
#if TSPD_ROUTE_IRQ_TO_EL3
/*
* Disable the routing of NS interrupts to EL3
* after STD SMC processing is finished on this
* core.
*/
disable_intr_rm_local
(
INTR_TYPE_NS
,
SECURE
);
#endif
}
SMC_RET3
(
ns_cpu_context
,
x1
,
x2
,
x3
);
}
...
...
@@ -564,6 +649,15 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
* We are done stashing the non-secure context. Ask the
* secure payload to do the work now.
*/
#if TSPD_ROUTE_IRQ_TO_EL3
/*
* Enable the routing of NS interrupts to EL3 during resumption
* of STD SMC call on this core.
*/
enable_intr_rm_local
(
INTR_TYPE_NS
,
SECURE
);
#endif
/* We just need to return to the preempted point in
* TSP and the execution will resume as normal.
...
...
services/spd/tspd/tspd_pm.c
View file @
9d212557
...
...
@@ -133,6 +133,14 @@ static void tspd_cpu_on_finish_handler(uint64_t unused)
/* Initialise this cpu's secure context */
cm_init_context
(
mpidr
,
&
tsp_on_entrypoint
);
#if TSPD_ROUTE_IRQ_TO_EL3
/*
* Disable the NS interrupt locally since it will be enabled globally
* within cm_init_context.
*/
disable_intr_rm_local
(
INTR_TYPE_NS
,
SECURE
);
#endif
/* Enter the TSP */
rc
=
tspd_synchronous_sp_entry
(
tsp_ctx
);
...
...
services/spd/tspd/tspd_private.h
View file @
9d212557
...
...
@@ -120,6 +120,34 @@
#define TSPD_C_RT_CTX_SIZE 0x60
#define TSPD_C_RT_CTX_ENTRIES (TSPD_C_RT_CTX_SIZE >> DWORD_SHIFT)
/*******************************************************************************
* Constants that allow assembler code to preserve caller-saved registers of the
* SP context while performing a TSP preemption.
* Note: These offsets have to match with the offsets for the corresponding
* registers in cpu_context as we are using memcpy to copy the values from
* cpu_context to sp_ctx.
******************************************************************************/
#define TSPD_SP_CTX_X0 0x0
#define TSPD_SP_CTX_X1 0x8
#define TSPD_SP_CTX_X2 0x10
#define TSPD_SP_CTX_X3 0x18
#define TSPD_SP_CTX_X4 0x20
#define TSPD_SP_CTX_X5 0x28
#define TSPD_SP_CTX_X6 0x30
#define TSPD_SP_CTX_X7 0x38
#define TSPD_SP_CTX_X8 0x40
#define TSPD_SP_CTX_X9 0x48
#define TSPD_SP_CTX_X10 0x50
#define TSPD_SP_CTX_X11 0x58
#define TSPD_SP_CTX_X12 0x60
#define TSPD_SP_CTX_X13 0x68
#define TSPD_SP_CTX_X14 0x70
#define TSPD_SP_CTX_X15 0x78
#define TSPD_SP_CTX_X16 0x80
#define TSPD_SP_CTX_X17 0x88
#define TSPD_SP_CTX_SIZE 0x90
#define TSPD_SP_CTX_ENTRIES (TSPD_SP_CTX_SIZE >> DWORD_SHIFT)
#ifndef __ASSEMBLY__
#include <cassert.h>
...
...
@@ -142,6 +170,17 @@ DEFINE_REG_STRUCT(c_rt_regs, TSPD_C_RT_CTX_ENTRIES);
CASSERT
(
TSPD_C_RT_CTX_SIZE
==
sizeof
(
c_rt_regs_t
),
\
assert_spd_c_rt_regs_size_mismatch
);
/* SEL1 Secure payload (SP) caller saved register context structure. */
DEFINE_REG_STRUCT
(
sp_ctx_regs
,
TSPD_SP_CTX_ENTRIES
);
/*
* Compile time assertion to ensure that both the compiler and linker
* have the same double word aligned view of the size of the C runtime
* register context.
*/
CASSERT
(
TSPD_SP_CTX_SIZE
==
sizeof
(
sp_ctx_regs_t
),
\
assert_spd_sp_regs_size_mismatch
);
/*******************************************************************************
* Structure which helps the SPD to maintain the per-cpu state of the SP.
* 'saved_spsr_el3' - temporary copy to allow FIQ handling when the TSP has been
...
...
@@ -155,6 +194,10 @@ CASSERT(TSPD_C_RT_CTX_SIZE == sizeof(c_rt_regs_t), \
* 'cpu_ctx' - space to maintain SP architectural state
* 'saved_tsp_args' - space to store arguments for TSP arithmetic operations
* which will queried using the TSP_GET_ARGS SMC by TSP.
* 'sp_ctx' - space to save the SEL1 Secure Payload(SP) caller saved
* register context after it has been preempted by an EL3
* routed NS interrupt and when a Secure Interrupt is taken
* to SP.
******************************************************************************/
typedef
struct
tsp_context
{
uint64_t
saved_elr_el3
;
...
...
@@ -164,6 +207,9 @@ typedef struct tsp_context {
uint64_t
c_rt_ctx
;
cpu_context_t
cpu_ctx
;
uint64_t
saved_tsp_args
[
TSP_NUM_ARGS
];
#if TSPD_ROUTE_IRQ_TO_EL3
sp_ctx_regs_t
sp_ctx
;
#endif
}
tsp_context_t
;
/* Helper macros to store and retrieve tsp args from tsp_context */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment