From 3ed5606bd1156e61241b57cb2dcceb90f75f6332 Mon Sep 17 00:00:00 2001
From: David Horstmann <david.horstmann@arm.com>
Date: Wed, 14 Oct 2020 15:17:49 +0100
Subject: [PATCH] Use constant stack size with RECLAIM_INIT_CODE

Currently, when RECLAIM_INIT_CODE is set, the
stacks are scaled to ensure that the entirety
of the init section can be reclaimed as stack.

This causes an issue in lib/psci/aarch64/psci_helpers.S,
where the stack size is used for cache operations in
psci_do_pwrdown_cache_maintenance(). If the stacks
are scaled, then the PSCI code may fail to invalidate
some of the stack memory before power down.

Resizing stacks is also not good for stability in general,
since code that works with a small number of cores may
overflow the stack when the number of cores is increased.

Change to make every stack be PLATFORM_STACK_SIZE big,
and allow the total stack to be smaller than the
init section.

Any pages of the init section not reclaimed as
stack will be set to read-only and execute-never,
for security.

Change-Id: I10b3884981006431f2fcbec3864c81d4a8c246e8
Signed-off-by: David Horstmann <david.horstmann@arm.com>
---
 include/plat/arm/common/arm_reclaim_init.ld.S | 54 ++++++-------------
 plat/arm/common/arm_bl31_setup.c              | 34 ++++++++++--
 plat/common/aarch64/platform_mp_stack.S       | 33 ------------
 3 files changed, 46 insertions(+), 75 deletions(-)

diff --git a/include/plat/arm/common/arm_reclaim_init.ld.S b/include/plat/arm/common/arm_reclaim_init.ld.S
index e4d4f1254..717f65e2b 100644
--- a/include/plat/arm/common/arm_reclaim_init.ld.S
+++ b/include/plat/arm/common/arm_reclaim_init.ld.S
@@ -14,54 +14,30 @@ SECTIONS
             __INIT_CODE_START__ = .;
 	    *(*text.init*);
             __INIT_CODE_END__ = .;
+            INIT_CODE_END_ALIGNED = ALIGN(PAGE_SIZE);
         } >RAM
 
 #ifdef BL31_PROGBITS_LIMIT
     ASSERT(__INIT_CODE_END__ <= BL31_PROGBITS_LIMIT,
             "BL31 init has exceeded progbits limit.")
 #endif
-
-    ASSERT(__INIT_CODE_END__ <= __STACKS_END__,
-        "Init code ends past the end of the stacks")
-
 }
 
-#undef	MIN
 #define	ABS		ABSOLUTE
-#define	COUNT		PLATFORM_CORE_COUNT
-#define	ALIGN_MASK	~(CACHE_WRITEBACK_GRANULE - 1)
-
-#define PRIMARY_STACK							\
-	__STACKS_START__ = .;						\
-	*(tzfw_normal_stacks)						\
-	OFFSET = ABS(SIZEOF(.init) - (. - __STACKS_START__));		\
-	/* Offset sign */						\
-	SIGN = ABS(OFFSET) & (1 << 63);					\
-	/* Offset mask */						\
-	MASK = ABS(SIGN >> 63) - 1;					\
-	. +=  ABS(OFFSET) & ABS(MASK);					\
-	.  = ALIGN(PAGE_SIZE);						\
-	__STACKS_END__ = .;						\
-	/* Total stack size */						\
-	SIZE = ABS(. - __STACKS_START__);				\
-	/* Maximum primary CPU stack */					\
-	STACK = ABS(__STACKS_START__ + SIZE / COUNT) & ALIGN_MASK;	\
-	/* Primary CPU stack */						\
-	__PRIMARY_STACK__ = MIN(STACK, ABS(__INIT_CODE_START__));
 
-#if (COUNT > 1)
-#define	SECONDARY_STACK					\
-	/* Size of the secondary CPUs' stack */		\
-	REST = ABS(__STACKS_END__ - __PRIMARY_STACK__);	\
-	/* Secondary per-CPU stack size */		\
-	__STACK_SIZE__ = ABS(REST / (COUNT - 1));
-#else
-#define	SECONDARY_STACK
-#endif
-
-#define STACK_SECTION		\
-	stacks (NOLOAD) : {	\
-		PRIMARY_STACK	\
-		SECONDARY_STACK	\
+#define STACK_SECTION							\
+	stacks (NOLOAD) : {						\
+		__STACKS_START__ = .;					\
+		*(tzfw_normal_stacks)					\
+		__STACKS_END__ = .;					\
+		/* Allow room for the init section where necessary. */	\
+		OFFSET = ABS(SIZEOF(.init) - (. - __STACKS_START__));	\
+		/* Offset sign */					\
+		SIGN = ABS(OFFSET) & (1 << 63);				\
+		/* Offset mask */					\
+		MASK = ABS(SIGN >> 63) - 1;				\
+		. +=  ABS(OFFSET) & ABS(MASK);				\
+		.  = ALIGN(PAGE_SIZE);					\
 	}
+
 #endif /* ARM_RECLAIM_INIT_LD_S */
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index fc238b1d8..81ef6e7b2 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -47,9 +47,12 @@ CASSERT(BL31_BASE >= ARM_FW_CONFIG_LIMIT, assert_bl31_base_overflows);
 #if RECLAIM_INIT_CODE
 IMPORT_SYM(unsigned long, __INIT_CODE_START__, BL_INIT_CODE_BASE);
 IMPORT_SYM(unsigned long, __INIT_CODE_END__, BL_CODE_END_UNALIGNED);
+IMPORT_SYM(unsigned long, __STACKS_END__, BL_STACKS_END_UNALIGNED);
 
 #define	BL_INIT_CODE_END	((BL_CODE_END_UNALIGNED + PAGE_SIZE - 1) & \
 					~(PAGE_SIZE - 1))
+#define	BL_STACKS_END		((BL_STACKS_END_UNALIGNED + PAGE_SIZE - 1) & \
+					~(PAGE_SIZE - 1))
 
 #define MAP_BL_INIT_CODE	MAP_REGION_FLAT(			\
 					BL_INIT_CODE_BASE,		\
@@ -291,14 +294,39 @@ void arm_bl31_plat_runtime_setup(void)
 
 #if RECLAIM_INIT_CODE
 /*
- * Zero out and make RW memory used to store image boot time code so it can
- * be reclaimed during runtime
+ * Make memory for image boot time code RW to reclaim it as stack for the
+ * secondary cores, or RO where it cannot be reclaimed:
+ *
+ *            |-------- INIT SECTION --------|
+ *  -----------------------------------------
+ * |  CORE 0  |  CORE 1  |  CORE 2  | EXTRA  |
+ * |  STACK   |  STACK   |  STACK   | SPACE  |
+ *  -----------------------------------------
+ *             <-------------------> <------>
+ *                MAKE RW AND XN       MAKE
+ *                  FOR STACKS       RO AND XN
  */
 void arm_free_init_memory(void)
 {
-	int ret = xlat_change_mem_attributes(BL_INIT_CODE_BASE,
+	int ret = 0;
+
+	if (BL_STACKS_END < BL_INIT_CODE_END) {
+		/* Reclaim some of the init section as stack if possible. */
+		if (BL_INIT_CODE_BASE < BL_STACKS_END) {
+			ret |= xlat_change_mem_attributes(BL_INIT_CODE_BASE,
+					BL_STACKS_END - BL_INIT_CODE_BASE,
+					MT_RW_DATA);
+		}
+		/* Make the rest of the init section read-only. */
+		ret |= xlat_change_mem_attributes(BL_STACKS_END,
+				BL_INIT_CODE_END - BL_STACKS_END,
+				MT_RO_DATA);
+	} else {
+		/* The stacks cover the init section, so reclaim it all. */
+		ret |= xlat_change_mem_attributes(BL_INIT_CODE_BASE,
 				BL_INIT_CODE_END - BL_INIT_CODE_BASE,
 				MT_RW_DATA);
+	}
 
 	if (ret != 0) {
 		ERROR("Could not reclaim initialization code");
diff --git a/plat/common/aarch64/platform_mp_stack.S b/plat/common/aarch64/platform_mp_stack.S
index ee0dbb4f6..c34a4cf3b 100644
--- a/plat/common/aarch64/platform_mp_stack.S
+++ b/plat/common/aarch64/platform_mp_stack.S
@@ -32,42 +32,9 @@
 	 * -----------------------------------------------------
 	 */
 func plat_get_my_stack
-#if (defined(IMAGE_BL31) && RECLAIM_INIT_CODE)
-#if (PLATFORM_CORE_COUNT == 1)
-	/* Single CPU */
-	adrp	x0, __PRIMARY_STACK__
-	add	x0, x0, :lo12:__PRIMARY_STACK__
-	ret
-#else
-	mov	x10, x30
-	bl	plat_my_core_pos
-	cbnz	x0, 2f
-
-	/* Primary CPU */
-	adrp	x0, __PRIMARY_STACK__
-	add	x0, x0, :lo12:__PRIMARY_STACK__
-	ret	x10
-
-	/* Secondary CPU */
-2:	sub	x0, x0, #(PLATFORM_CORE_COUNT - 1)
-	adrp	x1, __STACKS_END__
-	adrp	x2, __STACK_SIZE__
-	add	x1, x1, :lo12:__STACKS_END__
-	add	x2, x2, :lo12:__STACK_SIZE__
-
-	madd	x0, x0, x2, x1
-	bic	x0, x0, #(CACHE_WRITEBACK_GRANULE - 1)
-	ret	x10
-#endif
-	/* Prevent linker from removal of stack section */
-	.quad	platform_normal_stacks
-
-#else /* !(IMAGE_BL31 && RECLAIM_INIT_CODE) */
 	mov	x10, x30
 	get_my_mp_stack platform_normal_stacks, PLATFORM_STACK_SIZE
 	ret	x10
-
-#endif /* IMAGE_BL31 && RECLAIM_INIT_CODE */
 endfunc plat_get_my_stack
 
 	/* -----------------------------------------------------
-- 
GitLab