From 683f788fa7374669724eb419a8c3e763b05bcc5c Mon Sep 17 00:00:00 2001 From: Soby Mathew Date: Thu, 29 Jan 2015 12:00:58 +0000 Subject: [PATCH] Fix the Cortex-A57 reset handler register usage The CPU specific reset handlers no longer have the freedom of using any general purpose register because it is being invoked by the BL3-1 entry point in addition to BL1. The Cortex-A57 CPU specific reset handler was overwriting x20 register which was being used by the BL3-1 entry point to save the entry point information. This patch fixes this bug by reworking the register allocation in the Cortex-A57 reset handler to avoid using x20. The patch also explicitly mentions the register clobber list for each of the callee functions invoked by the reset handler Change-Id: I28fcff8e742aeed883eaec8f6c4ee2bd3fce30df --- docs/firmware-design.md | 1 + docs/porting-guide.md | 3 +-- lib/cpus/aarch64/cortex_a53.S | 1 + lib/cpus/aarch64/cortex_a57.S | 17 ++++++++++------- lib/cpus/aarch64/cpu_helpers.S | 4 ++++ 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/docs/firmware-design.md b/docs/firmware-design.md index 4a50a7b78..acfef4e26 100644 --- a/docs/firmware-design.md +++ b/docs/firmware-design.md @@ -1066,6 +1066,7 @@ array and returns it. Note that only the part number and implementator fields in midr are used to find the matching `cpu_ops` entry. The `reset_func()` in the returned `cpu_ops` is then invoked which executes the required reset handling for that CPU and also any errata workarounds enabled by the platform. +This function must preserve the values of general purpose registers x20 to x29. Refer to Section "Guidelines for Reset Handlers" for general guidelines regarding placement of code in a reset handler. diff --git a/docs/porting-guide.md b/docs/porting-guide.md index a30535d77..09cd7d5ed 100644 --- a/docs/porting-guide.md +++ b/docs/porting-guide.md @@ -491,8 +491,7 @@ are just an ARM Trusted Firmware convention. A platform may need to do additional initialization after reset. This function allows the platform to do the platform specific intializations. Platform specific errata workarounds could also be implemented here. The api should -preserve the value in x10 register as it is used by the caller to store the -return address. +preserve the values of callee saved registers x19 to x29. The default implementation doesn't do anything. If a platform needs to override the default implementation, refer to the [Firmware Design Guide] for general diff --git a/lib/cpus/aarch64/cortex_a53.S b/lib/cpus/aarch64/cortex_a53.S index 306b42e7a..188f3c1eb 100644 --- a/lib/cpus/aarch64/cortex_a53.S +++ b/lib/cpus/aarch64/cortex_a53.S @@ -61,6 +61,7 @@ func cortex_a53_reset_func /* --------------------------------------------- * As a bare minimum enable the SMP bit if it is * not already set. + * Clobbers : x0 * --------------------------------------------- */ mrs x0, CPUECTLR_EL1 diff --git a/lib/cpus/aarch64/cortex_a57.S b/lib/cpus/aarch64/cortex_a57.S index 3334e688c..eb6c736f2 100644 --- a/lib/cpus/aarch64/cortex_a57.S +++ b/lib/cpus/aarch64/cortex_a57.S @@ -87,6 +87,7 @@ func cortex_a57_disable_ext_debug * This applies only to revision r0p0 of Cortex A57. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. + * Clobbers : x0 - x5 * -------------------------------------------------- */ func errata_a57_806969_wa @@ -119,6 +120,7 @@ skip_806969: * This applies only to revision r0p0 of Cortex A57. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. + * Clobbers : x0 - x5 * --------------------------------------------------- */ func errata_a57_813420_wa @@ -147,6 +149,7 @@ skip_813420: /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A57. + * Clobbers: x0-x5, x15, x19, x30 * ------------------------------------------------- */ func cortex_a57_reset_func @@ -155,20 +158,20 @@ func cortex_a57_reset_func /* * Extract the variant[20:23] and revision[0:3] from x0 - * and pack it in x20[0:7] as variant[4:7] and revision[0:3]. - * First extract x0[16:23] to x20[0:7] and zero fill the rest. - * Then extract x0[0:3] into x20[0:3] retaining other bits. + * and pack it in x15[0:7] as variant[4:7] and revision[0:3]. + * First extract x0[16:23] to x15[0:7] and zero fill the rest. + * Then extract x0[0:3] into x15[0:3] retaining other bits. */ - ubfx x20, x0, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS) - bfxil x20, x0, #MIDR_REV_SHIFT, #MIDR_REV_BITS + ubfx x15, x0, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS) + bfxil x15, x0, #MIDR_REV_SHIFT, #MIDR_REV_BITS #if ERRATA_A57_806969 - mov x0, x20 + mov x0, x15 bl errata_a57_806969_wa #endif #if ERRATA_A57_813420 - mov x0, x20 + mov x0, x15 bl errata_a57_813420_wa #endif diff --git a/lib/cpus/aarch64/cpu_helpers.S b/lib/cpus/aarch64/cpu_helpers.S index d829f60ba..bebe7c0a5 100644 --- a/lib/cpus/aarch64/cpu_helpers.S +++ b/lib/cpus/aarch64/cpu_helpers.S @@ -42,11 +42,13 @@ * The reset handler common to all platforms. After a matching * cpu_ops structure entry is found, the correponding reset_handler * in the cpu_ops is invoked. + * Clobbers: x0 - x19, x30 */ .globl reset_handler func reset_handler mov x19, x30 + /* The plat_reset_handler can clobber x0 - x18, x30 */ bl plat_reset_handler /* Get the matching cpu_ops pointer */ @@ -60,6 +62,8 @@ func reset_handler ldr x2, [x0, #CPU_RESET_FUNC] mov x30, x19 cbz x2, 1f + + /* The cpu_ops reset handler can clobber x0 - x19, x30 */ br x2 1: ret