aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManish V Badarkhe <Manish.Badarkhe@arm.com>2021-01-24 03:26:50 +0000
committerManish V Badarkhe <Manish.Badarkhe@arm.com>2021-02-09 15:55:26 +0000
commitf98630fbbff6ca5dcebed818ccd3c77353149812 (patch)
treed4b21fc0041c15af7f0e5b4d4db34c27c6a3b006
parentd30a6615d1cc267164b3bf6d71e0e15b2ec4f8a1 (diff)
downloadarm-trusted-firmware-f98630fbbff6ca5dcebed818ccd3c77353149812.tar.gz
plat/arm: fvp: Protect GICR frames for fused/unused cores
Currently, BLs are mapping the GIC memory region as read-write for all cores on boot-up. This opens up the security hole where the active core can write the GICR frame of fused/inactive core. To avoid this issue, disable the GICR frame of all inactive cores as below: 1. After primary CPU boots up, map GICR region of all cores as read-only. 2. After primary CPU boots up, map its GICR region as read-write and initialize its redistributor interface. 3. After secondary CPU boots up, map its GICR region as read-write and initialize its redistributor interface. 4. All unused/fused core's redistributor regions remain read-only and write attempt to such protected regions results in an exception. As mentioned above, this patch offers only the GICR memory-mapped region protection considering there is no facility at the GIC IP level to avoid writing the redistributor area. These changes are currently done in BL31 of Arm FVP and guarded under the flag 'FVP_GICR_REGION_PROTECTION'. As of now, this patch is tested manually as below: 1. Disable the FVP cores (core 1, 2, 3) with core 0 as an active core. 2. Verify data abort triggered by manually updating the ‘GICR_CTLR’ register of core 1’s(fused) redistributor from core 0(active). Change-Id: I86c99c7b41bae137b2011cf2ac17fad0a26e776d Signed-off-by: Manish V Badarkhe <Manish.Badarkhe@arm.com>
-rw-r--r--plat/arm/board/fvp/fvp_common.c17
-rw-r--r--plat/arm/board/fvp/fvp_def.h11
-rw-r--r--plat/arm/board/fvp/fvp_gicv3.c40
-rw-r--r--plat/arm/board/fvp/platform.mk9
4 files changed, 74 insertions, 3 deletions
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 44880d996..52686faca 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -48,6 +48,18 @@ arm_config_t arm_config;
DEVICE1_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE)
+#if FVP_GICR_REGION_PROTECTION
+#define MAP_GICD_MEM MAP_REGION_FLAT(BASE_GICD_BASE, \
+ BASE_GICD_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+/* Map all core's redistributor memory as read-only. After boots up,
+ * per-core map its redistributor memory as read-write */
+#define MAP_GICR_MEM MAP_REGION_FLAT(BASE_GICR_BASE, \
+ (BASE_GICR_SIZE * PLATFORM_CORE_COUNT),\
+ MT_DEVICE | MT_RO | MT_SECURE)
+#endif /* FVP_GICR_REGION_PROTECTION */
+
/*
* Need to be mapped with write permissions in order to set a new non-volatile
* counter value.
@@ -138,7 +150,12 @@ const mmap_region_t plat_arm_mmap[] = {
ARM_MAP_EL3_TZC_DRAM,
V2M_MAP_IOFPGA,
MAP_DEVICE0,
+#if FVP_GICR_REGION_PROTECTION
+ MAP_GICD_MEM,
+ MAP_GICR_MEM,
+#else
MAP_DEVICE1,
+#endif /* FVP_GICR_REGION_PROTECTION */
ARM_V2M_MAP_MEM_PROTECT,
#if SPM_MM
ARM_SPM_BUF_EL3_MMAP,
diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h
index 4efe69258..831eb35b7 100644
--- a/plat/arm/board/fvp/fvp_def.h
+++ b/plat/arm/board/fvp/fvp_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -135,7 +135,16 @@
/* Base FVP compatible GIC memory map */
#define BASE_GICD_BASE UL(0x2f000000)
+#define BASE_GICD_SIZE UL(0x10000)
#define BASE_GICR_BASE UL(0x2f100000)
+
+#if GIC_ENABLE_V4_EXTN
+/* GICv4 redistributor size: 256KB */
+#define BASE_GICR_SIZE UL(0x40000)
+#else
+#define BASE_GICR_SIZE UL(0x20000)
+#endif /* GIC_ENABLE_V4_EXTN */
+
#define BASE_GICC_BASE UL(0x2c000000)
#define BASE_GICH_BASE UL(0x2c010000)
#define BASE_GICV_BASE UL(0x2c02f000)
diff --git a/plat/arm/board/fvp/fvp_gicv3.c b/plat/arm/board/fvp/fvp_gicv3.c
index 3e04d6b67..8f3e7b702 100644
--- a/plat/arm/board/fvp/fvp_gicv3.c
+++ b/plat/arm/board/fvp/fvp_gicv3.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,6 +15,11 @@
#include <plat/arm/common/fconf_sec_intr_config.h>
#include <plat/common/platform.h>
+#if FVP_GICR_REGION_PROTECTION
+/* To indicate GICR region of the core initialized as Read-Write */
+static bool fvp_gicr_rw_region_init[PLATFORM_CORE_COUNT] = {false};
+#endif /* FVP_GICR_REGION_PROTECTION */
+
/* The GICv3 driver only needs to be initialized in EL3 */
static uintptr_t fvp_rdistif_base_addrs[PLATFORM_CORE_COUNT];
@@ -61,8 +66,39 @@ static gicv3_driver_data_t fvp_gic_data = {
.mpidr_to_core_pos = fvp_gicv3_mpidr_hash
};
+/******************************************************************************
+ * This function gets called per core to make its redistributor frame rw
+ *****************************************************************************/
+static void fvp_gicv3_make_rdistrif_rw(void)
+{
+#if FVP_GICR_REGION_PROTECTION
+ unsigned int core_pos = plat_my_core_pos();
+
+ /* Make the redistributor frame RW if it is not done previously */
+ if (fvp_gicr_rw_region_init[core_pos] != true) {
+ int ret = xlat_change_mem_attributes(BASE_GICR_BASE +
+ (core_pos * BASE_GICR_SIZE),
+ BASE_GICR_SIZE,
+ MT_EXECUTE_NEVER |
+ MT_DEVICE | MT_RW |
+ MT_SECURE);
+
+ if (ret != 0) {
+ ERROR("Failed to make redistributor frame \
+ read write = %d\n", ret);
+ panic();
+ } else {
+ fvp_gicr_rw_region_init[core_pos] = true;
+ }
+ }
+#else
+ return;
+#endif /* FVP_GICR_REGION_PROTECTION */
+}
+
void plat_arm_gic_driver_init(void)
{
+ fvp_gicv3_make_rdistrif_rw();
/*
* Get GICD and GICR base addressed through FCONF APIs.
* FCONF is not supported in BL32 for FVP.
@@ -117,6 +153,8 @@ void plat_arm_gic_pcpu_init(void)
int result;
const uint64_t *plat_gicr_frames = fvp_gicr_frames;
+ fvp_gicv3_make_rdistrif_rw();
+
do {
result = gicv3_rdistif_probe(*plat_gicr_frames);
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 0a6fa56ad..6c09d7268 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -16,6 +16,10 @@ FVP_MAX_CPUS_PER_CLUSTER := 4
# Default number of threads per CPU on FVP
FVP_MAX_PE_PER_CPU := 1
+# Disable redistributor frame of inactive/fused CPU cores by marking it as read
+# only; enable redistributor frames of all CPU cores by default.
+FVP_GICR_REGION_PROTECTION := 0
+
FVP_DT_PREFIX := fvp-base-gicv3-psci
# The FVP platform depends on this macro to build with correct GIC driver.
@@ -30,6 +34,9 @@ $(eval $(call add_define,FVP_MAX_CPUS_PER_CLUSTER))
# Pass FVP_MAX_PE_PER_CPU to the build system.
$(eval $(call add_define,FVP_MAX_PE_PER_CPU))
+# Pass FVP_GICR_REGION_PROTECTION to the build system.
+$(eval $(call add_define,FVP_GICR_REGION_PROTECTION))
+
# Sanity check the cluster count and if FVP_CLUSTER_COUNT <= 2,
# choose the CCI driver , else the CCN driver
ifeq ($(FVP_CLUSTER_COUNT), 0)