diff options
author | Alistair Delva <adelva@google.com> | 2020-02-05 15:42:52 -0800 |
---|---|---|
committer | Alistair Delva <adelva@google.com> | 2020-02-06 18:35:58 +0000 |
commit | 5dfd96a0b3264f2ea428fcbed5d76f7f4aef4f2f (patch) | |
tree | 76d9e0cabe45c1ed6d9ea87a5deb9c75c4345653 /lib | |
parent | f8cb4bf36efbe497216e23043732fbb8949c7d43 (diff) | |
parent | 5f62213e684dbea03b5a2bb732405a03ccc1a815 (diff) | |
download | platform_external_arm-trusted-firmware-5dfd96a0b3264f2ea428fcbed5d76f7f4aef4f2f.tar.gz platform_external_arm-trusted-firmware-5dfd96a0b3264f2ea428fcbed5d76f7f4aef4f2f.tar.bz2 platform_external_arm-trusted-firmware-5dfd96a0b3264f2ea428fcbed5d76f7f4aef4f2f.zip |
Merge '5f62213e684dbea03b5a2bb732405a03ccc1a815' into master
Update to fix an incompatibility with U-Boot 2020.01 on rockpi
IGNORE_MERGE_CONFLICT_CHECK==false positive
Bug: 147107640
Change-Id: Ie767196449b0a8e661883f8220ae02eb3535c4a5
Diffstat (limited to 'lib')
49 files changed, 2834 insertions, 653 deletions
diff --git a/lib/compiler-rt/compiler-rt.mk b/lib/compiler-rt/compiler-rt.mk index 49e497eb8..a8d36a361 100644 --- a/lib/compiler-rt/compiler-rt.mk +++ b/lib/compiler-rt/compiler-rt.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -28,9 +28,17 @@ # POSSIBILITY OF SUCH DAMAGE. # +CPPFLAGS += -Ilib/compiler-rt/include + +COMPILER_RT_SRCS := lib/compiler-rt/builtins/popcountdi2.c \ + lib/compiler-rt/builtins/popcountsi2.c + ifeq (${ARCH},aarch32) -COMPILER_RT_SRCS := lib/compiler-rt/builtins/arm/aeabi_uldivmod.S \ - lib/compiler-rt/builtins/udivmoddi4.c \ +COMPILER_RT_SRCS += lib/compiler-rt/builtins/arm/aeabi_ldivmod.S \ + lib/compiler-rt/builtins/arm/aeabi_uldivmod.S \ lib/compiler-rt/builtins/ctzdi2.c \ - lib/compiler-rt/builtins/lshrdi3.c + lib/compiler-rt/builtins/divdi3.c \ + lib/compiler-rt/builtins/divmoddi4.c \ + lib/compiler-rt/builtins/lshrdi3.c \ + lib/compiler-rt/builtins/udivmoddi4.c endif diff --git a/lib/compiler-rt/include/float.h b/lib/compiler-rt/include/float.h new file mode 100644 index 000000000..710cecca9 --- /dev/null +++ b/lib/compiler-rt/include/float.h @@ -0,0 +1 @@ +/* Empty */ diff --git a/lib/cpus/aarch64/aem_generic.S b/lib/cpus/aarch64/aem_generic.S index 51b5ce91c..6291e43e1 100644 --- a/lib/cpus/aarch64/aem_generic.S +++ b/lib/cpus/aarch64/aem_generic.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -18,15 +18,43 @@ func aem_generic_core_pwr_dwn msr sctlr_el3, x1 isb + /* --------------------------------------------- + * AEM model supports L3 caches in which case L2 + * will be private per core caches and flush + * from L1 to L2 is not sufficient. + * --------------------------------------------- + */ + mrs x1, clidr_el1 + + /* --------------------------------------------- + * Check if L3 cache is implemented. + * --------------------------------------------- + */ + tst x1, ((1 << CLIDR_FIELD_WIDTH) - 1) << CTYPE_SHIFT(3) + + /* --------------------------------------------- + * There is no L3 cache, flush L1 to L2 only. + * --------------------------------------------- + */ mov x0, #DCCISW + b.eq dcsw_op_level1 + + mov x18, x30 /* --------------------------------------------- - * Flush L1 cache to PoU. + * Flush L1 cache to L2. * --------------------------------------------- */ - b dcsw_op_louis -endfunc aem_generic_core_pwr_dwn + bl dcsw_op_level1 + mov x30, x18 + /* --------------------------------------------- + * Flush L2 cache to L3. + * --------------------------------------------- + */ + mov x0, #DCCISW + b dcsw_op_level2 +endfunc aem_generic_core_pwr_dwn func aem_generic_cluster_pwr_dwn /* --------------------------------------------- @@ -39,7 +67,7 @@ func aem_generic_cluster_pwr_dwn isb /* --------------------------------------------- - * Flush L1 and L2 caches to PoC. + * Flush all caches to PoC. * --------------------------------------------- */ mov x0, #DCCISW diff --git a/lib/cpus/aarch64/cortex_a65.S b/lib/cpus/aarch64/cortex_a65.S new file mode 100644 index 000000000..666324c1e --- /dev/null +++ b/lib/cpus/aarch64/cortex_a65.S @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include <arch.h> + +#include <asm_macros.S> +#include <common/bl_common.h> +#include <common/debug.h> +#include <cortex_a65.h> +#include <cpu_macros.S> +#include <plat_macros.S> + +/* Hardware handled coherency */ +#if !HW_ASSISTED_COHERENCY +#error "Cortex-A65 must be compiled with HW_ASSISTED_COHERENCY enabled" +#endif + +/* 64-bit only core */ +#if CTX_INCLUDE_AARCH32_REGS +#error "Cortex-A65 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0" +#endif + +/* ------------------------------------------------- + * The CPU Ops reset function for Cortex-A65. + * Shall clobber: x0-x19 + * ------------------------------------------------- + */ +func cortex_a65_reset_func + mov x19, x30 + +#if ERRATA_DSU_936184 + bl errata_dsu_936184_wa +#endif + + ret x19 +endfunc cortex_a65_reset_func + +func cortex_a65_cpu_pwr_dwn + mrs x0, CORTEX_A65_CPUPWRCTLR_EL1 + orr x0, x0, #CORTEX_A65_CPUPWRCTLR_EL1_CORE_PWRDN_BIT + msr CORTEX_A65_CPUPWRCTLR_EL1, x0 + isb + ret +endfunc cortex_a65_cpu_pwr_dwn + +#if REPORT_ERRATA +/* + * Errata printing function for Cortex-A65. Must follow AAPCS. + */ +func cortex_a65_errata_report + stp x8, x30, [sp, #-16]! + + bl cpu_get_rev_var + mov x8, x0 + + /* + * Report all errata. The revision-variant information is passed to + * checking functions of each errata. + */ + report_errata ERRATA_DSU_936184, cortex_a65, dsu_936184 + + ldp x8, x30, [sp], #16 + ret +endfunc cortex_a65_errata_report +#endif + +.section .rodata.cortex_a65_regs, "aS" +cortex_a65_regs: /* The ascii list of register names to be reported */ + .asciz "cpuectlr_el1", "" + +func cortex_a65_cpu_reg_dump + adr x6, cortex_a65_regs + mrs x8, CORTEX_A65_ECTLR_EL1 + ret +endfunc cortex_a65_cpu_reg_dump + +declare_cpu_ops cortex_a65, CORTEX_A65_MIDR, \ + cortex_a65_reset_func, \ + cortex_a65_cpu_pwr_dwn diff --git a/lib/cpus/aarch64/cortex_a65ae.S b/lib/cpus/aarch64/cortex_a65ae.S new file mode 100644 index 000000000..ac6583ebc --- /dev/null +++ b/lib/cpus/aarch64/cortex_a65ae.S @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include <arch.h> + +#include <asm_macros.S> +#include <common/bl_common.h> +#include <common/debug.h> +#include <cortex_a65ae.h> +#include <cpu_macros.S> +#include <plat_macros.S> + +/* Hardware handled coherency */ +#if !HW_ASSISTED_COHERENCY +#error "Cortex-A65AE must be compiled with HW_ASSISTED_COHERENCY enabled" +#endif + +/* 64-bit only core */ +#if CTX_INCLUDE_AARCH32_REGS +#error "Cortex-A65AE supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0" +#endif + +/* ------------------------------------------------- + * The CPU Ops reset function for Cortex-A65. + * Shall clobber: x0-x19 + * ------------------------------------------------- + */ +func cortex_a65ae_reset_func + mov x19, x30 + +#if ERRATA_DSU_936184 + bl errata_dsu_936184_wa +#endif + + ret x19 +endfunc cortex_a65ae_reset_func + +func cortex_a65ae_cpu_pwr_dwn + mrs x0, CORTEX_A65AE_CPUPWRCTLR_EL1 + orr x0, x0, #CORTEX_A65AE_CPUPWRCTLR_EL1_CORE_PWRDN_BIT + msr CORTEX_A65AE_CPUPWRCTLR_EL1, x0 + isb + ret +endfunc cortex_a65ae_cpu_pwr_dwn + +#if REPORT_ERRATA +/* + * Errata printing function for Cortex-A65AE. Must follow AAPCS. + */ +func cortex_a65ae_errata_report + stp x8, x30, [sp, #-16]! + + bl cpu_get_rev_var + mov x8, x0 + + /* + * Report all errata. The revision-variant information is passed to + * checking functions of each errata. + */ + report_errata ERRATA_DSU_936184, cortex_a65ae, dsu_936184 + + ldp x8, x30, [sp], #16 + ret +endfunc cortex_a65ae_errata_report +#endif + +.section .rodata.cortex_a65ae_regs, "aS" +cortex_a65ae_regs: /* The ascii list of register names to be reported */ + .asciz "cpuectlr_el1", "" + +func cortex_a65ae_cpu_reg_dump + adr x6, cortex_a65ae_regs + mrs x8, CORTEX_A65AE_ECTLR_EL1 + ret +endfunc cortex_a65ae_cpu_reg_dump + +declare_cpu_ops cortex_a65ae, CORTEX_A65AE_MIDR, \ + cortex_a65ae_reset_func, \ + cortex_a65ae_cpu_pwr_dwn diff --git a/lib/cpus/aarch64/cortex_a76.S b/lib/cpus/aarch64/cortex_a76.S index 868667ebc..baefa4676 100644 --- a/lib/cpus/aarch64/cortex_a76.S +++ b/lib/cpus/aarch64/cortex_a76.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -85,7 +85,7 @@ bic x3, x2, #CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE csel x3, x3, x1, eq msr CORTEX_A76_CPUACTLR2_EL1, x3 - eret /* ERET implies ISB */ + exception_return /* exception_return contains ISB */ .endif 1: /* diff --git a/lib/cpus/aarch64/cortex_hercules.S b/lib/cpus/aarch64/cortex_hercules.S index 4e048145f..a23919626 100644 --- a/lib/cpus/aarch64/cortex_hercules.S +++ b/lib/cpus/aarch64/cortex_hercules.S @@ -16,12 +16,49 @@ #error "cortex_hercules must be compiled with HW_ASSISTED_COHERENCY enabled" #endif + +/* -------------------------------------------------- + * Errata Workaround for Hercules Erratum 1688305. + * This applies to revision r0p0 and r1p0 of Hercules. + * Inputs: + * x0: variant[4:7] and revision[0:3] of current cpu. + * Shall clobber: x0-x17 + * -------------------------------------------------- + */ +func errata_hercules_1688305_wa + /* Compare x0 against revision r1p0 */ + mov x17, x30 + bl check_errata_1688305 + cbz x0, 1f + mrs x1, CORTEX_HERCULES_ACTLR2_EL1 + orr x1, x1, CORTEX_HERCULES_ACTLR2_EL1_BIT_1 + msr CORTEX_HERCULES_ACTLR2_EL1, x1 + isb +1: + ret x17 +endfunc errata_hercules_1688305_wa + +func check_errata_1688305 + /* Applies to r0p0 and r1p0 */ + mov x1, #0x10 + b cpu_rev_var_ls +endfunc check_errata_1688305 + /* ------------------------------------------------- * The CPU Ops reset function for Cortex-Hercules * ------------------------------------------------- */ -#if ENABLE_AMU func cortex_hercules_reset_func + mov x19, x30 + bl cpu_get_rev_var + mov x18, x0 + +#if ERRATA_HERCULES_1688305 + mov x0, x18 + bl errata_hercules_1688305_wa +#endif + +#if ENABLE_AMU /* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */ mrs x0, actlr_el3 bic x0, x0, #CORTEX_HERCULES_ACTLR_TAM_BIT @@ -39,11 +76,11 @@ func cortex_hercules_reset_func /* Enable group1 counters */ mov x0, #CORTEX_HERCULES_AMU_GROUP1_MASK msr CPUAMCNTENSET1_EL0, x0 - isb +#endif - ret + isb + ret x19 endfunc cortex_hercules_reset_func -#endif /* --------------------------------------------- * HW will do the cache maintenance while powering down @@ -66,6 +103,18 @@ endfunc cortex_hercules_core_pwr_dwn */ #if REPORT_ERRATA func cortex_hercules_errata_report + stp x8, x30, [sp, #-16]! + + bl cpu_get_rev_var + mov x8, x0 + + /* + * Report all errata. The revision-variant information is passed to + * checking functions of each errata. + */ + report_errata ERRATA_HERCULES_1688305, cortex_hercules, 1688305 + + ldp x8, x30, [sp], #16 ret endfunc cortex_hercules_errata_report #endif @@ -89,12 +138,6 @@ func cortex_hercules_cpu_reg_dump ret endfunc cortex_hercules_cpu_reg_dump -#if ENABLE_AMU -#define HERCULES_RESET_FUNC cortex_hercules_reset_func -#else -#define HERCULES_RESET_FUNC CPU_NO_RESET_FUNC -#endif - declare_cpu_ops cortex_hercules, CORTEX_HERCULES_MIDR, \ - HERCULES_RESET_FUNC, \ + cortex_hercules_reset_func, \ cortex_hercules_core_pwr_dwn diff --git a/lib/cpus/aarch64/cortex_hercules_ae.S b/lib/cpus/aarch64/cortex_hercules_ae.S new file mode 100644 index 000000000..c4a216353 --- /dev/null +++ b/lib/cpus/aarch64/cortex_hercules_ae.S @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2019, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <common/bl_common.h> +#include <cortex_hercules_ae.h> +#include <cpu_macros.S> +#include <plat_macros.S> + +/* Hardware handled coherency */ +#if HW_ASSISTED_COHERENCY == 0 +#error "cortex_hercules_ae must be compiled with HW_ASSISTED_COHERENCY enabled" +#endif + + /* ------------------------------------------------- + * The CPU Ops reset function for Cortex-Hercules-AE + * ------------------------------------------------- + */ +#if ENABLE_AMU +func cortex_hercules_ae_reset_func + /* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */ + mrs x0, actlr_el3 + bic x0, x0, #CORTEX_HERCULES_ACTLR_TAM_BIT + msr actlr_el3, x0 + + /* Make sure accesses from non-secure EL0/EL1 are not trapped to EL2 */ + mrs x0, actlr_el2 + bic x0, x0, #CORTEX_HERCULES_ACTLR_TAM_BIT + msr actlr_el2, x0 + + /* Enable group0 counters */ + mov x0, #CORTEX_HERCULES_AMU_GROUP0_MASK + msr CPUAMCNTENSET0_EL0, x0 + + /* Enable group1 counters */ + mov x0, #CORTEX_HERCULES_AMU_GROUP1_MASK + msr CPUAMCNTENSET1_EL0, x0 + isb + + ret +endfunc cortex_hercules_ae_reset_func +#endif + + /* ------------------------------------------------------- + * HW will do the cache maintenance while powering down + * ------------------------------------------------------- + */ +func cortex_hercules_ae_core_pwr_dwn + /* ------------------------------------------------------- + * Enable CPU power down bit in power control register + * ------------------------------------------------------- + */ + mrs x0, CORTEX_HERCULES_CPUPWRCTLR_EL1 + orr x0, x0, #CORTEX_HERCULES_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT + msr CORTEX_HERCULES_CPUPWRCTLR_EL1, x0 + isb + ret +endfunc cortex_hercules_ae_core_pwr_dwn + + /* + * Errata printing function for cortex_hercules_ae. Must follow AAPCS. + */ +#if REPORT_ERRATA +func cortex_hercules_ae_errata_report + ret +endfunc cortex_hercules_ae_errata_report +#endif + + /* ------------------------------------------------------- + * This function provides cortex_hercules_ae specific + * register information for crash reporting. + * It needs to return with x6 pointing to + * a list of register names in ascii and + * x8 - x15 having values of registers to be + * reported. + * ------------------------------------------------------- + */ +.section .rodata.cortex_hercules_ae_regs, "aS" +cortex_hercules_ae_regs: /* The ascii list of register names to be reported */ + .asciz "cpuectlr_el1", "" + +func cortex_hercules_ae_cpu_reg_dump + adr x6, cortex_hercules_ae_regs + mrs x8, CORTEX_HERCULES_CPUECTLR_EL1 + ret +endfunc cortex_hercules_ae_cpu_reg_dump + +#if ENABLE_AMU +#define HERCULES_AE_RESET_FUNC cortex_hercules_ae_reset_func +#else +#define HERCULES_AE_RESET_FUNC CPU_NO_RESET_FUNC +#endif + +declare_cpu_ops cortex_hercules_ae, CORTEX_HERCULES_AE_MIDR, \ + HERCULES_AE_RESET_FUNC, \ + cortex_hercules_ae_core_pwr_dwn diff --git a/lib/cpus/aarch64/cpu_helpers.S b/lib/cpus/aarch64/cpu_helpers.S index de1177c39..808c7f807 100644 --- a/lib/cpus/aarch64/cpu_helpers.S +++ b/lib/cpus/aarch64/cpu_helpers.S @@ -227,6 +227,27 @@ func cpu_rev_var_hs ret endfunc cpu_rev_var_hs +/* + * Compare the CPU's revision-variant (x0) with a given range (x1 - x2), for errata + * application purposes. If the revision-variant is between or includes the given + * values, this indicates that errata applies; otherwise not. + * + * Shall clobber: x0-x4 + */ + .globl cpu_rev_var_range +func cpu_rev_var_range + mov x3, #ERRATA_APPLIES + mov x4, #ERRATA_NOT_APPLIES + cmp x0, x1 + csel x1, x3, x4, hs + cbz x1, 1f + cmp x0, x2 + csel x1, x3, x4, ls +1: + mov x0, x1 + ret +endfunc cpu_rev_var_range + #if REPORT_ERRATA /* * void print_errata_status(void); diff --git a/lib/cpus/aarch64/neoverse_n1.S b/lib/cpus/aarch64/neoverse_n1.S index b143a2e7b..d537ed6a8 100644 --- a/lib/cpus/aarch64/neoverse_n1.S +++ b/lib/cpus/aarch64/neoverse_n1.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, 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 <neoverse_n1.h> #include <cpuamu.h> #include <cpu_macros.S> +#include <context.h> /* Hardware handled coherency */ #if HW_ASSISTED_COHERENCY == 0 @@ -20,6 +21,8 @@ #error "Neoverse-N1 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0" #endif + .global neoverse_n1_errata_ic_trap_handler + /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Erratum 1043202. * This applies to revision r0p0 and r1p0 of Neoverse N1. @@ -43,6 +46,7 @@ func errata_n1_1043202_wa msr CPUPMR_EL3, x0 ldr x0, =0x800200071 msr CPUPCR_EL3, x0 + isb 1: ret x17 endfunc errata_n1_1043202_wa @@ -336,6 +340,41 @@ func check_errata_1315703 b cpu_rev_var_ls endfunc check_errata_1315703 +/* -------------------------------------------------- + * Errata Workaround for Neoverse N1 Erratum 1542419. + * This applies to revisions r3p0 - r4p0 of Neoverse N1 + * Inputs: + * x0: variant[4:7] and revision[0:3] of current cpu. + * Shall clobber: x0-x17 + * -------------------------------------------------- + */ +func errata_n1_1542419_wa + /* Compare x0 against revision r3p0 and r4p0 */ + mov x17, x30 + bl check_errata_1542419 + cbz x0, 1f + + /* Apply instruction patching sequence */ + ldr x0, =0x0 + msr CPUPSELR_EL3, x0 + ldr x0, =0xEE670D35 + msr CPUPOR_EL3, x0 + ldr x0, =0xFFFF0FFF + msr CPUPMR_EL3, x0 + ldr x0, =0x08000020007D + msr CPUPCR_EL3, x0 + isb +1: + ret x17 +endfunc errata_n1_1542419_wa + +func check_errata_1542419 + /* Applies to everything r3p0 - r4p0. */ + mov x1, #0x30 + mov x2, #0x40 + b cpu_rev_var_range +endfunc check_errata_1542419 + func neoverse_n1_reset_func mov x19, x30 @@ -405,6 +444,11 @@ func neoverse_n1_reset_func bl errata_n1_1315703_wa #endif +#if ERRATA_N1_1542419 + mov x0, x18 + bl errata_n1_1542419_wa +#endif + #if ENABLE_AMU /* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */ mrs x0, actlr_el3 @@ -421,6 +465,13 @@ func neoverse_n1_reset_func msr CPUAMCNTENSET_EL0, x0 #endif +#if NEOVERSE_N1_EXTERNAL_LLC + /* Some system may have External LLC, core needs to be made aware */ + mrs x0, NEOVERSE_N1_CPUECTLR_EL1 + orr x0, x0, NEOVERSE_N1_CPUECTLR_EL1_EXTLLC_BIT + msr NEOVERSE_N1_CPUECTLR_EL1, x0 +#endif + #if ERRATA_DSU_936184 bl errata_dsu_936184_wa #endif @@ -470,6 +521,7 @@ func neoverse_n1_errata_report report_errata ERRATA_N1_1262888, neoverse_n1, 1262888 report_errata ERRATA_N1_1275112, neoverse_n1, 1275112 report_errata ERRATA_N1_1315703, neoverse_n1, 1315703 + report_errata ERRATA_N1_1542419, neoverse_n1, 1542419 report_errata ERRATA_DSU_936184, neoverse_n1, dsu_936184 ldp x8, x30, [sp], #16 @@ -477,6 +529,42 @@ func neoverse_n1_errata_report endfunc neoverse_n1_errata_report #endif +/* + * Handle trap of EL0 IC IVAU instructions to EL3 by executing a TLB + * inner-shareable invalidation to an arbitrary address followed by a DSB. + * + * x1: Exception Syndrome + */ +func neoverse_n1_errata_ic_trap_handler + cmp x1, #NEOVERSE_N1_EC_IC_TRAP + b.ne 1f + tlbi vae3is, xzr + dsb sy + + # Skip the IC instruction itself + mrs x3, elr_el3 + add x3, x3, #4 + msr elr_el3, x3 + + ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] + ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] + ldp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] + ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] + +#if IMAGE_BL31 && RAS_EXTENSION + /* + * Issue Error Synchronization Barrier to synchronize SErrors before + * exiting EL3. We're running with EAs unmasked, so any synchronized + * errors would be taken immediately; therefore no need to inspect + * DISR_EL1 register. + */ + esb +#endif + exception_return +1: + ret +endfunc neoverse_n1_errata_ic_trap_handler + /* --------------------------------------------- * This function provides neoverse_n1 specific * register information for crash reporting. @@ -496,6 +584,7 @@ func neoverse_n1_cpu_reg_dump ret endfunc neoverse_n1_cpu_reg_dump -declare_cpu_ops neoverse_n1, NEOVERSE_N1_MIDR, \ +declare_cpu_ops_eh neoverse_n1, NEOVERSE_N1_MIDR, \ neoverse_n1_reset_func, \ + neoverse_n1_errata_ic_trap_handler, \ neoverse_n1_core_pwr_dwn diff --git a/lib/cpus/aarch64/neoverse_zeus.S b/lib/cpus/aarch64/neoverse_zeus.S index 3d850137c..44882b459 100644 --- a/lib/cpus/aarch64/neoverse_zeus.S +++ b/lib/cpus/aarch64/neoverse_zeus.S @@ -46,6 +46,16 @@ func neoverse_zeus_errata_report endfunc neoverse_zeus_errata_report #endif +func neoverse_zeus_reset_func + mov x19, x30 + + /* Disable speculative loads */ + msr SSBS, xzr + + isb + ret x19 +endfunc neoverse_zeus_reset_func + /* --------------------------------------------- * This function provides Neoverse-Zeus specific * register information for crash reporting. @@ -66,5 +76,5 @@ func neoverse_zeus_cpu_reg_dump endfunc neoverse_zeus_cpu_reg_dump declare_cpu_ops neoverse_zeus, NEOVERSE_ZEUS_MIDR, \ - CPU_NO_RESET_FUNC, \ + neoverse_zeus_reset_func, \ neoverse_zeus_core_pwr_dwn diff --git a/lib/cpus/aarch64/wa_cve_2017_5715_mmu.S b/lib/cpus/aarch64/wa_cve_2017_5715_mmu.S index 9277cc624..5134ee3f1 100644 --- a/lib/cpus/aarch64/wa_cve_2017_5715_mmu.S +++ b/lib/cpus/aarch64/wa_cve_2017_5715_mmu.S @@ -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 */ @@ -48,7 +48,7 @@ vector_base wa_cve_2017_5715_mmu_vbar ccmp w0, w1, #0, eq /* Static predictor will predict a fall through */ bne 1f - eret + exception_return 1: .endif diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk index 260402351..e3bfc2f2e 100644 --- a/lib/cpus/cpu-ops.mk +++ b/lib/cpus/cpu-ops.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -20,6 +20,10 @@ WORKAROUND_CVE_2017_5715 ?=1 WORKAROUND_CVE_2018_3639 ?=1 DYNAMIC_WORKAROUND_CVE_2018_3639 ?=0 +# Flag to indicate internal or external Last level cache +# By default internal +NEOVERSE_N1_EXTERNAL_LLC ?=0 + # Process SKIP_A57_L1_FLUSH_PWR_DWN flag $(eval $(call assert_boolean,SKIP_A57_L1_FLUSH_PWR_DWN)) $(eval $(call add_define,SKIP_A57_L1_FLUSH_PWR_DWN)) @@ -43,6 +47,9 @@ $(eval $(call add_define,WORKAROUND_CVE_2018_3639)) $(eval $(call assert_boolean,DYNAMIC_WORKAROUND_CVE_2018_3639)) $(eval $(call add_define,DYNAMIC_WORKAROUND_CVE_2018_3639)) +$(eval $(call assert_boolean,NEOVERSE_N1_EXTERNAL_LLC)) +$(eval $(call add_define,NEOVERSE_N1_EXTERNAL_LLC)) + ifneq (${DYNAMIC_WORKAROUND_CVE_2018_3639},0) ifeq (${WORKAROUND_CVE_2018_3639},0) $(error "Error: WORKAROUND_CVE_2018_3639 must be 1 if DYNAMIC_WORKAROUND_CVE_2018_3639 is 1") @@ -234,9 +241,13 @@ ERRATA_A76_1275112 ?=0 # only to revision <= r3p0 of the Cortex A76 cpu. ERRATA_A76_1286807 ?=0 +# Flag to apply erratum 1688305 workaround during reset. This erratum applies +# to revisions r0p0 - r1p0 of the Hercules cpu. +ERRATA_HERCULES_1688305 ?=0 + # Flag to apply T32 CLREX workaround during reset. This erratum applies # only to r0p0 and r1p0 of the Neoverse N1 cpu. -ERRATA_N1_1043202 ?=1 +ERRATA_N1_1043202 ?=0 # Flag to apply erratum 1073348 workaround during reset. This erratum applies # only to revision r0p0 and r1p0 of the Neoverse N1 cpu. @@ -276,7 +287,11 @@ ERRATA_N1_1275112 ?=0 # Flag to apply erratum 1315703 workaround during reset. This erratum applies # to revisions before r3p1 of the Neoverse N1 cpu. -ERRATA_N1_1315703 ?=1 +ERRATA_N1_1315703 ?=0 + +# Flag to apply erratum 1542419 workaround during reset. This erratum applies +# to revisions r3p0 - r4p0 of the Neoverse N1 cpu. +ERRATA_N1_1542419 ?=0 # Flag to apply DSU erratum 798953. This erratum applies to DSUs revision r0p0. # Applying the workaround results in higher DSU power consumption on idle. @@ -463,6 +478,10 @@ $(eval $(call add_define,ERRATA_A76_1275112)) $(eval $(call assert_boolean,ERRATA_A76_1286807)) $(eval $(call add_define,ERRATA_A76_1286807)) +# Process ERRATA_HERCULES_1688305 flag +$(eval $(call assert_boolean,ERRATA_HERCULES_1688305)) +$(eval $(call add_define,ERRATA_HERCULES_1688305)) + # Process ERRATA_N1_1043202 flag $(eval $(call assert_boolean,ERRATA_N1_1043202)) $(eval $(call add_define,ERRATA_N1_1043202)) @@ -507,6 +526,10 @@ $(eval $(call add_define,ERRATA_N1_1275112)) $(eval $(call assert_boolean,ERRATA_N1_1315703)) $(eval $(call add_define,ERRATA_N1_1315703)) +# Process ERRATA_N1_1542419 flag +$(eval $(call assert_boolean,ERRATA_N1_1542419)) +$(eval $(call add_define,ERRATA_N1_1542419)) + # Process ERRATA_DSU_798953 flag $(eval $(call assert_boolean,ERRATA_DSU_798953)) $(eval $(call add_define,ERRATA_DSU_798953)) diff --git a/lib/debugfs/blobs.h b/lib/debugfs/blobs.h new file mode 100644 index 000000000..54ca9f75d --- /dev/null +++ b/lib/debugfs/blobs.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "dev.h" + +static const dirtab_t blobtab[] = { + {"ctl", DEV_ROOT_QBLOBCTL, 0, O_READ}, + {"fip.bin", DEV_ROOT_QBLOBCTL + 1, 0x100000, O_READ, (void *)0x8000000} +}; diff --git a/lib/debugfs/debugfs.mk b/lib/debugfs/debugfs.mk new file mode 100644 index 000000000..138fc72a1 --- /dev/null +++ b/lib/debugfs/debugfs.mk @@ -0,0 +1,13 @@ +# +# Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +DEBUGFS_SRCS := $(addprefix lib/debugfs/, \ + dev.c \ + devc.c \ + devroot.c \ + devfip.c) + +DEBUGFS_SRCS += lib/debugfs/debugfs_smc.c diff --git a/lib/debugfs/debugfs_smc.c b/lib/debugfs/debugfs_smc.c new file mode 100644 index 000000000..400c166d7 --- /dev/null +++ b/lib/debugfs/debugfs_smc.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +#include <lib/debugfs.h> +#include <lib/smccc.h> +#include <lib/spinlock.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <smccc_helpers.h> + +#define MAX_PATH_LEN 256 + +#define MOUNT 0 +#define CREATE 1 +#define OPEN 2 +#define CLOSE 3 +#define READ 4 +#define WRITE 5 +#define SEEK 6 +#define BIND 7 +#define STAT 8 +#define INIT 10 +#define VERSION 11 + +/* This is the virtual address to which we map the NS shared buffer */ +#define DEBUGFS_SHARED_BUF_VIRT ((void *)0x81000000U) + +static union debugfs_parms { + struct { + char fname[MAX_PATH_LEN]; + } open; + + struct { + char srv[MAX_PATH_LEN]; + char where[MAX_PATH_LEN]; + char spec[MAX_PATH_LEN]; + } mount; + + struct { + char path[MAX_PATH_LEN]; + dir_t dir; + } stat; + + struct { + char oldpath[MAX_PATH_LEN]; + char newpath[MAX_PATH_LEN]; + } bind; +} parms; + +/* debugfs_access_lock protects shared buffer and internal */ +/* FS functions from concurrent acccesses. */ +static spinlock_t debugfs_access_lock; + +static bool debugfs_initialized; + +uintptr_t debugfs_smc_handler(unsigned int smc_fid, + u_register_t cmd, + u_register_t arg2, + u_register_t arg3, + u_register_t arg4, + void *cookie, + void *handle, + u_register_t flags) +{ + int64_t smc_ret = DEBUGFS_E_INVALID_PARAMS, smc_resp = 0; + int ret; + + /* Allow calls from non-secure only */ + if (is_caller_secure(flags)) { + SMC_RET1(handle, DEBUGFS_E_DENIED); + } + + /* Expect a SiP service fast call */ + if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) || + (GET_SMC_OEN(smc_fid) != OEN_SIP_START)) { + SMC_RET1(handle, SMC_UNK); + } + + /* Truncate parameters if 32b SMC convention call */ + if (GET_SMC_CC(smc_fid) == SMC_32) { + arg2 &= 0xffffffff; + arg3 &= 0xffffffff; + arg4 &= 0xffffffff; + } + + spin_lock(&debugfs_access_lock); + + if (debugfs_initialized == true) { + /* Copy NS shared buffer to internal secure location */ + memcpy(&parms, (void *)DEBUGFS_SHARED_BUF_VIRT, + sizeof(union debugfs_parms)); + } + + switch (cmd) { + case INIT: + if (debugfs_initialized == false) { + /* TODO: check PA validity e.g. whether */ + /* it is an NS region. */ + ret = mmap_add_dynamic_region(arg2, + (uintptr_t)DEBUGFS_SHARED_BUF_VIRT, + PAGE_SIZE_4KB, + MT_MEMORY | MT_RW | MT_NS); + if (ret == 0) { + debugfs_initialized = true; + smc_ret = SMC_OK; + smc_resp = 0; + } + } + break; + + case VERSION: + smc_ret = SMC_OK; + smc_resp = DEBUGFS_VERSION; + break; + + case MOUNT: + ret = mount(parms.mount.srv, + parms.mount.where, + parms.mount.spec); + if (ret == 0) { + smc_ret = SMC_OK; + smc_resp = 0; + } + break; + + case OPEN: + ret = open(parms.open.fname, arg2); + if (ret >= 0) { + smc_ret = SMC_OK; + smc_resp = ret; + } + break; + + case CLOSE: + ret = close(arg2); + if (ret == 0) { + smc_ret = SMC_OK; + smc_resp = 0; + } + break; + + case READ: + ret = read(arg2, DEBUGFS_SHARED_BUF_VIRT, arg3); + if (ret >= 0) { + smc_ret = SMC_OK; + smc_resp = ret; + } + break; + + case SEEK: + ret = seek(arg2, arg3, arg4); + if (ret == 0) { + smc_ret = SMC_OK; + smc_resp = 0; + } + break; + + case BIND: + ret = bind(parms.bind.oldpath, parms.bind.newpath); + if (ret == 0) { + smc_ret = SMC_OK; + smc_resp = 0; + } + break; + + case STAT: + ret = stat(parms.stat.path, &parms.stat.dir); + if (ret == 0) { + memcpy((void *)DEBUGFS_SHARED_BUF_VIRT, &parms, + sizeof(union debugfs_parms)); + smc_ret = SMC_OK; + smc_resp = 0; + } + break; + + /* Not implemented */ + case CREATE: + /* Intentional fall-through */ + + /* Not implemented */ + case WRITE: + /* Intentional fall-through */ + + default: + smc_ret = SMC_UNK; + smc_resp = 0; + } + + spin_unlock(&debugfs_access_lock); + + SMC_RET2(handle, smc_ret, smc_resp); + + /* Not reached */ + return smc_ret; +} + +int debugfs_smc_setup(void) +{ + debugfs_initialized = false; + debugfs_access_lock.lock = 0; + + return 0; +} diff --git a/lib/debugfs/dev.c b/lib/debugfs/dev.c new file mode 100644 index 000000000..0361437b8 --- /dev/null +++ b/lib/debugfs/dev.c @@ -0,0 +1,849 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <cdefs.h> +#include <common/debug.h> +#include <lib/debugfs.h> +#include <string.h> + +#include "dev.h" + +#define NR_MOUNT_POINTS 4 + +struct mount_point { + chan_t *new; + chan_t *old; +}; + +/* This array contains all the available channels of the filesystem. + * A file descriptor is the index of a specific channel in this array. + */ +static chan_t fdset[NR_CHANS]; + +/* This array contains all the available mount points of the filesystem. */ +static struct mount_point mount_points[NR_MOUNT_POINTS]; + +/* This variable stores the channel associated to the root directory. */ +static chan_t slash_channel; + +/* This function creates a channel from a device index and registers + * it to fdset. + */ +static chan_t *create_new_channel(unsigned char index) +{ + chan_t *channel = NULL; + int i; + + for (i = 0; i < NR_CHANS; i++) { + if (fdset[i].index == NODEV) { + channel = &fdset[i]; + channel->index = index; + break; + } + } + + return channel; +} + +/******************************************************************************* + * This function returns a pointer to an existing channel in fdset from a file + * descriptor. + ******************************************************************************/ +static chan_t *fd_to_channel(int fd) +{ + if ((fd < 0) || (fd >= NR_CHANS) || (fdset[fd].index == NODEV)) { + return NULL; + } + + return &fdset[fd]; +} + +/******************************************************************************* + * This function returns a file descriptor from a channel. + * The caller must be sure that the channel is registered in fdset. + ******************************************************************************/ +static int channel_to_fd(chan_t *channel) +{ + return (channel == NULL) ? -1 : (channel - fdset); +} + +/******************************************************************************* + * This function checks the validity of a mode. + ******************************************************************************/ +static bool is_valid_mode(int mode) +{ + if ((mode & O_READ) && (mode & (O_WRITE | O_RDWR))) { + return false; + } + if ((mode & O_WRITE) && (mode & (O_READ | O_RDWR))) { + return false; + } + if ((mode & O_RDWR) && (mode & (O_READ | O_WRITE))) { + return false; + } + + return true; +} + +/******************************************************************************* + * This function extracts the next part of the given path contained and puts it + * in token. It returns a pointer to the remainder of the path. + ******************************************************************************/ +static const char *next(const char *path, char *token) +{ + int index; + const char *cursor; + + while (*path == '/') { + ++path; + } + + index = 0; + cursor = path; + if (*path != '\0') { + while (*cursor != '/' && *cursor != '\0') { + if (index == NAMELEN) { + return NULL; + } + token[index++] = *cursor++; + } + } + token[index] = '\0'; + + return cursor; +} + +/******************************************************************************* + * This function returns the driver index in devtab of the driver + * identified by id. + ******************************************************************************/ +static int get_device_index(int id) +{ + int index; + dev_t * const *dp; + + for (index = 0, dp = devtab; *dp && (*dp)->id != id; ++dp) { + index++; + } + + if (*dp == NULL) { + return -1; + } + + return index; +} + +/******************************************************************************* + * This function clears a given channel fields + ******************************************************************************/ +static void channel_clear(chan_t *channel) +{ + channel->offset = 0; + channel->qid = 0; + channel->index = NODEV; + channel->dev = 0; + channel->mode = 0; +} + +/******************************************************************************* + * This function closes the channel pointed to by c. + ******************************************************************************/ +void channel_close(chan_t *channel) +{ + if (channel != NULL) { + channel_clear(channel); + } +} + +/******************************************************************************* + * This function copies data from src to dst after applying the offset of the + * channel c. nbytes bytes are expected to be copied unless the data goes over + * dst + len. + * It returns the actual number of bytes that were copied. + ******************************************************************************/ +int buf_to_channel(chan_t *channel, void *dst, void *src, int nbytes, long len) +{ + const char *addr = src; + + if ((channel == NULL) || (dst == NULL) || (src == NULL)) { + return 0; + } + + if (channel->offset >= len) { + return 0; + } + + if ((channel->offset + nbytes) > len) { + nbytes = len - channel->offset; + } + + memcpy(dst, addr + channel->offset, nbytes); + + channel->offset += nbytes; + + return nbytes; +} + +/******************************************************************************* + * This function checks whether a channel (identified by its device index and + * qid) is registered as a mount point. + * Returns a pointer to the channel it is mounted to when found, NULL otherwise. + ******************************************************************************/ +static chan_t *mount_point_to_channel(int index, qid_t qid) +{ + chan_t *channel; + struct mount_point *mp; + + for (mp = mount_points; mp < &mount_points[NR_MOUNT_POINTS]; mp++) { + channel = mp->new; + if (channel == NULL) { + continue; + } + + if ((channel->index == index) && (channel->qid == qid)) { + return mp->old; + } + } + + return NULL; +} + +/******************************************************************************* + * This function calls the attach function of the driver identified by id. + ******************************************************************************/ +chan_t *attach(int id, int dev) +{ + /* Get the devtab index for the driver identified by id */ + int index = get_device_index(id); + + if (index < 0) { + return NULL; + } + + return devtab[index]->attach(id, dev); +} + +/******************************************************************************* + * This function is the default implementation of the driver attach function. + * It creates a new channel and returns a pointer to it. + ******************************************************************************/ +chan_t *devattach(int id, int dev) +{ + chan_t *channel; + int index; + + index = get_device_index(id); + if (index < 0) { + return NULL; + } + + channel = create_new_channel(index); + if (channel == NULL) { + return NULL; + } + + channel->dev = dev; + channel->qid = CHDIR; + + return channel; +} + +/******************************************************************************* + * This function returns a channel given a path. + * It goes through the filesystem, from the root namespace ('/') or from a + * device namespace ('#'), switching channel on mount points. + ******************************************************************************/ +chan_t *path_to_channel(const char *path, int mode) +{ + int i, n; + const char *path_next; + chan_t *mnt, *channel; + char elem[NAMELEN]; + + if (path == NULL) { + return NULL; + } + + switch (path[0]) { + case '/': + channel = clone(&slash_channel, NULL); + path_next = path; + break; + case '#': + path_next = next(path + 1, elem); + if (path_next == NULL) { + goto noent; + } + + n = 0; + for (i = 1; (elem[i] >= '0') && (elem[i] <= '9'); i++) { + n += elem[i] - '0'; + } + + if (elem[i] != '\0') { + goto noent; + } + + channel = attach(elem[0], n); + break; + default: + return NULL; + } + + if (channel == NULL) { + return NULL; + } + + for (path_next = next(path_next, elem); *elem; + path_next = next(path_next, elem)) { + if ((channel->qid & CHDIR) == 0) { + goto notfound; + } + + if (devtab[channel->index]->walk(channel, elem) < 0) { + channel_close(channel); + goto notfound; + } + + mnt = mount_point_to_channel(channel->index, channel->qid); + if (mnt != NULL) { + clone(mnt, channel); + } + } + + if (path_next == NULL) { + goto notfound; + } + + /* TODO: check mode */ + return channel; + +notfound: + channel_close(channel); +noent: + return NULL; +} + +/******************************************************************************* + * This function calls the clone function of the driver associated to the + * channel c. + ******************************************************************************/ +chan_t *clone(chan_t *c, chan_t *nc) +{ + return devtab[c->index]->clone(c, nc); +} + +/******************************************************************************* + * This function is the default implementation of the driver clone function. + * It creates a new channel and returns a pointer to it. + * It clones channel into new_channel. + ******************************************************************************/ +chan_t *devclone(chan_t *channel, chan_t *new_channel) +{ + if (channel == NULL) { + return NULL; + } + + if (new_channel == NULL) { + new_channel = create_new_channel(channel->index); + if (new_channel == NULL) { + return NULL; + } + } + + new_channel->qid = channel->qid; + new_channel->dev = channel->dev; + new_channel->mode = channel->mode; + new_channel->offset = channel->offset; + new_channel->index = channel->index; + + return new_channel; +} + +/******************************************************************************* + * This function is the default implementation of the driver walk function. + * It goes through all the elements of tab using the gen function until a match + * is found with name. + * If a match is found, it copies the qid of the new directory. + ******************************************************************************/ +int devwalk(chan_t *channel, const char *name, const dirtab_t *tab, + int ntab, devgen_t *gen) +{ + int i; + dir_t dir; + + if ((channel == NULL) || (name == NULL) || (gen == NULL)) { + return -1; + } + + if ((name[0] == '.') && (name[1] == '\0')) { + return 1; + } + + for (i = 0; ; i++) { + switch ((*gen)(channel, tab, ntab, i, &dir)) { + case 0: + /* Intentional fall-through */ + case -1: + return -1; + case 1: + if (strncmp(name, dir.name, NAMELEN) != 0) { + continue; + } + channel->qid = dir.qid; + return 1; + } + } +} + +/******************************************************************************* + * This is a helper function which exposes the content of a directory, element + * by element. It is meant to be called until the end of the directory is + * reached or an error occurs. + * It returns -1 on error, 0 on end of directory and 1 when a new file is found. + ******************************************************************************/ +int dirread(chan_t *channel, dir_t *dir, const dirtab_t *tab, + int ntab, devgen_t *gen) +{ + int i, ret; + + if ((channel == NULL) || (dir == NULL) || (gen == NULL)) { + return -1; + } + + i = channel->offset/sizeof(dir_t); + ret = (*gen)(channel, tab, ntab, i, dir); + if (ret == 1) { + channel->offset += sizeof(dir_t); + } + + return ret; +} + +/******************************************************************************* + * This function sets the elements of dir. + ******************************************************************************/ +void make_dir_entry(chan_t *channel, dir_t *dir, + const char *name, long length, qid_t qid, unsigned int mode) +{ + if ((channel == NULL) || (dir == NULL) || (name == NULL)) { + return; + } + + strlcpy(dir->name, name, sizeof(dir->name)); + dir->length = length; + dir->qid = qid; + dir->mode = mode; + + if ((qid & CHDIR) != 0) { + dir->mode |= O_DIR; + } + + dir->index = channel->index; + dir->dev = channel->dev; +} + +/******************************************************************************* + * This function is the default implementation of the internal driver gen + * function. + * It copies and formats the information of the nth element of tab into dir. + ******************************************************************************/ +int devgen(chan_t *channel, const dirtab_t *tab, int ntab, int n, dir_t *dir) +{ + const dirtab_t *dp; + + if ((channel == NULL) || (dir == NULL) || (tab == NULL) || + (n >= ntab)) { + return 0; + } + + dp = &tab[n]; + make_dir_entry(channel, dir, dp->name, dp->length, dp->qid, dp->perm); + return 1; +} + +/******************************************************************************* + * This function returns a file descriptor identifying the channel associated to + * the given path. + ******************************************************************************/ +int open(const char *path, int mode) +{ + chan_t *channel; + + if (path == NULL) { + return -1; + } + + if (is_valid_mode(mode) == false) { + return -1; + } + + channel = path_to_channel(path, mode); + + return channel_to_fd(channel); +} + +/******************************************************************************* + * This function closes the channel identified by the file descriptor fd. + ******************************************************************************/ +int close(int fd) +{ + chan_t *channel; + + channel = fd_to_channel(fd); + if (channel == NULL) { + return -1; + } + + channel_close(channel); + return 0; +} + +/******************************************************************************* + * This function is the default implementation of the driver stat function. + * It goes through all the elements of tab using the gen function until a match + * is found with file. + * If a match is found, dir contains the information file. + ******************************************************************************/ +int devstat(chan_t *dirc, const char *file, dir_t *dir, + const dirtab_t *tab, int ntab, devgen_t *gen) +{ + int i, r = 0; + chan_t *c, *mnt; + + if ((dirc == NULL) || (dir == NULL) || (gen == NULL)) { + return -1; + } + + c = path_to_channel(file, O_STAT); + if (c == NULL) { + return -1; + } + + for (i = 0; ; i++) { + switch ((*gen)(dirc, tab, ntab, i, dir)) { + case 0: + /* Intentional fall-through */ + case -1: + r = -1; + goto leave; + case 1: + mnt = mount_point_to_channel(dir->index, dir->qid); + if (mnt != NULL) { + dir->qid = mnt->qid; + dir->index = mnt->index; + } + + if ((dir->qid != c->qid) || (dir->index != c->index)) { + continue; + } + + goto leave; + } + } + +leave: + channel_close(c); + return r; +} + +/******************************************************************************* + * This function calls the stat function of the driver associated to the parent + * directory of the file in path. + * The result is stored in dir. + ******************************************************************************/ +int stat(const char *path, dir_t *dir) +{ + int r; + size_t len; + chan_t *channel; + char *p, dirname[PATHLEN]; + + if ((path == NULL) || (dir == NULL)) { + return -1; + } + + len = strlen(path); + if ((len + 1) > sizeof(dirname)) { + return -1; + } + + memcpy(dirname, path, len); + for (p = dirname + len; p > dirname; --p) { + if (*p != '/') { + break; + } + } + + p = memrchr(dirname, '/', p - dirname); + if (p == NULL) { + return -1; + } + + dirname[p - dirname + 1] = '\0'; + + channel = path_to_channel(dirname, O_STAT); + if (channel == NULL) { + return -1; + } + + r = devtab[channel->index]->stat(channel, path, dir); + channel_close(channel); + + return r; +} + +/******************************************************************************* + * This function calls the read function of the driver associated to fd. + * It fills buf with at most n bytes. + * It returns the number of bytes that were actually read. + ******************************************************************************/ +int read(int fd, void *buf, int n) +{ + chan_t *channel; + + if (buf == NULL) { + return -1; + } + + channel = fd_to_channel(fd); + if (channel == NULL) { + return -1; + } + + if (((channel->qid & CHDIR) != 0) && (n < sizeof(dir_t))) { + return -1; + } + + return devtab[channel->index]->read(channel, buf, n); +} + +/******************************************************************************* + * This function calls the write function of the driver associated to fd. + * It writes at most n bytes of buf. + * It returns the number of bytes that were actually written. + ******************************************************************************/ +int write(int fd, void *buf, int n) +{ + chan_t *channel; + + if (buf == NULL) { + return -1; + } + + channel = fd_to_channel(fd); + if (channel == NULL) { + return -1; + } + + if ((channel->qid & CHDIR) != 0) { + return -1; + } + + return devtab[channel->index]->write(channel, buf, n); +} + +/******************************************************************************* + * This function calls the seek function of the driver associated to fd. + * It applies the offset off according to the strategy whence. + ******************************************************************************/ +int seek(int fd, long off, int whence) +{ + chan_t *channel; + + channel = fd_to_channel(fd); + if (channel == NULL) { + return -1; + } + + if ((channel->qid & CHDIR) != 0) { + return -1; + } + + return devtab[channel->index]->seek(channel, off, whence); +} + +/******************************************************************************* + * This function is the default error implementation of the driver mount + * function. + ******************************************************************************/ +chan_t *deverrmount(chan_t *channel, const char *spec) +{ + return NULL; +} + +/******************************************************************************* + * This function is the default error implementation of the driver write + * function. + ******************************************************************************/ +int deverrwrite(chan_t *channel, void *buf, int n) +{ + return -1; +} + +/******************************************************************************* + * This function is the default error implementation of the driver seek + * function. + ******************************************************************************/ +int deverrseek(chan_t *channel, long off, int whence) +{ + return -1; +} + +/******************************************************************************* + * This function is the default implementation of the driver seek function. + * It applies the offset off according to the strategy whence to the channel c. + ******************************************************************************/ +int devseek(chan_t *channel, long off, int whence) +{ + switch (whence) { + case KSEEK_SET: + channel->offset = off; + break; + case KSEEK_CUR: + channel->offset += off; + break; + case KSEEK_END: + /* Not implemented */ + return -1; + } + + return 0; +} + +/******************************************************************************* + * This function registers the channel associated to the path new as a mount + * point for the channel c. + ******************************************************************************/ +static int add_mount_point(chan_t *channel, const char *new) +{ + int i; + chan_t *cn; + struct mount_point *mp; + + if (new == NULL) { + goto err0; + } + + cn = path_to_channel(new, O_READ); + if (cn == NULL) { + goto err0; + } + + if ((cn->qid & CHDIR) == 0) { + goto err1; + } + + for (i = NR_MOUNT_POINTS - 1; i >= 0; i--) { + mp = &mount_points[i]; + if (mp->new == NULL) { + break; + } + } + + if (i < 0) { + goto err1; + } + + mp->new = cn; + mp->old = channel; + + return 0; + +err1: + channel_close(cn); +err0: + return -1; +} + +/******************************************************************************* + * This function registers the path new as a mount point for the path old. + ******************************************************************************/ +int bind(const char *old, const char *new) +{ + chan_t *channel; + + channel = path_to_channel(old, O_BIND); + if (channel == NULL) { + return -1; + } + + if (add_mount_point(channel, new) < 0) { + channel_close(channel); + return -1; + } + + return 0; +} + +/******************************************************************************* + * This function calls the mount function of the driver associated to the path + * srv. + * It mounts the path srv on the path where. + ******************************************************************************/ +int mount(const char *srv, const char *where, const char *spec) +{ + chan_t *channel, *mount_point_chan; + int ret; + + channel = path_to_channel(srv, O_RDWR); + if (channel == NULL) { + goto err0; + } + + mount_point_chan = devtab[channel->index]->mount(channel, spec); + if (mount_point_chan == NULL) { + goto err1; + } + + ret = add_mount_point(mount_point_chan, where); + if (ret < 0) { + goto err2; + } + + channel_close(channel); + + return 0; + +err2: + channel_close(mount_point_chan); +err1: + channel_close(channel); +err0: + return -1; +} + +/******************************************************************************* + * This function initializes the device environment. + * It creates the '/' channel. + * It links the device drivers to the physical drivers. + ******************************************************************************/ +void debugfs_init(void) +{ + chan_t *channel, *cloned_channel; + + for (channel = fdset; channel < &fdset[NR_CHANS]; channel++) { + channel_clear(channel); + } + + channel = devattach('/', 0); + if (channel == NULL) { + panic(); + } + + cloned_channel = clone(channel, &slash_channel); + if (cloned_channel == NULL) { + panic(); + } + + channel_close(channel); + devlink(); +} + +__dead2 void devpanic(const char *cause) +{ + panic(); +} diff --git a/lib/debugfs/dev.h b/lib/debugfs/dev.h new file mode 100644 index 000000000..c142651c7 --- /dev/null +++ b/lib/debugfs/dev.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef DEV_H +#define DEV_H + +#include <cdefs.h> +#include <lib/debugfs.h> +#include <stddef.h> + +/* FIXME: need configurability */ +#define NR_CHANS 10 +#define NR_CONSS 1 +#define NR_BINDS 4 +#define NR_FILES 18 + +#define NODEV 255 +#define CHDIR (1 << 15) + +#define SYNCDEV 0 +#define SYNCALL 1 + +typedef struct dev dev_t; +typedef struct chan chan_t; +typedef struct dirtab dirtab_t; +typedef int devgen_t(chan_t *, const dirtab_t *, int, int, dir_t *); +typedef struct attr attr_t; + +enum { + DEV_ROOT_QROOT, + DEV_ROOT_QDEV, + DEV_ROOT_QFIP, + DEV_ROOT_QBLOBS, + DEV_ROOT_QBLOBCTL, + DEV_ROOT_QPSCI +}; + +/******************************************************************************* + * This structure contains the necessary information to represent a directory + * of the filesystem. + ******************************************************************************/ +struct dirtab { + char name[NAMELEN]; + qid_t qid; + long length; + unsigned char perm; + void *data; +}; + +/******************************************************************************* + * This structure defines the interface of device drivers. + * Each driver must implement a subset of those functions. + * It is possible to redirect to default implementations defined in dev.c. + ******************************************************************************/ +/* FIXME: comments for the callbacks */ +struct dev { + char id; + int (*stat)(chan_t *c, const char *file, dir_t *dir); + int (*walk)(chan_t *c, const char *name); + int (*read)(chan_t *c, void *buf, int n); + int (*write)(chan_t *c, void *buf, int n); + int (*seek)(chan_t *c, long off, int whence); + chan_t *(*clone)(chan_t *c, chan_t *nc); + chan_t *(*attach)(int id, int dev); + chan_t *(*mount)(chan_t *c, const char *spec); +}; + +/******************************************************************************* + * This structure defines the channel structure. + * A channel is a handle on an element of the filesystem. + ******************************************************************************/ +struct chan { + long offset; + qid_t qid; + unsigned char index; /* device index in devtab */ + unsigned char dev; + unsigned char mode; +}; + +/******************************************************************************* + * This structure defines an abstract argument passed to physical drivers from + * the configuration file. + ******************************************************************************/ +struct attr { + char *key; + char *value; +}; + +chan_t *path_to_channel(const char *path, int mode); +chan_t *clone(chan_t *c, chan_t *nc); +chan_t *attach(int id, int dev); +void channel_close(chan_t *c); +int buf_to_channel(chan_t *c, void *dst, void *src, int nbytes, long len); +int dirread(chan_t *c, dir_t *dir, const dirtab_t *tab, + int ntab, devgen_t *gen); +void make_dir_entry(chan_t *c, dir_t *dir, const char *name, long length, + qid_t qid, unsigned int mode); +void devlink(void); + +chan_t *devattach(int id, int dev); +int devseek(chan_t *c, long off, int whence); +chan_t *devclone(chan_t *c, chan_t *nc); +int devgen(chan_t *c, const dirtab_t *tab, int ntab, int n, dir_t *dir); +int devwalk(chan_t *c, const char *name, const dirtab_t *tab, int ntab, + devgen_t *gen); +int devstat(chan_t *dirc, const char *file, dir_t *dir, + const dirtab_t *tab, int ntab, devgen_t *gen); + +chan_t *deverrmount(chan_t *c, const char *spec); +int deverrwrite(chan_t *c, void *buf, int n); +int deverrseek(chan_t *c, long off, int whence); + +extern dev_t *const devtab[]; + +void __dead2 devpanic(const char *cause); + +#endif /* DEV_H */ diff --git a/lib/debugfs/devc.c b/lib/debugfs/devc.c new file mode 100644 index 000000000..1099a85d8 --- /dev/null +++ b/lib/debugfs/devc.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +typedef struct dev dev_t; + +extern dev_t rootdevtab; +extern dev_t fipdevtab; + +dev_t *const devtab[] = { + &rootdevtab, + &fipdevtab, + 0 +}; + +void devlink(void) +{ +} diff --git a/lib/debugfs/devfip.c b/lib/debugfs/devfip.c new file mode 100644 index 000000000..5581b219f --- /dev/null +++ b/lib/debugfs/devfip.c @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <lib/debugfs.h> +#include <limits.h> +#include <plat/arm/common/plat_arm.h> +#include <stdlib.h> +#include <string.h> +#include <tools_share/firmware_image_package.h> + +#include "dev.h" + +#define NR_FIPS 1 +#define STOC_HEADER (sizeof(fip_toc_header_t)) +#define STOC_ENTRY (sizeof(fip_toc_entry_t)) + +struct fipfile { + chan_t *c; + long offset[NR_FILES]; + long size[NR_FILES]; +}; + +struct fip_entry { + uuid_t uuid; + long long offset_address; + long long size; + long long flags; +}; + +struct uuidnames { + const char name[NAMELEN]; + const uuid_t uuid; +}; + +/******************************************************************************* + * This array links the FIP file names to their UUID. + * The elements are ordered according to the image number stored in + * tbbr_img_def.h, starting at index 1. + * + * TODO: this name to uuid binding will preferably be done using + * the coming Property Access Layer / Firmware CONFiguration feature. + ******************************************************************************/ +static const struct uuidnames uuidnames[] = { + {"", { {0}, {0}, {0}, 0, 0, {0} } }, + {"bl2.bin", UUID_TRUSTED_BOOT_FIRMWARE_BL2}, + {"scp-bl2.bin", UUID_SCP_FIRMWARE_SCP_BL2}, + {"bl31.bin", UUID_EL3_RUNTIME_FIRMWARE_BL31}, + {"bl32.bin", UUID_SECURE_PAYLOAD_BL32}, + {"bl33.bin", UUID_NON_TRUSTED_FIRMWARE_BL33}, + {"tb-fw.crt", UUID_TRUSTED_BOOT_FW_CERT}, + {"trstd-k.crt", UUID_TRUSTED_KEY_CERT}, + {"scp-fw-k.crt", UUID_SCP_FW_KEY_CERT}, + {"soc-fw-k.crt", UUID_SOC_FW_KEY_CERT}, + {"tos-fw-k.crt", UUID_TRUSTED_OS_FW_KEY_CERT}, + {"nt-fw-k.crt", UUID_NON_TRUSTED_FW_KEY_CERT}, + {"scp-fw-c.crt", UUID_SCP_FW_CONTENT_CERT}, + {"soc-fw-c.crt", UUID_SOC_FW_CONTENT_CERT}, + {"tos-fw-c.crt", UUID_TRUSTED_OS_FW_CONTENT_CERT}, + {"nt-fw-c.crt", UUID_NON_TRUSTED_FW_CONTENT_CERT}, + { }, + {"fwu.crt", UUID_TRUSTED_FWU_CERT}, + {"scp-bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U}, + {"bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_BL2U}, + {"ns-bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U}, + {"bl32-xtr1.bin", UUID_SECURE_PAYLOAD_BL32_EXTRA1}, + {"bl32-xtr2.bin", UUID_SECURE_PAYLOAD_BL32_EXTRA2}, + {"hw.cfg", UUID_HW_CONFIG}, + {"tb-fw.cfg", UUID_TB_FW_CONFIG}, + {"soc-fw.cfg", UUID_SOC_FW_CONFIG}, + {"tos-fw.cfg", UUID_TOS_FW_CONFIG}, + {"nt-fw.cfg", UUID_NT_FW_CONFIG}, + {"rot-k.crt", UUID_ROT_KEY_CERT}, + {"nt-k.crt", UUID_NON_TRUSTED_WORLD_KEY_CERT} +}; + +/******************************************************************************* + * This array contains all the available FIP files. + ******************************************************************************/ +static struct fipfile archives[NR_FIPS]; + +/******************************************************************************* + * This variable stores the current number of registered FIP files. + ******************************************************************************/ +static int nfips; + +/******************************************************************************* + * This function parses the ToC of the FIP. + ******************************************************************************/ +static int get_entry(chan_t *c, struct fip_entry *entry) +{ + int n; + + n = devtab[c->index]->read(c, entry, sizeof(struct fip_entry)); + if (n <= 0) { + return n; + } + + if (n != sizeof(struct fip_entry)) { + return -1; + } + + if ((entry->size > LONG_MAX) || (entry->offset_address > LONG_MAX)) { + return -1; + } + + if (entry->size == 0) { + return 0; + } + + return 1; +} + +/******************************************************************************* + * This function exposes the FIP images as files. + ******************************************************************************/ +static int fipgen(chan_t *c, const dirtab_t *tab, int ntab, int n, dir_t *dir) +{ + int i, r; + long off; + chan_t nc; + struct fip_entry entry; + struct fipfile *fip; + static const char unk[] = "unknown"; + + if (c->dev >= nfips) { + panic(); + } + + clone(archives[c->dev].c, &nc); + fip = &archives[nc.dev]; + + off = STOC_HEADER; + for (i = 0; i <= n; i++) { + if (fip->offset[i] == -1) { + return 0; + } + + if (devtab[nc.index]->seek(&nc, off, KSEEK_SET) < 0) { + return -1; + } + + r = get_entry(&nc, &entry); + if (r <= 0) { + return r; + } + + off += sizeof(entry); + } + + for (i = 1; i < NELEM(uuidnames); i++) { + if (memcmp(&uuidnames[i].uuid, + &entry.uuid, sizeof(uuid_t)) == 0) { + break; + } + } + + if (i < NELEM(uuidnames)) { + make_dir_entry(c, dir, uuidnames[i].name, + entry.size, n, O_READ); + } else { + // TODO: set name depending on uuid node value + make_dir_entry(c, dir, unk, entry.size, n, O_READ); + } + + return 1; +} + +static int fipwalk(chan_t *c, const char *name) +{ + return devwalk(c, name, NULL, 0, fipgen); +} + +static int fipstat(chan_t *c, const char *file, dir_t *dir) +{ + return devstat(c, file, dir, NULL, 0, fipgen); +} + +/******************************************************************************* + * This function copies at most n bytes of the FIP image referred by c into + * buf. + ******************************************************************************/ +static int fipread(chan_t *c, void *buf, int n) +{ + long off; + chan_t cs; + struct fipfile *fip; + long size; + + /* Only makes sense when using debug language */ + assert(c->qid != CHDIR); + + if ((c->dev >= nfips) || ((c->qid & CHDIR) != 0)) { + panic(); + } + + fip = &archives[c->dev]; + + if ((c->qid >= NR_FILES) || (fip->offset[c->qid] < 0)) { + panic(); + } + + clone(fip->c, &cs); + + size = fip->size[c->qid]; + if (c->offset >= size) { + return 0; + } + + if (n < 0) { + return -1; + } + + if (n > (size - c->offset)) { + n = size - c->offset; + } + + off = fip->offset[c->qid] + c->offset; + if (devtab[cs.index]->seek(&cs, off, KSEEK_SET) < 0) { + return -1; + } + + n = devtab[cs.index]->read(&cs, buf, n); + if (n > 0) { + c->offset += n; + } + + return n; +} + +/******************************************************************************* + * This function parses the FIP spec and registers its images in order to + * expose them as files in the driver namespace. + * It acts as an initialization function for the FIP driver. + * It returns a pointer to the newly created channel. + ******************************************************************************/ +static chan_t *fipmount(chan_t *c, const char *spec) +{ + int r, n, t; + chan_t *cspec; + uint32_t hname; + struct fip_entry entry; + struct fipfile *fip; + dir_t dir; + + if (nfips == NR_FIPS) { + return NULL; + } + + fip = &archives[nfips]; + + for (n = 0; n < NR_FILES; n++) { + fip->offset[n] = -1; + } + + cspec = path_to_channel(spec, O_READ); + if (cspec == NULL) { + return NULL; + } + + fip->c = cspec; + + r = devtab[cspec->index]->read(cspec, &hname, sizeof(hname)); + if (r < 0) { + goto err; + } + + if ((r != sizeof(hname)) || (hname != TOC_HEADER_NAME)) { + goto err; + } + + if (stat(spec, &dir) < 0) { + goto err; + } + + t = cspec->index; + if (devtab[t]->seek(cspec, STOC_HEADER, KSEEK_SET) < 0) { + goto err; + } + + for (n = 0; n < NR_FILES; n++) { + switch (get_entry(cspec, &entry)) { + case 0: + return attach('F', nfips++); + case -1: + goto err; + default: + if ((entry.offset_address + entry.size) > dir.length) { + goto err; + } + + fip->offset[n] = entry.offset_address; + fip->size[n] = entry.size; + break; + } + } + +err: + channel_close(cspec); + return NULL; +} + +const dev_t fipdevtab = { + .id = 'F', + .stat = fipstat, + .clone = devclone, + .attach = devattach, + .walk = fipwalk, + .read = fipread, + .write = deverrwrite, + .mount = fipmount, + .seek = devseek +}; + diff --git a/lib/debugfs/devroot.c b/lib/debugfs/devroot.c new file mode 100644 index 000000000..9dd6c92ef --- /dev/null +++ b/lib/debugfs/devroot.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <common/debug.h> +#include <lib/debugfs.h> + +#include "blobs.h" +#include "dev.h" + +/******************************************************************************* + * This array contains the directories available from the root directory. + ******************************************************************************/ +static const dirtab_t dirtab[] = { + {"dev", CHDIR | DEV_ROOT_QDEV, 0, O_READ}, + {"blobs", CHDIR | DEV_ROOT_QBLOBS, 0, O_READ}, + {"fip", CHDIR | DEV_ROOT_QFIP, 0, O_READ} +}; + +static const dirtab_t devfstab[] = { +}; + +/******************************************************************************* + * This function exposes the elements of the root directory. + * It also exposes the content of the dev and blobs directories. + ******************************************************************************/ +static int rootgen(chan_t *channel, const dirtab_t *tab, int ntab, + int n, dir_t *dir) +{ + switch (channel->qid & ~CHDIR) { + case DEV_ROOT_QROOT: + tab = dirtab; + ntab = NELEM(dirtab); + break; + case DEV_ROOT_QDEV: + tab = devfstab; + ntab = NELEM(devfstab); + break; + case DEV_ROOT_QBLOBS: + tab = blobtab; + ntab = NELEM(blobtab); + break; + default: + return 0; + } + + return devgen(channel, tab, ntab, n, dir); +} + +static int rootwalk(chan_t *channel, const char *name) +{ + return devwalk(channel, name, NULL, 0, rootgen); +} + +/******************************************************************************* + * This function copies at most n bytes from the element referred by c into buf. + ******************************************************************************/ +static int rootread(chan_t *channel, void *buf, int size) +{ + const dirtab_t *dp; + dir_t *dir; + + if ((channel->qid & CHDIR) != 0) { + if (size < sizeof(dir_t)) { + return -1; + } + + dir = buf; + return dirread(channel, dir, NULL, 0, rootgen); + } + + /* Only makes sense when using debug language */ + assert(channel->qid != DEV_ROOT_QBLOBCTL); + + dp = &blobtab[channel->qid - DEV_ROOT_QBLOBCTL]; + return buf_to_channel(channel, buf, dp->data, size, dp->length); +} + +static int rootstat(chan_t *channel, const char *file, dir_t *dir) +{ + return devstat(channel, file, dir, NULL, 0, rootgen); +} + +const dev_t rootdevtab = { + .id = '/', + .stat = rootstat, + .clone = devclone, + .attach = devattach, + .walk = rootwalk, + .read = rootread, + .write = deverrwrite, + .mount = deverrmount, + .seek = devseek +}; diff --git a/lib/el3_runtime/aarch32/context_mgmt.c b/lib/el3_runtime/aarch32/context_mgmt.c index a4702fcc6..73d1e354d 100644 --- a/lib/el3_runtime/aarch32/context_mgmt.c +++ b/lib/el3_runtime/aarch32/context_mgmt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -281,10 +281,28 @@ void cm_prepare_el3_exit(uint32_t security_state) * * HDCR.HPMN: Set to value of PMCR.N which is the * architecturally-defined reset value. + * + * HDCR.HLP: Set to one so that event counter + * overflow, that is recorded in PMOVSCLR[0-30], + * occurs on the increment that changes + * PMEVCNTR<n>[63] from 1 to 0, when ARMv8.5-PMU is + * implemented. This bit is RES0 in versions of the + * architecture earlier than ARMv8.5, setting it to 1 + * doesn't have any effect on them. + * This bit is Reserved, UNK/SBZP in ARMv7. + * + * HDCR.HPME: Set to zero to disable EL2 Event + * counters. */ - write_hdcr(HDCR_RESET_VAL | - ((read_pmcr() & PMCR_N_BITS) >> PMCR_N_SHIFT)); - +#if (ARM_ARCH_MAJOR > 7) + write_hdcr((HDCR_RESET_VAL | HDCR_HLP_BIT | + ((read_pmcr() & PMCR_N_BITS) >> + PMCR_N_SHIFT)) & ~HDCR_HPME_BIT); +#else + write_hdcr((HDCR_RESET_VAL | + ((read_pmcr() & PMCR_N_BITS) >> + PMCR_N_SHIFT)) & ~HDCR_HPME_BIT); +#endif /* * Set HSTR to its architectural reset value so that * access to system registers in the cproc=1111 diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S index e6ab19bcc..9bd25bac9 100644 --- a/lib/el3_runtime/aarch64/context.S +++ b/lib/el3_runtime/aarch64/context.S @@ -6,6 +6,7 @@ #include <arch.h> #include <asm_macros.S> +#include <assert_macros.S> #include <context.h> .global el1_sysregs_context_save @@ -14,25 +15,16 @@ .global fpregs_context_save .global fpregs_context_restore #endif -#if CTX_INCLUDE_PAUTH_REGS - .global pauth_context_restore - .global pauth_context_save -#endif -#if ENABLE_PAUTH - .global pauth_load_bl_apiakey -#endif - .global save_gp_registers - .global restore_gp_registers - .global restore_gp_registers_eret + .global save_gp_pmcr_pauth_regs + .global restore_gp_pmcr_pauth_regs .global el3_exit -/* ----------------------------------------------------- - * The following function strictly follows the AArch64 - * PCS to use x9-x17 (temporary caller-saved registers) - * to save EL1 system register context. It assumes that - * 'x0' is pointing to a 'el1_sys_regs' structure where - * the register context will be saved. - * ----------------------------------------------------- +/* ------------------------------------------------------------------ + * The following function strictly follows the AArch64 PCS to use + * x9-x17 (temporary caller-saved registers) to save EL1 system + * register context. It assumes that 'x0' is pointing to a + * 'el1_sys_regs' structure where the register context will be saved. + * ------------------------------------------------------------------ */ func el1_sysregs_context_save @@ -80,9 +72,6 @@ func el1_sysregs_context_save mrs x9, vbar_el1 stp x17, x9, [x0, #CTX_CONTEXTIDR_EL1] - mrs x10, pmcr_el0 - str x10, [x0, #CTX_PMCR_EL0] - /* Save AArch32 system registers if the build has instructed so */ #if CTX_INCLUDE_AARCH32_REGS mrs x11, spsr_abt @@ -112,16 +101,27 @@ func el1_sysregs_context_save str x14, [x0, #CTX_CNTKCTL_EL1] #endif + /* Save MTE system registers if the build has instructed so */ +#if CTX_INCLUDE_MTE_REGS + mrs x15, TFSRE0_EL1 + mrs x16, TFSR_EL1 + stp x15, x16, [x0, #CTX_TFSRE0_EL1] + + mrs x9, RGSR_EL1 + mrs x10, GCR_EL1 + stp x9, x10, [x0, #CTX_RGSR_EL1] +#endif + ret endfunc el1_sysregs_context_save -/* ----------------------------------------------------- - * The following function strictly follows the AArch64 - * PCS to use x9-x17 (temporary caller-saved registers) - * to restore EL1 system register context. It assumes - * that 'x0' is pointing to a 'el1_sys_regs' structure - * from where the register context will be restored - * ----------------------------------------------------- +/* ------------------------------------------------------------------ + * The following function strictly follows the AArch64 PCS to use + * x9-x17 (temporary caller-saved registers) to restore EL1 system + * register context. It assumes that 'x0' is pointing to a + * 'el1_sys_regs' structure from where the register context will be + * restored + * ------------------------------------------------------------------ */ func el1_sysregs_context_restore @@ -169,9 +169,6 @@ func el1_sysregs_context_restore msr contextidr_el1, x17 msr vbar_el1, x9 - ldr x10, [x0, #CTX_PMCR_EL0] - msr pmcr_el0, x10 - /* Restore AArch32 system registers if the build has instructed so */ #if CTX_INCLUDE_AARCH32_REGS ldp x11, x12, [x0, #CTX_SPSR_ABT] @@ -199,26 +196,34 @@ func el1_sysregs_context_restore ldr x14, [x0, #CTX_CNTKCTL_EL1] msr cntkctl_el1, x14 #endif + /* Restore MTE system registers if the build has instructed so */ +#if CTX_INCLUDE_MTE_REGS + ldp x11, x12, [x0, #CTX_TFSRE0_EL1] + msr TFSRE0_EL1, x11 + msr TFSR_EL1, x12 + + ldp x13, x14, [x0, #CTX_RGSR_EL1] + msr RGSR_EL1, x13 + msr GCR_EL1, x14 +#endif /* No explict ISB required here as ERET covers it */ ret endfunc el1_sysregs_context_restore -/* ----------------------------------------------------- - * The following function follows the aapcs_64 strictly - * to use x9-x17 (temporary caller-saved registers - * according to AArch64 PCS) to save floating point - * register context. It assumes that 'x0' is pointing to - * a 'fp_regs' structure where the register context will +/* ------------------------------------------------------------------ + * The following function follows the aapcs_64 strictly to use + * x9-x17 (temporary caller-saved registers according to AArch64 PCS) + * to save floating point register context. It assumes that 'x0' is + * pointing to a 'fp_regs' structure where the register context will * be saved. * - * Access to VFP registers will trap if CPTR_EL3.TFP is - * set. However currently we don't use VFP registers - * nor set traps in Trusted Firmware, and assume it's - * cleared + * Access to VFP registers will trap if CPTR_EL3.TFP is set. + * However currently we don't use VFP registers nor set traps in + * Trusted Firmware, and assume it's cleared. * * TODO: Revisit when VFP is used in secure world - * ----------------------------------------------------- + * ------------------------------------------------------------------ */ #if CTX_INCLUDE_FPREGS func fpregs_context_save @@ -252,21 +257,19 @@ func fpregs_context_save ret endfunc fpregs_context_save -/* ----------------------------------------------------- - * The following function follows the aapcs_64 strictly - * to use x9-x17 (temporary caller-saved registers - * according to AArch64 PCS) to restore floating point - * register context. It assumes that 'x0' is pointing to - * a 'fp_regs' structure from where the register context +/* ------------------------------------------------------------------ + * The following function follows the aapcs_64 strictly to use x9-x17 + * (temporary caller-saved registers according to AArch64 PCS) to + * restore floating point register context. It assumes that 'x0' is + * pointing to a 'fp_regs' structure from where the register context * will be restored. * - * Access to VFP registers will trap if CPTR_EL3.TFP is - * set. However currently we don't use VFP registers - * nor set traps in Trusted Firmware, and assume it's - * cleared + * Access to VFP registers will trap if CPTR_EL3.TFP is set. + * However currently we don't use VFP registers nor set traps in + * Trusted Firmware, and assume it's cleared. * * TODO: Revisit when VFP is used in secure world - * ----------------------------------------------------- + * ------------------------------------------------------------------ */ func fpregs_context_restore ldp q0, q1, [x0, #CTX_FP_Q0] @@ -306,109 +309,23 @@ func fpregs_context_restore endfunc fpregs_context_restore #endif /* CTX_INCLUDE_FPREGS */ -#if CTX_INCLUDE_PAUTH_REGS -/* ----------------------------------------------------- - * The following function strictly follows the AArch64 - * PCS to use x9-x17 (temporary caller-saved registers) - * to save the ARMv8.3-PAuth register context. It assumes - * that 'sp' is pointing to a 'cpu_context_t' structure - * to where the register context will be saved. - * ----------------------------------------------------- - */ -func pauth_context_save - add x11, sp, #CTX_PAUTH_REGS_OFFSET - - mrs x9, APIAKeyLo_EL1 - mrs x10, APIAKeyHi_EL1 - stp x9, x10, [x11, #CTX_PACIAKEY_LO] - - mrs x9, APIBKeyLo_EL1 - mrs x10, APIBKeyHi_EL1 - stp x9, x10, [x11, #CTX_PACIBKEY_LO] - - mrs x9, APDAKeyLo_EL1 - mrs x10, APDAKeyHi_EL1 - stp x9, x10, [x11, #CTX_PACDAKEY_LO] - - mrs x9, APDBKeyLo_EL1 - mrs x10, APDBKeyHi_EL1 - stp x9, x10, [x11, #CTX_PACDBKEY_LO] - - mrs x9, APGAKeyLo_EL1 - mrs x10, APGAKeyHi_EL1 - stp x9, x10, [x11, #CTX_PACGAKEY_LO] - - ret -endfunc pauth_context_save - -/* ----------------------------------------------------- - * The following function strictly follows the AArch64 - * PCS to use x9-x17 (temporary caller-saved registers) - * to restore the ARMv8.3-PAuth register context. It assumes - * that 'sp' is pointing to a 'cpu_context_t' structure - * from where the register context will be restored. - * ----------------------------------------------------- - */ -func pauth_context_restore - add x11, sp, #CTX_PAUTH_REGS_OFFSET - - ldp x9, x10, [x11, #CTX_PACIAKEY_LO] - msr APIAKeyLo_EL1, x9 - msr APIAKeyHi_EL1, x10 - - ldp x9, x10, [x11, #CTX_PACIBKEY_LO] - msr APIBKeyLo_EL1, x9 - msr APIBKeyHi_EL1, x10 - - ldp x9, x10, [x11, #CTX_PACDAKEY_LO] - msr APDAKeyLo_EL1, x9 - msr APDAKeyHi_EL1, x10 - - ldp x9, x10, [x11, #CTX_PACDBKEY_LO] - msr APDBKeyLo_EL1, x9 - msr APDBKeyHi_EL1, x10 - - ldp x9, x10, [x11, #CTX_PACGAKEY_LO] - msr APGAKeyLo_EL1, x9 - msr APGAKeyHi_EL1, x10 - - ret -endfunc pauth_context_restore -#endif /* CTX_INCLUDE_PAUTH_REGS */ - -/* ----------------------------------------------------- - * The following function strictly follows the AArch64 - * PCS to use x9-x17 (temporary caller-saved registers) - * to load the APIA key used by the firmware. - * ----------------------------------------------------- - */ -#if ENABLE_PAUTH -func pauth_load_bl_apiakey - /* Load instruction key A used by the Trusted Firmware. */ - adrp x11, plat_apiakey - add x11, x11, :lo12:plat_apiakey - ldp x9, x10, [x11, #0] - - msr APIAKeyLo_EL1, x9 - msr APIAKeyHi_EL1, x10 - - ret -endfunc pauth_load_bl_apiakey -#endif /* ENABLE_PAUTH */ - -/* ----------------------------------------------------- - * The following functions are used to save and restore - * all the general purpose registers. Ideally we would - * only save and restore the callee saved registers when - * a world switch occurs but that type of implementation - * is more complex. So currently we will always save and - * restore these registers on entry and exit of EL3. - * These are not macros to ensure their invocation fits - * within the 32 instructions per exception vector. +/* ------------------------------------------------------------------ + * The following function is used to save and restore all the general + * purpose and ARMv8.3-PAuth (if enabled) registers. + * It also checks if Secure Cycle Counter is not disabled in MDCR_EL3 + * when ARMv8.5-PMU is implemented, and if called from Non-secure + * state saves PMCR_EL0 and disables Cycle Counter. + * + * Ideally we would only save and restore the callee saved registers + * when a world switch occurs but that type of implementation is more + * complex. So currently we will always save and restore these + * registers on entry and exit of EL3. + * These are not macros to ensure their invocation fits within the 32 + * instructions per exception vector. * clobbers: x18 - * ----------------------------------------------------- + * ------------------------------------------------------------------ */ -func save_gp_registers +func save_gp_pmcr_pauth_regs stp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] stp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] stp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] @@ -426,15 +343,114 @@ func save_gp_registers stp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28] mrs x18, sp_el0 str x18, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_SP_EL0] + + /* ---------------------------------------------------------- + * Check if earlier initialization MDCR_EL3.SCCD to 1 failed, + * meaning that ARMv8-PMU is not implemented and PMCR_EL0 + * should be saved in non-secure context. + * ---------------------------------------------------------- + */ + mrs x9, mdcr_el3 + tst x9, #MDCR_SCCD_BIT + bne 1f + + /* Secure Cycle Counter is not disabled */ + mrs x9, pmcr_el0 + + /* Check caller's security state */ + mrs x10, scr_el3 + tst x10, #SCR_NS_BIT + beq 2f + + /* Save PMCR_EL0 if called from Non-secure state */ + str x9, [sp, #CTX_EL3STATE_OFFSET + CTX_PMCR_EL0] + + /* Disable cycle counter when event counting is prohibited */ +2: orr x9, x9, #PMCR_EL0_DP_BIT + msr pmcr_el0, x9 + isb +1: +#if CTX_INCLUDE_PAUTH_REGS + /* ---------------------------------------------------------- + * Save the ARMv8.3-PAuth keys as they are not banked + * by exception level + * ---------------------------------------------------------- + */ + add x19, sp, #CTX_PAUTH_REGS_OFFSET + + mrs x20, APIAKeyLo_EL1 /* x21:x20 = APIAKey */ + mrs x21, APIAKeyHi_EL1 + mrs x22, APIBKeyLo_EL1 /* x23:x22 = APIBKey */ + mrs x23, APIBKeyHi_EL1 + mrs x24, APDAKeyLo_EL1 /* x25:x24 = APDAKey */ + mrs x25, APDAKeyHi_EL1 + mrs x26, APDBKeyLo_EL1 /* x27:x26 = APDBKey */ + mrs x27, APDBKeyHi_EL1 + mrs x28, APGAKeyLo_EL1 /* x29:x28 = APGAKey */ + mrs x29, APGAKeyHi_EL1 + + stp x20, x21, [x19, #CTX_PACIAKEY_LO] + stp x22, x23, [x19, #CTX_PACIBKEY_LO] + stp x24, x25, [x19, #CTX_PACDAKEY_LO] + stp x26, x27, [x19, #CTX_PACDBKEY_LO] + stp x28, x29, [x19, #CTX_PACGAKEY_LO] +#endif /* CTX_INCLUDE_PAUTH_REGS */ + ret -endfunc save_gp_registers +endfunc save_gp_pmcr_pauth_regs -/* ----------------------------------------------------- - * This function restores all general purpose registers except x30 from the - * CPU context. x30 register must be explicitly restored by the caller. - * ----------------------------------------------------- +/* ------------------------------------------------------------------ + * This function restores ARMv8.3-PAuth (if enabled) and all general + * purpose registers except x30 from the CPU context. + * x30 register must be explicitly restored by the caller. + * ------------------------------------------------------------------ */ -func restore_gp_registers +func restore_gp_pmcr_pauth_regs +#if CTX_INCLUDE_PAUTH_REGS + /* Restore the ARMv8.3 PAuth keys */ + add x10, sp, #CTX_PAUTH_REGS_OFFSET + + ldp x0, x1, [x10, #CTX_PACIAKEY_LO] /* x1:x0 = APIAKey */ + ldp x2, x3, [x10, #CTX_PACIBKEY_LO] /* x3:x2 = APIBKey */ + ldp x4, x5, [x10, #CTX_PACDAKEY_LO] /* x5:x4 = APDAKey */ + ldp x6, x7, [x10, #CTX_PACDBKEY_LO] /* x7:x6 = APDBKey */ + ldp x8, x9, [x10, #CTX_PACGAKEY_LO] /* x9:x8 = APGAKey */ + + msr APIAKeyLo_EL1, x0 + msr APIAKeyHi_EL1, x1 + msr APIBKeyLo_EL1, x2 + msr APIBKeyHi_EL1, x3 + msr APDAKeyLo_EL1, x4 + msr APDAKeyHi_EL1, x5 + msr APDBKeyLo_EL1, x6 + msr APDBKeyHi_EL1, x7 + msr APGAKeyLo_EL1, x8 + msr APGAKeyHi_EL1, x9 +#endif /* CTX_INCLUDE_PAUTH_REGS */ + + /* ---------------------------------------------------------- + * Restore PMCR_EL0 when returning to Non-secure state if + * Secure Cycle Counter is not disabled in MDCR_EL3 when + * ARMv8.5-PMU is implemented. + * ---------------------------------------------------------- + */ + mrs x0, scr_el3 + tst x0, #SCR_NS_BIT + beq 2f + + /* ---------------------------------------------------------- + * Back to Non-secure state. + * Check if earlier initialization MDCR_EL3.SCCD to 1 failed, + * meaning that ARMv8-PMU is not implemented and PMCR_EL0 + * should be restored from non-secure context. + * ---------------------------------------------------------- + */ + mrs x0, mdcr_el3 + tst x0, #MDCR_SCCD_BIT + bne 2f + ldr x0, [sp, #CTX_EL3STATE_OFFSET + CTX_PMCR_EL0] + msr pmcr_el0, x0 +2: ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] ldp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] @@ -453,49 +469,35 @@ func restore_gp_registers msr sp_el0, x28 ldp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28] ret -endfunc restore_gp_registers +endfunc restore_gp_pmcr_pauth_regs -/* ----------------------------------------------------- - * Restore general purpose registers (including x30), and exit EL3 via ERET to - * a lower exception level. - * ----------------------------------------------------- - */ -func restore_gp_registers_eret - bl restore_gp_registers - ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] - -#if IMAGE_BL31 && RAS_EXTENSION - /* - * Issue Error Synchronization Barrier to synchronize SErrors before - * exiting EL3. We're running with EAs unmasked, so any synchronized - * errors would be taken immediately; therefore no need to inspect - * DISR_EL1 register. - */ - esb -#endif - eret -endfunc restore_gp_registers_eret - -/* ----------------------------------------------------- - * This routine assumes that the SP_EL3 is pointing to - * a valid context structure from where the gp regs and - * other special registers can be retrieved. - * ----------------------------------------------------- +/* ------------------------------------------------------------------ + * This routine assumes that the SP_EL3 is pointing to a valid + * context structure from where the gp regs and other special + * registers can be retrieved. + * ------------------------------------------------------------------ */ func el3_exit - /* ----------------------------------------------------- - * Save the current SP_EL0 i.e. the EL3 runtime stack - * which will be used for handling the next SMC. Then - * switch to SP_EL3 - * ----------------------------------------------------- +#if ENABLE_ASSERTIONS + /* el3_exit assumes SP_EL0 on entry */ + mrs x17, spsel + cmp x17, #MODE_SP_EL0 + ASM_ASSERT(eq) +#endif + + /* ---------------------------------------------------------- + * Save the current SP_EL0 i.e. the EL3 runtime stack which + * will be used for handling the next SMC. + * Then switch to SP_EL3. + * ---------------------------------------------------------- */ mov x17, sp - msr spsel, #1 + msr spsel, #MODE_SP_ELX str x17, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] - /* ----------------------------------------------------- + /* ---------------------------------------------------------- * Restore SPSR_EL3, ELR_EL3 and SCR_EL3 prior to ERET - * ----------------------------------------------------- + * ---------------------------------------------------------- */ ldr x18, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3] ldp x16, x17, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] @@ -504,19 +506,34 @@ func el3_exit msr elr_el3, x17 #if IMAGE_BL31 && DYNAMIC_WORKAROUND_CVE_2018_3639 - /* Restore mitigation state as it was on entry to EL3 */ + /* ---------------------------------------------------------- + * Restore mitigation state as it was on entry to EL3 + * ---------------------------------------------------------- + */ ldr x17, [sp, #CTX_CVE_2018_3639_OFFSET + CTX_CVE_2018_3639_DISABLE] - cmp x17, xzr - beq 1f + cbz x17, 1f blr x17 1: #endif + /* ---------------------------------------------------------- + * Restore general purpose (including x30), PMCR_EL0 and + * ARMv8.3-PAuth registers. + * Exit EL3 via ERET to a lower exception level. + * ---------------------------------------------------------- + */ + bl restore_gp_pmcr_pauth_regs + ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] -#if CTX_INCLUDE_PAUTH_REGS - /* Restore ARMv8.3-PAuth registers */ - bl pauth_context_restore +#if IMAGE_BL31 && RAS_EXTENSION + /* ---------------------------------------------------------- + * Issue Error Synchronization Barrier to synchronize SErrors + * before exiting EL3. We're running with EAs unmasked, so + * any synchronized errors would be taken immediately; + * therefore no need to inspect DISR_EL1 register. + * ---------------------------------------------------------- + */ + esb #endif + exception_return - /* Restore saved general purpose registers and return */ - b restore_gp_registers_eret endfunc el3_exit diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c index 05ba5ed6c..dc4717abe 100644 --- a/lib/el3_runtime/aarch64/context_mgmt.c +++ b/lib/el3_runtime/aarch64/context_mgmt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -66,10 +66,10 @@ void __init cm_init(void) void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep) { unsigned int security_state; - uint32_t scr_el3, pmcr_el0; + u_register_t scr_el3; el3_state_t *state; gp_regs_t *gp_regs; - unsigned long sctlr_elx, actlr_elx; + u_register_t sctlr_elx, actlr_elx; assert(ctx != NULL); @@ -87,7 +87,7 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep) * the required value depending on the state of the SPSR_EL3 and the * Security state and entrypoint attributes of the next EL. */ - scr_el3 = (uint32_t)read_scr(); + scr_el3 = read_scr(); scr_el3 &= ~(SCR_NS_BIT | SCR_RW_BIT | SCR_FIQ_BIT | SCR_IRQ_BIT | SCR_ST_BIT | SCR_HCE_BIT); /* @@ -137,17 +137,30 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep) scr_el3 |= SCR_API_BIT | SCR_APK_BIT; #endif /* !CTX_INCLUDE_PAUTH_REGS */ - unsigned int mte = get_armv8_5_mte_support(); - /* - * Enable MTE support unilaterally for normal world if the CPU supports - * it. + * Enable MTE support. Support is enabled unilaterally for the normal + * world, and only for the secure world when CTX_INCLUDE_MTE_REGS is + * set. */ - if (mte != MTE_UNIMPLEMENTED) { - if (security_state == NON_SECURE) { - scr_el3 |= SCR_ATA_BIT; - } +#if CTX_INCLUDE_MTE_REGS + assert(get_armv8_5_mte_support() == MTE_IMPLEMENTED_ELX); + scr_el3 |= SCR_ATA_BIT; +#else + unsigned int mte = get_armv8_5_mte_support(); + if (mte == MTE_IMPLEMENTED_EL0) { + /* + * Can enable MTE across both worlds as no MTE registers are + * used + */ + scr_el3 |= SCR_ATA_BIT; + } else if (mte == MTE_IMPLEMENTED_ELX && security_state == NON_SECURE) { + /* + * Can only enable MTE in Non-Secure world without register + * saving + */ + scr_el3 |= SCR_ATA_BIT; } +#endif #ifdef IMAGE_BL31 /* @@ -168,6 +181,16 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep) scr_el3 |= SCR_HCE_BIT; } + /* Enable S-EL2 if the next EL is EL2 and security state is secure */ + if ((security_state == SECURE) && (GET_EL(ep->spsr) == MODE_EL2)) { + if (GET_RW(ep->spsr) != MODE_RW_64) { + ERROR("S-EL2 can not be used in AArch32."); + panic(); + } + + scr_el3 |= SCR_EEL2_BIT; + } + /* * Initialise SCTLR_EL1 to the reset value corresponding to the target * execution state setting all fields rather than relying of the hw. @@ -225,31 +248,10 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep) actlr_elx = read_actlr_el1(); write_ctx_reg((get_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx)); - if (security_state == SECURE) { - /* - * Initialise PMCR_EL0 for secure context only, setting all - * fields rather than relying on hw. Some fields are - * architecturally UNKNOWN on reset. - * - * PMCR_EL0.LC: Set to one so that cycle counter overflow, that - * is recorded in PMOVSCLR_EL0[31], occurs on the increment - * that changes PMCCNTR_EL0[63] from 1 to 0. - * - * PMCR_EL0.DP: Set to one so that the cycle counter, - * PMCCNTR_EL0 does not count when event counting is prohibited. - * - * PMCR_EL0.X: Set to zero to disable export of events. - * - * PMCR_EL0.D: Set to zero so that, when enabled, PMCCNTR_EL0 - * counts on every clock cycle. - */ - pmcr_el0 = ((PMCR_EL0_RESET_VAL | PMCR_EL0_LC_BIT - | PMCR_EL0_DP_BIT) - & ~(PMCR_EL0_X_BIT | PMCR_EL0_D_BIT)); - write_ctx_reg(get_sysregs_ctx(ctx), CTX_PMCR_EL0, pmcr_el0); - } - - /* Populate EL3 state so that we've the right context before doing ERET */ + /* + * Populate EL3 state so that we've the right context + * before doing ERET + */ state = get_el3state_ctx(ctx); write_ctx_reg(state, CTX_SCR_EL3, scr_el3); write_ctx_reg(state, CTX_ELR_EL3, ep->pc); @@ -324,7 +326,7 @@ void cm_init_my_context(const entry_point_info_t *ep) ******************************************************************************/ void cm_prepare_el3_exit(uint32_t security_state) { - uint32_t sctlr_elx, scr_el3, mdcr_el2; + u_register_t sctlr_elx, scr_el3, mdcr_el2; cpu_context_t *ctx = cm_get_context(security_state); bool el2_unused = false; uint64_t hcr_el2 = 0U; @@ -332,11 +334,11 @@ void cm_prepare_el3_exit(uint32_t security_state) assert(ctx != NULL); if (security_state == NON_SECURE) { - scr_el3 = (uint32_t)read_ctx_reg(get_el3state_ctx(ctx), + scr_el3 = read_ctx_reg(get_el3state_ctx(ctx), CTX_SCR_EL3); if ((scr_el3 & SCR_HCE_BIT) != 0U) { /* Use SCTLR_EL1.EE value to initialise sctlr_el2 */ - sctlr_elx = (uint32_t)read_ctx_reg(get_sysregs_ctx(ctx), + sctlr_elx = read_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1); sctlr_elx &= SCTLR_EE_BIT; sctlr_elx |= SCTLR_EL2_RES1; @@ -441,6 +443,29 @@ void cm_prepare_el3_exit(uint32_t security_state) * relying on hw. Some fields are architecturally * UNKNOWN on reset. * + * MDCR_EL2.HLP: Set to one so that event counter + * overflow, that is recorded in PMOVSCLR_EL0[0-30], + * occurs on the increment that changes + * PMEVCNTR<n>_EL0[63] from 1 to 0, when ARMv8.5-PMU is + * implemented. This bit is RES0 in versions of the + * architecture earlier than ARMv8.5, setting it to 1 + * doesn't have any effect on them. + * + * MDCR_EL2.TTRF: Set to zero so that access to Trace + * Filter Control register TRFCR_EL1 at EL1 is not + * trapped to EL2. This bit is RES0 in versions of + * the architecture earlier than ARMv8.4. + * + * MDCR_EL2.HPMD: Set to one so that event counting is + * prohibited at EL2. This bit is RES0 in versions of + * the architecture earlier than ARMv8.1, setting it + * to 1 doesn't have any effect on them. + * + * MDCR_EL2.TPMS: Set to zero so that accesses to + * Statistical Profiling control registers from EL1 + * do not trap to EL2. This bit is RES0 when SPE is + * not implemented. + * * MDCR_EL2.TDRA: Set to zero so that Non-secure EL0 and * EL1 System register accesses to the Debug ROM * registers are not trapped to EL2. @@ -469,13 +494,15 @@ void cm_prepare_el3_exit(uint32_t security_state) * MDCR_EL2.HPMN: Set to value of PMCR_EL0.N which is the * architecturally-defined reset value. */ - mdcr_el2 = ((MDCR_EL2_RESET_VAL | - ((read_pmcr_el0() & PMCR_EL0_N_BITS) - >> PMCR_EL0_N_SHIFT)) & - ~(MDCR_EL2_TDRA_BIT | MDCR_EL2_TDOSA_BIT - | MDCR_EL2_TDA_BIT | MDCR_EL2_TDE_BIT - | MDCR_EL2_HPME_BIT | MDCR_EL2_TPM_BIT - | MDCR_EL2_TPMCR_BIT)); + mdcr_el2 = ((MDCR_EL2_RESET_VAL | MDCR_EL2_HLP | + MDCR_EL2_HPMD) | + ((read_pmcr_el0() & PMCR_EL0_N_BITS) + >> PMCR_EL0_N_SHIFT)) & + ~(MDCR_EL2_TTRF | MDCR_EL2_TPMS | + MDCR_EL2_TDRA_BIT | MDCR_EL2_TDOSA_BIT | + MDCR_EL2_TDA_BIT | MDCR_EL2_TDE_BIT | + MDCR_EL2_HPME_BIT | MDCR_EL2_TPM_BIT | + MDCR_EL2_TPMCR_BIT); write_mdcr_el2(mdcr_el2); @@ -591,7 +618,7 @@ void cm_write_scr_el3_bit(uint32_t security_state, { cpu_context_t *ctx; el3_state_t *state; - uint32_t scr_el3; + u_register_t scr_el3; ctx = cm_get_context(security_state); assert(ctx != NULL); @@ -607,9 +634,9 @@ void cm_write_scr_el3_bit(uint32_t security_state, * and set it to its new value. */ state = get_el3state_ctx(ctx); - scr_el3 = (uint32_t)read_ctx_reg(state, CTX_SCR_EL3); + scr_el3 = read_ctx_reg(state, CTX_SCR_EL3); scr_el3 &= ~(1U << bit_pos); - scr_el3 |= value << bit_pos; + scr_el3 |= (u_register_t)value << bit_pos; write_ctx_reg(state, CTX_SCR_EL3, scr_el3); } @@ -617,7 +644,7 @@ void cm_write_scr_el3_bit(uint32_t security_state, * This function retrieves SCR_EL3 member of 'cpu_context' pertaining to the * given security state. ******************************************************************************/ -uint32_t cm_get_scr_el3(uint32_t security_state) +u_register_t cm_get_scr_el3(uint32_t security_state) { cpu_context_t *ctx; el3_state_t *state; @@ -627,7 +654,7 @@ uint32_t cm_get_scr_el3(uint32_t security_state) /* Populate EL3 state so that ERET jumps to the correct entry */ state = get_el3state_ctx(ctx); - return (uint32_t)read_ctx_reg(state, CTX_SCR_EL3); + return read_ctx_reg(state, CTX_SCR_EL3); } /******************************************************************************* diff --git a/lib/extensions/pauth/pauth_helpers.S b/lib/extensions/pauth/pauth_helpers.S new file mode 100644 index 000000000..d483c7df7 --- /dev/null +++ b/lib/extensions/pauth/pauth_helpers.S @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <lib/el3_runtime/cpu_data.h> + + .global pauth_init_enable_el1 + .global pauth_disable_el1 + .global pauth_init_enable_el3 + .global pauth_disable_el3 + .globl pauth_load_bl31_apiakey + .globl pauth_load_bl1_apiakey_enable + +/* ------------------------------------------------------------- + * Program APIAKey_EL1 and enable pointer authentication in EL1 + * ------------------------------------------------------------- + */ +func pauth_init_enable_el1 + stp x29, x30, [sp, #-16]! + + /* Initialize platform key */ + bl plat_init_apkey + + /* Program instruction key A used by the Trusted Firmware */ + msr APIAKeyLo_EL1, x0 + msr APIAKeyHi_EL1, x1 + + /* Enable pointer authentication */ + mrs x0, sctlr_el1 + orr x0, x0, #SCTLR_EnIA_BIT + +#if ENABLE_BTI + /* Enable PAC branch type compatibility */ + bic x0, x0, #(SCTLR_BT0_BIT | SCTLR_BT1_BIT) +#endif + msr sctlr_el1, x0 + isb + + ldp x29, x30, [sp], #16 + ret +endfunc pauth_init_enable_el1 + +/* ------------------------------------------------------------- + * Disable pointer authentication in EL3 + * ------------------------------------------------------------- + */ +func pauth_disable_el1 + mrs x0, sctlr_el1 + bic x0, x0, #SCTLR_EnIA_BIT + msr sctlr_el1, x0 + isb + ret +endfunc pauth_disable_el1 + +/* ------------------------------------------------------------- + * Program APIAKey_EL1 and enable pointer authentication in EL3 + * ------------------------------------------------------------- + */ +func pauth_init_enable_el3 + stp x29, x30, [sp, #-16]! + + /* Initialize platform key */ + bl plat_init_apkey + + /* Program instruction key A used by the Trusted Firmware */ + msr APIAKeyLo_EL1, x0 + msr APIAKeyHi_EL1, x1 + + /* Enable pointer authentication */ + mrs x0, sctlr_el3 + orr x0, x0, #SCTLR_EnIA_BIT + +#if ENABLE_BTI + /* Enable PAC branch type compatibility */ + bic x0, x0, #SCTLR_BT_BIT +#endif + msr sctlr_el3, x0 + isb + + ldp x29, x30, [sp], #16 + ret +endfunc pauth_init_enable_el3 + +/* ------------------------------------------------------------- + * Disable pointer authentication in EL3 + * ------------------------------------------------------------- + */ +func pauth_disable_el3 + mrs x0, sctlr_el3 + bic x0, x0, #SCTLR_EnIA_BIT + msr sctlr_el3, x0 + isb + ret +endfunc pauth_disable_el3 + +/* ------------------------------------------------------------- + * The following functions strictly follow the AArch64 PCS + * to use x9-x17 (temporary caller-saved registers) to load + * the APIAKey_EL1 and enable pointer authentication. + * ------------------------------------------------------------- + */ +func pauth_load_bl31_apiakey + /* tpidr_el3 contains the address of cpu_data structure */ + mrs x9, tpidr_el3 + + /* Load apiakey from cpu_data */ + ldp x10, x11, [x9, #CPU_DATA_APIAKEY_OFFSET] + + /* Program instruction key A */ + msr APIAKeyLo_EL1, x10 + msr APIAKeyHi_EL1, x11 + isb + ret +endfunc pauth_load_bl31_apiakey + +func pauth_load_bl1_apiakey_enable + /* Load instruction key A used by the Trusted Firmware */ + adrp x9, bl1_apiakey + add x9, x9, :lo12:bl1_apiakey + ldp x10, x11, [x9] + + /* Program instruction key A */ + msr APIAKeyLo_EL1, x10 + msr APIAKeyHi_EL1, x11 + + /* Enable pointer authentication */ + mrs x9, sctlr_el3 + orr x9, x9, #SCTLR_EnIA_BIT + +#if ENABLE_BTI + /* Enable PAC branch type compatibility */ + bic x9, x9, #SCTLR_BT_BIT +#endif + msr sctlr_el3, x9 + isb + ret +endfunc pauth_load_bl1_apiakey_enable diff --git a/lib/libc/assert.c b/lib/libc/assert.c index 60f1a8660..49f59db16 100644 --- a/lib/libc/assert.c +++ b/lib/libc/assert.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -18,7 +18,8 @@ */ #if PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_VERBOSE -void __assert(const char *file, unsigned int line, const char *assertion) +void __dead2 __assert(const char *file, unsigned int line, + const char *assertion) { printf("ASSERT: %s:%d:%s\n", file, line, assertion); backtrace("assert"); @@ -26,7 +27,7 @@ void __assert(const char *file, unsigned int line, const char *assertion) plat_panic_handler(); } #elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO -void __assert(const char *file, unsigned int line) +void __dead2 __assert(const char *file, unsigned int line) { printf("ASSERT: %s:%d\n", file, line); backtrace("assert"); @@ -34,7 +35,7 @@ void __assert(const char *file, unsigned int line) plat_panic_handler(); } #else -void __assert(void) +void __dead2 __assert(void) { backtrace("assert"); (void)console_flush(); diff --git a/lib/libc/libc.mk b/lib/libc/libc.mk index e1b5560f8..93d30d035 100644 --- a/lib/libc/libc.mk +++ b/lib/libc/libc.mk @@ -12,6 +12,7 @@ LIBC_SRCS := $(addprefix lib/libc/, \ memcmp.c \ memcpy.c \ memmove.c \ + memrchr.c \ memset.c \ printf.c \ putchar.c \ diff --git a/lib/libc/memrchr.c b/lib/libc/memrchr.c new file mode 100644 index 000000000..01caef3ae --- /dev/null +++ b/lib/libc/memrchr.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <string.h> + +#undef memrchr + +void *memrchr(const void *src, int c, size_t len) +{ + const unsigned char *s = src + (len - 1); + + while (len--) { + if (*s == (unsigned char)c) { + return (void*) s; + } + + s--; + } + + return NULL; +} diff --git a/lib/locks/bakery/bakery_lock_coherent.c b/lib/locks/bakery/bakery_lock_coherent.c index 1634e3af6..748eeddf4 100644 --- a/lib/locks/bakery/bakery_lock_coherent.c +++ b/lib/locks/bakery/bakery_lock_coherent.c @@ -137,10 +137,11 @@ void bakery_lock_get(bakery_lock_t *bakery) } /* - * Lock acquired. Ensure that any reads from a shared resource in the - * critical section read values after the lock is acquired. + * Lock acquired. Ensure that any reads and writes from a shared + * resource in the critical section read/write values after the lock is + * acquired. */ - dmbld(); + dmbish(); } @@ -154,11 +155,14 @@ void bakery_lock_release(bakery_lock_t *bakery) /* * Ensure that other observers see any stores in the critical section - * before releasing the lock. Release the lock by resetting ticket. - * Then signal other waiting contenders. + * before releasing the lock. Also ensure all loads in the critical + * section are complete before releasing the lock. Release the lock by + * resetting ticket. Then signal other waiting contenders. */ - dmbst(); + dmbish(); bakery->lock_data[me] = 0U; + + /* Required to ensure ordering of the following sev */ dsb(); sev(); } diff --git a/lib/locks/bakery/bakery_lock_normal.c b/lib/locks/bakery/bakery_lock_normal.c index f906f51ea..caced8f46 100644 --- a/lib/locks/bakery/bakery_lock_normal.c +++ b/lib/locks/bakery/bakery_lock_normal.c @@ -219,10 +219,11 @@ void bakery_lock_get(bakery_lock_t *lock) } /* - * Lock acquired. Ensure that any reads from a shared resource in the - * critical section read values after the lock is acquired. + * Lock acquired. Ensure that any reads and writes from a shared + * resource in the critical section read/write values after the lock is + * acquired. */ - dmbld(); + dmbish(); } void bakery_lock_release(bakery_lock_t *lock) @@ -240,11 +241,14 @@ void bakery_lock_release(bakery_lock_t *lock) /* * Ensure that other observers see any stores in the critical section - * before releasing the lock. Release the lock by resetting ticket. - * Then signal other waiting contenders. + * before releasing the lock. Also ensure all loads in the critical + * section are complete before releasing the lock. Release the lock by + * resetting ticket. Then signal other waiting contenders. */ - dmbst(); + dmbish(); my_bakery_info->lock_data = 0U; write_cache_op((uintptr_t)my_bakery_info, is_cached); + + /* This sev is ordered by the dsbish in write_cahce_op */ sev(); } diff --git a/lib/locks/exclusive/aarch64/spinlock.S b/lib/locks/exclusive/aarch64/spinlock.S index d0569f1cd..e941b8a34 100644 --- a/lib/locks/exclusive/aarch64/spinlock.S +++ b/lib/locks/exclusive/aarch64/spinlock.S @@ -9,56 +9,38 @@ .globl spin_lock .globl spin_unlock -#if ARM_ARCH_AT_LEAST(8, 1) +#if USE_SPINLOCK_CAS +#if !ARM_ARCH_AT_LEAST(8, 1) +#error USE_SPINLOCK_CAS option requires at least an ARMv8.1 platform +#endif /* * When compiled for ARMv8.1 or later, choose spin locks based on Compare and * Swap instruction. */ -# define USE_CAS 1 - -/* - * Lock contenders using CAS, upon failing to acquire the lock, wait with the - * monitor in open state. Therefore, a normal store upon unlocking won't - * generate an SEV. Use explicit SEV instruction with CAS unlock. - */ -# define COND_SEV() sev - -#else - -# define USE_CAS 0 - -/* - * Lock contenders using exclusive pairs, upon failing to acquire the lock, wait - * with the monitor in exclusive state. A normal store upon unlocking will - * implicitly generate an envent; so, no explicit SEV with unlock is required. - */ -# define COND_SEV() - -#endif - -#if USE_CAS /* * Acquire lock using Compare and Swap instruction. * - * Compare for 0 with acquire semantics, and swap 1. Wait until CAS returns - * 0. + * Compare for 0 with acquire semantics, and swap 1. If failed to acquire, use + * load exclusive semantics to monitor the address and enter WFE. * * void spin_lock(spinlock_t *lock); */ func spin_lock mov w2, #1 - sevl -1: +1: mov w1, wzr +2: casa w1, w2, [x0] + cbz w1, 3f + ldxr w1, [x0] + cbz w1, 2b wfe - mov w1, wzr - casa w1, w2, [x0] - cbnz w1, 1b + b 1b +3: ret endfunc spin_lock -#else /* !USE_CAS */ +#else /* !USE_SPINLOCK_CAS */ /* * Acquire lock using load-/store-exclusive instruction pair. @@ -76,17 +58,18 @@ l2: ldaxr w1, [x0] ret endfunc spin_lock -#endif /* USE_CAS */ +#endif /* USE_SPINLOCK_CAS */ /* * Release lock previously acquired by spin_lock. * - * Unconditionally write 0, and conditionally generate an event. + * Use store-release to unconditionally clear the spinlock variable. + * Store operation generates an event to all cores waiting in WFE + * when address is monitored by the global monitor. * * void spin_unlock(spinlock_t *lock); */ func spin_unlock stlr wzr, [x0] - COND_SEV() ret endfunc spin_unlock diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c index 5d24356c9..5ab15c6ee 100644 --- a/lib/psci/psci_common.c +++ b/lib/psci/psci_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -43,6 +43,7 @@ const spd_pm_ops_t *psci_spd_pm; static plat_local_state_t psci_req_local_pwr_states[PLAT_MAX_PWR_LVL][PLATFORM_CORE_COUNT]; +unsigned int psci_plat_core_count; /******************************************************************************* * Arrays that hold the platform's power domain tree information for state @@ -159,9 +160,10 @@ void psci_query_sys_suspend_pwrstate(psci_power_state_t *state_info) ******************************************************************************/ unsigned int psci_is_last_on_cpu(void) { - int cpu_idx, my_idx = (int) plat_my_core_pos(); + unsigned int cpu_idx, my_idx = plat_my_core_pos(); - for (cpu_idx = 0; cpu_idx < PLATFORM_CORE_COUNT; cpu_idx++) { + for (cpu_idx = 0; cpu_idx < psci_plat_core_count; + cpu_idx++) { if (cpu_idx == my_idx) { assert(psci_get_aff_info_state() == AFF_STATE_ON); continue; @@ -192,27 +194,24 @@ static unsigned int get_power_on_target_pwrlvl(void) pwrlvl = psci_get_suspend_pwrlvl(); if (pwrlvl == PSCI_INVALID_PWR_LVL) pwrlvl = PLAT_MAX_PWR_LVL; + assert(pwrlvl < PSCI_INVALID_PWR_LVL); return pwrlvl; } /****************************************************************************** * Helper function to update the requested local power state array. This array * does not store the requested state for the CPU power level. Hence an - * assertion is added to prevent us from accessing the wrong index. + * assertion is added to prevent us from accessing the CPU power level. *****************************************************************************/ static void psci_set_req_local_pwr_state(unsigned int pwrlvl, unsigned int cpu_idx, plat_local_state_t req_pwr_state) { - /* - * This should never happen, we have this here to avoid - * "array subscript is above array bounds" errors in GCC. - */ assert(pwrlvl > PSCI_CPU_PWR_LVL); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Warray-bounds" - psci_req_local_pwr_states[pwrlvl - 1U][cpu_idx] = req_pwr_state; -#pragma GCC diagnostic pop + if ((pwrlvl > PSCI_CPU_PWR_LVL) && (pwrlvl <= PLAT_MAX_PWR_LVL) && + (cpu_idx < psci_plat_core_count)) { + psci_req_local_pwr_states[pwrlvl - 1U][cpu_idx] = req_pwr_state; + } } /****************************************************************************** @@ -222,10 +221,10 @@ void __init psci_init_req_local_pwr_states(void) { /* Initialize the requested state of all non CPU power domains as OFF */ unsigned int pwrlvl; - int core; + unsigned int core; for (pwrlvl = 0U; pwrlvl < PLAT_MAX_PWR_LVL; pwrlvl++) { - for (core = 0; core < PLATFORM_CORE_COUNT; core++) { + for (core = 0; core < psci_plat_core_count; core++) { psci_req_local_pwr_states[pwrlvl][core] = PLAT_MAX_OFF_STATE; } @@ -241,11 +240,15 @@ void __init psci_init_req_local_pwr_states(void) * assertion is added to prevent us from accessing the CPU power level. *****************************************************************************/ static plat_local_state_t *psci_get_req_local_pwr_states(unsigned int pwrlvl, - int cpu_idx) + unsigned int cpu_idx) { assert(pwrlvl > PSCI_CPU_PWR_LVL); - return &psci_req_local_pwr_states[pwrlvl - 1U][cpu_idx]; + if ((pwrlvl > PSCI_CPU_PWR_LVL) && (pwrlvl <= PLAT_MAX_PWR_LVL) && + (cpu_idx < psci_plat_core_count)) { + return &psci_req_local_pwr_states[pwrlvl - 1U][cpu_idx]; + } else + return NULL; } /* @@ -351,7 +354,7 @@ static void psci_set_target_local_pwr_states(unsigned int end_pwrlvl, /******************************************************************************* * PSCI helper function to get the parent nodes corresponding to a cpu_index. ******************************************************************************/ -void psci_get_parent_pwr_domain_nodes(int cpu_idx, +void psci_get_parent_pwr_domain_nodes(unsigned int cpu_idx, unsigned int end_lvl, unsigned int *node_index) { @@ -417,7 +420,7 @@ void psci_do_state_coordination(unsigned int end_pwrlvl, psci_power_state_t *state_info) { unsigned int lvl, parent_idx, cpu_idx = plat_my_core_pos(); - int start_idx; + unsigned int start_idx; unsigned int ncpus; plat_local_state_t target_state, *req_states; @@ -763,7 +766,7 @@ int psci_validate_entry_point(entry_point_info_t *ep, void psci_warmboot_entrypoint(void) { unsigned int end_pwrlvl; - int cpu_idx = (int) plat_my_core_pos(); + unsigned int cpu_idx = plat_my_core_pos(); unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0}; psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} }; @@ -772,7 +775,7 @@ void psci_warmboot_entrypoint(void) * suspend. */ if (psci_get_aff_info_state() == AFF_STATE_OFF) { - ERROR("Unexpected affinity info state"); + ERROR("Unexpected affinity info state.\n"); panic(); } @@ -886,7 +889,7 @@ int psci_spd_migrate_info(u_register_t *mpidr) void psci_print_power_domain_map(void) { #if LOG_LEVEL >= LOG_LEVEL_INFO - int idx; + unsigned int idx; plat_local_state_t state; plat_local_state_type_t state_type; @@ -898,7 +901,7 @@ void psci_print_power_domain_map(void) }; INFO("PSCI Power Domain Map:\n"); - for (idx = 0; idx < (PSCI_NUM_PWR_DOMAINS - PLATFORM_CORE_COUNT); + for (idx = 0; idx < (PSCI_NUM_PWR_DOMAINS - psci_plat_core_count); idx++) { state_type = find_local_state_type( psci_non_cpu_pd_nodes[idx].local_state); @@ -910,7 +913,7 @@ void psci_print_power_domain_map(void) psci_non_cpu_pd_nodes[idx].local_state); } - for (idx = 0; idx < PLATFORM_CORE_COUNT; idx++) { + for (idx = 0; idx < psci_plat_core_count; idx++) { state = psci_get_cpu_local_state_by_idx(idx); state_type = find_local_state_type(state); INFO(" CPU Node : MPID 0x%llx, parent_node %d," diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c index 5c0e952a9..52a8b8a18 100644 --- a/lib/psci/psci_main.c +++ b/lib/psci/psci_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -219,16 +219,19 @@ int psci_cpu_off(void) int psci_affinity_info(u_register_t target_affinity, unsigned int lowest_affinity_level) { - int target_idx; + int ret; + unsigned int target_idx; /* We dont support level higher than PSCI_CPU_PWR_LVL */ if (lowest_affinity_level > PSCI_CPU_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* Calculate the cpu index of the target */ - target_idx = plat_core_pos_by_mpidr(target_affinity); - if (target_idx == -1) + ret = plat_core_pos_by_mpidr(target_affinity); + if (ret == -1) { return PSCI_E_INVALID_PARAMS; + } + target_idx = (unsigned int)ret; /* * Generic management: @@ -245,7 +248,7 @@ int psci_affinity_info(u_register_t target_affinity, * target CPUs shutdown was not seen by the current CPU's cluster. And * so the cache may contain stale data for the target CPU. */ - flush_cpu_data_by_index((unsigned int)target_idx, + flush_cpu_data_by_index(target_idx, psci_svc_cpu_data.aff_info_state); return psci_get_aff_info_state_by_idx(target_idx); diff --git a/lib/psci/psci_off.c b/lib/psci/psci_off.c index e8cd8feb0..54470457a 100644 --- a/lib/psci/psci_off.c +++ b/lib/psci/psci_off.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -43,7 +43,7 @@ static void psci_set_power_off_state(psci_power_state_t *state_info) int psci_do_cpu_off(unsigned int end_pwrlvl) { int rc = PSCI_E_SUCCESS; - int idx = (int) plat_my_core_pos(); + unsigned int idx = plat_my_core_pos(); psci_power_state_t state_info; unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0}; diff --git a/lib/psci/psci_on.c b/lib/psci/psci_on.c index aa6b324ed..dd48e105d 100644 --- a/lib/psci/psci_on.c +++ b/lib/psci/psci_on.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -20,12 +20,12 @@ /* * Helper functions for the CPU level spinlocks */ -static inline void psci_spin_lock_cpu(int idx) +static inline void psci_spin_lock_cpu(unsigned int idx) { spin_lock(&psci_cpu_pd_nodes[idx].cpu_lock); } -static inline void psci_spin_unlock_cpu(int idx) +static inline void psci_spin_unlock_cpu(unsigned int idx) { spin_unlock(&psci_cpu_pd_nodes[idx].cpu_lock); } @@ -61,12 +61,14 @@ int psci_cpu_on_start(u_register_t target_cpu, { int rc; aff_info_state_t target_aff_state; - int target_idx = plat_core_pos_by_mpidr(target_cpu); + int ret = plat_core_pos_by_mpidr(target_cpu); + unsigned int target_idx = (unsigned int)ret; /* Calling function must supply valid input arguments */ - assert(target_idx >= 0); + assert(ret >= 0); assert(ep != NULL); + /* * This function must only be called on platforms where the * CPU_ON platform hooks have been implemented. @@ -93,7 +95,7 @@ int psci_cpu_on_start(u_register_t target_cpu, * target CPUs shutdown was not seen by the current CPU's cluster. And * so the cache may contain stale data for the target CPU. */ - flush_cpu_data_by_index((unsigned int)target_idx, + flush_cpu_data_by_index(target_idx, psci_svc_cpu_data.aff_info_state); rc = cpu_on_validate_state(psci_get_aff_info_state_by_idx(target_idx)); if (rc != PSCI_E_SUCCESS) @@ -113,7 +115,7 @@ int psci_cpu_on_start(u_register_t target_cpu, * turned OFF. */ psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_ON_PENDING); - flush_cpu_data_by_index((unsigned int)target_idx, + flush_cpu_data_by_index(target_idx, psci_svc_cpu_data.aff_info_state); /* @@ -126,7 +128,7 @@ int psci_cpu_on_start(u_register_t target_cpu, if (target_aff_state != AFF_STATE_ON_PENDING) { assert(target_aff_state == AFF_STATE_OFF); psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_ON_PENDING); - flush_cpu_data_by_index((unsigned int)target_idx, + flush_cpu_data_by_index(target_idx, psci_svc_cpu_data.aff_info_state); assert(psci_get_aff_info_state_by_idx(target_idx) == @@ -146,11 +148,11 @@ int psci_cpu_on_start(u_register_t target_cpu, if (rc == PSCI_E_SUCCESS) /* Store the re-entry information for the non-secure world. */ - cm_init_context_by_index((unsigned int)target_idx, ep); + cm_init_context_by_index(target_idx, ep); else { /* Restore the state on error. */ psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_OFF); - flush_cpu_data_by_index((unsigned int)target_idx, + flush_cpu_data_by_index(target_idx, psci_svc_cpu_data.aff_info_state); } @@ -164,7 +166,7 @@ exit: * are called by the common finisher routine in psci_common.c. The `state_info` * is the psci_power_state from which this CPU has woken up from. ******************************************************************************/ -void psci_cpu_on_finish(int cpu_idx, const psci_power_state_t *state_info) +void psci_cpu_on_finish(unsigned int cpu_idx, const psci_power_state_t *state_info) { /* * Plat. management: Perform the platform specific actions @@ -182,6 +184,14 @@ void psci_cpu_on_finish(int cpu_idx, const psci_power_state_t *state_info) #endif /* + * Plat. management: Perform any platform specific actions which + * can only be done with the cpu and the cluster guaranteed to + * be coherent. + */ + if (psci_plat_pm_ops->pwr_domain_on_finish_late != NULL) + psci_plat_pm_ops->pwr_domain_on_finish_late(state_info); + + /* * All the platform specific actions for turning this cpu * on have completed. Perform enough arch.initialization * to run in the non-secure address space. diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h index bbcc5cfe7..e2dcfa8b1 100644 --- a/lib/psci/psci_private.h +++ b/lib/psci/psci_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -55,16 +55,16 @@ static inline aff_info_state_t psci_get_aff_info_state(void) return get_cpu_data(psci_svc_cpu_data.aff_info_state); } -static inline aff_info_state_t psci_get_aff_info_state_by_idx(int idx) +static inline aff_info_state_t psci_get_aff_info_state_by_idx(unsigned int idx) { - return get_cpu_data_by_index((unsigned int)idx, + return get_cpu_data_by_index(idx, psci_svc_cpu_data.aff_info_state); } -static inline void psci_set_aff_info_state_by_idx(int idx, +static inline void psci_set_aff_info_state_by_idx(unsigned int idx, aff_info_state_t aff_state) { - set_cpu_data_by_index((unsigned int)idx, + set_cpu_data_by_index(idx, psci_svc_cpu_data.aff_info_state, aff_state); } @@ -88,9 +88,10 @@ static inline plat_local_state_t psci_get_cpu_local_state(void) return get_cpu_data(psci_svc_cpu_data.local_state); } -static inline plat_local_state_t psci_get_cpu_local_state_by_idx(int idx) +static inline plat_local_state_t psci_get_cpu_local_state_by_idx( + unsigned int idx) { - return get_cpu_data_by_index((unsigned int)idx, + return get_cpu_data_by_index(idx, psci_svc_cpu_data.local_state); } @@ -113,7 +114,7 @@ typedef struct non_cpu_pwr_domain_node { * Index of the first CPU power domain node level 0 which has this node * as its parent. */ - int cpu_start_idx; + unsigned int cpu_start_idx; /* * Number of CPU power domains which are siblings of the domain indexed @@ -250,6 +251,7 @@ extern const plat_psci_ops_t *psci_plat_pm_ops; extern non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS]; extern cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT]; extern unsigned int psci_caps; +extern unsigned int psci_plat_core_count; /******************************************************************************* * SPD's power management hooks registered with PSCI @@ -269,7 +271,7 @@ void psci_get_target_local_pwr_states(unsigned int end_pwrlvl, psci_power_state_t *target_state); int psci_validate_entry_point(entry_point_info_t *ep, uintptr_t entrypoint, u_register_t context_id); -void psci_get_parent_pwr_domain_nodes(int cpu_idx, +void psci_get_parent_pwr_domain_nodes(unsigned int cpu_idx, unsigned int end_lvl, unsigned int *node_index); void psci_do_state_coordination(unsigned int end_pwrlvl, @@ -299,7 +301,7 @@ void prepare_cpu_pwr_dwn(unsigned int power_level); int psci_cpu_on_start(u_register_t target_cpu, const entry_point_info_t *ep); -void psci_cpu_on_finish(int cpu_idx, const psci_power_state_t *state_info); +void psci_cpu_on_finish(unsigned int cpu_idx, const psci_power_state_t *state_info); /* Private exported functions from psci_off.c */ int psci_do_cpu_off(unsigned int end_pwrlvl); @@ -310,7 +312,7 @@ void psci_cpu_suspend_start(const entry_point_info_t *ep, psci_power_state_t *state_info, unsigned int is_power_down_state); -void psci_cpu_suspend_finish(int cpu_idx, const psci_power_state_t *state_info); +void psci_cpu_suspend_finish(unsigned int cpu_idx, const psci_power_state_t *state_info); /* Private exported functions from psci_helpers.S */ void psci_do_pwrdown_cache_maintenance(unsigned int pwr_level); diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c index b9467d3e0..d1ec99808 100644 --- a/lib/psci/psci_setup.c +++ b/lib/psci/psci_setup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -84,15 +84,16 @@ static void __init psci_init_pwr_domain_node(unsigned char node_idx, *******************************************************************************/ static void __init psci_update_pwrlvl_limits(void) { - int j, cpu_idx; + unsigned int cpu_idx; + int j; unsigned int nodes_idx[PLAT_MAX_PWR_LVL] = {0}; unsigned int temp_index[PLAT_MAX_PWR_LVL]; - for (cpu_idx = 0; cpu_idx < PLATFORM_CORE_COUNT; cpu_idx++) { + for (cpu_idx = 0; cpu_idx < psci_plat_core_count; cpu_idx++) { psci_get_parent_pwr_domain_nodes(cpu_idx, - (unsigned int)PLAT_MAX_PWR_LVL, + PLAT_MAX_PWR_LVL, temp_index); - for (j = (int) PLAT_MAX_PWR_LVL - 1; j >= 0; j--) { + for (j = (int)PLAT_MAX_PWR_LVL - 1; j >= 0; j--) { if (temp_index[j] != nodes_idx[j]) { nodes_idx[j] = temp_index[j]; psci_non_cpu_pd_nodes[nodes_idx[j]].cpu_start_idx @@ -109,12 +110,13 @@ static void __init psci_update_pwrlvl_limits(void) * informs the number of root power domains. The parent nodes of the root nodes * will point to an invalid entry(-1). ******************************************************************************/ -static void __init populate_power_domain_tree(const unsigned char *topology) +static unsigned int __init populate_power_domain_tree(const unsigned char + *topology) { unsigned int i, j = 0U, num_nodes_at_lvl = 1U, num_nodes_at_next_lvl; unsigned int node_index = 0U, num_children; - int parent_node_index = 0; - int level = (int) PLAT_MAX_PWR_LVL; + unsigned int parent_node_index = 0U; + int level = (int)PLAT_MAX_PWR_LVL; /* * For each level the inputs are: @@ -143,8 +145,8 @@ static void __init populate_power_domain_tree(const unsigned char *topology) for (j = node_index; j < (node_index + num_children); j++) psci_init_pwr_domain_node((unsigned char)j, - parent_node_index - 1, - (unsigned char)level); + parent_node_index - 1U, + (unsigned char)level); node_index = j; num_nodes_at_next_lvl += num_children; @@ -160,7 +162,8 @@ static void __init populate_power_domain_tree(const unsigned char *topology) } /* Validate the sanity of array exported by the platform */ - assert((int) j == PLATFORM_CORE_COUNT); + assert(j <= PLATFORM_CORE_COUNT); + return j; } /******************************************************************************* @@ -199,7 +202,7 @@ int __init psci_setup(const psci_lib_args_t *lib_args) topology_tree = plat_get_power_domain_tree_desc(); /* Populate the power domain arrays using the platform topology map */ - populate_power_domain_tree(topology_tree); + psci_plat_core_count = populate_power_domain_tree(topology_tree); /* Update the CPU limits for each node in psci_non_cpu_pd_nodes */ psci_update_pwrlvl_limits(); @@ -280,6 +283,12 @@ void psci_arch_setup(void) /* Having initialized cpu_ops, we can now print errata status */ print_errata_status(); + +#if ENABLE_PAUTH + /* Store APIAKey_EL1 key */ + set_cpu_data(apiakey[0], read_apiakeylo_el1()); + set_cpu_data(apiakey[1], read_apiakeyhi_el1()); +#endif /* ENABLE_PAUTH */ } /****************************************************************************** diff --git a/lib/psci/psci_stat.c b/lib/psci/psci_stat.c index 772a1840a..ecef95ab6 100644 --- a/lib/psci/psci_stat.c +++ b/lib/psci/psci_stat.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -28,7 +28,7 @@ typedef struct psci_stat { * that goes to power down in non cpu power domains. */ static int last_cpu_in_non_cpu_pd[PSCI_NUM_NON_CPU_PWR_DOMAINS] = { - [0 ... PSCI_NUM_NON_CPU_PWR_DOMAINS - 1] = -1}; + [0 ... PSCI_NUM_NON_CPU_PWR_DOMAINS - 1U] = -1}; /* * Following are used to store PSCI STAT values for @@ -77,7 +77,7 @@ void psci_stats_update_pwr_down(unsigned int end_pwrlvl, const psci_power_state_t *state_info) { unsigned int lvl, parent_idx; - int cpu_idx = (int) plat_my_core_pos(); + unsigned int cpu_idx = plat_my_core_pos(); assert(end_pwrlvl <= PLAT_MAX_PWR_LVL); assert(state_info != NULL); @@ -94,7 +94,7 @@ void psci_stats_update_pwr_down(unsigned int end_pwrlvl, * The power domain is entering a low power state, so this is * the last CPU for this power domain */ - last_cpu_in_non_cpu_pd[parent_idx] = cpu_idx; + last_cpu_in_non_cpu_pd[parent_idx] = (int)cpu_idx; parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node; } @@ -110,7 +110,7 @@ void psci_stats_update_pwr_up(unsigned int end_pwrlvl, const psci_power_state_t *state_info) { unsigned int lvl, parent_idx; - int cpu_idx = (int) plat_my_core_pos(); + unsigned int cpu_idx = plat_my_core_pos(); int stat_idx; plat_local_state_t local_state; u_register_t residency; @@ -150,7 +150,7 @@ void psci_stats_update_pwr_up(unsigned int end_pwrlvl, /* Call into platform interface to calculate residency. */ residency = plat_psci_stat_get_residency(lvl, state_info, - last_cpu_in_non_cpu_pd[parent_idx]); + (unsigned int)last_cpu_in_non_cpu_pd[parent_idx]); /* Initialize back to reset value */ last_cpu_in_non_cpu_pd[parent_idx] = -1; diff --git a/lib/psci/psci_suspend.c b/lib/psci/psci_suspend.c index 6d5c099fb..da9f328a5 100644 --- a/lib/psci/psci_suspend.c +++ b/lib/psci/psci_suspend.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -25,7 +25,7 @@ * This function does generic and platform specific operations after a wake-up * from standby/retention states at multiple power levels. ******************************************************************************/ -static void psci_suspend_to_standby_finisher(int cpu_idx, +static void psci_suspend_to_standby_finisher(unsigned int cpu_idx, unsigned int end_pwrlvl) { unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0}; @@ -157,7 +157,7 @@ void psci_cpu_suspend_start(const entry_point_info_t *ep, unsigned int is_power_down_state) { int skip_wfi = 0; - int idx = (int) plat_my_core_pos(); + unsigned int idx = plat_my_core_pos(); unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0}; /* @@ -276,7 +276,7 @@ exit: * are called by the common finisher routine in psci_common.c. The `state_info` * is the psci_power_state from which this CPU has woken up from. ******************************************************************************/ -void psci_cpu_suspend_finish(int cpu_idx, const psci_power_state_t *state_info) +void psci_cpu_suspend_finish(unsigned int cpu_idx, const psci_power_state_t *state_info) { unsigned int counter_freq; unsigned int max_off_lvl; @@ -304,6 +304,12 @@ void psci_cpu_suspend_finish(int cpu_idx, const psci_power_state_t *state_info) counter_freq = plat_get_syscnt_freq2(); write_cntfrq_el0(counter_freq); +#if ENABLE_PAUTH + /* Store APIAKey_EL1 key */ + set_cpu_data(apiakey[0], read_apiakeylo_el1()); + set_cpu_data(apiakey[1], read_apiakeyhi_el1()); +#endif /* ENABLE_PAUTH */ + /* * Call the cpu suspend finish handler registered by the Secure Payload * Dispatcher to let it do any bookeeping. If the handler encounters an diff --git a/lib/romlib/jmptbl.i b/lib/romlib/jmptbl.i index a7280d0d6..33710f581 100644 --- a/lib/romlib/jmptbl.i +++ b/lib/romlib/jmptbl.i @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -17,6 +17,7 @@ fdt fdt_getprop_namelen fdt fdt_setprop_inplace fdt fdt_check_header fdt fdt_node_offset_by_compatible +fdt fdt_setprop_inplace_namelen_partial mbedtls mbedtls_asn1_get_alg mbedtls mbedtls_asn1_get_alg_null mbedtls mbedtls_asn1_get_bitstring_null diff --git a/lib/semihosting/semihosting.c b/lib/semihosting/semihosting.c index 051dd008b..60fc52a00 100644 --- a/lib/semihosting/semihosting.c +++ b/lib/semihosting/semihosting.c @@ -15,7 +15,7 @@ #endif long semihosting_call(unsigned long operation, - void *system_block_address); + uintptr_t system_block_address); typedef struct { const char *file_name; @@ -53,7 +53,7 @@ long semihosting_file_open(const char *file_name, size_t mode) open_block.name_length = strlen(file_name); return semihosting_call(SEMIHOSTING_SYS_OPEN, - (void *) &open_block); + (uintptr_t) &open_block); } long semihosting_file_seek(long file_handle, ssize_t offset) @@ -65,7 +65,7 @@ long semihosting_file_seek(long file_handle, ssize_t offset) seek_block.location = offset; result = semihosting_call(SEMIHOSTING_SYS_SEEK, - (void *) &seek_block); + (uintptr_t) &seek_block); if (result) result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0); @@ -86,7 +86,7 @@ long semihosting_file_read(long file_handle, size_t *length, uintptr_t buffer) read_block.length = *length; result = semihosting_call(SEMIHOSTING_SYS_READ, - (void *) &read_block); + (uintptr_t) &read_block); if (result == *length) { return -EINVAL; @@ -112,7 +112,7 @@ long semihosting_file_write(long file_handle, write_block.length = *length; result = semihosting_call(SEMIHOSTING_SYS_WRITE, - (void *) &write_block); + (uintptr_t) &write_block); *length = result; @@ -122,28 +122,28 @@ long semihosting_file_write(long file_handle, long semihosting_file_close(long file_handle) { return semihosting_call(SEMIHOSTING_SYS_CLOSE, - (void *) &file_handle); + (uintptr_t) &file_handle); } long semihosting_file_length(long file_handle) { return semihosting_call(SEMIHOSTING_SYS_FLEN, - (void *) &file_handle); + (uintptr_t) &file_handle); } char semihosting_read_char(void) { - return semihosting_call(SEMIHOSTING_SYS_READC, NULL); + return semihosting_call(SEMIHOSTING_SYS_READC, 0); } void semihosting_write_char(char character) { - semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character); + semihosting_call(SEMIHOSTING_SYS_WRITEC, (uintptr_t) &character); } void semihosting_write_string(char *string) { - semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string); + semihosting_call(SEMIHOSTING_SYS_WRITE0, (uintptr_t) string); } long semihosting_system(char *command_line) @@ -154,7 +154,7 @@ long semihosting_system(char *command_line) system_block.command_length = strlen(command_line); return semihosting_call(SEMIHOSTING_SYS_SYSTEM, - (void *) &system_block); + (uintptr_t) &system_block); } long semihosting_get_flen(const char *file_name) @@ -216,3 +216,15 @@ semihosting_fail: semihosting_file_close(file_handle); return ret; } + +void semihosting_exit(uint32_t reason, uint32_t subcode) +{ +#ifdef __aarch64__ + uint64_t parameters[] = {reason, subcode}; + + (void) semihosting_call(SEMIHOSTING_SYS_EXIT, (uintptr_t) ¶meters); +#else + /* The subcode is not supported on AArch32. */ + (void) semihosting_call(SEMIHOSTING_SYS_EXIT, reason); +#endif +} diff --git a/lib/sprt/sprt_host.c b/lib/sprt/sprt_host.c deleted file mode 100644 index c4d436e1c..000000000 --- a/lib/sprt/sprt_host.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <errno.h> -#include <stddef.h> -#include <stdint.h> - -#include "sprt_common.h" -#include "sprt_queue.h" - -void sprt_initialize_queues(void *buffer_base, size_t buffer_size) -{ - /* Initialize queue for blocking messages */ - - void *blocking_base = buffer_base; - uint32_t blocking_num = 4U; - size_t blocking_size = SPRT_QUEUE_HEADER_SIZE + - SPRT_QUEUE_ENTRY_MSG_SIZE * blocking_num; - - sprt_queue_init(blocking_base, blocking_num, SPRT_QUEUE_ENTRY_MSG_SIZE); - - /* Initialize queue for non-blocking messages */ - - void *non_blocking_base = (void *)((uintptr_t)blocking_base + blocking_size); - size_t non_blocking_size = buffer_size - blocking_size; - uint32_t non_blocking_num = (non_blocking_size - SPRT_QUEUE_HEADER_SIZE) / - SPRT_QUEUE_ENTRY_MSG_SIZE; - - sprt_queue_init(non_blocking_base, non_blocking_num, SPRT_QUEUE_ENTRY_MSG_SIZE); -} - -int sprt_push_message(void *buffer_base, - const struct sprt_queue_entry_message *message, - int queue_num) -{ - struct sprt_queue *q = buffer_base; - - while (queue_num-- > 0) { - uintptr_t next_addr = (uintptr_t)q + sizeof(struct sprt_queue) + - q->entry_num * q->entry_size; - q = (struct sprt_queue *) next_addr; - } - - return sprt_queue_push(q, message); -} diff --git a/lib/sprt/sprt_host.mk b/lib/sprt/sprt_host.mk deleted file mode 100644 index abcfe5e49..000000000 --- a/lib/sprt/sprt_host.mk +++ /dev/null @@ -1,11 +0,0 @@ -# -# Copyright (c) 2018, Arm Limited. All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause -# - -SPRT_LIB_SOURCES := $(addprefix lib/sprt/, \ - sprt_host.c \ - sprt_queue.c) - -SPRT_LIB_INCLUDES := -Iinclude/lib/sprt/ diff --git a/lib/sprt/sprt_queue.c b/lib/sprt/sprt_queue.c deleted file mode 100644 index 2bd4139ea..000000000 --- a/lib/sprt/sprt_queue.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2018, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <assert.h> -#include <errno.h> -#include <stdint.h> -#include <string.h> - -#include "sprt_queue.h" - -void sprt_queue_init(void *queue_base, uint32_t entry_num, uint32_t entry_size) -{ - assert(queue_base != NULL); - assert(entry_size > 0U); - assert(entry_num > 0U); - - struct sprt_queue *queue = (struct sprt_queue *)queue_base; - - queue->entry_num = entry_num; - queue->entry_size = entry_size; - queue->idx_write = 0U; - queue->idx_read = 0U; - - memset(queue->data, 0, entry_num * entry_size); -} - -int sprt_queue_is_empty(void *queue_base) -{ - assert(queue_base != NULL); - - struct sprt_queue *queue = (struct sprt_queue *)queue_base; - - return (queue->idx_write == queue->idx_read); -} - -int sprt_queue_is_full(void *queue_base) -{ - assert(queue_base != NULL); - - struct sprt_queue *queue = (struct sprt_queue *)queue_base; - - uint32_t idx_next_write = (queue->idx_write + 1) % queue->entry_num; - - return (idx_next_write == queue->idx_read); -} - -int sprt_queue_push(void *queue_base, const void *entry) -{ - assert(entry != NULL); - assert(queue_base != NULL); - - if (sprt_queue_is_full(queue_base) != 0) { - return -ENOMEM; - } - - struct sprt_queue *queue = (struct sprt_queue *)queue_base; - - uint8_t *dst_entry = &queue->data[queue->entry_size * queue->idx_write]; - - memcpy(dst_entry, entry, queue->entry_size); - - /* - * Make sure that the message data is visible before increasing the - * counter of available messages. - */ - __asm__ volatile("dmb st" ::: "memory"); - - queue->idx_write = (queue->idx_write + 1) % queue->entry_num; - - __asm__ volatile("dmb st" ::: "memory"); - - return 0; -} - -int sprt_queue_pop(void *queue_base, void *entry) -{ - assert(entry != NULL); - assert(queue_base != NULL); - - if (sprt_queue_is_empty(queue_base) != 0) { - return -ENOENT; - } - - struct sprt_queue *queue = (struct sprt_queue *)queue_base; - - uint8_t *src_entry = &queue->data[queue->entry_size * queue->idx_read]; - - memcpy(entry, src_entry, queue->entry_size); - - /* - * Make sure that the message data is visible before increasing the - * counter of read messages. - */ - __asm__ volatile("dmb st" ::: "memory"); - - queue->idx_read = (queue->idx_read + 1) % queue->entry_num; - - __asm__ volatile("dmb st" ::: "memory"); - - return 0; -} diff --git a/lib/sprt/sprt_queue.h b/lib/sprt/sprt_queue.h deleted file mode 100644 index 4ea1bc231..000000000 --- a/lib/sprt/sprt_queue.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef SPRT_QUEUE_H -#define SPRT_QUEUE_H - -#include <stdint.h> - -/* Struct that defines a queue. Not to be used directly. */ -struct __attribute__((__packed__)) sprt_queue { - uint32_t entry_num; /* Number of entries */ - uint32_t entry_size; /* Size of an entry */ - uint32_t idx_write; /* Index of first empty entry */ - uint32_t idx_read; /* Index of first entry to read */ - uint8_t data[0]; /* Start of data */ -}; - -#define SPRT_QUEUE_HEADER_SIZE (sizeof(struct sprt_queue)) - -/* - * Initializes a memory region to be used as a queue of the given number of - * entries with the specified size. - */ -void sprt_queue_init(void *queue_base, uint32_t entry_num, uint32_t entry_size); - -/* Returns 1 if the queue is empty, 0 otherwise */ -int sprt_queue_is_empty(void *queue_base); - -/* Returns 1 if the queue is full, 0 otherwise */ -int sprt_queue_is_full(void *queue_base); - -/* - * Pushes a new entry intro the queue. Returns 0 on success, -ENOMEM if the - * queue is full. - */ -int sprt_queue_push(void *queue_base, const void *entry); - -/* - * Pops an entry from the queue. Returns 0 on success, -ENOENT if the queue is - * empty. - */ -int sprt_queue_pop(void *queue_base, void *entry); - -#endif /* SPRT_QUEUE_H */ diff --git a/lib/stack_protector/stack_protector.mk b/lib/stack_protector/stack_protector.mk index 94e804be9..b5aba1528 100644 --- a/lib/stack_protector/stack_protector.mk +++ b/lib/stack_protector/stack_protector.mk @@ -11,7 +11,9 @@ ifeq (${ENABLE_STACK_PROTECTOR},0) ENABLE_STACK_PROTECTOR := none endif -ifneq (${ENABLE_STACK_PROTECTOR},none) +ifeq (${ENABLE_STACK_PROTECTOR},none) + TF_CFLAGS += -fno-stack-protector +else STACK_PROTECTOR_ENABLED := 1 BL_COMMON_SOURCES += lib/stack_protector/stack_protector.c \ lib/stack_protector/${ARCH}/asm_stack_protector.S diff --git a/lib/xlat_tables/aarch32/nonlpae_tables.c b/lib/xlat_tables/aarch32/nonlpae_tables.c index bd6b152ef..b8c268665 100644 --- a/lib/xlat_tables/aarch32/nonlpae_tables.c +++ b/lib/xlat_tables/aarch32/nonlpae_tables.c @@ -284,10 +284,10 @@ void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, } /* map all memory as shared/global/domain0/no-usr access */ -static unsigned long mmap_desc(unsigned attr, unsigned long addr_pa, - unsigned int level) +static uint32_t mmap_desc(unsigned attr, unsigned int addr_pa, + unsigned int level) { - unsigned long desc; + uint32_t desc; switch (level) { case 1: @@ -380,14 +380,14 @@ static unsigned int mmap_region_attr(const mmap_region_t *mm, uintptr_t base_va, } static mmap_region_t *init_xlation_table_inner(mmap_region_t *mm, - unsigned long base_va, - unsigned long *table, + unsigned int base_va, + uint32_t *table, unsigned int level) { unsigned int level_size_shift = (level == 1) ? ONE_MB_SHIFT : FOUR_KB_SHIFT; unsigned int level_size = 1 << level_size_shift; - unsigned long level_index_mask = (level == 1) ? + unsigned int level_index_mask = (level == 1) ? (NUM_1MB_IN_4GB - 1) << ONE_MB_SHIFT : (NUM_4K_IN_1MB - 1) << FOUR_KB_SHIFT; @@ -396,7 +396,7 @@ static mmap_region_t *init_xlation_table_inner(mmap_region_t *mm, VERBOSE("init xlat table at %p (level%1d)\n", (void *)table, level); do { - unsigned long desc = MMU32B_UNSET_DESC; + uint32_t desc = MMU32B_UNSET_DESC; if (mm->base_va + mm->size <= base_va) { /* Area now after the region so skip it */ @@ -427,7 +427,7 @@ static mmap_region_t *init_xlation_table_inner(mmap_region_t *mm, } if (desc == MMU32B_UNSET_DESC) { - unsigned long xlat_table; + uintptr_t xlat_table; /* * Area not covered by a region so need finer table @@ -443,7 +443,7 @@ static mmap_region_t *init_xlation_table_inner(mmap_region_t *mm, ~(MMU32B_L1_TABLE_ALIGN - 1); desc = *table; } else { - xlat_table = (unsigned long)mmu_l2_base + + xlat_table = (uintptr_t)mmu_l2_base + next_xlat * MMU32B_L2_TABLE_SIZE; next_xlat++; assert(next_xlat <= MAX_XLAT_TABLES); @@ -456,7 +456,7 @@ static mmap_region_t *init_xlation_table_inner(mmap_region_t *mm, } /* Recurse to fill in new table */ mm = init_xlation_table_inner(mm, base_va, - (unsigned long *)xlat_table, + (uint32_t *)xlat_table, level + 1); } #if LOG_LEVEL >= LOG_LEVEL_VERBOSE @@ -480,7 +480,7 @@ void init_xlat_tables(void) memset(mmu_l1_base, 0, MMU32B_L1_TABLE_SIZE); - init_xlation_table_inner(mmap, 0, (unsigned long *)mmu_l1_base, 1); + init_xlation_table_inner(mmap, 0, (uint32_t *)mmu_l1_base, 1); VERBOSE("init xlat - max_va=%p, max_pa=%llx\n", (void *)xlat_max_va, xlat_max_pa); diff --git a/lib/xlat_tables_v2/xlat_tables_core.c b/lib/xlat_tables_v2/xlat_tables_core.c index 4f62f469f..b2259e5f3 100644 --- a/lib/xlat_tables_v2/xlat_tables_core.c +++ b/lib/xlat_tables_v2/xlat_tables_core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -607,7 +607,8 @@ static uintptr_t xlat_tables_map_region(xlat_ctx_t *ctx, mmap_region_t *mm, } /* Point to new subtable from this one. */ - table_base[table_idx] = TABLE_DESC | (unsigned long)subtable; + table_base[table_idx] = + TABLE_DESC | (uintptr_t)subtable; /* Recurse to write into subtable */ end_va = xlat_tables_map_region(ctx, mm, table_idx_va, @@ -687,10 +688,10 @@ static int mmap_add_region_check(const xlat_ctx_t *ctx, const mmap_region_t *mm) if ((base_pa > end_pa) || (base_va > end_va)) return -ERANGE; - if ((base_va + (uintptr_t)size - (uintptr_t)1) > ctx->va_max_address) + if (end_va > ctx->va_max_address) return -ERANGE; - if ((base_pa + (unsigned long long)size - 1ULL) > ctx->pa_max_address) + if (end_pa > ctx->pa_max_address) return -ERANGE; /* Check that there is space in the ctx->mmap array */ diff --git a/lib/xlat_tables_v2/xlat_tables_utils.c b/lib/xlat_tables_v2/xlat_tables_utils.c index 232142e84..30babc63f 100644 --- a/lib/xlat_tables_v2/xlat_tables_utils.c +++ b/lib/xlat_tables_v2/xlat_tables_utils.c @@ -551,7 +551,7 @@ int xlat_change_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va, * before writing the new descriptor. */ *entry = INVALID_DESC; -#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) +#if !HW_ASSISTED_COHERENCY dccvac((uintptr_t)entry); #endif /* Invalidate any cached copy of this mapping in the TLBs. */ @@ -562,7 +562,7 @@ int xlat_change_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va, /* Write new descriptor */ *entry = xlat_desc(ctx, new_attr, addr_pa, level); -#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) +#if !HW_ASSISTED_COHERENCY dccvac((uintptr_t)entry); #endif base_va += PAGE_SIZE; |