diff --git a/Makefile b/Makefile index 9972362..2f53cdf 100644 --- a/Makefile +++ b/Makefile @@ -651,6 +651,12 @@ endif endif +# SDEI_IN_FCONF is only supported when SDEI_SUPPORT is enabled. +ifeq ($(SDEI_SUPPORT)-$(SDEI_IN_FCONF),0-1) +$(error "SDEI_IN_FCONF is an experimental feature and is only supported when \ + SDEI_SUPPORT is enabled") +endif + # If pointer authentication is used in the firmware, make sure that all the # registers associated to it are also saved and restored. # Not doing it would leak the value of the keys used by EL3 to EL1 and S-EL1. @@ -882,6 +888,7 @@ $(eval $(call assert_boolean,USE_COHERENT_MEM)) $(eval $(call assert_boolean,USE_DEBUGFS)) $(eval $(call assert_boolean,ARM_IO_IN_DTB)) +$(eval $(call assert_boolean,SDEI_IN_FCONF)) $(eval $(call assert_boolean,USE_ROMLIB)) $(eval $(call assert_boolean,USE_TBBR_DEFS)) $(eval $(call assert_boolean,WARMBOOT_ENABLE_DCACHE_EARLY)) @@ -961,6 +968,7 @@ $(eval $(call add_define,USE_COHERENT_MEM)) $(eval $(call add_define,USE_DEBUGFS)) $(eval $(call add_define,ARM_IO_IN_DTB)) +$(eval $(call add_define,SDEI_IN_FCONF)) $(eval $(call add_define,USE_ROMLIB)) $(eval $(call add_define,USE_TBBR_DEFS)) $(eval $(call add_define,WARMBOOT_ENABLE_DCACHE_EARLY)) diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst index 6f3b605..c863079 100644 --- a/docs/getting_started/build-options.rst +++ b/docs/getting_started/build-options.rst @@ -645,6 +645,11 @@ configuration device tree, instead of static structure in the code base. This is currently an experimental feature. +- ``SDEI_IN_FCONF``: This flag determines whether to configure SDEI setup in + runtime using firmware configuration framework. The platform specific SDEI + shared and private events configuration is retrieved from device tree rather + than static C structures at compile time. This is currently an experimental + feature and is only supported if SDEI_SUPPORT build flag is enabled. - ``USE_ROMLIB``: This flag determines whether library at ROM will be used. This feature creates a library of functions to be placed in ROM and thus diff --git a/fdts/fvp-base-gicv3-psci-common.dtsi b/fdts/fvp-base-gicv3-psci-common.dtsi index fb73f60..4a7b656 100644 --- a/fdts/fvp-base-gicv3-psci-common.dtsi +++ b/fdts/fvp-base-gicv3-psci-common.dtsi @@ -4,6 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include + /memreserve/ 0x80000000 0x00010000; / { @@ -36,6 +38,30 @@ max-pwr-lvl = <2>; }; +#if SDEI_IN_FCONF + firmware { + sdei { + compatible = "arm,sdei-1.0"; + method = "smc"; + private_event_count = <3>; + shared_event_count = <3>; + /* + * Each event descriptor has typically 3 fields: + * 1. Event number + * 2. Interrupt number the event is bound to or + * if event is dynamic, specified as SDEI_DYN_IRQ + * 3. Bit map of event flags + */ + private_events = <1000 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>, + <1001 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>, + <1002 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>; + shared_events = <2000 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>, + <2001 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>, + <2002 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>; + }; + }; +#endif /* SDEI_IN_FCONF */ + cpus { #address-cells = <2>; #size-cells = <0>; diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h index 7c852e1..89f7c61 100644 --- a/include/plat/arm/common/arm_def.h +++ b/include/plat/arm/common/arm_def.h @@ -565,6 +565,13 @@ /* SGI used for SDEI signalling */ #define ARM_SDEI_SGI ARM_IRQ_SEC_SGI_0 +#if SDEI_IN_FCONF +/* ARM SDEI dynamic private event max count */ +#define ARM_SDEI_DP_EVENT_MAX_CNT 3 + +/* ARM SDEI dynamic shared event max count */ +#define ARM_SDEI_DS_EVENT_MAX_CNT 3 +#else /* ARM SDEI dynamic private event numbers */ #define ARM_SDEI_DP_EVENT_0 1000 #define ARM_SDEI_DP_EVENT_1 1001 @@ -585,5 +592,6 @@ SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), \ SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), \ SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC) +#endif /* SDEI_IN_FCONF */ #endif /* ARM_DEF_H */ diff --git a/include/plat/arm/common/fconf_sdei_getter.h b/include/plat/arm/common/fconf_sdei_getter.h new file mode 100644 index 0000000..e0a97a6 --- /dev/null +++ b/include/plat/arm/common/fconf_sdei_getter.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef FCONF_SDEI_GETTER_H +#define FCONF_SDEI_GETTER_H + +#include + +#include + +#define sdei__dyn_config_getter(id) sdei_dyn_config.id + +struct sdei_dyn_config_t { + uint32_t private_ev_cnt; + int32_t private_ev_nums[PLAT_SDEI_DP_EVENT_MAX_CNT]; + unsigned int private_ev_intrs[PLAT_SDEI_DP_EVENT_MAX_CNT]; + unsigned int private_ev_flags[PLAT_SDEI_DP_EVENT_MAX_CNT]; + uint32_t shared_ev_cnt; + int32_t shared_ev_nums[PLAT_SDEI_DS_EVENT_MAX_CNT]; + unsigned int shared_ev_intrs[PLAT_SDEI_DS_EVENT_MAX_CNT]; + unsigned int shared_ev_flags[PLAT_SDEI_DS_EVENT_MAX_CNT]; +}; + +int fconf_populate_sdei_dyn_config(uintptr_t config); + +extern struct sdei_dyn_config_t sdei_dyn_config; + +#endif /* FCONF_SDEI_GETTER_H */ diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index b8ba14c..720c259 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -132,6 +132,7 @@ /* SDEI platform functions */ #if SDEI_SUPPORT +void plat_sdei_setup(void); int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode); void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr); #endif diff --git a/include/services/sdei.h b/include/services/sdei.h index ae8c7e4..063ed6f 100644 --- a/include/services/sdei.h +++ b/include/services/sdei.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -9,6 +9,7 @@ #include #include +#include /* Range 0xC4000020 - 0xC400003F reserved for SDE 64bit smc calls */ #define SDEI_VERSION 0xC4000020U @@ -41,50 +42,6 @@ #define SDEI_EV_HANDLED 0U #define SDEI_EV_FAILED 1U -/* Internal: SDEI flag bit positions */ -#define SDEI_MAPF_DYNAMIC_SHIFT_ 1U -#define SDEI_MAPF_BOUND_SHIFT_ 2U -#define SDEI_MAPF_SIGNALABLE_SHIFT_ 3U -#define SDEI_MAPF_PRIVATE_SHIFT_ 4U -#define SDEI_MAPF_CRITICAL_SHIFT_ 5U -#define SDEI_MAPF_EXPLICIT_SHIFT_ 6U - -/* SDEI event 0 */ -#define SDEI_EVENT_0 0 - -/* Placeholder interrupt for dynamic mapping */ -#define SDEI_DYN_IRQ 0U - -/* SDEI flags */ - -/* - * These flags determine whether or not an event can be associated with an - * interrupt. Static events are permanently associated with an interrupt, and - * can't be changed at runtime. Association of dynamic events with interrupts - * can be changed at run time using the SDEI_INTERRUPT_BIND and - * SDEI_INTERRUPT_RELEASE calls. - * - * SDEI_MAPF_DYNAMIC only indicates run time configurability, where as - * SDEI_MAPF_BOUND indicates interrupt association. For example: - * - * - Calling SDEI_INTERRUPT_BIND on a dynamic event will have both - * SDEI_MAPF_DYNAMIC and SDEI_MAPF_BOUND set. - * - * - Statically-bound events will always have SDEI_MAPF_BOUND set, and neither - * SDEI_INTERRUPT_BIND nor SDEI_INTERRUPT_RELEASE can be called on them. - * - * See also the is_map_bound() macro. - */ -#define SDEI_MAPF_DYNAMIC BIT(SDEI_MAPF_DYNAMIC_SHIFT_) -#define SDEI_MAPF_BOUND BIT(SDEI_MAPF_BOUND_SHIFT_) -#define SDEI_MAPF_EXPLICIT BIT(SDEI_MAPF_EXPLICIT_SHIFT_) - -#define SDEI_MAPF_SIGNALABLE BIT(SDEI_MAPF_SIGNALABLE_SHIFT_) -#define SDEI_MAPF_PRIVATE BIT(SDEI_MAPF_PRIVATE_SHIFT_) - -#define SDEI_MAPF_NORMAL 0 -#define SDEI_MAPF_CRITICAL BIT(SDEI_MAPF_CRITICAL_SHIFT_) - /* Indices of private and shared mappings */ #define SDEI_MAP_IDX_PRIV_ 0U #define SDEI_MAP_IDX_SHRD_ 1U diff --git a/include/services/sdei_flags.h b/include/services/sdei_flags.h new file mode 100644 index 0000000..d1308f8 --- /dev/null +++ b/include/services/sdei_flags.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SDEI_FLAGS_H +#define SDEI_FLAGS_H + +#include + +/* Internal: SDEI flag bit positions */ +#define SDEI_MAPF_DYNAMIC_SHIFT_ 1U +#define SDEI_MAPF_BOUND_SHIFT_ 2U +#define SDEI_MAPF_SIGNALABLE_SHIFT_ 3U +#define SDEI_MAPF_PRIVATE_SHIFT_ 4U +#define SDEI_MAPF_CRITICAL_SHIFT_ 5U +#define SDEI_MAPF_EXPLICIT_SHIFT_ 6U + +/* SDEI event 0 */ +#define SDEI_EVENT_0 0 + +/* Placeholder interrupt for dynamic mapping */ +#define SDEI_DYN_IRQ 0U + +/* SDEI flags */ + +/* + * These flags determine whether or not an event can be associated with an + * interrupt. Static events are permanently associated with an interrupt, and + * can't be changed at runtime. Association of dynamic events with interrupts + * can be changed at run time using the SDEI_INTERRUPT_BIND and + * SDEI_INTERRUPT_RELEASE calls. + * + * SDEI_MAPF_DYNAMIC only indicates run time configurability, where as + * SDEI_MAPF_BOUND indicates interrupt association. For example: + * + * - Calling SDEI_INTERRUPT_BIND on a dynamic event will have both + * SDEI_MAPF_DYNAMIC and SDEI_MAPF_BOUND set. + * + * - Statically-bound events will always have SDEI_MAPF_BOUND set, and neither + * SDEI_INTERRUPT_BIND nor SDEI_INTERRUPT_RELEASE can be called on them. + * + * See also the is_map_bound() macro. + */ +#define SDEI_MAPF_DYNAMIC BIT(SDEI_MAPF_DYNAMIC_SHIFT_) +#define SDEI_MAPF_BOUND BIT(SDEI_MAPF_BOUND_SHIFT_) +#define SDEI_MAPF_EXPLICIT BIT(SDEI_MAPF_EXPLICIT_SHIFT_) + +#define SDEI_MAPF_SIGNALABLE BIT(SDEI_MAPF_SIGNALABLE_SHIFT_) +#define SDEI_MAPF_PRIVATE BIT(SDEI_MAPF_PRIVATE_SHIFT_) + +#define SDEI_MAPF_NORMAL 0 +#define SDEI_MAPF_CRITICAL BIT(SDEI_MAPF_CRITICAL_SHIFT_) + +#endif /* SDEI_FLAGS_H */ diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 608e963..e5880d2 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -223,7 +223,10 @@ USE_DEBUGFS := 0 # Build option to fconf based io -ARM_IO_IN_DTB := 0 +ARM_IO_IN_DTB := 0 + +# Build option to support SDEI through fconf +SDEI_IN_FCONF :=0 # Build option to choose whether Trusted Firmware uses library at ROM USE_ROMLIB := 0 diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h index 1ed3074..62ede9a 100644 --- a/plat/arm/board/fvp/include/platform_def.h +++ b/plat/arm/board/fvp/include/platform_def.h @@ -264,8 +264,13 @@ #define PLAT_ARM_G0_IRQ_PROPS(grp) ARM_G0_IRQ_PROPS(grp) +#if SDEI_IN_FCONF +#define PLAT_SDEI_DP_EVENT_MAX_CNT ARM_SDEI_DP_EVENT_MAX_CNT +#define PLAT_SDEI_DS_EVENT_MAX_CNT ARM_SDEI_DS_EVENT_MAX_CNT +#else #define PLAT_ARM_PRIVATE_SDEI_EVENTS ARM_SDEI_PRIVATE_EVENTS #define PLAT_ARM_SHARED_SDEI_EVENTS ARM_SDEI_SHARED_EVENTS +#endif #define PLAT_ARM_SP_IMAGE_STACK_BASE (PLAT_SP_IMAGE_NS_BUF_BASE + \ PLAT_SP_IMAGE_NS_BUF_SIZE) diff --git a/plat/arm/common/aarch64/arm_sdei.c b/plat/arm/common/aarch64/arm_sdei.c index 493134b..3c74a46 100644 --- a/plat/arm/common/aarch64/arm_sdei.c +++ b/plat/arm/common/aarch64/arm_sdei.c @@ -1,16 +1,51 @@ /* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* SDEI configuration for ARM platforms */ -#include - #include +#include #include +#if SDEI_IN_FCONF +#include +#endif +#include +#include + + +#if SDEI_IN_FCONF +/* Private event mappings */ +static sdei_ev_map_t arm_sdei_private[PLAT_SDEI_DP_EVENT_MAX_CNT + 1] = { 0 }; + +/* Shared event mappings */ +static sdei_ev_map_t arm_sdei_shared[PLAT_SDEI_DS_EVENT_MAX_CNT] = { 0 }; + +void plat_sdei_setup(void) +{ + uint32_t i; + + arm_sdei_private[0] = (sdei_ev_map_t)SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI); + + for (i = 0; i < FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_cnt); i++) { + arm_sdei_private[i + 1] = (sdei_ev_map_t)SDEI_PRIVATE_EVENT( + FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_nums[i]), + FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_intrs[i]), + FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_flags[i])); + } + + for (i = 0; i < FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_cnt); i++) { + arm_sdei_shared[i] = (sdei_ev_map_t)SDEI_SHARED_EVENT( \ + FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_nums[i]), + FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_intrs[i]), + FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_flags[i])); + } + INFO("FCONF: SDEI platform setup\n"); +} +#else /* Private event mappings */ static sdei_ev_map_t arm_sdei_private[] = { PLAT_ARM_PRIVATE_SDEI_EVENTS @@ -21,5 +56,11 @@ PLAT_ARM_SHARED_SDEI_EVENTS }; +void plat_sdei_setup(void) +{ + INFO("SDEI platform setup\n"); +} +#endif /* SDEI_IN_FCONF */ + /* Export ARM SDEI events */ REGISTER_SDEI_MAP(arm_sdei_private, arm_sdei_shared); diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk index 3b0c39d..387c131 100644 --- a/plat/arm/common/arm_common.mk +++ b/plat/arm/common/arm_common.mk @@ -263,6 +263,9 @@ ifeq (${SDEI_SUPPORT},1) BL31_SOURCES += plat/arm/common/aarch64/arm_sdei.c +ifeq (${SDEI_IN_FCONF},1) +BL31_SOURCES += plat/arm/common/fconf/fconf_sdei_getter.c +endif endif # RAS sources diff --git a/plat/arm/common/fconf/fconf_sdei_getter.c b/plat/arm/common/fconf/fconf_sdei_getter.c new file mode 100644 index 0000000..c26e316 --- /dev/null +++ b/plat/arm/common/fconf/fconf_sdei_getter.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include + +#include +#include +#include +#include + +#define PRIVATE_EVENT_NUM(i) private_events[3 * (i)] +#define PRIVATE_EVENT_INTR(i) private_events[3 * (i) + 1] +#define PRIVATE_EVENT_FLAGS(i) private_events[3 * (i) + 2] + +#define SHARED_EVENT_NUM(i) shared_events[3 * (i)] +#define SHARED_EVENT_INTR(i) shared_events[3 * (i) + 1] +#define SHARED_EVENT_FLAGS(i) shared_events[3 * (i) + 2] + +struct sdei_dyn_config_t sdei_dyn_config; + +int fconf_populate_sdei_dyn_config(uintptr_t config) +{ + uint32_t i; + int node, err; + uint32_t private_events[PLAT_SDEI_DP_EVENT_MAX_CNT * 3]; + uint32_t shared_events[PLAT_SDEI_DS_EVENT_MAX_CNT * 3]; + + const void *dtb = (void *)config; + + /* Check that the node offset points to compatible property */ + node = fdt_node_offset_by_compatible(dtb, -1, "arm,sdei-1.0"); + if (node < 0) { + ERROR("FCONF: Can't find 'arm,sdei-1.0' compatible node in dtb\n"); + return node; + } + + /* Read number of private mappings */ + err = fdt_read_uint32(dtb, node, "private_event_count", + &sdei_dyn_config.private_ev_cnt); + if (err < 0) { + ERROR("FCONF: Read cell failed for 'private_event_count': %u\n", + sdei_dyn_config.private_ev_cnt); + return err; + } + + /* Check if the value is in range */ + if (sdei_dyn_config.private_ev_cnt > PLAT_SDEI_DP_EVENT_MAX_CNT) { + ERROR("FCONF: Invalid value for 'private_event_count': %u\n", + sdei_dyn_config.private_ev_cnt); + return -1; + } + + /* Read private mappings */ + err = fdt_read_uint32_array(dtb, node, "private_events", + sdei_dyn_config.private_ev_cnt * 3, private_events); + if (err < 0) { + ERROR("FCONF: Read cell failed for 'private_events': %d\n", err); + return err; + } + + /* Move data to fconf struct */ + for (i = 0; i < sdei_dyn_config.private_ev_cnt; i++) { + sdei_dyn_config.private_ev_nums[i] = PRIVATE_EVENT_NUM(i); + sdei_dyn_config.private_ev_intrs[i] = PRIVATE_EVENT_INTR(i); + sdei_dyn_config.private_ev_flags[i] = PRIVATE_EVENT_FLAGS(i); + } + + /* Read number of shared mappings */ + err = fdt_read_uint32(dtb, node, "shared_event_count", + &sdei_dyn_config.shared_ev_cnt); + if (err < 0) { + ERROR("FCONF: Read cell failed for 'shared_event_count'\n"); + return err; + } + + /* Check if the value is in range */ + if (sdei_dyn_config.shared_ev_cnt > PLAT_SDEI_DS_EVENT_MAX_CNT) { + ERROR("FCONF: Invalid value for 'shared_event_count': %u\n", + sdei_dyn_config.shared_ev_cnt); + return -1; + } + + /* Read shared mappings */ + err = fdt_read_uint32_array(dtb, node, "shared_events", + sdei_dyn_config.shared_ev_cnt * 3, shared_events); + if (err < 0) { + ERROR("FCONF: Read cell failed for 'shared_events': %d\n", err); + return err; + } + + /* Move data to fconf struct */ + for (i = 0; i < sdei_dyn_config.shared_ev_cnt; i++) { + sdei_dyn_config.shared_ev_nums[i] = SHARED_EVENT_NUM(i); + sdei_dyn_config.shared_ev_intrs[i] = SHARED_EVENT_INTR(i); + sdei_dyn_config.shared_ev_flags[i] = SHARED_EVENT_FLAGS(i); + } + + return 0; +} + +FCONF_REGISTER_POPULATOR(HW_CONFIG, sdei, fconf_populate_sdei_dyn_config); diff --git a/services/std_svc/sdei/sdei_main.c b/services/std_svc/sdei/sdei_main.c index 0424177..dba5e07 100644 --- a/services/std_svc/sdei/sdei_main.c +++ b/services/std_svc/sdei/sdei_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -226,6 +226,7 @@ /* SDEI dispatcher initialisation */ void sdei_init(void) { + plat_sdei_setup(); sdei_class_init(SDEI_CRITICAL); sdei_class_init(SDEI_NORMAL); @@ -328,8 +329,11 @@ } /* Register handler and argument for an SDEI event */ -static int64_t sdei_event_register(int ev_num, uint64_t ep, uint64_t arg, - uint64_t flags, uint64_t mpidr) +static int64_t sdei_event_register(int ev_num, + uint64_t ep, + uint64_t arg, + uint64_t flags, + uint64_t mpidr) { int ret; unsigned int routing;