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
c195f1a7
Unverified
Commit
c195f1a7
authored
Nov 13, 2017
by
davidcunado-arm
Committed by
GitHub
Nov 13, 2017
Browse files
Merge pull request #1152 from jeenu-arm/ehf-and-sdei
EHF and SDEI
parents
bf2de7e4
cafad7be
Changes
44
Hide whitespace changes
Inline
Side-by-side
bl31/bl31.mk
View file @
c195f1a7
...
@@ -32,6 +32,20 @@ ifeq (${ENABLE_PMF}, 1)
...
@@ -32,6 +32,20 @@ ifeq (${ENABLE_PMF}, 1)
BL31_SOURCES
+=
lib/pmf/pmf_main.c
BL31_SOURCES
+=
lib/pmf/pmf_main.c
endif
endif
ifeq
(${EL3_EXCEPTION_HANDLING},1)
BL31_SOURCES
+=
bl31/ehf.c
endif
ifeq
(${SDEI_SUPPORT},1)
ifeq
(${EL3_EXCEPTION_HANDLING},0)
$(error
EL3_EXCEPTION_HANDLING
must
be
1
for
SDEI
support)
endif
BL31_SOURCES
+=
services/std_svc/sdei/sdei_event.c
\
services/std_svc/sdei/sdei_intr_mgmt.c
\
services/std_svc/sdei/sdei_main.c
\
services/std_svc/sdei/sdei_state.c
endif
BL31_LINKERFILE
:=
bl31/bl31.ld.S
BL31_LINKERFILE
:=
bl31/bl31.ld.S
# Flag used to indicate if Crash reporting via console should be included
# Flag used to indicate if Crash reporting via console should be included
...
@@ -41,4 +55,9 @@ CRASH_REPORTING := $(DEBUG)
...
@@ -41,4 +55,9 @@ CRASH_REPORTING := $(DEBUG)
endif
endif
$(eval
$(call
assert_boolean,CRASH_REPORTING))
$(eval
$(call
assert_boolean,CRASH_REPORTING))
$(eval
$(call
assert_boolean,EL3_EXCEPTION_HANDLING))
$(eval
$(call
assert_boolean,SDEI_SUPPORT))
$(eval
$(call
add_define,CRASH_REPORTING))
$(eval
$(call
add_define,CRASH_REPORTING))
$(eval
$(call
add_define,EL3_EXCEPTION_HANDLING))
$(eval
$(call
add_define,SDEI_SUPPORT))
bl31/bl31_main.c
View file @
c195f1a7
...
@@ -12,6 +12,7 @@
...
@@ -12,6 +12,7 @@
#include <console.h>
#include <console.h>
#include <context_mgmt.h>
#include <context_mgmt.h>
#include <debug.h>
#include <debug.h>
#include <ehf.h>
#include <platform.h>
#include <platform.h>
#include <pmf.h>
#include <pmf.h>
#include <runtime_instr.h>
#include <runtime_instr.h>
...
@@ -79,6 +80,11 @@ void bl31_main(void)
...
@@ -79,6 +80,11 @@ void bl31_main(void)
/* Initialise helper libraries */
/* Initialise helper libraries */
bl31_lib_init
();
bl31_lib_init
();
#if EL3_EXCEPTION_HANDLING
INFO
(
"BL31: Initialising Exception Handling Framework
\n
"
);
ehf_init
();
#endif
/* Initialize the runtime services e.g. psci. */
/* Initialize the runtime services e.g. psci. */
INFO
(
"BL31: Initializing runtime services
\n
"
);
INFO
(
"BL31: Initializing runtime services
\n
"
);
runtime_svc_init
();
runtime_svc_init
();
...
...
bl31/ehf.c
0 → 100644
View file @
c195f1a7
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* Exception handlers at EL3, their priority levels, and management.
*/
#include <assert.h>
#include <cpu_data.h>
#include <debug.h>
#include <ehf.h>
#include <gic_common.h>
#include <interrupt_mgmt.h>
#include <platform.h>
#include <pubsub_events.h>
/* Output EHF logs as verbose */
#define EHF_LOG(...) VERBOSE("EHF: " __VA_ARGS__)
#define EHF_INVALID_IDX (-1)
/* For a valid handler, return the actual function pointer; otherwise, 0. */
#define RAW_HANDLER(h) \
((ehf_handler_t) ((h & _EHF_PRI_VALID) ? (h & ~_EHF_PRI_VALID) : 0))
#define PRI_BIT(idx) (((ehf_pri_bits_t) 1) << idx)
/*
* Convert index into secure priority using the platform-defined priority bits
* field.
*/
#define IDX_TO_PRI(idx) \
((idx << (7 - exception_data.pri_bits)) & 0x7f)
/* Check whether a given index is valid */
#define IS_IDX_VALID(idx) \
((exception_data.ehf_priorities[idx].ehf_handler & _EHF_PRI_VALID) != 0)
/* Returns whether given priority is in secure priority range */
#define IS_PRI_SECURE(pri) ((pri & 0x80) == 0)
/* To be defined by the platform */
extern
const
ehf_priorities_t
exception_data
;
/* Translate priority to the index in the priority array */
static
int
pri_to_idx
(
unsigned
int
priority
)
{
int
idx
;
idx
=
EHF_PRI_TO_IDX
(
priority
,
exception_data
.
pri_bits
);
assert
((
idx
>=
0
)
&&
(
idx
<
exception_data
.
num_priorities
));
assert
(
IS_IDX_VALID
(
idx
));
return
idx
;
}
/* Return whether there are outstanding priority activation */
static
int
has_valid_pri_activations
(
pe_exc_data_t
*
pe_data
)
{
return
pe_data
->
active_pri_bits
!=
0
;
}
static
pe_exc_data_t
*
this_cpu_data
(
void
)
{
return
&
get_cpu_data
(
ehf_data
);
}
/*
* Return the current priority index of this CPU. If no priority is active,
* return EHF_INVALID_IDX.
*/
static
int
get_pe_highest_active_idx
(
pe_exc_data_t
*
pe_data
)
{
if
(
!
has_valid_pri_activations
(
pe_data
))
return
EHF_INVALID_IDX
;
/* Current priority is the right-most bit */
return
__builtin_ctz
(
pe_data
->
active_pri_bits
);
}
/*
* Mark priority active by setting the corresponding bit in active_pri_bits and
* programming the priority mask.
*
* This API is to be used as part of delegating to lower ELs other than for
* interrupts; e.g. while handling synchronous exceptions.
*
* This API is expected to be invoked before restoring context (Secure or
* Non-secure) in preparation for the respective dispatch.
*/
void
ehf_activate_priority
(
unsigned
int
priority
)
{
int
idx
,
cur_pri_idx
;
unsigned
int
old_mask
,
run_pri
;
pe_exc_data_t
*
pe_data
=
this_cpu_data
();
/*
* Query interrupt controller for the running priority, or idle priority
* if no interrupts are being handled. The requested priority must be
* less (higher priority) than the active running priority.
*/
run_pri
=
plat_ic_get_running_priority
();
if
(
priority
>=
run_pri
)
{
ERROR
(
"Running priority higher (0x%x) than requested (0x%x)
\n
"
,
run_pri
,
priority
);
panic
();
}
/*
* If there were priority activations already, the requested priority
* must be less (higher priority) than the current highest priority
* activation so far.
*/
cur_pri_idx
=
get_pe_highest_active_idx
(
pe_data
);
idx
=
pri_to_idx
(
priority
);
if
((
cur_pri_idx
!=
EHF_INVALID_IDX
)
&&
(
idx
>=
cur_pri_idx
))
{
ERROR
(
"Activation priority mismatch: req=0x%x current=0x%x
\n
"
,
priority
,
IDX_TO_PRI
(
cur_pri_idx
));
panic
();
}
/* Set the bit corresponding to the requested priority */
pe_data
->
active_pri_bits
|=
PRI_BIT
(
idx
);
/*
* Program priority mask for the activated level. Check that the new
* priority mask is setting a higher priority level than the existing
* mask.
*/
old_mask
=
plat_ic_set_priority_mask
(
priority
);
if
(
priority
>=
old_mask
)
{
ERROR
(
"Requested priority (0x%x) lower than Priority Mask (0x%x)
\n
"
,
priority
,
old_mask
);
panic
();
}
/*
* If this is the first activation, save the priority mask. This will be
* restored after the last deactivation.
*/
if
(
cur_pri_idx
==
EHF_INVALID_IDX
)
pe_data
->
init_pri_mask
=
old_mask
;
EHF_LOG
(
"activate prio=%d
\n
"
,
get_pe_highest_active_idx
(
pe_data
));
}
/*
* Mark priority inactive by clearing the corresponding bit in active_pri_bits,
* and programming the priority mask.
*
* This API is expected to be used as part of delegating to to lower ELs other
* than for interrupts; e.g. while handling synchronous exceptions.
*
* This API is expected to be invoked after saving context (Secure or
* Non-secure), having concluded the respective dispatch.
*/
void
ehf_deactivate_priority
(
unsigned
int
priority
)
{
int
idx
,
cur_pri_idx
;
pe_exc_data_t
*
pe_data
=
this_cpu_data
();
unsigned
int
old_mask
,
run_pri
;
/*
* Query interrupt controller for the running priority, or idle priority
* if no interrupts are being handled. The requested priority must be
* less (higher priority) than the active running priority.
*/
run_pri
=
plat_ic_get_running_priority
();
if
(
priority
>=
run_pri
)
{
ERROR
(
"Running priority higher (0x%x) than requested (0x%x)
\n
"
,
run_pri
,
priority
);
panic
();
}
/*
* Deactivation is allowed only when there are priority activations, and
* the deactivation priority level must match the current activated
* priority.
*/
cur_pri_idx
=
get_pe_highest_active_idx
(
pe_data
);
idx
=
pri_to_idx
(
priority
);
if
((
cur_pri_idx
==
EHF_INVALID_IDX
)
||
(
idx
!=
cur_pri_idx
))
{
ERROR
(
"Deactivation priority mismatch: req=0x%x current=0x%x
\n
"
,
priority
,
IDX_TO_PRI
(
cur_pri_idx
));
panic
();
}
/* Clear bit corresponding to highest priority */
pe_data
->
active_pri_bits
&=
(
pe_data
->
active_pri_bits
-
1
);
/*
* Restore priority mask corresponding to the next priority, or the
* one stashed earlier if there are no more to deactivate.
*/
idx
=
get_pe_highest_active_idx
(
pe_data
);
if
(
idx
==
EHF_INVALID_IDX
)
old_mask
=
plat_ic_set_priority_mask
(
pe_data
->
init_pri_mask
);
else
old_mask
=
plat_ic_set_priority_mask
(
priority
);
if
(
old_mask
>=
priority
)
{
ERROR
(
"Deactivation priority (0x%x) lower than Priority Mask (0x%x)
\n
"
,
priority
,
old_mask
);
panic
();
}
EHF_LOG
(
"deactivate prio=%d
\n
"
,
get_pe_highest_active_idx
(
pe_data
));
}
/*
* After leaving Non-secure world, stash current Non-secure Priority Mask, and
* set Priority Mask to the highest Non-secure priority so that Non-secure
* interrupts cannot preempt Secure execution.
*
* If the current running priority is in the secure range, or if there are
* outstanding priority activations, this function does nothing.
*
* This function subscribes to the 'cm_exited_normal_world' event published by
* the Context Management Library.
*/
static
void
*
ehf_exited_normal_world
(
const
void
*
arg
)
{
unsigned
int
run_pri
;
pe_exc_data_t
*
pe_data
=
this_cpu_data
();
/* If the running priority is in the secure range, do nothing */
run_pri
=
plat_ic_get_running_priority
();
if
(
IS_PRI_SECURE
(
run_pri
))
return
0
;
/* Do nothing if there are explicit activations */
if
(
has_valid_pri_activations
(
pe_data
))
return
0
;
assert
(
pe_data
->
ns_pri_mask
==
0
);
pe_data
->
ns_pri_mask
=
plat_ic_set_priority_mask
(
GIC_HIGHEST_NS_PRIORITY
);
/* The previous Priority Mask is not expected to be in secure range */
if
(
IS_PRI_SECURE
(
pe_data
->
ns_pri_mask
))
{
ERROR
(
"Priority Mask (0x%x) already in secure range
\n
"
,
pe_data
->
ns_pri_mask
);
panic
();
}
EHF_LOG
(
"Priority Mask: 0x%x => 0x%x
\n
"
,
pe_data
->
ns_pri_mask
,
GIC_HIGHEST_NS_PRIORITY
);
return
0
;
}
/*
* Conclude Secure execution and prepare for return to Non-secure world. Restore
* the Non-secure Priority Mask previously stashed upon leaving Non-secure
* world.
*
* If there the current running priority is in the secure range, or if there are
* outstanding priority activations, this function does nothing.
*
* This function subscribes to the 'cm_entering_normal_world' event published by
* the Context Management Library.
*/
static
void
*
ehf_entering_normal_world
(
const
void
*
arg
)
{
unsigned
int
old_pmr
,
run_pri
;
pe_exc_data_t
*
pe_data
=
this_cpu_data
();
/* If the running priority is in the secure range, do nothing */
run_pri
=
plat_ic_get_running_priority
();
if
(
IS_PRI_SECURE
(
run_pri
))
return
0
;
/*
* If there are explicit activations, do nothing. The Priority Mask will
* be restored upon the last deactivation.
*/
if
(
has_valid_pri_activations
(
pe_data
))
return
0
;
/* Do nothing if we don't have a valid Priority Mask to restore */
if
(
pe_data
->
ns_pri_mask
==
0
)
return
0
;
old_pmr
=
plat_ic_set_priority_mask
(
pe_data
->
ns_pri_mask
);
/*
* When exiting secure world, the current Priority Mask must be
* GIC_HIGHEST_NS_PRIORITY (as set during entry), or the Non-secure
* priority mask set upon calling ehf_allow_ns_preemption()
*/
if
((
old_pmr
!=
GIC_HIGHEST_NS_PRIORITY
)
&&
(
old_pmr
!=
pe_data
->
ns_pri_mask
))
{
ERROR
(
"Invalid Priority Mask (0x%x) restored
\n
"
,
old_pmr
);
panic
();
}
EHF_LOG
(
"Priority Mask: 0x%x => 0x%x
\n
"
,
old_pmr
,
pe_data
->
ns_pri_mask
);
pe_data
->
ns_pri_mask
=
0
;
return
0
;
}
/*
* Program Priority Mask to the original Non-secure priority such that
* Non-secure interrupts may preempt Secure execution, viz. during Yielding SMC
* calls.
*
* This API is expected to be invoked before delegating a yielding SMC to Secure
* EL1. I.e. within the window of secure execution after Non-secure context is
* saved (after entry into EL3) and Secure context is restored (before entering
* Secure EL1).
*/
void
ehf_allow_ns_preemption
(
void
)
{
unsigned
int
old_pmr
__unused
;
pe_exc_data_t
*
pe_data
=
this_cpu_data
();
/*
* We should have been notified earlier of entering secure world, and
* therefore have stashed the Non-secure priority mask.
*/
assert
(
pe_data
->
ns_pri_mask
!=
0
);
/* Make sure no priority levels are active when requesting this */
if
(
has_valid_pri_activations
(
pe_data
))
{
ERROR
(
"PE %lx has priority activations: 0x%x
\n
"
,
read_mpidr_el1
(),
pe_data
->
active_pri_bits
);
panic
();
}
old_pmr
=
plat_ic_set_priority_mask
(
pe_data
->
ns_pri_mask
);
EHF_LOG
(
"Priority Mask: 0x%x => 0x%x
\n
"
,
old_pmr
,
pe_data
->
ns_pri_mask
);
pe_data
->
ns_pri_mask
=
0
;
}
/*
* Return whether Secure execution has explicitly allowed Non-secure interrupts
* to preempt itself, viz. during Yielding SMC calls.
*/
unsigned
int
ehf_is_ns_preemption_allowed
(
void
)
{
unsigned
int
run_pri
;
pe_exc_data_t
*
pe_data
=
this_cpu_data
();
/* If running priority is in secure range, return false */
run_pri
=
plat_ic_get_running_priority
();
if
(
IS_PRI_SECURE
(
run_pri
))
return
0
;
/*
* If Non-secure preemption was permitted by calling
* ehf_allow_ns_preemption() earlier:
*
* - There wouldn't have been priority activations;
* - We would have cleared the stashed the Non-secure Priority Mask.
*/
if
(
has_valid_pri_activations
(
pe_data
))
return
0
;
if
(
pe_data
->
ns_pri_mask
!=
0
)
return
0
;
return
1
;
}
/*
* Top-level EL3 interrupt handler.
*/
static
uint64_t
ehf_el3_interrupt_handler
(
uint32_t
id
,
uint32_t
flags
,
void
*
handle
,
void
*
cookie
)
{
int
pri
,
idx
,
intr
,
intr_raw
,
ret
=
0
;
ehf_handler_t
handler
;
/*
* Top-level interrupt type handler from Interrupt Management Framework
* doesn't acknowledge the interrupt; so the interrupt ID must be
* invalid.
*/
assert
(
id
==
INTR_ID_UNAVAILABLE
);
/*
* Acknowledge interrupt. Proceed with handling only for valid interrupt
* IDs. This situation may arise because of Interrupt Management
* Framework identifying an EL3 interrupt, but before it's been
* acknowledged here, the interrupt was either deasserted, or there was
* a higher-priority interrupt of another type.
*/
intr_raw
=
plat_ic_acknowledge_interrupt
();
intr
=
plat_ic_get_interrupt_id
(
intr_raw
);
if
(
intr
==
INTR_ID_UNAVAILABLE
)
return
0
;
/* Having acknowledged the interrupt, get the running priority */
pri
=
plat_ic_get_running_priority
();
/* Check EL3 interrupt priority is in secure range */
assert
(
IS_PRI_SECURE
(
pri
));
/*
* Translate the priority to a descriptor index. We do this by masking
* and shifting the running priority value (platform-supplied).
*/
idx
=
pri_to_idx
(
pri
);
/* Validate priority */
assert
(
pri
==
IDX_TO_PRI
(
idx
));
handler
=
RAW_HANDLER
(
exception_data
.
ehf_priorities
[
idx
].
ehf_handler
);
if
(
!
handler
)
{
ERROR
(
"No EL3 exception handler for priority 0x%x
\n
"
,
IDX_TO_PRI
(
idx
));
panic
();
}
/*
* Call registered handler. Pass the raw interrupt value to registered
* handlers.
*/
ret
=
handler
(
intr_raw
,
flags
,
handle
,
cookie
);
return
ret
;
}
/*
* Initialize the EL3 exception handling.
*/
void
ehf_init
(
void
)
{
unsigned
int
flags
=
0
;
int
ret
__unused
;
/* Ensure EL3 interrupts are supported */
assert
(
plat_ic_has_interrupt_type
(
INTR_TYPE_EL3
));
/*
* Make sure that priority water mark has enough bits to represent the
* whole priority array.
*/
assert
(
exception_data
.
num_priorities
<=
(
sizeof
(
ehf_pri_bits_t
)
*
8
));
assert
(
exception_data
.
ehf_priorities
);
/*
* Bit 7 of GIC priority must be 0 for secure interrupts. This means
* platforms must use at least 1 of the remaining 7 bits.
*/
assert
((
exception_data
.
pri_bits
>=
1
)
||
(
exception_data
.
pri_bits
<
8
));
/* Route EL3 interrupts when in Secure and Non-secure. */
set_interrupt_rm_flag
(
flags
,
NON_SECURE
);
set_interrupt_rm_flag
(
flags
,
SECURE
);
/* Register handler for EL3 interrupts */
ret
=
register_interrupt_type_handler
(
INTR_TYPE_EL3
,
ehf_el3_interrupt_handler
,
flags
);
assert
(
ret
==
0
);
}
/*
* Register a handler at the supplied priority. Registration is allowed only if
* a handler hasn't been registered before, or one wasn't provided at build
* time. The priority for which the handler is being registered must also accord
* with the platform-supplied data.
*/
void
ehf_register_priority_handler
(
unsigned
int
pri
,
ehf_handler_t
handler
)
{
int
idx
;
/* Sanity check for handler */
assert
(
handler
!=
NULL
);
/* Handler ought to be 4-byte aligned */
assert
((((
uintptr_t
)
handler
)
&
3
)
==
0
);
/* Ensure we register for valid priority */
idx
=
pri_to_idx
(
pri
);
assert
(
idx
<
exception_data
.
num_priorities
);
assert
(
IDX_TO_PRI
(
idx
)
==
pri
);
/* Return failure if a handler was already registered */
if
(
exception_data
.
ehf_priorities
[
idx
].
ehf_handler
!=
_EHF_NO_HANDLER
)
{
ERROR
(
"Handler already registered for priority 0x%x
\n
"
,
pri
);
panic
();
}
/*
* Install handler, and retain the valid bit. We assume that the handler
* is 4-byte aligned, which is usually the case.
*/
exception_data
.
ehf_priorities
[
idx
].
ehf_handler
=
(((
uintptr_t
)
handler
)
|
_EHF_PRI_VALID
);
EHF_LOG
(
"register pri=0x%x handler=%p
\n
"
,
pri
,
handler
);
}
SUBSCRIBE_TO_EVENT
(
cm_entering_normal_world
,
ehf_entering_normal_world
);
SUBSCRIBE_TO_EVENT
(
cm_exited_normal_world
,
ehf_exited_normal_world
);
docs/plantuml/plantuml_to_svg.sh
0 → 100755
View file @
c195f1a7
#!/bin/bash
# Convert all PlantUML files in this directory to SVG files. The plantuml_jar
# environment variable must be set to the path to PlantUML JAR file.
if
[
-z
"
$plantuml_jar
"
]
;
then
echo
"Usage: plantuml_jar=/path/to/plantuml.jar
$0
*.puml"
>
&2
exit
1
fi
java
-jar
"
$plantuml_jar
"
-nometadata
-tsvg
"
$@
"
# vim:set noet sts=8 tw=80:
docs/plantuml/sdei_explicit_dispatch.puml
0 → 100644
View file @
c195f1a7
/'
' Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
'
' SPDX-License-Identifier: BSD-3-Clause
'/
@startuml
autonumber "<b>[#]</b>"
participant "SDEI client" as EL2
participant EL3
participant SEL1
activate EL2
EL2->EL3: **SDEI_EVENT_REGISTER**(ev, handler, ...)
EL3->EL2: success
EL2->EL3: **SDEI_EVENT_ENABLE**(ev)
EL3->EL2: success
EL2->EL3: **SDEI_PE_UNMASK**()
EL3->EL2: 1
... <<Business as usual>> ...
EL3<--]: **CRITICAL EVENT**
activate EL3 #red
note over EL3: Critical event triage
EL3->SEL1: dispatch
activate SEL1 #salmon
note over SEL1: Critical event handling
SEL1->EL3: done
deactivate SEL1
EL3-->EL3: sdei_dispatch_event(ev)
note over EL3: Prepare SDEI dispatch
EL3->EL2: dispatch
activate EL2 #salmon
note over EL2: SDEI handler
EL2->EL3: **SDEI_EVENT_COMPLETE()**
deactivate EL2
note over EL3: Complete SDEI dispatch
EL3->EL2: resumes preempted execution
deactivate EL3
... <<Normal execution resumes>> ...
@enduml
docs/plantuml/sdei_explicit_dispatch.svg
0 → 100644
View file @
c195f1a7
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
contentScriptType=
"application/ecmascript"
contentStyleType=
"text/css"
height=
"767px"
preserveAspectRatio=
"none"
style=
"width:692px;height:767px;"
version=
"1.1"
viewBox=
"0 0 692 767"
width=
"692px"
zoomAndPan=
"magnify"
><defs><filter
height=
"300%"
id=
"f13jg8eb0anesb"
width=
"300%"
x=
"-1"
y=
"-1"
><feGaussianBlur
result=
"blurOut"
stdDeviation=
"2.0"
/><feColorMatrix
in=
"blurOut"
result=
"blurOut2"
type=
"matrix"
values=
"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"
/><feOffset
dx=
"4.0"
dy=
"4.0"
in=
"blurOut2"
result=
"blurOut3"
/><feBlend
in=
"SourceGraphic"
in2=
"blurOut3"
mode=
"normal"
/></filter></defs><g><rect
fill=
"#FFFFFF"
filter=
"url(#f13jg8eb0anesb)"
height=
"174.7969"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"48.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"48.2969"
y2=
"223.0938"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"48.2969"
y2=
"223.0938"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"66.5"
y1=
"48.2969"
y2=
"48.2969"
/><rect
fill=
"#FFFFFF"
filter=
"url(#f13jg8eb0anesb)"
height=
"412.5938"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"263.8984"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"263.8984"
y2=
"676.4922"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"263.8984"
y2=
"676.4922"
/><rect
fill=
"#FFFFFF"
filter=
"url(#f13jg8eb0anesb)"
height=
"1"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"717.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"717.2969"
y2=
"718.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"717.2969"
y2=
"718.2969"
/><rect
fill=
"#FA8072"
filter=
"url(#f13jg8eb0anesb)"
height=
"68.2656"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"61.5"
y=
"531.8281"
/><rect
fill=
"#FF0000"
filter=
"url(#f13jg8eb0anesb)"
height=
"383.4609"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"375.5"
y=
"284.8984"
/><rect
fill=
"#FA8072"
filter=
"url(#f13jg8eb0anesb)"
height=
"68.2656"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"588.5"
y=
"353.1641"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"61"
x2=
"61"
y1=
"38.2969"
y2=
"223.0938"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"61"
x2=
"61"
y1=
"223.0938"
y2=
"263.8984"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"61"
x2=
"61"
y1=
"263.8984"
y2=
"676.4922"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"61"
x2=
"61"
y1=
"676.4922"
y2=
"717.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"61"
x2=
"61"
y1=
"717.2969"
y2=
"727.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"380"
x2=
"380"
y1=
"38.2969"
y2=
"223.0938"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"380"
x2=
"380"
y1=
"223.0938"
y2=
"263.8984"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"380"
x2=
"380"
y1=
"263.8984"
y2=
"676.4922"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"380"
x2=
"380"
y1=
"676.4922"
y2=
"717.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"380"
x2=
"380"
y1=
"717.2969"
y2=
"727.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"593.5"
x2=
"593.5"
y1=
"38.2969"
y2=
"223.0938"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"593.5"
x2=
"593.5"
y1=
"223.0938"
y2=
"263.8984"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"593.5"
x2=
"593.5"
y1=
"263.8984"
y2=
"676.4922"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"593.5"
x2=
"593.5"
y1=
"676.4922"
y2=
"717.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"593.5"
x2=
"593.5"
y1=
"717.2969"
y2=
"727.2969"
/><rect
fill=
"#FEFECE"
filter=
"url(#f13jg8eb0anesb)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"87"
x=
"16"
y=
"3"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"73"
x=
"23"
y=
"22.9951"
>
SDEI client
</text><rect
fill=
"#FEFECE"
filter=
"url(#f13jg8eb0anesb)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"87"
x=
"16"
y=
"726.2969"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"73"
x=
"23"
y=
"746.292"
>
SDEI client
</text><rect
fill=
"#FEFECE"
filter=
"url(#f13jg8eb0anesb)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"39"
x=
"359"
y=
"3"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"25"
x=
"366"
y=
"22.9951"
>
EL3
</text><rect
fill=
"#FEFECE"
filter=
"url(#f13jg8eb0anesb)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"39"
x=
"359"
y=
"726.2969"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"25"
x=
"366"
y=
"746.292"
>
EL3
</text><rect
fill=
"#FEFECE"
filter=
"url(#f13jg8eb0anesb)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"48"
x=
"567.5"
y=
"3"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"34"
x=
"574.5"
y=
"22.9951"
>
SEL1
</text><rect
fill=
"#FEFECE"
filter=
"url(#f13jg8eb0anesb)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"48"
x=
"567.5"
y=
"726.2969"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"34"
x=
"574.5"
y=
"746.292"
>
SEL1
</text><rect
fill=
"#FFFFFF"
filter=
"url(#f13jg8eb0anesb)"
height=
"174.7969"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"48.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"48.2969"
y2=
"223.0938"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"48.2969"
y2=
"223.0938"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"66.5"
y1=
"48.2969"
y2=
"48.2969"
/><rect
fill=
"#FFFFFF"
filter=
"url(#f13jg8eb0anesb)"
height=
"412.5938"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"263.8984"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"263.8984"
y2=
"676.4922"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"263.8984"
y2=
"676.4922"
/><rect
fill=
"#FFFFFF"
filter=
"url(#f13jg8eb0anesb)"
height=
"1"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"717.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"717.2969"
y2=
"718.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"717.2969"
y2=
"718.2969"
/><rect
fill=
"#FA8072"
filter=
"url(#f13jg8eb0anesb)"
height=
"68.2656"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"61.5"
y=
"531.8281"
/><rect
fill=
"#FF0000"
filter=
"url(#f13jg8eb0anesb)"
height=
"383.4609"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"375.5"
y=
"284.8984"
/><rect
fill=
"#FA8072"
filter=
"url(#f13jg8eb0anesb)"
height=
"68.2656"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"588.5"
y=
"353.1641"
/><polygon
fill=
"#A80036"
points=
"368.5,65.2969,378.5,69.2969,368.5,73.2969,372.5,69.2969"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"374.5"
y1=
"69.2969"
y2=
"69.2969"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"73.5"
y=
"64.3638"
>
[1]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"164"
x=
"98.5"
y=
"64.3638"
>
SDEI_EVENT_REGISTER
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"101"
x=
"262.5"
y=
"64.3638"
>
(ev, handler, ...)
</text><polygon
fill=
"#A80036"
points=
"77.5,94.4297,67.5,98.4297,77.5,102.4297,73.5,98.4297"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"71.5"
x2=
"379.5"
y1=
"98.4297"
y2=
"98.4297"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"83.5"
y=
"93.4966"
>
[2]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"51"
x=
"108.5"
y=
"93.4966"
>
success
</text><polygon
fill=
"#A80036"
points=
"368.5,123.5625,378.5,127.5625,368.5,131.5625,372.5,127.5625"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"374.5"
y1=
"127.5625"
y2=
"127.5625"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"73.5"
y=
"122.6294"
>
[3]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"151"
x=
"98.5"
y=
"122.6294"
>
SDEI_EVENT_ENABLE
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"25"
x=
"249.5"
y=
"122.6294"
>
(ev)
</text><polygon
fill=
"#A80036"
points=
"77.5,152.6953,67.5,156.6953,77.5,160.6953,73.5,156.6953"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"71.5"
x2=
"379.5"
y1=
"156.6953"
y2=
"156.6953"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"83.5"
y=
"151.7622"
>
[4]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"51"
x=
"108.5"
y=
"151.7622"
>
success
</text><polygon
fill=
"#A80036"
points=
"368.5,181.8281,378.5,185.8281,368.5,189.8281,372.5,185.8281"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"374.5"
y1=
"185.8281"
y2=
"185.8281"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"73.5"
y=
"180.895"
>
[5]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"129"
x=
"98.5"
y=
"180.895"
>
SDEI_PE_UNMASK
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"10"
x=
"227.5"
y=
"180.895"
>
()
</text><polygon
fill=
"#A80036"
points=
"77.5,210.9609,67.5,214.9609,77.5,218.9609,73.5,214.9609"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"71.5"
x2=
"379.5"
y1=
"214.9609"
y2=
"214.9609"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"83.5"
y=
"210.0278"
>
[6]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"8"
x=
"108.5"
y=
"210.0278"
>
1
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"11"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"142"
x=
"256.5"
y=
"247.3042"
>
<<
Business as usual
>>
</text><polygon
fill=
"#A80036"
points=
"396.5,280.8984,386.5,284.8984,396.5,288.8984,392.5,284.8984"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;"
x1=
"390.5"
x2=
"680"
y1=
"284.8984"
y2=
"284.8984"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"402.5"
y=
"279.9653"
>
[7]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"116"
x=
"427.5"
y=
"279.9653"
>
CRITICAL EVENT
</text><polygon
fill=
"#FBFB77"
filter=
"url(#f13jg8eb0anesb)"
points=
"306,298.0313,306,323.0313,451,323.0313,451,308.0313,441,298.0313,306,298.0313"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"441"
x2=
"441"
y1=
"298.0313"
y2=
"308.0313"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"451"
x2=
"441"
y1=
"308.0313"
y2=
"308.0313"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"124"
x=
"312"
y=
"315.0981"
>
Critical event triage
</text><polygon
fill=
"#A80036"
points=
"576.5,349.1641,586.5,353.1641,576.5,357.1641,580.5,353.1641"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"385.5"
x2=
"582.5"
y1=
"353.1641"
y2=
"353.1641"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"392.5"
y=
"348.231"
>
[8]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"54"
x=
"417.5"
y=
"348.231"
>
dispatch
</text><polygon
fill=
"#FBFB77"
filter=
"url(#f13jg8eb0anesb)"
points=
"510,366.2969,510,391.2969,672,391.2969,672,376.2969,662,366.2969,510,366.2969"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"662"
x2=
"662"
y1=
"366.2969"
y2=
"376.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"672"
x2=
"662"
y1=
"376.2969"
y2=
"376.2969"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"141"
x=
"516"
y=
"383.3638"
>
Critical event handling
</text><polygon
fill=
"#A80036"
points=
"396.5,417.4297,386.5,421.4297,396.5,425.4297,392.5,421.4297"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"390.5"
x2=
"592.5"
y1=
"421.4297"
y2=
"421.4297"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"402.5"
y=
"416.4966"
>
[9]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"32"
x=
"427.5"
y=
"416.4966"
>
done
</text><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;"
x1=
"385.5"
x2=
"427.5"
y1=
"450.6953"
y2=
"450.6953"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;"
x1=
"427.5"
x2=
"427.5"
y1=
"450.6953"
y2=
"463.6953"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;"
x1=
"386.5"
x2=
"427.5"
y1=
"463.6953"
y2=
"463.6953"
/><polygon
fill=
"#A80036"
points=
"396.5,459.6953,386.5,463.6953,396.5,467.6953,392.5,463.6953"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"30"
x=
"392.5"
y=
"445.6294"
>
[10]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"155"
x=
"426.5"
y=
"445.6294"
>
sdei_dispatch_event(ev)
</text><polygon
fill=
"#FBFB77"
filter=
"url(#f13jg8eb0anesb)"
points=
"297,476.6953,297,501.6953,460,501.6953,460,486.6953,450,476.6953,297,476.6953"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"450"
x2=
"450"
y1=
"476.6953"
y2=
"486.6953"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"460"
x2=
"450"
y1=
"486.6953"
y2=
"486.6953"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"142"
x=
"303"
y=
"493.7622"
>
Prepare SDEI dispatch
</text><polygon
fill=
"#A80036"
points=
"82.5,527.8281,72.5,531.8281,82.5,535.8281,78.5,531.8281"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"76.5"
x2=
"374.5"
y1=
"531.8281"
y2=
"531.8281"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"30"
x=
"88.5"
y=
"526.895"
>
[11]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"54"
x=
"122.5"
y=
"526.895"
>
dispatch
</text><polygon
fill=
"#FBFB77"
filter=
"url(#f13jg8eb0anesb)"
points=
"8,544.9609,8,569.9609,111,569.9609,111,554.9609,101,544.9609,8,544.9609"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"101"
x2=
"101"
y1=
"544.9609"
y2=
"554.9609"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"111"
x2=
"101"
y1=
"554.9609"
y2=
"554.9609"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"82"
x=
"14"
y=
"562.0278"
>
SDEI handler
</text><polygon
fill=
"#A80036"
points=
"363.5,596.0938,373.5,600.0938,363.5,604.0938,367.5,600.0938"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"369.5"
y1=
"600.0938"
y2=
"600.0938"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"30"
x=
"73.5"
y=
"595.1606"
>
[12]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"184"
x=
"107.5"
y=
"595.1606"
>
SDEI_EVENT_COMPLETE()
</text><polygon
fill=
"#FBFB77"
filter=
"url(#f13jg8eb0anesb)"
points=
"291,613.2266,291,638.2266,466,638.2266,466,623.2266,456,613.2266,291,613.2266"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"456"
x2=
"456"
y1=
"613.2266"
y2=
"623.2266"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"466"
x2=
"456"
y1=
"623.2266"
y2=
"623.2266"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"154"
x=
"297"
y=
"630.2935"
>
Complete SDEI dispatch
</text><polygon
fill=
"#A80036"
points=
"77.5,664.3594,67.5,668.3594,77.5,672.3594,73.5,668.3594"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"71.5"
x2=
"379.5"
y1=
"668.3594"
y2=
"668.3594"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"30"
x=
"83.5"
y=
"663.4263"
>
[13]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"197"
x=
"117.5"
y=
"663.4263"
>
resumes preempted execution
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"11"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"190"
x=
"232.5"
y=
"700.7026"
>
<<
Normal execution resumes
>>
</text></g></svg>
\ No newline at end of file
docs/plantuml/sdei_general.puml
0 → 100644
View file @
c195f1a7
/'
' Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
'
' SPDX-License-Identifier: BSD-3-Clause
'/
@startuml
autonumber "<b>[#]</b>"
participant "SDEI client" as EL2
participant EL3
participant "SDEI interrupt source" as SDEI
activate EL2
EL2->EL3: **SDEI_INTERRUPT_BIND**(irq)
EL3->EL2: event number: ev
EL2->EL3: **SDEI_EVENT_REGISTER**(ev, handler, ...)
EL3->EL2: success
EL2->EL3: **SDEI_EVENT_ENABLE**(ev)
EL3->EL2: success
EL2->EL3: **SDEI_PE_UNMASK**()
EL3->EL2: 1
... <<Business as usual>> ...
SDEI-->EL3: SDEI interrupt
activate SDEI #salmon
activate EL3 #red
note over EL3: Prepare SDEI dispatch
EL3->EL2: dispatch
activate EL2 #salmon
note over EL2: SDEI handler
EL2->EL3: **SDEI_EVENT_COMPLETE()**
deactivate EL2
note over EL3: Complete SDEI dispatch
EL3-->SDEI: EOI
deactivate SDEI
EL3->EL2: resumes preempted execution
deactivate EL3
... <<Normal execution resumes>> ...
@enduml
docs/plantuml/sdei_general.svg
0 → 100644
View file @
c195f1a7
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
contentScriptType=
"application/ecmascript"
contentStyleType=
"text/css"
height=
"676px"
preserveAspectRatio=
"none"
style=
"width:608px;height:676px;"
version=
"1.1"
viewBox=
"0 0 608 676"
width=
"608px"
zoomAndPan=
"magnify"
><defs><filter
height=
"300%"
id=
"fvds2ijrtbp5u"
width=
"300%"
x=
"-1"
y=
"-1"
><feGaussianBlur
result=
"blurOut"
stdDeviation=
"2.0"
/><feColorMatrix
in=
"blurOut"
result=
"blurOut2"
type=
"matrix"
values=
"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"
/><feOffset
dx=
"4.0"
dy=
"4.0"
in=
"blurOut2"
result=
"blurOut3"
/><feBlend
in=
"SourceGraphic"
in2=
"blurOut3"
mode=
"normal"
/></filter></defs><g><rect
fill=
"#FFFFFF"
filter=
"url(#fvds2ijrtbp5u)"
height=
"233.0625"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"48.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"48.2969"
y2=
"281.3594"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"48.2969"
y2=
"281.3594"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"66.5"
y1=
"48.2969"
y2=
"48.2969"
/><rect
fill=
"#FFFFFF"
filter=
"url(#fvds2ijrtbp5u)"
height=
"263.0625"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"322.1641"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"322.1641"
y2=
"585.2266"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"322.1641"
y2=
"585.2266"
/><rect
fill=
"#FFFFFF"
filter=
"url(#fvds2ijrtbp5u)"
height=
"1"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"626.0313"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"626.0313"
y2=
"627.0313"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"626.0313"
y2=
"627.0313"
/><rect
fill=
"#FA8072"
filter=
"url(#fvds2ijrtbp5u)"
height=
"68.2656"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"61.5"
y=
"411.4297"
/><rect
fill=
"#FF0000"
filter=
"url(#fvds2ijrtbp5u)"
height=
"233.9297"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"375.5"
y=
"343.1641"
/><rect
fill=
"#FA8072"
filter=
"url(#fvds2ijrtbp5u)"
height=
"204.7969"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"513.5"
y=
"343.1641"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"61"
x2=
"61"
y1=
"38.2969"
y2=
"281.3594"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"61"
x2=
"61"
y1=
"281.3594"
y2=
"322.1641"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"61"
x2=
"61"
y1=
"322.1641"
y2=
"585.2266"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"61"
x2=
"61"
y1=
"585.2266"
y2=
"626.0313"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"61"
x2=
"61"
y1=
"626.0313"
y2=
"636.0313"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"380"
x2=
"380"
y1=
"38.2969"
y2=
"281.3594"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"380"
x2=
"380"
y1=
"281.3594"
y2=
"322.1641"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"380"
x2=
"380"
y1=
"322.1641"
y2=
"585.2266"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"380"
x2=
"380"
y1=
"585.2266"
y2=
"626.0313"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"380"
x2=
"380"
y1=
"626.0313"
y2=
"636.0313"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"518"
x2=
"518"
y1=
"38.2969"
y2=
"281.3594"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"518"
x2=
"518"
y1=
"281.3594"
y2=
"322.1641"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"518"
x2=
"518"
y1=
"322.1641"
y2=
"585.2266"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;"
x1=
"518"
x2=
"518"
y1=
"585.2266"
y2=
"626.0313"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"518"
x2=
"518"
y1=
"626.0313"
y2=
"636.0313"
/><rect
fill=
"#FEFECE"
filter=
"url(#fvds2ijrtbp5u)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"87"
x=
"16"
y=
"3"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"73"
x=
"23"
y=
"22.9951"
>
SDEI client
</text><rect
fill=
"#FEFECE"
filter=
"url(#fvds2ijrtbp5u)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"87"
x=
"16"
y=
"635.0313"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"73"
x=
"23"
y=
"655.0264"
>
SDEI client
</text><rect
fill=
"#FEFECE"
filter=
"url(#fvds2ijrtbp5u)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"39"
x=
"359"
y=
"3"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"25"
x=
"366"
y=
"22.9951"
>
EL3
</text><rect
fill=
"#FEFECE"
filter=
"url(#fvds2ijrtbp5u)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"39"
x=
"359"
y=
"635.0313"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"25"
x=
"366"
y=
"655.0264"
>
EL3
</text><rect
fill=
"#FEFECE"
filter=
"url(#fvds2ijrtbp5u)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"161"
x=
"436"
y=
"3"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"147"
x=
"443"
y=
"22.9951"
>
SDEI interrupt source
</text><rect
fill=
"#FEFECE"
filter=
"url(#fvds2ijrtbp5u)"
height=
"30.2969"
style=
"stroke: #A80036; stroke-width: 1.5;"
width=
"161"
x=
"436"
y=
"635.0313"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"14"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"147"
x=
"443"
y=
"655.0264"
>
SDEI interrupt source
</text><rect
fill=
"#FFFFFF"
filter=
"url(#fvds2ijrtbp5u)"
height=
"233.0625"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"48.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"48.2969"
y2=
"281.3594"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"48.2969"
y2=
"281.3594"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"66.5"
y1=
"48.2969"
y2=
"48.2969"
/><rect
fill=
"#FFFFFF"
filter=
"url(#fvds2ijrtbp5u)"
height=
"263.0625"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"322.1641"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"322.1641"
y2=
"585.2266"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"322.1641"
y2=
"585.2266"
/><rect
fill=
"#FFFFFF"
filter=
"url(#fvds2ijrtbp5u)"
height=
"1"
style=
"stroke: #FFFFFF; stroke-width: 1.0;"
width=
"10"
x=
"56.5"
y=
"626.0313"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"56.5"
x2=
"56.5"
y1=
"626.0313"
y2=
"627.0313"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"66.5"
y1=
"626.0313"
y2=
"627.0313"
/><rect
fill=
"#FA8072"
filter=
"url(#fvds2ijrtbp5u)"
height=
"68.2656"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"61.5"
y=
"411.4297"
/><rect
fill=
"#FF0000"
filter=
"url(#fvds2ijrtbp5u)"
height=
"233.9297"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"375.5"
y=
"343.1641"
/><rect
fill=
"#FA8072"
filter=
"url(#fvds2ijrtbp5u)"
height=
"204.7969"
style=
"stroke: #A80036; stroke-width: 1.0;"
width=
"10"
x=
"513.5"
y=
"343.1641"
/><polygon
fill=
"#A80036"
points=
"368.5,65.2969,378.5,69.2969,368.5,73.2969,372.5,69.2969"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"374.5"
y1=
"69.2969"
y2=
"69.2969"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"73.5"
y=
"64.3638"
>
[1]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"163"
x=
"98.5"
y=
"64.3638"
>
SDEI_INTERRUPT_BIND
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"26"
x=
"261.5"
y=
"64.3638"
>
(irq)
</text><polygon
fill=
"#A80036"
points=
"77.5,94.4297,67.5,98.4297,77.5,102.4297,73.5,98.4297"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"71.5"
x2=
"379.5"
y1=
"98.4297"
y2=
"98.4297"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"83.5"
y=
"93.4966"
>
[2]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"113"
x=
"108.5"
y=
"93.4966"
>
event number: ev
</text><polygon
fill=
"#A80036"
points=
"368.5,123.5625,378.5,127.5625,368.5,131.5625,372.5,127.5625"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"374.5"
y1=
"127.5625"
y2=
"127.5625"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"73.5"
y=
"122.6294"
>
[3]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"164"
x=
"98.5"
y=
"122.6294"
>
SDEI_EVENT_REGISTER
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"101"
x=
"262.5"
y=
"122.6294"
>
(ev, handler, ...)
</text><polygon
fill=
"#A80036"
points=
"77.5,152.6953,67.5,156.6953,77.5,160.6953,73.5,156.6953"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"71.5"
x2=
"379.5"
y1=
"156.6953"
y2=
"156.6953"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"83.5"
y=
"151.7622"
>
[4]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"51"
x=
"108.5"
y=
"151.7622"
>
success
</text><polygon
fill=
"#A80036"
points=
"368.5,181.8281,378.5,185.8281,368.5,189.8281,372.5,185.8281"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"374.5"
y1=
"185.8281"
y2=
"185.8281"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"73.5"
y=
"180.895"
>
[5]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"151"
x=
"98.5"
y=
"180.895"
>
SDEI_EVENT_ENABLE
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"25"
x=
"249.5"
y=
"180.895"
>
(ev)
</text><polygon
fill=
"#A80036"
points=
"77.5,210.9609,67.5,214.9609,77.5,218.9609,73.5,214.9609"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"71.5"
x2=
"379.5"
y1=
"214.9609"
y2=
"214.9609"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"83.5"
y=
"210.0278"
>
[6]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"51"
x=
"108.5"
y=
"210.0278"
>
success
</text><polygon
fill=
"#A80036"
points=
"368.5,240.0938,378.5,244.0938,368.5,248.0938,372.5,244.0938"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"374.5"
y1=
"244.0938"
y2=
"244.0938"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"73.5"
y=
"239.1606"
>
[7]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"129"
x=
"98.5"
y=
"239.1606"
>
SDEI_PE_UNMASK
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"10"
x=
"227.5"
y=
"239.1606"
>
()
</text><polygon
fill=
"#A80036"
points=
"77.5,269.2266,67.5,273.2266,77.5,277.2266,73.5,273.2266"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"71.5"
x2=
"379.5"
y1=
"273.2266"
y2=
"273.2266"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"83.5"
y=
"268.2935"
>
[8]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"8"
x=
"108.5"
y=
"268.2935"
>
1
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"11"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"142"
x=
"219"
y=
"305.5698"
>
<<
Business as usual
>>
</text><polygon
fill=
"#A80036"
points=
"396.5,339.1641,386.5,343.1641,396.5,347.1641,392.5,343.1641"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;"
x1=
"390.5"
x2=
"512.5"
y1=
"343.1641"
y2=
"343.1641"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"402.5"
y=
"338.231"
>
[9]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"89"
x=
"427.5"
y=
"338.231"
>
SDEI interrupt
</text><polygon
fill=
"#FBFB77"
filter=
"url(#fvds2ijrtbp5u)"
points=
"297,356.2969,297,381.2969,460,381.2969,460,366.2969,450,356.2969,297,356.2969"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"450"
x2=
"450"
y1=
"356.2969"
y2=
"366.2969"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"460"
x2=
"450"
y1=
"366.2969"
y2=
"366.2969"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"142"
x=
"303"
y=
"373.3638"
>
Prepare SDEI dispatch
</text><polygon
fill=
"#A80036"
points=
"82.5,407.4297,72.5,411.4297,82.5,415.4297,78.5,411.4297"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"76.5"
x2=
"374.5"
y1=
"411.4297"
y2=
"411.4297"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"30"
x=
"88.5"
y=
"406.4966"
>
[10]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"54"
x=
"122.5"
y=
"406.4966"
>
dispatch
</text><polygon
fill=
"#FBFB77"
filter=
"url(#fvds2ijrtbp5u)"
points=
"8,424.5625,8,449.5625,111,449.5625,111,434.5625,101,424.5625,8,424.5625"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"101"
x2=
"101"
y1=
"424.5625"
y2=
"434.5625"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"111"
x2=
"101"
y1=
"434.5625"
y2=
"434.5625"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"82"
x=
"14"
y=
"441.6294"
>
SDEI handler
</text><polygon
fill=
"#A80036"
points=
"363.5,475.6953,373.5,479.6953,363.5,483.6953,367.5,479.6953"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"66.5"
x2=
"369.5"
y1=
"479.6953"
y2=
"479.6953"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"30"
x=
"73.5"
y=
"474.7622"
>
[11]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"184"
x=
"107.5"
y=
"474.7622"
>
SDEI_EVENT_COMPLETE()
</text><polygon
fill=
"#FBFB77"
filter=
"url(#fvds2ijrtbp5u)"
points=
"291,492.8281,291,517.8281,466,517.8281,466,502.8281,456,492.8281,291,492.8281"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"456"
x2=
"456"
y1=
"492.8281"
y2=
"502.8281"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"466"
x2=
"456"
y1=
"502.8281"
y2=
"502.8281"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"154"
x=
"297"
y=
"509.895"
>
Complete SDEI dispatch
</text><polygon
fill=
"#A80036"
points=
"506.5,543.9609,516.5,547.9609,506.5,551.9609,510.5,547.9609"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;"
x1=
"385.5"
x2=
"512.5"
y1=
"547.9609"
y2=
"547.9609"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"30"
x=
"392.5"
y=
"543.0278"
>
[12]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"21"
x=
"426.5"
y=
"543.0278"
>
EOI
</text><polygon
fill=
"#A80036"
points=
"77.5,573.0938,67.5,577.0938,77.5,581.0938,73.5,577.0938"
style=
"stroke: #A80036; stroke-width: 1.0;"
/><line
style=
"stroke: #A80036; stroke-width: 1.0;"
x1=
"71.5"
x2=
"379.5"
y1=
"577.0938"
y2=
"577.0938"
/><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
font-weight=
"bold"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"30"
x=
"83.5"
y=
"572.1606"
>
[13]
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"13"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"197"
x=
"117.5"
y=
"572.1606"
>
resumes preempted execution
</text><text
fill=
"#000000"
font-family=
"sans-serif"
font-size=
"11"
lengthAdjust=
"spacingAndGlyphs"
textLength=
"190"
x=
"195"
y=
"609.437"
>
<<
Normal execution resumes
>>
</text></g></svg>
\ No newline at end of file
docs/platform-interrupt-controller-API.rst
View file @
c195f1a7
...
@@ -292,6 +292,22 @@ inserts to order memory updates before updating mask, then writes to the GIC
...
@@ -292,6 +292,22 @@ inserts to order memory updates before updating mask, then writes to the GIC
*Priority Mask Register*, and make sure memory updates are visible before
*Priority Mask Register*, and make sure memory updates are visible before
potential trigger due to mask update.
potential trigger due to mask update.
Function: unsigned int plat_ic_get_interrupt_id(unsigned int raw); [optional]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
Argument : unsigned int
Return : unsigned int
This API should extract and return the interrupt number from the raw value
obtained by the acknowledging the interrupt (read using
``plat_ic_acknowledge_interrupt()``). If the interrupt ID is invalid, this API
should return ``INTR_ID_UNAVAILABLE``.
In case of ARM standard platforms using GIC, the implementation of the API
masks out the interrupt ID field from the acknowledged value from GIC.
----
----
*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
docs/porting-guide.rst
View file @
c195f1a7
...
@@ -1904,6 +1904,74 @@ calculated by the linker then a link time assertion is raised. A compile time
...
@@ -1904,6 +1904,74 @@ calculated by the linker then a link time assertion is raised. A compile time
assertion is raised if the value of the constant is not aligned to the cache
assertion is raised if the value of the constant is not aligned to the cache
line boundary.
line boundary.
SDEI porting requirements
~~~~~~~~~~~~~~~~~~~~~~~~~
The SDEI dispatcher requires the platform to provide the following macros
and functions, of which some are optional, and some others mandatory.
Macros
......
Macro: PLAT_SDEI_NORMAL_PRI [mandatory]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This macro must be defined to the EL3 exception priority level associated with
Normal SDEI events on the platform. This must have a higher value (therefore of
lower priority) than ``PLAT_SDEI_CRITICAL_PRI``.
Macro: PLAT_SDEI_CRITICAL_PRI [mandatory]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This macro must be defined to the EL3 exception priority level associated with
Critical SDEI events on the platform. This must have a lower value (therefore of
higher priority) than ``PLAT_SDEI_NORMAL_PRI``.
It's recommended that SDEI exception priorities in general are assigned the
lowest among Secure priorities. Among the SDEI exceptions, Critical SDEI
priority must be higher than Normal SDEI priority.
Functions
.........
Function: int plat_sdei_validate_entry_point(uintptr_t ep) [optional]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
Argument: uintptr_t
Return: int
This function validates the address of client entry points provided for both
event registration and *Complete and Resume* SDEI calls. The function takes one
argument, which is the address of the handler the SDEI client requested to
register. The function must return ``0`` for successful validation, or ``-1``
upon failure.
The default implementation always returns ``0``. On ARM platforms, this function
is implemented to translate the entry point to physical address, and further to
ensure that the address is located in Non-secure DRAM.
Function: void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr) [optional]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
Argument: uint64_t
Argument: unsigned int
Return: void
SDEI specification requires that a PE comes out of reset with the events masked.
The client therefore is expected to call ``PE_UNMASK`` to unmask SDEI events on
the PE. No SDEI events can be dispatched until such time.
Should a PE receive an interrupt that was bound to an SDEI event while the
events are masked on the PE, the dispatcher implementation invokes the function
``plat_sdei_handle_masked_trigger``. The MPIDR of the PE that received the
interrupt and the interrupt ID are passed as parameters.
The default implementation only prints out a warning message.
Power State Coordination Interface (in BL31)
Power State Coordination Interface (in BL31)
--------------------------------------------
--------------------------------------------
...
@@ -2479,14 +2547,17 @@ Function : plat\_ic\_acknowledge\_interrupt() [mandatory]
...
@@ -2479,14 +2547,17 @@ Function : plat\_ic\_acknowledge\_interrupt() [mandatory]
Return : uint32_t
Return : uint32_t
This API is used by the CPU to indicate to the platform IC that processing of
This API is used by the CPU to indicate to the platform IC that processing of
the highest pending interrupt has begun. It should return the id of the
the highest pending interrupt has begun. It should return the raw, unmodified
interrupt which is being processed.
value obtained from the interrupt controller when acknowledging an interrupt.
The actual interrupt number shall be extracted from this raw value using the API
`plat_ic_get_interrupt_id()`__.
.. __: platform-interrupt-controller-API.rst#function-unsigned-int-plat-ic-get-interrupt-id-unsigned-int-raw-optional
This function in ARM standard platforms using GICv2, reads the *Interrupt
This function in ARM standard platforms using GICv2, reads the *Interrupt
Acknowledge Register* (``GICC_IAR``). This changes the state of the highest
Acknowledge Register* (``GICC_IAR``). This changes the state of the highest
priority pending interrupt from pending to active in the interrupt controller.
priority pending interrupt from pending to active in the interrupt controller.
It returns the value read from the ``GICC_IAR``. This value is the id of the
It returns the value read from the ``GICC_IAR``, unmodified.
interrupt whose state has been changed.
In the case of ARM standard platforms using GICv3, if the API is invoked
In the case of ARM standard platforms using GICv3, if the API is invoked
from EL3, the function reads the system register ``ICC_IAR0_EL1``, *Interrupt
from EL3, the function reads the system register ``ICC_IAR0_EL1``, *Interrupt
...
@@ -2494,7 +2565,7 @@ Acknowledge Register group 0*. If the API is invoked from S-EL1, the function
...
@@ -2494,7 +2565,7 @@ Acknowledge Register group 0*. If the API is invoked from S-EL1, the function
reads the system register ``ICC_IAR1_EL1``, *Interrupt Acknowledge Register
reads the system register ``ICC_IAR1_EL1``, *Interrupt Acknowledge Register
group 1*. The read changes the state of the highest pending interrupt from
group 1*. The read changes the state of the highest pending interrupt from
pending to active in the interrupt controller. The value read is returned
pending to active in the interrupt controller. The value read is returned
and is the id of the interrupt whose state has been chang
ed.
unmodifi
ed.
The TSP uses this API to start processing of the secure physical timer
The TSP uses this API to start processing of the secure physical timer
interrupt.
interrupt.
...
...
docs/sdei.rst
0 → 100644
View file @
c195f1a7
Software Delegated Exception Interface
======================================
.. section-numbering::
:suffix: .
.. contents::
:depth: 2
This document provides an overview of the SDEI dispatcher implementation in ARM
Trusted Firmware.
Introduction
------------
`Software Delegated Exception Interface`_ (SDEI) is an ARM specification for
Non-secure world to register handlers with firmware to receive notifications
about system events. Firmware will first receive the system events by way of
asynchronous exceptions and, in response, arranges for the registered handler to
execute in the Non-secure EL.
Normal world software that interacts with the SDEI dispatcher (makes SDEI
requests and receives notifications) is referred to as the *SDEI Client*. A
client receives the event notification at the registered handler even when it
was executing with exceptions masked. The list of SDEI events available to the
client are specific to the platform [#std-event]_. See also `Determining client
EL`_.
.. _general SDEI dispatch:
The following figure depicts a general sequence involving SDEI client executing
at EL2 and an event dispatch resulting from the triggering of a bound interrupt.
A commentary is provided below:
.. image:: plantuml/sdei_general.svg
As part of initialisation, the SDEI client binds a Non-secure interrupt [1], and
the SDEI dispatcher returns a platform dynamic event number [2]. The client then
registers a handler for that event [3], enables the event [5], and unmasks all
events on the current PE [7]. This sequence is typical of an SDEI client, but it
may involve additional SDEI calls.
At a later point in time, when the bound interrupt triggers [9], it's trapped to
EL3. The interrupt is handed over to the SDEI dispatcher, which then arranges to
execute the registered handler [10]. The client terminates its execution with
``SDEI_EVENT_COMPLETE`` [11], following which the dispatcher resumes the
original EL2 execution [13]. Note that the SDEI interrupt remains active until
the client handler completes, at which point EL3 does EOI [12].
SDEI events can be explicitly dispatched in response to other asynchronous
exceptions. See `Explicit dispatch of events`_.
The remainder of this document only discusses the design and implementation of
SDEI dispatcher in ARM Trusted Firmware, and assumes that the reader is familiar
with the SDEI specification, the interfaces, and their requirements.
.. [#std-event] Except event 0, which is defined by the SDEI specification as a
standard event.
Defining events
---------------
A platform choosing to include the SDEI dispatcher must also define the events
available on the platform, along with their attributes.
The platform is expected to provide two arrays of event descriptors: one for
private events, and another for shared events. The SDEI dispatcher provides
``SDEI_PRIVATE_EVENT()`` and ``SDEI_SHARED_EVENT()`` macros to populate the
event descriptors. Both macros take 3 arguments:
- The event number: this must be a positive 32-bit integer.
- The interrupt number the event is bound to:
- If it's not applicable to an event, this shall be left as ``0``.
- If the event is dynamic, this should be specified as ``SDEI_DYN_IRQ``.
- A bit map of `Event flags`_.
To define event 0, the macro ``SDEI_DEFINE_EVENT_0()`` should be used. This
macro takes only one parameter: an SGI number to signal other PEs.
Once the event descriptor arrays are defined, they should be exported to the
SDEI dispatcher using the ``REGISTER_SDEI_MAP()`` macro, passing it the pointers
to the private and shared event descriptor arrays, respectively. Note that the
``REGISTER_SDEI_MAP()`` macro must be used in the same file where the arrays are
defined.
Regarding event descriptors:
- For Event 0:
- There must be exactly one descriptor in the private array, and none in the
shared array.
- The event should be defined using ``SDEI_DEFINE_EVENT_0()``.
- Must be bound to a Secure SGI on the platform.
- Statically bound shared and private interrupts must be bound to shared and
private interrupts on the platform, respectively. See the section on
`interrupt configuration`__.
.. __: `Configuration within Exception Handling Framework`_
- Both arrays should be one-dimensional. The ``REGISTER_SDEI_MAP()`` macro
takes care of replicating private events for each PE on the platform.
- Both arrays must be sorted in the increasing order of event number.
The SDEI specification doesn't have provisions for discovery of available events
on the platform. The list of events made available to the client, along with
their semantics, have to be communicated out of band; for example, through
Device Trees or firmware configuration tables.
See also `Event definition example`_.
Event flags
~~~~~~~~~~~
Event flags describe the properties of the event. They are bit maps that can be
``OR``\ ed to form parameters to macros that `define events`__.
.. __: `Defining events`_
- ``SDEI_MAPF_DYNAMIC``: Marks the event as dynamic. Dynamic events can be
bound to (or released from) any Non-secure interrupt at runtime via. the
``SDEI_INTERRUPT_BIND`` and ``SDEI_INTERRUPT_RELEASE`` calls.
- ``SDEI_MAPF_BOUND``: Marks the event as statically bound to an interrupt.
These events cannot be re-bound at runtime.
- ``SDEI_MAPF_CRITICAL``: Marks the event as having *Critical* priority.
Without this flag, the event is assumed to have *Normal* priority.
Event definition example
------------------------
.. code:: c
static sdei_ev_map_t plat_private_sdei[] = {
/* Event 0 definition */
SDEI_DEFINE_EVENT_0(8),
/* PPI */
SDEI_PRIVATE_EVENT(8, 23, SDEI_MAPF_BOUND),
/* Dynamic private events */
SDEI_PRIVATE_EVENT(100, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
SDEI_PRIVATE_EVENT(101, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC)
};
/* Shared event mappings */
static sdei_ev_map_t plat_shared_sdei[] = {
SDEI_SHARED_EVENT(804, 0, SDEI_MAPF_DYNAMIC),
/* Dynamic shared events */
SDEI_SHARED_EVENT(3000, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
SDEI_SHARED_EVENT(3001, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC)
};
/* Export SDEI events */
REGISTER_SDEI_MAP(plat_private_sdei, plat_shared_sdei);
Configuration within Exception Handling Framework
-------------------------------------------------
The SDEI dispatcher functions alongside the Exception Handling Framework. This
means that the platform must assign priorities to both Normal and Critical SDEI
interrupts for the platform:
- Install priority descriptors for Normal and Critical SDEI interrupts.
- For those interrupts that are statically bound (i.e. events defined as having
the ``SDEI_MAPF_BOUND`` property), enumerate their properties for the GIC
driver to configure interrupts accordingly.
The interrupts must be configured to target EL3. This means that they should
be configured as *Group 0*. Additionally, on GICv2 systems, the build option
``GICV2_G0_FOR_EL3`` must be set to ``1``.
See also `SDEI porting requirements`_.
Determining client EL
---------------------
The SDEI specification requires that the *physical* SDEI client executes in the
highest Non-secure EL implemented on the system. This means that the dispatcher
will only allow SDEI calls to be made from:
- EL2, if EL2 is implemented. The Hypervisor is expected to implement a
*virtual* SDEI dispatcher to support SDEI clients in Guest Operating Systems
executing in Non-secure EL1.
- Non-secure EL1, if EL2 is not implemented or disabled.
See the function ``sdei_client_el()`` in ``sdei_private.h``.
Explicit dispatch of events
---------------------------
Typically, an SDEI event dispatch is caused by the PE receiving interrupts that
are bound to an SDEI event. However, there are cases where the Secure world
requires dispatch of an SDEI event as a direct or indirect result of a past
activity, viz. receiving a Secure interrupt or an exception.
The SDEI dispatcher implementation provides ``sdei_dispatch_event()`` API for
this purpose. The API has the following signature:
::
int sdei_dispatch_event(int ev_num, unsigned int preempted_sec_state);
- The parameter ``ev_num`` is the event number to dispatch;
- The parameter ``preempted_sec_state`` indicates the context that was
preempted. This must be either ``SECURE`` or ``NON_SECURE``.
The API returns ``0`` on success, or ``-1`` on failure.
The following figure depicts a scenario involving explicit dispatch of SDEI
event. A commentary is provided below:
.. image:: plantuml/sdei_explicit_dispatch.svg
As part of initialisation, the SDEI client registers a handler for a platform
event [1], enables the event [3], and unmasks the current PE [5]. Note that,
unlike in `general SDEI dispatch`_, this doesn't involve interrupt binding, as
bound or dynamic events can't be explicitly dispatched (see the section below).
At a later point in time, a critical event [#critical-event]_ is trapped into
EL3 [7]. EL3 performs a first-level triage of the event, and decides to dispatch
to Secure EL1 for further handling [8]. The dispatch completes, but intends to
involve Non-secure world in further handling, and therefore decides to
explicitly dispatch an event [10] (which the client had already registered for
[1]). The rest of the sequence is similar to that in the `general SDEI
dispatch`_: the requested event is dispatched to the client (assuming all the
conditions are met), and when the handler completes, the preempted execution
resumes.
Conditions for event dispatch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
All of the following requirements must be met for the API to return ``0`` and
event to be dispatched:
- SDEI events must be unmasked on the PE. I.e. the client must have called
``PE_UNMASK`` beforehand.
- Event 0 can't be dispatched.
- The event must neither be a dynamic event nor be bound to an interrupt.
- The event must be private to the PE.
- The event must have been registered for and enabled.
- A dispatch for the same event must not be outstanding. I.e. it hasn't already
been dispatched and is yet to be completed.
- The priority of the event (either Critical or Normal, as configured by the
platform at build-time) shouldn't cause priority inversion. This means:
- If it's of Normal priority, neither Normal nor Critical priority dispatch
must be outstanding on the PE.
- If it's of a Critical priority, no Critical priority dispatch must be
outstanding on the PE.
Further, the caller should be aware of the following assumptions made by the
dispatcher:
- The caller of the API is a component running in EL3; for example, the *Secure
Partition Manager*.
- The requested dispatch will be permitted by the Exception Handling Framework.
I.e. the caller must make sure that the requested dispatch has sufficient
priority so as not to cause priority level inversion within Exception
Handling Framework.
- At the time of the call, the active context is Secure, and it has been saved.
- Upon returning success, the Non-secure context will be restored and setup for
the event dispatch, and it will be the active context. The Non-secure context
should not be modified further by the caller.
- The API returning success only means that the dispatch is scheduled at the
next ``ERET``, and not immediately performed. Also, the caller must be
prepared for this API to return failure and handle accordingly.
- Upon completing the event (i.e. when the client calls either
``SDEI_EVENT_COMPLETE`` or ``SDEI_COMPLETE_AND_RESUME``), the preempted
context is resumed (as indicated by the ``preempted_sec_state`` parameter of
the API).
.. [#critical-event] Examples of critical event are *SError*, *Synchronous
External Abort*, *Fault Handling interrupt*, or *Error
Recovery interrupt* from one of RAS nodes in the system.
Porting requirements
--------------------
The porting requirements of the SDEI dispatcher are outlined in the `porting
guide`__.
.. __: `SDEI porting requirements`_
Note on writing SDEI event handlers
-----------------------------------
*This section pertains to SDEI event handlers in general, not just when using
ARM Trusted Firmware SDEI dispatcher.*
The SDEI specification requires that event handlers preserve the contents of all
registers except ``x0`` to ``x17``. This has significance if event handler is
written in C: compilers typically adjust the stack frame at the beginning and
end of C functions. For example, AArch64 GCC typically produces the following
function prologue and epilogue:
::
c_event_handler:
stp x29, x30, [sp,#-32]!
mov x29, sp
...
bl ...
...
ldp x29, x30, [sp],#32
ret
The register ``x29`` is used as frame pointer in the prologue. Because neither a
valid ``SDEI_EVENT_COMPLETE`` nor ``SDEI_EVENT_COMPLETE_AND_RESUME`` calls
return to the handler, the epilogue never gets executed, and registers ``x29``
and ``x30`` (in the case above) are inadvertently corrupted. This violates the
SDEI specification, and the normal execution thereafter will result in
unexpected behaviour.
To work this around, it's advised that the top-level event handlers are
implemented in assembly, following a similar pattern as below:
::
asm_event_handler:
/* Save link register whilst maintaining stack alignment */
stp xzr, x30, [sp, #-16]!
bl c_event_handler
/* Restore link register */
ldp xzr, x30, [sp], #16
/* Complete call */
ldr x0, =SDEI_EVENT_COMPLETE
smc #0
b .
----
*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
.. _SDEI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
.. _SDEI porting requirements: porting-guide.rst#sdei-porting-requirements
docs/user-guide.rst
View file @
c195f1a7
...
@@ -361,6 +361,11 @@ Common build options
...
@@ -361,6 +361,11 @@ Common build options
Firmware
as
error
.
It
can
take
the
value
1
(
flag
the
use
of
deprecated
Firmware
as
error
.
It
can
take
the
value
1
(
flag
the
use
of
deprecated
APIs
as
error
)
or
0.
The
default
is
0.
APIs
as
error
)
or
0.
The
default
is
0.
-
``
EL3_EXCEPTION_HANDLING
``:
When
set
to
``
1
``,
enable
handling
of
exceptions
targeted
at
EL3
.
When
set
``
0
``
(
default
),
no
exceptions
are
expected
or
handled
at
EL3
,
and
a
panic
will
result
.
This
is
supported
only
for
AArch64
builds
.
-
``
FIP_NAME
``:
This
is
an
optional
build
option
which
specifies
the
FIP
-
``
FIP_NAME
``:
This
is
an
optional
build
option
which
specifies
the
FIP
filename
for
the
``
fip
``
target
.
Default
is
``
fip
.
bin
``.
filename
for
the
``
fip
``
target
.
Default
is
``
fip
.
bin
``.
...
@@ -529,6 +534,12 @@ Common build options
...
@@ -529,6 +534,12 @@ Common build options
optional
.
It
is
only
needed
if
the
platform
makefile
specifies
that
it
optional
.
It
is
only
needed
if
the
platform
makefile
specifies
that
it
is
required
in
order
to
build
the
``
fwu_fip
``
target
.
is
required
in
order
to
build
the
``
fwu_fip
``
target
.
-
``
SDEI_SUPPORT
``:
Setting
this
to
``
1
``
enables
support
for
Software
Delegated
Exception
Interface
to
BL31
image
.
This
defaults
to
``
0
``.
When
set
to
``
1
``,
the
build
option
``
EL3_EXCEPTION_HANDLING
``
must
also
be
set
to
``
1
``.
-
``
SEPARATE_CODE_AND_RODATA
``:
Whether
code
and
read
-
only
data
should
be
-
``
SEPARATE_CODE_AND_RODATA
``:
Whether
code
and
read
-
only
data
should
be
isolated
on
separate
memory
pages
.
This
is
a
trade
-
off
between
security
and
isolated
on
separate
memory
pages
.
This
is
a
trade
-
off
between
security
and
memory
usage
.
See
"Isolating code and read-only data on separate memory
memory
usage
.
See
"Isolating code and read-only data on separate memory
...
...
drivers/arm/gic/v2/gicv2_main.c
View file @
c195f1a7
...
@@ -72,6 +72,8 @@ void gicv2_cpuif_disable(void)
...
@@ -72,6 +72,8 @@ void gicv2_cpuif_disable(void)
******************************************************************************/
******************************************************************************/
void
gicv2_pcpu_distif_init
(
void
)
void
gicv2_pcpu_distif_init
(
void
)
{
{
unsigned
int
ctlr
;
assert
(
driver_data
);
assert
(
driver_data
);
assert
(
driver_data
->
gicd_base
);
assert
(
driver_data
->
gicd_base
);
...
@@ -89,6 +91,13 @@ void gicv2_pcpu_distif_init(void)
...
@@ -89,6 +91,13 @@ void gicv2_pcpu_distif_init(void)
driver_data
->
g0_interrupt_array
);
driver_data
->
g0_interrupt_array
);
}
}
#endif
#endif
/* Enable G0 interrupts if not already */
ctlr
=
gicd_read_ctlr
(
driver_data
->
gicd_base
);
if
((
ctlr
&
CTLR_ENABLE_G0_BIT
)
==
0
)
{
gicd_write_ctlr
(
driver_data
->
gicd_base
,
ctlr
|
CTLR_ENABLE_G0_BIT
);
}
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -308,9 +317,26 @@ void gicv2_set_pe_target_mask(unsigned int proc_num)
...
@@ -308,9 +317,26 @@ void gicv2_set_pe_target_mask(unsigned int proc_num)
if
(
driver_data
->
target_masks
[
proc_num
])
if
(
driver_data
->
target_masks
[
proc_num
])
return
;
return
;
/* Read target register corresponding to this CPU */
/*
driver_data
->
target_masks
[
proc_num
]
=
* Update target register corresponding to this CPU and flush for it to
gicv2_get_cpuif_id
(
driver_data
->
gicd_base
);
* be visible to other CPUs.
*/
if
(
driver_data
->
target_masks
[
proc_num
]
==
0
)
{
driver_data
->
target_masks
[
proc_num
]
=
gicv2_get_cpuif_id
(
driver_data
->
gicd_base
);
#if !HW_ASSISTED_COHERENCY
/*
* PEs only update their own masks. Primary updates it with
* caches on. But because secondaries does it with caches off,
* all updates go to memory directly, and there's no danger of
* secondaries overwriting each others' mask, despite
* target_masks[] not being cache line aligned.
*/
flush_dcache_range
((
uintptr_t
)
&
driver_data
->
target_masks
[
proc_num
],
sizeof
(
driver_data
->
target_masks
[
proc_num
]));
#endif
}
}
}
/*******************************************************************************
/*******************************************************************************
...
...
drivers/arm/gic/v3/gicv3_helpers.c
View file @
c195f1a7
...
@@ -541,12 +541,13 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
...
@@ -541,12 +541,13 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
/*******************************************************************************
/*******************************************************************************
* Helper function to configure properties of secure G0 and G1S PPIs and SGIs.
* Helper function to configure properties of secure G0 and G1S PPIs and SGIs.
******************************************************************************/
******************************************************************************/
void
gicv3_secure_ppi_sgi_configure_props
(
uintptr_t
gicr_base
,
unsigned
int
gicv3_secure_ppi_sgi_configure_props
(
uintptr_t
gicr_base
,
const
interrupt_prop_t
*
interrupt_props
,
const
interrupt_prop_t
*
interrupt_props
,
unsigned
int
interrupt_props_num
)
unsigned
int
interrupt_props_num
)
{
{
unsigned
int
i
;
unsigned
int
i
;
const
interrupt_prop_t
*
current_prop
;
const
interrupt_prop_t
*
current_prop
;
unsigned
int
ctlr_enable
=
0
;
/* Make sure there's a valid property array */
/* Make sure there's a valid property array */
assert
(
interrupt_props
!=
NULL
);
assert
(
interrupt_props
!=
NULL
);
...
@@ -564,10 +565,13 @@ void gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base,
...
@@ -564,10 +565,13 @@ void gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base,
/* Configure this interrupt as G0 or a G1S interrupt */
/* Configure this interrupt as G0 or a G1S interrupt */
assert
((
current_prop
->
intr_grp
==
INTR_GROUP0
)
||
assert
((
current_prop
->
intr_grp
==
INTR_GROUP0
)
||
(
current_prop
->
intr_grp
==
INTR_GROUP1S
));
(
current_prop
->
intr_grp
==
INTR_GROUP1S
));
if
(
current_prop
->
intr_grp
==
INTR_GROUP1S
)
if
(
current_prop
->
intr_grp
==
INTR_GROUP1S
)
{
gicr_set_igrpmodr0
(
gicr_base
,
current_prop
->
intr_num
);
gicr_set_igrpmodr0
(
gicr_base
,
current_prop
->
intr_num
);
else
ctlr_enable
|=
CTLR_ENABLE_G1S_BIT
;
}
else
{
gicr_clr_igrpmodr0
(
gicr_base
,
current_prop
->
intr_num
);
gicr_clr_igrpmodr0
(
gicr_base
,
current_prop
->
intr_num
);
ctlr_enable
|=
CTLR_ENABLE_G0_BIT
;
}
/* Set the priority of this interrupt */
/* Set the priority of this interrupt */
gicr_set_ipriorityr
(
gicr_base
,
current_prop
->
intr_num
,
gicr_set_ipriorityr
(
gicr_base
,
current_prop
->
intr_num
,
...
@@ -586,4 +590,6 @@ void gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base,
...
@@ -586,4 +590,6 @@ void gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base,
/* Enable this interrupt */
/* Enable this interrupt */
gicr_set_isenabler0
(
gicr_base
,
current_prop
->
intr_num
);
gicr_set_isenabler0
(
gicr_base
,
current_prop
->
intr_num
);
}
}
return
ctlr_enable
;
}
}
drivers/arm/gic/v3/gicv3_main.c
View file @
c195f1a7
...
@@ -224,12 +224,16 @@ void gicv3_distif_init(void)
...
@@ -224,12 +224,16 @@ void gicv3_distif_init(void)
void
gicv3_rdistif_init
(
unsigned
int
proc_num
)
void
gicv3_rdistif_init
(
unsigned
int
proc_num
)
{
{
uintptr_t
gicr_base
;
uintptr_t
gicr_base
;
unsigned
int
bitmap
=
0
;
uint32_t
ctlr
;
assert
(
gicv3_driver_data
);
assert
(
gicv3_driver_data
);
assert
(
proc_num
<
gicv3_driver_data
->
rdistif_num
);
assert
(
proc_num
<
gicv3_driver_data
->
rdistif_num
);
assert
(
gicv3_driver_data
->
rdistif_base_addrs
);
assert
(
gicv3_driver_data
->
rdistif_base_addrs
);
assert
(
gicv3_driver_data
->
gicd_base
);
assert
(
gicv3_driver_data
->
gicd_base
);
assert
(
gicd_read_ctlr
(
gicv3_driver_data
->
gicd_base
)
&
CTLR_ARE_S_BIT
);
ctlr
=
gicd_read_ctlr
(
gicv3_driver_data
->
gicd_base
);
assert
(
ctlr
&
CTLR_ARE_S_BIT
);
assert
(
IS_IN_EL3
());
assert
(
IS_IN_EL3
());
...
@@ -244,7 +248,7 @@ void gicv3_rdistif_init(unsigned int proc_num)
...
@@ -244,7 +248,7 @@ void gicv3_rdistif_init(unsigned int proc_num)
#if !ERROR_DEPRECATED
#if !ERROR_DEPRECATED
if
(
gicv3_driver_data
->
interrupt_props
!=
NULL
)
{
if
(
gicv3_driver_data
->
interrupt_props
!=
NULL
)
{
#endif
#endif
gicv3_secure_ppi_sgi_configure_props
(
gicr_base
,
bitmap
=
gicv3_secure_ppi_sgi_configure_props
(
gicr_base
,
gicv3_driver_data
->
interrupt_props
,
gicv3_driver_data
->
interrupt_props
,
gicv3_driver_data
->
interrupt_props_num
);
gicv3_driver_data
->
interrupt_props_num
);
#if !ERROR_DEPRECATED
#if !ERROR_DEPRECATED
...
@@ -258,6 +262,7 @@ void gicv3_rdistif_init(unsigned int proc_num)
...
@@ -258,6 +262,7 @@ void gicv3_rdistif_init(unsigned int proc_num)
gicv3_driver_data
->
g1s_interrupt_num
,
gicv3_driver_data
->
g1s_interrupt_num
,
gicv3_driver_data
->
g1s_interrupt_array
,
gicv3_driver_data
->
g1s_interrupt_array
,
INTR_GROUP1S
);
INTR_GROUP1S
);
bitmap
|=
CTLR_ENABLE_G1S_BIT
;
}
}
/* Configure the G0 SGIs/PPIs */
/* Configure the G0 SGIs/PPIs */
...
@@ -266,9 +271,14 @@ void gicv3_rdistif_init(unsigned int proc_num)
...
@@ -266,9 +271,14 @@ void gicv3_rdistif_init(unsigned int proc_num)
gicv3_driver_data
->
g0_interrupt_num
,
gicv3_driver_data
->
g0_interrupt_num
,
gicv3_driver_data
->
g0_interrupt_array
,
gicv3_driver_data
->
g0_interrupt_array
,
INTR_GROUP0
);
INTR_GROUP0
);
bitmap
|=
CTLR_ENABLE_G0_BIT
;
}
}
}
}
#endif
#endif
/* Enable interrupt groups as required, if not already */
if
((
ctlr
&
bitmap
)
!=
bitmap
)
gicd_set_ctlr
(
gicv3_driver_data
->
gicd_base
,
bitmap
,
RWP_TRUE
);
}
}
/*******************************************************************************
/*******************************************************************************
...
...
drivers/arm/gic/v3/gicv3_private.h
View file @
c195f1a7
...
@@ -95,7 +95,7 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
...
@@ -95,7 +95,7 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
const
unsigned
int
*
sec_intr_list
,
const
unsigned
int
*
sec_intr_list
,
unsigned
int
int_grp
);
unsigned
int
int_grp
);
#endif
#endif
void
gicv3_secure_ppi_sgi_configure_props
(
uintptr_t
gicr_base
,
unsigned
int
gicv3_secure_ppi_sgi_configure_props
(
uintptr_t
gicr_base
,
const
interrupt_prop_t
*
interrupt_props
,
const
interrupt_prop_t
*
interrupt_props
,
unsigned
int
interrupt_props_num
);
unsigned
int
interrupt_props_num
);
unsigned
int
gicv3_secure_spis_configure_props
(
uintptr_t
gicd_base
,
unsigned
int
gicv3_secure_spis_configure_props
(
uintptr_t
gicd_base
,
...
...
include/bl31/ehf.h
0 → 100644
View file @
c195f1a7
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __EHF_H__
#define __EHF_H__
#ifndef __ASSEMBLY__
#include <stdint.h>
#include <utils_def.h>
/* Valid priorities set bit 0 of the priority handler. */
#define _EHF_PRI_VALID (((uintptr_t) 1) << 0)
/* Marker for no handler registered for a valid priority */
#define _EHF_NO_HANDLER (0 | _EHF_PRI_VALID)
/* Extract the specified number of top bits from 7 lower bits of priority */
#define EHF_PRI_TO_IDX(pri, plat_bits) \
((pri & 0x7f) >> (7 - plat_bits))
/* Install exception priority descriptor at a suitable index */
#define EHF_PRI_DESC(plat_bits, priority) \
[EHF_PRI_TO_IDX(priority, plat_bits)] = { \
.ehf_handler = _EHF_NO_HANDLER, \
}
/* Macro for platforms to regiter its exception priorities */
#define EHF_REGISTER_PRIORITIES(priorities, num, bits) \
const ehf_priorities_t exception_data = { \
.num_priorities = num, \
.ehf_priorities = priorities, \
.pri_bits = bits, \
}
/*
* Priority stack, managed as a bitmap.
*
* Currently only supports 32 priority levels, allowing platforms to use up to 5
* top bits of priority. But the type can be changed to uint64_t should need
* arise to support 64 priority levels, allowing platforms to use up to 6 top
* bits of priority.
*/
typedef
uint32_t
ehf_pri_bits_t
;
/*
* Per-PE exception data. The data for each PE is kept as a per-CPU data field.
* See cpu_data.h.
*/
typedef
struct
{
ehf_pri_bits_t
active_pri_bits
;
/* Priority mask value before any priority levels were active */
uint8_t
init_pri_mask
;
/* Non-secure priority mask value stashed during Secure execution */
uint8_t
ns_pri_mask
;
}
__aligned
(
sizeof
(
uint64_t
))
pe_exc_data_t
;
typedef
int
(
*
ehf_handler_t
)(
uint32_t
intr_raw
,
uint32_t
flags
,
void
*
handle
,
void
*
cookie
);
typedef
struct
ehf_pri_desc
{
/*
* 4-byte-aligned exception handler. Bit 0 indicates the corresponding
* priority level is valid. This is effectively of ehf_handler_t type,
* but left as uintptr_t in order to make pointer arithmetic convenient.
*/
uintptr_t
ehf_handler
;
}
ehf_pri_desc_t
;
typedef
struct
ehf_priorities
{
ehf_pri_desc_t
*
ehf_priorities
;
unsigned
int
num_priorities
;
int
pri_bits
;
}
ehf_priorities_t
;
void
ehf_init
(
void
);
void
ehf_activate_priority
(
unsigned
int
priority
);
void
ehf_deactivate_priority
(
unsigned
int
priority
);
void
ehf_register_priority_handler
(
unsigned
int
pri
,
ehf_handler_t
handler
);
void
ehf_allow_ns_preemption
(
void
);
unsigned
int
ehf_is_ns_preemption_allowed
(
void
);
#endif
/* __ASSEMBLY__ */
#endif
/* __EHF_H__ */
include/drivers/arm/gic_common.h
View file @
c195f1a7
...
@@ -34,10 +34,10 @@
...
@@ -34,10 +34,10 @@
#define GIC_INTR_CFG_EDGE 1
#define GIC_INTR_CFG_EDGE 1
/* Constants to categorise priorities */
/* Constants to categorise priorities */
#define GIC_HIGHEST_SEC_PRIORITY 0
#define GIC_HIGHEST_SEC_PRIORITY 0
x0
#define GIC_LOWEST_SEC_PRIORITY
127
#define GIC_LOWEST_SEC_PRIORITY
0x7f
#define GIC_HIGHEST_NS_PRIORITY
128
#define GIC_HIGHEST_NS_PRIORITY
0x80
#define GIC_LOWEST_NS_PRIORITY
254
/* 255
would disable a
n
interrupt */
#define GIC_LOWEST_NS_PRIORITY
0xfe
/* 0xff
would disable a
ll
interrupt
s
*/
/*******************************************************************************
/*******************************************************************************
* GIC Distributor interface register offsets that are common to GICv3 & GICv2
* GIC Distributor interface register offsets that are common to GICv3 & GICv2
...
...
include/drivers/arm/gicv3.h
View file @
c195f1a7
...
@@ -245,6 +245,9 @@
...
@@ -245,6 +245,9 @@
#define GICR_NUM_REGS(reg_name) \
#define GICR_NUM_REGS(reg_name) \
DIV_ROUND_UP_2EVAL(TOTAL_PCPU_INTR_NUM, (1 << reg_name ## _SHIFT))
DIV_ROUND_UP_2EVAL(TOTAL_PCPU_INTR_NUM, (1 << reg_name ## _SHIFT))
/* Interrupt ID mask for HPPIR, AHPPIR, IAR and AIAR CPU Interface registers */
#define INT_ID_MASK 0xffffff
/*******************************************************************************
/*******************************************************************************
* This structure describes some of the implementation defined attributes of the
* This structure describes some of the implementation defined attributes of the
* GICv3 IP. It is used by the platform port to specify these attributes in order
* GICv3 IP. It is used by the platform port to specify these attributes in order
...
...
include/lib/aarch64/arch.h
View file @
c195f1a7
...
@@ -598,4 +598,10 @@
...
@@ -598,4 +598,10 @@
#define MAKE_MAIR_NORMAL_MEMORY(inner, outer) ((inner) | ((outer) << MAIR_NORM_OUTER_SHIFT))
#define MAKE_MAIR_NORMAL_MEMORY(inner, outer) ((inner) | ((outer) << MAIR_NORM_OUTER_SHIFT))
/* PAR_EL1 fields */
#define PAR_F_SHIFT 0
#define PAR_F_MASK 1
#define PAR_ADDR_SHIFT 12
#define PAR_ADDR_MASK (BIT(40) - 1)
/* 40-bits-wide page address */
#endif
/* __ARCH_H__ */
#endif
/* __ARCH_H__ */
Prev
1
2
3
Next
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