diff --git a/Makefile b/Makefile index 2f53cdf..7627797 100644 --- a/Makefile +++ b/Makefile @@ -889,6 +889,7 @@ $(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,SEC_INT_DESC_IN_FCONF)) $(eval $(call assert_boolean,USE_ROMLIB)) $(eval $(call assert_boolean,USE_TBBR_DEFS)) $(eval $(call assert_boolean,WARMBOOT_ENABLE_DCACHE_EARLY)) @@ -969,6 +970,7 @@ $(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,SEC_INT_DESC_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 c863079..7ca1067 100644 --- a/docs/getting_started/build-options.rst +++ b/docs/getting_started/build-options.rst @@ -651,6 +651,12 @@ than static C structures at compile time. This is currently an experimental feature and is only supported if SDEI_SUPPORT build flag is enabled. +- ``SEC_INT_DESC_IN_FCONF``: This flag determines whether to configure Group 0 + and Group1 secure interrupts using the firmware configuration framework. The + platform specific secure interrupt property descriptor is retrieved from + device tree in runtime rather than depending on static C structure at compile + time. This is currently an experimental feature. + - ``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 reduces SRAM usage. Refer to :ref:`Library at ROM` for further details. Default diff --git a/fdts/fvp-base-gicv3-psci-common.dtsi b/fdts/fvp-base-gicv3-psci-common.dtsi index 0deb8a2..192f574 100644 --- a/fdts/fvp-base-gicv3-psci-common.dtsi +++ b/fdts/fvp-base-gicv3-psci-common.dtsi @@ -6,6 +6,11 @@ #include +#define LEVEL 0 +#define EDGE 2 +#define SDEI_NORMAL 0x70 +#define HIGHEST_SEC 0 + /memreserve/ 0x80000000 0x00010000; / { @@ -38,8 +43,9 @@ max-pwr-lvl = <2>; }; -#if SDEI_IN_FCONF +#if SDEI_IN_FCONF || SEC_INT_DESC_IN_FCONF firmware { +#if SDEI_IN_FCONF sdei { compatible = "arm,sdei-1.0"; method = "smc"; @@ -59,9 +65,38 @@ <2001 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>, <2002 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>; }; - }; #endif /* SDEI_IN_FCONF */ +#if SEC_INT_DESC_IN_FCONF + sec_interrupts { + compatible = "arm,secure_interrupt_desc"; + /* Number of G0 and G1 secure interrupts defined by the platform */ + g0_intr_cnt = <2>; + g1s_intr_cnt = <9>; + /* + * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 + * terminology. Each interrupt property descriptor has 3 fields: + * 1. Interrupt number + * 2. Interrupt priority + * 3. Type of interrupt (Edge or Level configured) + */ + g0_intr_desc = < 8 SDEI_NORMAL EDGE>, + <14 HIGHEST_SEC EDGE>; + + g1s_intr_desc = < 9 HIGHEST_SEC EDGE>, + <10 HIGHEST_SEC EDGE>, + <11 HIGHEST_SEC EDGE>, + <12 HIGHEST_SEC EDGE>, + <13 HIGHEST_SEC EDGE>, + <15 HIGHEST_SEC EDGE>, + <29 HIGHEST_SEC LEVEL>, + <56 HIGHEST_SEC LEVEL>, + <57 HIGHEST_SEC LEVEL>; + }; +#endif /* SEC_INT_DESC_IN_FCONF */ + }; +#endif /* SDEI_IN_FCONF || SEC_INT_DESC_IN_FCONF */ + cpus { #address-cells = <2>; #size-cells = <0>; diff --git a/include/plat/arm/common/fconf_sec_intr_config.h b/include/plat/arm/common/fconf_sec_intr_config.h new file mode 100644 index 0000000..5d6b594 --- /dev/null +++ b/include/plat/arm/common/fconf_sec_intr_config.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef FCONF_SEC_INTR_CONFIG_H +#define FCONF_SEC_INTR_CONFIG_H + +#include + +#include + +#define hw_config__sec_intr_prop_getter(id) sec_intr_prop.id + +#define SEC_INT_COUNT_MAX U(15) + +struct sec_intr_prop_t { + interrupt_prop_t descriptor[SEC_INT_COUNT_MAX]; + uint32_t count; +}; + +int fconf_populate_sec_intr_config(uintptr_t config); + +extern struct sec_intr_prop_t sec_intr_prop; + +#endif /* FCONF_SEC_INTR_CONFIG_H */ diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index e5880d2..585f06f 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -226,7 +226,10 @@ ARM_IO_IN_DTB := 0 # Build option to support SDEI through fconf -SDEI_IN_FCONF :=0 +SDEI_IN_FCONF := 0 + +# Build option to support Secure Interrupt descriptors through fconf +SEC_INT_DESC_IN_FCONF := 0 # Build option to choose whether Trusted Firmware uses library at ROM USE_ROMLIB := 0 diff --git a/plat/arm/board/fvp/fvp_gicv3.c b/plat/arm/board/fvp/fvp_gicv3.c index a3ee8ef..3e04d6b 100644 --- a/plat/arm/board/fvp/fvp_gicv3.c +++ b/plat/arm/board/fvp/fvp_gicv3.c @@ -12,6 +12,7 @@ #include #include #include +#include #include /* The GICv3 driver only needs to be initialized in EL3 */ @@ -23,10 +24,13 @@ /* List of zero terminated GICR frame addresses which CPUs will probe */ static uint64_t *fvp_gicr_frames = fvp_gicr_base_addrs; +#if !(SEC_INT_DESC_IN_FCONF && ((!defined(__aarch64__) && defined(IMAGE_BL32)) || \ + (defined(__aarch64__) && defined(IMAGE_BL31)))) static const interrupt_prop_t fvp_interrupt_props[] = { PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S), PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0) }; +#endif /* * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register @@ -52,8 +56,6 @@ static gicv3_driver_data_t fvp_gic_data = { - .interrupt_props = fvp_interrupt_props, - .interrupt_props_num = ARRAY_SIZE(fvp_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = fvp_rdistif_base_addrs, .mpidr_to_core_pos = fvp_gicv3_mpidr_hash @@ -61,7 +63,10 @@ void plat_arm_gic_driver_init(void) { - /* Get GICD and GICR base addressed through FCONF APIs */ + /* + * Get GICD and GICR base addressed through FCONF APIs. + * FCONF is not supported in BL32 for FVP. + */ #if (!defined(__aarch64__) && defined(IMAGE_BL32)) || \ (defined(__aarch64__) && defined(IMAGE_BL31)) fvp_gic_data.gicd_base = (uintptr_t)FCONF_GET_PROPERTY(hw_config, @@ -69,9 +74,20 @@ gicd_base); fvp_gicr_base_addrs[0] = FCONF_GET_PROPERTY(hw_config, gicv3_config, gicr_base); +#if SEC_INT_DESC_IN_FCONF + fvp_gic_data.interrupt_props = FCONF_GET_PROPERTY(hw_config, + sec_intr_prop, descriptor); + fvp_gic_data.interrupt_props_num = FCONF_GET_PROPERTY(hw_config, + sec_intr_prop, count); +#else + fvp_gic_data.interrupt_props = fvp_interrupt_props; + fvp_gic_data.interrupt_props_num = ARRAY_SIZE(fvp_interrupt_props); +#endif #else fvp_gic_data.gicd_base = PLAT_ARM_GICD_BASE; fvp_gicr_base_addrs[0] = PLAT_ARM_GICR_BASE; + fvp_gic_data.interrupt_props = fvp_interrupt_props; + fvp_gic_data.interrupt_props_num = ARRAY_SIZE(fvp_interrupt_props); #endif /* diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index 024e682..e605608 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -221,6 +221,11 @@ BL31_SOURCES += common/fdt_wrappers.c \ lib/fconf/fconf.c \ plat/arm/board/fvp/fconf/fconf_hw_config_getter.c + +ifeq (${SEC_INT_DESC_IN_FCONF},1) +BL31_SOURCES += plat/arm/common/fconf/fconf_sec_intr_config.c +endif + endif ifeq (${FVP_USE_SP804_TIMER},1) diff --git a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk index ba6ceec..64cb7ad 100644 --- a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk +++ b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk @@ -25,6 +25,11 @@ BL32_SOURCES += common/fdt_wrappers.c \ lib/fconf/fconf.c \ plat/arm/board/fvp/fconf/fconf_hw_config_getter.c + +ifeq (${SEC_INT_DESC_IN_FCONF},1) +BL32_SOURCES += plat/arm/common/fconf/fconf_sec_intr_config.c +endif + endif include plat/arm/common/sp_min/arm_sp_min.mk diff --git a/plat/arm/common/fconf/fconf_sec_intr_config.c b/plat/arm/common/fconf/fconf_sec_intr_config.c new file mode 100644 index 0000000..f28be24 --- /dev/null +++ b/plat/arm/common/fconf/fconf_sec_intr_config.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include + +#include +#include +#include +#include + +#define G0_INTR_NUM(i) g0_intr_prop[3U * (i)] +#define G0_INTR_PRIORITY(i) g0_intr_prop[3U * (i) + 1] +#define G0_INTR_CONFIG(i) g0_intr_prop[3U * (i) + 2] + +#define G1S_INTR_NUM(i) g1s_intr_prop[3U * (i)] +#define G1S_INTR_PRIORITY(i) g1s_intr_prop[3U * (i) + 1] +#define G1S_INTR_CONFIG(i) g1s_intr_prop[3U * (i) + 2] + +struct sec_intr_prop_t sec_intr_prop; + +static void print_intr_prop(interrupt_prop_t prop) +{ + VERBOSE("FCONF: Secure Interrupt NUM: %d, PRI: %d, TYPE: %d\n", + prop.intr_num, prop.intr_pri, prop.intr_cfg); +} + +int fconf_populate_sec_intr_config(uintptr_t config) +{ + int node, err; + uint32_t g0_intr_count, g1s_intr_count; + uint32_t g0_intr_prop[SEC_INT_COUNT_MAX * 3]; + uint32_t g1s_intr_prop[SEC_INT_COUNT_MAX * 3]; + + /* Necessary to work with libfdt APIs */ + const void *hw_config_dtb = (const void *)config; + + node = fdt_node_offset_by_compatible(hw_config_dtb, -1, + "arm,secure_interrupt_desc"); + if (node < 0) { + ERROR("FCONF: Unable to locate node with %s compatible property\n", + "arm,secure_interrupt_desc"); + return node; + } + + /* Read number of Group 0 interrupts specified by platform */ + err = fdt_read_uint32(hw_config_dtb, node, "g0_intr_cnt", &g0_intr_count); + if (err < 0) { + ERROR("FCONF: Could not locate g0s_intr_cnt property\n"); + return err; + } + + /* At least 1 Group 0 interrupt description has to be provided*/ + if (g0_intr_count < 1U) { + ERROR("FCONF: Invalid number of Group 0 interrupts count specified\n"); + return -1; + } + + /* Read number of Group 1 secure interrupts specified by platform */ + err = fdt_read_uint32(hw_config_dtb, node, "g1s_intr_cnt", + &g1s_intr_count); + if (err < 0) { + ERROR("FCONF: Could not locate g1s_intr_cnt property\n"); + return err; + } + + /* At least one Group 1 interrupt description has to be provided*/ + if (g1s_intr_count < 1U) { + ERROR("FCONF: Invalid number of Group 1 secure interrupts count specified\n"); + return -1; + } + + /* + * Check if the total number of secure interrupts described are within + * the limit defined statically by the platform. + */ + if ((g0_intr_count + g1s_intr_count) > SEC_INT_COUNT_MAX) { + ERROR("FCONF: Total number of secure interrupts exceed limit the of %d\n", + SEC_INT_COUNT_MAX); + return -1; + } + + sec_intr_prop.count = g0_intr_count + g1s_intr_count; + + /* Read the Group 0 interrupt descriptors */ + err = fdt_read_uint32_array(hw_config_dtb, node, "g0_intr_desc", + g0_intr_count * 3, g0_intr_prop); + if (err < 0) { + ERROR("FCONF: Read cell failed for 'g0s_intr_desc': %d\n", err); + return err; + } + + /* Read the Group 1 secure interrupt descriptors */ + err = fdt_read_uint32_array(hw_config_dtb, node, "g1s_intr_desc", + g1s_intr_count * 3, g1s_intr_prop); + if (err < 0) { + ERROR("FCONF: Read cell failed for 'g1s_intr_desc': %d\n", err); + return err; + } + + /* Populate Group 0 interrupt descriptors into fconf based C struct */ + for (uint32_t i = 0; i < g0_intr_count; i++) { + interrupt_prop_t sec_intr_property; + + /* Secure Interrupt Group: INTR_GROUP0 i.e., 0x1 */ + sec_intr_property.intr_grp = 1; + sec_intr_property.intr_num = G0_INTR_NUM(i); + sec_intr_property.intr_pri = G0_INTR_PRIORITY(i); + sec_intr_property.intr_cfg = G0_INTR_CONFIG(i); + sec_intr_prop.descriptor[i] = sec_intr_property; + print_intr_prop(sec_intr_property); + } + + /* Populate G1 secure interrupt descriptors into fconf based C struct */ + for (uint32_t i = 0; i < g1s_intr_count; i++) { + interrupt_prop_t sec_intr_property; + + /* Secure Interrupt Group: INTR_GROUP1S i.e., 0x0 */ + sec_intr_property.intr_grp = 0; + sec_intr_property.intr_num = G1S_INTR_NUM(i); + sec_intr_property.intr_pri = G1S_INTR_PRIORITY(i); + sec_intr_property.intr_cfg = G1S_INTR_CONFIG(i); + sec_intr_prop.descriptor[i + g0_intr_count] = sec_intr_property; + print_intr_prop(sec_intr_property); + } + + return 0; +} + +FCONF_REGISTER_POPULATOR(HW_CONFIG, sec_intr_prop, fconf_populate_sec_intr_config);