aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2020-02-07 04:22:22 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2020-02-07 04:22:22 +0000
commitd36ae3e4c44c6547467f7ca92298ebad99700cb3 (patch)
tree76d9e0cabe45c1ed6d9ea87a5deb9c75c4345653 /lib
parentf94bb7f616791b95961e9d25c0a7b0c79fd45edc (diff)
parentcabe6937f2c9d0a50e4631c0545bddd650233ae8 (diff)
downloadplatform_external_arm-trusted-firmware-android11-gsi.tar.gz
platform_external_arm-trusted-firmware-android11-gsi.tar.bz2
platform_external_arm-trusted-firmware-android11-gsi.zip
Change-Id: Id9d1eda28e2f504532858d4c602eeebec865f19e
Diffstat (limited to 'lib')
-rw-r--r--lib/compiler-rt/compiler-rt.mk16
-rw-r--r--lib/compiler-rt/include/float.h1
-rw-r--r--lib/cpus/aarch64/aem_generic.S38
-rw-r--r--lib/cpus/aarch64/cortex_a65.S81
-rw-r--r--lib/cpus/aarch64/cortex_a65ae.S81
-rw-r--r--lib/cpus/aarch64/cortex_a76.S4
-rw-r--r--lib/cpus/aarch64/cortex_hercules.S65
-rw-r--r--lib/cpus/aarch64/cortex_hercules_ae.S100
-rw-r--r--lib/cpus/aarch64/cpu_helpers.S21
-rw-r--r--lib/cpus/aarch64/neoverse_n1.S93
-rw-r--r--lib/cpus/aarch64/neoverse_zeus.S12
-rw-r--r--lib/cpus/aarch64/wa_cve_2017_5715_mmu.S4
-rw-r--r--lib/cpus/cpu-ops.mk29
-rw-r--r--lib/debugfs/blobs.h12
-rw-r--r--lib/debugfs/debugfs.mk13
-rw-r--r--lib/debugfs/debugfs_smc.c209
-rw-r--r--lib/debugfs/dev.c849
-rw-r--r--lib/debugfs/dev.h120
-rw-r--r--lib/debugfs/devc.c20
-rw-r--r--lib/debugfs/devfip.c317
-rw-r--r--lib/debugfs/devroot.c97
-rw-r--r--lib/el3_runtime/aarch32/context_mgmt.c26
-rw-r--r--lib/el3_runtime/aarch64/context.S421
-rw-r--r--lib/el3_runtime/aarch64/context_mgmt.c131
-rw-r--r--lib/extensions/pauth/pauth_helpers.S141
-rw-r--r--lib/libc/assert.c9
-rw-r--r--lib/libc/libc.mk1
-rw-r--r--lib/libc/memrchr.c24
-rw-r--r--lib/locks/bakery/bakery_lock_coherent.c16
-rw-r--r--lib/locks/bakery/bakery_lock_normal.c16
-rw-r--r--lib/locks/exclusive/aarch64/spinlock.S53
-rw-r--r--lib/psci/psci_common.c49
-rw-r--r--lib/psci/psci_main.c13
-rw-r--r--lib/psci/psci_off.c4
-rw-r--r--lib/psci/psci_on.c32
-rw-r--r--lib/psci/psci_private.h24
-rw-r--r--lib/psci/psci_setup.c33
-rw-r--r--lib/psci/psci_stat.c12
-rw-r--r--lib/psci/psci_suspend.c14
-rw-r--r--lib/romlib/jmptbl.i3
-rw-r--r--lib/semihosting/semihosting.c34
-rw-r--r--lib/sprt/sprt_host.c48
-rw-r--r--lib/sprt/sprt_host.mk11
-rw-r--r--lib/sprt/sprt_queue.c104
-rw-r--r--lib/sprt/sprt_queue.h47
-rw-r--r--lib/stack_protector/stack_protector.mk4
-rw-r--r--lib/xlat_tables/aarch32/nonlpae_tables.c22
-rw-r--r--lib/xlat_tables_v2/xlat_tables_core.c9
-rw-r--r--lib/xlat_tables_v2/xlat_tables_utils.c4
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) &parameters);
+#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;