Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
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
7 years ago
by
davidcunado-arm
Committed by
GitHub
7 years ago
Browse files
Options
Download
Plain Diff
Merge pull request #1152 from jeenu-arm/ehf-and-sdei
EHF and SDEI
parents
bf2de7e4
cafad7be
Changes
44
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
services/std_svc/sdei/sdei_main.c
+1064
-0
services/std_svc/sdei/sdei_main.c
services/std_svc/sdei/sdei_private.h
+234
-0
services/std_svc/sdei/sdei_private.h
services/std_svc/sdei/sdei_state.c
+150
-0
services/std_svc/sdei/sdei_state.c
services/std_svc/std_svc_setup.c
+13
-1
services/std_svc/std_svc_setup.c
with
1461 additions
and
1 deletion
+1461
-1
services/std_svc/sdei/sdei_main.c
0 → 100644
View file @
c195f1a7
This diff is collapsed.
Click to expand it.
services/std_svc/sdei/sdei_private.h
0 → 100644
View file @
c195f1a7
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __SDEI_PRIVATE_H__
#define __SDEI_PRIVATE_H__
#include <arch_helpers.h>
#include <debug.h>
#include <errno.h>
#include <interrupt_mgmt.h>
#include <platform.h>
#include <sdei.h>
#include <spinlock.h>
#include <stdbool.h>
#include <types.h>
#include <utils_def.h>
#ifdef AARCH32
# error SDEI is implemented only for AArch64 systems
#endif
#ifndef PLAT_SDEI_CRITICAL_PRI
# error Platform must define SDEI critical priority value
#endif
#ifndef PLAT_SDEI_NORMAL_PRI
# error Platform must define SDEI normal priority value
#endif
/* Output SDEI logs as verbose */
#define SDEI_LOG(...) VERBOSE("SDEI: " __VA_ARGS__)
/* SDEI handler unregistered state. This is the default state. */
#define SDEI_STATE_UNREGISTERED 0
/* SDE event status values in bit position */
#define SDEI_STATF_REGISTERED 0
#define SDEI_STATF_ENABLED 1
#define SDEI_STATF_RUNNING 2
/* SDEI SMC error codes */
#define SDEI_EINVAL (-2)
#define SDEI_EDENY (-3)
#define SDEI_EPEND (-5)
#define SDEI_ENOMEM (-10)
/*
* 'info' parameter to SDEI_EVENT_GET_INFO SMC.
*
* Note that the SDEI v1.0 speification mistakenly enumerates the
* SDEI_INFO_EV_SIGNALED as SDEI_INFO_SIGNALED. This will be corrected in a
* future version.
*/
#define SDEI_INFO_EV_TYPE 0
#define SDEI_INFO_EV_NOT_SIGNALED 1
#define SDEI_INFO_EV_PRIORITY 2
#define SDEI_INFO_EV_ROUTING_MODE 3
#define SDEI_INFO_EV_ROUTING_AFF 4
#define SDEI_PRIVATE_MAPPING() (&sdei_global_mappings[_SDEI_MAP_IDX_PRIV])
#define SDEI_SHARED_MAPPING() (&sdei_global_mappings[_SDEI_MAP_IDX_SHRD])
#define for_each_mapping_type(_i, _mapping) \
for (_i = 0, _mapping = &sdei_global_mappings[i]; \
_i < _SDEI_MAP_IDX_MAX; \
_i++, _mapping = &sdei_global_mappings[i])
#define iterate_mapping(_mapping, _i, _map) \
for (_map = (_mapping)->map, _i = 0; \
_i < (_mapping)->num_maps; \
_i++, _map++)
#define for_each_private_map(_i, _map) \
iterate_mapping(SDEI_PRIVATE_MAPPING(), _i, _map)
#define for_each_shared_map(_i, _map) \
iterate_mapping(SDEI_SHARED_MAPPING(), _i, _map)
/* SDEI_FEATURES */
#define SDEI_FEATURE_BIND_SLOTS 0
#define BIND_SLOTS_MASK 0xffff
#define FEATURES_SHARED_SLOTS_SHIFT 16
#define FEATURES_PRIVATE_SLOTS_SHIFT 0
#define FEATURE_BIND_SLOTS(_priv, _shrd) \
((((_priv) & BIND_SLOTS_MASK) << FEATURES_PRIVATE_SLOTS_SHIFT) | \
(((_shrd) & BIND_SLOTS_MASK) << FEATURES_SHARED_SLOTS_SHIFT))
#define GET_EV_STATE(_e, _s) get_ev_state_bit(_e, SDEI_STATF_##_s)
#define SET_EV_STATE(_e, _s) clr_ev_state_bit(_e->state, SDEI_STATF_##_s)
static
inline
int
is_event_private
(
sdei_ev_map_t
*
map
)
{
return
((
map
->
map_flags
&
BIT
(
_SDEI_MAPF_PRIVATE_SHIFT
))
!=
0
);
}
static
inline
int
is_event_shared
(
sdei_ev_map_t
*
map
)
{
return
!
is_event_private
(
map
);
}
static
inline
int
is_event_critical
(
sdei_ev_map_t
*
map
)
{
return
((
map
->
map_flags
&
BIT
(
_SDEI_MAPF_CRITICAL_SHIFT
))
!=
0
);
}
static
inline
int
is_event_normal
(
sdei_ev_map_t
*
map
)
{
return
!
is_event_critical
(
map
);
}
static
inline
int
is_event_signalable
(
sdei_ev_map_t
*
map
)
{
return
((
map
->
map_flags
&
BIT
(
_SDEI_MAPF_SIGNALABLE_SHIFT
))
!=
0
);
}
static
inline
int
is_map_dynamic
(
sdei_ev_map_t
*
map
)
{
return
((
map
->
map_flags
&
BIT
(
_SDEI_MAPF_DYNAMIC_SHIFT
))
!=
0
);
}
/*
* Checks whether an event is associated with an interrupt. Static events always
* return true, and dynamic events return whether SDEI_INTERRUPT_BIND had been
* called on them. This can be used on both static or dynamic events to check
* for an associated interrupt.
*/
static
inline
int
is_map_bound
(
sdei_ev_map_t
*
map
)
{
return
((
map
->
map_flags
&
BIT
(
_SDEI_MAPF_BOUND_SHIFT
))
!=
0
);
}
static
inline
void
set_map_bound
(
sdei_ev_map_t
*
map
)
{
map
->
map_flags
|=
BIT
(
_SDEI_MAPF_BOUND_SHIFT
);
}
static
inline
void
clr_map_bound
(
sdei_ev_map_t
*
map
)
{
map
->
map_flags
&=
~
(
BIT
(
_SDEI_MAPF_BOUND_SHIFT
));
}
static
inline
int
is_secure_sgi
(
unsigned
int
intr
)
{
return
(
plat_ic_is_sgi
(
intr
)
&&
(
plat_ic_get_interrupt_type
(
intr
)
==
INTR_TYPE_EL3
));
}
/*
* Determine EL of the client. If EL2 is implemented (hence the enabled HCE
* bit), deem EL2; otherwise, deem EL1.
*/
static
inline
unsigned
int
sdei_client_el
(
void
)
{
return
read_scr_el3
()
&
SCR_HCE_BIT
?
MODE_EL2
:
MODE_EL1
;
}
static
inline
unsigned
int
sdei_event_priority
(
sdei_ev_map_t
*
map
)
{
return
is_event_critical
(
map
)
?
PLAT_SDEI_CRITICAL_PRI
:
PLAT_SDEI_NORMAL_PRI
;
}
static
inline
int
get_ev_state_bit
(
sdei_entry_t
*
se
,
unsigned
int
bit_no
)
{
return
((
se
->
state
&
BIT
(
bit_no
))
!=
0
);
}
static
inline
void
clr_ev_state_bit
(
sdei_entry_t
*
se
,
unsigned
int
bit_no
)
{
se
->
state
&=
~
BIT
(
bit_no
);
}
/* SDEI actions for state transition */
typedef
enum
{
/*
* Actions resulting from client requests. These directly map to SMC
* calls. Note that the state table columns are listed in this order
* too.
*/
DO_REGISTER
=
0
,
DO_RELEASE
=
1
,
DO_ENABLE
=
2
,
DO_DISABLE
=
3
,
DO_UNREGISTER
=
4
,
DO_ROUTING
=
5
,
DO_CONTEXT
=
6
,
DO_COMPLETE
=
7
,
DO_COMPLETE_RESUME
=
8
,
/* Action for event dispatch */
DO_DISPATCH
=
9
,
DO_MAX
,
}
sdei_action_t
;
typedef
enum
{
SDEI_NORMAL
,
SDEI_CRITICAL
}
sdei_class_t
;
static
inline
void
sdei_map_lock
(
sdei_ev_map_t
*
map
)
{
spin_lock
(
&
map
->
lock
);
}
static
inline
void
sdei_map_unlock
(
sdei_ev_map_t
*
map
)
{
spin_unlock
(
&
map
->
lock
);
}
extern
const
sdei_mapping_t
sdei_global_mappings
[];
extern
sdei_entry_t
sdei_private_event_table
[];
extern
sdei_entry_t
sdei_shared_event_table
[];
void
init_sdei_state
(
void
);
sdei_ev_map_t
*
find_event_map_by_intr
(
int
intr_num
,
int
shared
);
sdei_ev_map_t
*
find_event_map
(
int
ev_num
);
sdei_entry_t
*
get_event_entry
(
sdei_ev_map_t
*
map
);
int
sdei_event_context
(
void
*
handle
,
unsigned
int
param
);
int
sdei_event_complete
(
int
resume
,
uint64_t
arg
);
void
sdei_pe_unmask
(
void
);
unsigned
int
sdei_pe_mask
(
void
);
int
sdei_intr_handler
(
uint32_t
intr
,
uint32_t
flags
,
void
*
handle
,
void
*
cookie
);
bool
can_sdei_state_trans
(
sdei_entry_t
*
se
,
sdei_action_t
act
);
#endif
/* __SDEI_PRIVATE_H__ */
This diff is collapsed.
Click to expand it.
services/std_svc/sdei/sdei_state.c
0 → 100644
View file @
c195f1a7
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <cassert.h>
#include <stdbool.h>
#include "sdei_private.h"
/* Aliases for SDEI handler states: 'R'unning, 'E'nabled, and re'G'istered */
#define r_ 0
#define R_ (1u << SDEI_STATF_RUNNING)
#define e_ 0
#define E_ (1u << SDEI_STATF_ENABLED)
#define g_ 0
#define G_ (1u << SDEI_STATF_REGISTERED)
/* All possible composite handler states */
#define reg_ (r_ | e_ | g_)
#define reG_ (r_ | e_ | G_)
#define rEg_ (r_ | E_ | g_)
#define rEG_ (r_ | E_ | G_)
#define Reg_ (R_ | e_ | g_)
#define ReG_ (R_ | e_ | G_)
#define REg_ (R_ | E_ | g_)
#define REG_ (R_ | E_ | G_)
#define MAX_STATES (REG_ + 1)
/* Invalid state */
#define SDEI_STATE_INVALID ((sdei_state_t) (-1))
/* No change in state */
#define SDEI_STATE_NOP ((sdei_state_t) (-2))
#define X___ SDEI_STATE_INVALID
#define NOP_ SDEI_STATE_NOP
/* Ensure special states don't overlap with valid ones */
CASSERT
(
X___
>
REG_
,
sdei_state_overlap_invalid
);
CASSERT
(
NOP_
>
REG_
,
sdei_state_overlap_nop
);
/*
* SDEI handler state machine: refer to sections 6.1 and 6.1.2 of the SDEI v1.0
* specification:
*
* http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
*
* Not all calls contribute to handler state transition. This table is also used
* to validate whether a call is permissible at a given handler state:
*
* - X___ denotes a forbidden transition;
* - NOP_ denotes a permitted transition, but there's no change in state;
* - Otherwise, XXX_ gives the new state.
*
* DISP[atch] is a transition added for the implementation, but is not mentioned
* in the spec.
*
* Those calls that the spec mentions as can be made any time don't picture in
* this table.
*/
static
const
sdei_state_t
sdei_state_table
[
MAX_STATES
][
DO_MAX
]
=
{
/*
* Action: REG REL ENA DISA UREG ROUT CTX COMP COMPR DISP
* Notes: [3] [1] [3] [3][4] [2]
*/
/* Handler unregistered, disabled, and not running. This is the default state. */
/* 0 */
[
reg_
]
=
{
reG_
,
NOP_
,
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
},
/* Handler unregistered and running */
/* 4 */
[
Reg_
]
=
{
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
NOP_
,
reg_
,
reg_
,
X___
,
},
/* Handler registered */
/* 1 */
[
reG_
]
=
{
X___
,
X___
,
rEG_
,
NOP_
,
reg_
,
NOP_
,
X___
,
X___
,
X___
,
X___
,
},
/* Handler registered and running */
/* 5 */
[
ReG_
]
=
{
X___
,
X___
,
REG_
,
NOP_
,
Reg_
,
X___
,
NOP_
,
reG_
,
reG_
,
X___
,
},
/* Handler registered and enabled */
/* 3 */
[
rEG_
]
=
{
X___
,
X___
,
NOP_
,
reG_
,
reg_
,
X___
,
X___
,
X___
,
X___
,
REG_
,
},
/* Handler registered, enabled, and running */
/* 7 */
[
REG_
]
=
{
X___
,
X___
,
NOP_
,
ReG_
,
Reg_
,
X___
,
NOP_
,
rEG_
,
rEG_
,
X___
,
},
/*
* Invalid states: no valid transition would leave the handler in these
* states; and no transition from these states is possible either.
*/
/*
* Handler can't be enabled without being registered. I.e., XEg is
* impossible.
*/
/* 2 */
[
rEg_
]
=
{
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
},
/* 6 */
[
REg_
]
=
{
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
X___
,
},
};
/*
* [1] Unregister will always also disable the event, so the new state will have
* Xeg.
* [2] Event is considered for dispatch only when it's both registered and
* enabled.
* [3] Never causes change in state.
* [4] Only allowed when running.
*/
/*
* Given an action, transition the state of an event by looking up the state
* table above:
*
* - Return false for invalid transition;
* - Return true for valid transition that causes no change in state;
* - Otherwise, update state and return true.
*
* This function assumes that the caller holds necessary locks. If the
* transition has constrains other than the state table describes, the caller is
* expected to restore the previous state. See sdei_event_register() for
* example.
*/
bool
can_sdei_state_trans
(
sdei_entry_t
*
se
,
sdei_action_t
act
)
{
sdei_state_t
next
;
assert
(
act
<
DO_MAX
);
if
(
se
->
state
>=
MAX_STATES
)
{
WARN
(
" event state invalid: %x
\n
"
,
se
->
state
);
return
false
;
}
next
=
sdei_state_table
[
se
->
state
][
act
];
switch
(
next
)
{
case
SDEI_STATE_INVALID
:
return
false
;
case
SDEI_STATE_NOP
:
return
true
;
default:
/* Valid transition. Update state. */
SDEI_LOG
(
" event state 0x%x => 0x%x
\n
"
,
se
->
state
,
next
);
se
->
state
=
next
;
return
true
;
}
}
This diff is collapsed.
Click to expand it.
services/std_svc/std_svc_setup.c
View file @
c195f1a7
...
...
@@ -11,6 +11,7 @@
#include <psci.h>
#include <runtime_instr.h>
#include <runtime_svc.h>
#include <sdei.h>
#include <smcc_helpers.h>
#include <spm_svc.h>
#include <std_svc.h>
...
...
@@ -45,6 +46,11 @@ static int32_t std_svc_setup(void)
}
#endif
#if SDEI_SUPPORT
/* SDEI initialisation */
sdei_init
();
#endif
return
ret
;
}
...
...
@@ -92,7 +98,6 @@ uintptr_t std_svc_smc_handler(uint32_t smc_fid,
SMC_RET1
(
handle
,
ret
);
}
#if ENABLE_SPM
/*
* Dispatch SPM calls to SPM SMC handler and return its return
...
...
@@ -104,6 +109,13 @@ uintptr_t std_svc_smc_handler(uint32_t smc_fid,
}
#endif
#if SDEI_SUPPORT
if
(
is_sdei_fid
(
smc_fid
))
{
return
sdei_smc_handler
(
smc_fid
,
x1
,
x2
,
x3
,
x4
,
cookie
,
handle
,
flags
);
}
#endif
switch
(
smc_fid
)
{
case
ARM_STD_SVC_CALL_COUNT
:
/*
...
...
This diff is collapsed.
Click to expand it.
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
Menu
Projects
Groups
Snippets
Help