summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile49
-rw-r--r--bl1/bl1.ld.S11
-rw-r--r--bl2/bl2.ld.S13
-rw-r--r--bl2/bl2_main.c3
-rw-r--r--bl2u/bl2u.ld.S13
-rw-r--r--bl31/aarch64/crash_reporting.S8
-rw-r--r--bl31/bl31.ld.S45
-rw-r--r--bl31/bl31.mk44
-rw-r--r--bl31/bl31_main.c6
-rw-r--r--bl31/ehf.c504
-rw-r--r--bl32/sp_min/aarch32/entrypoint.S36
-rw-r--r--bl32/sp_min/sp_min.ld.S25
-rw-r--r--bl32/sp_min/sp_min.mk6
-rw-r--r--bl32/tsp/tsp.ld.S13
-rw-r--r--common/aarch32/debug.S16
-rw-r--r--common/aarch64/debug.S1
-rw-r--r--common/bl_common.c42
-rw-r--r--docs/auth-framework.rst11
-rw-r--r--docs/firmware-design.rst185
-rwxr-xr-xdocs/plantuml/plantuml_to_svg.sh13
-rw-r--r--docs/plantuml/sdei_explicit_dispatch.puml45
-rw-r--r--docs/plantuml/sdei_explicit_dispatch.svg1
-rw-r--r--docs/plantuml/sdei_general.puml43
-rw-r--r--docs/plantuml/sdei_general.svg1
-rw-r--r--docs/plat/hikey.rst25
-rw-r--r--docs/plat/hikey960.rst24
-rw-r--r--docs/plat/poplar.rst175
-rw-r--r--docs/plat/rpi3.rst364
-rw-r--r--docs/platform-interrupt-controller-API.rst313
-rw-r--r--docs/platform-migration-guide.rst11
-rw-r--r--docs/porting-guide.rst186
-rw-r--r--docs/sdei.rst370
-rw-r--r--docs/spm-user-guide.rst59
-rw-r--r--docs/user-guide.rst129
-rw-r--r--docs/xlat-tables-lib-v2-design.rst63
-rw-r--r--drivers/arm/ccn/ccn.c2
-rw-r--r--drivers/arm/ccn/ccn_private.h8
-rw-r--r--drivers/arm/gic/common/gic_common.c22
-rw-r--r--drivers/arm/gic/common/gic_common_private.h4
-rw-r--r--drivers/arm/gic/v2/gicv2_helpers.c118
-rw-r--r--drivers/arm/gic/v2/gicv2_main.c373
-rw-r--r--drivers/arm/gic/v2/gicv2_private.h34
-rw-r--r--drivers/arm/gic/v3/arm_gicv3_common.c105
-rw-r--r--drivers/arm/gic/v3/gic500.c22
-rw-r--r--drivers/arm/gic/v3/gic600.c27
-rw-r--r--drivers/arm/gic/v3/gicv3_helpers.c196
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c825
-rw-r--r--drivers/arm/gic/v3/gicv3_private.h202
-rw-r--r--drivers/auth/mbedtls/mbedtls_common.c5
-rw-r--r--drivers/auth/mbedtls/mbedtls_crypto.c3
-rw-r--r--drivers/auth/mbedtls/mbedtls_crypto.mk48
-rw-r--r--drivers/auth/tbbr/tbbr_cot.c2
-rw-r--r--include/bl31/ehf.h90
-rw-r--r--include/bl31/interrupt_mgmt.h9
-rw-r--r--include/common/aarch32/asm_macros.S19
-rw-r--r--include/common/aarch32/el3_common_macros.S2
-rw-r--r--include/common/aarch64/asm_macros.S8
-rw-r--r--include/common/aarch64/el3_common_macros.S23
-rw-r--r--include/common/bl_common.h1
-rw-r--r--include/common/interrupt_props.h29
-rw-r--r--include/common/param_header.h13
-rw-r--r--include/drivers/arm/arm_gicv3_common.h20
-rw-r--r--include/drivers/arm/gic_common.h25
-rw-r--r--include/drivers/arm/gic_v2.h35
-rw-r--r--include/drivers/arm/gic_v3.h10
-rw-r--r--include/drivers/arm/gicv2.h72
-rw-r--r--include/drivers/arm/gicv3.h229
-rw-r--r--include/drivers/auth/mbedtls/mbedtls_config.h30
-rw-r--r--include/lib/aarch32/arch.h50
-rw-r--r--include/lib/aarch32/arch_helpers.h21
-rw-r--r--include/lib/aarch32/smcc_helpers.h6
-rw-r--r--include/lib/aarch32/smcc_macros.S92
-rw-r--r--include/lib/aarch64/arch.h105
-rw-r--r--include/lib/aarch64/arch_helpers.h35
-rw-r--r--include/lib/cpus/aarch32/cortex_a12.h20
-rw-r--r--include/lib/cpus/aarch32/cortex_a15.h20
-rw-r--r--include/lib/cpus/aarch32/cortex_a17.h20
-rw-r--r--include/lib/cpus/aarch32/cortex_a5.h20
-rw-r--r--include/lib/cpus/aarch32/cortex_a7.h20
-rw-r--r--include/lib/cpus/aarch32/cortex_a9.h31
-rw-r--r--include/lib/cpus/aarch64/cortex_a75.h34
-rw-r--r--include/lib/el3_runtime/aarch64/context.h26
-rw-r--r--include/lib/el3_runtime/cpu_data.h18
-rw-r--r--include/lib/el3_runtime/pubsub.h84
-rw-r--r--include/lib/el3_runtime/pubsub_events.h36
-rw-r--r--include/lib/extensions/amu.h15
-rw-r--r--include/lib/extensions/spe.h13
-rw-r--r--include/lib/extensions/sve.h12
-rw-r--r--include/lib/psci/psci.h20
-rw-r--r--include/lib/utils.h19
-rw-r--r--include/lib/utils_def.h13
-rw-r--r--include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h5
-rw-r--r--include/lib/xlat_tables/xlat_tables_defs.h65
-rw-r--r--include/lib/xlat_tables/xlat_tables_v2.h152
-rw-r--r--include/lib/xlat_tables/xlat_tables_v2_helpers.h57
-rw-r--r--include/plat/arm/board/common/board_arm_def.h49
-rw-r--r--include/plat/arm/board/common/v2m_def.h6
-rw-r--r--include/plat/arm/common/arm_common.ld.S30
-rw-r--r--include/plat/arm/common/arm_def.h201
-rw-r--r--include/plat/arm/common/arm_spm_def.h111
-rw-r--r--include/plat/arm/common/plat_arm.h11
-rw-r--r--include/plat/arm/css/common/css_def.h23
-rw-r--r--include/plat/common/platform.h42
-rw-r--r--include/services/sdei.h181
-rw-r--r--include/services/secure_partition.h66
-rw-r--r--include/services/spm_svc.h89
-rw-r--r--lib/aarch32/arm32_aeabi_divmod.c203
-rw-r--r--lib/aarch32/arm32_aeabi_divmod_a32.S30
-rw-r--r--lib/aarch64/misc_helpers.S30
-rw-r--r--lib/cpus/aarch32/cortex_a12.S75
-rw-r--r--lib/cpus/aarch32/cortex_a15.S81
-rw-r--r--lib/cpus/aarch32/cortex_a17.S75
-rw-r--r--lib/cpus/aarch32/cortex_a5.S75
-rw-r--r--lib/cpus/aarch32/cortex_a53.S4
-rw-r--r--lib/cpus/aarch32/cortex_a57.S4
-rw-r--r--lib/cpus/aarch32/cortex_a7.S75
-rw-r--r--lib/cpus/aarch32/cortex_a72.S4
-rw-r--r--lib/cpus/aarch32/cortex_a9.S75
-rw-r--r--lib/cpus/aarch64/cortex_a75.S29
-rw-r--r--lib/el3_runtime/aarch32/context_mgmt.c19
-rw-r--r--lib/el3_runtime/aarch64/context.S51
-rw-r--r--lib/el3_runtime/aarch64/context_mgmt.c101
-rw-r--r--lib/extensions/amu/aarch32/amu.c32
-rw-r--r--lib/extensions/amu/aarch64/amu.c40
-rw-r--r--lib/extensions/spe/spe.c85
-rw-r--r--lib/extensions/sve/sve.c126
-rw-r--r--lib/locks/exclusive/aarch32/spinlock.S12
-rw-r--r--lib/psci/psci_common.c4
-rw-r--r--lib/psci/psci_lib.mk1
-rw-r--r--lib/psci/psci_main.c33
-rw-r--r--lib/psci/psci_mem_protect.c38
-rw-r--r--lib/psci/psci_on.c3
-rw-r--r--lib/psci/psci_private.h9
-rw-r--r--lib/psci/psci_setup.c9
-rw-r--r--lib/psci/psci_suspend.c14
-rw-r--r--lib/psci/psci_system_off.c30
-rw-r--r--lib/utils/mem_region.c78
-rw-r--r--lib/xlat_tables/aarch32/xlat_tables.c4
-rw-r--r--lib/xlat_tables/aarch64/xlat_tables.c11
-rw-r--r--lib/xlat_tables_v2/aarch32/xlat_tables_arch.c26
-rw-r--r--lib/xlat_tables_v2/aarch32/xlat_tables_arch_private.h22
-rw-r--r--lib/xlat_tables_v2/aarch64/xlat_tables_arch.c80
-rw-r--r--lib/xlat_tables_v2/aarch64/xlat_tables_arch_private.h28
-rw-r--r--lib/xlat_tables_v2/xlat_tables.mk2
-rw-r--r--lib/xlat_tables_v2/xlat_tables_internal.c561
-rw-r--r--lib/xlat_tables_v2/xlat_tables_private.h34
-rw-r--r--maintainers.rst52
-rw-r--r--make_helpers/armv7-a-cpus.mk50
-rw-r--r--make_helpers/build_macros.mk2
-rw-r--r--make_helpers/defaults.mk38
-rw-r--r--make_helpers/tbbr/tbbr_tools.mk3
-rw-r--r--plat/arm/board/common/board_arm_trusted_boot.c13
-rw-r--r--plat/arm/board/common/board_common.mk14
-rw-r--r--plat/arm/board/common/board_css_common.c9
-rw-r--r--plat/arm/board/common/rotpk/arm_rotpk_ecdsa.derbin0 -> 91 bytes
-rw-r--r--plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin1
-rw-r--r--plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem5
-rw-r--r--plat/arm/board/fvp/fvp_common.c75
-rw-r--r--plat/arm/board/fvp/fvp_pm.c111
-rw-r--r--plat/arm/board/fvp/fvp_topology.c16
-rw-r--r--plat/arm/board/fvp/include/plat.ld.S11
-rw-r--r--plat/arm/board/fvp/include/platform_def.h16
-rw-r--r--plat/arm/board/fvp/platform.mk9
-rw-r--r--plat/arm/board/fvp/sp_min/sp_min-fvp.mk5
-rw-r--r--plat/arm/board/fvp/tsp/tsp-fvp.mk5
-rw-r--r--plat/arm/board/juno/include/platform_def.h76
-rw-r--r--plat/arm/board/juno/juno_bl2_setup.c29
-rw-r--r--plat/arm/board/juno/platform.mk19
-rw-r--r--plat/arm/board/juno/sp_min/sp_min-juno.mk3
-rw-r--r--plat/arm/common/aarch64/arm_ehf.c24
-rw-r--r--plat/arm/common/aarch64/arm_helpers.S29
-rw-r--r--plat/arm/common/aarch64/arm_sdei.c33
-rw-r--r--plat/arm/common/arm_bl2_setup.c4
-rw-r--r--plat/arm/common/arm_common.c57
-rw-r--r--plat/arm/common/arm_common.mk22
-rw-r--r--plat/arm/common/arm_gicv2.c36
-rw-r--r--plat/arm/common/arm_gicv3.c78
-rw-r--r--plat/arm/common/arm_gicv3_legacy.c13
-rw-r--r--plat/arm/common/arm_nor_psci_mem_protect.c95
-rw-r--r--plat/arm/common/arm_pm.c49
-rw-r--r--plat/arm/common/arm_tzc400.c28
-rw-r--r--plat/arm/common/arm_tzc_dmc500.c2
-rw-r--r--plat/arm/css/common/css_bl2_setup.c8
-rw-r--r--plat/arm/css/common/css_pm.c42
-rw-r--r--plat/arm/css/drivers/scp/css_pm_scmi.c84
-rw-r--r--plat/arm/css/drivers/scp/css_scp.h2
-rw-r--r--plat/common/aarch32/platform_helpers.S53
-rw-r--r--plat/common/aarch64/plat_common.c26
-rw-r--r--plat/common/aarch64/platform_helpers.S21
-rw-r--r--plat/common/plat_gicv2.c171
-rw-r--r--plat/common/plat_gicv3.c126
-rw-r--r--plat/common/plat_psci_common.c9
-rw-r--r--plat/compat/plat_compat.mk3
-rw-r--r--plat/hisilicon/hikey/aarch64/hikey_common.c8
-rw-r--r--plat/hisilicon/hikey/hikey_bl1_setup.c11
-rw-r--r--plat/hisilicon/hikey/hikey_bl31_setup.c17
-rw-r--r--plat/hisilicon/hikey/hikey_io_storage.c2
-rw-r--r--plat/hisilicon/hikey/include/hi6220.h7
-rw-r--r--plat/hisilicon/hikey/include/platform_def.h6
-rw-r--r--plat/hisilicon/hikey/platform.mk1
-rw-r--r--plat/hisilicon/hikey960/aarch64/hikey960_common.c8
-rw-r--r--plat/hisilicon/hikey960/hikey960_pm.c87
-rw-r--r--plat/hisilicon/hikey960/include/platform_def.h10
-rw-r--r--plat/hisilicon/hikey960/platform.mk1
-rw-r--r--plat/hisilicon/poplar/include/platform_def.h46
-rw-r--r--plat/hisilicon/poplar/platform.mk2
-rw-r--r--plat/mediatek/mt6795/bl31.ld.S9
-rw-r--r--plat/mediatek/mt6795/platform.mk2
-rw-r--r--plat/mediatek/mt8173/include/platform_def.h33
-rw-r--r--plat/mediatek/mt8173/platform.mk3
-rw-r--r--plat/nvidia/tegra/common/tegra_gic.c6
-rw-r--r--plat/nvidia/tegra/platform.mk3
-rw-r--r--plat/nvidia/tegra/soc/t186/drivers/mce/ari.c6
-rw-r--r--plat/qemu/aarch64/plat_helpers.S1
-rw-r--r--plat/qemu/include/platform_def.h8
-rw-r--r--plat/qemu/platform.mk49
-rw-r--r--plat/qemu/qemu_bl31_setup.c41
-rw-r--r--plat/qemu/qemu_io_storage.c98
-rw-r--r--plat/qemu/qemu_rotpk.S15
-rw-r--r--plat/qemu/qemu_trusted_boot.c31
-rw-r--r--plat/rockchip/rk3328/include/platform_def.h8
-rw-r--r--plat/rockchip/rk3328/platform.mk5
-rw-r--r--plat/rockchip/rk3368/platform.mk5
-rw-r--r--plat/rockchip/rk3399/include/plat.ld.S20
-rw-r--r--plat/rockchip/rk3399/plat_sip_calls.c1
-rw-r--r--plat/rockchip/rk3399/platform.mk5
-rw-r--r--plat/rpi3/aarch64/plat_helpers.S183
-rw-r--r--plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c131
-rw-r--r--plat/rpi3/include/plat_macros.S23
-rw-r--r--plat/rpi3/include/platform_def.h229
-rw-r--r--plat/rpi3/platform.mk113
-rw-r--r--plat/rpi3/rpi3_bl1_setup.c63
-rw-r--r--plat/rpi3/rpi3_bl2_setup.c89
-rw-r--r--plat/rpi3/rpi3_bl31_setup.c168
-rw-r--r--plat/rpi3/rpi3_common.c166
-rw-r--r--plat/rpi3/rpi3_hw.h51
-rw-r--r--plat/rpi3/rpi3_image_load.c35
-rw-r--r--plat/rpi3/rpi3_io_storage.c251
-rw-r--r--plat/rpi3/rpi3_pm.c209
-rw-r--r--plat/rpi3/rpi3_private.h35
-rw-r--r--plat/rpi3/rpi3_topology.c56
-rw-r--r--plat/socionext/uniphier/platform.mk11
-rw-r--r--plat/socionext/uniphier/uniphier_gicv3.c63
-rw-r--r--plat/socionext/uniphier/uniphier_rotpk.S1
-rw-r--r--plat/xilinx/zynqmp/include/platform_def.h36
-rw-r--r--plat/xilinx/zynqmp/platform.mk3
-rw-r--r--services/spd/opteed/opteed_common.c2
-rw-r--r--services/spd/tlkd/tlkd_common.c2
-rw-r--r--services/spd/trusty/trusty.c15
-rw-r--r--services/spd/tspd/tspd_common.c2
-rw-r--r--services/std_svc/sdei/sdei_event.c98
-rw-r--r--services/std_svc/sdei/sdei_intr_mgmt.c678
-rw-r--r--services/std_svc/sdei/sdei_main.c1066
-rw-r--r--services/std_svc/sdei/sdei_private.h234
-rw-r--r--services/std_svc/sdei/sdei_state.c150
-rw-r--r--services/std_svc/spm/aarch64/spm_helpers.S74
-rw-r--r--services/std_svc/spm/aarch64/spm_shim_exceptions.S128
-rw-r--r--services/std_svc/spm/secure_partition_setup.c314
-rw-r--r--services/std_svc/spm/spm.mk25
-rw-r--r--services/std_svc/spm/spm_main.c455
-rw-r--r--services/std_svc/spm/spm_private.h55
-rw-r--r--services/std_svc/spm/spm_shim_private.h29
-rw-r--r--services/std_svc/std_svc_setup.c42
-rw-r--r--tools/cert_create/include/cert.h10
-rw-r--r--tools/cert_create/include/key.h9
-rw-r--r--tools/cert_create/include/sha.h4
-rw-r--r--tools/cert_create/src/cert.c37
-rw-r--r--tools/cert_create/src/ext.c2
-rw-r--r--tools/cert_create/src/key.c28
-rw-r--r--tools/cert_create/src/main.c60
-rw-r--r--tools/cert_create/src/sha.c29
-rw-r--r--tools/fiptool/fiptool.c15
-rw-r--r--tools/fiptool/fiptool.h2
-rw-r--r--tools/fiptool/fiptool_platform.h30
-rw-r--r--tools/fiptool/win_posix.c287
-rw-r--r--tools/fiptool/win_posix.h187
276 files changed, 16320 insertions, 1292 deletions
diff --git a/Makefile b/Makefile
index b8f2eb51..51e622ef 100644
--- a/Makefile
+++ b/Makefile
@@ -127,20 +127,28 @@ NM := ${CROSS_COMPILE}nm
PP := ${CROSS_COMPILE}gcc -E
DTC ?= dtc
+ifeq (${ARM_ARCH_MAJOR},7)
+target32-directive = -target arm-none-eabi
+# Will set march32-directive from platform configuration
+else
+target32-directive = -target armv8a-none-eabi
+march32-directive = -march=armv8-a
+endif
+
ifeq ($(notdir $(CC)),armclang)
-TF_CFLAGS_aarch32 = -target arm-arm-none-eabi -march=armv8-a
+TF_CFLAGS_aarch32 = -target arm-arm-none-eabi $(march32-directive)
TF_CFLAGS_aarch64 = -target aarch64-arm-none-eabi -march=armv8-a
else ifneq ($(findstring clang,$(notdir $(CC))),)
-TF_CFLAGS_aarch32 = -target armv8a-none-eabi
+TF_CFLAGS_aarch32 = $(target32-directive)
TF_CFLAGS_aarch64 = -target aarch64-elf
else
-TF_CFLAGS_aarch32 = -march=armv8-a
+TF_CFLAGS_aarch32 = $(march32-directive)
TF_CFLAGS_aarch64 = -march=armv8-a
endif
TF_CFLAGS_aarch64 += -mgeneral-regs-only -mstrict-align
-ASFLAGS_aarch32 = -march=armv8-a
+ASFLAGS_aarch32 = $(march32-directive)
ASFLAGS_aarch64 = -march=armv8-a
CPPFLAGS = ${DEFINES} ${INCLUDES} -nostdinc \
@@ -192,6 +200,7 @@ INCLUDES += -Iinclude/bl1 \
-Iinclude/lib/cpus/${ARCH} \
-Iinclude/lib/el3_runtime \
-Iinclude/lib/el3_runtime/${ARCH} \
+ -Iinclude/lib/extensions \
-Iinclude/lib/pmf \
-Iinclude/lib/psci \
-Iinclude/lib/xlat_tables \
@@ -263,6 +272,12 @@ include lib/stack_protector/stack_protector.mk
include ${PLAT_MAKEFILE_FULL}
+$(eval $(call MAKE_PREREQ_DIR,${BUILD_PLAT}))
+
+ifeq (${ARM_ARCH_MAJOR},7)
+include make_helpers/armv7-a-cpus.mk
+endif
+
# Platform compatibility is not supported in AArch32
ifneq (${ARCH},aarch32)
# If the platform has not defined ENABLE_PLAT_COMPAT, then enable it by default
@@ -371,6 +386,17 @@ ifdef SCP_BL2
NEED_SCP_BL2 := yes
endif
+# For AArch32, BL31 is not currently supported.
+ifneq (${ARCH},aarch32)
+ ifdef BL31_SOURCES
+ # When booting an EL3 payload, there is no need to compile the BL31 image nor
+ # put it in the FIP.
+ ifndef EL3_PAYLOAD_BASE
+ NEED_BL31 := yes
+ endif
+ endif
+endif
+
# Process TBB related flags
ifneq (${GENERATE_COT},0)
# Common cert_create options
@@ -422,17 +448,11 @@ NEED_BL2U := yes
include bl2u/bl2u.mk
endif
-# For AArch32, BL31 is not currently supported.
-ifneq (${ARCH},aarch32)
+ifeq (${NEED_BL31},yes)
ifdef BL31_SOURCES
-# When booting an EL3 payload, there is no need to compile the BL31 image nor
-# put it in the FIP.
-ifndef EL3_PAYLOAD_BASE
-NEED_BL31 := yes
include bl31/bl31.mk
endif
endif
-endif
ifdef FDT_SOURCES
NEED_FDT := yes
@@ -448,14 +468,17 @@ $(eval $(call assert_boolean,CTX_INCLUDE_AARCH32_REGS))
$(eval $(call assert_boolean,CTX_INCLUDE_FPREGS))
$(eval $(call assert_boolean,DEBUG))
$(eval $(call assert_boolean,DISABLE_PEDANTIC))
+$(eval $(call assert_boolean,ENABLE_AMU))
$(eval $(call assert_boolean,ENABLE_ASSERTIONS))
$(eval $(call assert_boolean,ENABLE_PLAT_COMPAT))
$(eval $(call assert_boolean,ENABLE_PMF))
$(eval $(call assert_boolean,ENABLE_PSCI_STAT))
$(eval $(call assert_boolean,ENABLE_RUNTIME_INSTRUMENTATION))
$(eval $(call assert_boolean,ENABLE_SPE_FOR_LOWER_ELS))
+$(eval $(call assert_boolean,ENABLE_SVE_FOR_NS))
$(eval $(call assert_boolean,ERROR_DEPRECATED))
$(eval $(call assert_boolean,GENERATE_COT))
+$(eval $(call assert_boolean,GICV2_G0_FOR_EL3))
$(eval $(call assert_boolean,HW_ASSISTED_COHERENCY))
$(eval $(call assert_boolean,LOAD_IMAGE_V2))
$(eval $(call assert_boolean,NS_TIMER_SWITCH))
@@ -486,13 +509,16 @@ $(eval $(call add_define,ARM_GIC_ARCH))
$(eval $(call add_define,COLD_BOOT_SINGLE_CPU))
$(eval $(call add_define,CTX_INCLUDE_AARCH32_REGS))
$(eval $(call add_define,CTX_INCLUDE_FPREGS))
+$(eval $(call add_define,ENABLE_AMU))
$(eval $(call add_define,ENABLE_ASSERTIONS))
$(eval $(call add_define,ENABLE_PLAT_COMPAT))
$(eval $(call add_define,ENABLE_PMF))
$(eval $(call add_define,ENABLE_PSCI_STAT))
$(eval $(call add_define,ENABLE_RUNTIME_INSTRUMENTATION))
$(eval $(call add_define,ENABLE_SPE_FOR_LOWER_ELS))
+$(eval $(call add_define,ENABLE_SVE_FOR_NS))
$(eval $(call add_define,ERROR_DEPRECATED))
+$(eval $(call add_define,GICV2_G0_FOR_EL3))
$(eval $(call add_define,HW_ASSISTED_COHERENCY))
$(eval $(call add_define,LOAD_IMAGE_V2))
$(eval $(call add_define,LOG_LEVEL))
@@ -503,6 +529,7 @@ $(eval $(call add_define,PROGRAMMABLE_RESET_ADDRESS))
$(eval $(call add_define,PSCI_EXTENDED_STATE_ID))
$(eval $(call add_define,RESET_TO_BL31))
$(eval $(call add_define,SEPARATE_CODE_AND_RODATA))
+$(eval $(call add_define,ENABLE_SPM))
$(eval $(call add_define,SPD_${SPD}))
$(eval $(call add_define,SPIN_ON_BL1_EXIT))
$(eval $(call add_define,TRUSTED_BOARD_BOOT))
diff --git a/bl1/bl1.ld.S b/bl1/bl1.ld.S
index 2c453bd2..e4c454b3 100644
--- a/bl1/bl1.ld.S
+++ b/bl1/bl1.ld.S
@@ -5,6 +5,7 @@
*/
#include <platform_def.h>
+#include <xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
@@ -18,7 +19,7 @@ MEMORY {
SECTIONS
{
. = BL1_RO_BASE;
- ASSERT(. == ALIGN(4096),
+ ASSERT(. == ALIGN(PAGE_SIZE),
"BL1_RO_BASE address is not aligned on a page boundary.")
#if SEPARATE_CODE_AND_RODATA
@@ -27,7 +28,7 @@ SECTIONS
*bl1_entrypoint.o(.text*)
*(.text*)
*(.vectors)
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__TEXT_END__ = .;
} >ROM
@@ -88,7 +89,7 @@ SECTIONS
"cpu_ops not defined for this platform.")
. = BL1_RW_BASE;
- ASSERT(BL1_RW_BASE == ALIGN(4096),
+ ASSERT(BL1_RW_BASE == ALIGN(PAGE_SIZE),
"BL1_RW_BASE address is not aligned on a page boundary.")
/*
@@ -141,7 +142,7 @@ SECTIONS
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
- coherent_ram (NOLOAD) : ALIGN(4096) {
+ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
*(tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
@@ -150,7 +151,7 @@ SECTIONS
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
#endif
diff --git a/bl2/bl2.ld.S b/bl2/bl2.ld.S
index f3ab7061..4fe78f9e 100644
--- a/bl2/bl2.ld.S
+++ b/bl2/bl2.ld.S
@@ -5,6 +5,7 @@
*/
#include <platform_def.h>
+#include <xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
@@ -18,7 +19,7 @@ MEMORY {
SECTIONS
{
. = BL2_BASE;
- ASSERT(. == ALIGN(4096),
+ ASSERT(. == ALIGN(PAGE_SIZE),
"BL2_BASE address is not aligned on a page boundary.")
#if SEPARATE_CODE_AND_RODATA
@@ -27,7 +28,7 @@ SECTIONS
*bl2_entrypoint.o(.text*)
*(.text*)
*(.vectors)
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__TEXT_END__ = .;
} >RAM
@@ -41,7 +42,7 @@ SECTIONS
KEEP(*(.img_parser_lib_descs))
__PARSER_LIB_DESCS_END__ = .;
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__RODATA_END__ = .;
} >RAM
#else
@@ -64,7 +65,7 @@ SECTIONS
* read-only, executable. No RW data from the next section must
* creep in. Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__RO_END__ = .;
} >RAM
#endif
@@ -120,7 +121,7 @@ SECTIONS
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
- coherent_ram (NOLOAD) : ALIGN(4096) {
+ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
*(tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
@@ -129,7 +130,7 @@ SECTIONS
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
#endif
diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c
index 0fe82d91..018deb34 100644
--- a/bl2/bl2_main.c
+++ b/bl2/bl2_main.c
@@ -34,6 +34,9 @@ void bl2_main(void)
auth_mod_init();
#endif /* TRUSTED_BOARD_BOOT */
+ /* initialize boot source */
+ bl2_plat_preload_setup();
+
/* Load the subsequent bootloader images. */
next_bl_ep_info = bl2_load_images();
diff --git a/bl2u/bl2u.ld.S b/bl2u/bl2u.ld.S
index efae293d..da587172 100644
--- a/bl2u/bl2u.ld.S
+++ b/bl2u/bl2u.ld.S
@@ -5,6 +5,7 @@
*/
#include <platform_def.h>
+#include <xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
@@ -18,7 +19,7 @@ MEMORY {
SECTIONS
{
. = BL2U_BASE;
- ASSERT(. == ALIGN(4096),
+ ASSERT(. == ALIGN(PAGE_SIZE),
"BL2U_BASE address is not aligned on a page boundary.")
#if SEPARATE_CODE_AND_RODATA
@@ -27,14 +28,14 @@ SECTIONS
*bl2u_entrypoint.o(.text*)
*(.text*)
*(.vectors)
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__TEXT_END__ = .;
} >RAM
.rodata . : {
__RODATA_START__ = .;
*(.rodata*)
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__RODATA_END__ = .;
} >RAM
#else
@@ -51,7 +52,7 @@ SECTIONS
* read-only, executable. No RW data from the next section must
* creep in. Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__RO_END__ = .;
} >RAM
#endif
@@ -107,7 +108,7 @@ SECTIONS
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
- coherent_ram (NOLOAD) : ALIGN(4096) {
+ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
*(tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
@@ -116,7 +117,7 @@ SECTIONS
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
#endif
diff --git a/bl31/aarch64/crash_reporting.S b/bl31/aarch64/crash_reporting.S
index 34e4dcdd..cf32b31d 100644
--- a/bl31/aarch64/crash_reporting.S
+++ b/bl31/aarch64/crash_reporting.S
@@ -46,8 +46,7 @@ non_el3_sys_regs:
"tpidrro_el0", "dacr32_el2", "ifsr32_el2", "par_el1",\
"mpidr_el1", "afsr0_el1", "afsr1_el1", "contextidr_el1",\
"vbar_el1", "cntp_ctl_el0", "cntp_cval_el0", "cntv_ctl_el0",\
- "cntv_cval_el0", "cntkctl_el1", "fpexc32_el2", "sp_el0",\
- "isr_el1", ""
+ "cntv_cval_el0", "cntkctl_el1", "sp_el0", "isr_el1", ""
panic_msg:
.asciz "PANIC in EL3 at x30 = 0x"
@@ -313,9 +312,8 @@ func do_crash_reporting
mrs x15, cntv_cval_el0
bl str_in_crash_buf_print
mrs x8, cntkctl_el1
- mrs x9, fpexc32_el2
- mrs x10, sp_el0
- mrs x11, isr_el1
+ mrs x9, sp_el0
+ mrs x10, isr_el1
bl str_in_crash_buf_print
/* Get the cpu specific registers to report */
diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S
index 48861f40..dd046c43 100644
--- a/bl31/bl31.ld.S
+++ b/bl31/bl31.ld.S
@@ -5,6 +5,7 @@
*/
#include <platform_def.h>
+#include <xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
@@ -22,7 +23,7 @@ MEMORY {
SECTIONS
{
. = BL31_BASE;
- ASSERT(. == ALIGN(4096),
+ ASSERT(. == ALIGN(PAGE_SIZE),
"BL31_BASE address is not aligned on a page boundary.")
#if SEPARATE_CODE_AND_RODATA
@@ -31,7 +32,7 @@ SECTIONS
*bl31_entrypoint.o(.text*)
*(.text*)
*(.vectors)
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__TEXT_END__ = .;
} >RAM
@@ -62,7 +63,11 @@ SECTIONS
KEEP(*(cpu_ops))
__CPU_OPS_END__ = .;
- . = NEXT(4096);
+ /* Place pubsub sections for events */
+ . = ALIGN(8);
+#include <pubsub_events.h>
+
+ . = NEXT(PAGE_SIZE);
__RODATA_END__ = .;
} >RAM
#else
@@ -95,6 +100,10 @@ SECTIONS
KEEP(*(cpu_ops))
__CPU_OPS_END__ = .;
+ /* Place pubsub sections for events */
+ . = ALIGN(8);
+#include <pubsub_events.h>
+
*(.vectors)
__RO_END_UNALIGNED__ = .;
/*
@@ -102,7 +111,7 @@ SECTIONS
* executable. No RW data from the next section must creep in.
* Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__RO_END__ = .;
} >RAM
#endif
@@ -110,6 +119,23 @@ SECTIONS
ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
"cpu_ops not defined for this platform.")
+#if ENABLE_SPM
+ /*
+ * Exception vectors of the SPM shim layer. They must be aligned to a 2K
+ * address, but we need to place them in a separate page so that we can set
+ * individual permissions to them, so the actual alignment needed is 4K.
+ *
+ * There's no need to include this into the RO section of BL31 because it
+ * doesn't need to be accessed by BL31.
+ */
+ spm_shim_exceptions : ALIGN(PAGE_SIZE) {
+ __SPM_SHIM_EXCEPTIONS_START__ = .;
+ *(.spm_shim_exceptions)
+ . = NEXT(PAGE_SIZE);
+ __SPM_SHIM_EXCEPTIONS_END__ = .;
+ } >RAM
+#endif
+
/*
* Define a linker symbol to mark start of the RW memory area for this
* image.
@@ -194,6 +220,13 @@ SECTIONS
* the .bss section and eliminates the unecessary zero init
*/
xlat_table (NOLOAD) : {
+#if ENABLE_SPM
+ __SP_IMAGE_XLAT_TABLES_START__ = .;
+ *secure_partition*.o(xlat_table)
+ /* Make sure that the rest of the page is empty. */
+ . = NEXT(PAGE_SIZE);
+ __SP_IMAGE_XLAT_TABLES_END__ = .;
+#endif
*(xlat_table)
} >RAM
@@ -204,7 +237,7 @@ SECTIONS
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
- coherent_ram (NOLOAD) : ALIGN(4096) {
+ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
/*
* Bakery locks are stored in coherent memory
@@ -219,7 +252,7 @@ SECTIONS
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
#endif
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 0c9e3939..fdcc9313 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -4,6 +4,15 @@
# SPDX-License-Identifier: BSD-3-Clause
#
+################################################################################
+# Include SPM Makefile
+################################################################################
+ifeq (${ENABLE_SPM},1)
+$(info Including SPM makefile)
+include services/std_svc/spm/spm.mk
+endif
+
+
include lib/psci/psci_lib.mk
BL31_SOURCES += bl31/bl31_main.c \
@@ -15,12 +24,40 @@ BL31_SOURCES += bl31/bl31_main.c \
common/runtime_svc.c \
plat/common/aarch64/platform_mp_stack.S \
services/std_svc/std_svc_setup.c \
- ${PSCI_LIB_SOURCES}
+ ${PSCI_LIB_SOURCES} \
+ ${SPM_SOURCES} \
+
ifeq (${ENABLE_PMF}, 1)
BL31_SOURCES += lib/pmf/pmf_main.c
endif
+ifeq (${EL3_EXCEPTION_HANDLING},1)
+BL31_SOURCES += bl31/ehf.c
+endif
+
+ifeq (${SDEI_SUPPORT},1)
+ifeq (${EL3_EXCEPTION_HANDLING},0)
+ $(error EL3_EXCEPTION_HANDLING must be 1 for SDEI support)
+endif
+BL31_SOURCES += services/std_svc/sdei/sdei_event.c \
+ services/std_svc/sdei/sdei_intr_mgmt.c \
+ services/std_svc/sdei/sdei_main.c \
+ services/std_svc/sdei/sdei_state.c
+endif
+
+ifeq (${ENABLE_SPE_FOR_LOWER_ELS},1)
+BL31_SOURCES += lib/extensions/spe/spe.c
+endif
+
+ifeq (${ENABLE_AMU},1)
+BL31_SOURCES += lib/extensions/amu/aarch64/amu.c
+endif
+
+ifeq (${ENABLE_SVE_FOR_NS},1)
+BL31_SOURCES += lib/extensions/sve/sve.c
+endif
+
BL31_LINKERFILE := bl31/bl31.ld.S
# Flag used to indicate if Crash reporting via console should be included
@@ -30,4 +67,9 @@ CRASH_REPORTING := $(DEBUG)
endif
$(eval $(call assert_boolean,CRASH_REPORTING))
+$(eval $(call assert_boolean,EL3_EXCEPTION_HANDLING))
+$(eval $(call assert_boolean,SDEI_SUPPORT))
+
$(eval $(call add_define,CRASH_REPORTING))
+$(eval $(call add_define,EL3_EXCEPTION_HANDLING))
+$(eval $(call add_define,SDEI_SUPPORT))
diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c
index 4a88bd7b..a34cf86d 100644
--- a/bl31/bl31_main.c
+++ b/bl31/bl31_main.c
@@ -12,6 +12,7 @@
#include <console.h>
#include <context_mgmt.h>
#include <debug.h>
+#include <ehf.h>
#include <platform.h>
#include <pmf.h>
#include <runtime_instr.h>
@@ -79,6 +80,11 @@ void bl31_main(void)
/* Initialise helper libraries */
bl31_lib_init();
+#if EL3_EXCEPTION_HANDLING
+ INFO("BL31: Initialising Exception Handling Framework\n");
+ ehf_init();
+#endif
+
/* Initialize the runtime services e.g. psci. */
INFO("BL31: Initializing runtime services\n");
runtime_svc_init();
diff --git a/bl31/ehf.c b/bl31/ehf.c
new file mode 100644
index 00000000..65f2df52
--- /dev/null
+++ b/bl31/ehf.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Exception handlers at EL3, their priority levels, and management.
+ */
+
+#include <assert.h>
+#include <cpu_data.h>
+#include <debug.h>
+#include <ehf.h>
+#include <gic_common.h>
+#include <interrupt_mgmt.h>
+#include <platform.h>
+#include <pubsub_events.h>
+
+/* Output EHF logs as verbose */
+#define EHF_LOG(...) VERBOSE("EHF: " __VA_ARGS__)
+
+#define EHF_INVALID_IDX (-1)
+
+/* For a valid handler, return the actual function pointer; otherwise, 0. */
+#define RAW_HANDLER(h) \
+ ((ehf_handler_t) ((h & _EHF_PRI_VALID) ? (h & ~_EHF_PRI_VALID) : 0))
+
+#define PRI_BIT(idx) (((ehf_pri_bits_t) 1) << idx)
+
+/*
+ * Convert index into secure priority using the platform-defined priority bits
+ * field.
+ */
+#define IDX_TO_PRI(idx) \
+ ((idx << (7 - exception_data.pri_bits)) & 0x7f)
+
+/* Check whether a given index is valid */
+#define IS_IDX_VALID(idx) \
+ ((exception_data.ehf_priorities[idx].ehf_handler & _EHF_PRI_VALID) != 0)
+
+/* Returns whether given priority is in secure priority range */
+#define IS_PRI_SECURE(pri) ((pri & 0x80) == 0)
+
+/* To be defined by the platform */
+extern const ehf_priorities_t exception_data;
+
+/* Translate priority to the index in the priority array */
+static int pri_to_idx(unsigned int priority)
+{
+ int idx;
+
+ idx = EHF_PRI_TO_IDX(priority, exception_data.pri_bits);
+ assert((idx >= 0) && (idx < exception_data.num_priorities));
+ assert(IS_IDX_VALID(idx));
+
+ return idx;
+}
+
+/* Return whether there are outstanding priority activation */
+static int has_valid_pri_activations(pe_exc_data_t *pe_data)
+{
+ return pe_data->active_pri_bits != 0;
+}
+
+static pe_exc_data_t *this_cpu_data(void)
+{
+ return &get_cpu_data(ehf_data);
+}
+
+/*
+ * Return the current priority index of this CPU. If no priority is active,
+ * return EHF_INVALID_IDX.
+ */
+static int get_pe_highest_active_idx(pe_exc_data_t *pe_data)
+{
+ if (!has_valid_pri_activations(pe_data))
+ return EHF_INVALID_IDX;
+
+ /* Current priority is the right-most bit */
+ return __builtin_ctz(pe_data->active_pri_bits);
+}
+
+/*
+ * Mark priority active by setting the corresponding bit in active_pri_bits and
+ * programming the priority mask.
+ *
+ * This API is to be used as part of delegating to lower ELs other than for
+ * interrupts; e.g. while handling synchronous exceptions.
+ *
+ * This API is expected to be invoked before restoring context (Secure or
+ * Non-secure) in preparation for the respective dispatch.
+ */
+void ehf_activate_priority(unsigned int priority)
+{
+ int idx, cur_pri_idx;
+ unsigned int old_mask, run_pri;
+ pe_exc_data_t *pe_data = this_cpu_data();
+
+ /*
+ * Query interrupt controller for the running priority, or idle priority
+ * if no interrupts are being handled. The requested priority must be
+ * less (higher priority) than the active running priority.
+ */
+ run_pri = plat_ic_get_running_priority();
+ if (priority >= run_pri) {
+ ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
+ run_pri, priority);
+ panic();
+ }
+
+ /*
+ * If there were priority activations already, the requested priority
+ * must be less (higher priority) than the current highest priority
+ * activation so far.
+ */
+ cur_pri_idx = get_pe_highest_active_idx(pe_data);
+ idx = pri_to_idx(priority);
+ if ((cur_pri_idx != EHF_INVALID_IDX) && (idx >= cur_pri_idx)) {
+ ERROR("Activation priority mismatch: req=0x%x current=0x%x\n",
+ priority, IDX_TO_PRI(cur_pri_idx));
+ panic();
+ }
+
+ /* Set the bit corresponding to the requested priority */
+ pe_data->active_pri_bits |= PRI_BIT(idx);
+
+ /*
+ * Program priority mask for the activated level. Check that the new
+ * priority mask is setting a higher priority level than the existing
+ * mask.
+ */
+ old_mask = plat_ic_set_priority_mask(priority);
+ if (priority >= old_mask) {
+ ERROR("Requested priority (0x%x) lower than Priority Mask (0x%x)\n",
+ priority, old_mask);
+ panic();
+ }
+
+ /*
+ * If this is the first activation, save the priority mask. This will be
+ * restored after the last deactivation.
+ */
+ if (cur_pri_idx == EHF_INVALID_IDX)
+ pe_data->init_pri_mask = old_mask;
+
+ EHF_LOG("activate prio=%d\n", get_pe_highest_active_idx(pe_data));
+}
+
+/*
+ * Mark priority inactive by clearing the corresponding bit in active_pri_bits,
+ * and programming the priority mask.
+ *
+ * This API is expected to be used as part of delegating to to lower ELs other
+ * than for interrupts; e.g. while handling synchronous exceptions.
+ *
+ * This API is expected to be invoked after saving context (Secure or
+ * Non-secure), having concluded the respective dispatch.
+ */
+void ehf_deactivate_priority(unsigned int priority)
+{
+ int idx, cur_pri_idx;
+ pe_exc_data_t *pe_data = this_cpu_data();
+ unsigned int old_mask, run_pri;
+
+ /*
+ * Query interrupt controller for the running priority, or idle priority
+ * if no interrupts are being handled. The requested priority must be
+ * less (higher priority) than the active running priority.
+ */
+ run_pri = plat_ic_get_running_priority();
+ if (priority >= run_pri) {
+ ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
+ run_pri, priority);
+ panic();
+ }
+
+ /*
+ * Deactivation is allowed only when there are priority activations, and
+ * the deactivation priority level must match the current activated
+ * priority.
+ */
+ cur_pri_idx = get_pe_highest_active_idx(pe_data);
+ idx = pri_to_idx(priority);
+ if ((cur_pri_idx == EHF_INVALID_IDX) || (idx != cur_pri_idx)) {
+ ERROR("Deactivation priority mismatch: req=0x%x current=0x%x\n",
+ priority, IDX_TO_PRI(cur_pri_idx));
+ panic();
+ }
+
+ /* Clear bit corresponding to highest priority */
+ pe_data->active_pri_bits &= (pe_data->active_pri_bits - 1);
+
+ /*
+ * Restore priority mask corresponding to the next priority, or the
+ * one stashed earlier if there are no more to deactivate.
+ */
+ idx = get_pe_highest_active_idx(pe_data);
+ if (idx == EHF_INVALID_IDX)
+ old_mask = plat_ic_set_priority_mask(pe_data->init_pri_mask);
+ else
+ old_mask = plat_ic_set_priority_mask(priority);
+
+ if (old_mask >= priority) {
+ ERROR("Deactivation priority (0x%x) lower than Priority Mask (0x%x)\n",
+ priority, old_mask);
+ panic();
+ }
+
+ EHF_LOG("deactivate prio=%d\n", get_pe_highest_active_idx(pe_data));
+}
+
+/*
+ * After leaving Non-secure world, stash current Non-secure Priority Mask, and
+ * set Priority Mask to the highest Non-secure priority so that Non-secure
+ * interrupts cannot preempt Secure execution.
+ *
+ * If the current running priority is in the secure range, or if there are
+ * outstanding priority activations, this function does nothing.
+ *
+ * This function subscribes to the 'cm_exited_normal_world' event published by
+ * the Context Management Library.
+ */
+static void *ehf_exited_normal_world(const void *arg)
+{
+ unsigned int run_pri;
+ pe_exc_data_t *pe_data = this_cpu_data();
+
+ /* If the running priority is in the secure range, do nothing */
+ run_pri = plat_ic_get_running_priority();
+ if (IS_PRI_SECURE(run_pri))
+ return 0;
+
+ /* Do nothing if there are explicit activations */
+ if (has_valid_pri_activations(pe_data))
+ return 0;
+
+ assert(pe_data->ns_pri_mask == 0);
+
+ pe_data->ns_pri_mask =
+ plat_ic_set_priority_mask(GIC_HIGHEST_NS_PRIORITY);
+
+ /* The previous Priority Mask is not expected to be in secure range */
+ if (IS_PRI_SECURE(pe_data->ns_pri_mask)) {
+ ERROR("Priority Mask (0x%x) already in secure range\n",
+ pe_data->ns_pri_mask);
+ panic();
+ }
+
+ EHF_LOG("Priority Mask: 0x%x => 0x%x\n", pe_data->ns_pri_mask,
+ GIC_HIGHEST_NS_PRIORITY);
+
+ return 0;
+}
+
+/*
+ * Conclude Secure execution and prepare for return to Non-secure world. Restore
+ * the Non-secure Priority Mask previously stashed upon leaving Non-secure
+ * world.
+ *
+ * If there the current running priority is in the secure range, or if there are
+ * outstanding priority activations, this function does nothing.
+ *
+ * This function subscribes to the 'cm_entering_normal_world' event published by
+ * the Context Management Library.
+ */
+static void *ehf_entering_normal_world(const void *arg)
+{
+ unsigned int old_pmr, run_pri;
+ pe_exc_data_t *pe_data = this_cpu_data();
+
+ /* If the running priority is in the secure range, do nothing */
+ run_pri = plat_ic_get_running_priority();
+ if (IS_PRI_SECURE(run_pri))
+ return 0;
+
+ /*
+ * If there are explicit activations, do nothing. The Priority Mask will
+ * be restored upon the last deactivation.
+ */
+ if (has_valid_pri_activations(pe_data))
+ return 0;
+
+ /* Do nothing if we don't have a valid Priority Mask to restore */
+ if (pe_data->ns_pri_mask == 0)
+ return 0;
+
+ old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask);
+
+ /*
+ * When exiting secure world, the current Priority Mask must be
+ * GIC_HIGHEST_NS_PRIORITY (as set during entry), or the Non-secure
+ * priority mask set upon calling ehf_allow_ns_preemption()
+ */
+ if ((old_pmr != GIC_HIGHEST_NS_PRIORITY) &&
+ (old_pmr != pe_data->ns_pri_mask)) {
+ ERROR("Invalid Priority Mask (0x%x) restored\n", old_pmr);
+ panic();
+ }
+
+ EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask);
+
+ pe_data->ns_pri_mask = 0;
+
+ return 0;
+}
+
+/*
+ * Program Priority Mask to the original Non-secure priority such that
+ * Non-secure interrupts may preempt Secure execution, viz. during Yielding SMC
+ * calls.
+ *
+ * This API is expected to be invoked before delegating a yielding SMC to Secure
+ * EL1. I.e. within the window of secure execution after Non-secure context is
+ * saved (after entry into EL3) and Secure context is restored (before entering
+ * Secure EL1).
+ */
+void ehf_allow_ns_preemption(void)
+{
+ unsigned int old_pmr __unused;
+ pe_exc_data_t *pe_data = this_cpu_data();
+
+ /*
+ * We should have been notified earlier of entering secure world, and
+ * therefore have stashed the Non-secure priority mask.
+ */
+ assert(pe_data->ns_pri_mask != 0);
+
+ /* Make sure no priority levels are active when requesting this */
+ if (has_valid_pri_activations(pe_data)) {
+ ERROR("PE %lx has priority activations: 0x%x\n",
+ read_mpidr_el1(), pe_data->active_pri_bits);
+ panic();
+ }
+
+ old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask);
+
+ EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask);
+
+ pe_data->ns_pri_mask = 0;
+}
+
+/*
+ * Return whether Secure execution has explicitly allowed Non-secure interrupts
+ * to preempt itself, viz. during Yielding SMC calls.
+ */
+unsigned int ehf_is_ns_preemption_allowed(void)
+{
+ unsigned int run_pri;
+ pe_exc_data_t *pe_data = this_cpu_data();
+
+ /* If running priority is in secure range, return false */
+ run_pri = plat_ic_get_running_priority();
+ if (IS_PRI_SECURE(run_pri))
+ return 0;
+
+ /*
+ * If Non-secure preemption was permitted by calling
+ * ehf_allow_ns_preemption() earlier:
+ *
+ * - There wouldn't have been priority activations;
+ * - We would have cleared the stashed the Non-secure Priority Mask.
+ */
+ if (has_valid_pri_activations(pe_data))
+ return 0;
+ if (pe_data->ns_pri_mask != 0)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Top-level EL3 interrupt handler.
+ */
+static uint64_t ehf_el3_interrupt_handler(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ int pri, idx, intr, intr_raw, ret = 0;
+ ehf_handler_t handler;
+
+ /*
+ * Top-level interrupt type handler from Interrupt Management Framework
+ * doesn't acknowledge the interrupt; so the interrupt ID must be
+ * invalid.
+ */
+ assert(id == INTR_ID_UNAVAILABLE);
+
+ /*
+ * Acknowledge interrupt. Proceed with handling only for valid interrupt
+ * IDs. This situation may arise because of Interrupt Management
+ * Framework identifying an EL3 interrupt, but before it's been
+ * acknowledged here, the interrupt was either deasserted, or there was
+ * a higher-priority interrupt of another type.
+ */
+ intr_raw = plat_ic_acknowledge_interrupt();
+ intr = plat_ic_get_interrupt_id(intr_raw);
+ if (intr == INTR_ID_UNAVAILABLE)
+ return 0;
+
+ /* Having acknowledged the interrupt, get the running priority */
+ pri = plat_ic_get_running_priority();
+
+ /* Check EL3 interrupt priority is in secure range */
+ assert(IS_PRI_SECURE(pri));
+
+ /*
+ * Translate the priority to a descriptor index. We do this by masking
+ * and shifting the running priority value (platform-supplied).
+ */
+ idx = pri_to_idx(pri);
+
+ /* Validate priority */
+ assert(pri == IDX_TO_PRI(idx));
+
+ handler = RAW_HANDLER(exception_data.ehf_priorities[idx].ehf_handler);
+ if (!handler) {
+ ERROR("No EL3 exception handler for priority 0x%x\n",
+ IDX_TO_PRI(idx));
+ panic();
+ }
+
+ /*
+ * Call registered handler. Pass the raw interrupt value to registered
+ * handlers.
+ */
+ ret = handler(intr_raw, flags, handle, cookie);
+
+ return ret;
+}
+
+/*
+ * Initialize the EL3 exception handling.
+ */
+void ehf_init(void)
+{
+ unsigned int flags = 0;
+ int ret __unused;
+
+ /* Ensure EL3 interrupts are supported */
+ assert(plat_ic_has_interrupt_type(INTR_TYPE_EL3));
+
+ /*
+ * Make sure that priority water mark has enough bits to represent the
+ * whole priority array.
+ */
+ assert(exception_data.num_priorities <= (sizeof(ehf_pri_bits_t) * 8));
+
+ assert(exception_data.ehf_priorities);
+
+ /*
+ * Bit 7 of GIC priority must be 0 for secure interrupts. This means
+ * platforms must use at least 1 of the remaining 7 bits.
+ */
+ assert((exception_data.pri_bits >= 1) || (exception_data.pri_bits < 8));
+
+ /* Route EL3 interrupts when in Secure and Non-secure. */
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ set_interrupt_rm_flag(flags, SECURE);
+
+ /* Register handler for EL3 interrupts */
+ ret = register_interrupt_type_handler(INTR_TYPE_EL3,
+ ehf_el3_interrupt_handler, flags);
+ assert(ret == 0);
+}
+
+/*
+ * Register a handler at the supplied priority. Registration is allowed only if
+ * a handler hasn't been registered before, or one wasn't provided at build
+ * time. The priority for which the handler is being registered must also accord
+ * with the platform-supplied data.
+ */
+void ehf_register_priority_handler(unsigned int pri, ehf_handler_t handler)
+{
+ int idx;
+
+ /* Sanity check for handler */
+ assert(handler != NULL);
+
+ /* Handler ought to be 4-byte aligned */
+ assert((((uintptr_t) handler) & 3) == 0);
+
+ /* Ensure we register for valid priority */
+ idx = pri_to_idx(pri);
+ assert(idx < exception_data.num_priorities);
+ assert(IDX_TO_PRI(idx) == pri);
+
+ /* Return failure if a handler was already registered */
+ if (exception_data.ehf_priorities[idx].ehf_handler != _EHF_NO_HANDLER) {
+ ERROR("Handler already registered for priority 0x%x\n", pri);
+ panic();
+ }
+
+ /*
+ * Install handler, and retain the valid bit. We assume that the handler
+ * is 4-byte aligned, which is usually the case.
+ */
+ exception_data.ehf_priorities[idx].ehf_handler =
+ (((uintptr_t) handler) | _EHF_PRI_VALID);
+
+ EHF_LOG("register pri=0x%x handler=%p\n", pri, handler);
+}
+
+SUBSCRIBE_TO_EVENT(cm_entering_normal_world, ehf_entering_normal_world);
+SUBSCRIBE_TO_EVENT(cm_exited_normal_world, ehf_exited_normal_world);
diff --git a/bl32/sp_min/aarch32/entrypoint.S b/bl32/sp_min/aarch32/entrypoint.S
index d868c53d..b2b7953f 100644
--- a/bl32/sp_min/aarch32/entrypoint.S
+++ b/bl32/sp_min/aarch32/entrypoint.S
@@ -30,6 +30,16 @@
stcopr \reg, SCR
.endm
+ .macro clrex_on_monitor_entry
+#if (ARM_ARCH_MAJOR == 7)
+ /*
+ * ARMv7 architectures need to clear the exclusive access when
+ * entering Monitor mode.
+ */
+ clrex
+#endif
+ .endm
+
vector_base sp_min_vector_table
b sp_min_entrypoint
b plat_panic_handler /* Undef */
@@ -147,6 +157,8 @@ func handle_smc
smcc_save_gp_mode_regs
+ clrex_on_monitor_entry
+
/*
* `sp` still points to `smc_ctx_t`. Save it to a register
* and restore the C runtime stack pointer to `sp`.
@@ -162,6 +174,15 @@ func handle_smc
stcopr r0, SCR
isb
+ /*
+ * Set PMCR.DP to 1 to prohibit cycle counting whilst in Secure Mode.
+ * Also, the PMCR.LC field has an architecturally UNKNOWN value on reset
+ * and so set to 1 as ARM has deprecated use of PMCR.LC=0.
+ */
+ ldcopr r0, PMCR
+ orr r0, r0, #(PMCR_LC_BIT | PMCR_DP_BIT)
+ stcopr r0, PMCR
+
ldr r0, [r2, #SMC_CTX_GPREG_R0] /* smc_fid */
/* Check whether an SMC64 is issued */
tst r0, #(FUNCID_CC_MASK << FUNCID_CC_SHIFT)
@@ -194,11 +215,7 @@ func handle_fiq
smcc_save_gp_mode_regs
- /*
- * AArch32 architectures need to clear the exclusive access when
- * entering Monitor mode.
- */
- clrex
+ clrex_on_monitor_entry
/* load run-time stack */
mov r2, sp
@@ -210,6 +227,15 @@ func handle_fiq
stcopr r0, SCR
isb
+ /*
+ * Set PMCR.DP to 1 to prohibit cycle counting whilst in Secure Mode.
+ * Also, the PMCR.LC field has an architecturally UNKNOWN value on reset
+ * and so set to 1 as ARM has deprecated use of PMCR.LC=0.
+ */
+ ldcopr r0, PMCR
+ orr r0, r0, #(PMCR_LC_BIT | PMCR_DP_BIT)
+ stcopr r0, PMCR
+
push {r2, r3}
bl sp_min_fiq
pop {r0, r3}
diff --git a/bl32/sp_min/sp_min.ld.S b/bl32/sp_min/sp_min.ld.S
index d0fb4a03..e798a0d3 100644
--- a/bl32/sp_min/sp_min.ld.S
+++ b/bl32/sp_min/sp_min.ld.S
@@ -5,6 +5,7 @@
*/
#include <platform_def.h>
+#include <xlat_tables_defs.h>
OUTPUT_FORMAT(elf32-littlearm)
OUTPUT_ARCH(arm)
@@ -18,7 +19,7 @@ MEMORY {
SECTIONS
{
. = BL32_BASE;
- ASSERT(. == ALIGN(4096),
+ ASSERT(. == ALIGN(PAGE_SIZE),
"BL32_BASE address is not aligned on a page boundary.")
#if SEPARATE_CODE_AND_RODATA
@@ -27,7 +28,7 @@ SECTIONS
*entrypoint.o(.text*)
*(.text*)
*(.vectors)
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__TEXT_END__ = .;
} >RAM
@@ -50,7 +51,11 @@ SECTIONS
KEEP(*(cpu_ops))
__CPU_OPS_END__ = .;
- . = NEXT(4096);
+ /* Place pubsub sections for events */
+ . = ALIGN(8);
+#include <pubsub_events.h>
+
+ . = NEXT(PAGE_SIZE);
__RODATA_END__ = .;
} >RAM
#else
@@ -75,6 +80,10 @@ SECTIONS
KEEP(*(cpu_ops))
__CPU_OPS_END__ = .;
+ /* Place pubsub sections for events */
+ . = ALIGN(8);
+#include <pubsub_events.h>
+
*(.vectors)
__RO_END_UNALIGNED__ = .;
@@ -83,7 +92,7 @@ SECTIONS
* read-only, executable. No RW data from the next section must
* creep in. Ensure the rest of the current memory block is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__RO_END__ = .;
} >RAM
#endif
@@ -102,6 +111,10 @@ SECTIONS
__DATA_END__ = .;
} >RAM
+#ifdef BL32_PROGBITS_LIMIT
+ ASSERT(. <= BL32_PROGBITS_LIMIT, "BL32 progbits has exceeded its limit.")
+#endif
+
stacks (NOLOAD) : {
__STACKS_START__ = .;
*(tzfw_normal_stacks)
@@ -178,7 +191,7 @@ SECTIONS
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
- coherent_ram (NOLOAD) : ALIGN(4096) {
+ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
/*
* Bakery locks are stored in coherent memory
@@ -193,7 +206,7 @@ SECTIONS
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
diff --git a/bl32/sp_min/sp_min.mk b/bl32/sp_min/sp_min.mk
index 39588ce7..56489a3c 100644
--- a/bl32/sp_min/sp_min.mk
+++ b/bl32/sp_min/sp_min.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -22,6 +22,10 @@ ifeq (${ENABLE_PMF}, 1)
BL32_SOURCES += lib/pmf/pmf_main.c
endif
+ifeq (${ENABLE_AMU}, 1)
+BL32_SOURCES += lib/extensions/amu/aarch32/amu.c
+endif
+
BL32_LINKERFILE := bl32/sp_min/sp_min.ld.S
# Include the platform-specific SP_MIN Makefile
diff --git a/bl32/tsp/tsp.ld.S b/bl32/tsp/tsp.ld.S
index 2b672efe..d256b46c 100644
--- a/bl32/tsp/tsp.ld.S
+++ b/bl32/tsp/tsp.ld.S
@@ -5,6 +5,7 @@
*/
#include <platform_def.h>
+#include <xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
@@ -19,7 +20,7 @@ MEMORY {
SECTIONS
{
. = BL32_BASE;
- ASSERT(. == ALIGN(4096),
+ ASSERT(. == ALIGN(PAGE_SIZE),
"BL32_BASE address is not aligned on a page boundary.")
#if SEPARATE_CODE_AND_RODATA
@@ -28,14 +29,14 @@ SECTIONS
*tsp_entrypoint.o(.text*)
*(.text*)
*(.vectors)
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__TEXT_END__ = .;
} >RAM
.rodata . : {
__RODATA_START__ = .;
*(.rodata*)
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__RODATA_END__ = .;
} >RAM
#else
@@ -51,7 +52,7 @@ SECTIONS
* read-only, executable. No RW data from the next section must
* creep in. Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__RO_END__ = .;
} >RAM
#endif
@@ -106,7 +107,7 @@ SECTIONS
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
- coherent_ram (NOLOAD) : ALIGN(4096) {
+ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
*(tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
@@ -115,7 +116,7 @@ SECTIONS
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
#endif
diff --git a/common/aarch32/debug.S b/common/aarch32/debug.S
index 583ee4a5..f5063569 100644
--- a/common/aarch32/debug.S
+++ b/common/aarch32/debug.S
@@ -71,7 +71,15 @@ endfunc report_exception
assert_msg1:
.asciz "ASSERT: File "
assert_msg2:
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+ /******************************************************************
+ * Virtualization comes with the UDIV/SDIV instructions. If missing
+ * write file line number in hexadecimal format.
+ ******************************************************************/
+ .asciz " Line 0x"
+#else
.asciz " Line "
+#endif
/* ---------------------------------------------------------------------------
* Assertion support in assembly.
@@ -113,6 +121,13 @@ func asm_assert
bne 1f
mov r4, r6
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+ /******************************************************************
+ * Virtualization comes with the UDIV/SDIV instructions. If missing
+ * write file line number in hexadecimal format.
+ ******************************************************************/
+ bl asm_print_hex
+#else
/* Print line number in decimal */
mov r6, #10 /* Divide by 10 after every loop iteration */
ldr r5, =MAX_DEC_DIVISOR
@@ -124,6 +139,7 @@ dec_print_loop:
udiv r5, r5, r6 /* Reduce divisor */
cmp r5, #0
bne dec_print_loop
+#endif
bl plat_crash_console_flush
diff --git a/common/aarch64/debug.S b/common/aarch64/debug.S
index d794d12e..4478d0d0 100644
--- a/common/aarch64/debug.S
+++ b/common/aarch64/debug.S
@@ -6,6 +6,7 @@
#include <arch.h>
#include <asm_macros.S>
+#include <debug.h>
.globl asm_print_str
.globl asm_print_hex
diff --git a/common/bl_common.c b/common/bl_common.c
index cad4de90..b0d1bfa7 100644
--- a/common/bl_common.c
+++ b/common/bl_common.c
@@ -200,14 +200,14 @@ size_t image_size(unsigned int image_id)
#if LOAD_IMAGE_V2
/*******************************************************************************
- * Generic function to load an image at a specific address given
+ * Internal function to load an image at a specific address given
* an image ID and extents of free memory.
*
* If the load is successful then the image information is updated.
*
* Returns 0 on success, a negative error code otherwise.
******************************************************************************/
-int load_image(unsigned int image_id, image_info_t *image_data)
+static int load_image(unsigned int image_id, image_info_t *image_data)
{
uintptr_t dev_handle;
uintptr_t image_handle;
@@ -266,17 +266,6 @@ int load_image(unsigned int image_id, image_info_t *image_data)
goto exit;
}
-#if !TRUSTED_BOARD_BOOT
- /*
- * File has been successfully loaded.
- * Flush the image to main memory so that it can be executed later by
- * any CPU, regardless of cache and MMU state.
- * When TBB is enabled the image is flushed later, after image
- * authentication.
- */
- flush_dcache_range(image_base, image_size);
-#endif /* TRUSTED_BOARD_BOOT */
-
INFO("Image id=%u loaded: %p - %p\n", image_id, (void *) image_base,
(void *) (image_base + image_size));
@@ -329,18 +318,19 @@ static int load_auth_image_internal(unsigned int image_id,
image_data->image_size);
return -EAUTH;
}
+#endif /* TRUSTED_BOARD_BOOT */
/*
- * File has been successfully loaded and authenticated.
* Flush the image to main memory so that it can be executed later by
- * any CPU, regardless of cache and MMU state.
- * Do it only for child images, not for the parents (certificates).
+ * any CPU, regardless of cache and MMU state. If TBB is enabled, then
+ * the file has been successfully loaded and authenticated and flush
+ * only for child images, not for the parents (certificates).
*/
if (!is_parent_image) {
flush_dcache_range(image_data->image_base,
image_data->image_size);
}
-#endif /* TRUSTED_BOARD_BOOT */
+
return 0;
}
@@ -354,7 +344,13 @@ static int load_auth_image_internal(unsigned int image_id,
******************************************************************************/
int load_auth_image(unsigned int image_id, image_info_t *image_data)
{
- return load_auth_image_internal(image_id, image_data, 0);
+ int err;
+
+ do {
+ err = load_auth_image_internal(image_id, image_data, 0);
+ } while (err != 0 && plat_try_next_boot_source());
+
+ return err;
}
#else /* LOAD_IMAGE_V2 */
@@ -553,8 +549,14 @@ int load_auth_image(meminfo_t *mem_layout,
image_info_t *image_data,
entry_point_info_t *entry_point_info)
{
- return load_auth_image_internal(mem_layout, image_id, image_base,
- image_data, entry_point_info, 0);
+ int err;
+
+ do {
+ err = load_auth_image_internal(mem_layout, image_id, image_base,
+ image_data, entry_point_info, 0);
+ } while (err != 0 && plat_try_next_boot_source());
+
+ return err;
}
#endif /* LOAD_IMAGE_V2 */
diff --git a/docs/auth-framework.rst b/docs/auth-framework.rst
index 765d9f89..3a054c7f 100644
--- a/docs/auth-framework.rst
+++ b/docs/auth-framework.rst
@@ -921,9 +921,12 @@ three functions:
int verify_hash(void *data_ptr, unsigned int data_len,
void *digest_info_ptr, unsigned int digest_info_len);
-The key algorithm (rsa, ecdsa) must be specified in the build system using the
-``TF_MBEDTLS_KEY_ALG`` variable, so the Makefile can include the corresponding
-sources in the build.
+The mbedTLS library algorithm support is configured by the
+``TF_MBEDTLS_KEY_ALG`` variable which can take in 3 values: `rsa`, `ecdsa` or
+`rsa+ecdsa`. This variable allows the Makefile to include the corresponding
+sources in the build for the various algorthms. Setting the variable to
+`rsa+ecdsa` enables support for both rsa and ecdsa algorithms in the mbedTLS
+library.
Note: If code size is a concern, the build option ``MBEDTLS_SHA256_SMALLER`` can
be defined in the platform Makefile. It will make mbed TLS use an implementation
@@ -931,7 +934,7 @@ of SHA-256 with smaller memory footprint (~1.5 KB less) but slower (~30%).
--------------
-*Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.*
+*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
.. _Trusted Board Boot: ./trusted-board-boot.rst
.. _Platform Porting Guide: ./porting-guide.rst
diff --git a/docs/firmware-design.rst b/docs/firmware-design.rst
index 997d29b8..405964d2 100644
--- a/docs/firmware-design.rst
+++ b/docs/firmware-design.rst
@@ -886,10 +886,10 @@ Power State Coordination Interface
TODO: Provide design walkthrough of PSCI implementation.
-The PSCI v1.0 specification categorizes APIs as optional and mandatory. All the
-mandatory APIs in PSCI v1.0 and all the APIs in PSCI v0.2 draft specification
+The PSCI v1.1 specification categorizes APIs as optional and mandatory. All the
+mandatory APIs in PSCI v1.1, PSCI v1.0 and in PSCI v0.2 draft specification
`Power State Coordination Interface PDD`_ are implemented. The table lists
-the PSCI v1.0 APIs and their support in generic code.
+the PSCI v1.1 APIs and their support in generic code.
An API implementation might have a dependency on platform code e.g. CPU\_SUSPEND
requires the platform to export a part of the implementation. Hence the level
@@ -898,9 +898,9 @@ platform port as well. The Juno and FVP (all variants) platforms export all the
required support.
+-----------------------------+-------------+-------------------------------+
-| PSCI v1.0 API | Supported | Comments |
+| PSCI v1.1 API | Supported | Comments |
+=============================+=============+===============================+
-| ``PSCI_VERSION`` | Yes | The version returned is 1.0 |
+| ``PSCI_VERSION`` | Yes | The version returned is 1.1 |
+-----------------------------+-------------+-------------------------------+
| ``CPU_SUSPEND`` | Yes\* | |
+-----------------------------+-------------+-------------------------------+
@@ -936,6 +936,12 @@ required support.
+-----------------------------+-------------+-------------------------------+
| ``PSCI_STAT_COUNT`` | Yes\* | |
+-----------------------------+-------------+-------------------------------+
+| ``SYSTEM_RESET2`` | Yes\* | |
++-----------------------------+-------------+-------------------------------+
+| ``MEM_PROTECT`` | Yes\* | |
++-----------------------------+-------------+-------------------------------+
+| ``MEM_PROTECT_CHECK_RANGE`` | Yes\* | |
++-----------------------------+-------------+-------------------------------+
\*Note : These PSCI APIs require platform power management hooks to be
registered with the generic PSCI code to be supported.
@@ -1138,7 +1144,6 @@ The sample crash output is shown below.
cntv_ctl_el0 :0x0000000000000000
cntv_cval_el0 :0x0000000000000000
cntkctl_el1 :0x0000000000000000
- fpexc32_el2 :0x0000000004000700
sp_el0 :0x0000000004010780
Guidelines for Reset Handlers
@@ -1161,6 +1166,56 @@ In other words, the reset handler should be able to detect whether an action has
already been performed and act as appropriate. Possible courses of actions are,
e.g. skip the action the second time, or undo/redo it.
+Configuring secure interrupts
+-----------------------------
+
+The GIC driver is responsible for performing initial configuration of secure
+interrupts on the platform. To this end, the platform is expected to provide the
+GIC driver (either GICv2 or GICv3, as selected by the platform) with the
+interrupt configuration during the driver initialisation.
+
+There are two ways to specify secure interrupt configuration:
+
+#. Array of secure interrupt properties: In this scheme, in both GICv2 and GICv3
+ driver data structures, the ``interrupt_props`` member points to an array of
+ interrupt properties. Each element of the array specifies the interrupt
+ number and its configuration, viz. priority, group, configuration. Each
+ element of the array shall be populated by the macro ``INTR_PROP_DESC()``.
+ The macro takes the following arguments:
+
+ - 10-bit interrupt number,
+
+ - 8-bit interrupt priority,
+
+ - Interrupt type (one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1``,
+ ``INTR_TYPE_NS``),
+
+ - Interrupt configuration (either ``GIC_INTR_CFG_LEVEL`` or
+ ``GIC_INTR_CFG_EDGE``).
+
+#. Array of secure interrupts: In this scheme, the GIC driver is provided an
+ array of secure interrupt numbers. The GIC driver, at the time of
+ initialisation, iterates through the array and assigns each interrupt
+ the appropriate group.
+
+ - For the GICv2 driver, in ``gicv2_driver_data`` structure, the
+ ``g0_interrupt_array`` member of the should point to the array of
+ interrupts to be assigned to *Group 0*, and the ``g0_interrupt_num``
+ member of the should be set to the number of interrupts in the array.
+
+ - For the GICv3 driver, in ``gicv3_driver_data`` structure:
+
+ - The ``g0_interrupt_array`` member of the should point to the array of
+ interrupts to be assigned to *Group 0*, and the ``g0_interrupt_num``
+ member of the should be set to the number of interrupts in the array.
+
+ - The ``g1s_interrupt_array`` member of the should point to the array of
+ interrupts to be assigned to *Group 1 Secure*, and the
+ ``g1s_interrupt_num`` member of the should be set to the number of
+ interrupts in the array.
+
+ **Note that this scheme is deprecated.**
+
CPU specific operations framework
---------------------------------
@@ -2202,6 +2257,93 @@ should consider the trade-off between memory footprint and security.
This build flag is disabled by default, minimising memory footprint. On ARM
platforms, it is enabled.
+Publish and Subscribe Framework
+-------------------------------
+
+The Publish and Subscribe Framework allows EL3 components to define and publish
+events, to which other EL3 components can subscribe.
+
+The following macros are provided by the framework:
+
+- ``REGISTER_PUBSUB_EVENT(event)``: Defines an event, and takes one argument,
+ the event name, which must be a valid C identifier. All calls to
+ ``REGISTER_PUBSUB_EVENT`` macro must be placed in the file
+ ``pubsub_events.h``.
+
+- ``PUBLISH_EVENT_ARG(event, arg)``: Publishes a defined event, by iterating
+ subscribed handlers and calling them in turn. The handlers will be passed the
+ parameter ``arg``. The expected use-case is to broadcast an event.
+
+- ``PUBLISH_EVENT(event)``: Like ``PUBLISH_EVENT_ARG``, except that the value
+ ``NULL`` is passed to subscribed handlers.
+
+- ``SUBSCRIBE_TO_EVENT(event, handler)``: Registers the ``handler`` to
+ subscribe to ``event``. The handler will be executed whenever the ``event``
+ is published.
+
+- ``for_each_subscriber(event, subscriber)``: Iterates through all handlers
+ subscribed for ``event``. ``subscriber`` must be a local variable of type
+ ``pubsub_cb_t *``, and will point to each subscribed handler in turn during
+ iteration. This macro can be used for those patterns that none of the
+ ``PUBLISH_EVENT_*()`` macros cover.
+
+Publishing an event that wasn't defined using ``REGISTER_PUBSUB_EVENT`` will
+result in build error. Subscribing to an undefined event however won't.
+
+Subscribed handlers must be of type ``pubsub_cb_t``, with following function
+signature:
+
+::
+
+ typedef void* (*pubsub_cb_t)(const void *arg);
+
+There may be arbitrary number of handlers registered to the same event. The
+order in which subscribed handlers are notified when that event is published is
+not defined. Subscribed handlers may be executed in any order; handlers should
+not assume any relative ordering amongst them.
+
+Publishing an event on a PE will result in subscribed handlers executing on that
+PE only; it won't cause handlers to execute on a different PE.
+
+Note that publishing an event on a PE blocks until all the subscribed handlers
+finish executing on the PE.
+
+ARM Trusted Firmware generic code publishes and subscribes to some events
+within. Platform ports are discouraged from subscribing to them. These events
+may be withdrawn, renamed, or have their semantics altered in the future.
+Platforms may however register, publish, and subscribe to platform-specific
+events.
+
+Publish and Subscribe Example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A publisher that wants to publish event ``foo`` would:
+
+- Define the event ``foo`` in the ``pubsub_events.h``.
+
+ ::
+
+ REGISTER_PUBSUB_EVENT(foo);
+
+- Depending on the nature of event, use one of ``PUBLISH_EVENT_*()`` macros to
+ publish the event at the appropriate path and time of execution.
+
+A subscriber that wants to subscribe to event ``foo`` published above would
+implement:
+
+::
+
+ void *foo_handler(const void *arg)
+ {
+ void *result;
+
+ /* Do handling ... */
+
+ return result;
+ }
+
+ SUBSCRIBE_TO_EVENT(foo, foo_handler);
+
Performance Measurement Framework
---------------------------------
@@ -2377,6 +2519,35 @@ This Architecture Extension is targeted when ``ARM_ARCH_MAJOR`` == 8 and
table entries for a given stage of translation for a particular translation
regime.
+ARMv7
+~~~~~
+
+This Architecture Extension is targeted when ``ARM_ARCH_MAJOR`` == 7.
+
+There are several ARMv7 extensions available. Obviously the TrustZone
+extension is mandatory to support the ARM Trusted Firmware bootloader
+and runtime services.
+
+Platform implementing an ARMv7 system can to define from its target
+Cortex-A architecture through ``ARM_CORTEX_A<X> = yes`` in their
+``plaform.mk`` script. For example ``ARM_CORTEX_A15=yes`` for a
+Cortex-A15 target.
+
+Platform can also set ``ARM_WITH_NEON=yes`` to enable neon support.
+Note that using neon at runtime has constraints on non secure wolrd context.
+The trusted firmware does not yet provide VFP context management.
+
+Directive ``ARM_CORTEX_A<x>`` and ``ARM_WITH_NEON`` are used to set
+the toolchain target architecture directive.
+
+Platform may choose to not define straight the toolchain target architecture
+directive by defining ``MARCH32_DIRECTIVE``.
+I.e:
+
+::
+
+ MARCH32_DIRECTIVE := -mach=armv7-a
+
Code Structure
--------------
@@ -2425,7 +2596,7 @@ kernel at boot time. These can be found in the ``fdts`` directory.
References
----------
-.. [#] Trusted Board Boot Requirements CLIENT PDD (ARM DEN 0006B-5). Available
+.. [#] Trusted Board Boot Requirements CLIENT PDD (ARM DEN0006C-1). Available
under NDA through your ARM account representative.
.. [#] `Power State Coordination Interface PDD`_
.. [#] `SMC Calling Convention PDD`_
diff --git a/docs/plantuml/plantuml_to_svg.sh b/docs/plantuml/plantuml_to_svg.sh
new file mode 100755
index 00000000..0bf8588b
--- /dev/null
+++ b/docs/plantuml/plantuml_to_svg.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Convert all PlantUML files in this directory to SVG files. The plantuml_jar
+# environment variable must be set to the path to PlantUML JAR file.
+
+if [ -z "$plantuml_jar" ]; then
+ echo "Usage: plantuml_jar=/path/to/plantuml.jar $0 *.puml" >&2
+ exit 1
+fi
+
+java -jar "$plantuml_jar" -nometadata -tsvg "$@"
+
+# vim:set noet sts=8 tw=80:
diff --git a/docs/plantuml/sdei_explicit_dispatch.puml b/docs/plantuml/sdei_explicit_dispatch.puml
new file mode 100644
index 00000000..c80fcd11
--- /dev/null
+++ b/docs/plantuml/sdei_explicit_dispatch.puml
@@ -0,0 +1,45 @@
+/'
+ ' Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ '
+ ' SPDX-License-Identifier: BSD-3-Clause
+ '/
+
+@startuml
+
+autonumber "<b>[#]</b>"
+participant "SDEI client" as EL2
+participant EL3
+participant "Secure Partition" as SP
+
+activate EL2
+EL2->EL3: **SDEI_EVENT_REGISTER**(ev, handler, ...)
+EL3->EL2: success
+EL2->EL3: **SDEI_EVENT_ENABLE**(ev)
+EL3->EL2: success
+EL2->EL3: **SDEI_PE_UNMASK**()
+EL3->EL2: 1
+
+... <<Business as usual>> ...
+
+EL3<--]: **CRITICAL EVENT**
+activate EL3 #red
+note over EL3: Critical event triage
+EL3->SP: dispatch
+activate SP #salmon
+note over SP: Critical event handling
+SP->EL3: done
+deactivate SP
+EL3-->EL3: sdei_dispatch_event(ev)
+note over EL3: Prepare SDEI dispatch
+EL3->EL2: dispatch
+activate EL2 #salmon
+note over EL2: SDEI handler
+EL2->EL3: **SDEI_EVENT_COMPLETE()**
+deactivate EL2
+note over EL3: Complete SDEI dispatch
+EL3->EL2: resumes preempted execution
+deactivate EL3
+
+... <<Normal execution resumes>> ...
+
+@enduml
diff --git a/docs/plantuml/sdei_explicit_dispatch.svg b/docs/plantuml/sdei_explicit_dispatch.svg
new file mode 100644
index 00000000..182df0af
--- /dev/null
+++ b/docs/plantuml/sdei_explicit_dispatch.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="767px" preserveAspectRatio="none" style="width:692px;height:767px;" version="1.1" viewBox="0 0 692 767" width="692px" zoomAndPan="magnify"><defs><filter height="300%" id="fueepysa066oi" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><rect fill="#FFFFFF" filter="url(#fueepysa066oi)" height="174.7969" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="48.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="48.2969" y2="223.0938"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="48.2969" y2="223.0938"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="66.5" y1="48.2969" y2="48.2969"/><rect fill="#FFFFFF" filter="url(#fueepysa066oi)" height="412.5938" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="263.8984"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="263.8984" y2="676.4922"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="263.8984" y2="676.4922"/><rect fill="#FFFFFF" filter="url(#fueepysa066oi)" height="1" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="717.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="717.2969" y2="718.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="717.2969" y2="718.2969"/><rect fill="#FA8072" filter="url(#fueepysa066oi)" height="68.2656" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="61.5" y="531.8281"/><rect fill="#FF0000" filter="url(#fueepysa066oi)" height="383.4609" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="375.5" y="284.8984"/><rect fill="#FA8072" filter="url(#fueepysa066oi)" height="68.2656" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="588.5" y="353.1641"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="61" x2="61" y1="38.2969" y2="223.0938"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="61" x2="61" y1="223.0938" y2="263.8984"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="61" x2="61" y1="263.8984" y2="676.4922"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="61" x2="61" y1="676.4922" y2="717.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="61" x2="61" y1="717.2969" y2="727.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="380" x2="380" y1="38.2969" y2="223.0938"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="380" x2="380" y1="223.0938" y2="263.8984"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="380" x2="380" y1="263.8984" y2="676.4922"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="380" x2="380" y1="676.4922" y2="717.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="380" x2="380" y1="717.2969" y2="727.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="593" x2="593" y1="38.2969" y2="223.0938"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="593" x2="593" y1="223.0938" y2="263.8984"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="593" x2="593" y1="263.8984" y2="676.4922"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="593" x2="593" y1="676.4922" y2="717.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="593" x2="593" y1="717.2969" y2="727.2969"/><rect fill="#FEFECE" filter="url(#fueepysa066oi)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="87" x="16" y="3"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="73" x="23" y="22.9951">SDEI client</text><rect fill="#FEFECE" filter="url(#fueepysa066oi)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="87" x="16" y="726.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="73" x="23" y="746.292">SDEI client</text><rect fill="#FEFECE" filter="url(#fueepysa066oi)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="39" x="359" y="3"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="25" x="366" y="22.9951">EL3</text><rect fill="#FEFECE" filter="url(#fueepysa066oi)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="39" x="359" y="726.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="25" x="366" y="746.292">EL3</text><rect fill="#FEFECE" filter="url(#fueepysa066oi)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="123" x="530" y="3"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="109" x="537" y="22.9951">Secure Partition</text><rect fill="#FEFECE" filter="url(#fueepysa066oi)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="123" x="530" y="726.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="109" x="537" y="746.292">Secure Partition</text><rect fill="#FFFFFF" filter="url(#fueepysa066oi)" height="174.7969" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="48.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="48.2969" y2="223.0938"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="48.2969" y2="223.0938"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="66.5" y1="48.2969" y2="48.2969"/><rect fill="#FFFFFF" filter="url(#fueepysa066oi)" height="412.5938" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="263.8984"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="263.8984" y2="676.4922"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="263.8984" y2="676.4922"/><rect fill="#FFFFFF" filter="url(#fueepysa066oi)" height="1" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="717.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="717.2969" y2="718.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="717.2969" y2="718.2969"/><rect fill="#FA8072" filter="url(#fueepysa066oi)" height="68.2656" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="61.5" y="531.8281"/><rect fill="#FF0000" filter="url(#fueepysa066oi)" height="383.4609" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="375.5" y="284.8984"/><rect fill="#FA8072" filter="url(#fueepysa066oi)" height="68.2656" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="588.5" y="353.1641"/><polygon fill="#A80036" points="368.5,65.2969,378.5,69.2969,368.5,73.2969,372.5,69.2969" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="374.5" y1="69.2969" y2="69.2969"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="73.5" y="64.3638">[1]</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="164" x="98.5" y="64.3638">SDEI_EVENT_REGISTER</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="101" x="262.5" y="64.3638">(ev, handler, ...)</text><polygon fill="#A80036" points="77.5,94.4297,67.5,98.4297,77.5,102.4297,73.5,98.4297" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="71.5" x2="379.5" y1="98.4297" y2="98.4297"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="83.5" y="93.4966">[2]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="51" x="108.5" y="93.4966">success</text><polygon fill="#A80036" points="368.5,123.5625,378.5,127.5625,368.5,131.5625,372.5,127.5625" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="374.5" y1="127.5625" y2="127.5625"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="73.5" y="122.6294">[3]</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="151" x="98.5" y="122.6294">SDEI_EVENT_ENABLE</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="25" x="249.5" y="122.6294">(ev)</text><polygon fill="#A80036" points="77.5,152.6953,67.5,156.6953,77.5,160.6953,73.5,156.6953" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="71.5" x2="379.5" y1="156.6953" y2="156.6953"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="83.5" y="151.7622">[4]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="51" x="108.5" y="151.7622">success</text><polygon fill="#A80036" points="368.5,181.8281,378.5,185.8281,368.5,189.8281,372.5,185.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="374.5" y1="185.8281" y2="185.8281"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="73.5" y="180.895">[5]</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="129" x="98.5" y="180.895">SDEI_PE_UNMASK</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="10" x="227.5" y="180.895">()</text><polygon fill="#A80036" points="77.5,210.9609,67.5,214.9609,77.5,218.9609,73.5,214.9609" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="71.5" x2="379.5" y1="214.9609" y2="214.9609"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="83.5" y="210.0278">[6]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="8" x="108.5" y="210.0278">1</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="142" x="256.5" y="247.3042">&lt;&lt;Business as usual&gt;&gt;</text><polygon fill="#A80036" points="396.5,280.8984,386.5,284.8984,396.5,288.8984,392.5,284.8984" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="390.5" x2="680" y1="284.8984" y2="284.8984"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="402.5" y="279.9653">[7]</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="116" x="427.5" y="279.9653">CRITICAL EVENT</text><polygon fill="#FBFB77" filter="url(#fueepysa066oi)" points="306,298.0313,306,323.0313,451,323.0313,451,308.0313,441,298.0313,306,298.0313" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="441" x2="441" y1="298.0313" y2="308.0313"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="451" x2="441" y1="308.0313" y2="308.0313"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="124" x="312" y="315.0981">Critical event triage</text><polygon fill="#A80036" points="576.5,349.1641,586.5,353.1641,576.5,357.1641,580.5,353.1641" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="385.5" x2="582.5" y1="353.1641" y2="353.1641"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="392.5" y="348.231">[8]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="54" x="417.5" y="348.231">dispatch</text><polygon fill="#FBFB77" filter="url(#fueepysa066oi)" points="510,366.2969,510,391.2969,672,391.2969,672,376.2969,662,366.2969,510,366.2969" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="662" x2="662" y1="366.2969" y2="376.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="672" x2="662" y1="376.2969" y2="376.2969"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="141" x="516" y="383.3638">Critical event handling</text><polygon fill="#A80036" points="396.5,417.4297,386.5,421.4297,396.5,425.4297,392.5,421.4297" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="390.5" x2="592.5" y1="421.4297" y2="421.4297"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="402.5" y="416.4966">[9]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="32" x="427.5" y="416.4966">done</text><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="385.5" x2="427.5" y1="450.6953" y2="450.6953"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="427.5" x2="427.5" y1="450.6953" y2="463.6953"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="386.5" x2="427.5" y1="463.6953" y2="463.6953"/><polygon fill="#A80036" points="396.5,459.6953,386.5,463.6953,396.5,467.6953,392.5,463.6953" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="30" x="392.5" y="445.6294">[10]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="155" x="426.5" y="445.6294">sdei_dispatch_event(ev)</text><polygon fill="#FBFB77" filter="url(#fueepysa066oi)" points="297,476.6953,297,501.6953,460,501.6953,460,486.6953,450,476.6953,297,476.6953" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="450" x2="450" y1="476.6953" y2="486.6953"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="460" x2="450" y1="486.6953" y2="486.6953"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="142" x="303" y="493.7622">Prepare SDEI dispatch</text><polygon fill="#A80036" points="82.5,527.8281,72.5,531.8281,82.5,535.8281,78.5,531.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="76.5" x2="374.5" y1="531.8281" y2="531.8281"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="30" x="88.5" y="526.895">[11]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="54" x="122.5" y="526.895">dispatch</text><polygon fill="#FBFB77" filter="url(#fueepysa066oi)" points="8,544.9609,8,569.9609,111,569.9609,111,554.9609,101,544.9609,8,544.9609" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="101" x2="101" y1="544.9609" y2="554.9609"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="111" x2="101" y1="554.9609" y2="554.9609"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="82" x="14" y="562.0278">SDEI handler</text><polygon fill="#A80036" points="363.5,596.0938,373.5,600.0938,363.5,604.0938,367.5,600.0938" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="369.5" y1="600.0938" y2="600.0938"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="30" x="73.5" y="595.1606">[12]</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="184" x="107.5" y="595.1606">SDEI_EVENT_COMPLETE()</text><polygon fill="#FBFB77" filter="url(#fueepysa066oi)" points="291,613.2266,291,638.2266,466,638.2266,466,623.2266,456,613.2266,291,613.2266" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="456" x2="456" y1="613.2266" y2="623.2266"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="466" x2="456" y1="623.2266" y2="623.2266"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="154" x="297" y="630.2935">Complete SDEI dispatch</text><polygon fill="#A80036" points="77.5,664.3594,67.5,668.3594,77.5,672.3594,73.5,668.3594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="71.5" x2="379.5" y1="668.3594" y2="668.3594"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="30" x="83.5" y="663.4263">[13]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="197" x="117.5" y="663.4263">resumes preempted execution</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="190" x="232.5" y="700.7026">&lt;&lt;Normal execution resumes&gt;&gt;</text></g></svg> \ No newline at end of file
diff --git a/docs/plantuml/sdei_general.puml b/docs/plantuml/sdei_general.puml
new file mode 100644
index 00000000..ab6929ab
--- /dev/null
+++ b/docs/plantuml/sdei_general.puml
@@ -0,0 +1,43 @@
+/'
+ ' Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ '
+ ' SPDX-License-Identifier: BSD-3-Clause
+ '/
+
+@startuml
+
+autonumber "<b>[#]</b>"
+participant "SDEI client" as EL2
+participant EL3
+participant "SDEI interrupt source" as SDEI
+
+activate EL2
+EL2->EL3: **SDEI_INTERRUPT_BIND**(irq)
+EL3->EL2: event number: ev
+EL2->EL3: **SDEI_EVENT_REGISTER**(ev, handler, ...)
+EL3->EL2: success
+EL2->EL3: **SDEI_EVENT_ENABLE**(ev)
+EL3->EL2: success
+EL2->EL3: **SDEI_PE_UNMASK**()
+EL3->EL2: 1
+
+... <<Business as usual>> ...
+
+SDEI-->EL3: SDEI interrupt
+activate SDEI #salmon
+activate EL3 #red
+note over EL3: Prepare SDEI dispatch
+EL3->EL2: dispatch
+activate EL2 #salmon
+note over EL2: SDEI handler
+EL2->EL3: **SDEI_EVENT_COMPLETE()**
+deactivate EL2
+note over EL3: Complete SDEI dispatch
+EL3-->SDEI: EOI
+deactivate SDEI
+EL3->EL2: resumes preempted execution
+deactivate EL3
+
+... <<Normal execution resumes>> ...
+
+@enduml
diff --git a/docs/plantuml/sdei_general.svg b/docs/plantuml/sdei_general.svg
new file mode 100644
index 00000000..e1721122
--- /dev/null
+++ b/docs/plantuml/sdei_general.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="676px" preserveAspectRatio="none" style="width:608px;height:676px;" version="1.1" viewBox="0 0 608 676" width="608px" zoomAndPan="magnify"><defs><filter height="300%" id="fvds2ijrtbp5u" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><rect fill="#FFFFFF" filter="url(#fvds2ijrtbp5u)" height="233.0625" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="48.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="48.2969" y2="281.3594"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="48.2969" y2="281.3594"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="66.5" y1="48.2969" y2="48.2969"/><rect fill="#FFFFFF" filter="url(#fvds2ijrtbp5u)" height="263.0625" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="322.1641"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="322.1641" y2="585.2266"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="322.1641" y2="585.2266"/><rect fill="#FFFFFF" filter="url(#fvds2ijrtbp5u)" height="1" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="626.0313"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="626.0313" y2="627.0313"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="626.0313" y2="627.0313"/><rect fill="#FA8072" filter="url(#fvds2ijrtbp5u)" height="68.2656" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="61.5" y="411.4297"/><rect fill="#FF0000" filter="url(#fvds2ijrtbp5u)" height="233.9297" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="375.5" y="343.1641"/><rect fill="#FA8072" filter="url(#fvds2ijrtbp5u)" height="204.7969" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="513.5" y="343.1641"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="61" x2="61" y1="38.2969" y2="281.3594"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="61" x2="61" y1="281.3594" y2="322.1641"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="61" x2="61" y1="322.1641" y2="585.2266"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="61" x2="61" y1="585.2266" y2="626.0313"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="61" x2="61" y1="626.0313" y2="636.0313"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="380" x2="380" y1="38.2969" y2="281.3594"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="380" x2="380" y1="281.3594" y2="322.1641"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="380" x2="380" y1="322.1641" y2="585.2266"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="380" x2="380" y1="585.2266" y2="626.0313"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="380" x2="380" y1="626.0313" y2="636.0313"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="518" x2="518" y1="38.2969" y2="281.3594"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="518" x2="518" y1="281.3594" y2="322.1641"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="518" x2="518" y1="322.1641" y2="585.2266"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 1.0,4.0;" x1="518" x2="518" y1="585.2266" y2="626.0313"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="518" x2="518" y1="626.0313" y2="636.0313"/><rect fill="#FEFECE" filter="url(#fvds2ijrtbp5u)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="87" x="16" y="3"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="73" x="23" y="22.9951">SDEI client</text><rect fill="#FEFECE" filter="url(#fvds2ijrtbp5u)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="87" x="16" y="635.0313"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="73" x="23" y="655.0264">SDEI client</text><rect fill="#FEFECE" filter="url(#fvds2ijrtbp5u)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="39" x="359" y="3"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="25" x="366" y="22.9951">EL3</text><rect fill="#FEFECE" filter="url(#fvds2ijrtbp5u)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="39" x="359" y="635.0313"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="25" x="366" y="655.0264">EL3</text><rect fill="#FEFECE" filter="url(#fvds2ijrtbp5u)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="161" x="436" y="3"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="147" x="443" y="22.9951">SDEI interrupt source</text><rect fill="#FEFECE" filter="url(#fvds2ijrtbp5u)" height="30.2969" style="stroke: #A80036; stroke-width: 1.5;" width="161" x="436" y="635.0313"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="147" x="443" y="655.0264">SDEI interrupt source</text><rect fill="#FFFFFF" filter="url(#fvds2ijrtbp5u)" height="233.0625" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="48.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="48.2969" y2="281.3594"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="48.2969" y2="281.3594"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="66.5" y1="48.2969" y2="48.2969"/><rect fill="#FFFFFF" filter="url(#fvds2ijrtbp5u)" height="263.0625" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="322.1641"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="322.1641" y2="585.2266"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="322.1641" y2="585.2266"/><rect fill="#FFFFFF" filter="url(#fvds2ijrtbp5u)" height="1" style="stroke: #FFFFFF; stroke-width: 1.0;" width="10" x="56.5" y="626.0313"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="56.5" x2="56.5" y1="626.0313" y2="627.0313"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="66.5" y1="626.0313" y2="627.0313"/><rect fill="#FA8072" filter="url(#fvds2ijrtbp5u)" height="68.2656" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="61.5" y="411.4297"/><rect fill="#FF0000" filter="url(#fvds2ijrtbp5u)" height="233.9297" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="375.5" y="343.1641"/><rect fill="#FA8072" filter="url(#fvds2ijrtbp5u)" height="204.7969" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="513.5" y="343.1641"/><polygon fill="#A80036" points="368.5,65.2969,378.5,69.2969,368.5,73.2969,372.5,69.2969" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="374.5" y1="69.2969" y2="69.2969"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="73.5" y="64.3638">[1]</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="163" x="98.5" y="64.3638">SDEI_INTERRUPT_BIND</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="26" x="261.5" y="64.3638">(irq)</text><polygon fill="#A80036" points="77.5,94.4297,67.5,98.4297,77.5,102.4297,73.5,98.4297" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="71.5" x2="379.5" y1="98.4297" y2="98.4297"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="83.5" y="93.4966">[2]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="113" x="108.5" y="93.4966">event number: ev</text><polygon fill="#A80036" points="368.5,123.5625,378.5,127.5625,368.5,131.5625,372.5,127.5625" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="374.5" y1="127.5625" y2="127.5625"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="73.5" y="122.6294">[3]</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="164" x="98.5" y="122.6294">SDEI_EVENT_REGISTER</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="101" x="262.5" y="122.6294">(ev, handler, ...)</text><polygon fill="#A80036" points="77.5,152.6953,67.5,156.6953,77.5,160.6953,73.5,156.6953" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="71.5" x2="379.5" y1="156.6953" y2="156.6953"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="83.5" y="151.7622">[4]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="51" x="108.5" y="151.7622">success</text><polygon fill="#A80036" points="368.5,181.8281,378.5,185.8281,368.5,189.8281,372.5,185.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="374.5" y1="185.8281" y2="185.8281"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="73.5" y="180.895">[5]</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="151" x="98.5" y="180.895">SDEI_EVENT_ENABLE</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="25" x="249.5" y="180.895">(ev)</text><polygon fill="#A80036" points="77.5,210.9609,67.5,214.9609,77.5,218.9609,73.5,214.9609" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="71.5" x2="379.5" y1="214.9609" y2="214.9609"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="83.5" y="210.0278">[6]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="51" x="108.5" y="210.0278">success</text><polygon fill="#A80036" points="368.5,240.0938,378.5,244.0938,368.5,248.0938,372.5,244.0938" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="374.5" y1="244.0938" y2="244.0938"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="73.5" y="239.1606">[7]</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="129" x="98.5" y="239.1606">SDEI_PE_UNMASK</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="10" x="227.5" y="239.1606">()</text><polygon fill="#A80036" points="77.5,269.2266,67.5,273.2266,77.5,277.2266,73.5,273.2266" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="71.5" x2="379.5" y1="273.2266" y2="273.2266"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="83.5" y="268.2935">[8]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="8" x="108.5" y="268.2935">1</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="142" x="219" y="305.5698">&lt;&lt;Business as usual&gt;&gt;</text><polygon fill="#A80036" points="396.5,339.1641,386.5,343.1641,396.5,347.1641,392.5,343.1641" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="390.5" x2="512.5" y1="343.1641" y2="343.1641"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="21" x="402.5" y="338.231">[9]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="89" x="427.5" y="338.231">SDEI interrupt</text><polygon fill="#FBFB77" filter="url(#fvds2ijrtbp5u)" points="297,356.2969,297,381.2969,460,381.2969,460,366.2969,450,356.2969,297,356.2969" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="450" x2="450" y1="356.2969" y2="366.2969"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="460" x2="450" y1="366.2969" y2="366.2969"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="142" x="303" y="373.3638">Prepare SDEI dispatch</text><polygon fill="#A80036" points="82.5,407.4297,72.5,411.4297,82.5,415.4297,78.5,411.4297" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="76.5" x2="374.5" y1="411.4297" y2="411.4297"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="30" x="88.5" y="406.4966">[10]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="54" x="122.5" y="406.4966">dispatch</text><polygon fill="#FBFB77" filter="url(#fvds2ijrtbp5u)" points="8,424.5625,8,449.5625,111,449.5625,111,434.5625,101,424.5625,8,424.5625" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="101" x2="101" y1="424.5625" y2="434.5625"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="111" x2="101" y1="434.5625" y2="434.5625"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="82" x="14" y="441.6294">SDEI handler</text><polygon fill="#A80036" points="363.5,475.6953,373.5,479.6953,363.5,483.6953,367.5,479.6953" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="66.5" x2="369.5" y1="479.6953" y2="479.6953"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="30" x="73.5" y="474.7622">[11]</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="184" x="107.5" y="474.7622">SDEI_EVENT_COMPLETE()</text><polygon fill="#FBFB77" filter="url(#fvds2ijrtbp5u)" points="291,492.8281,291,517.8281,466,517.8281,466,502.8281,456,492.8281,291,492.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="456" x2="456" y1="492.8281" y2="502.8281"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="466" x2="456" y1="502.8281" y2="502.8281"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="154" x="297" y="509.895">Complete SDEI dispatch</text><polygon fill="#A80036" points="506.5,543.9609,516.5,547.9609,506.5,551.9609,510.5,547.9609" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="385.5" x2="512.5" y1="547.9609" y2="547.9609"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="30" x="392.5" y="543.0278">[12]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="21" x="426.5" y="543.0278">EOI</text><polygon fill="#A80036" points="77.5,573.0938,67.5,577.0938,77.5,581.0938,73.5,577.0938" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="71.5" x2="379.5" y1="577.0938" y2="577.0938"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="30" x="83.5" y="572.1606">[13]</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="197" x="117.5" y="572.1606">resumes preempted execution</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="190" x="195" y="609.437">&lt;&lt;Normal execution resumes&gt;&gt;</text></g></svg> \ No newline at end of file
diff --git a/docs/plat/hikey.rst b/docs/plat/hikey.rst
index e194edee..1c481044 100644
--- a/docs/plat/hikey.rst
+++ b/docs/plat/hikey.rst
@@ -38,6 +38,16 @@ Build Procedure
- Fetch all the above repositories into local host.
Make all the repositories in the same ${BUILD\_PATH}.
+ .. code:: shell
+
+ git clone https://github.com/ARM-software/arm-trusted-firmware -b integration
+ git clone https://github.com/OP-TEE/optee_os
+ git clone https://github.com/96boards-hikey/edk2 -b testing/hikey960_v2.5
+ git clone https://github.com/96boards-hikey/OpenPlatformPkg -b testing/hikey960_v1.3.4
+ git clone https://github.com/96boards-hikey/l-loader -b testing/hikey960_v1.2
+ git clone https://git.linaro.org/uefi/uefi-tools
+ git clone https://github.com/96boards-hikey/atf-fastboot
+
- Create the symbol link to OpenPlatformPkg in edk2.
.. code:: shell
@@ -74,20 +84,15 @@ Build Procedure
cd ${EDK2_DIR}
# Build UEFI & ARM Trust Firmware
${UEFI_TOOLS_DIR}/uefi-build.sh -b ${BUILD_OPTION} -a ../arm-trusted-firmware -s ../optee_os hikey
- # Generate l-loader.bin
- cd ${BUILD_PATH}/l-loader
- ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin
- ln -sf ${BUILD_PATH}/atf-fastboot/build/hikey/${FASTBOOT_BUILD_OPTION}/bl1.bin fastboot.bin
- arm-linux-gnueabihf-gcc -c -o start.o start.S
- arm-linux-gnueabihf-ld -Bstatic -Tl-loader.lds -Ttext 0xf9800800 start.o -o loader
- arm-linux-gnueabihf-objcopy -O binary loader temp
- python gen_loader_hikey.py -o l-loader.bin --img_loader=temp --img_bl1=bl1.bin --img_ns_bl1u=fastboot.bin
-- Generate partition table for aosp. The eMMC capacity is either 4GB or 8GB. Just change "aosp-4g" to "linux-4g" for debian.
+- Generate l-loader.bin and partition table for aosp. The eMMC capacity is either 8GB or 4GB. Just change "aosp-8g" to "linux-8g" for debian.
.. code:: shell
- PTABLE=aosp-4g SECTOR_SIZE=512 bash -x generate_ptable.sh
+ cd ${BUILD_PATH}/l-loader
+ ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin
+ ln -sf ${BUILD_PATH}/atf-fastboot/build/hikey/${FASTBOOT_BUILD_OPTION}/bl1.bin fastboot.bin
+ make hikey PTABLE_LST=aosp-8g
Setup Console
-------------
diff --git a/docs/plat/hikey960.rst b/docs/plat/hikey960.rst
index cd1880e1..8524b48a 100644
--- a/docs/plat/hikey960.rst
+++ b/docs/plat/hikey960.rst
@@ -35,6 +35,15 @@ Build Procedure
- Fetch all the above 5 repositories into local host.
Make all the repositories in the same ${BUILD\_PATH}.
+ .. code:: shell
+
+ git clone https://github.com/ARM-software/arm-trusted-firmware -b integration
+ git clone https://github.com/OP-TEE/optee_os
+ git clone https://github.com/96boards-hikey/edk2 -b testing/hikey960_v2.5
+ git clone https://github.com/96boards-hikey/OpenPlatformPkg -b testing/hikey960_v1.3.4
+ git clone https://github.com/96boards-hikey/l-loader -b testing/hikey960_v1.2
+ git clone https://git.linaro.org/uefi/uefi-tools
+
- Create the symbol link to OpenPlatformPkg in edk2.
.. code:: shell
@@ -66,19 +75,17 @@ Build Procedure
cd ${EDK2_DIR}
# Build UEFI & ARM Trust Firmware
${UEFI_TOOLS_DIR}/uefi-build.sh -b ${BUILD_OPTION} -a ../arm-trusted-firmware -s ../optee_os hikey960
- # Generate l-loader.bin
- cd ${BUILD_PATH}/l-loader
- ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin
- ln -sf ${EDK2_OUTPUT_DIR}/FV/fip.bin
- ln -sf ${EDK2_OUTPUT_DIR}/FV/BL33_AP_UEFI.fd
- python gen_loader_hikey960.py -o l-loader.bin --img_bl1=bl1.bin --img_ns_bl1u=BL33_AP_UEFI.fd
-- Generate partition table.
+- Generate l-loader.bin and partition table.
*Make sure that you're using the sgdisk in the l-loader directory.*
.. code:: shell
- PTABLE=aosp-32g SECTOR_SIZE=4096 SGDISK=./sgdisk bash -x generate_ptable.sh
+ cd ${BUILD_PATH}/l-loader
+ ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin
+ ln -sf ${EDK2_OUTPUT_DIR}/FV/fip.bin
+ ln -sf ${EDK2_OUTPUT_DIR}/FV/BL33_AP_UEFI.fd
+ make hikey960
Setup Console
-------------
@@ -129,6 +136,7 @@ Boot UEFI in recovery mode
$cd tools-images-hikey960
$ln -sf ${BUILD_PATH}/l-loader/l-loader.bin
+ $ln -sf ${BUILD_PATH}/l-loader/fip.bin
- Prepare config file.
diff --git a/docs/plat/poplar.rst b/docs/plat/poplar.rst
index d7f1fe06..01294783 100644
--- a/docs/plat/poplar.rst
+++ b/docs/plat/poplar.rst
@@ -11,6 +11,8 @@ of running any commercial set-top solution based on Linux or Android.
It supports a premium user experience with up to H.265 HEVC decoding of 4K
video at 60 frames per second.
+::
+
SOC Hisilicon Hi3798CV200
CPU Quad-core ARM Cortex-A53 64 bit
DRAM DDR3/3L/4 SDRAM interface, maximum 32-bit data width 2 GB
@@ -28,6 +30,8 @@ At the start of the boot sequence, the bootROM executes the so called l-loader
binary whose main role is to change the processor state to 64bit mode. This
must happen prior invoking the arm trusted firmware:
+::
+
l-loader --> arm_trusted_firmware --> u-boot
How to build
@@ -54,10 +58,16 @@ Build Procedure
- Prepare the AARCH64 toolchain.
- Build u-boot using poplar_defconfig
+
+.. code:: bash
+
make CROSS_COMPILE=aarch64-linux-gnu- poplar_defconfig
make CROSS_COMPILE=aarch64-linux-gnu-
- Build atf providing the previously generated u-boot.bin as the BL33 image
+
+.. code:: bash
+
make CROSS_COMPILE=aarch64-linux-gnu- all fip SPD=none PLAT=poplar
BL33=u-boot.bin
@@ -81,85 +91,86 @@ working firmware to eMMC.
Boot trace
==========
-Bootrom start
-Boot Media: eMMC
-Decrypt auxiliary code ...OK
-
-lsadc voltage min: 000000FE, max: 000000FF, aver: 000000FE, index: 00000000
-
-Entry boot auxiliary code
-
-Auxiliary code - v1.00
-DDR code - V1.1.2 20160205
-Build: Mar 24 2016 - 17:09:44
-Reg Version: v134
-Reg Time: 2016/03/18 09:44:55
-Reg Name: hi3798cv2dmb_hi3798cv200_ddr3_2gbyte_8bitx4_4layers.reg
-
-Boot auxiliary code success
-Bootrom success
-
-LOADER: Switched to aarch64 mode
-LOADER: Entering ARM TRUSTED FIRMWARE
-LOADER: CPU0 executes at 0x000ce000
-
-INFO: BL1: 0xe1000 - 0xe7000 [size = 24576]
-NOTICE: Booting Trusted Firmware
-NOTICE: BL1: v1.3(debug):v1.3-372-g1ba9c60
-NOTICE: BL1: Built : 17:51:33, Apr 30 2017
-INFO: BL1: RAM 0xe1000 - 0xe7000
-INFO: BL1: Loading BL2
-INFO: Loading image id=1 at address 0xe9000
-INFO: Image id=1 loaded at address 0xe9000, size = 0x5008
-NOTICE: BL1: Booting BL2
-INFO: Entry point address = 0xe9000
-INFO: SPSR = 0x3c5
-NOTICE: BL2: v1.3(debug):v1.3-372-g1ba9c60
-NOTICE: BL2: Built : 17:51:33, Apr 30 2017
-INFO: BL2: Loading BL31
-INFO: Loading image id=3 at address 0x129000
-INFO: Image id=3 loaded at address 0x129000, size = 0x8038
-INFO: BL2: Loading BL33
-INFO: Loading image id=5 at address 0x37000000
-INFO: Image id=5 loaded at address 0x37000000, size = 0x58f17
-NOTICE: BL1: Booting BL31
-INFO: Entry point address = 0x129000
-INFO: SPSR = 0x3cd
-INFO: Boot bl33 from 0x37000000 for 364311 Bytes
-NOTICE: BL31: v1.3(debug):v1.3-372-g1ba9c60
-NOTICE: BL31: Built : 17:51:33, Apr 30 2017
-INFO: BL31: Initializing runtime services
-INFO: BL31: Preparing for EL3 exit to normal world
-INFO: Entry point address = 0x37000000
-INFO: SPSR = 0x3c9
-
-
-U-Boot 2017.05-rc2-00130-gd2255b0 (Apr 30 2017 - 17:51:28 +0200)poplar
-
-Model: HiSilicon Poplar Development Board
-BOARD: Hisilicon HI3798cv200 Poplar
-DRAM: 1 GiB
-MMC: Hisilicon DWMMC: 0
-In: serial@f8b00000
-Out: serial@f8b00000
-Err: serial@f8b00000
-Net: Net Initialization Skipped
-No ethernet found.
-
-Hit any key to stop autoboot: 0
-starting USB...
-USB0: USB EHCI 1.00
-scanning bus 0 for devices... 1 USB Device(s) found
-USB1: USB EHCI 1.00
-scanning bus 1 for devices... 4 USB Device(s) found
- scanning usb for storage devices... 1 Storage Device(s) found
- scanning usb for ethernet devices... 1 Ethernet Device(s) found
-
-USB device 0:
- Device 0: Vendor: SanDisk Rev: 1.00 Prod: Cruzer Blade
- Type: Removable Hard Disk
- Capacity: 7632.0 MB = 7.4 GB (15630336 x 512)
-... is now current device
-Scanning usb 0:1...
-=>
-
+::
+
+ Bootrom start
+ Boot Media: eMMC
+ Decrypt auxiliary code ...OK
+
+ lsadc voltage min: 000000FE, max: 000000FF, aver: 000000FE, index: 00000000
+
+ Entry boot auxiliary code
+
+ Auxiliary code - v1.00
+ DDR code - V1.1.2 20160205
+ Build: Mar 24 2016 - 17:09:44
+ Reg Version: v134
+ Reg Time: 2016/03/18 09:44:55
+ Reg Name: hi3798cv2dmb_hi3798cv200_ddr3_2gbyte_8bitx4_4layers.reg
+
+ Boot auxiliary code success
+ Bootrom success
+
+ LOADER: Switched to aarch64 mode
+ LOADER: Entering ARM TRUSTED FIRMWARE
+ LOADER: CPU0 executes at 0x000ce000
+
+ INFO: BL1: 0xe1000 - 0xe7000 [size = 24576]
+ NOTICE: Booting Trusted Firmware
+ NOTICE: BL1: v1.3(debug):v1.3-372-g1ba9c60
+ NOTICE: BL1: Built : 17:51:33, Apr 30 2017
+ INFO: BL1: RAM 0xe1000 - 0xe7000
+ INFO: BL1: Loading BL2
+ INFO: Loading image id=1 at address 0xe9000
+ INFO: Image id=1 loaded at address 0xe9000, size = 0x5008
+ NOTICE: BL1: Booting BL2
+ INFO: Entry point address = 0xe9000
+ INFO: SPSR = 0x3c5
+ NOTICE: BL2: v1.3(debug):v1.3-372-g1ba9c60
+ NOTICE: BL2: Built : 17:51:33, Apr 30 2017
+ INFO: BL2: Loading BL31
+ INFO: Loading image id=3 at address 0x129000
+ INFO: Image id=3 loaded at address 0x129000, size = 0x8038
+ INFO: BL2: Loading BL33
+ INFO: Loading image id=5 at address 0x37000000
+ INFO: Image id=5 loaded at address 0x37000000, size = 0x58f17
+ NOTICE: BL1: Booting BL31
+ INFO: Entry point address = 0x129000
+ INFO: SPSR = 0x3cd
+ INFO: Boot bl33 from 0x37000000 for 364311 Bytes
+ NOTICE: BL31: v1.3(debug):v1.3-372-g1ba9c60
+ NOTICE: BL31: Built : 17:51:33, Apr 30 2017
+ INFO: BL31: Initializing runtime services
+ INFO: BL31: Preparing for EL3 exit to normal world
+ INFO: Entry point address = 0x37000000
+ INFO: SPSR = 0x3c9
+
+
+ U-Boot 2017.05-rc2-00130-gd2255b0 (Apr 30 2017 - 17:51:28 +0200)poplar
+
+ Model: HiSilicon Poplar Development Board
+ BOARD: Hisilicon HI3798cv200 Poplar
+ DRAM: 1 GiB
+ MMC: Hisilicon DWMMC: 0
+ In: serial@f8b00000
+ Out: serial@f8b00000
+ Err: serial@f8b00000
+ Net: Net Initialization Skipped
+ No ethernet found.
+
+ Hit any key to stop autoboot: 0
+ starting USB...
+ USB0: USB EHCI 1.00
+ scanning bus 0 for devices... 1 USB Device(s) found
+ USB1: USB EHCI 1.00
+ scanning bus 1 for devices... 4 USB Device(s) found
+ scanning usb for storage devices... 1 Storage Device(s) found
+ scanning usb for ethernet devices... 1 Ethernet Device(s) found
+
+ USB device 0:
+ Device 0: Vendor: SanDisk Rev: 1.00 Prod: Cruzer Blade
+ Type: Removable Hard Disk
+ Capacity: 7632.0 MB = 7.4 GB (15630336 x 512)
+ ... is now current device
+ Scanning usb 0:1...
+ =>
diff --git a/docs/plat/rpi3.rst b/docs/plat/rpi3.rst
new file mode 100644
index 00000000..219faaff
--- /dev/null
+++ b/docs/plat/rpi3.rst
@@ -0,0 +1,364 @@
+Arm Trusted Firmware for Raspberry Pi 3
+=======================================
+
+.. section-numbering::
+ :suffix: .
+
+.. contents::
+
+The `Raspberry Pi 3`_ is an inexpensive single-board computer that contains four
+Cortex-A53 cores, which makes it possible to have a port of the Arm Trusted
+Firmware.
+
+The following instructions explain how to use this port of the Trusted Firmware
+with the default distribution of `Raspbian`_ because that's the distribution
+officially supported by the Raspberry Pi Foundation. At the moment of writing
+this, the officially supported kernel is a AArch32 kernel. This doesn't mean
+that this port of the Trusted Firmware can't boot a AArch64 kernel. The `Linux
+tree fork`_ maintained by the Foundation can be compiled for AArch64 by
+following the steps in `AArch64 kernel build instructions`_.
+
+**IMPORTANT NOTE**: This port isn't secure. All of the memory used is DRAM,
+which is available from both the Non-secure and Secure worlds. This port
+shouldn't be considered more than a prototype to play with and implement
+elements like PSCI to support the Linux kernel.
+
+Design
+------
+
+The SoC used by the Raspberry Pi 3 is the Broadcom BCM2837. It is a SoC with a
+VideoCore IV that acts as primary processor (and loads everything from the SD
+card) and is located between all Arm cores and the DRAM. Check the `Raspberry Pi
+3 documentation`_ for more information.
+
+This explains why it is possible to change the execution state (AArch64/AArch32)
+depending on a few files on the SD card. We only care about the cases in which
+the cores boot in AArch64 mode.
+
+The rules are simple:
+
+- If a file called ``kernel8.img`` is located on the ``boot`` partition of the
+ SD card, it will load it and execute in EL2 in AArch64. Basically, it executes
+ a `default AArch64 stub`_ at address **0x0** that jumps to the kernel.
+
+- If there is also a file called ``armstub8.bin``, it will load it at address
+ **0x0** (instead of the default stub) and execute it in EL3 in AArch64. All
+ the cores are powered on at the same time and start at address **0x0**.
+
+This means that we can use the default AArch32 kernel provided in the official
+`Raspbian`_ distribution by renaming it to ``kernel8.img``, while the Trusted
+Firmware and anything else we need is in ``armstub8.bin``. This way we can
+forget about the default bootstrap code. When using a AArch64 kernel, it is only
+needed to make sure that the name on the SD card is ``kernel8.img``.
+
+Ideally, we want to load the kernel and have all cores available, which means
+that we need to make the secondary cores work in the way the kernel expects, as
+explained in `Secondary cores`_. In practice, a small bootstrap is needed
+between the Trusted Firmware and the kernel.
+
+To get the most out of a AArch32 kernel, we want to boot it in Hypervisor mode
+in AArch32. This means that BL33 can't be in EL2 in AArch64 mode. The
+architecture specifies that AArch32 Hypervisor mode isn't present when AArch64
+is used for EL2. When using a AArch64 kernel, it should simply start in EL2.
+
+Placement of images
+~~~~~~~~~~~~~~~~~~~
+
+The file ``armstub8.bin`` contains BL1 and the FIP. It is needed to add padding
+between them so that the addresses they are loaded to match the ones specified
+when compiling the Trusted Firmware.
+
+The device tree block is loaded by the VideoCore loader from an appropriate
+file, but we can specify the address it is loaded to in ``config.txt``.
+
+The file ``kernel8.img`` contains a kernel image that is loaded to the address
+specified in ``config.txt``. The `Linux kernel tree`_ has information about how
+a AArch32 Linux kernel image is loaded in ``Documentation/arm/Booting``:
+
+::
+
+ The zImage may also be placed in system RAM and called there. The
+ kernel should be placed in the first 128MiB of RAM. It is recommended
+ that it is loaded above 32MiB in order to avoid the need to relocate
+ prior to decompression, which will make the boot process slightly
+ faster.
+
+There are no similar restrictions for AArch64 kernels, as specified in the file
+``Documentation/arm64/booting.txt``.
+
+This means that we need to avoid the first 128 MiB of RAM when placing the
+Trusted Firmware images (and specially the first 32 MiB, as they are directly
+used to place the uncompressed AArch32 kernel image. This way, both AArch32 and
+AArch64 kernels can be placed at the same address.
+
+In the end, the images look like the following diagram when placed in memory.
+All addresses are Physical Addresses from the point of view of the Arm cores.
+Again, note that this is all just part of the same DRAM that goes from
+**0x00000000** to **0x3F000000**, it just has different names to simulate a real
+secure platform!
+
+::
+
+ 0x00000000 +-----------------+
+ | ROM | BL1
+ 0x00010000 +-----------------+
+ | FIP |
+ 0x00200000 +-----------------+
+ | |
+ | ... |
+ | |
+ 0x01000000 +-----------------+
+ | Kernel |
+ +-----------------+
+ | |
+ | ... |
+ | |
+ 0x02000000 +-----------------+
+ | DTB |
+ +-----------------+
+ | |
+ | ... |
+ | |
+ 0x10000000 +-----------------+
+ | Secure SRAM | BL2, BL31
+ 0x10100000 +-----------------+
+ | Secure DRAM |
+ 0x10300000 +-----------------+
+ | Non-secure DRAM | BL33
+ 0x11000000 +-----------------+
+ | |
+ | ... |
+ | |
+ 0x3F000000 +-----------------+
+ | I/O |
+ 0x40000000 +-----------------+
+
+The area between **0x10000000** and **0x11000000** has to be protected so that
+the kernel doesn't use it. That is done by adding ``memmap=256M$16M`` to the
+command line passed to the kernel. See the `Setup SD card`_ instructions to see
+how to do it.
+
+The last 16 MiB of DRAM can only be accessed by the VideoCore, that has
+different mappings than the Arm cores in which the I/O addresses don't overlap
+the DRAM. The memory reserved to be used by the VideoCore is always placed at
+the end of the DRAM, so this space isn't wasted.
+
+Considering the 128 MiB allocated to the GPU and the 16 MiB allocated for the
+Trusted Firmware, there are 880 MiB available for Linux.
+
+Boot sequence
+~~~~~~~~~~~~~
+
+The boot sequence of the Trusted Firmware is the usual one except when booting
+a AArch32 kernel. In that case, BL33 is booted in AArch32 Hypervisor mode so
+that it can jump to the kernel in the same mode and let it take over that
+privilege level. If BL33 was running in EL2 in AArch64 (as in the default
+bootflow of the Trusted Firmware) it could only jump to the kernel in AArch32 in
+Supervisor mode.
+
+The `Linux kernel tree`_ has instructions on how to jump to the Linux kernel
+in ``Documentation/arm/Booting`` and ``Documentation/arm64/booting.txt``. The
+bootstrap should take care of this.
+
+Secondary cores
+~~~~~~~~~~~~~~~
+
+The kernel used by `Raspbian`_ doesn't have support for PSCI, so it is needed to
+use mailboxes to trap the secondary cores until they are ready to jump to the
+kernel. This mailbox is located at a different address in the AArch32 default
+kernel than in the AArch64 kernel.
+
+Also, this port of the Trusted Firmware has another Trusted Mailbox in Shared BL
+RAM. During cold boot, all secondary cores wait in a loop until they are given
+given an address to jump to in this Mailbox (``bl31_warm_entrypoint``).
+
+Once BL31 has finished and the primary core has jumped to the BL33 payload, it
+has to call ``PSCI_CPU_ON`` to release the secondary CPUs from the wait loop.
+The payload then makes them wait in another waitloop listening from messages
+from the kernel. When the primary CPU jumps into the kernel, it will send an
+address to the mailbox so that the secondary CPUs jump to it and are recognised
+by the kernel.
+
+Build Instructions
+------------------
+
+To boot a AArch64 kernel, only the AArch64 toolchain is required.
+
+To boot a AArch32 kernel, both AArch64 and AArch32 toolchains are required. The
+AArch32 toolchain is needed for the AArch32 bootstrap needed to load a 32-bit
+kernel.
+
+First, clone and compile `Raspberry Pi 3 Arm Trusted Firmware bootstrap`_.
+Choose the one needed for the architecture of your kernel.
+
+Then compile the Arm Trusted Firmware. For a AArch32 kernel, use the following
+command line:
+
+.. code:: shell
+
+ CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \
+ RPI3_BL33_IN_AARCH32=1 \
+ BL33=../rpi3-arm-tf-bootstrap/aarch32/el2-bootstrap.bin \
+ all fip
+
+For a AArch64 kernel, use this other command line:
+
+.. code:: shell
+
+ CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \
+ BL33=../rpi3-arm-tf-bootstrap/aarch64/el2-bootstrap.bin \
+ all fip
+
+Then, join BL1 and the FIP with the following instructions (replace ``release``
+by ``debug`` if you set the build option ``DEBUG=1``):
+
+.. code:: shell
+
+ cp build/rpi3/release/bl1.bin bl1.pad.bin
+ truncate --size=65536 bl1.pad.bin
+ cat bl1.pad.bin build/rpi3/release/fip.bin > armstub8.bin
+
+The resulting file, ``armstub8.bin``, contains BL1 and the FIP in the place they
+need to be for the Trusted Firmware to boot correctly. Now, follow the
+instructions in `Setup SD card`_.
+
+The following build options are supported:
+
+- ``PRELOADED_BL33_BASE``: Specially useful because the file ``kernel8.img`` can
+ be loaded anywhere by modifying the file ``config.txt``. It doesn't have to
+ contain a kernel, it could have any arbitrary payload.
+
+- ``RESET_TO_BL31``: Set to 1 by default. If using a 32-bit kernel like
+ `Raspbian`_, the space used by BL1 can overwritten by the kernel when it is
+ being loaded. Even when using a AArch64 kernel the region used by
+ BL1 isn't protected and the kernel could overwrite it. The space used by BL31
+ is reserved by the command line passed to the kernel.
+
+- ``RPI3_BL33_IN_AARCH32``: This port can load a AArch64 or AArch32 BL33 image.
+ By default this option is 0, which means that the Trusted Firmware will jump
+ to BL33 in EL2 in AArch64 mode. If set to 1, it will jump to BL33 in
+ Hypervisor in AArch32 mode.
+
+The following is not currently supported:
+
+- AArch32 for the Trusted Firmware itself.
+
+- ``EL3_PAYLOAD_BASE``: The reason is that you can already load anything to any
+ address by changing the file ``armstub8.bin``, so there's no point in using
+ the Trusted Firmware in this case.
+
+- ``LOAD_IMAGE_V2=0``: Only version 2 is supported.
+
+AArch64 kernel build instructions
+---------------------------------
+
+The following instructions show how to install and run a AArch64 kernel by
+using a SD card with the default `Raspbian`_ install as base. Skip them if you
+want to use the default 32-bit kernel.
+
+Note that this system won't be fully 64-bit because all the tools in the
+filesystem are 32-bit binaries, but it's a quick way to get it working, and it
+allows the user to run 64-bit binaries in addition to 32-bit binaries.
+
+1. Clone the `Linux tree fork`_ maintained by the Raspberry Pi Foundation. To
+ speed things up, do a shallow clone of the desired branch.
+
+.. code:: shell
+
+ git clone --depth=1 -b rpi-4.14.y https://github.com/raspberrypi/linux
+ cd linux
+
+2. Configure and compile the kernel. Adapt the number after ``-j`` so that it is
+ 1.5 times the number of CPUs in your computer. This may take some time to
+ finish.
+
+.. code:: shell
+
+ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcmrpi3_defconfig
+ make -j 6 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
+
+3. Copy the kernel image and the device tree to the SD card. Replace the path
+ by the corresponding path in your computers to the ``boot`` partition of the
+ SD card.
+
+.. code:: shell
+
+ cp arch/arm64/boot/Image /path/to/boot/kernel8.img
+ cp arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dtb /path/to/boot/
+
+4. Install the kernel modules. Replace the path by the corresponding path to the
+ filesystem partition of the SD card on your computer.
+
+.. code:: shell
+
+ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
+ INSTALL_MOD_PATH=/path/to/filesystem modules_install
+
+5. Follow the instructions in `Setup SD card`_ except for the step of renaming
+ the existing ``kernel7.img`` (we have already copied a AArch64 kernel).
+
+Setup SD card
+-------------
+
+The instructions assume that you have an SD card with a fresh install of
+`Raspbian`_ (or that, at least, the ``boot`` partition is untouched, or nearly
+untouched). They have been tested with the image available in 2017-09-07.
+
+1. Insert the SD card and open the ``boot`` partition.
+
+2. Rename ``kernel7.img`` to ``kernel8.img``. This tricks the VideoCore
+ bootloader into booting the Arm cores in AArch64 mode, like the Trusted
+ Firmware needs, even though the kernel is not compiled for AArch64.
+
+3. Copy ``armstub8.bin`` here. When ``kernel8.img`` is available, The VideoCore
+ bootloader will look for a file called ``armstub8.bin`` and load it at
+ address **0x0** instead of a predefined one.
+
+4. Open ``cmdline.txt`` and add ``memmap=256M$16M`` to prevent the kernel from
+ using the memory needed by the Trusted Firmware. If you want to enable the
+ serial port "Mini UART", make sure that this file also contains
+ ``console=serial0,115200 console=tty1``.
+
+ Note that the 16 MiB reserved this way won't be available for Linux, the same
+ way as the memory reserved in DRAM for the GPU isn't available.
+
+5. Open ``config.txt`` and add the following lines at the end (``enable_uart=1``
+ is only needed to enable debugging through the Mini UART):
+
+::
+
+ enable_uart=1
+ kernel_address=0x01000000
+ device_tree_address=0x02000000
+
+If you connect a serial cable to the Mini UART and your computer, and connect
+to it (for example, with ``screen /dev/ttyUSB0 115200``) you should see some
+text. In the case of an AArch32 kernel, you should see something like this:
+
+::
+
+ NOTICE: Booting Trusted Firmware
+ NOTICE: BL1: v1.4(release):v1.4-329-g61e94684-dirty
+ NOTICE: BL1: Built : 00:09:25, Nov 6 2017
+ NOTICE: BL1: Booting BL2
+ NOTICE: BL2: v1.4(release):v1.4-329-g61e94684-dirty
+ NOTICE: BL2: Built : 00:09:25, Nov 6 2017
+ NOTICE: BL1: Booting BL31
+ NOTICE: BL31: v1.4(release):v1.4-329-g61e94684-dirty
+ NOTICE: BL31: Built : 00:09:25, Nov 6 2017
+ [ 0.266484] bcm2835-aux-uart 3f215040.serial: could not get clk: -517
+
+ Raspbian GNU/Linux 9 raspberrypi ttyS0
+ raspberrypi login:
+
+Just enter your credentials, everything should work as expected. Note that the
+HDMI output won't show any text during boot.
+
+.. _default Arm stub: https://github.com/raspberrypi/tools/blob/master/armstubs/armstub7.S
+.. _default AArch64 stub: https://github.com/raspberrypi/tools/blob/master/armstubs/armstub8.S
+.. _Linux kernel tree: https://github.com/torvalds/linux
+.. _Linux tree fork: https://github.com/raspberrypi/linux
+.. _Raspberry Pi 3: https://www.raspberrypi.org/products/raspberry-pi-3-model-b/
+.. _Raspberry Pi 3 Arm Trusted Firmware bootstrap: https://github.com/AntonioND/rpi3-arm-tf-bootstrap
+.. _Raspberry Pi 3 documentation: https://www.raspberrypi.org/documentation/
+.. _Raspbian: https://www.raspberrypi.org/downloads/raspbian/
diff --git a/docs/platform-interrupt-controller-API.rst b/docs/platform-interrupt-controller-API.rst
new file mode 100644
index 00000000..c14f0053
--- /dev/null
+++ b/docs/platform-interrupt-controller-API.rst
@@ -0,0 +1,313 @@
+Platform Interrupt Controller API documentation
+===============================================
+
+.. section-numbering::
+ :suffix: .
+
+.. contents::
+
+This document lists the optional platform interrupt controller API that
+abstracts the runtime configuration and control of interrupt controller from the
+generic code. The mandatory APIs are described in the `porting guide`__.
+
+.. __: porting-guide.rst#interrupt-management-framework-in-bl31
+
+Function: unsigned int plat_ic_get_running_priority(void); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : unsigned int
+
+This API should return the priority of the interrupt the PE is currently
+servicing. This must be be called only after an interrupt has already been
+acknowledged via. ``plat_ic_acknowledge_interrupt``.
+
+In the case of ARM standard platforms using GIC, the *Running Priority Register*
+is read to determine the priority of the interrupt.
+
+Function: int plat_ic_is_spi(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : int
+
+The API should return whether the interrupt ID (first parameter) is categorized
+as a Shared Peripheral Interrupt. Shared Peripheral Interrupts are typically
+associated to system-wide peripherals, and these interrupts can target any PE in
+the system.
+
+Function: int plat_ic_is_ppi(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : int
+
+The API should return whether the interrupt ID (first parameter) is categorized
+as a Private Peripheral Interrupt. Private Peripheral Interrupts are typically
+associated with peripherals that are private to each PE. Interrupts from private
+peripherals target to that PE only.
+
+Function: int plat_ic_is_sgi(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : int
+
+The API should return whether the interrupt ID (first parameter) is categorized
+as a Software Generated Interrupt. Software Generated Interrupts are raised by
+explicit programming by software, and are typically used in inter-PE
+communication. Secure SGIs are reserved for use by Secure world software.
+
+Function: unsigned int plat_ic_get_interrupt_active(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : int
+
+This API should return the *active* status of the interrupt ID specified by the
+first parameter, ``id``.
+
+In case of ARM standard platforms using GIC, the implementation of the API reads
+the GIC *Set Active Register* to read and return the active status of the
+interrupt.
+
+Function: void plat_ic_enable_interrupt(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : void
+
+This API should enable the interrupt ID specified by the first parameter,
+``id``. PEs in the system are expected to receive only enabled interrupts.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+inserts barrier to make memory updates visible before enabling interrupt, and
+then writes to GIC *Set Enable Register* to enable the interrupt.
+
+Function: void plat_ic_disable_interrupt(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : void
+
+This API should disable the interrupt ID specified by the first parameter,
+``id``. PEs in the system are not expected to receive disabled interrupts.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+writes to GIC *Clear Enable Register* to disable the interrupt, and inserts
+barrier to make memory updates visible afterwards.
+
+Function: void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Argument : unsigned int
+ Return : void
+
+This API should set the priority of the interrupt specified by first parameter
+``id`` to the value set by the second parameter ``priority``.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+writes to GIC *Priority Register* set interrupt priority.
+
+Function: int plat_ic_has_interrupt_type(unsigned int type); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : int
+
+This API should return whether the platform supports a given interrupt type. The
+parameter ``type`` shall be one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1``, or
+``INTR_TYPE_NS``.
+
+In case of ARM standard platforms using GICv3, the implementation of the API
+returns ``1`` for all interrupt types.
+
+In case of ARM standard platforms using GICv2, the API always return ``1`` for
+``INTR_TYPE_NS``. Return value for other types depends on the value of build
+option ``GICV2_G0_FOR_EL3``:
+
+- For interrupt type ``INTR_TYPE_EL3``:
+
+ - When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``0``, indicating no support
+ for EL3 interrupts.
+
+ - When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``1``, indicating support for
+ EL3 interrupts.
+
+- For interrupt type ``INTR_TYPE_S_EL1``:
+
+ - When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``1``, indicating support for
+ Secure EL1 interrupts.
+
+ - When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``0``, indicating no support
+ for Secure EL1 interrupts.
+
+Function: void plat_ic_set_interrupt_type(unsigned int id, unsigned int type); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Argument : unsigned int
+ Return : void
+
+This API should set the interrupt specified by first parameter ``id`` to the
+type specified by second parameter ``type``. The ``type`` parameter can be
+one of:
+
+- ``INTR_TYPE_NS``: interrupt is meant to be consumed by the Non-secure world.
+
+- ``INTR_TYPE_S_EL1``: interrupt is meant to be consumed by Secure EL1.
+
+- ``INTR_TYPE_EL3``: interrupt is meant to be consumed by EL3.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+writes to the GIC *Group Register* and *Group Modifier Register* (only GICv3) to
+assign the interrupt to the right group.
+
+For GICv3:
+
+- ``INTR_TYPE_NS`` maps to Group 1 interrupt.
+
+- ``INTR_TYPE_S_EL1`` maps to Secure Group 1 interrupt.
+
+- ``INTR_TYPE_EL3`` maps to Secure Group 0 interrupt.
+
+For GICv2:
+
+- ``INTR_TYPE_NS`` maps to Group 1 interrupt.
+
+- When the build option ``GICV2_G0_FOR_EL3`` is set to ``0`` (the default),
+ ``INTR_TYPE_S_EL1`` maps to Group 0. Otherwise, ``INTR_TYPE_EL3`` maps to
+ Group 0 interrupt.
+
+Function: void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : int
+ Argument : u_register_t
+ Return : void
+
+This API should raise an EL3 SGI. The first parameter, ``sgi_num``, specifies
+the ID of the SGI. The second parameter, ``target``, must be the MPIDR of the
+target PE.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+inserts barrier to make memory updates visible before raising SGI, then writes
+to appropriate *SGI Register* in order to raise the EL3 SGI.
+
+Function: void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, u_register_t mpidr); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Argument : unsigned int
+ Argument : u_register_t
+ Return : void
+
+This API should set the routing mode of Share Peripheral Interrupt (SPI)
+specified by first parameter ``id`` to that specified by the second parameter
+``routing_mode``.
+
+The ``routing_mode`` parameter can be one of:
+
+- ``INTR_ROUTING_MODE_ANY`` means the interrupt can be routed to any PE in the
+ system. The ``mpidr`` parameter is ignored in this case.
+
+- ``INTR_ROUTING_MODE_PE`` means the interrupt is routed to the PE whose MPIDR
+ value is specified by the parameter ``mpidr``.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+writes to the GIC *Target Register* (GICv2) or *Route Register* (GICv3) to set
+the routing.
+
+Function: void plat_ic_set_interrupt_pending(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : void
+
+This API should set the interrupt specified by first parameter ``id`` to
+*Pending*.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+inserts barrier to make memory updates visible before setting interrupt pending,
+and writes to the GIC *Set Pending Register* to set the interrupt pending
+status.
+
+Function: void plat_ic_clear_interrupt_pending(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : void
+
+This API should clear the *Pending* status of the interrupt specified by first
+parameter ``id``.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+writes to the GIC *Clear Pending Register* to clear the interrupt pending
+status, and inserts barrier to make memory updates visible afterwards.
+
+Function: unsigned int plat_ic_set_priority_mask(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : int
+
+This API should set the priority mask (first parameter) in the interrupt
+controller such that only interrupts of higher priority than the supplied one
+may be signalled to the PE. The API should return the current priority value
+that it's overwriting.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+inserts to order memory updates before updating mask, then writes to the GIC
+*Priority Mask Register*, and make sure memory updates are visible before
+potential trigger due to mask update.
+
+Function: unsigned int plat_ic_get_interrupt_id(unsigned int raw); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int
+ Return : unsigned int
+
+This API should extract and return the interrupt number from the raw value
+obtained by the acknowledging the interrupt (read using
+``plat_ic_acknowledge_interrupt()``). If the interrupt ID is invalid, this API
+should return ``INTR_ID_UNAVAILABLE``.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+masks out the interrupt ID field from the acknowledged value from GIC.
+
+----
+
+*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
diff --git a/docs/platform-migration-guide.rst b/docs/platform-migration-guide.rst
index 638033e4..ca755469 100644
--- a/docs/platform-migration-guide.rst
+++ b/docs/platform-migration-guide.rst
@@ -158,6 +158,17 @@ for the ``plat_psci_ops`` structure which is declared as :
int (*validate_ns_entrypoint)(unsigned long ns_entrypoint);
void (*get_sys_suspend_power_state)(
psci_power_state_t *req_state);
+ int (*get_pwr_lvl_state_idx)(plat_local_state_t pwr_domain_state,
+ int pwrlvl);
+ int (*translate_power_state_by_mpidr)(u_register_t mpidr,
+ unsigned int power_state,
+ psci_power_state_t *output_state);
+ int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
+ int (*mem_protect_chk)(uintptr_t base, u_register_t length);
+ int (*read_mem_protect)(int *val);
+ int (*write_mem_protect)(int val);
+ int (*system_reset2)(int is_vendor,
+ int reset_type, u_register_t cookie);
} plat_psci_ops_t;
The description of these handlers can be found in the `Porting Guide <porting-guide.rst#user-content-function--plat_setup_psci_ops-mandatory>`__.
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index 97985666..f020ec97 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -1596,6 +1596,34 @@ BL2 is responsible for loading the normal world BL33 image (e.g. UEFI).
This function isn't needed if either ``PRELOADED_BL33_BASE`` or ``EL3_PAYLOAD_BASE``
build options are used.
+Function : bl2\_plat\_preload\_setup [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+ Argument : void
+ Return : void
+
+This optional function performs any BL2 platform initialization
+required before image loading, that is not done later in
+bl2\_platform\_setup(). Specifically, if support for multiple
+boot sources is required, it initializes the boot sequence used by
+plat\_try\_next\_boot\_source().
+
+Function : plat\_try\_next\_boot\_source() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+ Argument : void
+ Return : int
+
+This optional function passes to the next boot source in the redundancy
+sequence.
+
+This function moves the current boot redundancy source to the next
+element in the boot sequence. If there are no more boot sources then it
+must return 0, otherwise it must return 1. The default implementation
+of this always returns 0.
+
FWU Boot Loader Stage 2 (BL2U)
------------------------------
@@ -1876,6 +1904,74 @@ calculated by the linker then a link time assertion is raised. A compile time
assertion is raised if the value of the constant is not aligned to the cache
line boundary.
+SDEI porting requirements
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The SDEI dispatcher requires the platform to provide the following macros
+and functions, of which some are optional, and some others mandatory.
+
+Macros
+......
+
+Macro: PLAT_SDEI_NORMAL_PRI [mandatory]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This macro must be defined to the EL3 exception priority level associated with
+Normal SDEI events on the platform. This must have a higher value (therefore of
+lower priority) than ``PLAT_SDEI_CRITICAL_PRI``.
+
+Macro: PLAT_SDEI_CRITICAL_PRI [mandatory]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This macro must be defined to the EL3 exception priority level associated with
+Critical SDEI events on the platform. This must have a lower value (therefore of
+higher priority) than ``PLAT_SDEI_NORMAL_PRI``.
+
+It's recommended that SDEI exception priorities in general are assigned the
+lowest among Secure priorities. Among the SDEI exceptions, Critical SDEI
+priority must be higher than Normal SDEI priority.
+
+Functions
+.........
+
+Function: int plat_sdei_validate_entry_point(uintptr_t ep) [optional]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+ Argument: uintptr_t
+ Return: int
+
+This function validates the address of client entry points provided for both
+event registration and *Complete and Resume* SDEI calls. The function takes one
+argument, which is the address of the handler the SDEI client requested to
+register. The function must return ``0`` for successful validation, or ``-1``
+upon failure.
+
+The default implementation always returns ``0``. On ARM platforms, this function
+is implemented to translate the entry point to physical address, and further to
+ensure that the address is located in Non-secure DRAM.
+
+Function: void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr) [optional]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+ Argument: uint64_t
+ Argument: unsigned int
+ Return: void
+
+SDEI specification requires that a PE comes out of reset with the events masked.
+The client therefore is expected to call ``PE_UNMASK`` to unmask SDEI events on
+the PE. No SDEI events can be dispatched until such time.
+
+Should a PE receive an interrupt that was bound to an SDEI event while the
+events are masked on the PE, the dispatcher implementation invokes the function
+``plat_sdei_handle_masked_trigger``. The MPIDR of the PE that received the
+interrupt and the interrupt ID are passed as parameters.
+
+The default implementation only prints out a warning message.
+
Power State Coordination Interface (in BL31)
--------------------------------------------
@@ -2107,13 +2203,32 @@ power domain levels. The handler needs to perform power management operation
corresponding to the local state at each power level. The generic code
expects the handler to succeed.
-The difference between turning a power domain off versus suspending it
-is that in the former case, the power domain is expected to re-initialize
-its state when it is next powered on (see ``pwr_domain_on_finish()``). In the
-latter case, the power domain is expected to save enough state so that it can
-resume execution by restoring this state when its powered on (see
+The difference between turning a power domain off versus suspending it is that
+in the former case, the power domain is expected to re-initialize its state
+when it is next powered on (see ``pwr_domain_on_finish()``). In the latter
+case, the power domain is expected to save enough state so that it can resume
+execution by restoring this state when its powered on (see
``pwr_domain_suspend_finish()``).
+When suspending a core, the platform can also choose to power off the GICv3
+Redistributor and ITS through an implementation-defined sequence. To achieve
+this safely, the ITS context must be saved first. The architectural part is
+implemented by the ``gicv3_its_save_disable()`` helper, but most of the needed
+sequence is implementation defined and it is therefore the responsibility of
+the platform code to implement the necessary sequence. Then the GIC
+Redistributor context can be saved using the ``gicv3_rdistif_save()`` helper.
+Powering off the Redistributor requires the implementation to support it and it
+is the responsibility of the platform code to execute the right implementation
+defined sequence.
+
+When a system suspend is requested, the platform can also make use of the
+``gicv3_distif_save()`` helper to save the context of the GIC Distributor after
+it has saved the context of the Redistributors and ITS of all the cores in the
+system. The context of the Distributor can be large and may require it to be
+allocated in a special area if it cannot fit in the platform's global static
+data, for example in DRAM. The Distributor can then be powered down using an
+implementation-defined sequence.
+
plat\_psci\_ops.pwr\_domain\_pwr\_down\_wfi()
.............................................
@@ -2159,6 +2274,10 @@ The ``target_state`` (first argument) has a similar meaning as described in
the ``pwr_domain_on_finish()`` operation. The generic code expects the platform
to succeed.
+If the Distributor, Redistributors or ITS have been powered off as part of a
+suspend, their context must be restored in this function in the reverse order
+to how they were saved during suspend sequence.
+
plat\_psci\_ops.system\_off()
.............................
@@ -2248,6 +2367,44 @@ appropriate.
Implementations are not expected to handle ``power_levels`` greater than
``PLAT_MAX_PWR_LVL``.
+plat\_psci\_ops.system\_reset2()
+................................
+
+This is an optional function. If implemented this function is
+called during the ``SYSTEM_RESET2`` call to perform a reset
+based on the first parameter ``reset_type`` as specified in
+`PSCI`_. The parameter ``cookie`` can be used to pass additional
+reset information. If the ``reset_type`` is not supported, the
+function must return ``PSCI_E_NOT_SUPPORTED``. For architectural
+resets, all failures must return ``PSCI_E_INVALID_PARAMETERS``
+and vendor reset can return other PSCI error codes as defined
+in `PSCI`_. On success this function will not return.
+
+plat\_psci\_ops.write\_mem\_protect()
+....................................
+
+This is an optional function. If implemented it enables or disables the
+``MEM_PROTECT`` functionality based on the value of ``val``.
+A non-zero value enables ``MEM_PROTECT`` and a value of zero
+disables it. Upon encountering failures it must return a negative value
+and on success it must return 0.
+
+plat\_psci\_ops.read\_mem\_protect()
+.....................................
+
+This is an optional function. If implemented it returns the current
+state of ``MEM_PROTECT`` via the ``val`` parameter. Upon encountering
+failures it must return a negative value and on success it must
+return 0.
+
+plat\_psci\_ops.mem\_protect\_chk()
+...................................
+
+This is an optional function. If implemented it checks if a memory
+region defined by a base address ``base`` and with a size of ``length``
+bytes is protected by ``MEM_PROTECT``. If the region is protected
+then it must return 0, otherwise it must return a negative number.
+
Interrupt Management framework (in BL31)
----------------------------------------
@@ -2266,6 +2423,10 @@ Standard layer to use GICv2 and the FVP can be configured to use either GICv2 or
GICv3 depending on the build flag ``FVP_USE_GIC_DRIVER`` (See FVP platform
specific build options in `User Guide`_ for more details).
+See also: `Interrupt Controller Abstraction APIs`__.
+
+.. __: platform-interrupt-controller-API.rst
+
Function : plat\_interrupt\_type\_to\_line() [mandatory]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2386,14 +2547,17 @@ Function : plat\_ic\_acknowledge\_interrupt() [mandatory]
Return : uint32_t
This API is used by the CPU to indicate to the platform IC that processing of
-the highest pending interrupt has begun. It should return the id of the
-interrupt which is being processed.
+the highest pending interrupt has begun. It should return the raw, unmodified
+value obtained from the interrupt controller when acknowledging an interrupt.
+The actual interrupt number shall be extracted from this raw value using the API
+`plat_ic_get_interrupt_id()`__.
+
+.. __: platform-interrupt-controller-API.rst#function-unsigned-int-plat-ic-get-interrupt-id-unsigned-int-raw-optional
This function in ARM standard platforms using GICv2, reads the *Interrupt
Acknowledge Register* (``GICC_IAR``). This changes the state of the highest
priority pending interrupt from pending to active in the interrupt controller.
-It returns the value read from the ``GICC_IAR``. This value is the id of the
-interrupt whose state has been changed.
+It returns the value read from the ``GICC_IAR``, unmodified.
In the case of ARM standard platforms using GICv3, if the API is invoked
from EL3, the function reads the system register ``ICC_IAR0_EL1``, *Interrupt
@@ -2401,7 +2565,7 @@ Acknowledge Register group 0*. If the API is invoked from S-EL1, the function
reads the system register ``ICC_IAR1_EL1``, *Interrupt Acknowledge Register
group 1*. The read changes the state of the highest pending interrupt from
pending to active in the interrupt controller. The value read is returned
-and is the id of the interrupt whose state has been changed.
+unmodified.
The TSP uses this API to start processing of the secure physical timer
interrupt.
@@ -2613,7 +2777,7 @@ amount of open resources per driver.
--------------
-*Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.*
+*Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.*
.. _Migration Guide: platform-migration-guide.rst
.. _include/plat/common/platform.h: ../include/plat/common/platform.h
diff --git a/docs/sdei.rst b/docs/sdei.rst
new file mode 100644
index 00000000..a67b7248
--- /dev/null
+++ b/docs/sdei.rst
@@ -0,0 +1,370 @@
+Software Delegated Exception Interface
+======================================
+
+
+.. section-numbering::
+ :suffix: .
+
+.. contents::
+ :depth: 2
+
+This document provides an overview of the SDEI dispatcher implementation in ARM
+Trusted Firmware.
+
+Introduction
+------------
+
+`Software Delegated Exception Interface`_ (SDEI) is an ARM specification for
+Non-secure world to register handlers with firmware to receive notifications
+about system events. Firmware will first receive the system events by way of
+asynchronous exceptions and, in response, arranges for the registered handler to
+execute in the Non-secure EL.
+
+Normal world software that interacts with the SDEI dispatcher (makes SDEI
+requests and receives notifications) is referred to as the *SDEI Client*. A
+client receives the event notification at the registered handler even when it
+was executing with exceptions masked. The list of SDEI events available to the
+client are specific to the platform [#std-event]_. See also `Determining client
+EL`_.
+
+.. _general SDEI dispatch:
+
+The following figure depicts a general sequence involving SDEI client executing
+at EL2 and an event dispatch resulting from the triggering of a bound interrupt.
+A commentary is provided below:
+
+.. image:: plantuml/sdei_general.svg
+
+As part of initialisation, the SDEI client binds a Non-secure interrupt [1], and
+the SDEI dispatcher returns a platform dynamic event number [2]. The client then
+registers a handler for that event [3], enables the event [5], and unmasks all
+events on the current PE [7]. This sequence is typical of an SDEI client, but it
+may involve additional SDEI calls.
+
+At a later point in time, when the bound interrupt triggers [9], it's trapped to
+EL3. The interrupt is handed over to the SDEI dispatcher, which then arranges to
+execute the registered handler [10]. The client terminates its execution with
+``SDEI_EVENT_COMPLETE`` [11], following which the dispatcher resumes the
+original EL2 execution [13]. Note that the SDEI interrupt remains active until
+the client handler completes, at which point EL3 does EOI [12].
+
+SDEI events can be explicitly dispatched in response to other asynchronous
+exceptions. See `Explicit dispatch of events`_.
+
+The remainder of this document only discusses the design and implementation of
+SDEI dispatcher in ARM Trusted Firmware, and assumes that the reader is familiar
+with the SDEI specification, the interfaces, and their requirements.
+
+.. [#std-event] Except event 0, which is defined by the SDEI specification as a
+ standard event.
+
+Defining events
+---------------
+
+A platform choosing to include the SDEI dispatcher must also define the events
+available on the platform, along with their attributes.
+
+The platform is expected to provide two arrays of event descriptors: one for
+private events, and another for shared events. The SDEI dispatcher provides
+``SDEI_PRIVATE_EVENT()`` and ``SDEI_SHARED_EVENT()`` macros to populate the
+event descriptors. Both macros take 3 arguments:
+
+- The event number: this must be a positive 32-bit integer.
+
+- The interrupt number the event is bound to:
+
+ - If it's not applicable to an event, this shall be left as ``0``.
+
+ - If the event is dynamic, this should be specified as ``SDEI_DYN_IRQ``.
+
+- A bit map of `Event flags`_.
+
+To define event 0, the macro ``SDEI_DEFINE_EVENT_0()`` should be used. This
+macro takes only one parameter: an SGI number to signal other PEs.
+
+Once the event descriptor arrays are defined, they should be exported to the
+SDEI dispatcher using the ``REGISTER_SDEI_MAP()`` macro, passing it the pointers
+to the private and shared event descriptor arrays, respectively. Note that the
+``REGISTER_SDEI_MAP()`` macro must be used in the same file where the arrays are
+defined.
+
+Regarding event descriptors:
+
+- For Event 0:
+
+ - There must be exactly one descriptor in the private array, and none in the
+ shared array.
+
+ - The event should be defined using ``SDEI_DEFINE_EVENT_0()``.
+
+ - Must be bound to a Secure SGI on the platform.
+
+- Statically bound shared and private interrupts must be bound to shared and
+ private interrupts on the platform, respectively. See the section on
+ `interrupt configuration`__.
+
+ .. __: `Configuration within Exception Handling Framework`_
+
+- Both arrays should be one-dimensional. The ``REGISTER_SDEI_MAP()`` macro
+ takes care of replicating private events for each PE on the platform.
+
+- Both arrays must be sorted in the increasing order of event number.
+
+The SDEI specification doesn't have provisions for discovery of available events
+on the platform. The list of events made available to the client, along with
+their semantics, have to be communicated out of band; for example, through
+Device Trees or firmware configuration tables.
+
+See also `Event definition example`_.
+
+Event flags
+~~~~~~~~~~~
+
+Event flags describe the properties of the event. They are bit maps that can be
+``OR``\ ed to form parameters to macros that `define events`__.
+
+.. __: `Defining events`_
+
+- ``SDEI_MAPF_DYNAMIC``: Marks the event as dynamic. Dynamic events can be
+ bound to (or released from) any Non-secure interrupt at runtime via. the
+ ``SDEI_INTERRUPT_BIND`` and ``SDEI_INTERRUPT_RELEASE`` calls.
+
+- ``SDEI_MAPF_BOUND``: Marks the event as statically bound to an interrupt.
+ These events cannot be re-bound at runtime.
+
+- ``SDEI_MAPF_CRITICAL``: Marks the event as having *Critical* priority.
+ Without this flag, the event is assumed to have *Normal* priority.
+
+Event definition example
+------------------------
+
+.. code:: c
+
+ static sdei_ev_map_t plat_private_sdei[] = {
+ /* Event 0 definition */
+ SDEI_DEFINE_EVENT_0(8),
+
+ /* PPI */
+ SDEI_PRIVATE_EVENT(8, 23, SDEI_MAPF_BOUND),
+
+ /* Dynamic private events */
+ SDEI_PRIVATE_EVENT(100, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+ SDEI_PRIVATE_EVENT(101, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC)
+ };
+
+ /* Shared event mappings */
+ static sdei_ev_map_t plat_shared_sdei[] = {
+ SDEI_SHARED_EVENT(804, 0, SDEI_MAPF_DYNAMIC),
+
+ /* Dynamic shared events */
+ SDEI_SHARED_EVENT(3000, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+ SDEI_SHARED_EVENT(3001, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC)
+ };
+
+ /* Export SDEI events */
+ REGISTER_SDEI_MAP(plat_private_sdei, plat_shared_sdei);
+
+Configuration within Exception Handling Framework
+-------------------------------------------------
+
+The SDEI dispatcher functions alongside the Exception Handling Framework. This
+means that the platform must assign priorities to both Normal and Critical SDEI
+interrupts for the platform:
+
+- Install priority descriptors for Normal and Critical SDEI interrupts.
+
+- For those interrupts that are statically bound (i.e. events defined as having
+ the ``SDEI_MAPF_BOUND`` property), enumerate their properties for the GIC
+ driver to configure interrupts accordingly.
+
+ The interrupts must be configured to target EL3. This means that they should
+ be configured as *Group 0*. Additionally, on GICv2 systems, the build option
+ ``GICV2_G0_FOR_EL3`` must be set to ``1``.
+
+See also `SDEI porting requirements`_.
+
+Determining client EL
+---------------------
+
+The SDEI specification requires that the *physical* SDEI client executes in the
+highest Non-secure EL implemented on the system. This means that the dispatcher
+will only allow SDEI calls to be made from:
+
+- EL2, if EL2 is implemented. The Hypervisor is expected to implement a
+ *virtual* SDEI dispatcher to support SDEI clients in Guest Operating Systems
+ executing in Non-secure EL1.
+
+- Non-secure EL1, if EL2 is not implemented or disabled.
+
+See the function ``sdei_client_el()`` in ``sdei_private.h``.
+
+Explicit dispatch of events
+---------------------------
+
+Typically, an SDEI event dispatch is caused by the PE receiving interrupts that
+are bound to an SDEI event. However, there are cases where the Secure world
+requires dispatch of an SDEI event as a direct or indirect result of a past
+activity, viz. receiving a Secure interrupt or an exception.
+
+The SDEI dispatcher implementation provides ``sdei_dispatch_event()`` API for
+this purpose. The API has the following signature:
+
+::
+
+ int sdei_dispatch_event(int ev_num, unsigned int preempted_sec_state);
+
+- The parameter ``ev_num`` is the event number to dispatch;
+
+- The parameter ``preempted_sec_state`` indicates the context that was
+ preempted. This must be either ``SECURE`` or ``NON_SECURE``.
+
+The API returns ``0`` on success, or ``-1`` on failure.
+
+The following figure depicts a scenario involving explicit dispatch of SDEI
+event. A commentary is provided below:
+
+.. image:: plantuml/sdei_explicit_dispatch.svg
+
+As part of initialisation, the SDEI client registers a handler for a platform
+event [1], enables the event [3], and unmasks the current PE [5]. Note that,
+unlike in `general SDEI dispatch`_, this doesn't involve interrupt binding, as
+bound or dynamic events can't be explicitly dispatched (see the section below).
+
+At a later point in time, a critical event [#critical-event]_ is trapped into
+EL3 [7]. EL3 performs a first-level triage of the event, and decides to dispatch
+to a Secure Partition [#secpart]_ for further handling [8]. The dispatch
+completes, but intends to involve Non-secure world in further handling, and
+therefore decides to explicitly dispatch an event [10] (which the client had
+already registered for [1]). The rest of the sequence is similar to that in the
+`general SDEI dispatch`_: the requested event is dispatched to the client
+(assuming all the conditions are met), and when the handler completes, the
+preempted execution resumes.
+
+.. [#critical-event] Examples of critical event are *SError*, *Synchronous
+ External Abort*, *Fault Handling interrupt*, or *Error
+ Recovery interrupt* from one of RAS nodes in the system.
+
+.. [#secpart] Dispatching to Secure Partition involves *Secure Partition
+ Manager*, which isn't depicted in the sequence.
+
+Conditions for event dispatch
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+All of the following requirements must be met for the API to return ``0`` and
+event to be dispatched:
+
+- SDEI events must be unmasked on the PE. I.e. the client must have called
+ ``PE_UNMASK`` beforehand.
+
+- Event 0 can't be dispatched.
+
+- The event must neither be a dynamic event nor be bound to an interrupt.
+
+- The event must be private to the PE.
+
+- The event must have been registered for and enabled.
+
+- A dispatch for the same event must not be outstanding. I.e. it hasn't already
+ been dispatched and is yet to be completed.
+
+- The priority of the event (either Critical or Normal, as configured by the
+ platform at build-time) shouldn't cause priority inversion. This means:
+
+ - If it's of Normal priority, neither Normal nor Critical priority dispatch
+ must be outstanding on the PE.
+
+ - If it's of a Critical priority, no Critical priority dispatch must be
+ outstanding on the PE.
+
+Further, the caller should be aware of the following assumptions made by the
+dispatcher:
+
+- The caller of the API is a component running in EL3; for example, the *Secure
+ Partition Manager*.
+
+- The requested dispatch will be permitted by the Exception Handling Framework.
+ I.e. the caller must make sure that the requested dispatch has sufficient
+ priority so as not to cause priority level inversion within Exception
+ Handling Framework.
+
+- At the time of the call, the active context is Secure, and it has been saved.
+
+- Upon returning success, the Non-secure context will be restored and setup for
+ the event dispatch, and it will be the active context. The Non-secure context
+ should not be modified further by the caller.
+
+- The API returning success only means that the dispatch is scheduled at the
+ next ``ERET``, and not immediately performed. Also, the caller must be
+ prepared for this API to return failure and handle accordingly.
+
+- Upon completing the event (i.e. when the client calls either
+ ``SDEI_EVENT_COMPLETE`` or ``SDEI_COMPLETE_AND_RESUME``), the preempted
+ context is resumed (as indicated by the ``preempted_sec_state`` parameter of
+ the API).
+
+Porting requirements
+--------------------
+
+The porting requirements of the SDEI dispatcher are outlined in the `porting
+guide`__.
+
+.. __: `SDEI porting requirements`_
+
+Note on writing SDEI event handlers
+-----------------------------------
+
+*This section pertains to SDEI event handlers in general, not just when using
+ARM Trusted Firmware SDEI dispatcher.*
+
+The SDEI specification requires that event handlers preserve the contents of all
+registers except ``x0`` to ``x17``. This has significance if event handler is
+written in C: compilers typically adjust the stack frame at the beginning and
+end of C functions. For example, AArch64 GCC typically produces the following
+function prologue and epilogue:
+
+::
+
+ c_event_handler:
+ stp x29, x30, [sp,#-32]!
+ mov x29, sp
+
+ ...
+
+ bl ...
+
+ ...
+
+ ldp x29, x30, [sp],#32
+ ret
+
+The register ``x29`` is used as frame pointer in the prologue. Because neither a
+valid ``SDEI_EVENT_COMPLETE`` nor ``SDEI_EVENT_COMPLETE_AND_RESUME`` calls
+return to the handler, the epilogue never gets executed, and registers ``x29``
+and ``x30`` (in the case above) are inadvertently corrupted. This violates the
+SDEI specification, and the normal execution thereafter will result in
+unexpected behaviour.
+
+To work this around, it's advised that the top-level event handlers are
+implemented in assembly, following a similar pattern as below:
+
+::
+
+ asm_event_handler:
+ /* Save link register whilst maintaining stack alignment */
+ stp xzr, x30, [sp, #-16]!
+ bl c_event_handler
+
+ /* Restore link register */
+ ldp xzr, x30, [sp], #16
+
+ /* Complete call */
+ ldr x0, =SDEI_EVENT_COMPLETE
+ smc #0
+ b .
+
+----
+
+*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
+
+.. _SDEI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
+.. _SDEI porting requirements: porting-guide.rst#sdei-porting-requirements
diff --git a/docs/spm-user-guide.rst b/docs/spm-user-guide.rst
new file mode 100644
index 00000000..a3b64d93
--- /dev/null
+++ b/docs/spm-user-guide.rst
@@ -0,0 +1,59 @@
+ARM Trusted Firmware - SPM User Guide
+=====================================
+
+.. section-numbering::
+ :suffix: .
+
+.. contents::
+
+
+This document briefly presents the Secure Partition Management (SPM) support in
+the Arm Trusted Firmware (TF), specifically focusing on how to build Arm TF with
+SPM support.
+
+Overview of the SPM software stack
+----------------------------------
+
+SPM is supported on the Arm FVP exclusively at the moment.
+
+It is not currently possible for BL31 to integrate SPM support and a Secure
+Payload Dispatcher (SPD) at the same time; they are mutually exclusive. In the
+SPM bootflow, a Secure Partition (SP) image executing at Secure-EL0 replaces the
+Secure Payload image executing at Secure-EL1 (e.g. a Trusted OS). Both are
+referred to as BL32.
+
+A working prototype of a SP has been implemented by repurposing the EDK2 code
+and tools, leveraging the concept of the *Standalone Management Mode (MM)* in
+the UEFI specification (see the PI v1.6 Volume 4: Management Mode Core
+Interface). This will be referred to as the *Standalone MM Secure Partition* in
+the rest of this document.
+
+
+Building TF with SPM support
+----------------------------
+
+To enable SPM support in the TF, the source code must be compiled with the build
+flag ``ENABLE_SPM=1``. On Arm platforms the build option ``ARM_BL31_IN_DRAM``
+can be used to select the location of BL31, both SRAM and DRAM are supported.
+
+
+Using the Standalone MM SP
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+First, build the Standalone MM Secure Partition. To build it, refer to the
+`instructions in the EDK2 repository`_.
+
+Then build TF with SPM support and include the Standalone MM Secure Partition
+image in the FIP:
+
+::
+
+ BL32=path/to/standalone/mm/sp BL33=path/to/bl33.bin \
+ make PLAT=fvp ENABLE_SPM=1 fip all
+
+
+--------------
+
+*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
+
+.. _instructions in the EDK2 repository: https://github.com/tianocore/edk2-staging/blob/AArch64StandaloneMm/HowtoBuild.MD
diff --git a/docs/user-guide.rst b/docs/user-guide.rst
index 1ff080d7..13f09641 100644
--- a/docs/user-guide.rst
+++ b/docs/user-guide.rst
@@ -219,7 +219,8 @@ Common build options
- ``ARM_ARCH_MAJOR``: The major version of ARM Architecture to target when
compiling ARM Trusted Firmware. Its value must be numeric, and defaults to
- 8 . See also, *ARMv8 Architecture Extensions* in `Firmware Design`_.
+ 8 . See also, *ARMv8 Architecture Extensions* and
+ *ARMv7 Architecture Extensions* in `Firmware Design`_.
- ``ARM_ARCH_MINOR``: The minor version of ARM Architecture to target when
compiling ARM Trusted Firmware. Its value must be a numeric, and defaults
@@ -320,6 +321,11 @@ Common build options
payload. Please refer to the "Booting an EL3 payload" section for more
details.
+- ``ENABLE_AMU``: Boolean option to enable Activity Monitor Unit extensions.
+ This is an optional architectural feature available on v8.4 onwards. Some
+ v8.2 implementations also implement an AMU and this option can be used to
+ enable this feature on those systems as well. Default is 0.
+
- ``ENABLE_ASSERTIONS``: This option controls whether or not calls to ``assert()``
are compiled out. For debug builds, this option defaults to 1, and calls to
``assert()`` are left in place. For release builds, this option defaults to 0
@@ -344,9 +350,20 @@ Common build options
the ``ENABLE_PMF`` build option as well. Default is 0.
- ``ENABLE_SPE_FOR_LOWER_ELS`` : Boolean option to enable Statistical Profiling
- extensions. This is an optional architectural feature available only for
- AArch64 8.2 onwards. This option defaults to 1 but is automatically
- disabled when the target architecture is AArch32 or AArch64 8.0/8.1.
+ extensions. This is an optional architectural feature for AArch64.
+ The default is 1 but is automatically disabled when the target architecture
+ is AArch32.
+
+- ``ENABLE_SVE_FOR_NS``: Boolean option to enable Scalable Vector Extension
+ (SVE) for the Non-secure world only. SVE is an optional architectural feature
+ for AArch64. Note that when SVE is enabled for the Non-secure world, access
+ to SIMD and floating-point functionality from the Secure world is disabled.
+ This is to avoid corruption of the Non-secure world data in the Z-registers
+ which are aliased by the SIMD and FP registers. The build option is not
+ compatible with the ``CTX_INCLUDE_FPREGS`` build option, and will raise an
+ assert on platforms where SVE is implemented and ``ENABLE_SVE_FOR_NS`` set to
+ 1. The default is 1 but is automatically disabled when the target
+ architecture is AArch32.
- ``ENABLE_STACK_PROTECTOR``: String option to enable the stack protection
checks in GCC. Allowed values are "all", "strong" and "0" (default).
@@ -361,6 +378,11 @@ Common build options
Firmware as error. It can take the value 1 (flag the use of deprecated
APIs as error) or 0. The default is 0.
+- ``EL3_EXCEPTION_HANDLING``: When set to ``1``, enable handling of exceptions
+ targeted at EL3. When set ``0`` (default), no exceptions are expected or
+ handled at EL3, and a panic will result. This is supported only for AArch64
+ builds.
+
- ``FIP_NAME``: This is an optional build option which specifies the FIP
filename for the ``fip`` target. Default is ``fip.bin``.
@@ -386,6 +408,19 @@ Common build options
images will include support for Trusted Board Boot, but the FIP and FWU\_FIP
will not include the corresponding certificates, causing a boot failure.
+- ``GICV2_G0_FOR_EL3``: Unlike GICv3, the GICv2 architecture doesn't have
+ inherent support for specific EL3 type interrupts. Setting this build option
+ to ``1`` assumes GICv2 *Group 0* interrupts are expected to target EL3, both
+ by `platform abstraction layer`__ and `Interrupt Management Framework`__.
+ This allows GICv2 platforms to enable features requiring EL3 interrupt type.
+ This also means that all GICv2 Group 0 interrupts are delivered to EL3, and
+ the Secure Payload interrupts needs to be synchronously handed over to Secure
+ EL1 for handling. The default value of this option is ``0``, which means the
+ Group 0 interrupts are assumed to be handled by Secure EL1.
+
+ .. __: `platform-interrupt-controller-API.rst`
+ .. __: `interrupt-framework-design.rst`
+
- ``HANDLE_EA_EL3_FIRST``: When defined External Aborts and SError Interrupts
will be always trapped in EL3 i.e. in BL31 at runtime.
@@ -407,11 +442,15 @@ Common build options
- ``KEY_ALG``: This build flag enables the user to select the algorithm to be
used for generating the PKCS keys and subsequent signing of the certificate.
- It accepts 3 values viz ``rsa``, ``rsa_1_5``, ``ecdsa``. The ``rsa_1_5`` is
+ It accepts 3 values viz. ``rsa``, ``rsa_1_5``, ``ecdsa``. The ``rsa_1_5`` is
the legacy PKCS#1 RSA 1.5 algorithm which is not TBBR compliant and is
retained only for compatibility. The default value of this flag is ``rsa``
which is the TBBR compliant PKCS#1 RSA 2.1 scheme.
+- ``HASH_ALG``: This build flag enables the user to select the secure hash
+ algorithm. It accepts 3 values viz. ``sha256``, ``sha384``, ``sha512``.
+ The default value of this flag is ``sha256``.
+
- ``LDFLAGS``: Extra user options appended to the linkers' command line in
addition to the one set by the build system.
@@ -516,6 +555,12 @@ Common build options
optional. It is only needed if the platform makefile specifies that it
is required in order to build the ``fwu_fip`` target.
+- ``SDEI_SUPPORT``: Setting this to ``1`` enables support for Software
+ Delegated Exception Interface to BL31 image. This defaults to ``0``.
+
+ When set to ``1``, the build option ``EL3_EXCEPTION_HANDLING`` must also be
+ set to ``1``.
+
- ``SEPARATE_CODE_AND_RODATA``: Whether code and read-only data should be
isolated on separate memory pages. This is a trade-off between security and
memory usage. See "Isolating code and read-only data on separate memory
@@ -643,12 +688,18 @@ ARM development platform specific build options
``arm_rotpk_rsa.der``, located in ``plat/arm/board/common/rotpk``. To use
this option, ``arm_rotprivk_rsa.pem`` must be specified as ``ROT_KEY`` when
creating the certificates.
+ - ``devel_ecdsa`` : return a development public key hash embedded in the BL1
+ and BL2 binaries. This hash has been obtained from the ECDSA public key
+ ``arm_rotpk_ecdsa.der``, located in ``plat/arm/board/common/rotpk``. To use
+ this option, ``arm_rotprivk_ecdsa.pem`` must be specified as ``ROT_KEY``
+ when creating the certificates.
- ``ARM_TSP_RAM_LOCATION``: location of the TSP binary. Options:
- - ``tsram`` : Trusted SRAM (default option)
+ - ``tsram`` : Trusted SRAM (default option when TBB is not enabled)
- ``tdram`` : Trusted DRAM (if available)
- - ``dram`` : Secure region in DRAM (configured by the TrustZone controller)
+ - ``dram`` : Secure region in DRAM (default option when TBB is enabled,
+ configured by the TrustZone controller)
- ``ARM_XLAT_TABLES_LIB_V1``: boolean option to compile the Trusted Firmware
with version 1 of the translation tables library instead of version 2. It is
@@ -990,6 +1041,10 @@ images with support for these features:
in the ARM platform port. The private/public RSA key pair may be
found in ``plat/arm/board/common/rotpk``.
+ - ``ARM_ROTPK_LOCATION=devel_ecdsa``: use the ROTPK hash that is hardcoded
+ in the ARM platform port. The private/public ECDSA key pair may be
+ found in ``plat/arm/board/common/rotpk``.
+
Example of command line using RSA development keys:
::
@@ -1168,7 +1223,7 @@ corrupted binaries.
make ARCH=aarch64 PLAT=juno LOAD_IMAGE_V2=1 JUNO_AARCH32_EL3_RUNTIME=1 \
BL33=<path-to-juno32-oe-uboot>/SOFTWARE/bl33-uboot.bin \
- SCP_BL2=<path-to-juno32-oe-uboot>/SOFTWARE/scp_bl2.bin SPD=tspd \
+ SCP_BL2=<path-to-juno32-oe-uboot>/SOFTWARE/scp_bl2.bin \
BL32=<path-to-bl32>/bl32.bin all fip
The resulting BL1 and FIP images may be found in:
@@ -1183,6 +1238,56 @@ The resulting BL1 and FIP images may be found in:
./build/fvp/release/bl1.bin
./build/fvp/release/fip.bin
+
+Booting Firmware Update images
+-------------------------------------
+
+When Firmware Update (FWU) is enabled there are at least 2 new images
+that have to be loaded, the Non-Secure FWU ROM (NS-BL1U), and the
+FWU FIP.
+
+Juno
+~~~~
+
+The new images must be programmed in flash memory by adding
+an entry in the ``SITE1/HBI0262x/images.txt`` configuration file
+on the Juno SD card (where ``x`` depends on the revision of the Juno board).
+Refer to the `Juno Getting Started Guide`_, section 2.3 "Flash memory
+programming" for more information. User should ensure these do not
+overlap with any other entries in the file.
+
+::
+
+ NOR10UPDATE: AUTO ;Image Update:NONE/AUTO/FORCE
+ NOR10ADDRESS: 0x00400000 ;Image Flash Address [ns_bl2u_base_address]
+ NOR10FILE: \SOFTWARE\fwu_fip.bin ;Image File Name
+ NOR10LOAD: 00000000 ;Image Load Address
+ NOR10ENTRY: 00000000 ;Image Entry Point
+
+ NOR11UPDATE: AUTO ;Image Update:NONE/AUTO/FORCE
+ NOR11ADDRESS: 0x03EB8000 ;Image Flash Address [ns_bl1u_base_address]
+ NOR11FILE: \SOFTWARE\ns_bl1u.bin ;Image File Name
+ NOR11LOAD: 00000000 ;Image Load Address
+
+The address ns_bl1u_base_address is the value of NS_BL1U_BASE - 0x8000000.
+In the same way, the address ns_bl2u_base_address is the value of
+NS_BL2U_BASE - 0x8000000.
+
+FVP
+~~~
+
+The additional fip images must be loaded with:
+
+::
+
+ --data cluster0.cpu0="<path_to>/ns_bl1u.bin"@0x0beb8000 [ns_bl1u_base_address]
+ --data cluster0.cpu0="<path_to>/fwu_fip.bin"@0x08400000 [ns_bl2u_base_address]
+
+The address ns_bl1u_base_address is the value of NS_BL1U_BASE.
+In the same way, the address ns_bl2u_base_address is the value of
+NS_BL2U_BASE.
+
+
EL3 payloads alternative boot flow
----------------------------------
@@ -1370,10 +1475,10 @@ Running the software on FVP
The latest version of the AArch64 build of ARM Trusted Firmware has been tested
on the following ARM FVPs (64-bit host machine only).
-NOTE: Unless otherwise stated, the model version is Version 11.0 Build 11.0.34.
+NOTE: Unless otherwise stated, the model version is Version 11.1 Build 11.1.22.
- ``Foundation_Platform``
-- ``FVP_Base_AEMv8A-AEMv8A`` (Version 8.5, Build 0.8.8502)
+- ``FVP_Base_AEMv8A-AEMv8A`` (Version 8.7, Build 0.8.8702)
- ``FVP_Base_Cortex-A35x4``
- ``FVP_Base_Cortex-A53x4``
- ``FVP_Base_Cortex-A57x4-A53x4``
@@ -1386,7 +1491,7 @@ NOTE: Unless otherwise stated, the model version is Version 11.0 Build 11.0.34.
The latest version of the AArch32 build of ARM Trusted Firmware has been tested
on the following ARM FVPs (64-bit host machine only).
-- ``FVP_Base_AEMv8A-AEMv8A`` (Version 8.5, Build 0.8.8502)
+- ``FVP_Base_AEMv8A-AEMv8A`` (Version 8.7, Build 0.8.8702)
- ``FVP_Base_Cortex-A32x4``
NOTE: The build numbers quoted above are those reported by launching the FVP
@@ -1405,7 +1510,7 @@ NOTE: FVPs can be launched with ``--cadi-server`` option such that a
CADI-compliant debugger (for example, ARM DS-5) can connect to and control its
execution.
-NOTE: With FVP model Version 11.0 Build 11.0.34 and Version 8.5 Build 0.8.5202
+NOTE: Since FVP model Version 11.0 Build 11.0.34 and Version 8.5 Build 0.8.5202
the internal synchronisation timings changed compared to older versions of the
models. The models can be launched with ``-Q 100`` option if they are required
to match the run time characteristics of the older versions.
diff --git a/docs/xlat-tables-lib-v2-design.rst b/docs/xlat-tables-lib-v2-design.rst
index 3006ce72..07cbf86c 100644
--- a/docs/xlat-tables-lib-v2-design.rst
+++ b/docs/xlat-tables-lib-v2-design.rst
@@ -66,7 +66,8 @@ map. It is one of the key interfaces to the library. It is identified by:
- its physical base address;
- its virtual base address;
- its size;
-- its attributes.
+- its attributes;
+- its mapping granularity (optional).
See the ``struct mmap_region`` type in `xlat\_tables\_v2.h`_.
@@ -76,9 +77,37 @@ might create new translation tables, update or split existing ones.
The region attributes specify the type of memory (for example device or cached
normal memory) as well as the memory access permissions (read-only or
-read-write, executable or not, secure or non-secure, and so on). See the
-``mmap_attr_t`` enumeration type in `xlat\_tables\_v2.h`_.
-
+read-write, executable or not, secure or non-secure, and so on). In the case of
+the EL1&0 translation regime, the attributes also specify whether the region is
+a User region (EL0) or Privileged region (EL1). See the ``mmap_attr_t``
+enumeration type in `xlat\_tables\_v2.h`_. Note that for the EL1&0 translation
+regime the Execute Never attribute is set simultaneously for both EL1 and EL0.
+
+The granularity controls the translation table level to go down to when mapping
+the region. For example, assuming the MMU has been configured to use a 4KB
+granule size, the library might map a 2MB memory region using either of the two
+following options:
+
+- using a single level-2 translation table entry;
+- using a level-2 intermediate entry to a level-3 translation table (which
+ contains 512 entries, each mapping 4KB).
+
+The first solution potentially requires less translation tables, hence
+potentially less memory. However, if part of this 2MB region is later remapped
+with different memory attributes, the library might need to split the existing
+page tables to refine the mappings. If a single level-2 entry has been used
+here, a level-3 table will need to be allocated on the fly and the level-2
+modified to point to this new level-3 table. This has a performance cost at
+run-time.
+
+If the user knows upfront that such a remapping operation is likely to happen
+then they might enforce a 4KB mapping granularity for this 2MB region from the
+beginning; remapping some of these 4KB pages on the fly then becomes a
+lightweight operation.
+
+The region's granularity is an optional field; if it is not specified the
+library will choose the mapping granularity for this region as it sees fit (more
+details can be found in `The memory mapping algorithm`_ section below).
Translation Context
~~~~~~~~~~~~~~~~~~~
@@ -190,6 +219,11 @@ the ``MAP_REGION*()`` family of helper macros. This is to limit the risk of
compatibility breaks, should the ``mmap_region`` structure type evolve in the
future.
+The ``MAP_REGION()`` and ``MAP_REGION_FLAT()`` macros do not allow specifying a
+mapping granularity, which leaves the library implementation free to choose
+it. However, in cases where a specific granularity is required, the
+``MAP_REGION2()`` macro might be used instead.
+
As explained earlier in this document, when the dynamic mapping feature is
disabled, there is no notion of dynamic regions. Conceptually, there are only
static regions. For this reason (and to retain backward compatibility with the
@@ -265,6 +299,9 @@ The architectural module
Core module
~~~~~~~~~~~
+From mmap regions to translation tables
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
All the APIs in this module work on a translation context. The translation
context contains the list of ``mmap_region``, which holds the information of all
the regions that are mapped at any given time. Whenever there is a request to
@@ -288,14 +325,18 @@ After the ``init_xlat_tables()`` API has been called, only dynamic regions can
be added. Changes to the translation tables (as well as the mmap regions list)
will take effect immediately.
+The memory mapping algorithm
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
The mapping function is implemented as a recursive algorithm. It is however
bound by the level of depth of the translation tables (the ARMv8-A architecture
allows up to 4 lookup levels).
-By default, the algorithm will attempt to minimize the number of translation
-tables created to satisfy the user's request. It will favour mapping a region
-using the biggest possible blocks, only creating a sub-table if it is strictly
-necessary. This is to reduce the memory footprint of the firmware.
+By default [#granularity-ref]_, the algorithm will attempt to minimize the
+number of translation tables created to satisfy the user's request. It will
+favour mapping a region using the biggest possible blocks, only creating a
+sub-table if it is strictly necessary. This is to reduce the memory footprint of
+the firmware.
The most common reason for needing a sub-table is when a specific mapping
requires a finer granularity. Misaligned regions also require a finer
@@ -322,6 +363,12 @@ entries in the translation tables are checked to ensure consistency. Please
refer to the comments in the source code of the core module for more details
about the sorting algorithm in use.
+.. [#granularity-ref] That is, when mmap regions do not enforce their mapping
+ granularity.
+
+TLB maintenance operations
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
The library takes care of performing TLB maintenance operations when required.
For example, when the user requests removing a dynamic region, the library
invalidates all TLB entries associated to that region to ensure that these
diff --git a/drivers/arm/ccn/ccn.c b/drivers/arm/ccn/ccn.c
index ec264d21..afb7d9d3 100644
--- a/drivers/arm/ccn/ccn.c
+++ b/drivers/arm/ccn/ccn.c
@@ -236,7 +236,7 @@ static unsigned long long ccn_master_to_rn_id_map(unsigned long long master_map)
node_id = ccn_plat_desc->master_to_rn_id_map[iface_id];
/* Set the bit corresponding to this node ID */
- rn_id_map |= (1UL << node_id);
+ rn_id_map |= (1ULL << node_id);
}
return rn_id_map;
diff --git a/drivers/arm/ccn/ccn_private.h b/drivers/arm/ccn/ccn_private.h
index f71597c1..c17c2742 100644
--- a/drivers/arm/ccn/ccn_private.h
+++ b/drivers/arm/ccn/ccn_private.h
@@ -134,13 +134,13 @@ typedef enum rn_types {
#define HNF_SAM_CTRL_SN1_ID_SHIFT 8
#define HNF_SAM_CTRL_SN2_ID_SHIFT 16
-#define HNF_SAM_CTRL_TAB0_MASK 0x3fUL
+#define HNF_SAM_CTRL_TAB0_MASK ULL(0x3f)
#define HNF_SAM_CTRL_TAB0_SHIFT 48
-#define HNF_SAM_CTRL_TAB1_MASK 0x3fUL
+#define HNF_SAM_CTRL_TAB1_MASK ULL(0x3f)
#define HNF_SAM_CTRL_TAB1_SHIFT 56
#define HNF_SAM_CTRL_3SN_ENB_SHIFT 32
-#define HNF_SAM_CTRL_3SN_ENB_MASK 0x01UL
+#define HNF_SAM_CTRL_3SN_ENB_MASK ULL(0x01)
/*
* Macro to create a value suitable for programming into a HNF SAM Control
@@ -169,7 +169,7 @@ typedef enum rn_types {
#define FOR_EACH_BIT(bit_pos, bit_map) \
for (bit_pos = __builtin_ctzll(bit_map); \
bit_map; \
- bit_map &= ~(1UL << bit_pos), \
+ bit_map &= ~(1ULL << (bit_pos)), \
bit_pos = __builtin_ctzll(bit_map))
/*
diff --git a/drivers/arm/gic/common/gic_common.c b/drivers/arm/gic/common/gic_common.c
index 6535813f..d523772b 100644
--- a/drivers/arm/gic/common/gic_common.c
+++ b/drivers/arm/gic/common/gic_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -273,6 +273,14 @@ void gicd_set_icpendr(uintptr_t base, unsigned int id)
gicd_write_icpendr(base, id, (1 << bit_num));
}
+unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id)
+{
+ unsigned int bit_num = id & ((1 << ISACTIVER_SHIFT) - 1);
+ unsigned int reg_val = gicd_read_isactiver(base, id);
+
+ return (reg_val >> bit_num) & 0x1;
+}
+
void gicd_set_isactiver(uintptr_t base, unsigned int id)
{
unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1);
@@ -291,3 +299,15 @@ void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
{
mmio_write_8(base + GICD_IPRIORITYR + id, pri & GIC_PRI_MASK);
}
+
+void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+ unsigned bit_num = id & ((1 << ICFGR_SHIFT) - 1);
+ uint32_t reg_val = gicd_read_icfgr(base, id);
+
+ /* Clear the field, and insert required configuration */
+ reg_val &= ~(GIC_CFG_MASK << bit_num);
+ reg_val |= ((cfg & GIC_CFG_MASK) << bit_num);
+
+ gicd_write_icfgr(base, id, reg_val);
+}
diff --git a/drivers/arm/gic/common/gic_common_private.h b/drivers/arm/gic/common/gic_common_private.h
index 2077cc46..2021f9aa 100644
--- a/drivers/arm/gic/common/gic_common_private.h
+++ b/drivers/arm/gic/common/gic_common_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -73,8 +73,10 @@ void gicd_set_isenabler(uintptr_t base, unsigned int id);
void gicd_set_icenabler(uintptr_t base, unsigned int id);
void gicd_set_ispendr(uintptr_t base, unsigned int id);
void gicd_set_icpendr(uintptr_t base, unsigned int id);
+unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id);
void gicd_set_isactiver(uintptr_t base, unsigned int id);
void gicd_set_icactiver(uintptr_t base, unsigned int id);
void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri);
+void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg);
#endif /* GIC_COMMON_PRIVATE_H_ */
diff --git a/drivers/arm/gic/v2/gicv2_helpers.c b/drivers/arm/gic/v2/gicv2_helpers.c
index 7cdbc27c..0df50fb0 100644
--- a/drivers/arm/gic/v2/gicv2_helpers.c
+++ b/drivers/arm/gic/v2/gicv2_helpers.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,6 +9,7 @@
#include <assert.h>
#include <debug.h>
#include <gic_common.h>
+#include <interrupt_props.h>
#include "../common/gic_common_private.h"
#include "gicv2_private.h"
@@ -72,15 +73,6 @@ void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val)
mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
}
-/*
- * Accessor to write the GIC Distributor ITARGETSR corresponding to the
- * interrupt `id`.
- */
-void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target)
-{
- mmio_write_8(base + GICD_ITARGETSR + id, target & GIC_TARGET_CPU_MASK);
-}
-
/*******************************************************************************
* Get the current CPU bit mask from GICD_ITARGETSR0
******************************************************************************/
@@ -121,6 +113,7 @@ void gicv2_spis_configure_defaults(uintptr_t gicd_base)
gicd_write_icfgr(gicd_base, index, 0);
}
+#if !ERROR_DEPRECATED
/*******************************************************************************
* Helper function to configure secure G0 SPIs.
******************************************************************************/
@@ -154,8 +147,50 @@ void gicv2_secure_spis_configure(uintptr_t gicd_base,
}
}
+#endif
/*******************************************************************************
+ * Helper function to configure properties of secure G0 SPIs.
+ ******************************************************************************/
+void gicv2_secure_spis_configure_props(uintptr_t gicd_base,
+ const interrupt_prop_t *interrupt_props,
+ unsigned int interrupt_props_num)
+{
+ unsigned int i;
+ const interrupt_prop_t *prop_desc;
+
+ /* Make sure there's a valid property array */
+ assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1);
+
+ for (i = 0; i < interrupt_props_num; i++) {
+ prop_desc = &interrupt_props[i];
+
+ if (prop_desc->intr_num < MIN_SPI_ID)
+ continue;
+
+ /* Configure this interrupt as a secure interrupt */
+ assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
+ gicd_clr_igroupr(gicd_base, prop_desc->intr_num);
+
+ /* Set the priority of this interrupt */
+ gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
+ prop_desc->intr_pri);
+
+ /* Target the secure interrupts to primary CPU */
+ gicd_set_itargetsr(gicd_base, prop_desc->intr_num,
+ gicv2_get_cpuif_id(gicd_base));
+
+ /* Set interrupt configuration */
+ gicd_set_icfgr(gicd_base, prop_desc->intr_num,
+ prop_desc->intr_cfg);
+
+ /* Enable this interrupt */
+ gicd_set_isenabler(gicd_base, prop_desc->intr_num);
+ }
+}
+
+#if !ERROR_DEPRECATED
+/*******************************************************************************
* Helper function to configure secure G0 SGIs and PPIs.
******************************************************************************/
void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
@@ -202,3 +237,66 @@ void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
/* Enable the Group 0 SGIs and PPIs */
gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
}
+#endif
+
+/*******************************************************************************
+ * Helper function to configure properties of secure G0 SGIs and PPIs.
+ ******************************************************************************/
+void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base,
+ const interrupt_prop_t *interrupt_props,
+ unsigned int interrupt_props_num)
+{
+ unsigned int i;
+ uint32_t sec_ppi_sgi_mask = 0;
+ const interrupt_prop_t *prop_desc;
+
+ /* Make sure there's a valid property array */
+ assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1);
+
+ /*
+ * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
+ * more scalable approach as it avoids clearing the enable bits in the
+ * GICD_CTLR.
+ */
+ gicd_write_icenabler(gicd_base, 0, ~0);
+
+ /* Setup the default PPI/SGI priorities doing four at a time */
+ for (i = 0; i < MIN_SPI_ID; i += 4)
+ gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL);
+
+ for (i = 0; i < interrupt_props_num; i++) {
+ prop_desc = &interrupt_props[i];
+
+ if (prop_desc->intr_num >= MIN_SPI_ID)
+ continue;
+
+ /* Configure this interrupt as a secure interrupt */
+ assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
+
+ /*
+ * Set interrupt configuration for PPIs. Configuration for SGIs
+ * are ignored.
+ */
+ if ((prop_desc->intr_num >= MIN_PPI_ID) &&
+ (prop_desc->intr_num < MIN_SPI_ID)) {
+ gicd_set_icfgr(gicd_base, prop_desc->intr_num,
+ prop_desc->intr_cfg);
+ }
+
+ /* We have an SGI or a PPI. They are Group0 at reset */
+ sec_ppi_sgi_mask |= (1u << prop_desc->intr_num);
+
+ /* Set the priority of this interrupt */
+ gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
+ prop_desc->intr_pri);
+ }
+
+ /*
+ * Invert the bitmask to create a mask for non-secure PPIs and SGIs.
+ * Program the GICD_IGROUPR0 with this bit mask.
+ */
+ gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
+
+ /* Enable the Group 0 SGIs and PPIs */
+ gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
+}
diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c
index deac927c..87986594 100644
--- a/drivers/arm/gic/v2/gicv2_main.c
+++ b/drivers/arm/gic/v2/gicv2_main.c
@@ -10,11 +10,20 @@
#include <debug.h>
#include <gic_common.h>
#include <gicv2.h>
+#include <interrupt_props.h>
+#include <spinlock.h>
#include "../common/gic_common_private.h"
#include "gicv2_private.h"
static const gicv2_driver_data_t *driver_data;
+/*
+ * Spinlock to guard registers needing read-modify-write. APIs protected by this
+ * spinlock are used either at boot time (when only a single CPU is active), or
+ * when the system is fully coherent.
+ */
+spinlock_t gic_lock;
+
/*******************************************************************************
* Enable secure interrupts and use FIQs to route them. Disable legacy bypass
* and set the priority mask register to allow all interrupts to trickle in.
@@ -63,13 +72,32 @@ void gicv2_cpuif_disable(void)
******************************************************************************/
void gicv2_pcpu_distif_init(void)
{
+ unsigned int ctlr;
+
assert(driver_data);
assert(driver_data->gicd_base);
- assert(driver_data->g0_interrupt_array);
- gicv2_secure_ppi_sgi_setup(driver_data->gicd_base,
- driver_data->g0_interrupt_num,
- driver_data->g0_interrupt_array);
+#if !ERROR_DEPRECATED
+ if (driver_data->interrupt_props != NULL) {
+#endif
+ gicv2_secure_ppi_sgi_setup_props(driver_data->gicd_base,
+ driver_data->interrupt_props,
+ driver_data->interrupt_props_num);
+#if !ERROR_DEPRECATED
+ } else {
+ assert(driver_data->g0_interrupt_array);
+ gicv2_secure_ppi_sgi_setup(driver_data->gicd_base,
+ driver_data->g0_interrupt_num,
+ driver_data->g0_interrupt_array);
+ }
+#endif
+
+ /* Enable G0 interrupts if not already */
+ ctlr = gicd_read_ctlr(driver_data->gicd_base);
+ if ((ctlr & CTLR_ENABLE_G0_BIT) == 0) {
+ gicd_write_ctlr(driver_data->gicd_base,
+ ctlr | CTLR_ENABLE_G0_BIT);
+ }
}
/*******************************************************************************
@@ -83,7 +111,6 @@ void gicv2_distif_init(void)
assert(driver_data);
assert(driver_data->gicd_base);
- assert(driver_data->g0_interrupt_array);
/* Disable the distributor before going further */
ctlr = gicd_read_ctlr(driver_data->gicd_base);
@@ -93,10 +120,22 @@ void gicv2_distif_init(void)
/* Set the default attribute of all SPIs */
gicv2_spis_configure_defaults(driver_data->gicd_base);
- /* Configure the G0 SPIs */
- gicv2_secure_spis_configure(driver_data->gicd_base,
- driver_data->g0_interrupt_num,
- driver_data->g0_interrupt_array);
+#if !ERROR_DEPRECATED
+ if (driver_data->interrupt_props != NULL) {
+#endif
+ gicv2_secure_spis_configure_props(driver_data->gicd_base,
+ driver_data->interrupt_props,
+ driver_data->interrupt_props_num);
+#if !ERROR_DEPRECATED
+ } else {
+ assert(driver_data->g0_interrupt_array);
+
+ /* Configure the G0 SPIs */
+ gicv2_secure_spis_configure(driver_data->gicd_base,
+ driver_data->g0_interrupt_num,
+ driver_data->g0_interrupt_array);
+ }
+#endif
/* Re-enable the secure SPIs now that they have been configured */
gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT);
@@ -112,25 +151,44 @@ void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data)
assert(plat_driver_data->gicd_base);
assert(plat_driver_data->gicc_base);
- /*
- * The platform should provide a list of atleast one type of
- * interrupts
- */
- assert(plat_driver_data->g0_interrupt_array);
-
- /*
- * If there are no interrupts of a particular type, then the number of
- * interrupts of that type should be 0 and vice-versa.
- */
- assert(plat_driver_data->g0_interrupt_array ?
- plat_driver_data->g0_interrupt_num :
- plat_driver_data->g0_interrupt_num == 0);
+#if !ERROR_DEPRECATED
+ if (plat_driver_data->interrupt_props == NULL) {
+ /* Interrupt properties array size must be 0 */
+ assert(plat_driver_data->interrupt_props_num == 0);
+
+ /* The platform should provide a list of secure interrupts */
+ assert(plat_driver_data->g0_interrupt_array);
+
+ /*
+ * If there are no interrupts of a particular type, then the
+ * number of interrupts of that type should be 0 and vice-versa.
+ */
+ assert(plat_driver_data->g0_interrupt_array ?
+ plat_driver_data->g0_interrupt_num :
+ plat_driver_data->g0_interrupt_num == 0);
+ }
+#else
+ assert(plat_driver_data->interrupt_props != NULL);
+ assert(plat_driver_data->interrupt_props_num > 0);
+#endif
/* Ensure that this is a GICv2 system */
gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT)
& PIDR2_ARCH_REV_MASK;
- assert(gic_version == ARCH_REV_GICV2);
+
+ /*
+ * GICv1 with security extension complies with trusted firmware
+ * GICv2 driver as far as virtualization and few tricky power
+ * features are not used. GICv2 features that are not supported
+ * by GICv1 with Security Extensions are:
+ * - virtual interrupt support.
+ * - wake up events.
+ * - writeable GIC state register (for power sequences)
+ * - interrupt priority drop.
+ * - interrupt signal bypass.
+ */
+ assert(gic_version == ARCH_REV_GICV2 || gic_version == ARCH_REV_GICV1);
driver_data = plat_driver_data;
@@ -240,3 +298,272 @@ unsigned int gicv2_get_interrupt_group(unsigned int id)
return gicd_get_igroupr(driver_data->gicd_base, id);
}
+
+/*******************************************************************************
+ * This function returns the priority of the interrupt the processor is
+ * currently servicing.
+ ******************************************************************************/
+unsigned int gicv2_get_running_priority(void)
+{
+ assert(driver_data);
+ assert(driver_data->gicc_base);
+
+ return gicc_read_rpr(driver_data->gicc_base);
+}
+
+/*******************************************************************************
+ * This function sets the GICv2 target mask pattern for the current PE. The PE
+ * target mask is used to translate linear PE index (returned by platform core
+ * position) to a bit mask used when targeting interrupts to a PE, viz. when
+ * raising SGIs and routing SPIs.
+ ******************************************************************************/
+void gicv2_set_pe_target_mask(unsigned int proc_num)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+ assert(driver_data->target_masks);
+ assert(proc_num < GICV2_MAX_TARGET_PE);
+ assert(proc_num < driver_data->target_masks_num);
+
+ /* Return if the target mask is already populated */
+ if (driver_data->target_masks[proc_num])
+ return;
+
+ /*
+ * Update target register corresponding to this CPU and flush for it to
+ * be visible to other CPUs.
+ */
+ if (driver_data->target_masks[proc_num] == 0) {
+ driver_data->target_masks[proc_num] =
+ gicv2_get_cpuif_id(driver_data->gicd_base);
+#if !HW_ASSISTED_COHERENCY
+ /*
+ * PEs only update their own masks. Primary updates it with
+ * caches on. But because secondaries does it with caches off,
+ * all updates go to memory directly, and there's no danger of
+ * secondaries overwriting each others' mask, despite
+ * target_masks[] not being cache line aligned.
+ */
+ flush_dcache_range((uintptr_t)
+ &driver_data->target_masks[proc_num],
+ sizeof(driver_data->target_masks[proc_num]));
+#endif
+ }
+}
+
+/*******************************************************************************
+ * This function returns the active status of the interrupt (either because the
+ * state is active, or active and pending).
+ ******************************************************************************/
+unsigned int gicv2_get_interrupt_active(unsigned int id)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+ assert(id <= MAX_SPI_ID);
+
+ return gicd_get_isactiver(driver_data->gicd_base, id);
+}
+
+/*******************************************************************************
+ * This function enables the interrupt identified by id.
+ ******************************************************************************/
+void gicv2_enable_interrupt(unsigned int id)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+ assert(id <= MAX_SPI_ID);
+
+ /*
+ * Ensure that any shared variable updates depending on out of band
+ * interrupt trigger are observed before enabling interrupt.
+ */
+ dsbishst();
+ gicd_set_isenabler(driver_data->gicd_base, id);
+}
+
+/*******************************************************************************
+ * This function disables the interrupt identified by id.
+ ******************************************************************************/
+void gicv2_disable_interrupt(unsigned int id)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+ assert(id <= MAX_SPI_ID);
+
+ /*
+ * Disable interrupt, and ensure that any shared variable updates
+ * depending on out of band interrupt trigger are observed afterwards.
+ */
+ gicd_set_icenabler(driver_data->gicd_base, id);
+ dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the interrupt priority as supplied for the given interrupt
+ * id.
+ ******************************************************************************/
+void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+ assert(id <= MAX_SPI_ID);
+
+ gicd_set_ipriorityr(driver_data->gicd_base, id, priority);
+}
+
+/*******************************************************************************
+ * This function assigns group for the interrupt identified by id. The group can
+ * be any of GICV2_INTR_GROUP*
+ ******************************************************************************/
+void gicv2_set_interrupt_type(unsigned int id, unsigned int type)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+ assert(id <= MAX_SPI_ID);
+
+ /* Serialize read-modify-write to Distributor registers */
+ spin_lock(&gic_lock);
+ switch (type) {
+ case GICV2_INTR_GROUP1:
+ gicd_set_igroupr(driver_data->gicd_base, id);
+ break;
+ case GICV2_INTR_GROUP0:
+ gicd_clr_igroupr(driver_data->gicd_base, id);
+ break;
+ default:
+ assert(0);
+ }
+ spin_unlock(&gic_lock);
+}
+
+/*******************************************************************************
+ * This function raises the specified SGI to requested targets.
+ *
+ * The proc_num parameter must be the linear index of the target PE in the
+ * system.
+ ******************************************************************************/
+void gicv2_raise_sgi(int sgi_num, int proc_num)
+{
+ unsigned int sgir_val, target;
+
+ assert(driver_data);
+ assert(proc_num < GICV2_MAX_TARGET_PE);
+ assert(driver_data->gicd_base);
+
+ /*
+ * Target masks array must have been supplied, and the core position
+ * should be valid.
+ */
+ assert(driver_data->target_masks);
+ assert(proc_num < driver_data->target_masks_num);
+
+ /* Don't raise SGI if the mask hasn't been populated */
+ target = driver_data->target_masks[proc_num];
+ assert(target != 0);
+
+ sgir_val = GICV2_SGIR_VALUE(SGIR_TGT_SPECIFIC, target, sgi_num);
+
+ /*
+ * Ensure that any shared variable updates depending on out of band
+ * interrupt trigger are observed before raising SGI.
+ */
+ dsbishst();
+ gicd_write_sgir(driver_data->gicd_base, sgir_val);
+}
+
+/*******************************************************************************
+ * This function sets the interrupt routing for the given SPI interrupt id.
+ * The interrupt routing is specified in routing mode. The proc_num parameter is
+ * linear index of the PE to target SPI. When proc_num < 0, the SPI may target
+ * all PEs.
+ ******************************************************************************/
+void gicv2_set_spi_routing(unsigned int id, int proc_num)
+{
+ int target;
+
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+
+ assert(id >= MIN_SPI_ID && id <= MAX_SPI_ID);
+
+ /*
+ * Target masks array must have been supplied, and the core position
+ * should be valid.
+ */
+ assert(driver_data->target_masks);
+ assert(proc_num < GICV2_MAX_TARGET_PE);
+ assert(proc_num < driver_data->target_masks_num);
+
+ if (proc_num < 0) {
+ /* Target all PEs */
+ target = GIC_TARGET_CPU_MASK;
+ } else {
+ /* Don't route interrupt if the mask hasn't been populated */
+ target = driver_data->target_masks[proc_num];
+ assert(target != 0);
+ }
+
+ gicd_set_itargetsr(driver_data->gicd_base, id, target);
+}
+
+/*******************************************************************************
+ * This function clears the pending status of an interrupt identified by id.
+ ******************************************************************************/
+void gicv2_clear_interrupt_pending(unsigned int id)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+
+ /* SGIs can't be cleared pending */
+ assert(id >= MIN_PPI_ID);
+
+ /*
+ * Clear pending interrupt, and ensure that any shared variable updates
+ * depending on out of band interrupt trigger are observed afterwards.
+ */
+ gicd_set_icpendr(driver_data->gicd_base, id);
+ dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the pending status of an interrupt identified by id.
+ ******************************************************************************/
+void gicv2_set_interrupt_pending(unsigned int id)
+{
+ assert(driver_data);
+ assert(driver_data->gicd_base);
+
+ /* SGIs can't be cleared pending */
+ assert(id >= MIN_PPI_ID);
+
+ /*
+ * Ensure that any shared variable updates depending on out of band
+ * interrupt trigger are observed before setting interrupt pending.
+ */
+ dsbishst();
+ gicd_set_ispendr(driver_data->gicd_base, id);
+}
+
+/*******************************************************************************
+ * This function sets the PMR register with the supplied value. Returns the
+ * original PMR.
+ ******************************************************************************/
+unsigned int gicv2_set_pmr(unsigned int mask)
+{
+ unsigned int old_mask;
+
+ assert(driver_data);
+ assert(driver_data->gicc_base);
+
+ old_mask = gicc_read_pmr(driver_data->gicc_base);
+
+ /*
+ * Order memory updates w.r.t. PMR write, and ensure they're visible
+ * before potential out of band interrupt trigger because of PMR update.
+ */
+ dmbishst();
+ gicc_write_pmr(driver_data->gicc_base, mask);
+ dsbishst();
+
+ return old_mask;
+}
diff --git a/drivers/arm/gic/v2/gicv2_private.h b/drivers/arm/gic/v2/gicv2_private.h
index 91ab43a2..25600deb 100644
--- a/drivers/arm/gic/v2/gicv2_private.h
+++ b/drivers/arm/gic/v2/gicv2_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,12 +15,20 @@
* Private function prototypes
******************************************************************************/
void gicv2_spis_configure_defaults(uintptr_t gicd_base);
+#if !ERROR_DEPRECATED
void gicv2_secure_spis_configure(uintptr_t gicd_base,
unsigned int num_ints,
const unsigned int *sec_intr_list);
void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
unsigned int num_ints,
const unsigned int *sec_intr_list);
+#endif
+void gicv2_secure_spis_configure_props(uintptr_t gicd_base,
+ const interrupt_prop_t *interrupt_props,
+ unsigned int interrupt_props_num);
+void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base,
+ const interrupt_prop_t *interrupt_props,
+ unsigned int interrupt_props_num);
unsigned int gicv2_get_cpuif_id(uintptr_t base);
/*******************************************************************************
@@ -32,6 +40,25 @@ static inline unsigned int gicd_read_pidr2(uintptr_t base)
}
/*******************************************************************************
+ * GIC Distributor interface accessors for writing entire registers
+ ******************************************************************************/
+static inline unsigned int gicd_get_itargetsr(uintptr_t base, unsigned int id)
+{
+ return mmio_read_8(base + GICD_ITARGETSR + id);
+}
+
+static inline void gicd_set_itargetsr(uintptr_t base, unsigned int id,
+ unsigned int target)
+{
+ mmio_write_8(base + GICD_ITARGETSR + id, target & GIC_TARGET_CPU_MASK);
+}
+
+static inline void gicd_write_sgir(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICD_SGIR, val);
+}
+
+/*******************************************************************************
* GIC CPU interface accessors for reading entire registers
******************************************************************************/
@@ -80,6 +107,11 @@ static inline unsigned int gicc_read_iidr(uintptr_t base)
return mmio_read_32(base + GICC_IIDR);
}
+static inline unsigned int gicc_read_rpr(uintptr_t base)
+{
+ return mmio_read_32(base + GICC_RPR);
+}
+
/*******************************************************************************
* GIC CPU interface accessors for writing entire registers
******************************************************************************/
diff --git a/drivers/arm/gic/v3/arm_gicv3_common.c b/drivers/arm/gic/v3/arm_gicv3_common.c
new file mode 100644
index 00000000..8d552ca5
--- /dev/null
+++ b/drivers/arm/gic/v3/arm_gicv3_common.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for implementation defined features that are identical in ARM GICv3
+* implementations (GIC-500 and GIC-600 for now). This driver only overrides
+* APIs that are different to those generic ones in GICv3 driver.
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <gicv3.h>
+
+#include "gicv3_private.h"
+#include "arm_gicv3_common.h"
+
+/*
+ * Flush the internal GIC cache of the LPIs pending tables to memory before
+ * saving the state of the Redistributor. This is required before powering off
+ * the GIC when the pending status must be preserved.
+ * `rdist_proc_num` is the processor number corresponding to the Redistributor of the
+ * current CPU.
+ */
+void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num)
+{
+ uintptr_t gicr_base = 0;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+
+ /*
+ * The GICR_WAKER.Sleep bit should be set only when both
+ * GICR_WAKER.ChildrenAsleep and GICR_WAKER.ProcessorSleep are set on
+ * all the Redistributors.
+ */
+ for (unsigned int i = 0; i < gicv3_driver_data->rdistif_num; i++) {
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[i];
+ assert(gicr_base);
+ assert(gicr_read_waker(gicr_base) & WAKER_CA_BIT);
+ assert(gicr_read_waker(gicr_base) & WAKER_PS_BIT);
+ }
+
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num];
+ /*
+ * According to the TRM, there is only one instance of the
+ * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed
+ * through any of the Redistributor.
+ */
+
+ /*
+ * Set GICR_WAKER.Sleep
+ * After this point, the system must be configured so that the
+ * wake_request signals for the right cores are asserted when a wakeup
+ * interrupt is detected. The GIC will not be able to do that anymore
+ * when the GICR_WAKER.Sleep bit is set to 1.
+ */
+ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_SL_BIT);
+
+ /* Wait until the GICR_WAKER.Quiescent bit is set */
+ while (!(gicr_read_waker(gicr_base) & WAKER_QSC_BIT))
+ ;
+}
+
+/*
+ * Allow the LPIs pending state to be read back from the tables in memory after
+ * having restored the state of the GIC Redistributor.
+ */
+void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num)
+{
+ uintptr_t gicr_base;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+
+ /*
+ * According to the TRM, there is only one instance of the
+ * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed
+ * through any of the Redistributor.
+ */
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num];
+ assert(gicr_base);
+
+ /*
+ * Writes to GICR_WAKER.Sleep bit are ignored if GICR_WAKER.Quiescent
+ * bit is not set. We should be alright on power on path, therefore
+ * coming out of sleep and Quiescent should be set, but we assert in
+ * case.
+ */
+ assert(gicr_read_waker(gicr_base) & WAKER_QSC_BIT);
+
+ /* Clear GICR_WAKER.Sleep */
+ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_SL_BIT);
+
+ /*
+ * We don't know if the effects of setting GICR_WAKER.Sleep bit is
+ * instantaneous, so we wait until the interface is not Quiescent
+ * anymore.
+ */
+ while (gicr_read_waker(gicr_base) & WAKER_QSC_BIT)
+ ;
+}
+
diff --git a/drivers/arm/gic/v3/gic500.c b/drivers/arm/gic/v3/gic500.c
new file mode 100644
index 00000000..f03e33f8
--- /dev/null
+++ b/drivers/arm/gic/v3/gic500.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for GIC500-specific features. This driver only overrides APIs that are
+ * different to those generic ones in GICv3 driver.
+ */
+#include "gicv3_private.h"
+
+void gicv3_distif_pre_save(unsigned int proc_num)
+{
+ arm_gicv3_distif_pre_save(proc_num);
+}
+
+void gicv3_distif_post_restore(unsigned int proc_num)
+{
+ arm_gicv3_distif_post_restore(proc_num);
+}
+
diff --git a/drivers/arm/gic/v3/gic600.c b/drivers/arm/gic/v3/gic600.c
index 4ea31ab1..eb4fc548 100644
--- a/drivers/arm/gic/v3/gic600.c
+++ b/drivers/arm/gic/v3/gic600.c
@@ -18,32 +18,29 @@
#include "gicv3_private.h"
/* GIC600-specific register offsets */
-#define GICR_PWRR 0x24
+#define GICR_PWRR 0x24
/* GICR_PWRR fields */
#define PWRR_RDPD_SHIFT 0
#define PWRR_RDGPD_SHIFT 2
#define PWRR_RDGPO_SHIFT 3
-#define PWRR_RDGPD (1 << PWRR_RDGPD_SHIFT)
-#define PWRR_RDGPO (1 << PWRR_RDGPO_SHIFT)
+#define PWRR_RDGPD (1 << PWRR_RDGPD_SHIFT)
+#define PWRR_RDGPO (1 << PWRR_RDGPO_SHIFT)
/* Values to write to GICR_PWRR register to power redistributor */
-#define PWRR_ON (0 << PWRR_RDPD_SHIFT)
-#define PWRR_OFF (1 << PWRR_RDPD_SHIFT)
-
-/* Generic GICv3 resources */
-extern const gicv3_driver_data_t *gicv3_driver_data;
+#define PWRR_ON (0 << PWRR_RDPD_SHIFT)
+#define PWRR_OFF (1 << PWRR_RDPD_SHIFT)
/* GIC600-specific accessor functions */
static void gicr_write_pwrr(uintptr_t base, unsigned int val)
{
- mmio_write_32(base + GICR_PWRR, val);
+ mmio_write_32(base + GICR_PWRR, val);
}
static uint32_t gicr_read_pwrr(uintptr_t base)
{
- return mmio_read_32(base + GICR_PWRR);
+ return mmio_read_32(base + GICR_PWRR);
}
static int gicr_group_powering_down(uint32_t pwrr)
@@ -82,6 +79,16 @@ static void gic600_pwr_off(uintptr_t base)
}
}
+void gicv3_distif_pre_save(unsigned int proc_num)
+{
+ arm_gicv3_distif_pre_save(proc_num);
+}
+
+void gicv3_distif_post_restore(unsigned int proc_num)
+{
+ arm_gicv3_distif_post_restore(proc_num);
+}
+
/*
* Power off GIC600 redistributor
*/
diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c
index 73ad060f..dee63f18 100644
--- a/drivers/arm/gic/v3/gicv3_helpers.c
+++ b/drivers/arm/gic/v3/gicv3_helpers.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,6 +9,7 @@
#include <assert.h>
#include <debug.h>
#include <gic_common.h>
+#include <interrupt_props.h>
#include "../common/gic_common_private.h"
#include "gicv3_private.h"
@@ -172,6 +173,51 @@ void gicr_set_isenabler0(uintptr_t base, unsigned int id)
}
/*
+ * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
+ * ICENABLER0.
+ */
+void gicr_set_icenabler0(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << ICENABLER_SHIFT) - 1);
+
+ gicr_write_icenabler0(base, (1 << bit_num));
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
+ * ISACTIVER0.
+ */
+unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1);
+ unsigned int reg_val = gicr_read_isactiver0(base);
+
+ return (reg_val >> bit_num) & 0x1;
+}
+
+/*
+ * Accessor to clear the bit corresponding to interrupt ID in GIC Re-distributor
+ * ICPENDRR0.
+ */
+void gicr_set_icpendr0(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << ICPENDR_SHIFT) - 1);
+
+ gicr_write_icpendr0(base, (1 << bit_num));
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
+ * ISPENDR0.
+ */
+void gicr_set_ispendr0(uintptr_t base, unsigned int id)
+{
+ unsigned bit_num = id & ((1 << ISPENDR_SHIFT) - 1);
+
+ gicr_write_ispendr0(base, (1 << bit_num));
+}
+
+/*
* Accessor to set the byte corresponding to interrupt ID
* in GIC Re-distributor IPRIORITYR.
*/
@@ -180,6 +226,38 @@ void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
mmio_write_8(base + GICR_IPRIORITYR + id, pri & GIC_PRI_MASK);
}
+/*
+ * Accessor to set the bit fields corresponding to interrupt ID
+ * in GIC Re-distributor ICFGR0.
+ */
+void gicr_set_icfgr0(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+ unsigned bit_num = id & ((1 << ICFGR_SHIFT) - 1);
+ uint32_t reg_val = gicr_read_icfgr0(base);
+
+ /* Clear the field, and insert required configuration */
+ reg_val &= ~(GIC_CFG_MASK << bit_num);
+ reg_val |= ((cfg & GIC_CFG_MASK) << bit_num);
+
+ gicr_write_icfgr0(base, reg_val);
+}
+
+/*
+ * Accessor to set the bit fields corresponding to interrupt ID
+ * in GIC Re-distributor ICFGR1.
+ */
+void gicr_set_icfgr1(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+ unsigned bit_num = id & ((1 << ICFGR_SHIFT) - 1);
+ uint32_t reg_val = gicr_read_icfgr1(base);
+
+ /* Clear the field, and insert required configuration */
+ reg_val &= ~(GIC_CFG_MASK << bit_num);
+ reg_val |= ((cfg & GIC_CFG_MASK) << bit_num);
+
+ gicr_write_icfgr1(base, reg_val);
+}
+
/******************************************************************************
* This function marks the core as awake in the re-distributor and
* ensures that the interface is active.
@@ -287,6 +365,7 @@ void gicv3_spis_configure_defaults(uintptr_t gicd_base)
gicd_write_icfgr(gicd_base, index, 0);
}
+#if !ERROR_DEPRECATED
/*******************************************************************************
* Helper function to configure secure G0 and G1S SPIs.
******************************************************************************/
@@ -333,6 +412,63 @@ void gicv3_secure_spis_configure(uintptr_t gicd_base,
}
}
+#endif
+
+/*******************************************************************************
+ * Helper function to configure properties of secure SPIs
+ ******************************************************************************/
+unsigned int gicv3_secure_spis_configure_props(uintptr_t gicd_base,
+ const interrupt_prop_t *interrupt_props,
+ unsigned int interrupt_props_num)
+{
+ unsigned int i;
+ const interrupt_prop_t *current_prop;
+ unsigned long long gic_affinity_val;
+ unsigned int ctlr_enable = 0;
+
+ /* Make sure there's a valid property array */
+ assert(interrupt_props != NULL);
+ assert(interrupt_props_num > 0);
+
+ for (i = 0; i < interrupt_props_num; i++) {
+ current_prop = &interrupt_props[i];
+
+ if (current_prop->intr_num < MIN_SPI_ID)
+ continue;
+
+ /* Configure this interrupt as a secure interrupt */
+ gicd_clr_igroupr(gicd_base, current_prop->intr_num);
+
+ /* Configure this interrupt as G0 or a G1S interrupt */
+ assert((current_prop->intr_grp == INTR_GROUP0) ||
+ (current_prop->intr_grp == INTR_GROUP1S));
+ if (current_prop->intr_grp == INTR_GROUP1S) {
+ gicd_set_igrpmodr(gicd_base, current_prop->intr_num);
+ ctlr_enable |= CTLR_ENABLE_G1S_BIT;
+ } else {
+ gicd_clr_igrpmodr(gicd_base, current_prop->intr_num);
+ ctlr_enable |= CTLR_ENABLE_G0_BIT;
+ }
+
+ /* Set interrupt configuration */
+ gicd_set_icfgr(gicd_base, current_prop->intr_num,
+ current_prop->intr_cfg);
+
+ /* Set the priority of this interrupt */
+ gicd_set_ipriorityr(gicd_base, current_prop->intr_num,
+ current_prop->intr_pri);
+
+ /* Target SPIs to the primary CPU */
+ gic_affinity_val = gicd_irouter_val_from_mpidr(read_mpidr(), 0);
+ gicd_write_irouter(gicd_base, current_prop->intr_num,
+ gic_affinity_val);
+
+ /* Enable this interrupt */
+ gicd_set_isenabler(gicd_base, current_prop->intr_num);
+ }
+
+ return ctlr_enable;
+}
/*******************************************************************************
* Helper function to configure the default attributes of SPIs.
@@ -362,6 +498,7 @@ void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base)
gicr_write_icfgr1(gicr_base, 0);
}
+#if !ERROR_DEPRECATED
/*******************************************************************************
* Helper function to configure secure G0 and G1S SPIs.
******************************************************************************/
@@ -399,3 +536,60 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
}
}
}
+#endif
+
+/*******************************************************************************
+ * Helper function to configure properties of secure G0 and G1S PPIs and SGIs.
+ ******************************************************************************/
+unsigned int gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base,
+ const interrupt_prop_t *interrupt_props,
+ unsigned int interrupt_props_num)
+{
+ unsigned int i;
+ const interrupt_prop_t *current_prop;
+ unsigned int ctlr_enable = 0;
+
+ /* Make sure there's a valid property array */
+ assert(interrupt_props != NULL);
+ assert(interrupt_props_num > 0);
+
+ for (i = 0; i < interrupt_props_num; i++) {
+ current_prop = &interrupt_props[i];
+
+ if (current_prop->intr_num >= MIN_SPI_ID)
+ continue;
+
+ /* Configure this interrupt as a secure interrupt */
+ gicr_clr_igroupr0(gicr_base, current_prop->intr_num);
+
+ /* Configure this interrupt as G0 or a G1S interrupt */
+ assert((current_prop->intr_grp == INTR_GROUP0) ||
+ (current_prop->intr_grp == INTR_GROUP1S));
+ if (current_prop->intr_grp == INTR_GROUP1S) {
+ gicr_set_igrpmodr0(gicr_base, current_prop->intr_num);
+ ctlr_enable |= CTLR_ENABLE_G1S_BIT;
+ } else {
+ gicr_clr_igrpmodr0(gicr_base, current_prop->intr_num);
+ ctlr_enable |= CTLR_ENABLE_G0_BIT;
+ }
+
+ /* Set the priority of this interrupt */
+ gicr_set_ipriorityr(gicr_base, current_prop->intr_num,
+ current_prop->intr_pri);
+
+ /*
+ * Set interrupt configuration for PPIs. Configuration for SGIs
+ * are ignored.
+ */
+ if ((current_prop->intr_num >= MIN_PPI_ID) &&
+ (current_prop->intr_num < MIN_SPI_ID)) {
+ gicr_set_icfgr1(gicr_base, current_prop->intr_num,
+ current_prop->intr_cfg);
+ }
+
+ /* Enable this interrupt */
+ gicr_set_isenabler0(gicr_base, current_prop->intr_num);
+ }
+
+ return ctlr_enable;
+}
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index b68d9988..8de5be3f 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -9,18 +9,48 @@
#include <assert.h>
#include <debug.h>
#include <gicv3.h>
+#include <interrupt_props.h>
+#include <spinlock.h>
#include "gicv3_private.h"
const gicv3_driver_data_t *gicv3_driver_data;
static unsigned int gicv2_compat;
/*
+ * Spinlock to guard registers needing read-modify-write. APIs protected by this
+ * spinlock are used either at boot time (when only a single CPU is active), or
+ * when the system is fully coherent.
+ */
+spinlock_t gic_lock;
+
+/*
* Redistributor power operations are weakly bound so that they can be
* overridden
*/
#pragma weak gicv3_rdistif_off
#pragma weak gicv3_rdistif_on
+
+/* Helper macros to save and restore GICD registers to and from the context */
+#define RESTORE_GICD_REGS(base, ctx, intr_num, reg, REG) \
+ do { \
+ for (unsigned int int_id = MIN_SPI_ID; int_id < intr_num; \
+ int_id += (1 << REG##_SHIFT)) { \
+ gicd_write_##reg(base, int_id, \
+ ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT]); \
+ } \
+ } while (0)
+
+#define SAVE_GICD_REGS(base, ctx, intr_num, reg, REG) \
+ do { \
+ for (unsigned int int_id = MIN_SPI_ID; int_id < intr_num; \
+ int_id += (1 << REG##_SHIFT)) { \
+ ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT] =\
+ gicd_read_##reg(base, int_id); \
+ } \
+ } while (0)
+
+
/*******************************************************************************
* This function initialises the ARM GICv3 driver in EL3 with provided platform
* inputs.
@@ -37,23 +67,33 @@ void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
assert(IS_IN_EL3());
- /*
- * The platform should provide a list of at least one type of
- * interrupts
- */
- assert(plat_driver_data->g0_interrupt_array ||
- plat_driver_data->g1s_interrupt_array);
-
- /*
- * If there are no interrupts of a particular type, then the number of
- * interrupts of that type should be 0 and vice-versa.
- */
- assert(plat_driver_data->g0_interrupt_array ?
- plat_driver_data->g0_interrupt_num :
- plat_driver_data->g0_interrupt_num == 0);
- assert(plat_driver_data->g1s_interrupt_array ?
- plat_driver_data->g1s_interrupt_num :
- plat_driver_data->g1s_interrupt_num == 0);
+#if !ERROR_DEPRECATED
+ if (plat_driver_data->interrupt_props == NULL) {
+ /* Interrupt properties array size must be 0 */
+ assert(plat_driver_data->interrupt_props_num == 0);
+
+ /*
+ * The platform should provide a list of at least one type of
+ * interrupt.
+ */
+ assert(plat_driver_data->g0_interrupt_array ||
+ plat_driver_data->g1s_interrupt_array);
+
+ /*
+ * If there are no interrupts of a particular type, then the
+ * number of interrupts of that type should be 0 and vice-versa.
+ */
+ assert(plat_driver_data->g0_interrupt_array ?
+ plat_driver_data->g0_interrupt_num :
+ plat_driver_data->g0_interrupt_num == 0);
+ assert(plat_driver_data->g1s_interrupt_array ?
+ plat_driver_data->g1s_interrupt_num :
+ plat_driver_data->g1s_interrupt_num == 0);
+ }
+#else
+ assert(plat_driver_data->interrupt_props != NULL);
+ assert(plat_driver_data->interrupt_props_num > 0);
+#endif
/* Check for system register support */
#ifdef AARCH32
@@ -119,8 +159,6 @@ void gicv3_distif_init(void)
assert(gicv3_driver_data);
assert(gicv3_driver_data->gicd_base);
- assert(gicv3_driver_data->g1s_interrupt_array ||
- gicv3_driver_data->g0_interrupt_array);
assert(IS_IN_EL3());
@@ -142,23 +180,37 @@ void gicv3_distif_init(void)
/* Set the default attribute of all SPIs */
gicv3_spis_configure_defaults(gicv3_driver_data->gicd_base);
- /* Configure the G1S SPIs */
- if (gicv3_driver_data->g1s_interrupt_array) {
- gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
+#if !ERROR_DEPRECATED
+ if (gicv3_driver_data->interrupt_props != NULL) {
+#endif
+ bitmap = gicv3_secure_spis_configure_props(
+ gicv3_driver_data->gicd_base,
+ gicv3_driver_data->interrupt_props,
+ gicv3_driver_data->interrupt_props_num);
+#if !ERROR_DEPRECATED
+ } else {
+ assert(gicv3_driver_data->g1s_interrupt_array ||
+ gicv3_driver_data->g0_interrupt_array);
+
+ /* Configure the G1S SPIs */
+ if (gicv3_driver_data->g1s_interrupt_array) {
+ gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
gicv3_driver_data->g1s_interrupt_num,
gicv3_driver_data->g1s_interrupt_array,
INTR_GROUP1S);
- bitmap |= CTLR_ENABLE_G1S_BIT;
- }
+ bitmap |= CTLR_ENABLE_G1S_BIT;
+ }
- /* Configure the G0 SPIs */
- if (gicv3_driver_data->g0_interrupt_array) {
- gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
+ /* Configure the G0 SPIs */
+ if (gicv3_driver_data->g0_interrupt_array) {
+ gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
gicv3_driver_data->g0_interrupt_num,
gicv3_driver_data->g0_interrupt_array,
INTR_GROUP0);
- bitmap |= CTLR_ENABLE_G0_BIT;
+ bitmap |= CTLR_ENABLE_G0_BIT;
+ }
}
+#endif
/* Enable the secure SPIs now that they have been configured */
gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE);
@@ -172,14 +224,16 @@ void gicv3_distif_init(void)
void gicv3_rdistif_init(unsigned int proc_num)
{
uintptr_t gicr_base;
+ unsigned int bitmap = 0;
+ uint32_t ctlr;
assert(gicv3_driver_data);
assert(proc_num < gicv3_driver_data->rdistif_num);
assert(gicv3_driver_data->rdistif_base_addrs);
assert(gicv3_driver_data->gicd_base);
- assert(gicd_read_ctlr(gicv3_driver_data->gicd_base) & CTLR_ARE_S_BIT);
- assert(gicv3_driver_data->g1s_interrupt_array ||
- gicv3_driver_data->g0_interrupt_array);
+
+ ctlr = gicd_read_ctlr(gicv3_driver_data->gicd_base);
+ assert(ctlr & CTLR_ARE_S_BIT);
assert(IS_IN_EL3());
@@ -191,21 +245,40 @@ void gicv3_rdistif_init(unsigned int proc_num)
/* Set the default attribute of all SGIs and PPIs */
gicv3_ppi_sgi_configure_defaults(gicr_base);
- /* Configure the G1S SGIs/PPIs */
- if (gicv3_driver_data->g1s_interrupt_array) {
- gicv3_secure_ppi_sgi_configure(gicr_base,
+#if !ERROR_DEPRECATED
+ if (gicv3_driver_data->interrupt_props != NULL) {
+#endif
+ bitmap = gicv3_secure_ppi_sgi_configure_props(gicr_base,
+ gicv3_driver_data->interrupt_props,
+ gicv3_driver_data->interrupt_props_num);
+#if !ERROR_DEPRECATED
+ } else {
+ assert(gicv3_driver_data->g1s_interrupt_array ||
+ gicv3_driver_data->g0_interrupt_array);
+
+ /* Configure the G1S SGIs/PPIs */
+ if (gicv3_driver_data->g1s_interrupt_array) {
+ gicv3_secure_ppi_sgi_configure(gicr_base,
gicv3_driver_data->g1s_interrupt_num,
gicv3_driver_data->g1s_interrupt_array,
INTR_GROUP1S);
- }
+ bitmap |= CTLR_ENABLE_G1S_BIT;
+ }
- /* Configure the G0 SGIs/PPIs */
- if (gicv3_driver_data->g0_interrupt_array) {
- gicv3_secure_ppi_sgi_configure(gicr_base,
+ /* Configure the G0 SGIs/PPIs */
+ if (gicv3_driver_data->g0_interrupt_array) {
+ gicv3_secure_ppi_sgi_configure(gicr_base,
gicv3_driver_data->g0_interrupt_num,
gicv3_driver_data->g0_interrupt_array,
INTR_GROUP0);
+ bitmap |= CTLR_ENABLE_G0_BIT;
+ }
}
+#endif
+
+ /* Enable interrupt groups as required, if not already */
+ if ((ctlr & bitmap) != bitmap)
+ gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE);
}
/*******************************************************************************
@@ -406,3 +479,679 @@ unsigned int gicv3_get_interrupt_type(unsigned int id,
/* Else it is a Group 0 Secure interrupt */
return INTR_GROUP0;
}
+
+/*****************************************************************************
+ * Function to save and disable the GIC ITS register context. The power
+ * management of GIC ITS is implementation-defined and this function doesn't
+ * save any memory structures required to support ITS. As the sequence to save
+ * this state is implementation defined, it should be executed in platform
+ * specific code. Calling this function alone and then powering down the GIC and
+ * ITS without implementing the aforementioned platform specific code will
+ * corrupt the ITS state.
+ *
+ * This function must be invoked after the GIC CPU interface is disabled.
+ *****************************************************************************/
+void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx)
+{
+ int i;
+
+ assert(gicv3_driver_data);
+ assert(IS_IN_EL3());
+ assert(its_ctx);
+ assert(gits_base);
+
+ its_ctx->gits_ctlr = gits_read_ctlr(gits_base);
+
+ /* Disable the ITS */
+ gits_write_ctlr(gits_base, its_ctx->gits_ctlr &
+ (~GITS_CTLR_ENABLED_BIT));
+
+ /* Wait for quiescent state */
+ gits_wait_for_quiescent_bit(gits_base);
+
+ its_ctx->gits_cbaser = gits_read_cbaser(gits_base);
+ its_ctx->gits_cwriter = gits_read_cwriter(gits_base);
+
+ for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++)
+ its_ctx->gits_baser[i] = gits_read_baser(gits_base, i);
+}
+
+/*****************************************************************************
+ * Function to restore the GIC ITS register context. The power
+ * management of GIC ITS is implementation defined and this function doesn't
+ * restore any memory structures required to support ITS. The assumption is
+ * that these structures are in memory and are retained during system suspend.
+ *
+ * This must be invoked before the GIC CPU interface is enabled.
+ *****************************************************************************/
+void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx)
+{
+ int i;
+
+ assert(gicv3_driver_data);
+ assert(IS_IN_EL3());
+ assert(its_ctx);
+ assert(gits_base);
+
+ /* Assert that the GITS is disabled and quiescent */
+ assert((gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT) == 0);
+ assert((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) != 0);
+
+ gits_write_cbaser(gits_base, its_ctx->gits_cbaser);
+ gits_write_cwriter(gits_base, its_ctx->gits_cwriter);
+
+ for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++)
+ gits_write_baser(gits_base, i, its_ctx->gits_baser[i]);
+
+ /* Restore the ITS CTLR but leave the ITS disabled */
+ gits_write_ctlr(gits_base, its_ctx->gits_ctlr &
+ (~GITS_CTLR_ENABLED_BIT));
+}
+
+/*****************************************************************************
+ * Function to save the GIC Redistributor register context. This function
+ * must be invoked after CPU interface disable and prior to Distributor save.
+ *****************************************************************************/
+void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx)
+{
+ uintptr_t gicr_base;
+ unsigned int int_id;
+
+ assert(gicv3_driver_data);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+ assert(IS_IN_EL3());
+ assert(rdist_ctx);
+
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+ /*
+ * Wait for any write to GICR_CTLR to complete before trying to save any
+ * state.
+ */
+ gicr_wait_for_pending_write(gicr_base);
+
+ rdist_ctx->gicr_ctlr = gicr_read_ctlr(gicr_base);
+
+ rdist_ctx->gicr_propbaser = gicr_read_propbaser(gicr_base);
+ rdist_ctx->gicr_pendbaser = gicr_read_pendbaser(gicr_base);
+
+ rdist_ctx->gicr_igroupr0 = gicr_read_igroupr0(gicr_base);
+ rdist_ctx->gicr_isenabler0 = gicr_read_isenabler0(gicr_base);
+ rdist_ctx->gicr_ispendr0 = gicr_read_ispendr0(gicr_base);
+ rdist_ctx->gicr_isactiver0 = gicr_read_isactiver0(gicr_base);
+ rdist_ctx->gicr_icfgr0 = gicr_read_icfgr0(gicr_base);
+ rdist_ctx->gicr_icfgr1 = gicr_read_icfgr1(gicr_base);
+ rdist_ctx->gicr_igrpmodr0 = gicr_read_igrpmodr0(gicr_base);
+ rdist_ctx->gicr_nsacr = gicr_read_nsacr(gicr_base);
+ for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM;
+ int_id += (1 << IPRIORITYR_SHIFT)) {
+ rdist_ctx->gicr_ipriorityr[(int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT] =
+ gicr_read_ipriorityr(gicr_base, int_id);
+ }
+
+
+ /*
+ * Call the pre-save hook that implements the IMP DEF sequence that may
+ * be required on some GIC implementations. As this may need to access
+ * the Redistributor registers, we pass it proc_num.
+ */
+ gicv3_distif_pre_save(proc_num);
+}
+
+/*****************************************************************************
+ * Function to restore the GIC Redistributor register context. We disable
+ * LPI and per-cpu interrupts before we start restore of the Redistributor.
+ * This function must be invoked after Distributor restore but prior to
+ * CPU interface enable. The pending and active interrupts are restored
+ * after the interrupts are fully configured and enabled.
+ *****************************************************************************/
+void gicv3_rdistif_init_restore(unsigned int proc_num,
+ const gicv3_redist_ctx_t * const rdist_ctx)
+{
+ uintptr_t gicr_base;
+ unsigned int int_id;
+
+ assert(gicv3_driver_data);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+ assert(IS_IN_EL3());
+ assert(rdist_ctx);
+
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+ /* Power on redistributor */
+ gicv3_rdistif_on(proc_num);
+
+ /*
+ * Call the post-restore hook that implements the IMP DEF sequence that
+ * may be required on some GIC implementations. As this may need to
+ * access the Redistributor registers, we pass it proc_num.
+ */
+ gicv3_distif_post_restore(proc_num);
+
+ /*
+ * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
+ * more scalable approach as it avoids clearing the enable bits in the
+ * GICD_CTLR
+ */
+ gicr_write_icenabler0(gicr_base, ~0);
+ /* Wait for pending writes to GICR_ICENABLER */
+ gicr_wait_for_pending_write(gicr_base);
+
+ /*
+ * Disable the LPIs to avoid unpredictable behavior when writing to
+ * GICR_PROPBASER and GICR_PENDBASER.
+ */
+ gicr_write_ctlr(gicr_base,
+ rdist_ctx->gicr_ctlr & ~(GICR_CTLR_EN_LPIS_BIT));
+
+ /* Restore registers' content */
+ gicr_write_propbaser(gicr_base, rdist_ctx->gicr_propbaser);
+ gicr_write_pendbaser(gicr_base, rdist_ctx->gicr_pendbaser);
+
+ gicr_write_igroupr0(gicr_base, rdist_ctx->gicr_igroupr0);
+
+ for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM;
+ int_id += (1 << IPRIORITYR_SHIFT)) {
+ gicr_write_ipriorityr(gicr_base, int_id,
+ rdist_ctx->gicr_ipriorityr[
+ (int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT]);
+ }
+
+ gicr_write_icfgr0(gicr_base, rdist_ctx->gicr_icfgr0);
+ gicr_write_icfgr1(gicr_base, rdist_ctx->gicr_icfgr1);
+ gicr_write_igrpmodr0(gicr_base, rdist_ctx->gicr_igrpmodr0);
+ gicr_write_nsacr(gicr_base, rdist_ctx->gicr_nsacr);
+
+ /* Restore after group and priorities are set */
+ gicr_write_ispendr0(gicr_base, rdist_ctx->gicr_ispendr0);
+ gicr_write_isactiver0(gicr_base, rdist_ctx->gicr_isactiver0);
+
+ /*
+ * Wait for all writes to the Distributor to complete before enabling
+ * the SGI and PPIs.
+ */
+ gicr_wait_for_upstream_pending_write(gicr_base);
+ gicr_write_isenabler0(gicr_base, rdist_ctx->gicr_isenabler0);
+
+ /*
+ * Restore GICR_CTLR.Enable_LPIs bit and wait for pending writes in case
+ * the first write to GICR_CTLR was still in flight (this write only
+ * restores GICR_CTLR.Enable_LPIs and no waiting is required for this
+ * bit).
+ */
+ gicr_write_ctlr(gicr_base, rdist_ctx->gicr_ctlr);
+ gicr_wait_for_pending_write(gicr_base);
+}
+
+/*****************************************************************************
+ * Function to save the GIC Distributor register context. This function
+ * must be invoked after CPU interface disable and Redistributor save.
+ *****************************************************************************/
+void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx)
+{
+ unsigned int num_ints;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(IS_IN_EL3());
+ assert(dist_ctx);
+
+ uintptr_t gicd_base = gicv3_driver_data->gicd_base;
+
+ num_ints = gicd_read_typer(gicd_base);
+ num_ints &= TYPER_IT_LINES_NO_MASK;
+ num_ints = (num_ints + 1) << 5;
+
+ assert(num_ints <= MAX_SPI_ID + 1);
+
+ /* Wait for pending write to complete */
+ gicd_wait_for_pending_write(gicd_base);
+
+ /* Save the GICD_CTLR */
+ dist_ctx->gicd_ctlr = gicd_read_ctlr(gicd_base);
+
+ /* Save GICD_IGROUPR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
+
+ /* Save GICD_ISENABLER for INT_IDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
+
+ /* Save GICD_ISPENDR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
+
+ /* Save GICD_ISACTIVER for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
+
+ /* Save GICD_IPRIORITYR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
+
+ /* Save GICD_ICFGR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
+
+ /* Save GICD_IGRPMODR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
+
+ /* Save GICD_NSACR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
+
+ /* Save GICD_IROUTER for INTIDs 32 - 1024 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
+
+ /*
+ * GICD_ITARGETSR<n> and GICD_SPENDSGIR<n> are RAZ/WI when
+ * GICD_CTLR.ARE_(S|NS) bits are set which is the case for our GICv3
+ * driver.
+ */
+}
+
+/*****************************************************************************
+ * Function to restore the GIC Distributor register context. We disable G0, G1S
+ * and G1NS interrupt groups before we start restore of the Distributor. This
+ * function must be invoked prior to Redistributor restore and CPU interface
+ * enable. The pending and active interrupts are restored after the interrupts
+ * are fully configured and enabled.
+ *****************************************************************************/
+void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx)
+{
+ unsigned int num_ints = 0;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(IS_IN_EL3());
+ assert(dist_ctx);
+
+ uintptr_t gicd_base = gicv3_driver_data->gicd_base;
+
+ /*
+ * Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring
+ * the ARE_S bit. The Distributor might generate a system error
+ * otherwise.
+ */
+ gicd_clr_ctlr(gicd_base,
+ CTLR_ENABLE_G0_BIT |
+ CTLR_ENABLE_G1S_BIT |
+ CTLR_ENABLE_G1NS_BIT,
+ RWP_TRUE);
+
+ /* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */
+ gicd_set_ctlr(gicd_base, CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
+
+ num_ints = gicd_read_typer(gicd_base);
+ num_ints &= TYPER_IT_LINES_NO_MASK;
+ num_ints = (num_ints + 1) << 5;
+
+ assert(num_ints <= MAX_SPI_ID + 1);
+
+ /* Restore GICD_IGROUPR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
+
+ /* Restore GICD_IPRIORITYR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
+
+ /* Restore GICD_ICFGR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
+
+ /* Restore GICD_IGRPMODR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
+
+ /* Restore GICD_NSACR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
+
+ /* Restore GICD_IROUTER for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
+
+ /*
+ * Restore ISENABLER, ISPENDR and ISACTIVER after the interrupts are
+ * configured.
+ */
+
+ /* Restore GICD_ISENABLER for INT_IDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
+
+ /* Restore GICD_ISPENDR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
+
+ /* Restore GICD_ISACTIVER for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
+
+ /* Restore the GICD_CTLR */
+ gicd_write_ctlr(gicd_base, dist_ctx->gicd_ctlr);
+ gicd_wait_for_pending_write(gicd_base);
+
+}
+
+/*******************************************************************************
+ * This function gets the priority of the interrupt the processor is currently
+ * servicing.
+ ******************************************************************************/
+unsigned int gicv3_get_running_priority(void)
+{
+ return read_icc_rpr_el1();
+}
+
+/*******************************************************************************
+ * This function checks if the interrupt identified by id is active (whether the
+ * state is either active, or active and pending). The proc_num is used if the
+ * interrupt is SGI or PPI and programs the corresponding Redistributor
+ * interface.
+ ******************************************************************************/
+unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num)
+{
+ unsigned int value;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+ assert(id <= MAX_SPI_ID);
+
+ if (id < MIN_SPI_ID) {
+ /* For SGIs and PPIs */
+ value = gicr_get_isactiver0(
+ gicv3_driver_data->rdistif_base_addrs[proc_num], id);
+ } else {
+ value = gicd_get_isactiver(gicv3_driver_data->gicd_base, id);
+ }
+
+ return value;
+}
+
+/*******************************************************************************
+ * This function enables the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface.
+ ******************************************************************************/
+void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num)
+{
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+ assert(id <= MAX_SPI_ID);
+
+ /*
+ * Ensure that any shared variable updates depending on out of band
+ * interrupt trigger are observed before enabling interrupt.
+ */
+ dsbishst();
+ if (id < MIN_SPI_ID) {
+ /* For SGIs and PPIs */
+ gicr_set_isenabler0(
+ gicv3_driver_data->rdistif_base_addrs[proc_num],
+ id);
+ } else {
+ gicd_set_isenabler(gicv3_driver_data->gicd_base, id);
+ }
+}
+
+/*******************************************************************************
+ * This function disables the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface.
+ ******************************************************************************/
+void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num)
+{
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+ assert(id <= MAX_SPI_ID);
+
+ /*
+ * Disable interrupt, and ensure that any shared variable updates
+ * depending on out of band interrupt trigger are observed afterwards.
+ */
+ if (id < MIN_SPI_ID) {
+ /* For SGIs and PPIs */
+ gicr_set_icenabler0(
+ gicv3_driver_data->rdistif_base_addrs[proc_num],
+ id);
+
+ /* Write to clear enable requires waiting for pending writes */
+ gicr_wait_for_pending_write(
+ gicv3_driver_data->rdistif_base_addrs[proc_num]);
+ } else {
+ gicd_set_icenabler(gicv3_driver_data->gicd_base, id);
+
+ /* Write to clear enable requires waiting for pending writes */
+ gicd_wait_for_pending_write(gicv3_driver_data->gicd_base);
+ }
+
+ dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the interrupt priority as supplied for the given interrupt
+ * id.
+ ******************************************************************************/
+void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
+ unsigned int priority)
+{
+ uintptr_t gicr_base;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+ assert(id <= MAX_SPI_ID);
+
+ if (id < MIN_SPI_ID) {
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ gicr_set_ipriorityr(gicr_base, id, priority);
+ } else {
+ gicd_set_ipriorityr(gicv3_driver_data->gicd_base, id, priority);
+ }
+}
+
+/*******************************************************************************
+ * This function assigns group for the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface. The group can be any of GICV3_INTR_GROUP*
+ ******************************************************************************/
+void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
+ unsigned int type)
+{
+ unsigned int igroup = 0, grpmod = 0;
+ uintptr_t gicr_base;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+
+ switch (type) {
+ case INTR_GROUP1S:
+ igroup = 0;
+ grpmod = 1;
+ break;
+ case INTR_GROUP0:
+ igroup = 0;
+ grpmod = 0;
+ break;
+ case INTR_GROUP1NS:
+ igroup = 1;
+ grpmod = 0;
+ break;
+ default:
+ assert(0);
+ }
+
+ if (id < MIN_SPI_ID) {
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ if (igroup)
+ gicr_set_igroupr0(gicr_base, id);
+ else
+ gicr_clr_igroupr0(gicr_base, id);
+
+ if (grpmod)
+ gicr_set_igrpmodr0(gicr_base, id);
+ else
+ gicr_clr_igrpmodr0(gicr_base, id);
+ } else {
+ /* Serialize read-modify-write to Distributor registers */
+ spin_lock(&gic_lock);
+ if (igroup)
+ gicd_set_igroupr(gicv3_driver_data->gicd_base, id);
+ else
+ gicd_clr_igroupr(gicv3_driver_data->gicd_base, id);
+
+ if (grpmod)
+ gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id);
+ else
+ gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id);
+ spin_unlock(&gic_lock);
+ }
+}
+
+/*******************************************************************************
+ * This function raises the specified Secure Group 0 SGI.
+ *
+ * The target parameter must be a valid MPIDR in the system.
+ ******************************************************************************/
+void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target)
+{
+ unsigned int tgt, aff3, aff2, aff1, aff0;
+ uint64_t sgi_val;
+
+ /* Verify interrupt number is in the SGI range */
+ assert((sgi_num >= MIN_SGI_ID) && (sgi_num < MIN_PPI_ID));
+
+ /* Extract affinity fields from target */
+ aff0 = MPIDR_AFFLVL0_VAL(target);
+ aff1 = MPIDR_AFFLVL1_VAL(target);
+ aff2 = MPIDR_AFFLVL2_VAL(target);
+ aff3 = MPIDR_AFFLVL3_VAL(target);
+
+ /*
+ * Make target list from affinity 0, and ensure GICv3 SGI can target
+ * this PE.
+ */
+ assert(aff0 < GICV3_MAX_SGI_TARGETS);
+ tgt = BIT(aff0);
+
+ /* Raise SGI to PE specified by its affinity */
+ sgi_val = GICV3_SGIR_VALUE(aff3, aff2, aff1, sgi_num, SGIR_IRM_TO_AFF,
+ tgt);
+
+ /*
+ * Ensure that any shared variable updates depending on out of band
+ * interrupt trigger are observed before raising SGI.
+ */
+ dsbishst();
+ write_icc_sgi0r_el1(sgi_val);
+ isb();
+}
+
+/*******************************************************************************
+ * This function sets the interrupt routing for the given SPI interrupt id.
+ * The interrupt routing is specified in routing mode and mpidr.
+ *
+ * The routing mode can be either of:
+ * - GICV3_IRM_ANY
+ * - GICV3_IRM_PE
+ *
+ * The mpidr is the affinity of the PE to which the interrupt will be routed,
+ * and is ignored for routing mode GICV3_IRM_ANY.
+ ******************************************************************************/
+void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr)
+{
+ unsigned long long aff;
+ uint64_t router;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+
+ assert((irm == GICV3_IRM_ANY) || (irm == GICV3_IRM_PE));
+ assert(id >= MIN_SPI_ID && id <= MAX_SPI_ID);
+
+ aff = gicd_irouter_val_from_mpidr(mpidr, irm);
+ gicd_write_irouter(gicv3_driver_data->gicd_base, id, aff);
+
+ /*
+ * In implementations that do not require 1 of N distribution of SPIs,
+ * IRM might be RAZ/WI. Read back and verify IRM bit.
+ */
+ if (irm == GICV3_IRM_ANY) {
+ router = gicd_read_irouter(gicv3_driver_data->gicd_base, id);
+ if (!((router >> IROUTER_IRM_SHIFT) & IROUTER_IRM_MASK)) {
+ ERROR("GICv3 implementation doesn't support routing ANY\n");
+ panic();
+ }
+ }
+}
+
+/*******************************************************************************
+ * This function clears the pending status of an interrupt identified by id.
+ * The proc_num is used if the interrupt is SGI or PPI, and programs the
+ * corresponding Redistributor interface.
+ ******************************************************************************/
+void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num)
+{
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+
+ /*
+ * Clear pending interrupt, and ensure that any shared variable updates
+ * depending on out of band interrupt trigger are observed afterwards.
+ */
+ if (id < MIN_SPI_ID) {
+ /* For SGIs and PPIs */
+ gicr_set_icpendr0(gicv3_driver_data->rdistif_base_addrs[proc_num],
+ id);
+ } else {
+ gicd_set_icpendr(gicv3_driver_data->gicd_base, id);
+ }
+ dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the pending status of an interrupt identified by id.
+ * The proc_num is used if the interrupt is SGI or PPI and programs the
+ * corresponding Redistributor interface.
+ ******************************************************************************/
+void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num)
+{
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+
+ /*
+ * Ensure that any shared variable updates depending on out of band
+ * interrupt trigger are observed before setting interrupt pending.
+ */
+ dsbishst();
+ if (id < MIN_SPI_ID) {
+ /* For SGIs and PPIs */
+ gicr_set_ispendr0(gicv3_driver_data->rdistif_base_addrs[proc_num],
+ id);
+ } else {
+ gicd_set_ispendr(gicv3_driver_data->gicd_base, id);
+ }
+}
+
+/*******************************************************************************
+ * This function sets the PMR register with the supplied value. Returns the
+ * original PMR.
+ ******************************************************************************/
+unsigned int gicv3_set_pmr(unsigned int mask)
+{
+ unsigned int old_mask;
+
+ old_mask = read_icc_pmr_el1();
+
+ /*
+ * Order memory updates w.r.t. PMR write, and ensure they're visible
+ * before potential out of band interrupt trigger because of PMR update.
+ * PMR system register writes are self-synchronizing, so no ISB required
+ * thereafter.
+ */
+ dsbishst();
+ write_icc_pmr_el1(mask);
+
+ return old_mask;
+}
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
index f95cfab6..52039074 100644
--- a/drivers/arm/gic/v3/gicv3_private.h
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -7,6 +7,7 @@
#ifndef __GICV3_PRIVATE_H__
#define __GICV3_PRIVATE_H__
+#include <assert.h>
#include <gic_common.h>
#include <gicv3.h>
#include <mmio.h>
@@ -22,17 +23,6 @@
#define RWP_FALSE 0
/*
- * Macro to wait for updates to :
- * GICD_CTLR[2:0] - the Group Enables
- * GICD_CTLR[5:4] - the ARE bits
- * GICD_ICENABLERn - the clearing of enable state for SPIs
- */
-#define gicd_wait_for_pending_write(gicd_base) \
- do { \
- ; \
- } while (gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT)
-
-/*
* Macro to convert an mpidr to a value suitable for programming into a
* GICD_IROUTER. Bits[31:24] in the MPIDR are cleared as they are not relevant
* to GICv3.
@@ -42,18 +32,6 @@
(irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT)
/*
- * Macro to wait for updates to :
- * GICR_ICENABLER0
- * GICR_CTLR.DPG1S
- * GICR_CTLR.DPG1NS
- * GICR_CTLR.DPG0
- */
-#define gicr_wait_for_pending_write(gicr_base) \
- do { \
- ; \
- } while (gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT)
-
-/*
* Macro to convert a GICR_TYPER affinity value into a MPIDR value. Bits[31:24]
* are zeroes.
*/
@@ -66,6 +44,11 @@
#endif
/*******************************************************************************
+ * GICv3 private global variables declarations
+ ******************************************************************************/
+extern const gicv3_driver_data_t *gicv3_driver_data;
+
+/*******************************************************************************
* Private GICv3 function prototypes for accessing entire registers.
* Note: The raw register values correspond to multiple interrupt IDs and
* the number of interrupt IDs involved depends on the register accessed.
@@ -84,9 +67,13 @@ void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val);
unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id);
unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id);
unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id);
+unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id);
void gicd_set_igrpmodr(uintptr_t base, unsigned int id);
void gicr_set_igrpmodr0(uintptr_t base, unsigned int id);
void gicr_set_isenabler0(uintptr_t base, unsigned int id);
+void gicr_set_icenabler0(uintptr_t base, unsigned int id);
+void gicr_set_ispendr0(uintptr_t base, unsigned int id);
+void gicr_set_icpendr0(uintptr_t base, unsigned int id);
void gicr_set_igroupr0(uintptr_t base, unsigned int id);
void gicd_clr_igrpmodr(uintptr_t base, unsigned int id);
void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id);
@@ -98,6 +85,7 @@ void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri);
******************************************************************************/
void gicv3_spis_configure_defaults(uintptr_t gicd_base);
void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base);
+#if !ERROR_DEPRECATED
void gicv3_secure_spis_configure(uintptr_t gicd_base,
unsigned int num_ints,
const unsigned int *sec_intr_list,
@@ -106,6 +94,13 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
unsigned int num_ints,
const unsigned int *sec_intr_list,
unsigned int int_grp);
+#endif
+unsigned int gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base,
+ const interrupt_prop_t *interrupt_props,
+ unsigned int interrupt_props_num);
+unsigned int gicv3_secure_spis_configure_props(uintptr_t gicd_base,
+ const interrupt_prop_t *interrupt_props,
+ unsigned int interrupt_props_num);
void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs,
unsigned int rdistif_num,
uintptr_t gicr_base,
@@ -116,6 +111,18 @@ void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base);
/*******************************************************************************
* GIC Distributor interface accessors
******************************************************************************/
+/*
+ * Wait for updates to :
+ * GICD_CTLR[2:0] - the Group Enables
+ * GICD_CTLR[5:4] - the ARE bits
+ * GICD_ICENABLERn - the clearing of enable state for SPIs
+ */
+static inline void gicd_wait_for_pending_write(uintptr_t gicd_base)
+{
+ while (gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT)
+ ;
+}
+
static inline unsigned int gicd_read_pidr2(uintptr_t base)
{
return mmio_read_32(base + GICD_PIDR2_GICV3);
@@ -161,6 +168,11 @@ static inline unsigned long long gicr_read_ctlr(uintptr_t base)
return mmio_read_64(base + GICR_CTLR);
}
+static inline void gicr_write_ctlr(uintptr_t base, uint64_t val)
+{
+ mmio_write_64(base + GICR_CTLR, val);
+}
+
static inline unsigned long long gicr_read_typer(uintptr_t base)
{
return mmio_read_64(base + GICR_TYPER);
@@ -176,6 +188,29 @@ static inline void gicr_write_waker(uintptr_t base, unsigned int val)
mmio_write_32(base + GICR_WAKER, val);
}
+/*
+ * Wait for updates to :
+ * GICR_ICENABLER0
+ * GICR_CTLR.DPG1S
+ * GICR_CTLR.DPG1NS
+ * GICR_CTLR.DPG0
+ */
+static inline void gicr_wait_for_pending_write(uintptr_t gicr_base)
+{
+ while (gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT)
+ ;
+}
+
+static inline void gicr_wait_for_upstream_pending_write(uintptr_t gicr_base)
+{
+ while (gicr_read_ctlr(gicr_base) & GICR_CTLR_UWP_BIT)
+ ;
+}
+
+/* Private implementation of Distributor power control hooks */
+void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num);
+void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num);
+
/*******************************************************************************
* GIC Re-distributor functions for accessing entire registers.
* Note: The raw register values correspond to multiple interrupt IDs and
@@ -196,6 +231,11 @@ static inline unsigned int gicr_read_isenabler0(uintptr_t base)
return mmio_read_32(base + GICR_ISENABLER0);
}
+static inline void gicr_write_icpendr0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ICPENDR0, val);
+}
+
static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val)
{
mmio_write_32(base + GICR_ISENABLER0, val);
@@ -206,6 +246,16 @@ static inline unsigned int gicr_read_igroupr0(uintptr_t base)
return mmio_read_32(base + GICR_IGROUPR0);
}
+static inline unsigned int gicr_read_ispendr0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_ISPENDR0);
+}
+
+static inline void gicr_write_ispendr0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ISPENDR0, val);
+}
+
static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val)
{
mmio_write_32(base + GICR_IGROUPR0, val);
@@ -221,14 +271,120 @@ static inline void gicr_write_igrpmodr0(uintptr_t base, unsigned int val)
mmio_write_32(base + GICR_IGRPMODR0, val);
}
+static inline unsigned int gicr_read_nsacr(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_NSACR);
+}
+
+static inline void gicr_write_nsacr(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_NSACR, val);
+}
+
+static inline unsigned int gicr_read_isactiver0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_ISACTIVER0);
+}
+
+static inline void gicr_write_isactiver0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ISACTIVER0, val);
+}
+
+static inline unsigned int gicr_read_icfgr0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_ICFGR0);
+}
+
static inline unsigned int gicr_read_icfgr1(uintptr_t base)
{
return mmio_read_32(base + GICR_ICFGR1);
}
+static inline void gicr_write_icfgr0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ICFGR0, val);
+}
+
static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val)
{
mmio_write_32(base + GICR_ICFGR1, val);
}
+static inline unsigned int gicr_read_propbaser(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_PROPBASER);
+}
+
+static inline void gicr_write_propbaser(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_PROPBASER, val);
+}
+
+static inline unsigned int gicr_read_pendbaser(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_PENDBASER);
+}
+
+static inline void gicr_write_pendbaser(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_PENDBASER, val);
+}
+
+/*******************************************************************************
+ * GIC ITS functions to read and write entire ITS registers.
+ ******************************************************************************/
+static inline uint32_t gits_read_ctlr(uintptr_t base)
+{
+ return mmio_read_32(base + GITS_CTLR);
+}
+
+static inline void gits_write_ctlr(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GITS_CTLR, val);
+}
+
+static inline uint64_t gits_read_cbaser(uintptr_t base)
+{
+ return mmio_read_64(base + GITS_CBASER);
+}
+
+static inline void gits_write_cbaser(uintptr_t base, uint64_t val)
+{
+ mmio_write_32(base + GITS_CBASER, val);
+}
+
+static inline uint64_t gits_read_cwriter(uintptr_t base)
+{
+ return mmio_read_64(base + GITS_CWRITER);
+}
+
+static inline void gits_write_cwriter(uintptr_t base, uint64_t val)
+{
+ mmio_write_32(base + GITS_CWRITER, val);
+}
+
+static inline uint64_t gits_read_baser(uintptr_t base, unsigned int its_table_id)
+{
+ assert(its_table_id < 8);
+ return mmio_read_64(base + GITS_BASER + (8 * its_table_id));
+}
+
+static inline void gits_write_baser(uintptr_t base, unsigned int its_table_id, uint64_t val)
+{
+ assert(its_table_id < 8);
+ mmio_write_64(base + GITS_BASER + (8 * its_table_id), val);
+}
+
+/*
+ * Wait for Quiescent bit when GIC ITS is disabled
+ */
+static inline void gits_wait_for_quiescent_bit(uintptr_t gits_base)
+{
+ assert(!(gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT));
+ while ((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) == 0)
+ ;
+}
+
+
#endif /* __GICV3_PRIVATE_H__ */
diff --git a/drivers/auth/mbedtls/mbedtls_common.c b/drivers/auth/mbedtls/mbedtls_common.c
index e9aa409b..205c2432 100644
--- a/drivers/auth/mbedtls/mbedtls_common.c
+++ b/drivers/auth/mbedtls/mbedtls_common.c
@@ -14,8 +14,9 @@
/*
* mbed TLS heap
*/
-#if (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA)
-#define MBEDTLS_HEAP_SIZE (14*1024)
+#if (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA) \
+ || (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA)
+#define MBEDTLS_HEAP_SIZE (13*1024)
#elif (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA)
#define MBEDTLS_HEAP_SIZE (7*1024)
#endif
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.c b/drivers/auth/mbedtls/mbedtls_crypto.c
index d8810d6d..bc9ed3a8 100644
--- a/drivers/auth/mbedtls/mbedtls_crypto.c
+++ b/drivers/auth/mbedtls/mbedtls_crypto.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,7 @@
#include <crypto_mod.h>
#include <debug.h>
#include <mbedtls_common.h>
+#include <mbedtls_config.h>
#include <stddef.h>
#include <string.h>
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.mk b/drivers/auth/mbedtls/mbedtls_crypto.mk
index 21b857bf..8eb4873d 100644
--- a/drivers/auth/mbedtls/mbedtls_crypto.mk
+++ b/drivers/auth/mbedtls/mbedtls_crypto.mk
@@ -37,28 +37,58 @@ MBEDTLS_CRYPTO_SOURCES := drivers/auth/mbedtls/mbedtls_crypto.c \
pk_wrap.c \
pkparse.c \
pkwrite.c \
- sha256.c \
)
+ifeq (${HASH_ALG}, sha384)
+ MBEDTLS_CRYPTO_SOURCES += \
+ $(addprefix ${MBEDTLS_DIR}/library/, \
+ sha256.c \
+ sha512.c \
+ )
+ TF_MBEDTLS_HASH_ALG_ID := TF_MBEDTLS_SHA384
+else ifeq (${HASH_ALG}, sha512)
+ MBEDTLS_CRYPTO_SOURCES += \
+ $(addprefix ${MBEDTLS_DIR}/library/, \
+ sha256.c \
+ sha512.c \
+ )
+ TF_MBEDTLS_HASH_ALG_ID := TF_MBEDTLS_SHA512
+else
+ MBEDTLS_CRYPTO_SOURCES += \
+ $(addprefix ${MBEDTLS_DIR}/library/, \
+ sha256.c \
+ )
+ TF_MBEDTLS_HASH_ALG_ID := TF_MBEDTLS_SHA256
+endif
+
# Key algorithm specific files
+MBEDTLS_ECDSA_CRYPTO_SOURCES += $(addprefix ${MBEDTLS_DIR}/library/, \
+ ecdsa.c \
+ ecp_curves.c \
+ ecp.c \
+ )
+
+MBEDTLS_RSA_CRYPTO_SOURCES += $(addprefix ${MBEDTLS_DIR}/library/, \
+ rsa.c \
+ )
+
ifeq (${TF_MBEDTLS_KEY_ALG},ecdsa)
- MBEDTLS_CRYPTO_SOURCES += $(addprefix ${MBEDTLS_DIR}/library/, \
- ecdsa.c \
- ecp_curves.c \
- ecp.c \
- )
+ MBEDTLS_CRYPTO_SOURCES += $(MBEDTLS_ECDSA_CRYPTO_SOURCES)
TF_MBEDTLS_KEY_ALG_ID := TF_MBEDTLS_ECDSA
else ifeq (${TF_MBEDTLS_KEY_ALG},rsa)
- MBEDTLS_CRYPTO_SOURCES += $(addprefix ${MBEDTLS_DIR}/library/, \
- rsa.c \
- )
+ MBEDTLS_CRYPTO_SOURCES += $(MBEDTLS_RSA_CRYPTO_SOURCES)
TF_MBEDTLS_KEY_ALG_ID := TF_MBEDTLS_RSA
+else ifeq (${TF_MBEDTLS_KEY_ALG},rsa+ecdsa)
+ MBEDTLS_CRYPTO_SOURCES += $(MBEDTLS_ECDSA_CRYPTO_SOURCES)
+ MBEDTLS_CRYPTO_SOURCES += $(MBEDTLS_RSA_CRYPTO_SOURCES)
+ TF_MBEDTLS_KEY_ALG_ID := TF_MBEDTLS_RSA_AND_ECDSA
else
$(error "TF_MBEDTLS_KEY_ALG=${TF_MBEDTLS_KEY_ALG} not supported on mbed TLS")
endif
# Needs to be set to drive mbed TLS configuration correctly
$(eval $(call add_define,TF_MBEDTLS_KEY_ALG_ID))
+$(eval $(call add_define,TF_MBEDTLS_HASH_ALG_ID))
BL1_SOURCES += ${MBEDTLS_CRYPTO_SOURCES}
BL2_SOURCES += ${MBEDTLS_CRYPTO_SOURCES}
diff --git a/drivers/auth/tbbr/tbbr_cot.c b/drivers/auth/tbbr/tbbr_cot.c
index 4aaab390..01d6fb5a 100644
--- a/drivers/auth/tbbr/tbbr_cot.c
+++ b/drivers/auth/tbbr/tbbr_cot.c
@@ -19,7 +19,7 @@
* Maximum key and hash sizes (in DER format)
*/
#define PK_DER_LEN 294
-#define HASH_DER_LEN 51
+#define HASH_DER_LEN 83
/*
* The platform must allocate buffers to store the authentication parameters
diff --git a/include/bl31/ehf.h b/include/bl31/ehf.h
new file mode 100644
index 00000000..be8c957c
--- /dev/null
+++ b/include/bl31/ehf.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __EHF_H__
+#define __EHF_H__
+
+#ifndef __ASSEMBLY__
+
+#include <stdint.h>
+#include <utils_def.h>
+
+/* Valid priorities set bit 0 of the priority handler. */
+#define _EHF_PRI_VALID (((uintptr_t) 1) << 0)
+
+/* Marker for no handler registered for a valid priority */
+#define _EHF_NO_HANDLER (0 | _EHF_PRI_VALID)
+
+/* Extract the specified number of top bits from 7 lower bits of priority */
+#define EHF_PRI_TO_IDX(pri, plat_bits) \
+ ((pri & 0x7f) >> (7 - plat_bits))
+
+/* Install exception priority descriptor at a suitable index */
+#define EHF_PRI_DESC(plat_bits, priority) \
+ [EHF_PRI_TO_IDX(priority, plat_bits)] = { \
+ .ehf_handler = _EHF_NO_HANDLER, \
+ }
+
+/* Macro for platforms to regiter its exception priorities */
+#define EHF_REGISTER_PRIORITIES(priorities, num, bits) \
+ const ehf_priorities_t exception_data = { \
+ .num_priorities = num, \
+ .ehf_priorities = priorities, \
+ .pri_bits = bits, \
+ }
+
+/*
+ * Priority stack, managed as a bitmap.
+ *
+ * Currently only supports 32 priority levels, allowing platforms to use up to 5
+ * top bits of priority. But the type can be changed to uint64_t should need
+ * arise to support 64 priority levels, allowing platforms to use up to 6 top
+ * bits of priority.
+ */
+typedef uint32_t ehf_pri_bits_t;
+
+/*
+ * Per-PE exception data. The data for each PE is kept as a per-CPU data field.
+ * See cpu_data.h.
+ */
+typedef struct {
+ ehf_pri_bits_t active_pri_bits;
+
+ /* Priority mask value before any priority levels were active */
+ uint8_t init_pri_mask;
+
+ /* Non-secure priority mask value stashed during Secure execution */
+ uint8_t ns_pri_mask;
+} __aligned(sizeof(uint64_t)) pe_exc_data_t;
+
+typedef int (*ehf_handler_t)(uint32_t intr_raw, uint32_t flags, void *handle,
+ void *cookie);
+
+typedef struct ehf_pri_desc {
+ /*
+ * 4-byte-aligned exception handler. Bit 0 indicates the corresponding
+ * priority level is valid. This is effectively of ehf_handler_t type,
+ * but left as uintptr_t in order to make pointer arithmetic convenient.
+ */
+ uintptr_t ehf_handler;
+} ehf_pri_desc_t;
+
+typedef struct ehf_priorities {
+ ehf_pri_desc_t *ehf_priorities;
+ unsigned int num_priorities;
+ int pri_bits;
+} ehf_priorities_t;
+
+void ehf_init(void);
+void ehf_activate_priority(unsigned int priority);
+void ehf_deactivate_priority(unsigned int priority);
+void ehf_register_priority_handler(unsigned int pri, ehf_handler_t handler);
+void ehf_allow_ns_preemption(void);
+unsigned int ehf_is_ns_preemption_allowed(void);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __EHF_H__ */
diff --git a/include/bl31/interrupt_mgmt.h b/include/bl31/interrupt_mgmt.h
index 9a6a7faa..cccad3ad 100644
--- a/include/bl31/interrupt_mgmt.h
+++ b/include/bl31/interrupt_mgmt.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,6 +17,11 @@
#define INTR_TYPE_NS U(2)
#define MAX_INTR_TYPES U(3)
#define INTR_TYPE_INVAL MAX_INTR_TYPES
+
+/* Interrupt routing modes */
+#define INTR_ROUTING_MODE_PE 0
+#define INTR_ROUTING_MODE_ANY 1
+
/*
* Constant passed to the interrupt handler in the 'id' field when the
* framework does not read the gic registers to determine the interrupt id.
@@ -93,6 +98,8 @@
#ifndef __ASSEMBLY__
+#include <stdint.h>
+
/* Prototype for defining a handler for an interrupt type */
typedef uint64_t (*interrupt_type_handler_t)(uint32_t id,
uint32_t flags,
diff --git a/include/common/aarch32/asm_macros.S b/include/common/aarch32/asm_macros.S
index f5737449..74322228 100644
--- a/include/common/aarch32/asm_macros.S
+++ b/include/common/aarch32/asm_macros.S
@@ -79,6 +79,25 @@
ldr r0, =(\_name + \_size)
.endm
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+ /*
+ * ARMv7 cores without Virtualization extension do not support the
+ * eret instruction.
+ */
+ .macro eret
+ movs pc, lr
+ .endm
+#endif
+
+#if (ARM_ARCH_MAJOR == 7)
+ /* ARMv7 does not support stl instruction */
+ .macro stl _reg, _write_lock
+ dmb
+ str \_reg, \_write_lock
+ dsb
+ .endm
+#endif
+
/*
* Helper macro to generate the best mov/movw/movt combinations
* according to the value to be moved.
diff --git a/include/common/aarch32/el3_common_macros.S b/include/common/aarch32/el3_common_macros.S
index 6fc00dd2..59e99f89 100644
--- a/include/common/aarch32/el3_common_macros.S
+++ b/include/common/aarch32/el3_common_macros.S
@@ -107,6 +107,7 @@
vmsr FPEXC, r0
isb
+#if (ARM_ARCH_MAJOR > 7)
/* ---------------------------------------------------------------------
* Initialise SDCR, setting all the fields rather than relying on hw.
*
@@ -116,6 +117,7 @@
*/
ldr r0, =(SDCR_RESET_VAL | SDCR_SPD(SDCR_SPD_DISABLE))
stcopr r0, SDCR
+#endif
.endm
diff --git a/include/common/aarch64/asm_macros.S b/include/common/aarch64/asm_macros.S
index 6d6989c2..94a9df92 100644
--- a/include/common/aarch64/asm_macros.S
+++ b/include/common/aarch64/asm_macros.S
@@ -51,8 +51,8 @@
* so that it inserts illegal AArch64 instructions. This increases
* security, robustness and potentially facilitates debugging.
*/
- .macro vector_base label
- .section .vectors, "ax"
+ .macro vector_base label, section_name=.vectors
+ .section \section_name, "ax"
.align 11, 0
\label:
.endm
@@ -64,9 +64,9 @@
* so that it inserts illegal AArch64 instructions. This increases
* security, robustness and potentially facilitates debugging.
*/
- .macro vector_entry label
+ .macro vector_entry label, section_name=.vectors
.cfi_sections .debug_frame
- .section .vectors, "ax"
+ .section \section_name, "ax"
.align 7, 0
.type \label, %function
.func \label
diff --git a/include/common/aarch64/el3_common_macros.S b/include/common/aarch64/el3_common_macros.S
index 34fdaee9..63a0fa77 100644
--- a/include/common/aarch64/el3_common_macros.S
+++ b/include/common/aarch64/el3_common_macros.S
@@ -95,10 +95,6 @@
* MDCR_EL3.SPD32: Set to 0b10 to disable AArch32 Secure self-hosted
* privileged debug from S-EL1.
*
- * MDCR_EL3.NSPB (ARM v8.2): SPE enabled in non-secure state and
- * disabled in secure state. Accesses to SPE registers at SEL1 generate
- * trap exceptions to EL3.
- *
* MDCR_EL3.TDOSA: Set to zero so that EL2 and EL2 System register
* access to the powerdown debug registers do not trap to EL3.
*
@@ -112,19 +108,6 @@
*/
mov_imm x0, ((MDCR_EL3_RESET_VAL | MDCR_SDD_BIT | MDCR_SPD32(MDCR_SPD32_DISABLE)) \
& ~(MDCR_TDOSA_BIT | MDCR_TDA_BIT | MDCR_TPM_BIT))
-
-#if ENABLE_SPE_FOR_LOWER_ELS
- /* Detect if SPE is implemented */
- mrs x1, id_aa64dfr0_el1
- ubfx x1, x1, #ID_AA64DFR0_PMS_SHIFT, #ID_AA64DFR0_PMS_LENGTH
- cmp x1, #0x1
- b.ne 1f
-
- /* Enable SPE for use by normal world */
- orr x0, x0, #MDCR_NSPB(MDCR_NSPB_EL1)
-1:
-#endif
-
msr mdcr_el3, x0
/* ---------------------------------------------------------------------
@@ -144,9 +127,9 @@
* CPTR_EL3.TTA: Set to zero so that System register accesses to the
* trace registers do not trap to EL3.
*
- * CPTR_EL3.TFP: Set to zero so that accesses to Advanced SIMD and
- * floating-point functionality do not trap to EL3.
- * ---------------------------------------------------------------------
+ * CPTR_EL3.TFP: Set to zero so that accesses to the V- or Z- registers
+ * by Advanced SIMD, floating-point or SVE instructions (if implemented)
+ * do not trap to EL3.
*/
mov_imm x0, (CPTR_EL3_RESET_VAL & ~(TCPAC_BIT | TTA_BIT | TFP_BIT))
msr cptr_el3, x0
diff --git a/include/common/bl_common.h b/include/common/bl_common.h
index 15ffc578..8915ba06 100644
--- a/include/common/bl_common.h
+++ b/include/common/bl_common.h
@@ -205,7 +205,6 @@ int is_mem_free(uintptr_t free_base, size_t free_size,
#if LOAD_IMAGE_V2
-int load_image(unsigned int image_id, image_info_t *image_data);
int load_auth_image(unsigned int image_id, image_info_t *image_data);
#else
diff --git a/include/common/interrupt_props.h b/include/common/interrupt_props.h
new file mode 100644
index 00000000..9786b40c
--- /dev/null
+++ b/include/common/interrupt_props.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __INTERRUPT_PROPS_H__
+#define __INTERRUPT_PROPS_H__
+
+#ifndef __ASSEMBLY__
+
+/* Create an interrupt property descriptor from various interrupt properties */
+#define INTR_PROP_DESC(num, pri, grp, cfg) \
+ { \
+ .intr_num = num, \
+ .intr_pri = pri, \
+ .intr_grp = grp, \
+ .intr_cfg = cfg, \
+ }
+
+typedef struct interrupt_prop {
+ unsigned int intr_num:10;
+ unsigned int intr_pri:8;
+ unsigned int intr_grp:2;
+ unsigned int intr_cfg:2;
+} interrupt_prop_t;
+
+#endif /* __ASSEMBLY__ */
+#endif /* __INTERRUPT_PROPS_H__ */
diff --git a/include/common/param_header.h b/include/common/param_header.h
index 90d59b3a..c982fc90 100644
--- a/include/common/param_header.h
+++ b/include/common/param_header.h
@@ -8,12 +8,13 @@
#define __PARAM_HEADER_H__
/* Param header types */
-#define PARAM_EP 0x01
-#define PARAM_IMAGE_BINARY 0x02
-#define PARAM_BL31 0x03
-#define PARAM_BL_LOAD_INFO 0x04
-#define PARAM_BL_PARAMS 0x05
-#define PARAM_PSCI_LIB_ARGS 0x06
+#define PARAM_EP 0x01
+#define PARAM_IMAGE_BINARY 0x02
+#define PARAM_BL31 0x03
+#define PARAM_BL_LOAD_INFO 0x04
+#define PARAM_BL_PARAMS 0x05
+#define PARAM_PSCI_LIB_ARGS 0x06
+#define PARAM_SP_IMAGE_BOOT_INFO 0x07
/* Param header version */
#define VERSION_1 0x01
diff --git a/include/drivers/arm/arm_gicv3_common.h b/include/drivers/arm/arm_gicv3_common.h
new file mode 100644
index 00000000..8970e3f4
--- /dev/null
+++ b/include/drivers/arm/arm_gicv3_common.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __ARM_GICV3_COMMON_H__
+#define __ARM_GICV3_COMMON_H__
+
+/*******************************************************************************
+ * GIC500/GIC600 Re-distributor interface registers & constants
+ ******************************************************************************/
+
+/* GICR_WAKER implementation-defined bit definitions */
+#define WAKER_SL_SHIFT 0
+#define WAKER_QSC_SHIFT 31
+
+#define WAKER_SL_BIT (1U << WAKER_SL_SHIFT)
+#define WAKER_QSC_BIT (1U << WAKER_QSC_SHIFT)
+
+#endif /* __ARM_GICV3_COMMON_H__ */
diff --git a/include/drivers/arm/gic_common.h b/include/drivers/arm/gic_common.h
index 7e097adc..001f5736 100644
--- a/include/drivers/arm/gic_common.h
+++ b/include/drivers/arm/gic_common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,20 +12,32 @@
******************************************************************************/
/* Constants to categorise interrupts */
#define MIN_SGI_ID 0
+#define MIN_SEC_SGI_ID 8
#define MIN_PPI_ID 16
#define MIN_SPI_ID 32
+#define MAX_SPI_ID 1019
+
+#define TOTAL_SPI_INTR_NUM (MAX_SPI_ID - MIN_SPI_ID + 1)
+#define TOTAL_PCPU_INTR_NUM (MIN_SPI_ID - MIN_SGI_ID)
/* Mask for the priority field common to all GIC interfaces */
#define GIC_PRI_MASK 0xff
+/* Mask for the configuration field common to all GIC interfaces */
+#define GIC_CFG_MASK 0x3
+
/* Constant to indicate a spurious interrupt in all GIC versions */
#define GIC_SPURIOUS_INTERRUPT 1023
+/* Interrupt configurations */
+#define GIC_INTR_CFG_LEVEL 0
+#define GIC_INTR_CFG_EDGE 1
+
/* Constants to categorise priorities */
-#define GIC_HIGHEST_SEC_PRIORITY 0
-#define GIC_LOWEST_SEC_PRIORITY 127
-#define GIC_HIGHEST_NS_PRIORITY 128
-#define GIC_LOWEST_NS_PRIORITY 254 /* 255 would disable an interrupt */
+#define GIC_HIGHEST_SEC_PRIORITY 0x0
+#define GIC_LOWEST_SEC_PRIORITY 0x7f
+#define GIC_HIGHEST_NS_PRIORITY 0x80
+#define GIC_LOWEST_NS_PRIORITY 0xfe /* 0xff would disable all interrupts */
/*******************************************************************************
* GIC Distributor interface register offsets that are common to GICv3 & GICv2
@@ -60,6 +72,8 @@
#define ARCH_REV_GICV3 0x3
/* GICv2 revision as reported by the PIDR2 register */
#define ARCH_REV_GICV2 0x2
+/* GICv1 revision as reported by the PIDR2 register */
+#define ARCH_REV_GICV1 0x1
#define IGROUPR_SHIFT 5
#define ISENABLER_SHIFT 5
@@ -69,6 +83,7 @@
#define ISACTIVER_SHIFT 5
#define ICACTIVER_SHIFT ISACTIVER_SHIFT
#define IPRIORITYR_SHIFT 2
+#define ITARGETSR_SHIFT 2
#define ICFGR_SHIFT 4
#define NSACR_SHIFT 4
diff --git a/include/drivers/arm/gic_v2.h b/include/drivers/arm/gic_v2.h
index 3a3d7aaa..258b8981 100644
--- a/include/drivers/arm/gic_v2.h
+++ b/include/drivers/arm/gic_v2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,9 @@
#ifndef __GIC_V2_H__
#define __GIC_V2_H__
+/* The macros required here are additional to those in gic_common.h. */
+#include <gic_common.h>
+
/******************************************************************************
* THIS DRIVER IS DEPRECATED. For GICv2 systems, use the driver in gicv2.h
* and for GICv3 systems, use the driver in gicv3.h.
@@ -19,50 +22,20 @@
#define MAX_PPIS U(14)
#define MAX_SGIS U(16)
-#define MIN_SGI_ID U(0)
-#define MIN_PPI_ID U(16)
-#define MIN_SPI_ID U(32)
#define GRP0 U(0)
#define GRP1 U(1)
-#define GIC_PRI_MASK U(0xff)
-#define GIC_HIGHEST_SEC_PRIORITY U(0)
-#define GIC_LOWEST_SEC_PRIORITY U(127)
-#define GIC_HIGHEST_NS_PRIORITY U(128)
-#define GIC_LOWEST_NS_PRIORITY U(254) /* 255 would disable an interrupt */
-#define GIC_SPURIOUS_INTERRUPT U(1023)
#define GIC_TARGET_CPU_MASK U(0xff)
#define ENABLE_GRP0 (U(1) << 0)
#define ENABLE_GRP1 (U(1) << 1)
/* Distributor interface definitions */
-#define GICD_CTLR U(0x0)
-#define GICD_TYPER U(0x4)
-#define GICD_IGROUPR U(0x80)
-#define GICD_ISENABLER U(0x100)
-#define GICD_ICENABLER U(0x180)
-#define GICD_ISPENDR U(0x200)
-#define GICD_ICPENDR U(0x280)
-#define GICD_ISACTIVER U(0x300)
-#define GICD_ICACTIVER U(0x380)
-#define GICD_IPRIORITYR U(0x400)
#define GICD_ITARGETSR U(0x800)
-#define GICD_ICFGR U(0xC00)
#define GICD_SGIR U(0xF00)
#define GICD_CPENDSGIR U(0xF10)
#define GICD_SPENDSGIR U(0xF20)
-#define IGROUPR_SHIFT U(5)
-#define ISENABLER_SHIFT U(5)
-#define ICENABLER_SHIFT ISENABLER_SHIFT
-#define ISPENDR_SHIFT U(5)
-#define ICPENDR_SHIFT ISPENDR_SHIFT
-#define ISACTIVER_SHIFT U(5)
-#define ICACTIVER_SHIFT ISACTIVER_SHIFT
-#define IPRIORITYR_SHIFT U(2)
-#define ITARGETSR_SHIFT U(2)
-#define ICFGR_SHIFT U(4)
#define CPENDSGIR_SHIFT U(2)
#define SPENDSGIR_SHIFT CPENDSGIR_SHIFT
diff --git a/include/drivers/arm/gic_v3.h b/include/drivers/arm/gic_v3.h
index ee8f26be..02f9006f 100644
--- a/include/drivers/arm/gic_v3.h
+++ b/include/drivers/arm/gic_v3.h
@@ -26,17 +26,17 @@
#define GICR_WAKER 0x14
/* GICR_WAKER bit definitions */
-#define WAKER_CA (1UL << 2)
-#define WAKER_PS (1UL << 1)
+#define WAKER_CA (U(1) << 2)
+#define WAKER_PS (U(1) << 1)
/* GICR_TYPER bit definitions */
#define GICR_TYPER_AFF_SHIFT 32
#define GICR_TYPER_AFF_MASK 0xffffffff
-#define GICR_TYPER_LAST (1UL << 4)
+#define GICR_TYPER_LAST (U(1) << 4)
/* GICv3 ICC_SRE register bit definitions*/
-#define ICC_SRE_EN (1UL << 3)
-#define ICC_SRE_SRE (1UL << 0)
+#define ICC_SRE_EN (U(1) << 3)
+#define ICC_SRE_SRE (U(1) << 0)
/*******************************************************************************
* GICv3 defintions
diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h
index a7880254..6e8322e1 100644
--- a/include/drivers/arm/gicv2.h
+++ b/include/drivers/arm/gicv2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,9 +10,17 @@
/*******************************************************************************
* GICv2 miscellaneous definitions
******************************************************************************/
+
+/* Interrupt group definitions */
+#define GICV2_INTR_GROUP0 0
+#define GICV2_INTR_GROUP1 1
+
/* Interrupt IDs reported by the HPPIR and IAR registers */
#define PENDING_G1_INTID 1022
+/* GICv2 can only target up to 8 PEs */
+#define GICV2_MAX_TARGET_PE 8
+
/*******************************************************************************
* GICv2 specific Distributor interface register offsets and constants.
******************************************************************************/
@@ -28,6 +36,19 @@
#define CPENDSGIR_SHIFT 2
#define SPENDSGIR_SHIFT CPENDSGIR_SHIFT
+#define SGIR_TGTLSTFLT_SHIFT 24
+#define SGIR_TGTLSTFLT_MASK 0x3
+#define SGIR_TGTLST_SHIFT 16
+#define SGIR_TGTLST_MASK 0xff
+#define SGIR_INTID_MASK 0xf
+
+#define SGIR_TGT_SPECIFIC 0
+
+#define GICV2_SGIR_VALUE(tgt_lst_flt, tgt, intid) \
+ ((((tgt_lst_flt) & SGIR_TGTLSTFLT_MASK) << SGIR_TGTLSTFLT_SHIFT) | \
+ (((tgt) & SGIR_TGTLST_MASK) << SGIR_TGTLST_SHIFT) | \
+ ((intid) & SGIR_INTID_MASK))
+
/*******************************************************************************
* GICv2 specific CPU interface register offsets and constants.
******************************************************************************/
@@ -95,6 +116,7 @@
#ifndef __ASSEMBLY__
+#include <interrupt_props.h>
#include <stdint.h>
/*******************************************************************************
@@ -103,23 +125,43 @@
* in order to initialize the GICv2 driver. The attributes are described
* below.
*
- * 1. The 'gicd_base' field contains the base address of the Distributor
- * interface programmer's view.
+ * The 'gicd_base' field contains the base address of the Distributor interface
+ * programmer's view.
+ *
+ * The 'gicc_base' field contains the base address of the CPU Interface
+ * programmer's view.
+ *
+ * The 'g0_interrupt_array' field is a pointer to an array in which each entry
+ * corresponds to an ID of a Group 0 interrupt. This field is ignored when
+ * 'interrupt_props' field is used. This field is deprecated.
+ *
+ * The 'g0_interrupt_num' field contains the number of entries in the
+ * 'g0_interrupt_array'. This field is ignored when 'interrupt_props' field is
+ * used. This field is deprecated.
*
- * 2. The 'gicc_base' field contains the base address of the CPU Interface
- * programmer's view.
+ * The 'target_masks' is a pointer to an array containing 'target_masks_num'
+ * elements. The GIC driver will populate the array with per-PE target mask to
+ * use to when targeting interrupts.
*
- * 3. The 'g0_interrupt_array' field is a pointer to an array in which each
- * entry corresponds to an ID of a Group 0 interrupt.
+ * The 'interrupt_props' field is a pointer to an array that enumerates secure
+ * interrupts and their properties. If this field is not NULL, both
+ * 'g0_interrupt_array' and 'g1s_interrupt_array' fields are ignored.
*
- * 4. The 'g0_interrupt_num' field contains the number of entries in the
- * 'g0_interrupt_array'.
+ * The 'interrupt_props_num' field contains the number of entries in the
+ * 'interrupt_props' array. If this field is non-zero, 'g0_interrupt_num' is
+ * ignored.
******************************************************************************/
typedef struct gicv2_driver_data {
uintptr_t gicd_base;
uintptr_t gicc_base;
+#if !ERROR_DEPRECATED
unsigned int g0_interrupt_num;
const unsigned int *g0_interrupt_array;
+#endif
+ unsigned int *target_masks;
+ unsigned int target_masks_num;
+ const interrupt_prop_t *interrupt_props;
+ unsigned int interrupt_props_num;
} gicv2_driver_data_t;
/*******************************************************************************
@@ -136,6 +178,18 @@ unsigned int gicv2_get_pending_interrupt_id(void);
unsigned int gicv2_acknowledge_interrupt(void);
void gicv2_end_of_interrupt(unsigned int id);
unsigned int gicv2_get_interrupt_group(unsigned int id);
+unsigned int gicv2_get_running_priority(void);
+void gicv2_set_pe_target_mask(unsigned int proc_num);
+unsigned int gicv2_get_interrupt_active(unsigned int id);
+void gicv2_enable_interrupt(unsigned int id);
+void gicv2_disable_interrupt(unsigned int id);
+void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority);
+void gicv2_set_interrupt_type(unsigned int id, unsigned int type);
+void gicv2_raise_sgi(int sgi_num, int proc_num);
+void gicv2_set_spi_routing(unsigned int id, int proc_num);
+void gicv2_set_interrupt_pending(unsigned int id);
+void gicv2_clear_interrupt_pending(unsigned int id);
+unsigned int gicv2_set_pmr(unsigned int mask);
#endif /* __ASSEMBLY__ */
#endif /* __GICV2_H__ */
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
index 8d9981ac..f2a53712 100644
--- a/include/drivers/arm/gicv3.h
+++ b/include/drivers/arm/gicv3.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -22,6 +22,9 @@
/* Constant to categorize LPI interrupt */
#define MIN_LPI_ID 8192
+/* GICv3 can only target up to 16 PEs with SGI */
+#define GICV3_MAX_SGI_TARGETS 16
+
/*******************************************************************************
* GICv3 specific Distributor interface register offsets and constants.
******************************************************************************/
@@ -66,9 +69,15 @@
#define GICD_CTLR_RWP_BIT (1 << GICD_CTLR_RWP_SHIFT)
/* GICD_IROUTER shifts and masks */
+#define IROUTER_SHIFT 0
#define IROUTER_IRM_SHIFT 31
#define IROUTER_IRM_MASK 0x1
+#define GICV3_IRM_PE 0
+#define GICV3_IRM_ANY 1
+
+#define NUM_OF_DIST_REGS 30
+
/*******************************************************************************
* GICv3 Re-distributor interface registers & constants
******************************************************************************/
@@ -77,18 +86,29 @@
#define GICR_CTLR 0x0
#define GICR_TYPER 0x08
#define GICR_WAKER 0x14
+#define GICR_PROPBASER 0x70
+#define GICR_PENDBASER 0x78
#define GICR_IGROUPR0 (GICR_SGIBASE_OFFSET + 0x80)
#define GICR_ISENABLER0 (GICR_SGIBASE_OFFSET + 0x100)
#define GICR_ICENABLER0 (GICR_SGIBASE_OFFSET + 0x180)
+#define GICR_ISPENDR0 (GICR_SGIBASE_OFFSET + 0x200)
+#define GICR_ICPENDR0 (GICR_SGIBASE_OFFSET + 0x280)
+#define GICR_ISACTIVER0 (GICR_SGIBASE_OFFSET + 0x300)
+#define GICR_ICACTIVER0 (GICR_SGIBASE_OFFSET + 0x380)
#define GICR_IPRIORITYR (GICR_SGIBASE_OFFSET + 0x400)
#define GICR_ICFGR0 (GICR_SGIBASE_OFFSET + 0xc00)
#define GICR_ICFGR1 (GICR_SGIBASE_OFFSET + 0xc04)
#define GICR_IGRPMODR0 (GICR_SGIBASE_OFFSET + 0xd00)
+#define GICR_NSACR (GICR_SGIBASE_OFFSET + 0xe00)
/* GICR_CTLR bit definitions */
+#define GICR_CTLR_UWP_SHIFT 31
+#define GICR_CTLR_UWP_MASK 0x1
+#define GICR_CTLR_UWP_BIT (1U << GICR_CTLR_UWP_SHIFT)
#define GICR_CTLR_RWP_SHIFT 3
#define GICR_CTLR_RWP_MASK 0x1
-#define GICR_CTLR_RWP_BIT (1 << GICR_CTLR_RWP_SHIFT)
+#define GICR_CTLR_RWP_BIT (1U << GICR_CTLR_RWP_SHIFT)
+#define GICR_CTLR_EN_LPIS_BIT (1U << 0)
/* GICR_WAKER bit definitions */
#define WAKER_CA_SHIFT 2
@@ -111,6 +131,8 @@
#define TYPER_LAST_BIT (1 << TYPER_LAST_SHIFT)
+#define NUM_OF_REDIST_REGS 30
+
/*******************************************************************************
* GICv3 CPU interface registers & constants
******************************************************************************/
@@ -147,10 +169,51 @@
#define IAR1_EL1_INTID_SHIFT 0
#define IAR1_EL1_INTID_MASK 0xffffff
+/* ICC SGI macros */
+#define SGIR_TGT_MASK 0xffff
+#define SGIR_AFF1_SHIFT 16
+#define SGIR_INTID_SHIFT 24
+#define SGIR_INTID_MASK 0xf
+#define SGIR_AFF2_SHIFT 32
+#define SGIR_IRM_SHIFT 40
+#define SGIR_IRM_MASK 0x1
+#define SGIR_AFF3_SHIFT 48
+#define SGIR_AFF_MASK 0xf
+
+#define SGIR_IRM_TO_AFF 0
+
+#define GICV3_SGIR_VALUE(aff3, aff2, aff1, intid, irm, tgt) \
+ ((((uint64_t) (aff3) & SGIR_AFF_MASK) << SGIR_AFF3_SHIFT) | \
+ (((uint64_t) (irm) & SGIR_IRM_MASK) << SGIR_IRM_SHIFT) | \
+ (((uint64_t) (aff2) & SGIR_AFF_MASK) << SGIR_AFF2_SHIFT) | \
+ (((intid) & SGIR_INTID_MASK) << SGIR_INTID_SHIFT) | \
+ (((aff1) & SGIR_AFF_MASK) << SGIR_AFF1_SHIFT) | \
+ ((tgt) & SGIR_TGT_MASK))
+
+/*****************************************************************************
+ * GICv3 ITS registers and constants
+ *****************************************************************************/
+
+#define GITS_CTLR 0x0
+#define GITS_IIDR 0x4
+#define GITS_TYPER 0x8
+#define GITS_CBASER 0x80
+#define GITS_CWRITER 0x88
+#define GITS_CREADR 0x90
+#define GITS_BASER 0x100
+
+/* GITS_CTLR bit definitions */
+#define GITS_CTLR_ENABLED_BIT 1
+#define GITS_CTLR_QUIESCENT_SHIFT 31
+#define GITS_CTLR_QUIESCENT_BIT (1U << GITS_CTLR_QUIESCENT_SHIFT)
+
#ifndef __ASSEMBLY__
+#include <gic_common.h>
+#include <interrupt_props.h>
#include <stdint.h>
#include <types.h>
+#include <utils_def.h>
#define gicv3_is_intr_id_special_identifier(id) \
(((id) >= PENDING_G1S_INTID) && ((id) <= GIC_SPURIOUS_INTERRUPT))
@@ -172,63 +235,137 @@
IAR0_EL1_INTID_MASK
#define gicv3_end_of_interrupt(id) write_icc_eoir0_el1(id)
+/*
+ * This macro returns the total number of GICD registers corresponding to
+ * the name.
+ */
+#define GICD_NUM_REGS(reg_name) \
+ DIV_ROUND_UP_2EVAL(TOTAL_SPI_INTR_NUM, (1 << reg_name ## _SHIFT))
+
+#define GICR_NUM_REGS(reg_name) \
+ DIV_ROUND_UP_2EVAL(TOTAL_PCPU_INTR_NUM, (1 << reg_name ## _SHIFT))
+
+/* Interrupt ID mask for HPPIR, AHPPIR, IAR and AIAR CPU Interface registers */
+#define INT_ID_MASK 0xffffff
+
/*******************************************************************************
* This structure describes some of the implementation defined attributes of the
* GICv3 IP. It is used by the platform port to specify these attributes in order
* to initialise the GICV3 driver. The attributes are described below.
*
- * 1. The 'gicd_base' field contains the base address of the Distributor
- * interface programmer's view.
+ * The 'gicd_base' field contains the base address of the Distributor interface
+ * programmer's view.
+ *
+ * The 'gicr_base' field contains the base address of the Re-distributor
+ * interface programmer's view.
+ *
+ * The 'g0_interrupt_array' field is a pointer to an array in which each entry
+ * corresponds to an ID of a Group 0 interrupt. This field is ignored when
+ * 'interrupt_props' field is used. This field is deprecated.
*
- * 2. The 'gicr_base' field contains the base address of the Re-distributor
- * interface programmer's view.
+ * The 'g0_interrupt_num' field contains the number of entries in the
+ * 'g0_interrupt_array'. This field is ignored when 'interrupt_props' field is
+ * used. This field is deprecated.
*
- * 3. The 'g0_interrupt_array' field is a ponter to an array in which each
- * entry corresponds to an ID of a Group 0 interrupt.
+ * The 'g1s_interrupt_array' field is a pointer to an array in which each entry
+ * corresponds to an ID of a Group 1 interrupt. This field is ignored when
+ * 'interrupt_props' field is used. This field is deprecated.
*
- * 4. The 'g0_interrupt_num' field contains the number of entries in the
- * 'g0_interrupt_array'.
+ * The 'g1s_interrupt_num' field contains the number of entries in the
+ * 'g1s_interrupt_array'. This field must be 0 if 'interrupt_props' field is
+ * used. This field is ignored when 'interrupt_props' field is used. This field
+ * is deprecated.
*
- * 5. The 'g1s_interrupt_array' field is a ponter to an array in which each
- * entry corresponds to an ID of a Group 1 interrupt.
+ * The 'interrupt_props' field is a pointer to an array that enumerates secure
+ * interrupts and their properties. If this field is not NULL, both
+ * 'g0_interrupt_array' and 'g1s_interrupt_array' fields are ignored.
*
- * 6. The 'g1s_interrupt_num' field contains the number of entries in the
- * 'g1s_interrupt_array'.
+ * The 'interrupt_props_num' field contains the number of entries in the
+ * 'interrupt_props' array. If this field is non-zero, both 'g0_interrupt_num'
+ * and 'g1s_interrupt_num' are ignored.
*
- * 7. The 'rdistif_num' field contains the number of Redistributor interfaces
- * the GIC implements. This is equal to the number of CPUs or CPU interfaces
- * instantiated in the GIC.
+ * The 'rdistif_num' field contains the number of Redistributor interfaces the
+ * GIC implements. This is equal to the number of CPUs or CPU interfaces
+ * instantiated in the GIC.
*
- * 8. The 'rdistif_base_addrs' field is a pointer to an array that has an entry
- * for storing the base address of the Redistributor interface frame of each
- * CPU in the system. The size of the array = 'rdistif_num'. The base
- * addresses are detected during driver initialisation.
+ * The 'rdistif_base_addrs' field is a pointer to an array that has an entry for
+ * storing the base address of the Redistributor interface frame of each CPU in
+ * the system. The size of the array = 'rdistif_num'. The base addresses are
+ * detected during driver initialisation.
*
- * 9. The 'mpidr_to_core_pos' field is a pointer to a hash function which the
- * driver will use to convert an MPIDR value to a linear core index. This
- * index will be used for accessing the 'rdistif_base_addrs' array. This is
- * an optional field. A GICv3 implementation maps each MPIDR to a linear core
- * index as well. This mapping can be found by reading the "Affinity Value"
- * and "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the
- * "Processor Numbers" are suitable to index into an array to access core
- * specific information. If this not the case, the platform port must provide
- * a hash function. Otherwise, the "Processor Number" field will be used to
- * access the array elements.
+ * The 'mpidr_to_core_pos' field is a pointer to a hash function which the
+ * driver will use to convert an MPIDR value to a linear core index. This index
+ * will be used for accessing the 'rdistif_base_addrs' array. This is an
+ * optional field. A GICv3 implementation maps each MPIDR to a linear core index
+ * as well. This mapping can be found by reading the "Affinity Value" and
+ * "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the
+ * "Processor Numbers" are suitable to index into an array to access core
+ * specific information. If this not the case, the platform port must provide a
+ * hash function. Otherwise, the "Processor Number" field will be used to access
+ * the array elements.
******************************************************************************/
typedef unsigned int (*mpidr_hash_fn)(u_register_t mpidr);
typedef struct gicv3_driver_data {
uintptr_t gicd_base;
uintptr_t gicr_base;
+#if !ERROR_DEPRECATED
unsigned int g0_interrupt_num;
unsigned int g1s_interrupt_num;
const unsigned int *g0_interrupt_array;
const unsigned int *g1s_interrupt_array;
+#endif
+ const interrupt_prop_t *interrupt_props;
+ unsigned int interrupt_props_num;
unsigned int rdistif_num;
uintptr_t *rdistif_base_addrs;
mpidr_hash_fn mpidr_to_core_pos;
} gicv3_driver_data_t;
+typedef struct gicv3_redist_ctx {
+ /* 64 bits registers */
+ uint64_t gicr_propbaser;
+ uint64_t gicr_pendbaser;
+
+ /* 32 bits registers */
+ uint32_t gicr_ctlr;
+ uint32_t gicr_igroupr0;
+ uint32_t gicr_isenabler0;
+ uint32_t gicr_ispendr0;
+ uint32_t gicr_isactiver0;
+ uint32_t gicr_ipriorityr[GICR_NUM_REGS(IPRIORITYR)];
+ uint32_t gicr_icfgr0;
+ uint32_t gicr_icfgr1;
+ uint32_t gicr_igrpmodr0;
+ uint32_t gicr_nsacr;
+} gicv3_redist_ctx_t;
+
+typedef struct gicv3_dist_ctx {
+ /* 64 bits registers */
+ uint64_t gicd_irouter[TOTAL_SPI_INTR_NUM];
+
+ /* 32 bits registers */
+ uint32_t gicd_ctlr;
+ uint32_t gicd_igroupr[GICD_NUM_REGS(IGROUPR)];
+ uint32_t gicd_isenabler[GICD_NUM_REGS(ISENABLER)];
+ uint32_t gicd_ispendr[GICD_NUM_REGS(ISPENDR)];
+ uint32_t gicd_isactiver[GICD_NUM_REGS(ISACTIVER)];
+ uint32_t gicd_ipriorityr[GICD_NUM_REGS(IPRIORITYR)];
+ uint32_t gicd_icfgr[GICD_NUM_REGS(ICFGR)];
+ uint32_t gicd_igrpmodr[GICD_NUM_REGS(IGRPMODR)];
+ uint32_t gicd_nsacr[GICD_NUM_REGS(NSACR)];
+} gicv3_dist_ctx_t;
+
+typedef struct gicv3_its_ctx {
+ /* 64 bits registers */
+ uint64_t gits_cbaser;
+ uint64_t gits_cwriter;
+ uint64_t gits_baser[8];
+
+ /* 32 bits registers */
+ uint32_t gits_ctlr;
+} gicv3_its_ctx_t;
+
/*******************************************************************************
* GICv3 EL3 driver API
******************************************************************************/
@@ -243,7 +380,35 @@ unsigned int gicv3_get_pending_interrupt_type(void);
unsigned int gicv3_get_pending_interrupt_id(void);
unsigned int gicv3_get_interrupt_type(unsigned int id,
unsigned int proc_num);
-
+void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx);
+void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx);
+/*
+ * gicv3_distif_post_restore and gicv3_distif_pre_save must be implemented if
+ * gicv3_distif_save and gicv3_rdistif_init_restore are used. If no
+ * implementation-defined sequence is needed at these steps, an empty function
+ * can be provided.
+ */
+void gicv3_distif_post_restore(unsigned int proc_num);
+void gicv3_distif_pre_save(unsigned int proc_num);
+void gicv3_rdistif_init_restore(unsigned int proc_num, const gicv3_redist_ctx_t * const rdist_ctx);
+void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx);
+void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx);
+void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx);
+
+unsigned int gicv3_get_running_priority(void);
+unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num);
+void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num);
+void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num);
+void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
+ unsigned int priority);
+void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
+ unsigned int group);
+void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target);
+void gicv3_set_spi_routing(unsigned int id, unsigned int irm,
+ u_register_t mpidr);
+void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num);
+void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num);
+unsigned int gicv3_set_pmr(unsigned int mask);
#endif /* __ASSEMBLY__ */
#endif /* __GICV3_H__ */
diff --git a/include/drivers/auth/mbedtls/mbedtls_config.h b/include/drivers/auth/mbedtls/mbedtls_config.h
index fdeb52bb..f8f26080 100644
--- a/include/drivers/auth/mbedtls/mbedtls_config.h
+++ b/include/drivers/auth/mbedtls/mbedtls_config.h
@@ -9,8 +9,16 @@
/*
* Key algorithms currently supported on mbed TLS libraries
*/
-#define TF_MBEDTLS_RSA 1
-#define TF_MBEDTLS_ECDSA 2
+#define TF_MBEDTLS_RSA 1
+#define TF_MBEDTLS_ECDSA 2
+#define TF_MBEDTLS_RSA_AND_ECDSA 3
+
+/*
+ * Hash algorithms currently supported on mbed TLS libraries
+ */
+#define TF_MBEDTLS_SHA256 1
+#define TF_MBEDTLS_SHA384 2
+#define TF_MBEDTLS_SHA512 3
/*
* Configuration file to build mbed TLS with the required features for
@@ -30,7 +38,6 @@
#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
#define MBEDTLS_X509_CHECK_KEY_USAGE
#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
-#define MBEDTLS_X509_RSASSA_PSS_SUPPORT
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
@@ -56,9 +63,19 @@
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#elif (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA)
#define MBEDTLS_RSA_C
+#define MBEDTLS_X509_RSASSA_PSS_SUPPORT
+#elif (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA)
+#define MBEDTLS_RSA_C
+#define MBEDTLS_X509_RSASSA_PSS_SUPPORT
+#define MBEDTLS_ECDSA_C
+#define MBEDTLS_ECP_C
+#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#endif
#define MBEDTLS_SHA256_C
+#if (TF_MBEDTLS_HASH_ALG_ID != TF_MBEDTLS_SHA256)
+#define MBEDTLS_SHA512_C
+#endif
#define MBEDTLS_VERSION_C
@@ -69,12 +86,13 @@
#define MBEDTLS_MPI_WINDOW_SIZE 2
#define MBEDTLS_MPI_MAX_SIZE 256
-/* System headers required to build mbed TLS with the current configuration */
-#include <stdlib.h>
-
/* Memory buffer allocator options */
#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 8
+#ifndef __ASSEMBLY__
+/* System headers required to build mbed TLS with the current configuration */
+#include <stdlib.h>
#include "mbedtls/check_config.h"
+#endif
#endif /* __MBEDTLS_CONFIG_H__ */
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
index 5fbb83a6..4d2a5fc9 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -44,6 +44,7 @@
(((mpidr) >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK)
#define MPIDR_AFFLVL2_VAL(mpidr) \
(((mpidr) >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK)
+#define MPIDR_AFFLVL3_VAL(mpidr) 0
/*
* The MPIDR_MAX_AFFLVL count starts from 0. Take care to
@@ -77,6 +78,11 @@
/* CSSELR definitions */
#define LEVEL_SHIFT 1
+/* ID_PFR0 definitions */
+#define ID_PFR0_AMU_SHIFT U(20)
+#define ID_PFR0_AMU_LENGTH U(4)
+#define ID_PFR0_AMU_MASK U(0xf)
+
/* ID_PFR1 definitions */
#define ID_PFR1_VIRTEXT_SHIFT 12
#define ID_PFR1_VIRTEXT_MASK 0xf
@@ -86,15 +92,21 @@
#define ID_PFR1_GIC_MASK 0xf
/* SCTLR definitions */
-#define SCTLR_RES1 ((1 << 23) | (1 << 22) | (1 << 11) | (1 << 4) | \
- (1 << 3))
+#define SCTLR_RES1_DEF ((1 << 23) | (1 << 22) | (1 << 4) | (1 << 3))
+#if ARM_ARCH_MAJOR == 7
+#define SCTLR_RES1 SCTLR_RES1_DEF
+#else
+#define SCTLR_RES1 (SCTLR_RES1_DEF | (1 << 11))
+#endif
#define SCTLR_M_BIT (1 << 0)
#define SCTLR_A_BIT (1 << 1)
#define SCTLR_C_BIT (1 << 2)
#define SCTLR_CP15BEN_BIT (1 << 5)
#define SCTLR_ITD_BIT (1 << 7)
+#define SCTLR_Z_BIT (1 << 11)
#define SCTLR_I_BIT (1 << 12)
#define SCTLR_V_BIT (1 << 13)
+#define SCTLR_RR_BIT (1 << 14)
#define SCTLR_NTWI_BIT (1 << 16)
#define SCTLR_NTWE_BIT (1 << 18)
#define SCTLR_WXN_BIT (1 << 19)
@@ -180,6 +192,7 @@
/* HCPTR definitions */
#define HCPTR_RES1 ((1 << 13) | (1<<12) | 0x3ff)
#define TCPAC_BIT (1 << 31)
+#define TAM_BIT (1 << 30)
#define TTA_BIT (1 << 20)
#define TCP11_BIT (1 << 10)
#define TCP10_BIT (1 << 10)
@@ -350,6 +363,8 @@
#define PMCR_N_SHIFT 11
#define PMCR_N_MASK 0x1f
#define PMCR_N_BITS (PMCR_N_MASK << PMCR_N_SHIFT)
+#define PMCR_LC_BIT (1 << 6)
+#define PMCR_DP_BIT (1 << 5)
/*******************************************************************************
* Definitions of register offsets, fields and macros for CPU system
@@ -382,6 +397,7 @@
/* System register defines The format is: coproc, opt1, CRn, CRm, opt2 */
#define SCR p15, 0, c1, c1, 0
#define SCTLR p15, 0, c1, c0, 0
+#define ACTLR p15, 0, c1, c0, 1
#define SDCR p15, 0, c1, c3, 1
#define MPIDR p15, 0, c0, c0, 5
#define MIDR p15, 0, c0, c0, 0
@@ -397,6 +413,7 @@
#define DCISW p15, 0, c7, c6, 2
#define CTR p15, 0, c0, c0, 1
#define CNTFRQ p15, 0, c14, c0, 0
+#define ID_PFR0 p15, 0, c0, c1, 0
#define ID_PFR1 p15, 0, c0, c1, 1
#define MAIR0 p15, 0, c10, c2, 0
#define MAIR1 p15, 0, c10, c2, 1
@@ -428,6 +445,11 @@
#define PMCR p15, 0, c9, c12, 0
#define CNTHP_CTL p15, 4, c14, c2, 1
+/* AArch32 coproc registers for 32bit MMU descriptor support */
+#define PRRR p15, 0, c10, c2, 0
+#define NMRR p15, 0, c10, c2, 1
+#define DACR p15, 0, c3, c0, 0
+
/* GICv3 CPU Interface system register defines. The format is: coproc, opt1, CRn, CRm, opt2 */
#define ICC_IAR1 p15, 0, c12, c12, 0
#define ICC_IAR0 p15, 0, c12, c8, 0
@@ -510,4 +532,28 @@
#define MAKE_MAIR_NORMAL_MEMORY(inner, outer) ((inner) | ((outer) << MAIR_NORM_OUTER_SHIFT))
+/*******************************************************************************
+ * Definitions for system register interface to AMU for ARMv8.4 onwards
+ ******************************************************************************/
+#define AMCR p15, 0, c13, c2, 0
+#define AMCFGR p15, 0, c13, c2, 1
+#define AMCGCR p15, 0, c13, c2, 2
+#define AMUSERENR p15, 0, c13, c2, 3
+#define AMCNTENCLR0 p15, 0, c13, c2, 4
+#define AMCNTENSET0 p15, 0, c13, c2, 5
+#define AMCNTENCLR1 p15, 0, c13, c3, 0
+#define AMCNTENSET1 p15, 0, c13, c1, 1
+
+/* Activity Monitor Group 0 Event Counter Registers */
+#define AMEVCNTR00 p15, 0, c0
+#define AMEVCNTR01 p15, 1, c0
+#define AMEVCNTR02 p15, 2, c0
+#define AMEVCNTR03 p15, 3, c0
+
+/* Activity Monitor Group 0 Event Type Registers */
+#define AMEVTYPER00 p15, 0, c13, c6, 0
+#define AMEVTYPER01 p15, 0, c13, c6, 1
+#define AMEVTYPER02 p15, 0, c13, c6, 2
+#define AMEVTYPER03 p15, 0, c13, c6, 3
+
#endif /* __ARCH_H__ */
diff --git a/include/lib/aarch32/arch_helpers.h b/include/lib/aarch32/arch_helpers.h
index 5d318360..0230195a 100644
--- a/include/lib/aarch32/arch_helpers.h
+++ b/include/lib/aarch32/arch_helpers.h
@@ -213,6 +213,7 @@ DEFINE_SYSOP_TYPE_FUNC(dmb, ld)
DEFINE_SYSOP_TYPE_FUNC(dsb, ish)
DEFINE_SYSOP_TYPE_FUNC(dsb, ishst)
DEFINE_SYSOP_TYPE_FUNC(dmb, ish)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ishst)
DEFINE_SYSOP_FUNC(isb)
void __dead2 smc(uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3,
@@ -226,6 +227,7 @@ DEFINE_SYSREG_RW_FUNCS(cpsr)
******************************************************************************/
DEFINE_COPROCR_READ_FUNC(mpidr, MPIDR)
DEFINE_COPROCR_READ_FUNC(midr, MIDR)
+DEFINE_COPROCR_READ_FUNC(id_pfr0, ID_PFR0)
DEFINE_COPROCR_READ_FUNC(id_pfr1, ID_PFR1)
DEFINE_COPROCR_READ_FUNC(isr, ISR)
DEFINE_COPROCR_READ_FUNC(clidr, CLIDR)
@@ -234,6 +236,7 @@ DEFINE_COPROCR_READ_FUNC_64(cntpct, CNTPCT_64)
DEFINE_COPROCR_RW_FUNCS(scr, SCR)
DEFINE_COPROCR_RW_FUNCS(ctr, CTR)
DEFINE_COPROCR_RW_FUNCS(sctlr, SCTLR)
+DEFINE_COPROCR_RW_FUNCS(actlr, ACTLR)
DEFINE_COPROCR_RW_FUNCS(hsctlr, HSCTLR)
DEFINE_COPROCR_RW_FUNCS(hcr, HCR)
DEFINE_COPROCR_RW_FUNCS(hcptr, HCPTR)
@@ -257,6 +260,7 @@ DEFINE_COPROCR_RW_FUNCS(icc_sre_el1, ICC_SRE)
DEFINE_COPROCR_RW_FUNCS(icc_sre_el2, ICC_HSRE)
DEFINE_COPROCR_RW_FUNCS(icc_sre_el3, ICC_MSRE)
DEFINE_COPROCR_RW_FUNCS(icc_pmr_el1, ICC_PMR)
+DEFINE_COPROCR_RW_FUNCS(icc_rpr_el1, ICC_RPR)
DEFINE_COPROCR_RW_FUNCS(icc_igrpen1_el3, ICC_MGRPEN1)
DEFINE_COPROCR_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0)
DEFINE_COPROCR_RW_FUNCS(icc_hppir0_el1, ICC_HPPIR0)
@@ -265,11 +269,24 @@ DEFINE_COPROCR_RW_FUNCS(icc_iar0_el1, ICC_IAR0)
DEFINE_COPROCR_RW_FUNCS(icc_iar1_el1, ICC_IAR1)
DEFINE_COPROCR_RW_FUNCS(icc_eoir0_el1, ICC_EOIR0)
DEFINE_COPROCR_RW_FUNCS(icc_eoir1_el1, ICC_EOIR1)
+DEFINE_COPROCR_RW_FUNCS_64(icc_sgi0r_el1, ICC_SGI0R_EL1_64)
DEFINE_COPROCR_RW_FUNCS(hdcr, HDCR)
DEFINE_COPROCR_RW_FUNCS(cnthp_ctl, CNTHP_CTL)
DEFINE_COPROCR_READ_FUNC(pmcr, PMCR)
+DEFINE_COPROCR_RW_FUNCS(nsacr, NSACR)
+
+/* AArch32 coproc registers for 32bit MMU descriptor support */
+DEFINE_COPROCR_RW_FUNCS(prrr, PRRR)
+DEFINE_COPROCR_RW_FUNCS(nmrr, NMRR)
+DEFINE_COPROCR_RW_FUNCS(dacr, DACR)
+
+DEFINE_COPROCR_RW_FUNCS(amcntenset0, AMCNTENSET0)
+DEFINE_COPROCR_RW_FUNCS(amcntenset1, AMCNTENSET1)
+DEFINE_COPROCR_RW_FUNCS(amcntenclr0, AMCNTENCLR0)
+DEFINE_COPROCR_RW_FUNCS(amcntenclr1, AMCNTENCLR1)
+
/*
* TLBI operation prototypes
*/
@@ -293,6 +310,7 @@ DEFINE_DCOP_PARAM_FUNC(cvac, DCCMVAC)
/* Previously defined accessor functions with incomplete register names */
#define dsb() dsbsy()
+#define dmb() dmbsy()
#define IS_IN_SECURE() \
(GET_NS_BIT(read_scr()) == 0)
@@ -324,4 +342,7 @@ DEFINE_DCOP_PARAM_FUNC(cvac, DCCMVAC)
#define read_ctr_el0() read_ctr()
+#define write_icc_sgi0r_el1(_v) \
+ write64_icc_sgi0r_el1(_v)
+
#endif /* __ARCH_HELPERS_H__ */
diff --git a/include/lib/aarch32/smcc_helpers.h b/include/lib/aarch32/smcc_helpers.h
index 1bc84381..53f1aa4a 100644
--- a/include/lib/aarch32/smcc_helpers.h
+++ b/include/lib/aarch32/smcc_helpers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -21,7 +21,8 @@
#define SMC_CTX_SP_MON 0x7C
#define SMC_CTX_LR_MON 0x80
#define SMC_CTX_SCR 0x84
-#define SMC_CTX_SIZE 0x88
+#define SMC_CTX_PMCR 0x88
+#define SMC_CTX_SIZE 0x8C
#ifndef __ASSEMBLY__
#include <cassert.h>
@@ -73,6 +74,7 @@ typedef struct smc_ctx {
u_register_t sp_mon;
u_register_t lr_mon;
u_register_t scr;
+ u_register_t pmcr;
} smc_ctx_t;
/*
diff --git a/include/lib/aarch32/smcc_macros.S b/include/lib/aarch32/smcc_macros.S
index 7edf4106..93f211f7 100644
--- a/include/lib/aarch32/smcc_macros.S
+++ b/include/lib/aarch32/smcc_macros.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,6 +13,8 @@
* spsr, lr, sp registers and the `scr` register to the SMC context on entry
* due a SMC call. The `lr` of the current mode (monitor) is expected to be
* already saved. The `sp` must point to the `smc_ctx_t` to save to.
+ * Additionally, also save the 'pmcr' register as this is updated whilst
+ * executing in the secure world.
*/
.macro smcc_save_gp_mode_regs
/* Save r0 - r12 in the SMC context */
@@ -20,6 +22,44 @@
mov r0, sp
add r0, r0, #SMC_CTX_SP_USR
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+ /* Must be in secure state to restore Monitor mode */
+ ldcopr r4, SCR
+ bic r2, r4, #SCR_NS_BIT
+ stcopr r2, SCR
+ isb
+
+ cps #MODE32_sys
+ stm r0!, {sp, lr}
+
+ cps #MODE32_irq
+ mrs r2, spsr
+ stm r0!, {r2, sp, lr}
+
+ cps #MODE32_fiq
+ mrs r2, spsr
+ stm r0!, {r2, sp, lr}
+
+ cps #MODE32_svc
+ mrs r2, spsr
+ stm r0!, {r2, sp, lr}
+
+ cps #MODE32_abt
+ mrs r2, spsr
+ stm r0!, {r2, sp, lr}
+
+ cps #MODE32_und
+ mrs r2, spsr
+ stm r0!, {r2, sp, lr}
+
+ /* lr_mon is already saved by caller */
+ cps #MODE32_mon
+ mrs r2, spsr
+ stm r0!, {r2}
+
+ stcopr r4, SCR
+ isb
+#else
/* Save the banked registers including the current SPSR and LR */
mrs r4, sp_usr
mrs r5, lr_usr
@@ -42,10 +82,13 @@
mrs r11, lr_und
mrs r12, spsr
stm r0!, {r4-r12}
-
/* lr_mon is already saved by caller */
+
ldcopr r4, SCR
+#endif
str r4, [sp, #SMC_CTX_SCR]
+ ldcopr r4, PMCR
+ str r4, [sp, #SMC_CTX_PMCR]
.endm
/*
@@ -70,8 +113,52 @@
stcopr r1, SCR
isb
+ /*
+ * Restore the PMCR register.
+ */
+ ldr r1, [r0, #SMC_CTX_PMCR]
+ stcopr r1, PMCR
+
/* Restore the banked registers including the current SPSR */
add r1, r0, #SMC_CTX_SP_USR
+
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+ /* Must be in secure state to restore Monitor mode */
+ ldcopr r4, SCR
+ bic r2, r4, #SCR_NS_BIT
+ stcopr r2, SCR
+ isb
+
+ cps #MODE32_sys
+ ldm r1!, {sp, lr}
+
+ cps #MODE32_irq
+ ldm r1!, {r2, sp, lr}
+ msr spsr_fsxc, r2
+
+ cps #MODE32_fiq
+ ldm r1!, {r2, sp, lr}
+ msr spsr_fsxc, r2
+
+ cps #MODE32_svc
+ ldm r1!, {r2, sp, lr}
+ msr spsr_fsxc, r2
+
+ cps #MODE32_abt
+ ldm r1!, {r2, sp, lr}
+ msr spsr_fsxc, r2
+
+ cps #MODE32_und
+ ldm r1!, {r2, sp, lr}
+ msr spsr_fsxc, r2
+
+ cps #MODE32_mon
+ ldm r1!, {r2}
+ msr spsr_fsxc, r2
+
+ stcopr r4, SCR
+ isb
+#else
ldm r1!, {r4-r12}
msr sp_usr, r4
msr lr_usr, r5
@@ -99,6 +186,7 @@
* f->[31:24] and c->[7:0] bits of SPSR.
*/
msr spsr_fsxc, r12
+#endif
/* Restore the LR */
ldr lr, [r0, #SMC_CTX_LR_MON]
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index e38a5307..96e2d5fe 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -68,6 +68,7 @@
#define ICC_CTLR_EL1 S3_0_C12_C12_4
#define ICC_CTLR_EL3 S3_6_C12_C12_4
#define ICC_PMR_EL1 S3_0_C4_C6_0
+#define ICC_RPR_EL1 S3_0_C12_C11_3
#define ICC_IGRPEN1_EL3 S3_6_c12_c12_7
#define ICC_IGRPEN0_EL1 S3_0_c12_c12_6
#define ICC_HPPIR0_EL1 S3_0_c12_c8_2
@@ -76,6 +77,7 @@
#define ICC_IAR1_EL1 S3_0_c12_c12_0
#define ICC_EOIR0_EL1 S3_0_c12_c8_1
#define ICC_EOIR1_EL1 S3_0_c12_c12_1
+#define ICC_SGI0R_EL1 S3_0_c12_c11_7
/*******************************************************************************
* Generic timer memory mapped registers & offsets
@@ -108,7 +110,13 @@
#define ID_AA64PFR0_EL1_SHIFT U(4)
#define ID_AA64PFR0_EL2_SHIFT U(8)
#define ID_AA64PFR0_EL3_SHIFT U(12)
+#define ID_AA64PFR0_AMU_SHIFT U(44)
+#define ID_AA64PFR0_AMU_LENGTH U(4)
+#define ID_AA64PFR0_AMU_MASK U(0xf)
#define ID_AA64PFR0_ELX_MASK U(0xf)
+#define ID_AA64PFR0_SVE_SHIFT U(32)
+#define ID_AA64PFR0_SVE_MASK U(0xf)
+#define ID_AA64PFR0_SVE_LENGTH U(4)
/* ID_AA64DFR0_EL1.PMS definitions (for ARMv8.2+) */
#define ID_AA64DFR0_PMS_SHIFT U(32)
@@ -124,6 +132,7 @@
#define ID_AA64PFR0_GIC_MASK ((U(1) << ID_AA64PFR0_GIC_WIDTH) - 1)
/* ID_AA64MMFR0_EL1 definitions */
+#define ID_AA64MMFR0_EL1_PARANGE_SHIFT U(0)
#define ID_AA64MMFR0_EL1_PARANGE_MASK U(0xf)
#define PARANGE_0000 U(32)
@@ -132,6 +141,22 @@
#define PARANGE_0011 U(42)
#define PARANGE_0100 U(44)
#define PARANGE_0101 U(48)
+#define PARANGE_0110 U(52)
+
+#define ID_AA64MMFR0_EL1_TGRAN4_SHIFT U(28)
+#define ID_AA64MMFR0_EL1_TGRAN4_MASK U(0xf)
+#define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED U(0x0)
+#define ID_AA64MMFR0_EL1_TGRAN4_NOT_SUPPORTED U(0xf)
+
+#define ID_AA64MMFR0_EL1_TGRAN64_SHIFT U(24)
+#define ID_AA64MMFR0_EL1_TGRAN64_MASK U(0xf)
+#define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED U(0x0)
+#define ID_AA64MMFR0_EL1_TGRAN64_NOT_SUPPORTED U(0xf)
+
+#define ID_AA64MMFR0_EL1_TGRAN16_SHIFT U(20)
+#define ID_AA64MMFR0_EL1_TGRAN16_MASK U(0xf)
+#define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED U(0x1)
+#define ID_AA64MMFR0_EL1_TGRAN16_NOT_SUPPORTED U(0x0)
/* ID_PFR1_EL1 definitions */
#define ID_PFR1_VIRTEXT_SHIFT U(12)
@@ -158,12 +183,25 @@
#define SCTLR_A_BIT (U(1) << 1)
#define SCTLR_C_BIT (U(1) << 2)
#define SCTLR_SA_BIT (U(1) << 3)
+#define SCTLR_SA0_BIT (U(1) << 4)
#define SCTLR_CP15BEN_BIT (U(1) << 5)
+#define SCTLR_ITD_BIT (U(1) << 7)
+#define SCTLR_SED_BIT (U(1) << 8)
+#define SCTLR_UMA_BIT (U(1) << 9)
#define SCTLR_I_BIT (U(1) << 12)
+#define SCTLR_V_BIT (U(1) << 13)
+#define SCTLR_DZE_BIT (U(1) << 14)
+#define SCTLR_UCT_BIT (U(1) << 15)
#define SCTLR_NTWI_BIT (U(1) << 16)
#define SCTLR_NTWE_BIT (U(1) << 18)
#define SCTLR_WXN_BIT (U(1) << 19)
+#define SCTLR_UWXN_BIT (U(1) << 20)
+#define SCTLR_E0E_BIT (U(1) << 24)
#define SCTLR_EE_BIT (U(1) << 25)
+#define SCTLR_UCI_BIT (U(1) << 26)
+#define SCTLR_TRE_BIT (U(1) << 28)
+#define SCTLR_AFE_BIT (U(1) << 29)
+#define SCTLR_TE_BIT (U(1) << 30)
#define SCTLR_RESET_VAL SCTLR_EL3_RES1
/* CPACR_El1 definitions */
@@ -263,15 +301,19 @@
/* CPTR_EL3 definitions */
#define TCPAC_BIT (U(1) << 31)
+#define TAM_BIT (U(1) << 30)
#define TTA_BIT (U(1) << 20)
#define TFP_BIT (U(1) << 10)
+#define CPTR_EZ_BIT (U(1) << 8)
#define CPTR_EL3_RESET_VAL U(0x0)
/* CPTR_EL2 definitions */
#define CPTR_EL2_RES1 ((U(1) << 13) | (U(1) << 12) | (U(0x3ff)))
#define CPTR_EL2_TCPAC_BIT (U(1) << 31)
+#define CPTR_EL2_TAM_BIT (U(1) << 30)
#define CPTR_EL2_TTA_BIT (U(1) << 20)
#define CPTR_EL2_TFP_BIT (U(1) << 10)
+#define CPTR_EL2_TZ_BIT (U(1) << 8)
#define CPTR_EL2_RESET_VAL CPTR_EL2_RES1
/* CPSR/SPSR definitions */
@@ -312,7 +354,7 @@
/*
* TCR defintions
*/
-#define TCR_EL3_RES1 ((1UL << 31) | (1UL << 23))
+#define TCR_EL3_RES1 ((U(1) << 31) | (U(1) << 23))
#define TCR_EL1_IPS_SHIFT U(32)
#define TCR_EL3_PS_SHIFT U(16)
@@ -348,6 +390,15 @@
#define TCR_SH_OUTER_SHAREABLE (U(0x2) << 12)
#define TCR_SH_INNER_SHAREABLE (U(0x3) << 12)
+#define TCR_TG0_SHIFT U(14)
+#define TCR_TG0_MASK U(3)
+#define TCR_TG0_4K (ULL(0) << TCR_TG0_SHIFT)
+#define TCR_TG0_64K (ULL(1) << TCR_TG0_SHIFT)
+#define TCR_TG0_16K (ULL(2) << TCR_TG0_SHIFT)
+
+#define TCR_EPD0_BIT (U(1) << 7)
+#define TCR_EPD1_BIT (U(1) << 23)
+
#define MODE_SP_SHIFT U(0x0)
#define MODE_SP_MASK U(0x1)
#define MODE_SP_EL0 U(0x0)
@@ -500,9 +551,26 @@
#define CNTACR_RWPT_SHIFT U(0x5)
/* PMCR_EL0 definitions */
+#define PMCR_EL0_RESET_VAL U(0x0)
#define PMCR_EL0_N_SHIFT U(11)
#define PMCR_EL0_N_MASK U(0x1f)
#define PMCR_EL0_N_BITS (PMCR_EL0_N_MASK << PMCR_EL0_N_SHIFT)
+#define PMCR_EL0_LC_BIT (U(1) << 6)
+#define PMCR_EL0_DP_BIT (U(1) << 5)
+#define PMCR_EL0_X_BIT (U(1) << 4)
+#define PMCR_EL0_D_BIT (U(1) << 3)
+
+/*******************************************************************************
+ * Definitions for system register interface to SVE
+ ******************************************************************************/
+#define ZCR_EL3 S3_6_C1_C2_0
+#define ZCR_EL2 S3_4_C1_C2_0
+
+/* ZCR_EL3 definitions */
+#define ZCR_EL3_LEN_MASK U(0xf)
+
+/* ZCR_EL2 definitions */
+#define ZCR_EL2_LEN_MASK U(0xf)
/*******************************************************************************
* Definitions of MAIR encodings for device and normal memory
@@ -553,4 +621,39 @@
#define MAKE_MAIR_NORMAL_MEMORY(inner, outer) ((inner) | ((outer) << MAIR_NORM_OUTER_SHIFT))
+/* PAR_EL1 fields */
+#define PAR_F_SHIFT 0
+#define PAR_F_MASK 1
+#define PAR_ADDR_SHIFT 12
+#define PAR_ADDR_MASK (BIT(40) - 1) /* 40-bits-wide page address */
+
+/*******************************************************************************
+ * Definitions for system register interface to SPE
+ ******************************************************************************/
+#define PMBLIMITR_EL1 S3_0_C9_C10_0
+
+/*******************************************************************************
+ * Definitions for system register interface to AMU for ARMv8.4 onwards
+ ******************************************************************************/
+#define AMCR_EL0 S3_3_C13_C2_0
+#define AMCFGR_EL0 S3_3_C13_C2_1
+#define AMCGCR_EL0 S3_3_C13_C2_2
+#define AMUSERENR_EL0 S3_3_C13_C2_3
+#define AMCNTENCLR0_EL0 S3_3_C13_C2_4
+#define AMCNTENSET0_EL0 S3_3_C13_C2_5
+#define AMCNTENCLR1_EL0 S3_3_C13_C3_0
+#define AMCNTENSET1_EL0 S3_3_C13_C3_1
+
+/* Activity Monitor Group 0 Event Counter Registers */
+#define AMEVCNTR00_EL0 S3_3_C13_C4_0
+#define AMEVCNTR01_EL0 S3_3_C13_C4_1
+#define AMEVCNTR02_EL0 S3_3_C13_C4_2
+#define AMEVCNTR03_EL0 S3_3_C13_C4_3
+
+/* Activity Monitor Group 0 Event Type Registers */
+#define AMEVTYPER00_EL0 S3_3_C13_C6_0
+#define AMEVTYPER01_EL0 S3_3_C13_C6_1
+#define AMEVTYPER02_EL0 S3_3_C13_C6_2
+#define AMEVTYPER03_EL0 S3_3_C13_C6_3
+
#endif /* __ARCH_H__ */
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index 0d0d7d33..831dfb06 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -31,11 +31,8 @@ static inline void write_ ## _name(uint64_t v) \
__asm__ volatile ("msr " #_reg_name ", %0" : : "r" (v)); \
}
-#define _DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _reg_name) \
-static inline void write_ ## _name(const uint64_t v) \
-{ \
- __asm__ volatile ("msr " #_reg_name ", %0" : : "i" (v)); \
-}
+#define SYSREG_WRITE_CONST(reg_name, v) \
+ __asm__ volatile ("msr " #reg_name ", %0" : : "i" (v))
/* Define read function for system register */
#define DEFINE_SYSREG_READ_FUNC(_name) \
@@ -59,11 +56,6 @@ static inline void write_ ## _name(const uint64_t v) \
#define DEFINE_RENAME_SYSREG_WRITE_FUNC(_name, _reg_name) \
_DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)
-/* Define write function for special system registers */
-#define DEFINE_SYSREG_WRITE_CONST_FUNC(_name) \
- _DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _name)
-
-
/**********************************************************************
* Macros to create inline functions for system instructions
*********************************************************************/
@@ -163,6 +155,7 @@ DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1r)
DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1w)
DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0r)
DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0w)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s1e2r)
void flush_dcache_range(uintptr_t addr, size_t size);
void clean_dcache_range(uintptr_t addr, size_t size);
@@ -171,15 +164,17 @@ void inv_dcache_range(uintptr_t addr, size_t size);
void dcsw_op_louis(u_register_t op_type);
void dcsw_op_all(u_register_t op_type);
+void disable_mmu_el1(void);
void disable_mmu_el3(void);
+void disable_mmu_icache_el1(void);
void disable_mmu_icache_el3(void);
/*******************************************************************************
* Misc. accessor prototypes
******************************************************************************/
-DEFINE_SYSREG_WRITE_CONST_FUNC(daifset)
-DEFINE_SYSREG_WRITE_CONST_FUNC(daifclr)
+#define write_daifclr(val) SYSREG_WRITE_CONST(daifclr, val)
+#define write_daifset(val) SYSREG_WRITE_CONST(daifset, val)
DEFINE_SYSREG_READ_FUNC(par_el1)
DEFINE_SYSREG_READ_FUNC(id_pfr1_el1)
@@ -202,8 +197,10 @@ DEFINE_SYSOP_TYPE_FUNC(dmb, sy)
DEFINE_SYSOP_TYPE_FUNC(dmb, st)
DEFINE_SYSOP_TYPE_FUNC(dmb, ld)
DEFINE_SYSOP_TYPE_FUNC(dsb, ish)
+DEFINE_SYSOP_TYPE_FUNC(dsb, nsh)
DEFINE_SYSOP_TYPE_FUNC(dsb, ishst)
DEFINE_SYSOP_TYPE_FUNC(dmb, ish)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ishst)
DEFINE_SYSOP_FUNC(isb)
uint32_t get_afflvl_shift(uint32_t);
@@ -305,14 +302,16 @@ DEFINE_SYSREG_READ_FUNC(isr_el1)
DEFINE_SYSREG_READ_FUNC(ctr_el0)
DEFINE_SYSREG_RW_FUNCS(mdcr_el2)
+DEFINE_SYSREG_RW_FUNCS(mdcr_el3)
DEFINE_SYSREG_RW_FUNCS(hstr_el2)
DEFINE_SYSREG_RW_FUNCS(cnthp_ctl_el2)
-DEFINE_SYSREG_READ_FUNC(pmcr_el0)
+DEFINE_SYSREG_RW_FUNCS(pmcr_el0)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el1, ICC_SRE_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el2, ICC_SRE_EL2)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el3, ICC_SRE_EL3)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_pmr_el1, ICC_PMR_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(icc_rpr_el1, ICC_RPR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen1_el3, ICC_IGRPEN1_EL3)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0_EL1)
DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir0_el1, ICC_HPPIR0_EL1)
@@ -321,7 +320,17 @@ DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar0_el1, ICC_IAR0_EL1)
DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar1_el1, ICC_IAR1_EL1)
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir0_el1, ICC_EOIR0_EL1)
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1)
+DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_sgi0r_el1, ICC_SGI0R_EL1)
+
+DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenclr0_el0, AMCNTENCLR0_EL0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset0_el0, AMCNTENSET0_EL0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenclr1_el0, AMCNTENCLR1_EL0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset1_el0, AMCNTENSET1_EL0)
+
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmblimitr_el1, PMBLIMITR_EL1)
+DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el3, ZCR_EL3)
+DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el2, ZCR_EL2)
#define IS_IN_EL(x) \
(GET_EL(read_CurrentEl()) == MODE_EL##x)
diff --git a/include/lib/cpus/aarch32/cortex_a12.h b/include/lib/cpus/aarch32/cortex_a12.h
new file mode 100644
index 00000000..3068a41f
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a12.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CORTEX_A12_H__
+#define __CORTEX_A12_H__
+
+/*******************************************************************************
+ * Cortex-A12 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A12_MIDR 0x410FC0C0
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A12_ACTLR_SMP_BIT (1 << 6)
+
+#endif /* __CORTEX_A12_H__ */
diff --git a/include/lib/cpus/aarch32/cortex_a15.h b/include/lib/cpus/aarch32/cortex_a15.h
new file mode 100644
index 00000000..905c139d
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a15.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CORTEX_A15_H__
+#define __CORTEX_A15_H__
+
+/*******************************************************************************
+ * Cortex-A15 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A15_MIDR 0x410FC0F0
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A15_ACTLR_SMP_BIT (1 << 6)
+
+#endif /* __CORTEX_A15_H__ */
diff --git a/include/lib/cpus/aarch32/cortex_a17.h b/include/lib/cpus/aarch32/cortex_a17.h
new file mode 100644
index 00000000..d2ca91c4
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a17.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CORTEX_A17_H__
+#define __CORTEX_A17_H__
+
+/*******************************************************************************
+ * Cortex-A17 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A17_MIDR 0x410FC0E0
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A17_ACTLR_SMP_BIT (1 << 6)
+
+#endif /* __CORTEX_A17_H__ */
diff --git a/include/lib/cpus/aarch32/cortex_a5.h b/include/lib/cpus/aarch32/cortex_a5.h
new file mode 100644
index 00000000..0a0b7ffa
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a5.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CORTEX_A5_H__
+#define __CORTEX_A5_H__
+
+/*******************************************************************************
+ * Cortex-A8 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A5_MIDR 0x410FC050
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A5_ACTLR_SMP_BIT (1 << 6)
+
+#endif /* __CORTEX_A5_H__ */
diff --git a/include/lib/cpus/aarch32/cortex_a7.h b/include/lib/cpus/aarch32/cortex_a7.h
new file mode 100644
index 00000000..61b0d008
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a7.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CORTEX_A7_H__
+#define __CORTEX_A7_H__
+
+/*******************************************************************************
+ * Cortex-A7 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A7_MIDR 0x410FC070
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A7_ACTLR_SMP_BIT (1 << 6)
+
+#endif /* __CORTEX_A7_H__ */
diff --git a/include/lib/cpus/aarch32/cortex_a9.h b/include/lib/cpus/aarch32/cortex_a9.h
new file mode 100644
index 00000000..be85f9be
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a9.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CORTEX_A9_H__
+#define __CORTEX_A9_H__
+
+/*******************************************************************************
+ * Cortex-A9 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A9_MIDR 0x410FC090
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A9_ACTLR_SMP_BIT (1 << 6)
+#define CORTEX_A9_ACTLR_FLZW_BIT (1 << 3)
+
+/*******************************************************************************
+ * CPU Power Control Register
+ ******************************************************************************/
+#define PCR p15, 0, c15, c0, 0
+
+#ifndef __ASSEMBLY__
+#include <arch_helpers.h>
+DEFINE_COPROCR_RW_FUNCS(pcr, PCR)
+#endif
+
+#endif /* __CORTEX_A9_H__ */
diff --git a/include/lib/cpus/aarch64/cortex_a75.h b/include/lib/cpus/aarch64/cortex_a75.h
index 1ffe20bb..d68c9572 100644
--- a/include/lib/cpus/aarch64/cortex_a75.h
+++ b/include/lib/cpus/aarch64/cortex_a75.h
@@ -19,4 +19,38 @@
/* Definitions of register field mask in CORTEX_A75_CPUPWRCTLR_EL1 */
#define CORTEX_A75_CORE_PWRDN_EN_MASK 0x1
+/*******************************************************************************
+ * CPU Activity Monitor Unit register specific definitions.
+ ******************************************************************************/
+#define CPUAMCNTENCLR_EL0 S3_3_C15_C9_7
+#define CPUAMCNTENSET_EL0 S3_3_C15_C9_6
+#define CPUAMCFGR_EL0 S3_3_C15_C10_6
+#define CPUAMUSERENR_EL0 S3_3_C15_C10_7
+
+/* Activity Monitor Event Counter Registers */
+#define CPUAMEVCNTR0_EL0 S3_3_C15_C9_0
+#define CPUAMEVCNTR1_EL0 S3_3_C15_C9_1
+#define CPUAMEVCNTR2_EL0 S3_3_C15_C9_2
+#define CPUAMEVCNTR3_EL0 S3_3_C15_C9_3
+#define CPUAMEVCNTR4_EL0 S3_3_C15_C9_4
+
+/* Activity Monitor Event Type Registers */
+#define CPUAMEVTYPER0_EL0 S3_3_C15_C10_0
+#define CPUAMEVTYPER1_EL0 S3_3_C15_C10_1
+#define CPUAMEVTYPER2_EL0 S3_3_C15_C10_2
+#define CPUAMEVTYPER3_EL0 S3_3_C15_C10_3
+#define CPUAMEVTYPER4_EL0 S3_3_C15_C10_4
+
+#define CORTEX_A75_ACTLR_AMEN_BIT (U(1) << 4)
+
+/*
+ * The Cortex-A75 core implements five counters, 0-4. Events 0, 1, 2, are
+ * fixed and are enabled (Group 0). Events 3 and 4 (Group 1) are
+ * programmable by programming the appropriate Event count bits in
+ * CPUAMEVTYPER<n> register and are disabled by default. Platforms may
+ * enable this with suitable programming.
+ */
+#define CORTEX_A75_AMU_GROUP0_MASK 0x7
+#define CORTEX_A75_AMU_GROUP1_MASK (0 << 3)
+
#endif /* __CORTEX_A75_H__ */
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index dcbf1c9d..58899049 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -87,22 +87,22 @@
#define CTX_AFSR1_EL1 U(0x98)
#define CTX_CONTEXTIDR_EL1 U(0xa0)
#define CTX_VBAR_EL1 U(0xa8)
+#define CTX_PMCR_EL0 U(0xb0)
/*
* If the platform is AArch64-only, there is no need to save and restore these
* AArch32 registers.
*/
#if CTX_INCLUDE_AARCH32_REGS
-#define CTX_SPSR_ABT U(0xb0)
-#define CTX_SPSR_UND U(0xb8)
-#define CTX_SPSR_IRQ U(0xc0)
-#define CTX_SPSR_FIQ U(0xc8)
-#define CTX_DACR32_EL2 U(0xd0)
-#define CTX_IFSR32_EL2 U(0xd8)
-#define CTX_FP_FPEXC32_EL2 U(0xe0)
-#define CTX_TIMER_SYSREGS_OFF U(0xf0) /* Align to the next 16 byte boundary */
+#define CTX_SPSR_ABT U(0xc0) /* Align to the next 16 byte boundary */
+#define CTX_SPSR_UND U(0xc8)
+#define CTX_SPSR_IRQ U(0xd0)
+#define CTX_SPSR_FIQ U(0xd8)
+#define CTX_DACR32_EL2 U(0xe0)
+#define CTX_IFSR32_EL2 U(0xe8)
+#define CTX_TIMER_SYSREGS_OFF U(0xf0) /* Align to the next 16 byte boundary */
#else
-#define CTX_TIMER_SYSREGS_OFF U(0xb0)
+#define CTX_TIMER_SYSREGS_OFF U(0xc0) /* Align to the next 16 byte boundary */
#endif /* __CTX_INCLUDE_AARCH32_REGS__ */
/*
@@ -160,7 +160,12 @@
#define CTX_FP_Q31 U(0x1f0)
#define CTX_FP_FPSR U(0x200)
#define CTX_FP_FPCR U(0x208)
-#define CTX_FPREGS_END U(0x210)
+#if CTX_INCLUDE_AARCH32_REGS
+#define CTX_FP_FPEXC32_EL2 U(0x210)
+#define CTX_FPREGS_END U(0x220) /* Align to the next 16 byte boundary */
+#else
+#define CTX_FPREGS_END U(0x210) /* Align to the next 16 byte boundary */
+#endif
#endif
#ifndef __ASSEMBLY__
@@ -308,7 +313,6 @@ CASSERT(CTX_EL3STATE_OFFSET == __builtin_offsetof(cpu_context_t, el3state_ctx),
* Function prototypes
******************************************************************************/
void el1_sysregs_context_save(el1_sys_regs_t *regs);
-void el1_sysregs_context_save_post_ops(void);
void el1_sysregs_context_restore(el1_sys_regs_t *regs);
#if CTX_INCLUDE_FPREGS
void fpregs_context_save(fp_regs_t *regs);
diff --git a/include/lib/el3_runtime/cpu_data.h b/include/lib/el3_runtime/cpu_data.h
index c0c3a199..3f48de5e 100644
--- a/include/lib/el3_runtime/cpu_data.h
+++ b/include/lib/el3_runtime/cpu_data.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,7 @@
#ifndef __CPU_DATA_H__
#define __CPU_DATA_H__
+#include <ehf.h>
#include <platform_def.h> /* CACHE_WRITEBACK_GRANULE required */
#ifdef AARCH32
@@ -96,6 +97,9 @@ typedef struct cpu_data {
#if PLAT_PCPU_DATA_SIZE
uint8_t platform_cpu_data[PLAT_PCPU_DATA_SIZE];
#endif
+#if defined(IMAGE_BL31) && EL3_EXCEPTION_HANDLING
+ pe_exc_data_t ehf_data;
+#endif
} __aligned(CACHE_WRITEBACK_GRANULE) cpu_data_t;
#if CRASH_REPORTING
@@ -141,17 +145,17 @@ void init_cpu_ops(void);
#define set_cpu_data(_m, _v) _cpu_data()->_m = _v
#define get_cpu_data_by_index(_ix, _m) _cpu_data_by_index(_ix)->_m
#define set_cpu_data_by_index(_ix, _m, _v) _cpu_data_by_index(_ix)->_m = _v
-
+/* ((cpu_data_t *)0)->_m is a dummy to get the sizeof the struct member _m */
#define flush_cpu_data(_m) flush_dcache_range((uintptr_t) \
- &(_cpu_data()->_m), \
- sizeof(_cpu_data()->_m))
+ &(_cpu_data()->_m), \
+ sizeof(((cpu_data_t *)0)->_m))
#define inv_cpu_data(_m) inv_dcache_range((uintptr_t) \
- &(_cpu_data()->_m), \
- sizeof(_cpu_data()->_m))
+ &(_cpu_data()->_m), \
+ sizeof(((cpu_data_t *)0)->_m))
#define flush_cpu_data_by_index(_ix, _m) \
flush_dcache_range((uintptr_t) \
&(_cpu_data_by_index(_ix)->_m), \
- sizeof(_cpu_data_by_index(_ix)->_m))
+ sizeof(((cpu_data_t *)0)->_m))
#endif /* __ASSEMBLY__ */
diff --git a/include/lib/el3_runtime/pubsub.h b/include/lib/el3_runtime/pubsub.h
new file mode 100644
index 00000000..9a854808
--- /dev/null
+++ b/include/lib/el3_runtime/pubsub.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PUBSUB_H__
+#define __PUBSUB_H__
+
+#define __pubsub_start_sym(event) __pubsub_##event##_start
+#define __pubsub_end_sym(event) __pubsub_##event##_end
+
+#ifdef __LINKER__
+
+/* For the linker ... */
+
+#define __pubsub_section(event) __pubsub_##event
+
+/*
+ * REGISTER_PUBSUB_EVENT has a different definition between linker and compiler
+ * contexts. In linker context, this collects pubsub sections for each event,
+ * placing guard symbols around each.
+ */
+#define REGISTER_PUBSUB_EVENT(event) \
+ __pubsub_start_sym(event) = .; \
+ KEEP(*(__pubsub_section(event))); \
+ __pubsub_end_sym(event) = .
+
+#else /* __LINKER__ */
+
+/* For the compiler ... */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <cdefs.h>
+#include <stddef.h>
+
+#define __pubsub_section(event) __section("__pubsub_" #event)
+
+/*
+ * In compiler context, REGISTER_PUBSUB_EVENT declares the per-event symbols
+ * exported by the linker required for the other pubsub macros to work.
+ */
+#define REGISTER_PUBSUB_EVENT(event) \
+ extern pubsub_cb_t __pubsub_start_sym(event)[]; \
+ extern pubsub_cb_t __pubsub_end_sym(event)[]
+
+/*
+ * Have the function func called back when the specified event happens. This
+ * macro places the function address into the pubsub section, which is picked up
+ * and invoked by the invoke_pubsubs() function via. the PUBLISH_EVENT* macros.
+ */
+#define SUBSCRIBE_TO_EVENT(event, func) \
+ pubsub_cb_t __cb_func_##func##event __pubsub_section(event) = func
+
+/*
+ * Iterate over subscribed handlers for a defined event. 'event' is the name of
+ * the event, and 'subscriber' a local variable of type 'pubsub_cb_t *'.
+ */
+#define for_each_subscriber(event, subscriber) \
+ for (subscriber = __pubsub_start_sym(event); \
+ subscriber < __pubsub_end_sym(event); \
+ subscriber++)
+
+/*
+ * Publish a defined event supplying an argument. All subscribed handlers are
+ * invoked, but the return value of handlers are ignored for now.
+ */
+#define PUBLISH_EVENT_ARG(event, arg) \
+ do { \
+ pubsub_cb_t *subscriber; \
+ for_each_subscriber(event, subscriber) { \
+ (*subscriber)(arg); \
+ } \
+ } while (0)
+
+/* Publish a defined event with NULL argument */
+#define PUBLISH_EVENT(event) PUBLISH_EVENT_ARG(event, NULL)
+
+/* Subscriber callback type */
+typedef void* (*pubsub_cb_t)(const void *arg);
+
+#endif /* __LINKER__ */
+#endif /* __PUBSUB_H__ */
diff --git a/include/lib/el3_runtime/pubsub_events.h b/include/lib/el3_runtime/pubsub_events.h
new file mode 100644
index 00000000..9cfedb4d
--- /dev/null
+++ b/include/lib/el3_runtime/pubsub_events.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <pubsub.h>
+
+/*
+ * This file defines a list of pubsub events, declared using
+ * REGISTER_PUBSUB_EVENT() macro.
+ */
+
+/*
+ * Event published after a CPU has been powered up and finished its
+ * initialization.
+ */
+REGISTER_PUBSUB_EVENT(psci_cpu_on_finish);
+
+#ifdef AARCH64
+/*
+ * These events are published by the AArch64 context management framework
+ * after the secure context is restored/saved via
+ * cm_el1_sysregs_context_{restore,save}() API.
+ */
+REGISTER_PUBSUB_EVENT(cm_entering_secure_world);
+REGISTER_PUBSUB_EVENT(cm_exited_secure_world);
+
+/*
+ * These events are published by the AArch64 context management framework
+ * after the normal context is restored/saved via
+ * cm_el1_sysregs_context_{restore,save}() API.
+ */
+REGISTER_PUBSUB_EVENT(cm_entering_normal_world);
+REGISTER_PUBSUB_EVENT(cm_exited_normal_world);
+#endif /* AARCH64 */
diff --git a/include/lib/extensions/amu.h b/include/lib/extensions/amu.h
new file mode 100644
index 00000000..bbefe8ff
--- /dev/null
+++ b/include/lib/extensions/amu.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __AMU_H__
+#define __AMU_H__
+
+/* Enable all group 0 counters */
+#define AMU_GROUP0_COUNTERS_MASK 0xf
+
+void amu_enable(int el2_unused);
+
+#endif /* __AMU_H__ */
diff --git a/include/lib/extensions/spe.h b/include/lib/extensions/spe.h
new file mode 100644
index 00000000..8a74127a
--- /dev/null
+++ b/include/lib/extensions/spe.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SPE_H__
+#define __SPE_H__
+
+void spe_enable(int el2_unused);
+void spe_disable(void);
+
+#endif /* __SPE_H__ */
diff --git a/include/lib/extensions/sve.h b/include/lib/extensions/sve.h
new file mode 100644
index 00000000..28923e3f
--- /dev/null
+++ b/include/lib/extensions/sve.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SVE_H__
+#define __SVE_H__
+
+void sve_enable(int el2_unused);
+
+#endif /* __SVE_H__ */
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
index 0ed39c9a..06434f9e 100644
--- a/include/lib/psci/psci.h
+++ b/include/lib/psci/psci.h
@@ -65,6 +65,11 @@
#define PSCI_STAT_RESIDENCY_AARCH64 U(0xc4000010)
#define PSCI_STAT_COUNT_AARCH32 U(0x84000011)
#define PSCI_STAT_COUNT_AARCH64 U(0xc4000011)
+#define PSCI_SYSTEM_RESET2_AARCH32 U(0x84000012)
+#define PSCI_SYSTEM_RESET2_AARCH64 U(0xc4000012)
+#define PSCI_MEM_PROTECT U(0x84000013)
+#define PSCI_MEM_CHK_RANGE_AARCH32 U(0x84000014)
+#define PSCI_MEM_CHK_RANGE_AARCH64 U(0xc4000014)
/* Macro to help build the psci capabilities bitfield */
#define define_psci_cap(x) (U(1) << (x & U(0x1f)))
@@ -146,7 +151,7 @@
* PSCI version
******************************************************************************/
#define PSCI_MAJOR_VER (U(1) << 16)
-#define PSCI_MINOR_VER U(0x0)
+#define PSCI_MINOR_VER U(0x1)
/*******************************************************************************
* PSCI error codes
@@ -164,6 +169,14 @@
#define PSCI_INVALID_MPIDR ~((u_register_t)0)
+/*
+ * SYSTEM_RESET2 macros
+ */
+#define PSCI_RESET2_TYPE_VENDOR_SHIFT 31
+#define PSCI_RESET2_TYPE_VENDOR (1U << PSCI_RESET2_TYPE_VENDOR_SHIFT)
+#define PSCI_RESET2_TYPE_ARCH (0U << PSCI_RESET2_TYPE_VENDOR_SHIFT)
+#define PSCI_RESET2_SYSTEM_WARM_RESET (PSCI_RESET2_TYPE_ARCH | 0)
+
#ifndef __ASSEMBLY__
#include <stdint.h>
@@ -288,6 +301,11 @@ typedef struct plat_psci_ops {
unsigned int power_state,
psci_power_state_t *output_state);
int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
+ int (*mem_protect_chk)(uintptr_t base, u_register_t length);
+ int (*read_mem_protect)(int *val);
+ int (*write_mem_protect)(int val);
+ int (*system_reset2)(int is_vendor,
+ int reset_type, u_register_t cookie);
} plat_psci_ops_t;
/*******************************************************************************
diff --git a/include/lib/utils.h b/include/lib/utils.h
index b75813f7..cfc83022 100644
--- a/include/lib/utils.h
+++ b/include/lib/utils.h
@@ -19,6 +19,25 @@
#include <types.h>
+typedef struct mem_region_t {
+ uintptr_t base;
+ size_t nbytes;
+} mem_region_t;
+
+/*
+ * zero_normalmem all the regions defined in tbl.
+ */
+void clear_mem_regions(mem_region_t *tbl, size_t nregions);
+
+
+/*
+ * checks that a region (addr + nbytes-1) of memory is totally covered by
+ * one of the regions defined in tbl. Caller must ensure that (addr+nbytes-1)
+ * doesn't overflow.
+ */
+int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
+ uintptr_t addr, size_t nbytes);
+
/*
* Fill a region of normal memory of size "length" in bytes with zero bytes.
*
diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h
index 26ac4409..185a1c12 100644
--- a/include/lib/utils_def.h
+++ b/include/lib/utils_def.h
@@ -16,7 +16,13 @@
#define SIZE_FROM_LOG2_WORDS(n) (4 << (n))
-#define BIT(nr) (1UL << (nr))
+#define BIT(nr) (1ULL << (nr))
+
+/*
+ * This variant of div_round_up can be used in macro definition but should not
+ * be used in C code as the `div` parameter is evaluated twice.
+ */
+#define DIV_ROUND_UP_2EVAL(n, d) (((n) + (d) - 1) / (d))
#define MIN(x, y) __extension__ ({ \
__typeof__(x) _x = (x); \
@@ -49,6 +55,11 @@
#define round_down(value, boundary) \
((value) & ~round_boundary(value, boundary))
+#define div_round_up(val, div) __extension__ ({ \
+ __typeof__(div) _div = (div); \
+ round_up((val), _div)/_div; \
+})
+
/*
* Evaluates to 1 if (ptr + inc) overflows, 0 otherwise.
* Both arguments must be unsigned pointer values (i.e. uintptr_t).
diff --git a/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h
index 7381bc82..6021e407 100644
--- a/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h
+++ b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h
@@ -16,6 +16,11 @@
#endif
/*
+ * Encode a Physical Address Space size for its use in TCR_ELx.
+ */
+unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr);
+
+/*
* In AArch64 state, the MMU may support 4 KB, 16 KB and 64 KB page
* granularity. For 4KB granularity, a level 0 table descriptor doesn't support
* block translation. For 16KB, the same thing happens to levels 0 and 1. For
diff --git a/include/lib/xlat_tables/xlat_tables_defs.h b/include/lib/xlat_tables/xlat_tables_defs.h
index b0f5a04c..3a7f2456 100644
--- a/include/lib/xlat_tables/xlat_tables_defs.h
+++ b/include/lib/xlat_tables/xlat_tables_defs.h
@@ -24,9 +24,19 @@
#define FOUR_KB_INDEX(x) ((x) >> FOUR_KB_SHIFT)
#define INVALID_DESC U(0x0)
+/*
+ * A block descriptor points to a region of memory bigger than the granule size
+ * (e.g. a 2MB region when the granule size is 4KB).
+ */
#define BLOCK_DESC U(0x1) /* Table levels 0-2 */
+/* A table descriptor points to the next level of translation table. */
#define TABLE_DESC U(0x3) /* Table levels 0-2 */
+/*
+ * A page descriptor points to a page, i.e. a memory region whose size is the
+ * translation granule size (e.g. 4KB).
+ */
#define PAGE_DESC U(0x3) /* Table level 3 */
+
#define DESC_MASK U(0x3)
#define FIRST_LEVEL_DESC_N ONE_GB_SHIFT
@@ -84,14 +94,39 @@
#define XLAT_BLOCK_MASK(level) (XLAT_BLOCK_SIZE(level) - 1)
/* Mask to get the address bits common to a block of a certain table level*/
#define XLAT_ADDR_MASK(level) (~XLAT_BLOCK_MASK(level))
+/*
+ * Extract from the given virtual address the index into the given lookup level.
+ * This macro assumes the system is using the 4KB translation granule.
+ */
+#define XLAT_TABLE_IDX(virtual_addr, level) \
+ (((virtual_addr) >> XLAT_ADDR_SHIFT(level)) & ULL(0x1FF))
/*
- * AP[1] bit is ignored by hardware and is
- * treated as if it is One in EL2/EL3
+ * The ARMv8 translation table descriptor format defines AP[2:1] as the Access
+ * Permissions bits, and does not define an AP[0] bit.
+ *
+ * AP[1] is valid only for a stage 1 translation that supports two VA ranges
+ * (i.e. in the ARMv8A.0 architecture, that is the S-EL1&0 regime).
+ *
+ * AP[1] is RES0 for stage 1 translations that support only one VA range
+ * (e.g. EL3).
*/
-#define AP_RO (U(0x1) << 5)
-#define AP_RW (U(0x0) << 5)
+#define AP2_SHIFT U(0x7)
+#define AP2_RO U(0x1)
+#define AP2_RW U(0x0)
+
+#define AP1_SHIFT U(0x6)
+#define AP1_ACCESS_UNPRIVILEGED U(0x1)
+#define AP1_NO_ACCESS_UNPRIVILEGED U(0x0)
+/*
+ * The following definitions must all be passed to the LOWER_ATTRS() macro to
+ * get the right bitmask.
+ */
+#define AP_RO (AP2_RO << 5)
+#define AP_RW (AP2_RW << 5)
+#define AP_ACCESS_UNPRIVILEGED (AP1_ACCESS_UNPRIVILEGED << 4)
+#define AP_NO_ACCESS_UNPRIVILEGED (AP1_NO_ACCESS_UNPRIVILEGED << 4)
#define NS (U(0x1) << 3)
#define ATTR_NON_CACHEABLE_INDEX U(0x2)
#define ATTR_DEVICE_INDEX U(0x1)
@@ -109,6 +144,28 @@
#define ATTR_INDEX_GET(attr) (((attr) >> 2) & ATTR_INDEX_MASK)
/*
+ * Shift values for the attributes fields in a block or page descriptor.
+ * See section D4.3.3 in the ARMv8-A ARM (issue B.a).
+ */
+
+/* Memory attributes index field, AttrIndx[2:0]. */
+#define ATTR_INDEX_SHIFT 2
+/* Non-secure bit, NS. */
+#define NS_SHIFT 5
+/* Shareability field, SH[1:0] */
+#define SHAREABILITY_SHIFT 8
+/* The Access Flag, AF. */
+#define ACCESS_FLAG_SHIFT 10
+/* The not global bit, nG. */
+#define NOT_GLOBAL_SHIFT 11
+/* Contiguous hint bit. */
+#define CONT_HINT_SHIFT 52
+/* Execute-never bits, XN. */
+#define PXN_SHIFT 53
+#define XN_SHIFT 54
+#define UXN_SHIFT XN_SHIFT
+
+/*
* Flags to override default values used to program system registers while
* enabling the MMU.
*/
diff --git a/include/lib/xlat_tables/xlat_tables_v2.h b/include/lib/xlat_tables/xlat_tables_v2.h
index 2be43296..ba3e3603 100644
--- a/include/lib/xlat_tables/xlat_tables_v2.h
+++ b/include/lib/xlat_tables/xlat_tables_v2.h
@@ -15,20 +15,36 @@
#include <xlat_mmu_helpers.h>
#include <xlat_tables_v2_helpers.h>
-/* Helper macro to define entries for mmap_region_t. It creates
- * identity mappings for each region.
+/*
+ * Default granularity size for an mmap_region_t.
+ * Useful when no specific granularity is required.
+ *
+ * By default, choose the biggest possible block size allowed by the
+ * architectural state and granule size in order to minimize the number of page
+ * tables required for the mapping.
*/
-#define MAP_REGION_FLAT(adr, sz, attr) MAP_REGION(adr, adr, sz, attr)
+#define REGION_DEFAULT_GRANULARITY XLAT_BLOCK_SIZE(MIN_LVL_BLOCK_DESC)
+
+/* Helper macro to define an mmap_region_t. */
+#define MAP_REGION(_pa, _va, _sz, _attr) \
+ _MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, REGION_DEFAULT_GRANULARITY)
-/* Helper macro to define entries for mmap_region_t. It allows to
- * re-map address mappings from 'pa' to 'va' for each region.
+/* Helper macro to define an mmap_region_t with an identity mapping. */
+#define MAP_REGION_FLAT(_adr, _sz, _attr) \
+ MAP_REGION(_adr, _adr, _sz, _attr)
+
+/*
+ * Helper macro to define an mmap_region_t to map with the desired granularity
+ * of translation tables.
+ *
+ * The granularity value passed to this macro must be a valid block or page
+ * size. When using a 4KB translation granule, this might be 4KB, 2MB or 1GB.
+ * Passing REGION_DEFAULT_GRANULARITY is also allowed and means that the library
+ * is free to choose the granularity for this region. In this case, it is
+ * equivalent to the MAP_REGION() macro.
*/
-#define MAP_REGION(_pa, _va, _sz, _attr) ((mmap_region_t){ \
- .base_pa = (_pa), \
- .base_va = (_va), \
- .size = (_sz), \
- .attr = (_attr), \
- })
+#define MAP_REGION2(_pa, _va, _sz, _attr, _gr) \
+ _MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, _gr)
/*
* Shifts and masks to access fields of an mmap_attr_t
@@ -41,6 +57,11 @@
#define MT_SEC_SHIFT U(4)
/* Access permissions for instruction execution (EXECUTE/EXECUTE_NEVER) */
#define MT_EXECUTE_SHIFT U(5)
+/*
+ * In the EL1&0 translation regime, mark the region as User (EL0) or
+ * Privileged (EL1). In the EL3 translation regime this has no effect.
+ */
+#define MT_USER_SHIFT U(6)
/* All other bits are reserved */
/*
@@ -73,10 +94,20 @@ typedef enum {
*/
MT_EXECUTE = U(0) << MT_EXECUTE_SHIFT,
MT_EXECUTE_NEVER = U(1) << MT_EXECUTE_SHIFT,
+
+ /*
+ * When mapping a region at EL0 or EL1, this attribute will be used to
+ * determine if a User mapping (EL0) will be created or a Privileged
+ * mapping (EL1).
+ */
+ MT_USER = U(1) << MT_USER_SHIFT,
+ MT_PRIVILEGED = U(0) << MT_USER_SHIFT,
} mmap_attr_t;
+/* Compound attributes for most common usages */
#define MT_CODE (MT_MEMORY | MT_RO | MT_EXECUTE)
#define MT_RO_DATA (MT_MEMORY | MT_RO | MT_EXECUTE_NEVER)
+#define MT_RW_DATA (MT_MEMORY | MT_RW | MT_EXECUTE_NEVER)
/*
* Structure for specifying a single region of memory.
@@ -86,9 +117,19 @@ typedef struct mmap_region {
uintptr_t base_va;
size_t size;
mmap_attr_t attr;
+ /* Desired granularity. See the MAP_REGION2() macro for more details. */
+ size_t granularity;
} mmap_region_t;
/*
+ * Translation regimes supported by this library.
+ */
+typedef enum xlat_regime {
+ EL1_EL0_REGIME,
+ EL3_REGIME,
+} xlat_regime_t;
+
+/*
* Declare the translation context type.
* Its definition is private.
*/
@@ -123,8 +164,32 @@ typedef struct xlat_ctx xlat_ctx_t;
*/
#define REGISTER_XLAT_CONTEXT(_ctx_name, _mmap_count, _xlat_tables_count, \
_virt_addr_space_size, _phy_addr_space_size) \
- _REGISTER_XLAT_CONTEXT(_ctx_name, _mmap_count, _xlat_tables_count, \
- _virt_addr_space_size, _phy_addr_space_size)
+ _REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, _mmap_count, \
+ _xlat_tables_count, \
+ _virt_addr_space_size, \
+ _phy_addr_space_size, \
+ IMAGE_XLAT_DEFAULT_REGIME, \
+ "xlat_table")
+
+/*
+ * Same as REGISTER_XLAT_CONTEXT plus the additional parameters:
+ *
+ * _xlat_regime:
+ * Specify the translation regime managed by this xlat_ctx_t instance. The
+ * values are the one from xlat_regime_t enumeration.
+ *
+ * _section_name:
+ * Specify the name of the section where the translation tables have to be
+ * placed by the linker.
+ */
+#define REGISTER_XLAT_CONTEXT2(_ctx_name, _mmap_count, _xlat_tables_count, \
+ _virt_addr_space_size, _phy_addr_space_size, \
+ _xlat_regime, _section_name) \
+ _REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, _mmap_count, \
+ _xlat_tables_count, \
+ _virt_addr_space_size, \
+ _phy_addr_space_size, \
+ _xlat_regime, _section_name)
/******************************************************************************
* Generic translation table APIs.
@@ -193,5 +258,66 @@ int mmap_remove_dynamic_region_ctx(xlat_ctx_t *ctx,
#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+/*
+ * Change the memory attributes of the memory region starting from a given
+ * virtual address in a set of translation tables.
+ *
+ * This function can only be used after the translation tables have been
+ * initialized.
+ *
+ * The base address of the memory region must be aligned on a page boundary.
+ * The size of this memory region must be a multiple of a page size.
+ * The memory region must be already mapped by the given translation tables
+ * and it must be mapped at the granularity of a page.
+ *
+ * Return 0 on success, a negative value on error.
+ *
+ * In case of error, the memory attributes remain unchanged and this function
+ * has no effect.
+ *
+ * ctx
+ * Translation context to work on.
+ * base_va:
+ * Virtual address of the 1st page to change the attributes of.
+ * size:
+ * Size in bytes of the memory region.
+ * attr:
+ * New attributes of the page tables. The attributes that can be changed are
+ * data access (MT_RO/MT_RW), instruction access (MT_EXECUTE_NEVER/MT_EXECUTE)
+ * and user/privileged access (MT_USER/MT_PRIVILEGED) in the case of contexts
+ * that are used in the EL1&0 translation regime. Also, note that this
+ * function doesn't allow to remap a region as RW and executable, or to remap
+ * device memory as executable.
+ *
+ * NOTE: The caller of this function must be able to write to the translation
+ * tables, i.e. the memory where they are stored must be mapped with read-write
+ * access permissions. This function assumes it is the case. If this is not
+ * the case then this function might trigger a data abort exception.
+ *
+ * NOTE2: The caller is responsible for making sure that the targeted
+ * translation tables are not modified by any other code while this function is
+ * executing.
+ */
+int change_mem_attributes(xlat_ctx_t *ctx, uintptr_t base_va, size_t size,
+ mmap_attr_t attr);
+
+/*
+ * Query the memory attributes of a memory page in a set of translation tables.
+ *
+ * Return 0 on success, a negative error code on error.
+ * On success, the attributes are stored into *attributes.
+ *
+ * ctx
+ * Translation context to work on.
+ * base_va
+ * Virtual address of the page to get the attributes of.
+ * There are no alignment restrictions on this address. The attributes of the
+ * memory page it lies within are returned.
+ * attributes
+ * Output parameter where to store the attributes of the targeted memory page.
+ */
+int get_mem_attributes(const xlat_ctx_t *ctx, uintptr_t base_va,
+ mmap_attr_t *attributes);
+
#endif /*__ASSEMBLY__*/
#endif /* __XLAT_TABLES_V2_H__ */
diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
index f5e31006..1be99b71 100644
--- a/include/lib/xlat_tables/xlat_tables_v2_helpers.h
+++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
@@ -27,6 +27,20 @@
/* Forward declaration */
struct mmap_region;
+/*
+ * Helper macro to define an mmap_region_t. This macro allows to specify all
+ * the fields of the structure but its parameter list is not guaranteed to
+ * remain stable as we add members to mmap_region_t.
+ */
+#define _MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, _gr) \
+ { \
+ .base_pa = (_pa), \
+ .base_va = (_va), \
+ .size = (_sz), \
+ .attr = (_attr), \
+ .granularity = (_gr), \
+ }
+
/* Struct that holds all information about the translation tables. */
struct xlat_ctx {
/*
@@ -85,11 +99,12 @@ struct xlat_ctx {
unsigned int initialized;
/*
- * Bit mask that has to be ORed to the rest of a translation table
- * descriptor in order to prohibit execution of code at the exception
- * level of this translation context.
+ * Translation regime managed by this xlat_ctx_t. It takes the values of
+ * the enumeration xlat_regime_t. The type is "int" to avoid a circular
+ * dependency on xlat_tables_v2.h, but this member must be treated as
+ * xlat_regime_t.
*/
- uint64_t execute_never_mask;
+ int xlat_regime;
};
#if PLAT_XLAT_TABLES_DYNAMIC
@@ -106,9 +121,9 @@ struct xlat_ctx {
/* do nothing */
#endif /* PLAT_XLAT_TABLES_DYNAMIC */
-
-#define _REGISTER_XLAT_CONTEXT(_ctx_name, _mmap_count, _xlat_tables_count, \
- _virt_addr_space_size, _phy_addr_space_size) \
+#define _REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, _mmap_count, _xlat_tables_count, \
+ _virt_addr_space_size, _phy_addr_space_size, \
+ _xlat_regime, _section_name) \
CASSERT(CHECK_VIRT_ADDR_SPACE_SIZE(_virt_addr_space_size), \
assert_invalid_virtual_addr_space_size_for_##_ctx_name); \
\
@@ -119,7 +134,7 @@ struct xlat_ctx {
\
static uint64_t _ctx_name##_xlat_tables[_xlat_tables_count] \
[XLAT_TABLE_ENTRIES] \
- __aligned(XLAT_TABLE_SIZE) __section("xlat_table"); \
+ __aligned(XLAT_TABLE_SIZE) __section(_section_name); \
\
static uint64_t _ctx_name##_base_xlat_table \
[GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)] \
@@ -140,12 +155,38 @@ struct xlat_ctx {
.tables = _ctx_name##_xlat_tables, \
.tables_num = _xlat_tables_count, \
_REGISTER_DYNMAP_STRUCT(_ctx_name) \
+ .xlat_regime = (_xlat_regime), \
.max_pa = 0, \
.max_va = 0, \
.next_table = 0, \
.initialized = 0, \
}
+#if AARCH64
+
+/*
+ * This IMAGE_EL macro must not to be used outside the library, and it is only
+ * used in AArch64.
+ */
+#if defined(IMAGE_BL1) || defined(IMAGE_BL31)
+# define IMAGE_EL 3
+# define IMAGE_XLAT_DEFAULT_REGIME EL3_REGIME
+#else
+# define IMAGE_EL 1
+# define IMAGE_XLAT_DEFAULT_REGIME EL1_EL0_REGIME
+#endif
+
+#else /* if AARCH32 */
+
+/*
+ * The PL1&0 translation regime in AArch32 behaves like the EL1&0 regime in
+ * AArch64 except for the XN bits, but we set and unset them at the same time,
+ * so there's no difference in practice.
+ */
+#define IMAGE_XLAT_DEFAULT_REGIME EL1_EL0_REGIME
+
+#endif /* AARCH64 */
+
#endif /*__ASSEMBLY__*/
#endif /* __XLAT_TABLES_V2_HELPERS_H__ */
diff --git a/include/plat/arm/board/common/board_arm_def.h b/include/plat/arm/board/common/board_arm_def.h
index 751c3bb1..69eb727f 100644
--- a/include/plat/arm/board/common/board_arm_def.h
+++ b/include/plat/arm/board/common/board_arm_def.h
@@ -52,11 +52,21 @@
* They are also used for the dynamically mapped regions in the images that
* enable dynamic memory mapping.
*/
-#if defined(IMAGE_BL31) || defined(IMAGE_BL32)
-# define PLAT_ARM_MMAP_ENTRIES 6
-# define MAX_XLAT_TABLES 4
+#if defined(IMAGE_BL31)
+# if ENABLE_SPM
+# define PLAT_ARM_MMAP_ENTRIES 9
+# define MAX_XLAT_TABLES 7
+# define PLAT_SP_IMAGE_MMAP_REGIONS 7
+# define PLAT_SP_IMAGE_MAX_XLAT_TABLES 10
+# else
+# define PLAT_ARM_MMAP_ENTRIES 7
+# define MAX_XLAT_TABLES 5
+# endif
+#elif defined(IMAGE_BL32)
+# define PLAT_ARM_MMAP_ENTRIES 7
+# define MAX_XLAT_TABLES 5
#else
-# define PLAT_ARM_MMAP_ENTRIES 10
+# define PLAT_ARM_MMAP_ENTRIES 11
# define MAX_XLAT_TABLES 5
#endif
@@ -64,14 +74,14 @@
* PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
* plus a little space for growth.
*/
-#define PLAT_ARM_MAX_BL1_RW_SIZE 0xA000
+#define PLAT_ARM_MAX_BL1_RW_SIZE 0xB000
/*
* PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
* little space for growth.
*/
#if TRUSTED_BOARD_BOOT
-# define PLAT_ARM_MAX_BL2_SIZE 0x1D000
+# define PLAT_ARM_MAX_BL2_SIZE 0x1E000
#else
# define PLAT_ARM_MAX_BL2_SIZE 0xF000
#endif
@@ -82,6 +92,14 @@
*/
#define PLAT_ARM_MAX_BL31_SIZE 0x1D000
+#ifdef AARCH32
+/*
+ * PLAT_ARM_MAX_BL32_SIZE is calculated for SP_MIN as the AArch32 Secure
+ * Payload.
+ */
+# define PLAT_ARM_MAX_BL32_SIZE 0x1D000
+#endif
+
#endif /* ARM_BOARD_OPTIMISE_MEM */
#define MAX_IO_DEVICES 3
@@ -89,11 +107,26 @@
#define PLAT_ARM_TRUSTED_SRAM_SIZE 0x00040000 /* 256 KB */
+/* Reserve the last block of flash for PSCI MEM PROTECT flag */
#define PLAT_ARM_FIP_BASE V2M_FLASH0_BASE
-#define PLAT_ARM_FIP_MAX_SIZE V2M_FLASH0_SIZE
+#define PLAT_ARM_FIP_MAX_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
#define PLAT_ARM_NVM_BASE V2M_FLASH0_BASE
-#define PLAT_ARM_NVM_SIZE V2M_FLASH0_SIZE
+#define PLAT_ARM_NVM_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/* PSCI memory protect definitions:
+ * This variable is stored in a non-secure flash because some ARM reference
+ * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT
+ * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions.
+ */
+#define PLAT_ARM_MEM_PROT_ADDR (V2M_FLASH0_BASE + \
+ V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+/*
+ * Map mem_protect flash region with read and write permissions
+ */
+#define ARM_V2M_MAP_MEM_PROTECT MAP_REGION_FLAT(PLAT_ARM_MEM_PROT_ADDR, \
+ V2M_FLASH_BLOCK_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
#endif /* __BOARD_ARM_DEF_H__ */
diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h
index 2ad513ac..e5f53732 100644
--- a/include/plat/arm/board/common/v2m_def.h
+++ b/include/plat/arm/board/common/v2m_def.h
@@ -69,6 +69,7 @@
/* NOR Flash */
#define V2M_FLASH0_BASE 0x08000000
#define V2M_FLASH0_SIZE 0x04000000
+#define V2M_FLASH_BLOCK_SIZE 0x00040000 /* 256 KB */
#define V2M_IOFPGA_BASE 0x1c000000
#define V2M_IOFPGA_SIZE 0x03000000
@@ -120,6 +121,11 @@
V2M_IOFPGA_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE)
+/* Region equivalent to V2M_MAP_IOFPGA suitable for mapping at EL0 */
+#define V2M_MAP_IOFPGA_EL0 MAP_REGION_FLAT( \
+ V2M_IOFPGA_BASE, \
+ V2M_IOFPGA_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE | MT_USER)
#endif /* __V2M_DEF_H__ */
diff --git a/include/plat/arm/common/arm_common.ld.S b/include/plat/arm/common/arm_common.ld.S
new file mode 100644
index 00000000..6edfa099
--- /dev/null
+++ b/include/plat/arm/common/arm_common.ld.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __ARM_COMMON_LD_S__
+#define __ARM_COMMON_LD_S__
+
+#include <xlat_tables_defs.h>
+
+MEMORY {
+ EL3_SEC_DRAM (rw): ORIGIN = ARM_EL3_TZC_DRAM1_BASE, LENGTH = ARM_EL3_TZC_DRAM1_SIZE
+}
+
+SECTIONS
+{
+ . = ARM_EL3_TZC_DRAM1_BASE;
+ ASSERT(. == ALIGN(PAGE_SIZE),
+ "ARM_EL3_TZC_DRAM_BASE address is not aligned on a page boundary.")
+ el3_tzc_dram (NOLOAD) : ALIGN(PAGE_SIZE) {
+ __EL3_SEC_DRAM_START__ = .;
+ *(arm_el3_tzc_dram)
+ __EL3_SEC_DRAM_UNALIGNED_END__ = .;
+
+ . = NEXT(PAGE_SIZE);
+ __EL3_SEC_DRAM_END__ = .;
+ } >EL3_SEC_DRAM
+}
+
+#endif /* __ARM_COMMON_LD_S__ */
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index 787ccb02..78875259 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -8,6 +8,8 @@
#include <arch.h>
#include <common_def.h>
+#include <gic_common.h>
+#include <interrupt_props.h>
#include <platform_def.h>
#include <tbbr_img_def.h>
#include <utils_def.h>
@@ -75,11 +77,23 @@
#define ARM_SCP_TZC_DRAM1_END (ARM_SCP_TZC_DRAM1_BASE + \
ARM_SCP_TZC_DRAM1_SIZE - 1)
+/*
+ * Define a 2MB region within the TZC secured DRAM for use by EL3 runtime
+ * firmware. This region is meant to be NOLOAD and will not be zero
+ * initialized. Data sections with the attribute `arm_el3_tzc_dram` will be
+ * placed here.
+ */
+#define ARM_EL3_TZC_DRAM1_BASE (ARM_SCP_TZC_DRAM1_BASE - ARM_EL3_TZC_DRAM1_SIZE)
+#define ARM_EL3_TZC_DRAM1_SIZE ULL(0x00200000) /* 2 MB */
+#define ARM_EL3_TZC_DRAM1_END (ARM_EL3_TZC_DRAM1_BASE + \
+ ARM_EL3_TZC_DRAM1_SIZE - 1)
+
#define ARM_AP_TZC_DRAM1_BASE (ARM_DRAM1_BASE + \
ARM_DRAM1_SIZE - \
ARM_TZC_DRAM1_SIZE)
#define ARM_AP_TZC_DRAM1_SIZE (ARM_TZC_DRAM1_SIZE - \
- ARM_SCP_TZC_DRAM1_SIZE)
+ (ARM_SCP_TZC_DRAM1_SIZE + \
+ ARM_EL3_TZC_DRAM1_SIZE))
#define ARM_AP_TZC_DRAM1_END (ARM_AP_TZC_DRAM1_BASE + \
ARM_AP_TZC_DRAM1_SIZE - 1)
@@ -152,9 +166,8 @@
#define ARM_IRQ_SEC_SGI_7 15
/*
- * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
- * terminology. On a GICv2 system or mode, the lists will be merged and treated
- * as Group 0 interrupts.
+ * List of secure interrupts are deprecated, but are retained only to support
+ * legacy configurations.
*/
#define ARM_G1S_IRQS ARM_IRQ_SEC_PHY_TIMER, \
ARM_IRQ_SEC_SGI_1, \
@@ -167,6 +180,33 @@
#define ARM_G0_IRQS ARM_IRQ_SEC_SGI_0, \
ARM_IRQ_SEC_SGI_6
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupt properties as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define ARM_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE)
+
+#define ARM_G0_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, PLAT_SDEI_NORMAL_PRI, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE)
+
#define ARM_MAP_SHARED_RAM MAP_REGION_FLAT( \
ARM_SHARED_RAM_BASE, \
ARM_SHARED_RAM_SIZE, \
@@ -177,7 +217,12 @@
ARM_NS_DRAM1_SIZE, \
MT_MEMORY | MT_RW | MT_NS)
+#define ARM_MAP_DRAM2 MAP_REGION_FLAT( \
+ ARM_DRAM2_BASE, \
+ ARM_DRAM2_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
#ifdef SPD_tspd
+
#define ARM_MAP_TSP_SEC_MEM MAP_REGION_FLAT( \
TSP_SEC_MEM_BASE, \
TSP_SEC_MEM_SIZE, \
@@ -191,6 +236,11 @@
MT_MEMORY | MT_RW | MT_SECURE)
#endif
+#define ARM_MAP_EL3_TZC_DRAM MAP_REGION_FLAT( \
+ ARM_EL3_TZC_DRAM1_BASE, \
+ ARM_EL3_TZC_DRAM1_SIZE, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+
/*
* The number of regions like RO(code), coherent and data required by
* different BL stages which need to be mapped in the MMU.
@@ -224,8 +274,18 @@
* Required platform porting definitions common to all ARM standard platforms
*****************************************************************************/
+/*
+ * We need to access DRAM2 from BL2 for PSCI_MEM_PROTECT for
+ * AArch64 builds
+ */
+#ifdef AARCH64
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 36)
+#else
#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32)
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32)
+#endif
+
/*
* This macro defines the deepest retention state possible. A higher state
@@ -266,14 +326,21 @@
/*******************************************************************************
* BL2 specific defines.
******************************************************************************/
-#if ARM_BL31_IN_DRAM || (defined(AARCH32) && !defined(JUNO_AARCH32_EL3_RUNTIME))
+#if ARM_BL31_IN_DRAM
/*
- * For AArch32 BL31 is not applicable.
* For AArch64 BL31 is loaded in the DRAM.
* Put BL2 just below BL1.
*/
#define BL2_BASE (BL1_RW_BASE - PLAT_ARM_MAX_BL2_SIZE)
#define BL2_LIMIT BL1_RW_BASE
+
+#elif defined(AARCH32) || JUNO_AARCH32_EL3_RUNTIME
+/*
+ * Put BL2 just below BL32.
+ */
+#define BL2_BASE (BL32_BASE - PLAT_ARM_MAX_BL2_SIZE)
+#define BL2_LIMIT BL32_BASE
+
#else
/*
* Put BL2 just below BL31.
@@ -310,67 +377,86 @@
#define BL31_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
#endif
+#if defined(AARCH32) || JUNO_AARCH32_EL3_RUNTIME
+/*******************************************************************************
+ * BL32 specific defines for EL3 runtime in AArch32 mode
+ ******************************************************************************/
+# if RESET_TO_SP_MIN && !JUNO_AARCH32_EL3_RUNTIME
+/* SP_MIN is the only BL image in SRAM. Allocate the whole of SRAM to BL32 */
+# define BL32_BASE ARM_BL_RAM_BASE
+# define BL32_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
+# else
+/* Put BL32 at the top of the Trusted SRAM.*/
+# define BL32_BASE (ARM_BL_RAM_BASE + \
+ ARM_BL_RAM_SIZE - \
+ PLAT_ARM_MAX_BL32_SIZE)
+# define BL32_PROGBITS_LIMIT BL1_RW_BASE
+# define BL32_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
+# endif /* RESET_TO_SP_MIN && !JUNO_AARCH32_EL3_RUNTIME */
+
+#else
/*******************************************************************************
- * BL32 specific defines.
+ * BL32 specific defines for EL3 runtime in AArch64 mode
******************************************************************************/
/*
* On ARM standard platforms, the TSP can execute from Trusted SRAM,
* Trusted DRAM (if available) or the DRAM region secured by the TrustZone
* controller.
*/
-#if ARM_BL31_IN_DRAM
-# define TSP_SEC_MEM_BASE (ARM_AP_TZC_DRAM1_BASE + \
+# if ENABLE_SPM
+# define TSP_SEC_MEM_BASE (ARM_AP_TZC_DRAM1_BASE + ULL(0x200000))
+# define TSP_SEC_MEM_SIZE (ARM_AP_TZC_DRAM1_SIZE - ULL(0x200000))
+# define BL32_BASE (ARM_AP_TZC_DRAM1_BASE + ULL(0x200000))
+# define BL32_LIMIT (ARM_AP_TZC_DRAM1_BASE + \
+ ARM_AP_TZC_DRAM1_SIZE)
+# elif ARM_BL31_IN_DRAM
+# define TSP_SEC_MEM_BASE (ARM_AP_TZC_DRAM1_BASE + \
PLAT_ARM_MAX_BL31_SIZE)
-# define TSP_SEC_MEM_SIZE (ARM_AP_TZC_DRAM1_SIZE - \
+# define TSP_SEC_MEM_SIZE (ARM_AP_TZC_DRAM1_SIZE - \
PLAT_ARM_MAX_BL31_SIZE)
-# define BL32_BASE (ARM_AP_TZC_DRAM1_BASE + \
+# define BL32_BASE (ARM_AP_TZC_DRAM1_BASE + \
PLAT_ARM_MAX_BL31_SIZE)
-# define BL32_LIMIT (ARM_AP_TZC_DRAM1_BASE + \
+# define BL32_LIMIT (ARM_AP_TZC_DRAM1_BASE + \
ARM_AP_TZC_DRAM1_SIZE)
-#elif ARM_TSP_RAM_LOCATION_ID == ARM_TRUSTED_SRAM_ID
-# define TSP_SEC_MEM_BASE ARM_BL_RAM_BASE
-# define TSP_SEC_MEM_SIZE ARM_BL_RAM_SIZE
-# define TSP_PROGBITS_LIMIT BL2_BASE
-# define BL32_BASE ARM_BL_RAM_BASE
-# define BL32_LIMIT BL31_BASE
-#elif ARM_TSP_RAM_LOCATION_ID == ARM_TRUSTED_DRAM_ID
-# define TSP_SEC_MEM_BASE PLAT_ARM_TRUSTED_DRAM_BASE
-# define TSP_SEC_MEM_SIZE PLAT_ARM_TRUSTED_DRAM_SIZE
-# define BL32_BASE PLAT_ARM_TRUSTED_DRAM_BASE
-# define BL32_LIMIT (PLAT_ARM_TRUSTED_DRAM_BASE \
+# elif ARM_TSP_RAM_LOCATION_ID == ARM_TRUSTED_SRAM_ID
+# define TSP_SEC_MEM_BASE ARM_BL_RAM_BASE
+# define TSP_SEC_MEM_SIZE ARM_BL_RAM_SIZE
+# define TSP_PROGBITS_LIMIT BL2_BASE
+# define BL32_BASE ARM_BL_RAM_BASE
+# define BL32_LIMIT BL31_BASE
+# elif ARM_TSP_RAM_LOCATION_ID == ARM_TRUSTED_DRAM_ID
+# define TSP_SEC_MEM_BASE PLAT_ARM_TRUSTED_DRAM_BASE
+# define TSP_SEC_MEM_SIZE PLAT_ARM_TRUSTED_DRAM_SIZE
+# define BL32_BASE PLAT_ARM_TRUSTED_DRAM_BASE
+# define BL32_LIMIT (PLAT_ARM_TRUSTED_DRAM_BASE \
+ (1 << 21))
-#elif ARM_TSP_RAM_LOCATION_ID == ARM_DRAM_ID
-# define TSP_SEC_MEM_BASE ARM_AP_TZC_DRAM1_BASE
-# define TSP_SEC_MEM_SIZE ARM_AP_TZC_DRAM1_SIZE
-# define BL32_BASE ARM_AP_TZC_DRAM1_BASE
-# define BL32_LIMIT (ARM_AP_TZC_DRAM1_BASE + \
+# elif ARM_TSP_RAM_LOCATION_ID == ARM_DRAM_ID
+# define TSP_SEC_MEM_BASE ARM_AP_TZC_DRAM1_BASE
+# define TSP_SEC_MEM_SIZE ARM_AP_TZC_DRAM1_SIZE
+# define BL32_BASE ARM_AP_TZC_DRAM1_BASE
+# define BL32_LIMIT (ARM_AP_TZC_DRAM1_BASE + \
ARM_AP_TZC_DRAM1_SIZE)
-#else
-# error "Unsupported ARM_TSP_RAM_LOCATION_ID value"
-#endif
+# else
+# error "Unsupported ARM_TSP_RAM_LOCATION_ID value"
+# endif
+#endif /* AARCH32 || JUNO_AARCH32_EL3_RUNTIME */
-/* BL32 is mandatory in AArch32 */
-#ifndef AARCH32
-#ifdef SPD_none
-#undef BL32_BASE
-#endif /* SPD_none */
-#endif
+/*
+ * BL32 is mandatory in AArch32. In AArch64, undefine BL32_BASE if there is no
+ * SPD and no SPM, as they are the only ones that can be used as BL32.
+ */
+#if !(defined(AARCH32) || JUNO_AARCH32_EL3_RUNTIME)
+# if defined(SPD_none) && !ENABLE_SPM
+# undef BL32_BASE
+# endif /* defined(SPD_none) && !ENABLE_SPM */
+#endif /* !(defined(AARCH32) || JUNO_AARCH32_EL3_RUNTIME) */
/*******************************************************************************
* FWU Images: NS_BL1U, BL2U & NS_BL2U defines.
******************************************************************************/
#define BL2U_BASE BL2_BASE
-#if ARM_BL31_IN_DRAM || (defined(AARCH32) && !defined(JUNO_AARCH32_EL3_RUNTIME))
-/*
- * For AArch32 BL31 is not applicable.
- * For AArch64 BL31 is loaded in the DRAM.
- * BL2U extends up to BL1.
- */
-#define BL2U_LIMIT BL1_RW_BASE
-#else
-/* BL2U extends up to BL31. */
-#define BL2U_LIMIT BL31_BASE
-#endif
+#define BL2U_LIMIT BL2_LIMIT
+
#define NS_BL2U_BASE ARM_NS_DRAM1_BASE
#define NS_BL1U_BASE (PLAT_ARM_NVM_BASE + 0x03EB8000)
@@ -385,5 +471,24 @@
*/
#define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE)
+/* Priority levels for ARM platforms */
+#define PLAT_SDEI_CRITICAL_PRI 0x60
+#define PLAT_SDEI_NORMAL_PRI 0x70
+
+/* ARM platforms use 3 upper bits of secure interrupt priority */
+#define ARM_PRI_BITS 3
+
+/* SGI used for SDEI signalling */
+#define ARM_SDEI_SGI ARM_IRQ_SEC_SGI_0
+
+/* ARM SDEI dynamic private event numbers */
+#define ARM_SDEI_DP_EVENT_0 1000
+#define ARM_SDEI_DP_EVENT_1 1001
+#define ARM_SDEI_DP_EVENT_2 1002
+
+/* ARM SDEI dynamic shared event numbers */
+#define ARM_SDEI_DS_EVENT_0 2000
+#define ARM_SDEI_DS_EVENT_1 2001
+#define ARM_SDEI_DS_EVENT_2 2002
#endif /* __ARM_DEF_H__ */
diff --git a/include/plat/arm/common/arm_spm_def.h b/include/plat/arm/common/arm_spm_def.h
new file mode 100644
index 00000000..3f5c958d
--- /dev/null
+++ b/include/plat/arm/common/arm_spm_def.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __ARM_SPM_DEF_H__
+#define __ARM_SPM_DEF_H__
+
+#include <arm_def.h>
+#include <platform_def.h>
+#include <utils_def.h>
+#include <xlat_tables_defs.h>
+
+/*
+ * If BL31 is placed in DRAM, place the Secure Partition in DRAM right after the
+ * region used by BL31. If BL31 it is placed in SRAM, put the Secure Partition
+ * at the base of DRAM.
+ */
+#define ARM_SP_IMAGE_BASE BL32_BASE
+#define ARM_SP_IMAGE_LIMIT BL32_LIMIT
+/* The maximum size of the S-EL0 payload can be 3MB */
+#define ARM_SP_IMAGE_SIZE ULL(0x300000)
+
+#ifdef IMAGE_BL2
+/* SPM Payload memory. Mapped as RW in BL2. */
+#define ARM_SP_IMAGE_MMAP MAP_REGION_FLAT( \
+ ARM_SP_IMAGE_BASE, \
+ ARM_SP_IMAGE_SIZE, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+#endif
+#ifdef IMAGE_BL31
+/* SPM Payload memory. Mapped as code in S-EL1 */
+#define ARM_SP_IMAGE_MMAP MAP_REGION2( \
+ ARM_SP_IMAGE_BASE, \
+ ARM_SP_IMAGE_BASE, \
+ ARM_SP_IMAGE_SIZE, \
+ MT_CODE | MT_SECURE | MT_USER, \
+ PAGE_SIZE)
+#endif
+
+/*
+ * Memory shared between EL3 and S-EL0. It is used by EL3 to push data into
+ * S-EL0, so it is mapped with RW permission from EL3 and with RO permission
+ * from S-EL0. Placed after SPM Payload memory.
+ */
+#define PLAT_SPM_BUF_BASE (ARM_SP_IMAGE_BASE + ARM_SP_IMAGE_SIZE)
+#define PLAT_SPM_BUF_SIZE ULL(0x100000)
+
+#define ARM_SPM_BUF_EL3_MMAP MAP_REGION_FLAT( \
+ PLAT_SPM_BUF_BASE, \
+ PLAT_SPM_BUF_SIZE, \
+ MT_RW_DATA | MT_SECURE)
+#define ARM_SPM_BUF_EL0_MMAP MAP_REGION2( \
+ PLAT_SPM_BUF_BASE, \
+ PLAT_SPM_BUF_BASE, \
+ PLAT_SPM_BUF_SIZE, \
+ MT_RO_DATA | MT_SECURE | MT_USER,\
+ PAGE_SIZE)
+
+/*
+ * Memory shared between Normal world and S-EL0 for passing data during service
+ * requests. Mapped as RW and NS. Placed after the shared memory between EL3 and
+ * S-EL0.
+ */
+#define ARM_SP_IMAGE_NS_BUF_BASE (PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE)
+#define ARM_SP_IMAGE_NS_BUF_SIZE ULL(0x10000)
+#define ARM_SP_IMAGE_NS_BUF_MMAP MAP_REGION2( \
+ ARM_SP_IMAGE_NS_BUF_BASE, \
+ ARM_SP_IMAGE_NS_BUF_BASE, \
+ ARM_SP_IMAGE_NS_BUF_SIZE, \
+ MT_RW_DATA | MT_NS | MT_USER, \
+ PAGE_SIZE)
+
+/*
+ * RW memory, which uses the remaining Trusted DRAM. Placed after the memory
+ * shared between Secure and Non-secure worlds. First there is the stack memory
+ * for all CPUs and then there is the common heap memory. Both are mapped with
+ * RW permissions.
+ */
+#define PLAT_SP_IMAGE_STACK_BASE (ARM_SP_IMAGE_NS_BUF_BASE + \
+ ARM_SP_IMAGE_NS_BUF_SIZE)
+#define PLAT_SP_IMAGE_STACK_PCPU_SIZE ULL(0x2000)
+#define ARM_SP_IMAGE_STACK_TOTAL_SIZE (PLATFORM_CORE_COUNT * \
+ PLAT_SP_IMAGE_STACK_PCPU_SIZE)
+
+#define ARM_SP_IMAGE_HEAP_BASE (PLAT_SP_IMAGE_STACK_BASE + \
+ ARM_SP_IMAGE_STACK_TOTAL_SIZE)
+#define ARM_SP_IMAGE_HEAP_SIZE (ARM_SP_IMAGE_LIMIT - ARM_SP_IMAGE_HEAP_BASE)
+
+#define ARM_SP_IMAGE_RW_MMAP MAP_REGION2( \
+ PLAT_SP_IMAGE_STACK_BASE, \
+ PLAT_SP_IMAGE_STACK_BASE, \
+ (ARM_SP_IMAGE_LIMIT - \
+ PLAT_SP_IMAGE_STACK_BASE), \
+ MT_RW_DATA | MT_SECURE | MT_USER,\
+ PAGE_SIZE)
+
+/* Total number of memory regions with distinct properties */
+#define ARM_SP_IMAGE_NUM_MEM_REGIONS 6
+
+/*
+ * Name of the section to put the translation tables used by the S-EL1/S-EL0
+ * context of a Secure Partition.
+ */
+#define PLAT_SP_IMAGE_XLAT_SECTION_NAME "arm_el3_tzc_dram"
+
+/* Cookies passed to the Secure Partition at boot. Not used by ARM platforms. */
+#define PLAT_SPM_COOKIE_0 ULL(0)
+#define PLAT_SPM_COOKIE_1 ULL(0)
+
+#endif /* __ARM_SPM_DEF_H__ */
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index f0e97678..abd73953 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -119,9 +119,15 @@ void arm_configure_sys_timer(void);
/* PM utility functions */
int arm_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state);
+int arm_validate_psci_entrypoint(uintptr_t entrypoint);
int arm_validate_ns_entrypoint(uintptr_t entrypoint);
+void arm_system_pwr_domain_save(void);
void arm_system_pwr_domain_resume(void);
void arm_program_trusted_mailbox(uintptr_t address);
+int arm_psci_read_mem_protect(int *val);
+int arm_nor_psci_write_mem_protect(int val);
+void arm_nor_psci_do_mem_protect(void);
+int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length);
/* Topology utility function */
int arm_check_mpidr(u_register_t mpidr);
@@ -179,6 +185,8 @@ void plat_arm_gic_cpuif_disable(void);
void plat_arm_gic_redistif_on(void);
void plat_arm_gic_redistif_off(void);
void plat_arm_gic_pcpu_init(void);
+void plat_arm_gic_save(void);
+void plat_arm_gic_resume(void);
void plat_arm_security_setup(void);
void plat_arm_pwrc_setup(void);
void plat_arm_interconnect_init(void);
@@ -219,7 +227,4 @@ int arm_execution_state_switch(unsigned int smc_fid,
uint32_t cookie_lo,
void *handle);
-/* Disable Statistical Profiling Extensions helper */
-void arm_disable_spe(void);
-
#endif /* __PLAT_ARM_H__ */
diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h
index ac0769c3..a2c0b4e8 100644
--- a/include/plat/arm/css/common/css_def.h
+++ b/include/plat/arm/css/common/css_def.h
@@ -8,6 +8,8 @@
#define __CSS_DEF_H__
#include <arm_def.h>
+#include <gic_common.h>
+#include <interrupt_props.h>
#include <tzc400.h>
/*************************************************************************
@@ -41,14 +43,21 @@
#define MHU_CPU_INTR_S_SET_OFFSET 0x308
/*
- * Define a list of Group 1 Secure interrupts as per GICv3 terminology. On a
- * GICv2 system or mode, the interrupts will be treated as Group 0 interrupts.
+ * Define a list of Group 1 Secure interrupt properties as per GICv3
+ * terminology. On a GICv2 system or mode, the interrupts will be treated as
+ * Group 0 interrupts.
*/
-#define CSS_G1S_IRQS CSS_IRQ_MHU, \
- CSS_IRQ_GPU_SMMU_0, \
- CSS_IRQ_TZC, \
- CSS_IRQ_TZ_WDOG, \
- CSS_IRQ_SEC_SYS_TIMER
+#define CSS_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(CSS_IRQ_MHU, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(CSS_IRQ_GPU_SMMU_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(CSS_IRQ_TZC, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(CSS_IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(CSS_IRQ_SEC_SYS_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
#if CSS_USE_SCMI_SDS_DRIVER
/* Memory region for shared data storage */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index e189f648..f11bee9f 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -23,6 +23,8 @@ struct bl31_params;
struct image_desc;
struct bl_load_info;
struct bl_params;
+struct mmap_region;
+struct secure_partition_boot_info;
/*******************************************************************************
* plat_get_rotpk_info() flags
@@ -70,6 +72,27 @@ uint32_t plat_interrupt_type_to_line(uint32_t type,
uint32_t security_state);
/*******************************************************************************
+ * Optional interrupt management functions, depending on chosen EL3 components.
+ ******************************************************************************/
+unsigned int plat_ic_get_running_priority(void);
+int plat_ic_is_spi(unsigned int id);
+int plat_ic_is_ppi(unsigned int id);
+int plat_ic_is_sgi(unsigned int id);
+unsigned int plat_ic_get_interrupt_active(unsigned int id);
+void plat_ic_disable_interrupt(unsigned int id);
+void plat_ic_enable_interrupt(unsigned int id);
+int plat_ic_has_interrupt_type(unsigned int type);
+void plat_ic_set_interrupt_type(unsigned int id, unsigned int type);
+void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority);
+void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target);
+void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
+ u_register_t mpidr);
+void plat_ic_set_interrupt_pending(unsigned int id);
+void plat_ic_clear_interrupt_pending(unsigned int id);
+unsigned int plat_ic_set_priority_mask(unsigned int mask);
+unsigned int plat_ic_get_interrupt_id(unsigned int raw);
+
+/*******************************************************************************
* Optional common functions (may be overridden)
******************************************************************************/
uintptr_t plat_get_my_stack(void);
@@ -80,6 +103,8 @@ int plat_crash_console_flush(void);
void plat_error_handler(int err) __dead2;
void plat_panic_handler(void) __dead2;
const char *plat_log_get_prefix(unsigned int log_level);
+void bl2_plat_preload_setup(void);
+int plat_try_next_boot_source(void);
/*******************************************************************************
* Mandatory BL1 functions
@@ -89,6 +114,16 @@ void bl1_plat_arch_setup(void);
void bl1_platform_setup(void);
struct meminfo *bl1_plat_sec_mem_layout(void);
+/*******************************************************************************
+ * Optional EL3 component functions in BL31
+ ******************************************************************************/
+
+/* SDEI platform functions */
+#if SDEI_SUPPORT
+int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode);
+void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr);
+#endif
+
/*
* The following function is mandatory when the
* firmware update feature is used.
@@ -271,6 +306,13 @@ int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr);
int plat_set_nv_ctr2(void *cookie, const struct auth_img_desc_s *img_desc,
unsigned int nv_ctr);
+/*******************************************************************************
+ * Secure Partitions functions
+ ******************************************************************************/
+const struct mmap_region *plat_get_secure_partition_mmap(void *cookie);
+const struct secure_partition_boot_info *plat_get_secure_partition_boot_info(
+ void *cookie);
+
#if LOAD_IMAGE_V2
/*******************************************************************************
* Mandatory BL image load functions(may be overridden).
diff --git a/include/services/sdei.h b/include/services/sdei.h
new file mode 100644
index 00000000..ce9a008c
--- /dev/null
+++ b/include/services/sdei.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SDEI_H__
+#define __SDEI_H__
+
+#include <spinlock.h>
+#include <utils_def.h>
+
+/* Range 0xC4000020 - 0xC400003F reserved for SDE 64bit smc calls */
+#define SDEI_VERSION 0xC4000020
+#define SDEI_EVENT_REGISTER 0xC4000021
+#define SDEI_EVENT_ENABLE 0xC4000022
+#define SDEI_EVENT_DISABLE 0xC4000023
+#define SDEI_EVENT_CONTEXT 0xC4000024
+#define SDEI_EVENT_COMPLETE 0xC4000025
+#define SDEI_EVENT_COMPLETE_AND_RESUME 0xC4000026
+
+#define SDEI_EVENT_UNREGISTER 0xC4000027
+#define SDEI_EVENT_STATUS 0xC4000028
+#define SDEI_EVENT_GET_INFO 0xC4000029
+#define SDEI_EVENT_ROUTING_SET 0xC400002A
+#define SDEI_PE_MASK 0xC400002B
+#define SDEI_PE_UNMASK 0xC400002C
+
+#define SDEI_INTERRUPT_BIND 0xC400002D
+#define SDEI_INTERRUPT_RELEASE 0xC400002E
+#define SDEI_EVENT_SIGNAL 0xC400002F
+#define SDEI_FEATURES 0xC4000030
+#define SDEI_PRIVATE_RESET 0xC4000031
+#define SDEI_SHARED_RESET 0xC4000032
+
+/* SDEI_EVENT_REGISTER flags */
+#define SDEI_REGF_RM_ANY 0
+#define SDEI_REGF_RM_PE 1
+
+/* SDEI_EVENT_COMPLETE status flags */
+#define SDEI_EV_HANDLED 0
+#define SDEI_EV_FAILED 1
+
+/* SDE event status values in bit position */
+#define SDEI_STATF_REGISTERED 0
+#define SDEI_STATF_ENABLED 1
+#define SDEI_STATF_RUNNING 2
+
+/* Internal: SDEI flag bit positions */
+#define _SDEI_MAPF_DYNAMIC_SHIFT 1
+#define _SDEI_MAPF_BOUND_SHIFT 2
+#define _SDEI_MAPF_SIGNALABLE_SHIFT 3
+#define _SDEI_MAPF_PRIVATE_SHIFT 4
+#define _SDEI_MAPF_CRITICAL_SHIFT 5
+
+/* SDEI event 0 */
+#define SDEI_EVENT_0 0
+
+/* Placeholder interrupt for dynamic mapping */
+#define SDEI_DYN_IRQ 0
+
+/* SDEI flags */
+
+/*
+ * These flags determine whether or not an event can be associated with an
+ * interrupt. Static events are permanently associated with an interrupt, and
+ * can't be changed at runtime. Association of dynamic events with interrupts
+ * can be changed at run time using the SDEI_INTERRUPT_BIND and
+ * SDEI_INTERRUPT_RELEASE calls.
+ *
+ * SDEI_MAPF_DYNAMIC only indicates run time configurability, where as
+ * SDEI_MAPF_BOUND indicates interrupt association. For example:
+ *
+ * - Calling SDEI_INTERRUPT_BIND on a dynamic event will have both
+ * SDEI_MAPF_DYNAMIC and SDEI_MAPF_BOUND set.
+ *
+ * - Statically-bound events will always have SDEI_MAPF_BOUND set, and neither
+ * SDEI_INTERRUPT_BIND nor SDEI_INTERRUPT_RELEASE can be called on them.
+ *
+ * See also the is_map_bound() macro.
+ */
+#define SDEI_MAPF_DYNAMIC BIT(_SDEI_MAPF_DYNAMIC_SHIFT)
+#define SDEI_MAPF_BOUND BIT(_SDEI_MAPF_BOUND_SHIFT)
+
+#define SDEI_MAPF_SIGNALABLE BIT(_SDEI_MAPF_SIGNALABLE_SHIFT)
+#define SDEI_MAPF_PRIVATE BIT(_SDEI_MAPF_PRIVATE_SHIFT)
+#define SDEI_MAPF_CRITICAL BIT(_SDEI_MAPF_CRITICAL_SHIFT)
+
+/* Indices of private and shared mappings */
+#define _SDEI_MAP_IDX_PRIV 0
+#define _SDEI_MAP_IDX_SHRD 1
+#define _SDEI_MAP_IDX_MAX 2
+
+/* The macros below are used to identify SDEI calls from the SMC function ID */
+#define SDEI_FID_MASK U(0xffe0)
+#define SDEI_FID_VALUE U(0x20)
+#define is_sdei_fid(_fid) \
+ ((((_fid) & SDEI_FID_MASK) == SDEI_FID_VALUE) && \
+ (((_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64))
+
+#define SDEI_EVENT_MAP(_event, _intr, _flags) \
+ { \
+ .ev_num = _event, \
+ .intr = _intr, \
+ .map_flags = _flags \
+ }
+
+#define SDEI_SHARED_EVENT(_event, _intr, _flags) \
+ SDEI_EVENT_MAP(_event, _intr, _flags)
+
+#define SDEI_PRIVATE_EVENT(_event, _intr, _flags) \
+ SDEI_EVENT_MAP(_event, _intr, _flags | SDEI_MAPF_PRIVATE)
+
+#define SDEI_DEFINE_EVENT_0(_intr) \
+ SDEI_PRIVATE_EVENT(SDEI_EVENT_0, _intr, SDEI_MAPF_SIGNALABLE)
+
+/*
+ * Declare shared and private entries for each core. Also declare a global
+ * structure containing private and share entries.
+ *
+ * This macro must be used in the same file as the platform SDEI mappings are
+ * declared. Only then would ARRAY_SIZE() yield a meaningful value.
+ */
+#define REGISTER_SDEI_MAP(_private, _shared) \
+ sdei_entry_t sdei_private_event_table \
+ [PLATFORM_CORE_COUNT * ARRAY_SIZE(_private)]; \
+ sdei_entry_t sdei_shared_event_table[ARRAY_SIZE(_shared)]; \
+ const sdei_mapping_t sdei_global_mappings[] = { \
+ [_SDEI_MAP_IDX_PRIV] = { \
+ .map = _private, \
+ .num_maps = ARRAY_SIZE(_private) \
+ }, \
+ [_SDEI_MAP_IDX_SHRD] = { \
+ .map = _shared, \
+ .num_maps = ARRAY_SIZE(_shared) \
+ }, \
+ }
+
+typedef uint8_t sdei_state_t;
+
+/* Runtime data of SDEI event */
+typedef struct sdei_entry {
+ uint64_t ep; /* Entry point */
+ uint64_t arg; /* Entry point argument */
+ uint64_t affinity; /* Affinity of shared event */
+ unsigned int reg_flags; /* Registration flags */
+
+ /* Event handler states: registered, enabled, running */
+ sdei_state_t state;
+} sdei_entry_t;
+
+/* Mapping of SDEI events to interrupts, and associated data */
+typedef struct sdei_ev_map {
+ int32_t ev_num; /* Event number */
+ unsigned int intr; /* Physical interrupt number for a bound map */
+ unsigned int map_flags; /* Mapping flags, see SDEI_MAPF_* */
+ int reg_count; /* Registration count */
+ spinlock_t lock; /* Per-event lock */
+} sdei_ev_map_t;
+
+typedef struct sdei_mapping {
+ sdei_ev_map_t *map;
+ size_t num_maps;
+} sdei_mapping_t;
+
+/* Handler to be called to handle SDEI smc calls */
+uint64_t sdei_smc_handler(uint32_t smc_fid,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags);
+
+void sdei_init(void);
+
+/* Public API to dispatch an event to Normal world */
+int sdei_dispatch_event(int ev_num, unsigned int preempted_sec_state);
+
+#endif /* __SDEI_H__ */
diff --git a/include/services/secure_partition.h b/include/services/secure_partition.h
new file mode 100644
index 00000000..334f7610
--- /dev/null
+++ b/include/services/secure_partition.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SECURE_PARTITION_H__
+#define __SECURE_PARTITION_H__
+
+#include <bl_common.h>
+#include <types.h>
+#include <utils_def.h>
+
+/* Linker symbols */
+extern uintptr_t __SP_IMAGE_XLAT_TABLES_START__;
+extern uintptr_t __SP_IMAGE_XLAT_TABLES_END__;
+
+/* Definitions */
+#define SP_IMAGE_XLAT_TABLES_START \
+ (uintptr_t)(&__SP_IMAGE_XLAT_TABLES_START__)
+#define SP_IMAGE_XLAT_TABLES_END \
+ (uintptr_t)(&__SP_IMAGE_XLAT_TABLES_END__)
+#define SP_IMAGE_XLAT_TABLES_SIZE \
+ (SP_IMAGE_XLAT_TABLES_END - SP_IMAGE_XLAT_TABLES_START)
+
+/*
+ * Flags used by the secure_partition_mp_info structure to describe the
+ * characteristics of a cpu. Only a single flag is defined at the moment to
+ * indicate the primary cpu.
+ */
+#define MP_INFO_FLAG_PRIMARY_CPU U(0x00000001)
+
+/*
+ * This structure is used to provide information required to initialise a S-EL0
+ * partition.
+ */
+typedef struct secure_partition_mp_info {
+ u_register_t mpidr;
+ unsigned int linear_id;
+ unsigned int flags;
+} secure_partition_mp_info_t;
+
+typedef struct secure_partition_boot_info {
+ param_header_t h;
+ uintptr_t sp_mem_base;
+ uintptr_t sp_mem_limit;
+ uintptr_t sp_image_base;
+ uintptr_t sp_stack_base;
+ uintptr_t sp_heap_base;
+ uintptr_t sp_ns_comm_buf_base;
+ uintptr_t sp_shared_buf_base;
+ size_t sp_image_size;
+ size_t sp_pcpu_stack_size;
+ size_t sp_heap_size;
+ size_t sp_ns_comm_buf_size;
+ size_t sp_shared_buf_size;
+ unsigned int num_sp_mem_regions;
+ unsigned int num_cpus;
+ secure_partition_mp_info_t *mp_info;
+} secure_partition_boot_info_t;
+
+/* Setup function for secure partitions context. */
+
+void secure_partition_setup(void);
+
+#endif /* __SECURE_PARTITION_H__ */
diff --git a/include/services/spm_svc.h b/include/services/spm_svc.h
new file mode 100644
index 00000000..738979eb
--- /dev/null
+++ b/include/services/spm_svc.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SPM_SVC_H__
+#define __SPM_SVC_H__
+
+#include <utils_def.h>
+
+#define SPM_VERSION_MAJOR U(0)
+#define SPM_VERSION_MINOR U(1)
+#define SPM_VERSION_FORM(major, minor) ((major << 16) | (minor))
+#define SPM_VERSION_COMPILED SPM_VERSION_FORM(SPM_VERSION_MAJOR, SPM_VERSION_MINOR)
+
+#define SP_VERSION_MAJOR U(1)
+#define SP_VERSION_MINOR U(0)
+#define SP_VERSION_FORM(major, minor) ((major << 16) | (minor))
+#define SP_VERSION_COMPILED SP_VERSION_FORM(SP_VERSION_MAJOR, SP_VERSION_MINOR)
+
+/* The macros below are used to identify SPM calls from the SMC function ID */
+#define SPM_FID_MASK U(0xffff)
+#define SPM_FID_MIN_VALUE U(0x40)
+#define SPM_FID_MAX_VALUE U(0x7f)
+#define is_spm_fid(_fid) \
+ ((((_fid) & SPM_FID_MASK) >= SPM_FID_MIN_VALUE) && \
+ (((_fid) & SPM_FID_MASK) <= SPM_FID_MAX_VALUE))
+
+/*
+ * SMC IDs defined for accessing services implemented by the Secure Partition
+ * Manager from the Secure Partition(s). These services enable a partition to
+ * handle delegated events and request privileged operations from the manager.
+ */
+#define SPM_VERSION_AARCH32 U(0x84000060)
+#define SP_EVENT_COMPLETE_AARCH64 U(0xC4000061)
+#define SP_MEMORY_ATTRIBUTES_GET_AARCH64 U(0xC4000064)
+#define SP_MEMORY_ATTRIBUTES_SET_AARCH64 U(0xC4000065)
+
+/*
+ * Macros used by SP_MEMORY_ATTRIBUTES_SET_AARCH64.
+ */
+
+#define SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS U(0)
+#define SP_MEMORY_ATTRIBUTES_ACCESS_RW U(1)
+/* Value U(2) is reserved. */
+#define SP_MEMORY_ATTRIBUTES_ACCESS_RO U(3)
+#define SP_MEMORY_ATTRIBUTES_ACCESS_MASK U(3)
+#define SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT 0
+
+#define SP_MEMORY_ATTRIBUTES_EXEC (U(0) << 2)
+#define SP_MEMORY_ATTRIBUTES_NON_EXEC (U(1) << 2)
+
+/*
+ * SMC IDs defined in [1] for accessing secure partition services from the
+ * Non-secure world. These FIDs occupy the range 0x40 - 0x5f
+ * [1] DEN0060A_ARM_MM_Interface_Specification.pdf
+ */
+#define SP_VERSION_AARCH64 U(0xC4000040)
+#define SP_VERSION_AARCH32 U(0x84000040)
+
+#define MM_COMMUNICATE_AARCH64 U(0xC4000041)
+#define MM_COMMUNICATE_AARCH32 U(0x84000041)
+
+/* SPM error codes. */
+#define SPM_SUCCESS 0
+#define SPM_NOT_SUPPORTED -1
+#define SPM_INVALID_PARAMETER -2
+#define SPM_DENIED -3
+#define SPM_NO_MEMORY -5
+
+#ifndef __ASSEMBLY__
+
+#include <stdint.h>
+
+int32_t spm_setup(void);
+
+uint64_t spm_smc_handler(uint32_t smc_fid,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __SPM_SVC_H__ */
diff --git a/lib/aarch32/arm32_aeabi_divmod.c b/lib/aarch32/arm32_aeabi_divmod.c
new file mode 100644
index 00000000..a8f2e742
--- /dev/null
+++ b/lib/aarch32/arm32_aeabi_divmod.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Form ABI specifications:
+ * int __aeabi_idiv(int numerator, int denominator);
+ * unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
+ *
+ * typedef struct { int quot; int rem; } idiv_return;
+ * typedef struct { unsigned quot; unsigned rem; } uidiv_return;
+ *
+ * __value_in_regs idiv_return __aeabi_idivmod(int numerator,
+ * int *denominator);
+ * __value_in_regs uidiv_return __aeabi_uidivmod(unsigned *numerator,
+ * unsigned denominator);
+ */
+
+/* struct qr - stores qutient/remainder to handle divmod EABI interfaces. */
+struct qr {
+ unsigned int q; /* computed quotient */
+ unsigned int r; /* computed remainder */
+ unsigned int q_n; /* specficies if quotient shall be negative */
+ unsigned int r_n; /* specficies if remainder shall be negative */
+};
+
+static void uint_div_qr(unsigned int numerator, unsigned int denominator,
+ struct qr *qr);
+
+/* returns in R0 and R1 by tail calling an asm function */
+unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator);
+
+unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator);
+unsigned int __aeabi_uimod(unsigned int numerator, unsigned int denominator);
+
+/* returns in R0 and R1 by tail calling an asm function */
+signed int __aeabi_idivmod(signed int numerator, signed int denominator);
+
+signed int __aeabi_idiv(signed int numerator, signed int denominator);
+signed int __aeabi_imod(signed int numerator, signed int denominator);
+
+/*
+ * __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator)
+ * Numerator and Denominator are received in R0 and R1.
+ * Where __ste_idivmod_ret_t is returned in R0 and R1.
+ *
+ * __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator,
+ * unsigned denominator)
+ * Numerator and Denominator are received in R0 and R1.
+ * Where __ste_uidivmod_ret_t is returned in R0 and R1.
+ */
+#ifdef __GNUC__
+signed int ret_idivmod_values(signed int quotient, signed int remainder);
+unsigned int ret_uidivmod_values(unsigned int quotient, unsigned int remainder);
+#else
+#error "Compiler not supported"
+#endif
+
+static void division_qr(unsigned int n, unsigned int p, struct qr *qr)
+{
+ unsigned int i = 1, q = 0;
+
+ if (p == 0) {
+ qr->r = 0xFFFFFFFF; /* division by 0 */
+ return;
+ }
+
+ while ((p >> 31) == 0) {
+ i = i << 1; /* count the max division steps */
+ p = p << 1; /* increase p until it has maximum size*/
+ }
+
+ while (i > 0) {
+ q = q << 1; /* write bit in q at index (size-1) */
+ if (n >= p) {
+ n -= p;
+ q++;
+ }
+ p = p >> 1; /* decrease p */
+ i = i >> 1; /* decrease remaining size in q */
+ }
+ qr->r = n;
+ qr->q = q;
+}
+
+static void uint_div_qr(unsigned int numerator, unsigned int denominator,
+ struct qr *qr)
+{
+ division_qr(numerator, denominator, qr);
+
+ /* negate quotient and/or remainder according to requester */
+ if (qr->q_n)
+ qr->q = -qr->q;
+ if (qr->r_n)
+ qr->r = -qr->r;
+}
+
+unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator)
+{
+ struct qr qr = { .q_n = 0, .r_n = 0 };
+
+ uint_div_qr(numerator, denominator, &qr);
+
+ return qr.q;
+}
+
+unsigned int __aeabi_uimod(unsigned int numerator, unsigned int denominator)
+{
+ struct qr qr = { .q_n = 0, .r_n = 0 };
+
+ uint_div_qr(numerator, denominator, &qr);
+
+ return qr.r;
+}
+
+unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator)
+{
+ struct qr qr = { .q_n = 0, .r_n = 0 };
+
+ uint_div_qr(numerator, denominator, &qr);
+
+ return ret_uidivmod_values(qr.q, qr.r);
+}
+
+signed int __aeabi_idiv(signed int numerator, signed int denominator)
+{
+ struct qr qr = { .q_n = 0, .r_n = 0 };
+
+ if (((numerator < 0) && (denominator > 0)) ||
+ ((numerator > 0) && (denominator < 0)))
+ qr.q_n = 1; /* quotient shall be negate */
+
+ if (numerator < 0) {
+ numerator = -numerator;
+ qr.r_n = 1; /* remainder shall be negate */
+ }
+
+ if (denominator < 0)
+ denominator = -denominator;
+
+ uint_div_qr(numerator, denominator, &qr);
+
+ return qr.q;
+}
+
+signed int __aeabi_imod(signed int numerator, signed int denominator)
+{
+ signed int s;
+ signed int i;
+ signed int j;
+ signed int h;
+ struct qr qr = { .q_n = 0, .r_n = 0 };
+
+ /* in case modulo of a power of 2 */
+ for (i = 0, j = 0, h = 0, s = denominator; (s != 0) || (h > 1); i++) {
+ if (s & 1) {
+ j = i;
+ h++;
+ }
+ s = s >> 1;
+ }
+ if (h == 1)
+ return numerator >> j;
+
+ if (((numerator < 0) && (denominator > 0)) ||
+ ((numerator > 0) && (denominator < 0)))
+ qr.q_n = 1; /* quotient shall be negate */
+
+ if (numerator < 0) {
+ numerator = -numerator;
+ qr.r_n = 1; /* remainder shall be negate */
+ }
+
+ if (denominator < 0)
+ denominator = -denominator;
+
+ uint_div_qr(numerator, denominator, &qr);
+
+ return qr.r;
+}
+
+signed int __aeabi_idivmod(signed int numerator, signed int denominator)
+{
+ struct qr qr = { .q_n = 0, .r_n = 0 };
+
+ if (((numerator < 0) && (denominator > 0)) ||
+ ((numerator > 0) && (denominator < 0)))
+ qr.q_n = 1; /* quotient shall be negate */
+
+ if (numerator < 0) {
+ numerator = -numerator;
+ qr.r_n = 1; /* remainder shall be negate */
+ }
+
+ if (denominator < 0)
+ denominator = -denominator;
+
+ uint_div_qr(numerator, denominator, &qr);
+
+ return ret_idivmod_values(qr.q, qr.r);
+}
diff --git a/lib/aarch32/arm32_aeabi_divmod_a32.S b/lib/aarch32/arm32_aeabi_divmod_a32.S
new file mode 100644
index 00000000..6915dcd8
--- /dev/null
+++ b/lib/aarch32/arm32_aeabi_divmod_a32.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+/*
+ * EABI wrappers from the udivmod and idivmod functions
+ */
+
+ .globl ret_uidivmod_values
+ .globl ret_idivmod_values
+
+/*
+ * signed ret_idivmod_values(signed quot, signed rem);
+ * return quotient and remaining the EABI way (regs r0,r1)
+ */
+func ret_idivmod_values
+ bx lr
+endfunc ret_idivmod_values
+
+/*
+ * unsigned ret_uidivmod_values(unsigned quot, unsigned rem);
+ * return quotient and remaining the EABI way (regs r0,r1)
+ */
+func ret_uidivmod_values
+ bx lr
+endfunc ret_uidivmod_values
diff --git a/lib/aarch64/misc_helpers.S b/lib/aarch64/misc_helpers.S
index 78153bfb..9dfe46a2 100644
--- a/lib/aarch64/misc_helpers.S
+++ b/lib/aarch64/misc_helpers.S
@@ -18,7 +18,9 @@
.globl zeromem16
.globl memcpy16
+ .globl disable_mmu_el1
.globl disable_mmu_el3
+ .globl disable_mmu_icache_el1
.globl disable_mmu_icache_el3
#if SUPPORT_VFP
@@ -451,11 +453,11 @@ endfunc memcpy16
func disable_mmu_el3
mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT)
-do_disable_mmu:
+do_disable_mmu_el3:
mrs x0, sctlr_el3
bic x0, x0, x1
msr sctlr_el3, x0
- isb // ensure MMU is off
+ isb /* ensure MMU is off */
dsb sy
ret
endfunc disable_mmu_el3
@@ -463,10 +465,32 @@ endfunc disable_mmu_el3
func disable_mmu_icache_el3
mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
- b do_disable_mmu
+ b do_disable_mmu_el3
endfunc disable_mmu_icache_el3
/* ---------------------------------------------------------------------------
+ * Disable the MMU at EL1
+ * ---------------------------------------------------------------------------
+ */
+
+func disable_mmu_el1
+ mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT)
+do_disable_mmu_el1:
+ mrs x0, sctlr_el1
+ bic x0, x0, x1
+ msr sctlr_el1, x0
+ isb /* ensure MMU is off */
+ dsb sy
+ ret
+endfunc disable_mmu_el1
+
+
+func disable_mmu_icache_el1
+ mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
+ b do_disable_mmu_el1
+endfunc disable_mmu_icache_el1
+
+/* ---------------------------------------------------------------------------
* Enable the use of VFP at EL3
* ---------------------------------------------------------------------------
*/
diff --git a/lib/cpus/aarch32/cortex_a12.S b/lib/cpus/aarch32/cortex_a12.S
new file mode 100644
index 00000000..73c97507
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a12.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a12.h>
+#include <cpu_macros.S>
+
+ .macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+ ldcopr r0, SCTLR
+ tst r0, #SCTLR_C_BIT
+ ASM_ASSERT(eq)
+#endif
+ .endm
+
+func cortex_a12_disable_smp
+ ldcopr r0, ACTLR
+ bic r0, #CORTEX_A12_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ dsb sy
+ bx lr
+endfunc cortex_a12_disable_smp
+
+func cortex_a12_enable_smp
+ ldcopr r0, ACTLR
+ orr r0, #CORTEX_A12_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ bx lr
+endfunc cortex_a12_enable_smp
+
+func cortex_a12_reset_func
+ b cortex_a12_enable_smp
+endfunc cortex_a12_reset_func
+
+func cortex_a12_core_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 cache */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a12_disable_smp
+endfunc cortex_a12_core_pwr_dwn
+
+func cortex_a12_cluster_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 caches */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ bl plat_disable_acp
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a12_disable_smp
+endfunc cortex_a12_cluster_pwr_dwn
+
+declare_cpu_ops cortex_a12, CORTEX_A12_MIDR, \
+ cortex_a12_reset_func, \
+ cortex_a12_core_pwr_dwn, \
+ cortex_a12_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a15.S b/lib/cpus/aarch32/cortex_a15.S
new file mode 100644
index 00000000..0d5a1165
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a15.S
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a15.h>
+#include <cpu_macros.S>
+
+/*
+ * Cortex-A15 support LPAE and Virtualization Extensions.
+ * Don't care if confiugration uses or not LPAE and VE.
+ * Therefore, where we don't check ARCH_IS_ARMV7_WITH_LPAE/VE
+ */
+
+ .macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+ ldcopr r0, SCTLR
+ tst r0, #SCTLR_C_BIT
+ ASM_ASSERT(eq)
+#endif
+ .endm
+
+func cortex_a15_disable_smp
+ ldcopr r0, ACTLR
+ bic r0, #CORTEX_A15_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ dsb sy
+ bx lr
+endfunc cortex_a15_disable_smp
+
+func cortex_a15_enable_smp
+ ldcopr r0, ACTLR
+ orr r0, #CORTEX_A15_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ bx lr
+endfunc cortex_a15_enable_smp
+
+func cortex_a15_reset_func
+ b cortex_a15_enable_smp
+endfunc cortex_a15_reset_func
+
+func cortex_a15_core_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 cache */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a15_disable_smp
+endfunc cortex_a15_core_pwr_dwn
+
+func cortex_a15_cluster_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 caches */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ bl plat_disable_acp
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a15_disable_smp
+endfunc cortex_a15_cluster_pwr_dwn
+
+declare_cpu_ops cortex_a15, CORTEX_A15_MIDR, \
+ cortex_a15_reset_func, \
+ cortex_a15_core_pwr_dwn, \
+ cortex_a15_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a17.S b/lib/cpus/aarch32/cortex_a17.S
new file mode 100644
index 00000000..316d4f05
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a17.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a17.h>
+#include <cpu_macros.S>
+
+ .macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+ ldcopr r0, SCTLR
+ tst r0, #SCTLR_C_BIT
+ ASM_ASSERT(eq)
+#endif
+ .endm
+
+func cortex_a17_disable_smp
+ ldcopr r0, ACTLR
+ bic r0, #CORTEX_A17_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ dsb sy
+ bx lr
+endfunc cortex_a17_disable_smp
+
+func cortex_a17_enable_smp
+ ldcopr r0, ACTLR
+ orr r0, #CORTEX_A17_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ bx lr
+endfunc cortex_a17_enable_smp
+
+func cortex_a17_reset_func
+ b cortex_a17_enable_smp
+endfunc cortex_a17_reset_func
+
+func cortex_a17_core_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 cache */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a17_disable_smp
+endfunc cortex_a17_core_pwr_dwn
+
+func cortex_a17_cluster_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 caches */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ bl plat_disable_acp
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a17_disable_smp
+endfunc cortex_a17_cluster_pwr_dwn
+
+declare_cpu_ops cortex_a17, CORTEX_A17_MIDR, \
+ cortex_a17_reset_func, \
+ cortex_a17_core_pwr_dwn, \
+ cortex_a17_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a5.S b/lib/cpus/aarch32/cortex_a5.S
new file mode 100644
index 00000000..c07c13ea
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a5.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a5.h>
+#include <cpu_macros.S>
+
+ .macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+ ldcopr r0, SCTLR
+ tst r0, #SCTLR_C_BIT
+ ASM_ASSERT(eq)
+#endif
+ .endm
+
+func cortex_a5_disable_smp
+ ldcopr r0, ACTLR
+ bic r0, #CORTEX_A5_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ dsb sy
+ bx lr
+endfunc cortex_a5_disable_smp
+
+func cortex_a5_enable_smp
+ ldcopr r0, ACTLR
+ orr r0, #CORTEX_A5_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ bx lr
+endfunc cortex_a5_enable_smp
+
+func cortex_a5_reset_func
+ b cortex_a5_enable_smp
+endfunc cortex_a5_reset_func
+
+func cortex_a5_core_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 cache */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a5_disable_smp
+endfunc cortex_a5_core_pwr_dwn
+
+func cortex_a5_cluster_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 caches */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ bl plat_disable_acp
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a5_disable_smp
+endfunc cortex_a5_cluster_pwr_dwn
+
+declare_cpu_ops cortex_a5, CORTEX_A5_MIDR, \
+ cortex_a5_reset_func, \
+ cortex_a5_core_pwr_dwn, \
+ cortex_a5_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a53.S b/lib/cpus/aarch32/cortex_a53.S
index 74cedc35..1647e169 100644
--- a/lib/cpus/aarch32/cortex_a53.S
+++ b/lib/cpus/aarch32/cortex_a53.S
@@ -174,7 +174,7 @@ func cortex_a53_core_pwr_dwn
push {r12, lr}
/* Assert if cache is enabled */
-#if ASM_ASSERTION
+#if ENABLE_ASSERTIONS
ldcopr r0, SCTLR
tst r0, #SCTLR_C_BIT
ASM_ASSERT(eq)
@@ -204,7 +204,7 @@ func cortex_a53_cluster_pwr_dwn
push {r12, lr}
/* Assert if cache is enabled */
-#if ASM_ASSERTION
+#if ENABLE_ASSERTIONS
ldcopr r0, SCTLR
tst r0, #SCTLR_C_BIT
ASM_ASSERT(eq)
diff --git a/lib/cpus/aarch32/cortex_a57.S b/lib/cpus/aarch32/cortex_a57.S
index b5189e77..64a6d674 100644
--- a/lib/cpus/aarch32/cortex_a57.S
+++ b/lib/cpus/aarch32/cortex_a57.S
@@ -406,7 +406,7 @@ func cortex_a57_core_pwr_dwn
push {r12, lr}
/* Assert if cache is enabled */
-#if ASM_ASSERTION
+#if ENABLE_ASSERTIONS
ldcopr r0, SCTLR
tst r0, #SCTLR_C_BIT
ASM_ASSERT(eq)
@@ -448,7 +448,7 @@ func cortex_a57_cluster_pwr_dwn
push {r12, lr}
/* Assert if cache is enabled */
-#if ASM_ASSERTION
+#if ENABLE_ASSERTIONS
ldcopr r0, SCTLR
tst r0, #SCTLR_C_BIT
ASM_ASSERT(eq)
diff --git a/lib/cpus/aarch32/cortex_a7.S b/lib/cpus/aarch32/cortex_a7.S
new file mode 100644
index 00000000..0278d1fd
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a7.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a7.h>
+#include <cpu_macros.S>
+
+ .macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+ ldcopr r0, SCTLR
+ tst r0, #SCTLR_C_BIT
+ ASM_ASSERT(eq)
+#endif
+ .endm
+
+func cortex_a7_disable_smp
+ ldcopr r0, ACTLR
+ bic r0, #CORTEX_A7_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ dsb sy
+ bx lr
+endfunc cortex_a7_disable_smp
+
+func cortex_a7_enable_smp
+ ldcopr r0, ACTLR
+ orr r0, #CORTEX_A7_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ bx lr
+endfunc cortex_a7_enable_smp
+
+func cortex_a7_reset_func
+ b cortex_a7_enable_smp
+endfunc cortex_a7_reset_func
+
+func cortex_a7_core_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 cache */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a7_disable_smp
+endfunc cortex_a7_core_pwr_dwn
+
+func cortex_a7_cluster_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 caches */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ bl plat_disable_acp
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a7_disable_smp
+endfunc cortex_a7_cluster_pwr_dwn
+
+declare_cpu_ops cortex_a7, CORTEX_A7_MIDR, \
+ cortex_a7_reset_func, \
+ cortex_a7_core_pwr_dwn, \
+ cortex_a7_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a72.S b/lib/cpus/aarch32/cortex_a72.S
index 69cc2ea5..75505206 100644
--- a/lib/cpus/aarch32/cortex_a72.S
+++ b/lib/cpus/aarch32/cortex_a72.S
@@ -120,7 +120,7 @@ func cortex_a72_core_pwr_dwn
push {r12, lr}
/* Assert if cache is enabled */
-#if ASM_ASSERTION
+#if ENABLE_ASSERTIONS
ldcopr r0, SCTLR
tst r0, #SCTLR_C_BIT
ASM_ASSERT(eq)
@@ -167,7 +167,7 @@ func cortex_a72_cluster_pwr_dwn
push {r12, lr}
/* Assert if cache is enabled */
-#if ASM_ASSERTION
+#if ENABLE_ASSERTIONS
ldcopr r0, SCTLR
tst r0, #SCTLR_C_BIT
ASM_ASSERT(eq)
diff --git a/lib/cpus/aarch32/cortex_a9.S b/lib/cpus/aarch32/cortex_a9.S
new file mode 100644
index 00000000..4f30f84a
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a9.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a9.h>
+#include <cpu_macros.S>
+
+ .macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+ ldcopr r0, SCTLR
+ tst r0, #SCTLR_C_BIT
+ ASM_ASSERT(eq)
+#endif
+ .endm
+
+func cortex_a9_disable_smp
+ ldcopr r0, ACTLR
+ bic r0, #CORTEX_A9_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ dsb sy
+ bx lr
+endfunc cortex_a9_disable_smp
+
+func cortex_a9_enable_smp
+ ldcopr r0, ACTLR
+ orr r0, #CORTEX_A9_ACTLR_SMP_BIT
+ stcopr r0, ACTLR
+ isb
+ bx lr
+endfunc cortex_a9_enable_smp
+
+func cortex_a9_reset_func
+ b cortex_a9_enable_smp
+endfunc cortex_a9_reset_func
+
+func cortex_a9_core_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 cache */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a9_disable_smp
+endfunc cortex_a9_core_pwr_dwn
+
+func cortex_a9_cluster_pwr_dwn
+ push {r12, lr}
+
+ assert_cache_enabled
+
+ /* Flush L1 caches */
+ mov r0, #DC_OP_CISW
+ bl dcsw_op_level1
+
+ bl plat_disable_acp
+
+ /* Exit cluster coherency */
+ pop {r12, lr}
+ b cortex_a9_disable_smp
+endfunc cortex_a9_cluster_pwr_dwn
+
+declare_cpu_ops cortex_a9, CORTEX_A9_MIDR, \
+ cortex_a9_reset_func, \
+ cortex_a9_core_pwr_dwn, \
+ cortex_a9_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a75.S b/lib/cpus/aarch64/cortex_a75.S
index 1f4500cb..4cab9e4f 100644
--- a/lib/cpus/aarch64/cortex_a75.S
+++ b/lib/cpus/aarch64/cortex_a75.S
@@ -11,6 +11,33 @@
#include <plat_macros.S>
#include <cortex_a75.h>
+func cortex_a75_reset_func
+#if ENABLE_AMU
+ /* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */
+ mrs x0, actlr_el3
+ orr x0, x0, #CORTEX_A75_ACTLR_AMEN_BIT
+ msr actlr_el3, x0
+ isb
+
+ /* Make sure accesses from EL0/EL1 are not trapped to EL2 */
+ mrs x0, actlr_el2
+ orr x0, x0, #CORTEX_A75_ACTLR_AMEN_BIT
+ msr actlr_el2, x0
+ isb
+
+ /* Enable group0 counters */
+ mov x0, #CORTEX_A75_AMU_GROUP0_MASK
+ msr CPUAMCNTENSET_EL0, x0
+ isb
+
+ /* Enable group1 counters */
+ mov x0, #CORTEX_A75_AMU_GROUP1_MASK
+ msr CPUAMCNTENSET_EL0, x0
+ isb
+#endif
+ ret
+endfunc cortex_a75_reset_func
+
/* ---------------------------------------------
* HW will do the cache maintenance while powering down
* ---------------------------------------------
@@ -47,5 +74,5 @@ func cortex_a75_cpu_reg_dump
endfunc cortex_a75_cpu_reg_dump
declare_cpu_ops cortex_a75, CORTEX_A75_MIDR, \
- CPU_NO_RESET_FUNC, \
+ cortex_a75_reset_func, \
cortex_a75_core_pwr_dwn
diff --git a/lib/el3_runtime/aarch32/context_mgmt.c b/lib/el3_runtime/aarch32/context_mgmt.c
index 3e7a5b73..76e440e3 100644
--- a/lib/el3_runtime/aarch32/context_mgmt.c
+++ b/lib/el3_runtime/aarch32/context_mgmt.c
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <amu.h>
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
@@ -125,6 +126,20 @@ static void cm_init_context_common(cpu_context_t *ctx, const entry_point_info_t
}
/*******************************************************************************
+ * Enable architecture extensions on first entry to Non-secure world.
+ * When EL2 is implemented but unused `el2_unused` is non-zero, otherwise
+ * it is zero.
+ ******************************************************************************/
+static void enable_extensions_nonsecure(int el2_unused)
+{
+#if IMAGE_BL32
+#if ENABLE_AMU
+ amu_enable(el2_unused);
+#endif
+#endif
+}
+
+/*******************************************************************************
* The following function initializes the cpu_context for a CPU specified by
* its `cpu_idx` for first use, and sets the initial entrypoint state as
* specified by the entry_point_info structure.
@@ -161,6 +176,7 @@ void cm_prepare_el3_exit(uint32_t security_state)
{
uint32_t hsctlr, scr;
cpu_context_t *ctx = cm_get_context(security_state);
+ int el2_unused = 0;
assert(ctx);
@@ -185,6 +201,8 @@ void cm_prepare_el3_exit(uint32_t security_state)
isb();
} else if (read_id_pfr1() &
(ID_PFR1_VIRTEXT_MASK << ID_PFR1_VIRTEXT_SHIFT)) {
+ el2_unused = 1;
+
/*
* Set the NS bit to access NS copies of certain banked
* registers
@@ -283,5 +301,6 @@ void cm_prepare_el3_exit(uint32_t security_state)
write_scr(read_scr() & ~SCR_NS_BIT);
isb();
}
+ enable_extensions_nonsecure(el2_unused);
}
}
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index 8a6c11b7..620ec16f 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -9,7 +9,6 @@
#include <context.h>
.global el1_sysregs_context_save
- .global el1_sysregs_context_save_post_ops
.global el1_sysregs_context_restore
#if CTX_INCLUDE_FPREGS
.global fpregs_context_save
@@ -74,6 +73,9 @@ 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
@@ -87,9 +89,6 @@ func el1_sysregs_context_save
mrs x15, dacr32_el2
mrs x16, ifsr32_el2
stp x15, x16, [x0, #CTX_DACR32_EL2]
-
- mrs x17, fpexc32_el2
- str x17, [x0, #CTX_FP_FPEXC32_EL2]
#endif
/* Save NS timer registers if the build has instructed so */
@@ -112,36 +111,6 @@ endfunc el1_sysregs_context_save
/* -----------------------------------------------------
* The following function strictly follows the AArch64
* PCS to use x9-x17 (temporary caller-saved registers)
- * to do post operations after saving the EL1 system
- * register context.
- * -----------------------------------------------------
- */
-func el1_sysregs_context_save_post_ops
-#if ENABLE_SPE_FOR_LOWER_ELS
- /* Detect if SPE is implemented */
- mrs x9, id_aa64dfr0_el1
- ubfx x9, x9, #ID_AA64DFR0_PMS_SHIFT, #ID_AA64DFR0_PMS_LENGTH
- cmp x9, #0x1
- b.ne 1f
-
- /*
- * Before switching from normal world to secure world
- * the profiling buffers need to be drained out to memory. This is
- * required to avoid an invalid memory access when TTBR is switched
- * for entry to SEL1.
- */
- .arch armv8.2-a+profile
- psb csync
- dsb nsh
- .arch armv8-a
-1:
-#endif
- ret
-endfunc el1_sysregs_context_save_post_ops
-
-/* -----------------------------------------------------
- * 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
@@ -193,6 +162,9 @@ 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]
@@ -206,9 +178,6 @@ func el1_sysregs_context_restore
ldp x15, x16, [x0, #CTX_DACR32_EL2]
msr dacr32_el2, x15
msr ifsr32_el2, x16
-
- ldr x17, [x0, #CTX_FP_FPEXC32_EL2]
- msr fpexc32_el2, x17
#endif
/* Restore NS timer registers if the build has instructed so */
#if NS_TIMER_SWITCH
@@ -269,6 +238,10 @@ func fpregs_context_save
mrs x10, fpcr
str x10, [x0, #CTX_FP_FPCR]
+#if CTX_INCLUDE_AARCH32_REGS
+ mrs x11, fpexc32_el2
+ str x11, [x0, #CTX_FP_FPEXC32_EL2]
+#endif
ret
endfunc fpregs_context_save
@@ -312,6 +285,10 @@ func fpregs_context_restore
ldr x10, [x0, #CTX_FP_FPCR]
msr fpcr, x10
+#if CTX_INCLUDE_AARCH32_REGS
+ ldr x11, [x0, #CTX_FP_FPEXC32_EL2]
+ msr fpexc32_el2, x11
+#endif
/*
* No explict ISB required here as ERET to
* switch to secure EL1 or non-secure world
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 3d26056a..c6c2249a 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <amu.h>
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
@@ -13,8 +14,11 @@
#include <interrupt_mgmt.h>
#include <platform.h>
#include <platform_def.h>
+#include <pubsub_events.h>
#include <smcc_helpers.h>
+#include <spe.h>
#include <string.h>
+#include <sve.h>
#include <utils.h>
@@ -58,7 +62,7 @@ void cm_init(void)
static void cm_init_context_common(cpu_context_t *ctx, const entry_point_info_t *ep)
{
unsigned int security_state;
- uint32_t scr_el3;
+ uint32_t scr_el3, pmcr_el0;
el3_state_t *state;
gp_regs_t *gp_regs;
unsigned long sctlr_elx;
@@ -164,11 +168,35 @@ static void cm_init_context_common(cpu_context_t *ctx, const entry_point_info_t
/*
* Store the initialised SCTLR_EL1 value in the cpu_context - SCTLR_EL2
- * and other EL2 resgisters are set up by cm_preapre_ns_entry() as they
+ * and other EL2 registers are set up by cm_preapre_ns_entry() as they
* are not part of the stored cpu_context.
*/
write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_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 */
state = get_el3state_ctx(ctx);
write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
@@ -184,6 +212,28 @@ static void cm_init_context_common(cpu_context_t *ctx, const entry_point_info_t
}
/*******************************************************************************
+ * Enable architecture extensions on first entry to Non-secure world.
+ * When EL2 is implemented but unused `el2_unused` is non-zero, otherwise
+ * it is zero.
+ ******************************************************************************/
+static void enable_extensions_nonsecure(int el2_unused)
+{
+#if IMAGE_BL31
+#if ENABLE_SPE_FOR_LOWER_ELS
+ spe_enable(el2_unused);
+#endif
+
+#if ENABLE_AMU
+ amu_enable(el2_unused);
+#endif
+
+#if ENABLE_SVE_FOR_NS
+ sve_enable(el2_unused);
+#endif
+#endif
+}
+
+/*******************************************************************************
* The following function initializes the cpu_context for a CPU specified by
* its `cpu_idx` for first use, and sets the initial entrypoint state as
* specified by the entry_point_info structure.
@@ -220,6 +270,7 @@ void cm_prepare_el3_exit(uint32_t security_state)
{
uint32_t sctlr_elx, scr_el3, mdcr_el2;
cpu_context_t *ctx = cm_get_context(security_state);
+ int el2_unused = 0;
assert(ctx);
@@ -233,6 +284,8 @@ void cm_prepare_el3_exit(uint32_t security_state)
sctlr_elx |= SCTLR_EL2_RES1;
write_sctlr_el2(sctlr_elx);
} else if (EL_IMPLEMENTED(2)) {
+ el2_unused = 1;
+
/*
* EL2 present but unused, need to disable safely.
* SCTLR_EL2 can be ignored in this case.
@@ -315,13 +368,6 @@ void cm_prepare_el3_exit(uint32_t security_state)
* relying on hw. Some fields are architecturally
* UNKNOWN on reset.
*
- * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical
- * profiling controls to EL2.
- *
- * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in non-secure
- * state. Accesses to profiling buffer controls at
- * non-secure EL1 are not trapped to EL2.
- *
* 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.
@@ -358,22 +404,6 @@ void cm_prepare_el3_exit(uint32_t security_state)
| MDCR_EL2_HPME_BIT | MDCR_EL2_TPM_BIT
| MDCR_EL2_TPMCR_BIT));
-#if ENABLE_SPE_FOR_LOWER_ELS
- uint64_t id_aa64dfr0_el1;
-
- /* Detect if SPE is implemented */
- id_aa64dfr0_el1 = read_id_aa64dfr0_el1() >>
- ID_AA64DFR0_PMS_SHIFT;
- if ((id_aa64dfr0_el1 & ID_AA64DFR0_PMS_MASK) == 1) {
- /*
- * Make sure traps to EL2 are not generated if
- * EL2 is implemented but not used.
- */
- mdcr_el2 &= ~MDCR_EL2_TPMS;
- mdcr_el2 |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1);
- }
-#endif
-
write_mdcr_el2(mdcr_el2);
/*
@@ -395,11 +425,11 @@ void cm_prepare_el3_exit(uint32_t security_state)
write_cnthp_ctl_el2(CNTHP_CTL_RESET_VAL &
~(CNTHP_CTL_ENABLE_BIT));
}
+ enable_extensions_nonsecure(el2_unused);
}
- el1_sysregs_context_restore(get_sysregs_ctx(ctx));
-
- cm_set_next_context(ctx);
+ cm_el1_sysregs_context_restore(security_state);
+ cm_set_next_eret_context(security_state);
}
/*******************************************************************************
@@ -415,7 +445,13 @@ void cm_el1_sysregs_context_save(uint32_t security_state)
assert(ctx);
el1_sysregs_context_save(get_sysregs_ctx(ctx));
- el1_sysregs_context_save_post_ops();
+
+#if IMAGE_BL31
+ if (security_state == SECURE)
+ PUBLISH_EVENT(cm_exited_secure_world);
+ else
+ PUBLISH_EVENT(cm_exited_normal_world);
+#endif
}
void cm_el1_sysregs_context_restore(uint32_t security_state)
@@ -426,6 +462,13 @@ void cm_el1_sysregs_context_restore(uint32_t security_state)
assert(ctx);
el1_sysregs_context_restore(get_sysregs_ctx(ctx));
+
+#if IMAGE_BL31
+ if (security_state == SECURE)
+ PUBLISH_EVENT(cm_entering_secure_world);
+ else
+ PUBLISH_EVENT(cm_entering_normal_world);
+#endif
}
/*******************************************************************************
diff --git a/lib/extensions/amu/aarch32/amu.c b/lib/extensions/amu/aarch32/amu.c
new file mode 100644
index 00000000..d450bd69
--- /dev/null
+++ b/lib/extensions/amu/aarch32/amu.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <amu.h>
+#include <arch.h>
+#include <arch_helpers.h>
+
+void amu_enable(int el2_unused)
+{
+ uint64_t features;
+
+ features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT;
+ if ((features & ID_PFR0_AMU_MASK) == 1) {
+ if (el2_unused) {
+ uint64_t v;
+
+ /*
+ * Non-secure access from EL0 or EL1 to the Activity Monitor
+ * registers do not trap to EL2.
+ */
+ v = read_hcptr();
+ v &= ~TAM_BIT;
+ write_hcptr(v);
+ }
+
+ /* Enable group 0 counters */
+ write_amcntenset0(AMU_GROUP0_COUNTERS_MASK);
+ }
+}
diff --git a/lib/extensions/amu/aarch64/amu.c b/lib/extensions/amu/aarch64/amu.c
new file mode 100644
index 00000000..007b3494
--- /dev/null
+++ b/lib/extensions/amu/aarch64/amu.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <amu.h>
+#include <arch.h>
+#include <arch_helpers.h>
+
+void amu_enable(int el2_unused)
+{
+ uint64_t features;
+
+ features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT;
+ if ((features & ID_AA64PFR0_AMU_MASK) == 1) {
+ uint64_t v;
+
+ if (el2_unused) {
+ /*
+ * CPTR_EL2.TAM: Set to zero so any accesses to
+ * the Activity Monitor registers do not trap to EL2.
+ */
+ v = read_cptr_el2();
+ v &= ~CPTR_EL2_TAM_BIT;
+ write_cptr_el2(v);
+ }
+
+ /*
+ * CPTR_EL3.TAM: Set to zero so that any accesses to
+ * the Activity Monitor registers do not trap to EL3.
+ */
+ v = read_cptr_el3();
+ v &= ~TAM_BIT;
+ write_cptr_el3(v);
+
+ /* Enable group 0 counters */
+ write_amcntenset0_el0(AMU_GROUP0_COUNTERS_MASK);
+ }
+}
diff --git a/lib/extensions/spe/spe.c b/lib/extensions/spe/spe.c
new file mode 100644
index 00000000..3b297f21
--- /dev/null
+++ b/lib/extensions/spe/spe.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <pubsub.h>
+
+/*
+ * The assembler does not yet understand the psb csync mnemonic
+ * so use the equivalent hint instruction.
+ */
+#define psb_csync() asm volatile("hint #17")
+
+void spe_enable(int el2_unused)
+{
+ uint64_t features;
+
+ features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT;
+ if ((features & ID_AA64DFR0_PMS_MASK) == 1) {
+ uint64_t v;
+
+ if (el2_unused) {
+ /*
+ * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical
+ * profiling controls to EL2.
+ *
+ * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure
+ * state. Accesses to profiling buffer controls at
+ * Non-secure EL1 are not trapped to EL2.
+ */
+ v = read_mdcr_el2();
+ v &= ~MDCR_EL2_TPMS;
+ v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1);
+ write_mdcr_el2(v);
+ }
+
+ /*
+ * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state
+ * and disabled in secure state. Accesses to SPE registers at
+ * S-EL1 generate trap exceptions to EL3.
+ */
+ v = read_mdcr_el3();
+ v |= MDCR_NSPB(MDCR_NSPB_EL1);
+ write_mdcr_el3(v);
+ }
+}
+
+void spe_disable(void)
+{
+ uint64_t features;
+
+ features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT;
+ if ((features & ID_AA64DFR0_PMS_MASK) == 1) {
+ uint64_t v;
+
+ /* Drain buffered data */
+ psb_csync();
+ dsbnsh();
+
+ /* Disable profiling buffer */
+ v = read_pmblimitr_el1();
+ v &= ~(1ULL << 0);
+ write_pmblimitr_el1(v);
+ isb();
+ }
+}
+
+static void *spe_drain_buffers_hook(const void *arg)
+{
+ uint64_t features;
+
+ features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT;
+ if ((features & ID_AA64DFR0_PMS_MASK) == 1) {
+ /* Drain buffered data */
+ psb_csync();
+ dsbnsh();
+ }
+
+ return 0;
+}
+
+SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook);
diff --git a/lib/extensions/sve/sve.c b/lib/extensions/sve/sve.c
new file mode 100644
index 00000000..14e51bd8
--- /dev/null
+++ b/lib/extensions/sve/sve.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <pubsub.h>
+#include <sve.h>
+
+static void *disable_sve_hook(const void *arg)
+{
+ uint64_t features;
+
+ features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT;
+ if ((features & ID_AA64PFR0_SVE_MASK) == 1) {
+ uint64_t cptr;
+
+ /*
+ * Disable SVE, SIMD and FP access for the Secure world.
+ * As the SIMD/FP registers are part of the SVE Z-registers, any
+ * use of SIMD/FP functionality will corrupt the SVE registers.
+ * Therefore it is necessary to prevent use of SIMD/FP support
+ * in the Secure world as well as SVE functionality.
+ */
+ cptr = read_cptr_el3();
+ cptr = (cptr | TFP_BIT) & ~(CPTR_EZ_BIT);
+ write_cptr_el3(cptr);
+
+ /*
+ * No explicit ISB required here as ERET to switch to Secure
+ * world covers it
+ */
+ }
+ return 0;
+}
+
+static void *enable_sve_hook(const void *arg)
+{
+ uint64_t features;
+
+ features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT;
+ if ((features & ID_AA64PFR0_SVE_MASK) == 1) {
+ uint64_t cptr;
+
+ /*
+ * Enable SVE, SIMD and FP access for the Non-secure world.
+ */
+ cptr = read_cptr_el3();
+ cptr = (cptr | CPTR_EZ_BIT) & ~(TFP_BIT);
+ write_cptr_el3(cptr);
+
+ /*
+ * No explicit ISB required here as ERET to switch to Non-secure
+ * world covers it
+ */
+ }
+ return 0;
+}
+
+void sve_enable(int el2_unused)
+{
+ uint64_t features;
+
+ features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT;
+ if ((features & ID_AA64PFR0_SVE_MASK) == 1) {
+ uint64_t cptr;
+#if CTX_INCLUDE_FPREGS
+ /*
+ * CTX_INCLUDE_FPREGS is not supported on SVE enabled systems.
+ */
+ assert(0);
+#endif
+ /*
+ * Update CPTR_EL3 to enable access to SVE functionality for the
+ * Non-secure world.
+ * NOTE - assumed that CPTR_EL3.TFP is set to allow access to
+ * the SIMD, floating-point and SVE support.
+ *
+ * CPTR_EL3.EZ: Set to 1 to enable access to SVE functionality
+ * in the Non-secure world.
+ */
+ cptr = read_cptr_el3();
+ cptr |= CPTR_EZ_BIT;
+ write_cptr_el3(cptr);
+
+ /*
+ * Need explicit ISB here to guarantee that update to ZCR_ELx
+ * and CPTR_EL2.TZ do not result in trap to EL3.
+ */
+ isb();
+
+ /*
+ * Ensure lower ELs have access to full vector length.
+ */
+ write_zcr_el3(ZCR_EL3_LEN_MASK);
+
+ if (el2_unused) {
+ /*
+ * Update CPTR_EL2 to enable access to SVE functionality
+ * for Non-secure world, EL2 and Non-secure EL1 and EL0.
+ * NOTE - assumed that CPTR_EL2.TFP is set to allow
+ * access to the SIMD, floating-point and SVE support.
+ *
+ * CPTR_EL2.TZ: Set to 0 to enable access to SVE support
+ * for EL2 and Non-secure EL1 and EL0.
+ */
+ cptr = read_cptr_el2();
+ cptr &= ~(CPTR_EL2_TZ_BIT);
+ write_cptr_el2(cptr);
+
+ /*
+ * Ensure lower ELs have access to full vector length.
+ */
+ write_zcr_el2(ZCR_EL2_LEN_MASK);
+ }
+ /*
+ * No explicit ISB required here as ERET to switch to
+ * Non-secure world covers it.
+ */
+ }
+}
+
+SUBSCRIBE_TO_EVENT(cm_exited_normal_world, disable_sve_hook);
+SUBSCRIBE_TO_EVENT(cm_entering_normal_world, enable_sve_hook);
diff --git a/lib/locks/exclusive/aarch32/spinlock.S b/lib/locks/exclusive/aarch32/spinlock.S
index bc77bc9c..9492cc08 100644
--- a/lib/locks/exclusive/aarch32/spinlock.S
+++ b/lib/locks/exclusive/aarch32/spinlock.S
@@ -9,6 +9,17 @@
.globl spin_lock
.globl spin_unlock
+#if ARM_ARCH_AT_LEAST(8, 0)
+/*
+ * According to the ARMv8-A Architecture Reference Manual, "when the global
+ * monitor for a PE changes from Exclusive Access state to Open Access state,
+ * an event is generated.". This applies to both AArch32 and AArch64 modes of
+ * ARMv8-A. As a result, no explicit SEV with unlock is required.
+ */
+#define COND_SEV()
+#else
+#define COND_SEV() sev
+#endif
func spin_lock
mov r2, #1
@@ -27,5 +38,6 @@ endfunc spin_lock
func spin_unlock
mov r1, #0
stl r1, [r0]
+ COND_SEV()
bx lr
endfunc spin_unlock
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
index 4502c24b..2220a745 100644
--- a/lib/psci/psci_common.c
+++ b/lib/psci/psci_common.c
@@ -767,12 +767,12 @@ void psci_warmboot_entrypoint(void)
psci_acquire_pwr_domain_locks(end_pwrlvl,
cpu_idx);
+ psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
+
#if ENABLE_PSCI_STAT
plat_psci_stat_accounting_stop(&state_info);
#endif
- psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
-
/*
* This CPU could be resuming from suspend or it could have just been
* turned on. To distinguish between these 2 cases, we examine the
diff --git a/lib/psci/psci_lib.mk b/lib/psci/psci_lib.mk
index 29080dbb..1d4aac4a 100644
--- a/lib/psci/psci_lib.mk
+++ b/lib/psci/psci_lib.mk
@@ -17,6 +17,7 @@ PSCI_LIB_SOURCES := lib/el3_runtime/cpu_data_array.c \
lib/psci/psci_main.c \
lib/psci/psci_setup.c \
lib/psci/psci_system_off.c \
+ lib/psci/psci_mem_protect.c \
lib/psci/${ARCH}/psci_helpers.S
ifeq (${ARCH}, aarch64)
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
index 257479aa..8e41cf02 100644
--- a/lib/psci/psci_main.c
+++ b/lib/psci/psci_main.c
@@ -220,6 +220,23 @@ int psci_affinity_info(u_register_t target_affinity,
if (target_idx == -1)
return PSCI_E_INVALID_PARAMS;
+ /*
+ * Generic management:
+ * Perform cache maintanence ahead of reading the target CPU state to
+ * ensure that the data is not stale.
+ * There is a theoretical edge case where the cache may contain stale
+ * data for the target CPU data - this can occur under the following
+ * conditions:
+ * - the target CPU is in another cluster from the current
+ * - the target CPU was the last CPU to shutdown on its cluster
+ * - the cluster was removed from coherency as part of the CPU shutdown
+ *
+ * In this case the cache maintenace that was performed as part of the
+ * 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(target_idx, psci_svc_cpu_data.aff_info_state);
+
return psci_get_aff_info_state_by_idx(target_idx);
}
@@ -408,6 +425,15 @@ u_register_t psci_smc_handler(uint32_t smc_fid,
case PSCI_STAT_COUNT_AARCH32:
return psci_stat_count(x1, x2);
#endif
+ case PSCI_MEM_PROTECT:
+ return psci_mem_protect(x1);
+
+ case PSCI_MEM_CHK_RANGE_AARCH32:
+ return psci_mem_chk_range(x1, x2);
+
+ case PSCI_SYSTEM_RESET2_AARCH32:
+ /* We should never return from psci_system_reset2() */
+ return psci_system_reset2(x1, x2);
default:
break;
@@ -445,6 +471,13 @@ u_register_t psci_smc_handler(uint32_t smc_fid,
return psci_stat_count(x1, x2);
#endif
+ case PSCI_MEM_CHK_RANGE_AARCH64:
+ return psci_mem_chk_range(x1, x2);
+
+ case PSCI_SYSTEM_RESET2_AARCH64:
+ /* We should never return from psci_system_reset2() */
+ return psci_system_reset2(x1, x2);
+
default:
break;
}
diff --git a/lib/psci/psci_mem_protect.c b/lib/psci/psci_mem_protect.c
new file mode 100644
index 00000000..fca84e90
--- /dev/null
+++ b/lib/psci/psci_mem_protect.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <utils.h>
+#include "psci_private.h"
+
+int psci_mem_protect(unsigned int enable)
+{
+ int val;
+
+ assert(psci_plat_pm_ops->read_mem_protect);
+ assert(psci_plat_pm_ops->write_mem_protect);
+
+ if (psci_plat_pm_ops->read_mem_protect(&val) < 0)
+ return PSCI_E_NOT_SUPPORTED;
+ if (psci_plat_pm_ops->write_mem_protect(enable) < 0)
+ return PSCI_E_NOT_SUPPORTED;
+
+ return val != 0;
+}
+
+int psci_mem_chk_range(uintptr_t base, u_register_t length)
+{
+ int ret;
+
+ assert(psci_plat_pm_ops->mem_protect_chk);
+
+ if (length == 0 || check_uptr_overflow(base, length-1))
+ return PSCI_E_DENIED;
+
+ ret = psci_plat_pm_ops->mem_protect_chk(base, length);
+ return (ret < 0) ? PSCI_E_DENIED : PSCI_E_SUCCESS;
+}
diff --git a/lib/psci/psci_on.c b/lib/psci/psci_on.c
index d3d0e2ff..53b044ec 100644
--- a/lib/psci/psci_on.c
+++ b/lib/psci/psci_on.c
@@ -11,6 +11,7 @@
#include <context_mgmt.h>
#include <debug.h>
#include <platform.h>
+#include <pubsub_events.h>
#include <stddef.h>
#include "psci_private.h"
@@ -188,6 +189,8 @@ void psci_cpu_on_finish(unsigned int cpu_idx,
if (psci_spd_pm && psci_spd_pm->svc_on_finish)
psci_spd_pm->svc_on_finish(0);
+ PUBLISH_EVENT(psci_cpu_on_finish);
+
/* Populate the mpidr field within the cpu node array */
/* This needs to be done only once */
psci_cpu_pd_nodes[cpu_idx].mpidr = read_mpidr() & MPIDR_AFFINITY_MASK;
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index da6a20fa..504fb9e4 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -89,7 +89,9 @@
define_psci_cap(PSCI_NODE_HW_STATE_AARCH64) | \
define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64) | \
define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64) | \
- define_psci_cap(PSCI_STAT_COUNT_AARCH64))
+ define_psci_cap(PSCI_STAT_COUNT_AARCH64) | \
+ define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64) | \
+ define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64))
/*
* Helper macros to get/set the fields of PSCI per-cpu data.
@@ -258,6 +260,7 @@ void psci_do_pwrup_cache_maintenance(void);
/* Private exported functions from psci_system_off.c */
void __dead2 psci_system_off(void);
void __dead2 psci_system_reset(void);
+int psci_system_reset2(uint32_t reset_type, u_register_t cookie);
/* Private exported functions from psci_stat.c */
void psci_stats_update_pwr_down(unsigned int end_pwrlvl,
@@ -269,4 +272,8 @@ u_register_t psci_stat_residency(u_register_t target_cpu,
u_register_t psci_stat_count(u_register_t target_cpu,
unsigned int power_state);
+/* Private exported functions from psci_mem_protect.c */
+int psci_mem_protect(unsigned int enable);
+int psci_mem_chk_range(uintptr_t base, u_register_t length);
+
#endif /* __PSCI_PRIVATE_H__ */
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index f70e34da..c00bd94a 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -243,6 +243,13 @@ int psci_setup(const psci_lib_args_t *lib_args)
psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET);
if (psci_plat_pm_ops->get_node_hw_state)
psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64);
+ if (psci_plat_pm_ops->read_mem_protect &&
+ psci_plat_pm_ops->write_mem_protect)
+ psci_caps |= define_psci_cap(PSCI_MEM_PROTECT);
+ if (psci_plat_pm_ops->mem_protect_chk)
+ psci_caps |= define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64);
+ if (psci_plat_pm_ops->system_reset2)
+ psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64);
#if ENABLE_PSCI_STAT
psci_caps |= define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);
@@ -259,8 +266,10 @@ int psci_setup(const psci_lib_args_t *lib_args)
******************************************************************************/
void psci_arch_setup(void)
{
+#if ARM_ARCH_MAJOR > 7 || defined(ARMV7_SUPPORTS_GENERIC_TIMER)
/* Program the counter frequency */
write_cntfrq_el0(plat_get_syscnt_freq2());
+#endif
/* Initialize the cpu_ops pointer. */
init_cpu_ops();
diff --git a/lib/psci/psci_suspend.c b/lib/psci/psci_suspend.c
index 40ecdeea..d9490672 100644
--- a/lib/psci/psci_suspend.c
+++ b/lib/psci/psci_suspend.c
@@ -37,6 +37,11 @@ static void psci_suspend_to_standby_finisher(unsigned int cpu_idx,
*/
psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
+#if ENABLE_PSCI_STAT
+ plat_psci_stat_accounting_stop(&state_info);
+ psci_stats_update_pwr_up(end_pwrlvl, &state_info);
+#endif
+
/*
* Plat. management: Allow the platform to do operations
* on waking up from retention.
@@ -236,10 +241,6 @@ exit:
PMF_NO_CACHE_MAINT);
#endif
-#if ENABLE_PSCI_STAT
- plat_psci_stat_accounting_start(state_info);
-#endif
-
/*
* We will reach here if only retention/standby states have been
* requested at multiple power levels. This means that the cpu
@@ -247,11 +248,6 @@ exit:
*/
wfi();
-#if ENABLE_PSCI_STAT
- plat_psci_stat_accounting_stop(state_info);
- psci_stats_update_pwr_up(end_pwrlvl, state_info);
-#endif
-
#if ENABLE_RUNTIME_INSTRUMENTATION
PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
RT_INSTR_EXIT_HW_LOW_PWR,
diff --git a/lib/psci/psci_system_off.c b/lib/psci/psci_system_off.c
index ef5d3d1d..13e9f4aa 100644
--- a/lib/psci/psci_system_off.c
+++ b/lib/psci/psci_system_off.c
@@ -49,3 +49,33 @@ void __dead2 psci_system_reset(void)
/* This function does not return. We should never get here */
}
+
+int psci_system_reset2(uint32_t reset_type, u_register_t cookie)
+{
+ int is_vendor;
+
+ psci_print_power_domain_map();
+
+ assert(psci_plat_pm_ops->system_reset2);
+
+ is_vendor = (reset_type >> PSCI_RESET2_TYPE_VENDOR_SHIFT) & 1;
+ if (!is_vendor) {
+ /*
+ * Only WARM_RESET is allowed for architectural type resets.
+ */
+ if (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET)
+ return PSCI_E_INVALID_PARAMS;
+ if (psci_plat_pm_ops->write_mem_protect &&
+ psci_plat_pm_ops->write_mem_protect(0) < 0) {
+ return PSCI_E_NOT_SUPPORTED;
+ }
+ }
+
+ /* Notify the Secure Payload Dispatcher */
+ if (psci_spd_pm && psci_spd_pm->svc_system_reset) {
+ psci_spd_pm->svc_system_reset();
+ }
+ console_flush();
+
+ return psci_plat_pm_ops->system_reset2(is_vendor, reset_type, cookie);
+}
diff --git a/lib/utils/mem_region.c b/lib/utils/mem_region.c
new file mode 100644
index 00000000..31c6231f
--- /dev/null
+++ b/lib/utils/mem_region.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <utils.h>
+
+/*
+ * All the regions defined in mem_region_t must have the following properties
+ *
+ * - Any contiguous regions must be merged into a single entry.
+ * - The number of bytes of each region must be greater than zero.
+ * - The calculation of the highest address within the region (base + nbytes-1)
+ * doesn't produce an overflow.
+ *
+ * These conditions must be fulfilled by the caller and they aren't checked
+ * at runtime.
+ */
+
+/*
+ * zero_normalmem all the regions defined in tbl.
+ * It assumes that MMU is enabled and the memory is Normal memory.
+ * tbl must be a valid pointer to a memory mem_region_t array,
+ * nregions is the size of the array.
+ */
+void clear_mem_regions(mem_region_t *tbl, size_t nregions)
+{
+ size_t i;
+
+ assert(tbl);
+ assert(nregions > 0);
+
+ for (i = 0; i < nregions; i++) {
+ assert(tbl->nbytes > 0);
+ assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
+ zero_normalmem((void *) (tbl->base), tbl->nbytes);
+ tbl++;
+ }
+}
+
+/*
+ * This function checks that a region (addr + nbytes-1) of memory is totally
+ * covered by one of the regions defined in tbl.
+ * tbl must be a valid pointer to a memory mem_region_t array, nregions
+ * is the size of the array and the region described by addr and nbytes must
+ * not generate an overflow.
+ * Returns:
+ * -1 means that the region is not covered by any of the regions
+ * described in tbl.
+ * 0 the region (addr + nbytes-1) is covered by one of the regions described
+ * in tbl
+ */
+int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
+ uintptr_t addr, size_t nbytes)
+{
+ uintptr_t region_start, region_end, start, end;
+ size_t i;
+
+ assert(tbl);
+ assert(nbytes > 0);
+ assert(!check_uptr_overflow(addr, nbytes-1));
+
+ region_start = addr;
+ region_end = addr + (nbytes - 1);
+ for (i = 0; i < nregions; i++) {
+ assert(tbl->nbytes > 0);
+ assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
+ start = tbl->base;
+ end = start + (tbl->nbytes - 1);
+ if (region_start >= start && region_end <= end)
+ return 0;
+ tbl++;
+ }
+
+ return -1;
+}
diff --git a/lib/xlat_tables/aarch32/xlat_tables.c b/lib/xlat_tables/aarch32/xlat_tables.c
index c7e34f20..720d4461 100644
--- a/lib/xlat_tables/aarch32/xlat_tables.c
+++ b/lib/xlat_tables/aarch32/xlat_tables.c
@@ -13,6 +13,10 @@
#include <xlat_tables.h>
#include "../xlat_tables_private.h"
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING)
+#error ARMv7 target does not support LPAE MMU descriptors
+#endif
+
#define XLAT_TABLE_LEVEL_BASE \
GET_XLAT_TABLE_LEVEL_BASE(PLAT_VIRT_ADDR_SPACE_SIZE)
diff --git a/lib/xlat_tables/aarch64/xlat_tables.c b/lib/xlat_tables/aarch64/xlat_tables.c
index 2ddf8cba..eabc3df9 100644
--- a/lib/xlat_tables/aarch64/xlat_tables.c
+++ b/lib/xlat_tables/aarch64/xlat_tables.c
@@ -60,7 +60,10 @@ static unsigned long long calc_physical_addr_size_bits(
/* Physical Address ranges supported in the AArch64 Memory Model */
static const unsigned int pa_range_bits_arr[] = {
PARANGE_0000, PARANGE_0001, PARANGE_0010, PARANGE_0011, PARANGE_0100,
- PARANGE_0101
+ PARANGE_0101,
+#if ARM_ARCH_AT_LEAST(8, 2)
+ PARANGE_0110,
+#endif
};
static unsigned long long get_max_supported_pa(void)
@@ -182,7 +185,11 @@ void init_xlat_tables(void)
/* Define EL1 and EL3 variants of the function enabling the MMU */
DEFINE_ENABLE_MMU_EL(1,
- (tcr_ps_bits << TCR_EL1_IPS_SHIFT),
+ /*
+ * TCR_EL1.EPD1: Disable translation table walk for addresses
+ * that are translated using TTBR1_EL1.
+ */
+ TCR_EPD1_BIT | (tcr_ps_bits << TCR_EL1_IPS_SHIFT),
tlbivmalle1)
DEFINE_ENABLE_MMU_EL(3,
TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT),
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
index e66b9275..fc7ca46a 100644
--- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
@@ -14,6 +14,10 @@
#include <xlat_tables_v2.h>
#include "../xlat_tables_private.h"
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING)
+#error ARMv7 target does not support LPAE MMU descriptors
+#endif
+
#if ENABLE_ASSERTIONS
unsigned long long xlat_arch_get_max_supported_pa(void)
{
@@ -22,13 +26,11 @@ unsigned long long xlat_arch_get_max_supported_pa(void)
}
#endif /* ENABLE_ASSERTIONS*/
-int is_mmu_enabled(void)
+int is_mmu_enabled_ctx(const xlat_ctx_t *ctx __unused)
{
return (read_sctlr() & SCTLR_M_BIT) != 0;
}
-#if PLAT_XLAT_TABLES_DYNAMIC
-
void xlat_arch_tlbi_va(uintptr_t va)
{
/*
@@ -40,6 +42,17 @@ void xlat_arch_tlbi_va(uintptr_t va)
tlbimvaais(TLBI_ADDR(va));
}
+void xlat_arch_tlbi_va_regime(uintptr_t va, xlat_regime_t xlat_regime __unused)
+{
+ /*
+ * Ensure the translation table write has drained into memory before
+ * invalidating the TLB entry.
+ */
+ dsbishst();
+
+ tlbimvaais(TLBI_ADDR(va));
+}
+
void xlat_arch_tlbi_va_sync(void)
{
/* Invalidate all entries from branch predictors. */
@@ -66,8 +79,6 @@ void xlat_arch_tlbi_va_sync(void)
isb();
}
-#endif /* PLAT_XLAT_TABLES_DYNAMIC */
-
int xlat_arch_current_el(void)
{
/*
@@ -77,11 +88,6 @@ int xlat_arch_current_el(void)
return 3;
}
-uint64_t xlat_arch_get_xn_desc(int el __unused)
-{
- return UPPER_ATTRS(XN);
-}
-
/*******************************************************************************
* Function for enabling the MMU in Secure PL1, assuming that the page tables
* have already been created.
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch_private.h b/lib/xlat_tables_v2/aarch32/xlat_tables_arch_private.h
new file mode 100644
index 00000000..509395d8
--- /dev/null
+++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch_private.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __XLAT_TABLES_ARCH_PRIVATE_H__
+#define __XLAT_TABLES_ARCH_PRIVATE_H__
+
+#include <xlat_tables_defs.h>
+#include <xlat_tables_v2.h>
+
+/*
+ * Return the execute-never mask that will prevent instruction fetch at the
+ * given translation regime.
+ */
+static inline uint64_t xlat_arch_regime_get_xn_desc(xlat_regime_t regime __unused)
+{
+ return UPPER_ATTRS(XN);
+}
+
+#endif /* __XLAT_TABLES_ARCH_PRIVATE_H__ */
diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
index 097e815c..aa5b9e54 100644
--- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
@@ -10,21 +10,13 @@
#include <bl_common.h>
#include <cassert.h>
#include <common_def.h>
-#include <platform_def.h>
#include <sys/types.h>
#include <utils.h>
#include <utils_def.h>
#include <xlat_tables_v2.h>
#include "../xlat_tables_private.h"
-#if defined(IMAGE_BL1) || defined(IMAGE_BL31)
-# define IMAGE_EL 3
-#else
-# define IMAGE_EL 1
-#endif
-
-static unsigned long long calc_physical_addr_size_bits(
- unsigned long long max_addr)
+unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr)
{
/* Physical address can't exceed 48 bits */
assert((max_addr & ADDR_MASK_48_TO_63) == 0);
@@ -56,7 +48,10 @@ static unsigned long long calc_physical_addr_size_bits(
/* Physical Address ranges supported in the AArch64 Memory Model */
static const unsigned int pa_range_bits_arr[] = {
PARANGE_0000, PARANGE_0001, PARANGE_0010, PARANGE_0011, PARANGE_0100,
- PARANGE_0101
+ PARANGE_0101,
+#if ARM_ARCH_AT_LEAST(8, 2)
+ PARANGE_0110,
+#endif
};
unsigned long long xlat_arch_get_max_supported_pa(void)
@@ -71,20 +66,31 @@ unsigned long long xlat_arch_get_max_supported_pa(void)
}
#endif /* ENABLE_ASSERTIONS*/
-int is_mmu_enabled(void)
+int is_mmu_enabled_ctx(const xlat_ctx_t *ctx)
+{
+ if (ctx->xlat_regime == EL1_EL0_REGIME) {
+ assert(xlat_arch_current_el() >= 1);
+ return (read_sctlr_el1() & SCTLR_M_BIT) != 0;
+ } else {
+ assert(ctx->xlat_regime == EL3_REGIME);
+ assert(xlat_arch_current_el() >= 3);
+ return (read_sctlr_el3() & SCTLR_M_BIT) != 0;
+ }
+}
+
+
+void xlat_arch_tlbi_va(uintptr_t va)
{
#if IMAGE_EL == 1
assert(IS_IN_EL(1));
- return (read_sctlr_el1() & SCTLR_M_BIT) != 0;
+ xlat_arch_tlbi_va_regime(va, EL1_EL0_REGIME);
#elif IMAGE_EL == 3
assert(IS_IN_EL(3));
- return (read_sctlr_el3() & SCTLR_M_BIT) != 0;
+ xlat_arch_tlbi_va_regime(va, EL3_REGIME);
#endif
}
-#if PLAT_XLAT_TABLES_DYNAMIC
-
-void xlat_arch_tlbi_va(uintptr_t va)
+void xlat_arch_tlbi_va_regime(uintptr_t va, xlat_regime_t xlat_regime)
{
/*
* Ensure the translation table write has drained into memory before
@@ -92,13 +98,21 @@ void xlat_arch_tlbi_va(uintptr_t va)
*/
dsbishst();
-#if IMAGE_EL == 1
- assert(IS_IN_EL(1));
- tlbivaae1is(TLBI_ADDR(va));
-#elif IMAGE_EL == 3
- assert(IS_IN_EL(3));
- tlbivae3is(TLBI_ADDR(va));
-#endif
+ /*
+ * This function only supports invalidation of TLB entries for the EL3
+ * and EL1&0 translation regimes.
+ *
+ * Also, it is architecturally UNDEFINED to invalidate TLBs of a higher
+ * exception level (see section D4.9.2 of the ARM ARM rev B.a).
+ */
+ if (xlat_regime == EL1_EL0_REGIME) {
+ assert(xlat_arch_current_el() >= 1);
+ tlbivaae1is(TLBI_ADDR(va));
+ } else {
+ assert(xlat_regime == EL3_REGIME);
+ assert(xlat_arch_current_el() >= 3);
+ tlbivae3is(TLBI_ADDR(va));
+ }
}
void xlat_arch_tlbi_va_sync(void)
@@ -124,8 +138,6 @@ void xlat_arch_tlbi_va_sync(void)
isb();
}
-#endif /* PLAT_XLAT_TABLES_DYNAMIC */
-
int xlat_arch_current_el(void)
{
int el = GET_EL(read_CurrentEl());
@@ -135,16 +147,6 @@ int xlat_arch_current_el(void)
return el;
}
-uint64_t xlat_arch_get_xn_desc(int el)
-{
- if (el == 3) {
- return UPPER_ATTRS(XN);
- } else {
- assert(el == 1);
- return UPPER_ATTRS(PXN);
- }
-}
-
/*******************************************************************************
* Macro generating the code for the function enabling the MMU in the given
* exception level, assuming that the pagetables have already been created.
@@ -252,11 +254,15 @@ void enable_mmu_arch(unsigned int flags,
* It is safer to restrict the max physical address accessible by the
* hardware as much as possible.
*/
- unsigned long long tcr_ps_bits = calc_physical_addr_size_bits(max_pa);
+ unsigned long long tcr_ps_bits = tcr_physical_addr_size_bits(max_pa);
#if IMAGE_EL == 1
assert(IS_IN_EL(1));
- tcr |= tcr_ps_bits << TCR_EL1_IPS_SHIFT;
+ /*
+ * TCR_EL1.EPD1: Disable translation table walk for addresses that are
+ * translated using TTBR1_EL1.
+ */
+ tcr |= TCR_EPD1_BIT | (tcr_ps_bits << TCR_EL1_IPS_SHIFT);
enable_mmu_internal_el1(flags, mair, tcr, ttbr);
#elif IMAGE_EL == 3
assert(IS_IN_EL(3));
diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch_private.h b/lib/xlat_tables_v2/aarch64/xlat_tables_arch_private.h
new file mode 100644
index 00000000..d201590a
--- /dev/null
+++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch_private.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __XLAT_TABLES_ARCH_PRIVATE_H__
+#define __XLAT_TABLES_ARCH_PRIVATE_H__
+
+#include <assert.h>
+#include <xlat_tables_defs.h>
+#include <xlat_tables_v2.h>
+
+/*
+ * Return the execute-never mask that will prevent instruction fetch at all ELs
+ * that are part of the given translation regime.
+ */
+static inline uint64_t xlat_arch_regime_get_xn_desc(xlat_regime_t regime)
+{
+ if (regime == EL1_EL0_REGIME) {
+ return UPPER_ATTRS(UXN) | UPPER_ATTRS(PXN);
+ } else {
+ assert(regime == EL3_REGIME);
+ return UPPER_ATTRS(XN);
+ }
+}
+
+#endif /* __XLAT_TABLES_ARCH_PRIVATE_H__ */
diff --git a/lib/xlat_tables_v2/xlat_tables.mk b/lib/xlat_tables_v2/xlat_tables.mk
index b94ce5d0..06dd844a 100644
--- a/lib/xlat_tables_v2/xlat_tables.mk
+++ b/lib/xlat_tables_v2/xlat_tables.mk
@@ -7,3 +7,5 @@
XLAT_TABLES_LIB_SRCS := $(addprefix lib/xlat_tables_v2/, \
${ARCH}/xlat_tables_arch.c \
xlat_tables_internal.c)
+
+INCLUDES += -Ilib/xlat_tables_v2/${ARCH}
diff --git a/lib/xlat_tables_v2/xlat_tables_internal.c b/lib/xlat_tables_v2/xlat_tables_internal.c
index 47929906..0acfacbf 100644
--- a/lib/xlat_tables_v2/xlat_tables_internal.c
+++ b/lib/xlat_tables_v2/xlat_tables_internal.c
@@ -14,7 +14,7 @@
#include <string.h>
#include <types.h>
#include <utils.h>
-#include <xlat_tables_arch.h>
+#include <xlat_tables_arch_private.h>
#include <xlat_tables_defs.h>
#include <xlat_tables_v2.h>
@@ -112,9 +112,11 @@ static uint64_t *xlat_table_get_empty(xlat_ctx_t *ctx)
#endif /* PLAT_XLAT_TABLES_DYNAMIC */
-/* Returns a block/page table descriptor for the given level and attributes. */
-static uint64_t xlat_desc(mmap_attr_t attr, unsigned long long addr_pa,
- int level, uint64_t execute_never_mask)
+/*
+ * Returns a block/page table descriptor for the given level and attributes.
+ */
+uint64_t xlat_desc(const xlat_ctx_t *ctx, mmap_attr_t attr,
+ unsigned long long addr_pa, int level)
{
uint64_t desc;
int mem_type;
@@ -133,9 +135,28 @@ static uint64_t xlat_desc(mmap_attr_t attr, unsigned long long addr_pa,
* Deduce other fields of the descriptor based on the MT_NS and MT_RW
* memory region attributes.
*/
+ desc |= LOWER_ATTRS(ACCESS_FLAG);
+
desc |= (attr & MT_NS) ? LOWER_ATTRS(NS) : 0;
desc |= (attr & MT_RW) ? LOWER_ATTRS(AP_RW) : LOWER_ATTRS(AP_RO);
- desc |= LOWER_ATTRS(ACCESS_FLAG);
+
+ /*
+ * Do not allow unprivileged access when the mapping is for a privileged
+ * EL. For translation regimes that do not have mappings for access for
+ * lower exception levels, set AP[2] to AP_NO_ACCESS_UNPRIVILEGED.
+ */
+ if (ctx->xlat_regime == EL1_EL0_REGIME) {
+ if (attr & MT_USER) {
+ /* EL0 mapping requested, so we give User access */
+ desc |= LOWER_ATTRS(AP_ACCESS_UNPRIVILEGED);
+ } else {
+ /* EL1 mapping requested, no User access granted */
+ desc |= LOWER_ATTRS(AP_NO_ACCESS_UNPRIVILEGED);
+ }
+ } else {
+ assert(ctx->xlat_regime == EL3_REGIME);
+ desc |= LOWER_ATTRS(AP_NO_ACCESS_UNPRIVILEGED);
+ }
/*
* Deduce shareability domain and executability of the memory region
@@ -156,7 +177,7 @@ static uint64_t xlat_desc(mmap_attr_t attr, unsigned long long addr_pa,
* fetch, which could be an issue if this memory region
* corresponds to a read-sensitive peripheral.
*/
- desc |= execute_never_mask;
+ desc |= xlat_arch_regime_get_xn_desc(ctx->xlat_regime);
} else { /* Normal memory */
/*
@@ -171,10 +192,13 @@ static uint64_t xlat_desc(mmap_attr_t attr, unsigned long long addr_pa,
* translation table.
*
* For read-only memory, rely on the MT_EXECUTE/MT_EXECUTE_NEVER
- * attribute to figure out the value of the XN bit.
+ * attribute to figure out the value of the XN bit. The actual
+ * XN bit(s) to set in the descriptor depends on the context's
+ * translation regime and the policy applied in
+ * xlat_arch_regime_get_xn_desc().
*/
if ((attr & MT_RW) || (attr & MT_EXECUTE_NEVER)) {
- desc |= execute_never_mask;
+ desc |= xlat_arch_regime_get_xn_desc(ctx->xlat_regime);
}
if (mem_type == MT_MEMORY) {
@@ -314,7 +338,7 @@ static void xlat_tables_unmap_region(xlat_ctx_t *ctx, mmap_region_t *mm,
if (action == ACTION_WRITE_BLOCK_ENTRY) {
table_base[table_idx] = INVALID_DESC;
- xlat_arch_tlbi_va(table_idx_va);
+ xlat_arch_tlbi_va_regime(table_idx_va, ctx->xlat_regime);
} else if (action == ACTION_RECURSE_INTO_TABLE) {
@@ -330,7 +354,8 @@ static void xlat_tables_unmap_region(xlat_ctx_t *ctx, mmap_region_t *mm,
*/
if (xlat_table_is_empty(ctx, subtable)) {
table_base[table_idx] = INVALID_DESC;
- xlat_arch_tlbi_va(table_idx_va);
+ xlat_arch_tlbi_va_regime(table_idx_va,
+ ctx->xlat_regime);
}
} else {
@@ -417,7 +442,8 @@ static action_t xlat_tables_map_region_action(const mmap_region_t *mm,
* descriptors. If not, create a table instead.
*/
if ((dest_pa & XLAT_BLOCK_MASK(level)) ||
- (level < MIN_LVL_BLOCK_DESC))
+ (level < MIN_LVL_BLOCK_DESC) ||
+ (mm->granularity < XLAT_BLOCK_SIZE(level)))
return ACTION_CREATE_NEW_TABLE;
else
return ACTION_WRITE_BLOCK_ENTRY;
@@ -535,8 +561,7 @@ static uintptr_t xlat_tables_map_region(xlat_ctx_t *ctx, mmap_region_t *mm,
if (action == ACTION_WRITE_BLOCK_ENTRY) {
table_base[table_idx] =
- xlat_desc(mm->attr, table_idx_pa, level,
- ctx->execute_never_mask);
+ xlat_desc(ctx, mm->attr, table_idx_pa, level);
} else if (action == ACTION_CREATE_NEW_TABLE) {
@@ -590,9 +615,10 @@ void print_mmap(mmap_region_t *const mmap)
mmap_region_t *mm = mmap;
while (mm->size) {
- tf_printf(" VA:%p PA:0x%llx size:0x%zx attr:0x%x\n",
+ tf_printf(" VA:%p PA:0x%llx size:0x%zx attr:0x%x",
(void *)mm->base_va, mm->base_pa,
mm->size, mm->attr);
+ tf_printf(" granularity:0x%zx\n", mm->granularity);
++mm;
};
tf_printf("\n");
@@ -608,11 +634,13 @@ void print_mmap(mmap_region_t *const mmap)
* ENOMEM: There is not enough memory in the mmap array.
* EPERM: Region overlaps another one in an invalid way.
*/
-static int mmap_add_region_check(xlat_ctx_t *ctx, unsigned long long base_pa,
- uintptr_t base_va, size_t size,
- mmap_attr_t attr)
+static int mmap_add_region_check(xlat_ctx_t *ctx, const mmap_region_t *mm)
{
- mmap_region_t *mm = ctx->mmap;
+ unsigned long long base_pa = mm->base_pa;
+ uintptr_t base_va = mm->base_va;
+ size_t size = mm->size;
+ size_t granularity = mm->granularity;
+
unsigned long long end_pa = base_pa + size - 1;
uintptr_t end_va = base_va + size - 1;
@@ -620,6 +648,12 @@ static int mmap_add_region_check(xlat_ctx_t *ctx, unsigned long long base_pa,
!IS_PAGE_ALIGNED(size))
return -EINVAL;
+ if ((granularity != XLAT_BLOCK_SIZE(1)) &&
+ (granularity != XLAT_BLOCK_SIZE(2)) &&
+ (granularity != XLAT_BLOCK_SIZE(3))) {
+ return -EINVAL;
+ }
+
/* Check for overflows */
if ((base_pa > end_pa) || (base_va > end_va))
return -ERANGE;
@@ -630,22 +664,27 @@ static int mmap_add_region_check(xlat_ctx_t *ctx, unsigned long long base_pa,
if ((base_pa + (unsigned long long)size - 1ULL) > ctx->pa_max_address)
return -ERANGE;
- /* Check that there is space in the mmap array */
+ /* Check that there is space in the ctx->mmap array */
if (ctx->mmap[ctx->mmap_num - 1].size != 0)
return -ENOMEM;
/* Check for PAs and VAs overlaps with all other regions */
- for (mm = ctx->mmap; mm->size; ++mm) {
+ for (mmap_region_t *mm_cursor = ctx->mmap;
+ mm_cursor->size; ++mm_cursor) {
- uintptr_t mm_end_va = mm->base_va + mm->size - 1;
+ uintptr_t mm_cursor_end_va = mm_cursor->base_va
+ + mm_cursor->size - 1;
/*
* Check if one of the regions is completely inside the other
* one.
*/
int fully_overlapped_va =
- ((base_va >= mm->base_va) && (end_va <= mm_end_va)) ||
- ((mm->base_va >= base_va) && (mm_end_va <= end_va));
+ ((base_va >= mm_cursor->base_va) &&
+ (end_va <= mm_cursor_end_va)) ||
+
+ ((mm_cursor->base_va >= base_va) &&
+ (mm_cursor_end_va <= end_va));
/*
* Full VA overlaps are only allowed if both regions are
@@ -656,13 +695,16 @@ static int mmap_add_region_check(xlat_ctx_t *ctx, unsigned long long base_pa,
if (fully_overlapped_va) {
#if PLAT_XLAT_TABLES_DYNAMIC
- if ((attr & MT_DYNAMIC) || (mm->attr & MT_DYNAMIC))
+ if ((mm->attr & MT_DYNAMIC) ||
+ (mm_cursor->attr & MT_DYNAMIC))
return -EPERM;
#endif /* PLAT_XLAT_TABLES_DYNAMIC */
- if ((mm->base_va - mm->base_pa) != (base_va - base_pa))
+ if ((mm_cursor->base_va - mm_cursor->base_pa) !=
+ (base_va - base_pa))
return -EPERM;
- if ((base_va == mm->base_va) && (size == mm->size))
+ if ((base_va == mm_cursor->base_va) &&
+ (size == mm_cursor->size))
return -EPERM;
} else {
@@ -672,13 +714,15 @@ static int mmap_add_region_check(xlat_ctx_t *ctx, unsigned long long base_pa,
* Partial overlaps are not allowed
*/
- unsigned long long mm_end_pa =
- mm->base_pa + mm->size - 1;
+ unsigned long long mm_cursor_end_pa =
+ mm_cursor->base_pa + mm_cursor->size - 1;
int separated_pa =
- (end_pa < mm->base_pa) || (base_pa > mm_end_pa);
+ (end_pa < mm_cursor->base_pa) ||
+ (base_pa > mm_cursor_end_pa);
int separated_va =
- (end_va < mm->base_va) || (base_va > mm_end_va);
+ (end_va < mm_cursor->base_va) ||
+ (base_va > mm_cursor_end_va);
if (!(separated_va && separated_pa))
return -EPERM;
@@ -703,8 +747,7 @@ void mmap_add_region_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm)
/* Static regions must be added before initializing the xlat tables. */
assert(!ctx->initialized);
- ret = mmap_add_region_check(ctx, mm->base_pa, mm->base_va, mm->size,
- mm->attr);
+ ret = mmap_add_region_check(ctx, mm);
if (ret != 0) {
ERROR("mmap_add_region_check() failed. error %d\n", ret);
assert(0);
@@ -799,7 +842,10 @@ int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm)
if (!mm->size)
return 0;
- ret = mmap_add_region_check(ctx, mm->base_pa, mm->base_va, mm->size, mm->attr | MT_DYNAMIC);
+ /* Now this region is a dynamic one */
+ mm->attr |= MT_DYNAMIC;
+
+ ret = mmap_add_region_check(ctx, mm);
if (ret != 0)
return ret;
@@ -808,14 +854,17 @@ int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm)
* static regions in mmap_add_region_ctx().
*/
- while ((mm_cursor->base_va + mm_cursor->size - 1) < end_va && mm_cursor->size)
+ while ((mm_cursor->base_va + mm_cursor->size - 1)
+ < end_va && mm_cursor->size)
++mm_cursor;
- while ((mm_cursor->base_va + mm_cursor->size - 1 == end_va) && (mm_cursor->size < mm->size))
+ while ((mm_cursor->base_va + mm_cursor->size - 1 == end_va)
+ && (mm_cursor->size < mm->size))
++mm_cursor;
/* Make room for new region by moving other regions up by one place */
- memmove(mm_cursor + 1, mm_cursor, (uintptr_t)mm_last - (uintptr_t)mm_cursor);
+ memmove(mm_cursor + 1, mm_cursor,
+ (uintptr_t)mm_last - (uintptr_t)mm_cursor);
/*
* Check we haven't lost the empty sentinal from the end of the array.
@@ -825,19 +874,20 @@ int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm)
assert(mm_last->size == 0);
*mm_cursor = *mm;
- mm_cursor->attr |= MT_DYNAMIC;
/*
* Update the translation tables if the xlat tables are initialized. If
* not, this region will be mapped when they are initialized.
*/
if (ctx->initialized) {
- uintptr_t end_va = xlat_tables_map_region(ctx, mm_cursor, 0, ctx->base_table,
- ctx->base_table_entries, ctx->base_level);
+ uintptr_t end_va = xlat_tables_map_region(ctx, mm_cursor,
+ 0, ctx->base_table, ctx->base_table_entries,
+ ctx->base_level);
/* Failed to map, remove mmap entry, unmap and return error. */
if (end_va != mm_cursor->base_va + mm_cursor->size - 1) {
- memmove(mm_cursor, mm_cursor + 1, (uintptr_t)mm_last - (uintptr_t)mm_cursor);
+ memmove(mm_cursor, mm_cursor + 1,
+ (uintptr_t)mm_last - (uintptr_t)mm_cursor);
/*
* Check if the mapping function actually managed to map
@@ -847,8 +897,8 @@ int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm)
return -ENOMEM;
/*
- * Something went wrong after mapping some table entries,
- * undo every change done up to this point.
+ * Something went wrong after mapping some table
+ * entries, undo every change done up to this point.
*/
mmap_region_t unmap_mm = {
.base_pa = 0,
@@ -972,9 +1022,10 @@ int mmap_remove_dynamic_region(uintptr_t base_va, size_t size)
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
/* Print the attributes of the specified block descriptor. */
-static void xlat_desc_print(uint64_t desc, uint64_t execute_never_mask)
+static void xlat_desc_print(const xlat_ctx_t *ctx, uint64_t desc)
{
int mem_type_index = ATTR_INDEX_GET(desc);
+ xlat_regime_t xlat_regime = ctx->xlat_regime;
if (mem_type_index == ATTR_IWBWA_OWBWA_NTR_INDEX) {
tf_printf("MEM");
@@ -985,9 +1036,49 @@ static void xlat_desc_print(uint64_t desc, uint64_t execute_never_mask)
tf_printf("DEV");
}
- tf_printf(LOWER_ATTRS(AP_RO) & desc ? "-RO" : "-RW");
+ const char *priv_str = "(PRIV)";
+ const char *user_str = "(USER)";
+
+ /*
+ * Showing Privileged vs Unprivileged only makes sense for EL1&0
+ * mappings
+ */
+ const char *ro_str = "-RO";
+ const char *rw_str = "-RW";
+ const char *no_access_str = "-NOACCESS";
+
+ if (xlat_regime == EL3_REGIME) {
+ /* For EL3, the AP[2] bit is all what matters */
+ tf_printf((desc & LOWER_ATTRS(AP_RO)) ? ro_str : rw_str);
+ } else {
+ const char *ap_str = (desc & LOWER_ATTRS(AP_RO)) ? ro_str : rw_str;
+ tf_printf(ap_str);
+ tf_printf(priv_str);
+ /*
+ * EL0 can only have the same permissions as EL1 or no
+ * permissions at all.
+ */
+ tf_printf((desc & LOWER_ATTRS(AP_ACCESS_UNPRIVILEGED))
+ ? ap_str : no_access_str);
+ tf_printf(user_str);
+ }
+
+ const char *xn_str = "-XN";
+ const char *exec_str = "-EXEC";
+
+ if (xlat_regime == EL3_REGIME) {
+ /* For EL3, the XN bit is all what matters */
+ tf_printf(LOWER_ATTRS(XN) & desc ? xn_str : exec_str);
+ } else {
+ /* For EL0 and EL1, we need to know who has which rights */
+ tf_printf(LOWER_ATTRS(PXN) & desc ? xn_str : exec_str);
+ tf_printf(priv_str);
+
+ tf_printf(LOWER_ATTRS(UXN) & desc ? xn_str : exec_str);
+ tf_printf(user_str);
+ }
+
tf_printf(LOWER_ATTRS(NS) & desc ? "-NS" : "-S");
- tf_printf(execute_never_mask & desc ? "-XN" : "-EXEC");
}
static const char * const level_spacers[] = {
@@ -1004,9 +1095,10 @@ static const char *invalid_descriptors_ommited =
* Recursive function that reads the translation tables passed as an argument
* and prints their status.
*/
-static void xlat_tables_print_internal(const uintptr_t table_base_va,
+static void xlat_tables_print_internal(xlat_ctx_t *ctx,
+ const uintptr_t table_base_va,
uint64_t *const table_base, const int table_entries,
- const unsigned int level, const uint64_t execute_never_mask)
+ const unsigned int level)
{
assert(level <= XLAT_TABLE_LEVEL_MAX);
@@ -1065,17 +1157,16 @@ static void xlat_tables_print_internal(const uintptr_t table_base_va,
uintptr_t addr_inner = desc & TABLE_ADDR_MASK;
- xlat_tables_print_internal(table_idx_va,
+ xlat_tables_print_internal(ctx, table_idx_va,
(uint64_t *)addr_inner,
- XLAT_TABLE_ENTRIES, level+1,
- execute_never_mask);
+ XLAT_TABLE_ENTRIES, level + 1);
} else {
tf_printf("%sVA:%p PA:0x%llx size:0x%zx ",
level_spacers[level],
(void *)table_idx_va,
(unsigned long long)(desc & TABLE_ADDR_MASK),
level_size);
- xlat_desc_print(desc, execute_never_mask);
+ xlat_desc_print(ctx, desc);
tf_printf("\n");
}
}
@@ -1095,7 +1186,15 @@ static void xlat_tables_print_internal(const uintptr_t table_base_va,
void xlat_tables_print(xlat_ctx_t *ctx)
{
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ const char *xlat_regime_str;
+ if (ctx->xlat_regime == EL1_EL0_REGIME) {
+ xlat_regime_str = "1&0";
+ } else {
+ assert(ctx->xlat_regime == EL3_REGIME);
+ xlat_regime_str = "3";
+ }
VERBOSE("Translation tables state:\n");
+ VERBOSE(" Xlat regime: EL%s\n", xlat_regime_str);
VERBOSE(" Max allowed PA: 0x%llx\n", ctx->pa_max_address);
VERBOSE(" Max allowed VA: %p\n", (void *) ctx->va_max_address);
VERBOSE(" Max mapped PA: 0x%llx\n", ctx->max_pa);
@@ -1119,22 +1218,21 @@ void xlat_tables_print(xlat_ctx_t *ctx)
used_page_tables, ctx->tables_num,
ctx->tables_num - used_page_tables);
- xlat_tables_print_internal(0, ctx->base_table, ctx->base_table_entries,
- ctx->base_level, ctx->execute_never_mask);
+ xlat_tables_print_internal(ctx, 0, ctx->base_table,
+ ctx->base_table_entries, ctx->base_level);
#endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */
}
void init_xlat_tables_ctx(xlat_ctx_t *ctx)
{
- mmap_region_t *mm = ctx->mmap;
-
- assert(!is_mmu_enabled());
+ assert(ctx != NULL);
assert(!ctx->initialized);
+ assert(ctx->xlat_regime == EL3_REGIME || ctx->xlat_regime == EL1_EL0_REGIME);
+ assert(!is_mmu_enabled_ctx(ctx));
- print_mmap(mm);
+ mmap_region_t *mm = ctx->mmap;
- ctx->execute_never_mask =
- xlat_arch_get_xn_desc(xlat_arch_current_el());
+ print_mmap(mm);
/* All tables must be zeroed before mapping any region. */
@@ -1217,3 +1315,348 @@ void enable_mmu_el3(unsigned int flags)
}
#endif /* AARCH32 */
+
+/*
+ * Do a translation table walk to find the block or page descriptor that maps
+ * virtual_addr.
+ *
+ * On success, return the address of the descriptor within the translation
+ * table. Its lookup level is stored in '*out_level'.
+ * On error, return NULL.
+ *
+ * xlat_table_base
+ * Base address for the initial lookup level.
+ * xlat_table_base_entries
+ * Number of entries in the translation table for the initial lookup level.
+ * virt_addr_space_size
+ * Size in bytes of the virtual address space.
+ */
+static uint64_t *find_xlat_table_entry(uintptr_t virtual_addr,
+ void *xlat_table_base,
+ int xlat_table_base_entries,
+ unsigned long long virt_addr_space_size,
+ int *out_level)
+{
+ unsigned int start_level;
+ uint64_t *table;
+ int entries;
+
+ VERBOSE("%s(%p)\n", __func__, (void *)virtual_addr);
+
+ start_level = GET_XLAT_TABLE_LEVEL_BASE(virt_addr_space_size);
+ VERBOSE("Starting translation table walk from level %i\n", start_level);
+
+ table = xlat_table_base;
+ entries = xlat_table_base_entries;
+
+ for (unsigned int level = start_level;
+ level <= XLAT_TABLE_LEVEL_MAX;
+ ++level) {
+ int idx;
+ uint64_t desc;
+ uint64_t desc_type;
+
+ VERBOSE("Table address: %p\n", (void *)table);
+
+ idx = XLAT_TABLE_IDX(virtual_addr, level);
+ VERBOSE("Index into level %i table: %i\n", level, idx);
+ if (idx >= entries) {
+ VERBOSE("Invalid address\n");
+ return NULL;
+ }
+
+ desc = table[idx];
+ desc_type = desc & DESC_MASK;
+ VERBOSE("Descriptor at level %i: 0x%llx\n", level,
+ (unsigned long long)desc);
+
+ if (desc_type == INVALID_DESC) {
+ VERBOSE("Invalid entry (memory not mapped)\n");
+ return NULL;
+ }
+
+ if (level == XLAT_TABLE_LEVEL_MAX) {
+ /*
+ * There can't be table entries at the final lookup
+ * level.
+ */
+ assert(desc_type == PAGE_DESC);
+ VERBOSE("Descriptor mapping a memory page (size: 0x%llx)\n",
+ (unsigned long long)XLAT_BLOCK_SIZE(XLAT_TABLE_LEVEL_MAX));
+ *out_level = level;
+ return &table[idx];
+ }
+
+ if (desc_type == BLOCK_DESC) {
+ VERBOSE("Descriptor mapping a memory block (size: 0x%llx)\n",
+ (unsigned long long)XLAT_BLOCK_SIZE(level));
+ *out_level = level;
+ return &table[idx];
+ }
+
+ assert(desc_type == TABLE_DESC);
+ VERBOSE("Table descriptor, continuing xlat table walk...\n");
+ table = (uint64_t *)(uintptr_t)(desc & TABLE_ADDR_MASK);
+ entries = XLAT_TABLE_ENTRIES;
+ }
+
+ /*
+ * This shouldn't be reached, the translation table walk should end at
+ * most at level XLAT_TABLE_LEVEL_MAX and return from inside the loop.
+ */
+ assert(0);
+
+ return NULL;
+}
+
+
+static int get_mem_attributes_internal(const xlat_ctx_t *ctx, uintptr_t base_va,
+ mmap_attr_t *attributes, uint64_t **table_entry,
+ unsigned long long *addr_pa, int *table_level)
+{
+ uint64_t *entry;
+ uint64_t desc;
+ int level;
+ unsigned long long virt_addr_space_size;
+
+ /*
+ * Sanity-check arguments.
+ */
+ assert(ctx != NULL);
+ assert(ctx->initialized);
+ assert(ctx->xlat_regime == EL1_EL0_REGIME || ctx->xlat_regime == EL3_REGIME);
+
+ virt_addr_space_size = (unsigned long long)ctx->va_max_address + 1;
+ assert(virt_addr_space_size > 0);
+
+ entry = find_xlat_table_entry(base_va,
+ ctx->base_table,
+ ctx->base_table_entries,
+ virt_addr_space_size,
+ &level);
+ if (entry == NULL) {
+ WARN("Address %p is not mapped.\n", (void *)base_va);
+ return -EINVAL;
+ }
+
+ if (addr_pa != NULL) {
+ *addr_pa = *entry & TABLE_ADDR_MASK;
+ }
+
+ if (table_entry != NULL) {
+ *table_entry = entry;
+ }
+
+ if (table_level != NULL) {
+ *table_level = level;
+ }
+
+ desc = *entry;
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ VERBOSE("Attributes: ");
+ xlat_desc_print(ctx, desc);
+ tf_printf("\n");
+#endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */
+
+ assert(attributes != NULL);
+ *attributes = 0;
+
+ int attr_index = (desc >> ATTR_INDEX_SHIFT) & ATTR_INDEX_MASK;
+
+ if (attr_index == ATTR_IWBWA_OWBWA_NTR_INDEX) {
+ *attributes |= MT_MEMORY;
+ } else if (attr_index == ATTR_NON_CACHEABLE_INDEX) {
+ *attributes |= MT_NON_CACHEABLE;
+ } else {
+ assert(attr_index == ATTR_DEVICE_INDEX);
+ *attributes |= MT_DEVICE;
+ }
+
+ int ap2_bit = (desc >> AP2_SHIFT) & 1;
+
+ if (ap2_bit == AP2_RW)
+ *attributes |= MT_RW;
+
+ if (ctx->xlat_regime == EL1_EL0_REGIME) {
+ int ap1_bit = (desc >> AP1_SHIFT) & 1;
+ if (ap1_bit == AP1_ACCESS_UNPRIVILEGED)
+ *attributes |= MT_USER;
+ }
+
+ int ns_bit = (desc >> NS_SHIFT) & 1;
+
+ if (ns_bit == 1)
+ *attributes |= MT_NS;
+
+ uint64_t xn_mask = xlat_arch_regime_get_xn_desc(ctx->xlat_regime);
+
+ if ((desc & xn_mask) == xn_mask) {
+ *attributes |= MT_EXECUTE_NEVER;
+ } else {
+ assert((desc & xn_mask) == 0);
+ }
+
+ return 0;
+}
+
+
+int get_mem_attributes(const xlat_ctx_t *ctx, uintptr_t base_va,
+ mmap_attr_t *attributes)
+{
+ return get_mem_attributes_internal(ctx, base_va, attributes,
+ NULL, NULL, NULL);
+}
+
+
+int change_mem_attributes(xlat_ctx_t *ctx,
+ uintptr_t base_va,
+ size_t size,
+ mmap_attr_t attr)
+{
+ /* Note: This implementation isn't optimized. */
+
+ assert(ctx != NULL);
+ assert(ctx->initialized);
+
+ unsigned long long virt_addr_space_size =
+ (unsigned long long)ctx->va_max_address + 1;
+ assert(virt_addr_space_size > 0);
+
+ if (!IS_PAGE_ALIGNED(base_va)) {
+ WARN("%s: Address %p is not aligned on a page boundary.\n",
+ __func__, (void *)base_va);
+ return -EINVAL;
+ }
+
+ if (size == 0) {
+ WARN("%s: Size is 0.\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((size % PAGE_SIZE) != 0) {
+ WARN("%s: Size 0x%zx is not a multiple of a page size.\n",
+ __func__, size);
+ return -EINVAL;
+ }
+
+ if (((attr & MT_EXECUTE_NEVER) == 0) && ((attr & MT_RW) != 0)) {
+ WARN("%s() doesn't allow to remap memory as read-write and executable.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ int pages_count = size / PAGE_SIZE;
+
+ VERBOSE("Changing memory attributes of %i pages starting from address %p...\n",
+ pages_count, (void *)base_va);
+
+ uintptr_t base_va_original = base_va;
+
+ /*
+ * Sanity checks.
+ */
+ for (int i = 0; i < pages_count; ++i) {
+ uint64_t *entry;
+ uint64_t desc;
+ int level;
+
+ entry = find_xlat_table_entry(base_va,
+ ctx->base_table,
+ ctx->base_table_entries,
+ virt_addr_space_size,
+ &level);
+ if (entry == NULL) {
+ WARN("Address %p is not mapped.\n", (void *)base_va);
+ return -EINVAL;
+ }
+
+ desc = *entry;
+
+ /*
+ * Check that all the required pages are mapped at page
+ * granularity.
+ */
+ if (((desc & DESC_MASK) != PAGE_DESC) ||
+ (level != XLAT_TABLE_LEVEL_MAX)) {
+ WARN("Address %p is not mapped at the right granularity.\n",
+ (void *)base_va);
+ WARN("Granularity is 0x%llx, should be 0x%x.\n",
+ (unsigned long long)XLAT_BLOCK_SIZE(level), PAGE_SIZE);
+ return -EINVAL;
+ }
+
+ /*
+ * If the region type is device, it shouldn't be executable.
+ */
+ int attr_index = (desc >> ATTR_INDEX_SHIFT) & ATTR_INDEX_MASK;
+ if (attr_index == ATTR_DEVICE_INDEX) {
+ if ((attr & MT_EXECUTE_NEVER) == 0) {
+ WARN("Setting device memory as executable at address %p.",
+ (void *)base_va);
+ return -EINVAL;
+ }
+ }
+
+ base_va += PAGE_SIZE;
+ }
+
+ /* Restore original value. */
+ base_va = base_va_original;
+
+ VERBOSE("%s: All pages are mapped, now changing their attributes...\n",
+ __func__);
+
+ for (int i = 0; i < pages_count; ++i) {
+
+ mmap_attr_t old_attr, new_attr;
+ uint64_t *entry;
+ int level;
+ unsigned long long addr_pa;
+
+ get_mem_attributes_internal(ctx, base_va, &old_attr,
+ &entry, &addr_pa, &level);
+
+ VERBOSE("Old attributes: 0x%x\n", old_attr);
+
+ /*
+ * From attr, only MT_RO/MT_RW, MT_EXECUTE/MT_EXECUTE_NEVER and
+ * MT_USER/MT_PRIVILEGED are taken into account. Any other
+ * information is ignored.
+ */
+
+ /* Clean the old attributes so that they can be rebuilt. */
+ new_attr = old_attr & ~(MT_RW|MT_EXECUTE_NEVER|MT_USER);
+
+ /*
+ * Update attributes, but filter out the ones this function
+ * isn't allowed to change.
+ */
+ new_attr |= attr & (MT_RW|MT_EXECUTE_NEVER|MT_USER);
+
+ VERBOSE("New attributes: 0x%x\n", new_attr);
+
+ /*
+ * The break-before-make sequence requires writing an invalid
+ * descriptor and making sure that the system sees the change
+ * before writing the new descriptor.
+ */
+ *entry = INVALID_DESC;
+
+ /* Invalidate any cached copy of this mapping in the TLBs. */
+ xlat_arch_tlbi_va_regime(base_va, ctx->xlat_regime);
+
+ /* Ensure completion of the invalidation. */
+ xlat_arch_tlbi_va_sync();
+
+ /* Write new descriptor */
+ *entry = xlat_desc(ctx, new_attr, addr_pa, level);
+
+ base_va += PAGE_SIZE;
+ }
+
+ /* Ensure that the last descriptor writen is seen by the system. */
+ dsbish();
+
+ return 0;
+}
diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h
index d352583c..79efbebb 100644
--- a/lib/xlat_tables_v2/xlat_tables_private.h
+++ b/lib/xlat_tables_v2/xlat_tables_private.h
@@ -34,12 +34,24 @@ typedef enum {
MT_DYNAMIC = 1 << MT_DYN_SHIFT
} mmap_priv_attr_t;
+#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+
/*
- * Function used to invalidate all levels of the translation walk for a given
- * virtual address. It must be called for every translation table entry that is
- * modified.
+ * Invalidate all TLB entries that match the given virtual address. This
+ * operation applies to all PEs in the same Inner Shareable domain as the PE
+ * that executes this function. This functions must be called for every
+ * translation table entry that is modified.
+ *
+ * xlat_arch_tlbi_va() applies the invalidation to the exception level of the
+ * current translation regime, whereas xlat_arch_tlbi_va_regime() applies it to
+ * the given translation regime.
+ *
+ * Note, however, that it is architecturally UNDEFINED to invalidate TLB entries
+ * pertaining to a higher exception level, e.g. invalidating EL3 entries from
+ * S-EL1.
*/
void xlat_arch_tlbi_va(uintptr_t va);
+void xlat_arch_tlbi_va_regime(uintptr_t va, xlat_regime_t xlat_regime);
/*
* This function has to be called at the end of any code that uses the function
@@ -47,8 +59,6 @@ void xlat_arch_tlbi_va(uintptr_t va);
*/
void xlat_arch_tlbi_va_sync(void);
-#endif /* PLAT_XLAT_TABLES_DYNAMIC */
-
/* Print VA, PA, size and attributes of all regions in the mmap array. */
void print_mmap(mmap_region_t *const mmap);
@@ -66,13 +76,6 @@ void xlat_tables_print(xlat_ctx_t *ctx);
int xlat_arch_current_el(void);
/*
- * Returns the bit mask that has to be ORed to the rest of a translation table
- * descriptor so that execution of code is prohibited at the given Exception
- * Level.
- */
-uint64_t xlat_arch_get_xn_desc(int el);
-
-/*
* Return the maximum physical address supported by the hardware.
* This value depends on the execution state (AArch32/AArch64).
*/
@@ -82,7 +85,10 @@ unsigned long long xlat_arch_get_max_supported_pa(void);
void enable_mmu_arch(unsigned int flags, uint64_t *base_table,
unsigned long long pa, uintptr_t max_va);
-/* Return 1 if the MMU of this Exception Level is enabled, 0 otherwise. */
-int is_mmu_enabled(void);
+/*
+ * Return 1 if the MMU of the translation regime managed by the given xlat_ctx_t
+ * is enabled, 0 otherwise.
+ */
+int is_mmu_enabled_ctx(const xlat_ctx_t *ctx);
#endif /* __XLAT_TABLES_PRIVATE_H__ */
diff --git a/maintainers.rst b/maintainers.rst
index 388073e4..04ab695e 100644
--- a/maintainers.rst
+++ b/maintainers.rst
@@ -21,8 +21,8 @@ Jens Wiklander (jens.wiklander@linaro.org, `jenswi-linaro`_)
Files:
-- docs/spd/optee-dispatcher.md
-- docs/plat/qemu.md
+- docs/plat/qemu.rst
+- docs/spd/optee-dispatcher.rst
- services/spd/opteed/\*
- plat/qemu/\*
@@ -33,8 +33,9 @@ Varun Wadekar (vwadekar@nvidia.com, `vwadekar`_)
Files:
-- docs/spd/tlk-dispatcher.md
-- docs/spd/trusty-dispatcher.md
+- docs/plat/nvidia-tegra.rst
+- docs/spd/tlk-dispatcher.rst
+- docs/spd/trusty-dispatcher.rst
- include/bl32/payloads/tlk.h
- include/lib/cpus/aarch64/denver.h
- lib/cpus/aarch64/denver.S
@@ -49,8 +50,9 @@ Haojian Zhuang (haojian.zhuang@linaro.org, `hzhuang1`_)
Files:
-- docs/plat/hikey.md
-- docs/plat/hikey960.md
+- docs/plat/hikey.rst
+- docs/plat/hikey960.rst
+- docs/plat/poplar.rst
- drivers/emmc/\*
- drivers/partition/\*
- drivers/synopsys/emmc/\*
@@ -71,32 +73,60 @@ Files:
- plat/mediatek/\*
+Raspberry Pi 3 platform sub-maintainer
+--------------------------------------
+
+Antonio Niño Díaz (antonio.ninodiaz@arm.com, `antonio-nino-diaz-arm`_)
+
+Files:
+
+- docs/plat/rpi3.rst
+- plat/rpi3/\*
+
RockChip platform sub-maintainer
--------------------------------
Tony Xie (tony.xie@rock-chips.com, `TonyXie06`_
-or `rkchrome`_)
+or `rockchip-linux`_)
Files:
- plat/rockchip/\*
+UniPhier platform sub-maintainer
+--------------------------------
+
+Masahiro Yamada (yamada.masahiro@socionext.com, `masahir0y`_)
+
+Files:
+
+- docs/plat/socionext-uniphier.rst
+- plat/socionext/\*
+
Xilinx platform sub-maintainer
------------------------------
-Sören Brinkmann (soren.brinkmann@xilinx.com, `sorenb-xlnx`_)
+Siva Durga Prasad Paladugu (siva.durga.paladugu@xilinx.com, `sivadur`_)
Files:
-- docs/plat/xilinx-zynqmp.md
+- docs/plat/xilinx-zynqmp.rst
- plat/xilinx/\*
+ARMv7 architecture sub-maintainer
+---------------------------------
+
+Etienne Carriere (etienne.carriere@linaro.org, `etienne-lms`_)
+
+.. _antonio-nino-diaz-arm: https://github.com/antonio-nino-diaz-arm
.. _danh-arm: https://github.com/danh-arm
.. _davidcunado-arm: https://github.com/davidcunado-arm
.. _jenswi-linaro: https://github.com/jenswi-linaro
.. _vwadekar: https://github.com/vwadekar
.. _hzhuang1: https://github.com/hzhuang1
+.. _masahir0y: https://github.com/masahir0y
.. _mtk09422: https://github.com/mtk09422
.. _TonyXie06: https://github.com/TonyXie06
-.. _rkchrome: https://github.com/rkchrome
-.. _sorenb-xlnx: https://github.com/sorenb-xlnx
+.. _sivadur: https://github.com/sivadur
+.. _rockchip-linux: https://github.com/rockchip-linux
+.. _etienne-lms: https://github.com/etienne-lms
diff --git a/make_helpers/armv7-a-cpus.mk b/make_helpers/armv7-a-cpus.mk
new file mode 100644
index 00000000..20e7ec53
--- /dev/null
+++ b/make_helpers/armv7-a-cpus.mk
@@ -0,0 +1,50 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${ARCH},aarch32)
+$(error ARM_ARCH_MAJOR=7 mandates ARCH=aarch32)
+endif
+
+# For ARMv7, set march32 from platform directive ARMV7_CORTEX_Ax=yes
+# and ARM_WITH_NEON=yes/no.
+#
+# GCC and Clang require -march=armv7-a for C-A9 and -march=armv7ve for C-A15.
+# armClang requires -march=armv7-a for all ARMv7 Cortex-A. To comply with
+# all, just drop -march and supply only -mcpu.
+
+# Platform can override march32-directive through MARCH32_DIRECTIVE
+ifdef MARCH32_DIRECTIVE
+march32-directive := $(MARCH32_DIRECTIVE)
+else
+march32-set-${ARM_CORTEX_A5} := -mcpu=cortex-a5
+march32-set-${ARM_CORTEX_A7} := -mcpu=cortex-a7
+march32-set-${ARM_CORTEX_A9} := -mcpu=cortex-a9
+march32-set-${ARM_CORTEX_A12} := -mcpu=cortex-a12
+march32-set-${ARM_CORTEX_A15} := -mcpu=cortex-a15
+march32-set-${ARM_CORTEX_A17} := -mcpu=cortex-a17
+march32-neon-$(ARM_WITH_NEON) := -mfpu=neon
+
+# default to -march=armv7-a as target directive
+march32-set-yes ?= -march=armv7-a
+march32-directive := ${march32-set-yes} ${march32-neon-yes}
+endif
+
+# Platform may override these extension support directives:
+#
+# ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING
+# Defined if core supports the Large Page Addressing extension.
+#
+# ARMV7_SUPPORTS_VIRTUALIZATION
+# Defined if ARMv7 core supports the Virtualization extension.
+#
+# ARMV7_SUPPORTS_GENERIC_TIMER
+# Defined if ARMv7 core supports the Generic Timer extension.
+
+ifeq ($(filter yes,$(ARM_CORTEX_A7) $(ARM_CORTEX_A12) $(ARM_CORTEX_A15) $(ARM_CORTEX_A17)),yes)
+$(eval $(call add_define,ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING))
+$(eval $(call add_define,ARMV7_SUPPORTS_VIRTUALIZATION))
+$(eval $(call add_define,ARMV7_SUPPORTS_GENERIC_TIMER))
+endif
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
index fd8eb05f..e1bfbbe7 100644
--- a/make_helpers/build_macros.mk
+++ b/make_helpers/build_macros.mk
@@ -291,7 +291,7 @@ define MAKE_BL
# Create generators for object directory structure
-$(eval $(call MAKE_PREREQ_DIR,${BUILD_DIR},))
+$(eval $(call MAKE_PREREQ_DIR,${BUILD_DIR},${BUILD_PLAT}))
$(eval $(foreach objd,${OBJ_DIRS},$(call MAKE_PREREQ_DIR,${objd},${BUILD_DIR})))
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 86010460..fa0d17de 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -24,9 +24,6 @@ ARM_ARCH_MINOR := 0
# in EL3. The platform port can change this value if needed.
ARM_GIC_ARCH := 2
-# Flag used to indicate if ASM_ASSERTION should be enabled for the build.
-ASM_ASSERTION := 0
-
# Base commit to perform code check on
BASE_COMMIT := origin/master
@@ -62,6 +59,9 @@ ENABLE_RUNTIME_INSTRUMENTATION := 0
# Flag to enable stack corruption protection
ENABLE_STACK_PROTECTOR := 0
+# Flag to enable exception handling in EL3
+EL3_EXCEPTION_HANDLING := 0
+
# Build flag to treat usage of deprecated platform and framework APIs as error.
ERROR_DEPRECATED := 0
@@ -77,6 +77,10 @@ FWU_FIP_NAME := fwu_fip.bin
# For Chain of Trust
GENERATE_COT := 0
+# Hint platform interrupt control layer that Group 0 interrupts are for EL3. By
+# default, they are for Secure EL1.
+GICV2_G0_FOR_EL3 := 0
+
# Whether system coherency is managed in hardware, without explicit software
# operations.
HW_ASSISTED_COHERENCY := 0
@@ -107,6 +111,9 @@ RESET_TO_BL31 := 0
# For Chain of Trust
SAVE_KEYS := 0
+# Software Delegated Exception support
+SDEI_SUPPORT := 0
+
# Whether code and read-only data should be put on separate memory pages. The
# platform Makefile is free to override this value.
SEPARATE_CODE_AND_RODATA := 0
@@ -114,6 +121,9 @@ SEPARATE_CODE_AND_RODATA := 0
# SPD choice
SPD := none
+# For including the Secure Partition Manager
+ENABLE_SPM := 0
+
# Flag to introduce an infinite loop in BL1 just before it exits into the next
# image. This is meant to help debugging the post-BL2 phase.
SPIN_ON_BL1_EXIT := 0
@@ -136,19 +146,21 @@ V := 0
# platforms).
WARMBOOT_ENABLE_DCACHE_EARLY := 0
-# By default, enable Statistical Profiling Extensions.
-# The top level Makefile will disable this feature depending on
-# the target architecture and version number.
+# Build option to enable/disable the Statistical Profiling Extensions
ENABLE_SPE_FOR_LOWER_ELS := 1
-# SPE is enabled by default but only supported on AArch64 8.2 onwards.
-# Disable it in all other cases.
+# SPE is only supported on AArch64 so disable it on AArch32.
ifeq (${ARCH},aarch32)
override ENABLE_SPE_FOR_LOWER_ELS := 0
+endif
+
+ENABLE_AMU := 0
+
+# By default, enable Scalable Vector Extension if implemented for Non-secure
+# lower ELs
+# Note SVE is only supported on AArch64 - therefore do not enable in AArch32
+ifneq (${ARCH},aarch32)
+ ENABLE_SVE_FOR_NS := 1
else
- ifeq (${ARM_ARCH_MAJOR},8)
- ifeq ($(ARM_ARCH_MINOR),$(filter $(ARM_ARCH_MINOR),0 1))
- ENABLE_SPE_FOR_LOWER_ELS := 0
- endif
- endif
+ override ENABLE_SVE_FOR_NS := 0
endif
diff --git a/make_helpers/tbbr/tbbr_tools.mk b/make_helpers/tbbr/tbbr_tools.mk
index 712fa6f6..6e6e2739 100644
--- a/make_helpers/tbbr/tbbr_tools.mk
+++ b/make_helpers/tbbr/tbbr_tools.mk
@@ -54,6 +54,7 @@ $(eval $(call FWU_CERT_ADD_CMD_OPT,${FWU_CERT},--fwu-cert))
# packed in the FIP). Developers can use their own keys by specifying the proper
# build option in the command line when building the Trusted Firmware
$(if ${KEY_ALG},$(eval $(call CERT_ADD_CMD_OPT,${KEY_ALG},--key-alg)))
+$(if ${HASH_ALG},$(eval $(call CERT_ADD_CMD_OPT,${HASH_ALG},--hash-alg)))
$(if ${ROT_KEY},$(eval $(call CERT_ADD_CMD_OPT,${ROT_KEY},--rot-key)))
$(if ${ROT_KEY},$(eval $(call FWU_CERT_ADD_CMD_OPT,${ROT_KEY},--rot-key)))
$(if ${TRUSTED_WORLD_KEY},$(eval $(call CERT_ADD_CMD_OPT,${TRUSTED_WORLD_KEY},--trusted-world-key)))
@@ -76,6 +77,7 @@ ifneq (${SCP_BL2},)
endif
ifeq (${ARCH},aarch64)
+ifeq (${NEED_BL31},yes)
# Add the BL31 CoT (key cert + img cert + image)
$(if ${BL31},$(eval $(call CERT_ADD_CMD_OPT,${BL31},--soc-fw,true)),\
$(eval $(call CERT_ADD_CMD_OPT,$(call IMG_BIN,31),--soc-fw,true)))
@@ -85,6 +87,7 @@ $(eval $(call CERT_ADD_CMD_OPT,${BUILD_PLAT}/soc_fw_key.crt,--soc-fw-key-cert))
$(eval $(call FIP_ADD_PAYLOAD,${BUILD_PLAT}/soc_fw_content.crt,--soc-fw-cert))
$(eval $(call FIP_ADD_PAYLOAD,${BUILD_PLAT}/soc_fw_key.crt,--soc-fw-key-cert))
endif
+endif
# Add the BL32 CoT (key cert + img cert + image)
ifeq (${NEED_BL32},yes)
diff --git a/plat/arm/board/common/board_arm_trusted_boot.c b/plat/arm/board/common/board_arm_trusted_boot.c
index 5d36d178..6c03c91b 100644
--- a/plat/arm/board/common/board_arm_trusted_boot.c
+++ b/plat/arm/board/common/board_arm_trusted_boot.c
@@ -18,6 +18,7 @@
/* ROTPK locations */
#define ARM_ROTPK_REGS_ID 1
#define ARM_ROTPK_DEVEL_RSA_ID 2
+#define ARM_ROTPK_DEVEL_ECDSA_ID 3
static const unsigned char rotpk_hash_hdr[] = \
"\x30\x31\x30\x0D\x06\x09\x60\x86\x48" \
@@ -41,6 +42,12 @@ static const unsigned char arm_devel_rotpk_hash[] = \
"\x37\x7A\x72\x47\x1B\xEC\x32\x73" \
"\xE9\x92\x32\xE2\x49\x59\xF6\x5E" \
"\x8B\x4A\x4A\x46\xD8\x22\x9A\xDA";
+#elif (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID)
+static const unsigned char arm_devel_rotpk_hash[] = \
+ "\x2E\x40\xBF\x6E\xF9\x12\xBB\x98" \
+ "\x31\x71\x09\x0E\x1E\x15\x3D\x0B" \
+ "\xFD\xD1\xCC\x69\x4A\x98\xEB\x8B" \
+ "\xA0\xB0\x20\x86\x4E\x6C\x07\x17";
#endif
/*
@@ -69,7 +76,8 @@ int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
memcpy(rotpk_hash_der, rotpk_hash_hdr, rotpk_hash_hdr_len);
dst = (uint8_t *)&rotpk_hash_der[rotpk_hash_hdr_len];
-#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID)
+#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) \
+ || (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID)
memcpy(dst, arm_devel_rotpk_hash, SHA256_BYTES);
#elif (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID)
uint32_t *src, tmp;
@@ -121,7 +129,8 @@ int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
*dst++ = (uint8_t)((tmp >> 8) & 0xFF);
*dst++ = (uint8_t)(tmp & 0xFF);
}
-#endif /* (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) */
+#endif /* (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) \
+ || (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID) */
*key_ptr = (void *)rotpk_hash_der;
*key_len = (unsigned int)sizeof(rotpk_hash_der);
diff --git a/plat/arm/board/common/board_common.mk b/plat/arm/board/common/board_common.mk
index 46672982..d63ae9a3 100644
--- a/plat/arm/board/common/board_common.mk
+++ b/plat/arm/board/common/board_common.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -12,9 +12,13 @@ PLAT_BL_COMMON_SOURCES += drivers/arm/pl011/${ARCH}/pl011_console.S \
BL1_SOURCES += plat/arm/board/common/drivers/norflash/norflash.c
-BL2_SOURCES += plat/arm/board/common/drivers/norflash/norflash.c
+BL2_SOURCES += lib/utils/mem_region.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c \
+ plat/arm/board/common/drivers/norflash/norflash.c
-#BL31_SOURCES +=
+BL31_SOURCES += lib/utils/mem_region.c \
+ plat/arm/board/common/drivers/norflash/norflash.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
ifneq (${TRUSTED_BOARD_BOOT},0)
ifneq (${ARM_CRYPTOCELL_INTEG}, 1)
@@ -22,7 +26,11 @@ ifneq (${TRUSTED_BOARD_BOOT},0)
ifeq (${ARM_ROTPK_LOCATION}, regs)
ARM_ROTPK_LOCATION_ID = ARM_ROTPK_REGS_ID
else ifeq (${ARM_ROTPK_LOCATION}, devel_rsa)
+ KEY_ALG := rsa
ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_RSA_ID
+ else ifeq (${ARM_ROTPK_LOCATION}, devel_ecdsa)
+ KEY_ALG := ecdsa
+ ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_ECDSA_ID
else
$(error "Unsupported ARM_ROTPK_LOCATION value")
endif
diff --git a/plat/arm/board/common/board_css_common.c b/plat/arm/board/common/board_css_common.c
index 159bf86f..032ebdf7 100644
--- a/plat/arm/board/common/board_css_common.c
+++ b/plat/arm/board/common/board_css_common.c
@@ -29,10 +29,16 @@ const mmap_region_t plat_arm_mmap[] = {
const mmap_region_t plat_arm_mmap[] = {
ARM_MAP_SHARED_RAM,
V2M_MAP_FLASH0_RO,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+ ARM_V2M_MAP_MEM_PROTECT,
+#endif
V2M_MAP_IOFPGA,
CSS_MAP_DEVICE,
SOC_CSS_MAP_DEVICE,
ARM_MAP_NS_DRAM1,
+#ifdef AARCH64
+ ARM_MAP_DRAM2,
+#endif
#ifdef SPD_tspd
ARM_MAP_TSP_SEC_MEM,
#endif
@@ -56,6 +62,9 @@ const mmap_region_t plat_arm_mmap[] = {
ARM_MAP_SHARED_RAM,
V2M_MAP_IOFPGA,
CSS_MAP_DEVICE,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+ ARM_V2M_MAP_MEM_PROTECT,
+#endif
SOC_CSS_MAP_DEVICE,
{0}
};
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der
new file mode 100644
index 00000000..25478772
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der
Binary files differ
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin
new file mode 100644
index 00000000..c5e123ab
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin
@@ -0,0 +1 @@
+.@¿nù»˜1q = ýÑÌiJ˜ë‹ ° †Nl \ No newline at end of file
diff --git a/plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem b/plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem
new file mode 100644
index 00000000..fb328e3c
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEINSaX6nvzS3teiBJA7WlTLRKJOajpy29o2cArLbUXoZBoAoGCCqGSM49
+AwEHoUQDQgAEm+ZIvTQ44aKk83DhVLsvsFpKDP/Ch9vA+4Hp+fmVfX6gDH8K1OBi
+SpRf7FJ9RGPIn2H6xst+a1OtLMWUDRqGkQ==
+-----END EC PRIVATE KEY-----
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index e869f5b2..6729863d 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -6,6 +6,7 @@
#include <arm_config.h>
#include <arm_def.h>
+#include <arm_spm_def.h>
#include <assert.h>
#include <cci.h>
#include <ccn.h>
@@ -13,6 +14,7 @@
#include <gicv2.h>
#include <mmio.h>
#include <plat_arm.h>
+#include <secure_partition.h>
#include <v2m_def.h>
#include "../fvp_def.h"
@@ -79,6 +81,9 @@ const mmap_region_t plat_arm_mmap[] = {
MAP_DEVICE0,
MAP_DEVICE1,
ARM_MAP_NS_DRAM1,
+#ifdef AARCH64
+ ARM_MAP_DRAM2,
+#endif
#ifdef SPD_tspd
ARM_MAP_TSP_SEC_MEM,
#endif
@@ -86,6 +91,9 @@ const mmap_region_t plat_arm_mmap[] = {
/* To access the Root of Trust Public Key registers. */
MAP_DEVICE2,
#endif
+#if ENABLE_SPM
+ ARM_SP_IMAGE_MMAP,
+#endif
#if ARM_BL31_IN_DRAM
ARM_MAP_BL31_SEC_DRAM,
#endif
@@ -106,12 +114,28 @@ const mmap_region_t plat_arm_mmap[] = {
#ifdef IMAGE_BL31
const mmap_region_t plat_arm_mmap[] = {
ARM_MAP_SHARED_RAM,
+ ARM_MAP_EL3_TZC_DRAM,
V2M_MAP_IOFPGA,
MAP_DEVICE0,
MAP_DEVICE1,
+ ARM_V2M_MAP_MEM_PROTECT,
+#if ENABLE_SPM
+ ARM_SPM_BUF_EL3_MMAP,
+#endif
+ {0}
+};
+
+#if ENABLE_SPM && defined(IMAGE_BL31)
+const mmap_region_t plat_arm_secure_partition_mmap[] = {
+ V2M_MAP_IOFPGA_EL0, /* for the UART */
+ ARM_SP_IMAGE_MMAP,
+ ARM_SP_IMAGE_NS_BUF_MMAP,
+ ARM_SP_IMAGE_RW_MMAP,
+ ARM_SPM_BUF_EL0_MMAP,
{0}
};
#endif
+#endif
#ifdef IMAGE_BL32
const mmap_region_t plat_arm_mmap[] = {
#ifdef AARCH32
@@ -151,6 +175,57 @@ static unsigned int get_interconnect_master(void)
}
#endif
+#if ENABLE_SPM && defined(IMAGE_BL31)
+/*
+ * Boot information passed to a secure partition during initialisation. Linear
+ * indices in MP information will be filled at runtime.
+ */
+static secure_partition_mp_info_t sp_mp_info[] = {
+ [0] = {0x80000000, 0},
+ [1] = {0x80000001, 0},
+ [2] = {0x80000002, 0},
+ [3] = {0x80000003, 0},
+ [4] = {0x80000100, 0},
+ [5] = {0x80000101, 0},
+ [6] = {0x80000102, 0},
+ [7] = {0x80000103, 0},
+};
+
+const secure_partition_boot_info_t plat_arm_secure_partition_boot_info = {
+ .h.type = PARAM_SP_IMAGE_BOOT_INFO,
+ .h.version = VERSION_1,
+ .h.size = sizeof(secure_partition_boot_info_t),
+ .h.attr = 0,
+ .sp_mem_base = ARM_SP_IMAGE_BASE,
+ .sp_mem_limit = ARM_SP_IMAGE_LIMIT,
+ .sp_image_base = ARM_SP_IMAGE_BASE,
+ .sp_stack_base = PLAT_SP_IMAGE_STACK_BASE,
+ .sp_heap_base = ARM_SP_IMAGE_HEAP_BASE,
+ .sp_ns_comm_buf_base = ARM_SP_IMAGE_NS_BUF_BASE,
+ .sp_shared_buf_base = PLAT_SPM_BUF_BASE,
+ .sp_image_size = ARM_SP_IMAGE_SIZE,
+ .sp_pcpu_stack_size = PLAT_SP_IMAGE_STACK_PCPU_SIZE,
+ .sp_heap_size = ARM_SP_IMAGE_HEAP_SIZE,
+ .sp_ns_comm_buf_size = ARM_SP_IMAGE_NS_BUF_SIZE,
+ .sp_shared_buf_size = PLAT_SPM_BUF_SIZE,
+ .num_sp_mem_regions = ARM_SP_IMAGE_NUM_MEM_REGIONS,
+ .num_cpus = PLATFORM_CORE_COUNT,
+ .mp_info = &sp_mp_info[0],
+};
+
+const struct mmap_region *plat_get_secure_partition_mmap(void *cookie)
+{
+ return plat_arm_secure_partition_mmap;
+}
+
+const struct secure_partition_boot_info *plat_get_secure_partition_boot_info(
+ void *cookie)
+{
+ return &plat_arm_secure_partition_boot_info;
+}
+
+#endif
+
/*******************************************************************************
* A single boot loader stack is expected to work on both the Foundation FVP
* models and the two flavours of the Base FVP models (AEMv8 & Cortex). The
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index 9a02089e..72845843 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,10 +9,12 @@
#include <assert.h>
#include <debug.h>
#include <errno.h>
+#include <gicv3.h>
#include <mmio.h>
#include <plat_arm.h>
#include <platform.h>
#include <psci.h>
+#include <spe.h>
#include <v2m_def.h>
#include "drivers/pwrc/fvp_pwrc.h"
#include "fvp_def.h"
@@ -36,6 +38,9 @@ const unsigned int arm_pm_idle_states[] = {
/* State-id - 0x22 */
arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN),
+ /* State-id - 0x222 */
+ arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
+ ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN),
0,
};
#endif
@@ -53,7 +58,7 @@ static void fvp_cluster_pwrdwn_common(void)
* On power down we need to disable statistical profiling extensions
* before exiting coherency.
*/
- arm_disable_spe();
+ spe_disable();
#endif
/* Disable coherency if this cluster is to be turned off */
@@ -63,6 +68,18 @@ static void fvp_cluster_pwrdwn_common(void)
fvp_pwrc_write_pcoffr(mpidr);
}
+/*
+ * Empty implementation of these hooks avoid setting the GICR_WAKER.Sleep bit
+ * on ARM GICv3 implementations on FVP. This is required, because FVP does not
+ * support SYSTEM_SUSPEND and it is `faked` in firmware. Hence, for wake up
+ * from `fake` system suspend the GIC must not be powered off.
+ */
+void arm_gicv3_distif_pre_save(unsigned int proc_num)
+{}
+
+void arm_gicv3_distif_post_restore(unsigned int proc_num)
+{}
+
static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state)
{
unsigned long mpidr;
@@ -90,6 +107,10 @@ static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_s
/* Enable coherency if this cluster was off */
fvp_interconnect_enable();
}
+ /* Perform the common system specific operations */
+ if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
+ ARM_LOCAL_STATE_OFF)
+ arm_system_pwr_domain_resume();
/*
* Clear PWKUPR.WEN bit to ensure interrupts do not interfere
@@ -201,13 +222,18 @@ void fvp_pwr_domain_suspend(const psci_power_state_t *target_state)
* register context.
*/
- /* Program the power controller to power off this cpu. */
- fvp_pwrc_write_ppoffr(read_mpidr_el1());
-
/* Perform the common cluster specific operations */
if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
ARM_LOCAL_STATE_OFF)
fvp_cluster_pwrdwn_common();
+
+ /* Perform the common system specific operations */
+ if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
+ ARM_LOCAL_STATE_OFF)
+ arm_system_pwr_domain_save();
+
+ /* Program the power controller to power off this cpu. */
+ fvp_pwrc_write_ppoffr(read_mpidr_el1());
}
/*******************************************************************************
@@ -309,6 +335,56 @@ static int fvp_node_hw_state(u_register_t target_cpu,
return ret;
}
+/*
+ * The FVP doesn't truly support power management at SYSTEM power domain. The
+ * SYSTEM_SUSPEND will be down-graded to the cluster level within the platform
+ * layer. The `fake` SYSTEM_SUSPEND allows us to validate some of the driver
+ * save and restore sequences on FVP.
+ */
+void fvp_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ unsigned int i;
+
+ for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
+ req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF;
+}
+
+/*******************************************************************************
+ * Handler to filter PSCI requests.
+ ******************************************************************************/
+/*
+ * The system power domain suspend is only supported only via
+ * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain
+ * will be downgraded to the lower level.
+ */
+static int fvp_validate_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ int rc;
+ rc = arm_validate_power_state(power_state, req_state);
+
+ /*
+ * Ensure that the system power domain level is never suspended
+ * via PSCI CPU SUSPEND API. Currently system suspend is only
+ * supported via PSCI SYSTEM SUSPEND API.
+ */
+ req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN;
+ return rc;
+}
+
+/*
+ * Custom `translate_power_state_by_mpidr` handler for FVP. Unlike in the
+ * `fvp_validate_power_state`, we do not downgrade the system power
+ * domain level request in `power_state` as it will be used to query the
+ * PSCI_STAT_COUNT/RESIDENCY at the system power domain level.
+ */
+static int fvp_translate_power_state_by_mpidr(u_register_t mpidr,
+ unsigned int power_state,
+ psci_power_state_t *output_state)
+{
+ return arm_validate_power_state(power_state, output_state);
+}
+
/*******************************************************************************
* Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
* platform layer will take care of registering the handlers with PSCI.
@@ -322,7 +398,26 @@ plat_psci_ops_t plat_arm_psci_pm_ops = {
.pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish,
.system_off = fvp_system_off,
.system_reset = fvp_system_reset,
- .validate_power_state = arm_validate_power_state,
- .validate_ns_entrypoint = arm_validate_ns_entrypoint,
- .get_node_hw_state = fvp_node_hw_state
+ .validate_power_state = fvp_validate_power_state,
+ .validate_ns_entrypoint = arm_validate_psci_entrypoint,
+ .translate_power_state_by_mpidr = fvp_translate_power_state_by_mpidr,
+ .get_node_hw_state = fvp_node_hw_state,
+#if !ARM_BL31_IN_DRAM
+ /*
+ * The TrustZone Controller is set up during the warmboot sequence after
+ * resuming the CPU from a SYSTEM_SUSPEND. If BL31 is located in SRAM
+ * this is not a problem but, if it is in TZC-secured DRAM, it tries to
+ * reconfigure the same memory it is running on, causing an exception.
+ */
+ .get_sys_suspend_power_state = fvp_get_sys_suspend_power_state,
+#endif
+#if !RESET_TO_BL31 && !RESET_TO_SP_MIN
+ /*
+ * mem_protect is not supported in RESET_TO_BL31 and RESET_TO_SP_MIN,
+ * as that would require mapping in all of NS DRAM into BL31 or BL32.
+ */
+ .mem_protect_chk = arm_psci_mem_protect_chk,
+ .read_mem_protect = arm_psci_read_mem_protect,
+ .write_mem_protect = arm_nor_psci_write_mem_protect,
+#endif
};
diff --git a/plat/arm/board/fvp/fvp_topology.c b/plat/arm/board/fvp/fvp_topology.c
index cf1492b6..4a007f4f 100644
--- a/plat/arm/board/fvp/fvp_topology.c
+++ b/plat/arm/board/fvp/fvp_topology.c
@@ -12,7 +12,7 @@
#include "drivers/pwrc/fvp_pwrc.h"
/* The FVP power domain tree descriptor */
-unsigned char fvp_power_domain_tree_desc[FVP_CLUSTER_COUNT + 1];
+unsigned char fvp_power_domain_tree_desc[FVP_CLUSTER_COUNT + 2];
CASSERT(FVP_CLUSTER_COUNT && FVP_CLUSTER_COUNT <= 256, assert_invalid_fvp_cluster_count);
@@ -23,18 +23,18 @@ CASSERT(FVP_CLUSTER_COUNT && FVP_CLUSTER_COUNT <= 256, assert_invalid_fvp_cluste
******************************************************************************/
const unsigned char *plat_get_power_domain_tree_desc(void)
{
- int i;
+ unsigned int i;
/*
- * The FVP power domain tree does not have a single system level power domain
- * i.e. a single root node. The first entry in the power domain descriptor
- * specifies the number of power domains at the highest power level. For the FVP
- * this is the number of cluster power domains.
+ * The highest level is the system level. The next level is constituted
+ * by clusters and then cores in clusters.
*/
- fvp_power_domain_tree_desc[0] = FVP_CLUSTER_COUNT;
+ fvp_power_domain_tree_desc[0] = 1;
+ fvp_power_domain_tree_desc[1] = FVP_CLUSTER_COUNT;
for (i = 0; i < FVP_CLUSTER_COUNT; i++)
- fvp_power_domain_tree_desc[i + 1] = FVP_MAX_CPUS_PER_CLUSTER;
+ fvp_power_domain_tree_desc[i + 2] = FVP_MAX_CPUS_PER_CLUSTER;
+
return fvp_power_domain_tree_desc;
}
diff --git a/plat/arm/board/fvp/include/plat.ld.S b/plat/arm/board/fvp/include/plat.ld.S
new file mode 100644
index 00000000..24c3debd
--- /dev/null
+++ b/plat/arm/board/fvp/include/plat.ld.S
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __PLAT_LD_S__
+#define __PLAT_LD_S__
+
+#include <arm_common.ld.S>
+
+#endif /* __PLAT_LD_S__ */
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index bf038e92..7080fc30 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -8,10 +8,11 @@
#define __PLATFORM_DEF_H__
#include <arm_def.h>
+#include <arm_spm_def.h>
#include <board_arm_def.h>
#include <common_def.h>
#include <tzc400.h>
-#include <utils.h>
+#include <utils_def.h>
#include <v2m_def.h>
#include "../fvp_def.h"
@@ -20,9 +21,9 @@
(FVP_CLUSTER_COUNT * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU)
#define PLAT_NUM_PWR_DOMAINS (FVP_CLUSTER_COUNT + \
- PLATFORM_CORE_COUNT)
+ PLATFORM_CORE_COUNT) + 1
-#define PLAT_MAX_PWR_LVL ARM_PWR_LVL1
+#define PLAT_MAX_PWR_LVL ARM_PWR_LVL2
/*
* Other platform porting definitions are provided by included headers
@@ -136,4 +137,13 @@
#define PLAT_ARM_G0_IRQS ARM_G0_IRQS
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+ ARM_G1S_IRQ_PROPS(grp), \
+ INTR_PROP_DESC(FVP_IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(FVP_IRQ_SEC_SYS_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp) ARM_G0_IRQ_PROPS(grp)
+
#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 6d8aa5fb..7edbd3df 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -48,7 +48,8 @@ FVP_GICV3_SOURCES := drivers/arm/gic/common/gic_common.c \
# Choose the GIC sources depending upon the how the FVP will be invoked
ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
-FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES}
+FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES} \
+ drivers/arm/gic/v3/gic500.c
else ifeq (${FVP_USE_GIC_DRIVER},FVP_GIC600)
FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES} \
drivers/arm/gic/v3/gic600.c
@@ -146,6 +147,9 @@ BL31_SOURCES += drivers/arm/smmu/smmu_v3.c \
# Disable the PSCI platform compatibility layer
ENABLE_PLAT_COMPAT := 0
+# Enable Activity Monitor Unit extensions by default
+ENABLE_AMU := 1
+
ifneq (${ENABLE_STACK_PROTECTOR},0)
PLAT_BL_COMMON_SOURCES += plat/arm/board/fvp/fvp_stack_protector.c
endif
@@ -154,5 +158,8 @@ ifeq (${ARCH},aarch32)
NEED_BL32 := yes
endif
+# Add support for platform supplied linker script for BL31 build
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
include plat/arm/board/common/board_common.mk
include plat/arm/common/arm_common.mk
diff --git a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
index 864df1ba..b370fd55 100644
--- a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
+++ b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
@@ -5,11 +5,14 @@
#
# SP_MIN source files specific to FVP platform
-BL32_SOURCES += plat/arm/board/fvp/aarch32/fvp_helpers.S \
+BL32_SOURCES += lib/utils/mem_region.c \
+ plat/arm/board/fvp/aarch32/fvp_helpers.S \
plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c \
plat/arm/board/fvp/fvp_pm.c \
plat/arm/board/fvp/fvp_topology.c \
plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c \
+ plat/arm/board/common/drivers/norflash/norflash.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c \
${FVP_CPU_LIBS} \
${FVP_GIC_SOURCES} \
${FVP_INTERCONNECT_SOURCES} \
diff --git a/plat/arm/board/fvp/tsp/tsp-fvp.mk b/plat/arm/board/fvp/tsp/tsp-fvp.mk
index 880072c9..861fe720 100644
--- a/plat/arm/board/fvp/tsp/tsp-fvp.mk
+++ b/plat/arm/board/fvp/tsp/tsp-fvp.mk
@@ -1,12 +1,13 @@
#
-# Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# TSP source files specific to FVP platform
-BL32_SOURCES += plat/arm/board/fvp/fvp_topology.c \
+BL32_SOURCES += plat/arm/board/fvp/aarch64/fvp_helpers.S \
plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c \
+ plat/arm/board/fvp/fvp_topology.c \
plat/arm/board/fvp/tsp/fvp_tsp_setup.c \
${FVP_GIC_SOURCES}
diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h
index f1714e13..e475ece5 100644
--- a/plat/arm/board/juno/include/platform_def.h
+++ b/plat/arm/board/juno/include/platform_def.h
@@ -12,6 +12,9 @@
#include <board_css_def.h>
#include <common_def.h>
#include <css_def.h>
+#if TRUSTED_BOARD_BOOT
+#include <mbedtls_config.h>
+#endif
#include <soc_css_def.h>
#include <tzc400.h>
#include <v2m_def.h>
@@ -68,11 +71,11 @@
#ifdef IMAGE_BL2
#ifdef SPD_opteed
-# define PLAT_ARM_MMAP_ENTRIES 9
-# define MAX_XLAT_TABLES 4
+# define PLAT_ARM_MMAP_ENTRIES 11
+# define MAX_XLAT_TABLES 5
#else
-# define PLAT_ARM_MMAP_ENTRIES 8
-# define MAX_XLAT_TABLES 3
+# define PLAT_ARM_MMAP_ENTRIES 10
+# define MAX_XLAT_TABLES 4
#endif
#endif
@@ -82,8 +85,8 @@
#endif
#ifdef IMAGE_BL31
-# define PLAT_ARM_MMAP_ENTRIES 5
-# define MAX_XLAT_TABLES 2
+# define PLAT_ARM_MMAP_ENTRIES 7
+# define MAX_XLAT_TABLES 3
#endif
#ifdef IMAGE_BL32
@@ -96,7 +99,7 @@
* plus a little space for growth.
*/
#if TRUSTED_BOARD_BOOT
-# define PLAT_ARM_MAX_BL1_RW_SIZE 0x9000
+# define PLAT_ARM_MAX_BL1_RW_SIZE 0xA000
#else
# define PLAT_ARM_MAX_BL1_RW_SIZE 0x6000
#endif
@@ -106,7 +109,11 @@
* little space for growth.
*/
#if TRUSTED_BOARD_BOOT
-# define PLAT_ARM_MAX_BL2_SIZE 0x18000
+#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
+# define PLAT_ARM_MAX_BL2_SIZE 0x1E000
+#else
+# define PLAT_ARM_MAX_BL2_SIZE 0x1A000
+#endif
#else
# define PLAT_ARM_MAX_BL2_SIZE 0xC000
#endif
@@ -114,8 +121,21 @@
/*
* PLAT_ARM_MAX_BL31_SIZE is calculated using the current BL31 debug size plus a
* little space for growth.
+ * SCP_BL2 image is loaded into the space BL31 -> BL1_RW_BASE.
+ * For TBB use case, PLAT_ARM_MAX_BL1_RW_SIZE has been increased and therefore
+ * PLAT_ARM_MAX_BL31_SIZE has been increased to ensure SCP_BL2 has the same
+ * space available.
*/
-#define PLAT_ARM_MAX_BL31_SIZE 0x1D000
+#define PLAT_ARM_MAX_BL31_SIZE 0x1E000
+
+#if JUNO_AARCH32_EL3_RUNTIME
+/*
+ * PLAT_ARM_MAX_BL32_SIZE is calculated for SP_MIN as the AArch32 Secure
+ * Payload. We also need to take care of SCP_BL2 size as well, as the SCP_BL2
+ * is loaded into the space BL32 -> BL1_RW_BASE
+ */
+# define PLAT_ARM_MAX_BL32_SIZE 0x1E000
+#endif
/*
* Since free SRAM space is scant, enable the ASSERTION message size
@@ -189,23 +209,27 @@
*/
#define PLAT_CSS_MAX_SCP_BL2U_SIZE 0x14000
-/*
- * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
- * terminology. On a GICv2 system or mode, the lists will be merged and treated
- * as Group 0 interrupts.
- */
-#define PLAT_ARM_G1S_IRQS CSS_G1S_IRQS, \
- ARM_G1S_IRQS, \
- JUNO_IRQ_DMA_SMMU, \
- JUNO_IRQ_HDLCD0_SMMU, \
- JUNO_IRQ_HDLCD1_SMMU, \
- JUNO_IRQ_USB_SMMU, \
- JUNO_IRQ_THIN_LINKS_SMMU, \
- JUNO_IRQ_SEC_I2C, \
- JUNO_IRQ_GPU_SMMU_1, \
- JUNO_IRQ_ETR_SMMU
-
-#define PLAT_ARM_G0_IRQS ARM_G0_IRQS
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+ CSS_G1S_IRQ_PROPS(grp), \
+ ARM_G1S_IRQ_PROPS(grp), \
+ INTR_PROP_DESC(JUNO_IRQ_DMA_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(JUNO_IRQ_HDLCD0_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(JUNO_IRQ_HDLCD1_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(JUNO_IRQ_USB_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(JUNO_IRQ_THIN_LINKS_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(JUNO_IRQ_SEC_I2C, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(JUNO_IRQ_GPU_SMMU_1, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(JUNO_IRQ_ETR_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_LEVEL)
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp) ARM_G0_IRQ_PROPS(grp)
/*
* Required ARM CSS SoC based platform porting definitions
diff --git a/plat/arm/board/juno/juno_bl2_setup.c b/plat/arm/board/juno/juno_bl2_setup.c
index 2771e0f3..cedef66c 100644
--- a/plat/arm/board/juno/juno_bl2_setup.c
+++ b/plat/arm/board/juno/juno_bl2_setup.c
@@ -29,33 +29,4 @@ int bl2_plat_handle_post_image_load(unsigned int image_id)
return err;
}
-
-#if !CSS_USE_SCMI_SDS_DRIVER
-/*
- * We need to override some of the platform functions when booting SP_MIN
- * on Juno AArch32. These needs to be done only for SCPI/BOM SCP systems as
- * in case of SDS, the structures remain in memory and doesn't need to be
- * overwritten.
- */
-
-static unsigned int scp_boot_config;
-
-void bl2_early_platform_setup(meminfo_t *mem_layout)
-{
- arm_bl2_early_platform_setup(mem_layout);
-
- /* Save SCP Boot config before it gets overwritten by SCP_BL2 loading */
- VERBOSE("BL2: Saving SCP Boot config = 0x%x\n", scp_boot_config);
- scp_boot_config = mmio_read_32(SCP_BOOT_CFG_ADDR);
-}
-
-void bl2_platform_setup(void)
-{
- arm_bl2_platform_setup();
-
- mmio_write_32(SCP_BOOT_CFG_ADDR, scp_boot_config);
- VERBOSE("BL2: Restored SCP Boot config = 0x%x\n", scp_boot_config);
-}
-#endif
-
#endif /* JUNO_AARCH32_EL3_RUNTIME */
diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk
index 79916cda..fee4391d 100644
--- a/plat/arm/board/juno/platform.mk
+++ b/plat/arm/board/juno/platform.mk
@@ -31,6 +31,19 @@ JUNO_AARCH32_EL3_RUNTIME := 0
$(eval $(call assert_boolean,JUNO_AARCH32_EL3_RUNTIME))
$(eval $(call add_define,JUNO_AARCH32_EL3_RUNTIME))
+ifeq (${JUNO_AARCH32_EL3_RUNTIME}, 1)
+# Include BL32 in FIP
+NEED_BL32 := yes
+# BL31 is not required
+override BL31_SOURCES =
+
+# The BL32 needs to be built separately invoking the AARCH32 compiler and
+# be specifed via `BL32` build option.
+ ifneq (${ARCH}, aarch32)
+ override BL32_SOURCES =
+ endif
+endif
+
ifeq (${ARCH},aarch64)
BL1_SOURCES += lib/cpus/aarch64/cortex_a53.S \
lib/cpus/aarch64/cortex_a57.S \
@@ -86,11 +99,11 @@ ENABLE_PLAT_COMPAT := 0
# Enable memory map related constants optimisation
ARM_BOARD_OPTIMISE_MEM := 1
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
+
include plat/arm/board/common/board_css.mk
include plat/arm/common/arm_common.mk
include plat/arm/soc/common/soc_css.mk
include plat/arm/css/common/css_common.mk
-ifeq (${KEY_ALG},ecdsa)
- $(error "ECDSA key algorithm is not fully supported on Juno.")
-endif
diff --git a/plat/arm/board/juno/sp_min/sp_min-juno.mk b/plat/arm/board/juno/sp_min/sp_min-juno.mk
index 336c4e7c..cd1f4976 100644
--- a/plat/arm/board/juno/sp_min/sp_min-juno.mk
+++ b/plat/arm/board/juno/sp_min/sp_min-juno.mk
@@ -8,7 +8,10 @@
BL32_SOURCES += lib/cpus/aarch32/cortex_a53.S \
lib/cpus/aarch32/cortex_a57.S \
lib/cpus/aarch32/cortex_a72.S \
+ lib/utils/mem_region.c \
+ plat/arm/board/common/drivers/norflash/norflash.c \
plat/arm/board/juno/juno_topology.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c \
plat/arm/soc/common/soc_css_security.c \
${JUNO_GIC_SOURCES} \
${JUNO_INTERCONNECT_SOURCES} \
diff --git a/plat/arm/common/aarch64/arm_ehf.c b/plat/arm/common/aarch64/arm_ehf.c
new file mode 100644
index 00000000..785b7bb5
--- /dev/null
+++ b/plat/arm/common/aarch64/arm_ehf.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <ehf.h>
+#include <platform_def.h>
+
+/*
+ * Enumeration of priority levels on ARM platforms.
+ */
+ehf_pri_desc_t arm_exceptions[] = {
+#if SDEI_SUPPORT
+ /* Critical priority SDEI */
+ EHF_PRI_DESC(ARM_PRI_BITS, PLAT_SDEI_CRITICAL_PRI),
+
+ /* Normal priority SDEI */
+ EHF_PRI_DESC(ARM_PRI_BITS, PLAT_SDEI_NORMAL_PRI),
+#endif
+};
+
+/* Plug in ARM exceptions to Exception Handling Framework. */
+EHF_REGISTER_PRIORITIES(arm_exceptions, ARRAY_SIZE(arm_exceptions), ARM_PRI_BITS);
diff --git a/plat/arm/common/aarch64/arm_helpers.S b/plat/arm/common/aarch64/arm_helpers.S
index b53e60db..9d3a1081 100644
--- a/plat/arm/common/aarch64/arm_helpers.S
+++ b/plat/arm/common/aarch64/arm_helpers.S
@@ -12,7 +12,6 @@
.globl plat_crash_console_putc
.globl plat_crash_console_flush
.globl platform_mem_init
- .globl arm_disable_spe
/* -----------------------------------------------------
@@ -88,34 +87,6 @@ func platform_mem_init
ret
endfunc platform_mem_init
- /* -----------------------------------------------------
- * void arm_disable_spe (void);
- * -----------------------------------------------------
- */
-#if ENABLE_SPE_FOR_LOWER_ELS
-func arm_disable_spe
- /* Detect if SPE is implemented */
- mrs x0, id_aa64dfr0_el1
- ubfx x0, x0, #ID_AA64DFR0_PMS_SHIFT, #ID_AA64DFR0_PMS_LENGTH
- cmp x0, #0x1
- b.ne 1f
-
- /* Drain buffered data */
- .arch armv8.2-a+profile
- psb csync
- dsb nsh
-
- /* Disable Profiling Buffer */
- mrs x0, pmblimitr_el1
- bic x0, x0, #1
- msr pmblimitr_el1, x0
- isb
- .arch armv8-a
-1:
- ret
-endfunc arm_disable_spe
-#endif
-
/*
* Need to use coherent stack when ARM Cryptocell is used to autheticate images
* since Cryptocell uses DMA to transfer data and it is not coherent with the
diff --git a/plat/arm/common/aarch64/arm_sdei.c b/plat/arm/common/aarch64/arm_sdei.c
new file mode 100644
index 00000000..514800c3
--- /dev/null
+++ b/plat/arm/common/aarch64/arm_sdei.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* SDEI configuration for ARM platforms */
+
+#include <ehf.h>
+#include <platform_def.h>
+#include <sdei.h>
+
+/* Private event mappings */
+static sdei_ev_map_t arm_private_sdei[] = {
+ /* Event 0 */
+ SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI),
+
+ /* Dynamic private events */
+ SDEI_PRIVATE_EVENT(ARM_SDEI_DP_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+ SDEI_PRIVATE_EVENT(ARM_SDEI_DP_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+ SDEI_PRIVATE_EVENT(ARM_SDEI_DP_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+};
+
+/* Shared event mappings */
+static sdei_ev_map_t arm_shared_sdei[] = {
+ /* Dynamic shared events */
+ SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+ SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+ SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+};
+
+/* Export ARM SDEI events */
+REGISTER_SDEI_MAP(arm_private_sdei, arm_shared_sdei);
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index cab6113e..5d83118a 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -193,6 +193,10 @@ void arm_bl2_platform_setup(void)
{
/* Initialize the secure environment */
plat_arm_security_setup();
+
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
+ arm_nor_psci_do_mem_protect();
+#endif
}
void bl2_platform_setup(void)
diff --git a/plat/arm/common/arm_common.c b/plat/arm/common/arm_common.c
index 420a3865..bf639737 100644
--- a/plat/arm/common/arm_common.c
+++ b/plat/arm/common/arm_common.c
@@ -11,6 +11,7 @@
#include <mmio.h>
#include <plat_arm.h>
#include <platform_def.h>
+#include <secure_partition.h>
extern const mmap_region_t plat_arm_mmap[];
@@ -79,6 +80,14 @@ void arm_setup_page_tables(uintptr_t total_base,
MT_DEVICE | MT_RW | MT_SECURE);
#endif
+#if ENABLE_SPM && defined(IMAGE_BL31)
+ /* The address of the following region is calculated by the linker. */
+ mmap_add_region(SP_IMAGE_XLAT_TABLES_START,
+ SP_IMAGE_XLAT_TABLES_START,
+ SP_IMAGE_XLAT_TABLES_SIZE,
+ MT_MEMORY | MT_RW | MT_SECURE);
+#endif
+
/* Now (re-)map the platform-specific memory regions */
mmap_add(plat_arm_get_mmap());
@@ -195,3 +204,51 @@ unsigned int plat_get_syscnt_freq2(void)
}
#endif /* ARM_SYS_CNTCTL_BASE */
+
+#if SDEI_SUPPORT
+/*
+ * Translate SDEI entry point to PA, and perform standard ARM entry point
+ * validation on it.
+ */
+int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode)
+{
+ uint64_t par, pa;
+ uint32_t scr_el3;
+
+ /* Doing Non-secure address translation requires SCR_EL3.NS set */
+ scr_el3 = read_scr_el3();
+ write_scr_el3(scr_el3 | SCR_NS_BIT);
+ isb();
+
+ assert((client_mode == MODE_EL2) || (client_mode == MODE_EL1));
+ if (client_mode == MODE_EL2) {
+ /*
+ * Translate entry point to Physical Address using the EL2
+ * translation regime.
+ */
+ ats1e2r(ep);
+ } else {
+ /*
+ * Translate entry point to Physical Address using the EL1&0
+ * translation regime, including stage 2.
+ */
+ ats12e1r(ep);
+ }
+ isb();
+ par = read_par_el1();
+
+ /* Restore original SCRL_EL3 */
+ write_scr_el3(scr_el3);
+ isb();
+
+ /* If the translation resulted in fault, return failure */
+ if ((par & PAR_F_MASK) != 0)
+ return -1;
+
+ /* Extract Physical Address from PAR */
+ pa = (par & (PAR_ADDR_MASK << PAR_ADDR_SHIFT));
+
+ /* Perform NS entry point validation on the physical address */
+ return arm_validate_ns_entrypoint(pa);
+}
+#endif
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 82f02b17..17acae52 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -9,7 +9,12 @@ ifeq (${ARCH}, aarch64)
# DRAM (if available) or the TZC secured area of DRAM.
# Trusted SRAM is the default.
- ARM_TSP_RAM_LOCATION := tsram
+ ifneq (${TRUSTED_BOARD_BOOT},0)
+ ARM_TSP_RAM_LOCATION ?= dram
+ else
+ ARM_TSP_RAM_LOCATION ?= tsram
+ endif
+
ifeq (${ARM_TSP_RAM_LOCATION}, tsram)
ARM_TSP_RAM_LOCATION_ID = ARM_TRUSTED_SRAM_ID
else ifeq (${ARM_TSP_RAM_LOCATION}, tdram)
@@ -21,14 +26,17 @@ ifeq (${ARCH}, aarch64)
endif
# Process flags
- $(eval $(call add_define,ARM_TSP_RAM_LOCATION_ID))
-
# Process ARM_BL31_IN_DRAM flag
ARM_BL31_IN_DRAM := 0
$(eval $(call assert_boolean,ARM_BL31_IN_DRAM))
$(eval $(call add_define,ARM_BL31_IN_DRAM))
+else
+ ARM_TSP_RAM_LOCATION_ID = ARM_TRUSTED_SRAM_ID
endif
+$(eval $(call add_define,ARM_TSP_RAM_LOCATION_ID))
+
+
# For the original power-state parameter format, the State-ID can be encoded
# according to the recommended encoding or zero. This flag determines which
# State-ID encoding to be parsed.
@@ -176,6 +184,14 @@ BL31_SOURCES += plat/arm/common/arm_sip_svc.c \
lib/pmf/pmf_smc.c
endif
+ifeq (${EL3_EXCEPTION_HANDLING},1)
+BL31_SOURCES += plat/arm/common/aarch64/arm_ehf.c
+endif
+
+ifeq (${SDEI_SUPPORT},1)
+BL31_SOURCES += plat/arm/common/aarch64/arm_sdei.c
+endif
+
ifneq (${TRUSTED_BOARD_BOOT},0)
# Include common TBB sources
diff --git a/plat/arm/common/arm_gicv2.c b/plat/arm/common/arm_gicv2.c
index 521fa8cd..5644c604 100644
--- a/plat/arm/common/arm_gicv2.c
+++ b/plat/arm/common/arm_gicv2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -23,16 +23,20 @@
* On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
* interrupts.
*****************************************************************************/
-static const unsigned int g0_interrupt_array[] = {
- PLAT_ARM_G1S_IRQS,
- PLAT_ARM_G0_IRQS
+static const interrupt_prop_t arm_interrupt_props[] = {
+ PLAT_ARM_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+ PLAT_ARM_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
};
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
+
static const gicv2_driver_data_t arm_gic_data = {
.gicd_base = PLAT_ARM_GICD_BASE,
.gicc_base = PLAT_ARM_GICC_BASE,
- .g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
- .g0_interrupt_array = g0_interrupt_array,
+ .interrupt_props = arm_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(arm_interrupt_props),
+ .target_masks = target_mask_array,
+ .target_masks_num = ARRAY_SIZE(target_mask_array),
};
/******************************************************************************
@@ -47,6 +51,7 @@ void plat_arm_gic_init(void)
{
gicv2_distif_init();
gicv2_pcpu_distif_init();
+ gicv2_set_pe_target_mask(plat_my_core_pos());
gicv2_cpuif_enable();
}
@@ -72,6 +77,7 @@ void plat_arm_gic_cpuif_disable(void)
void plat_arm_gic_pcpu_init(void)
{
gicv2_pcpu_distif_init();
+ gicv2_set_pe_target_mask(plat_my_core_pos());
}
/******************************************************************************
@@ -87,3 +93,21 @@ void plat_arm_gic_redistif_off(void)
{
return;
}
+
+
+/******************************************************************************
+ * ARM common helper to save & restore the GICv3 on resume from system suspend.
+ * The normal world currently takes care of saving and restoring the GICv2
+ * registers due to legacy reasons. Hence we just initialize the Distributor
+ * on resume from system suspend.
+ *****************************************************************************/
+void plat_arm_gic_save(void)
+{
+ return;
+}
+
+void plat_arm_gic_resume(void)
+{
+ gicv2_distif_init();
+ gicv2_pcpu_distif_init();
+}
diff --git a/plat/arm/common/arm_gicv3.c b/plat/arm/common/arm_gicv3.c
index c9bba095..e273b774 100644
--- a/plat/arm/common/arm_gicv3.c
+++ b/plat/arm/common/arm_gicv3.c
@@ -6,6 +6,7 @@
#include <arm_def.h>
#include <gicv3.h>
+#include <interrupt_props.h>
#include <plat_arm.h>
#include <platform.h>
#include <platform_def.h>
@@ -25,15 +26,17 @@
/* The GICv3 driver only needs to be initialized in EL3 */
static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
-/* Array of Group1 secure interrupts to be configured by the gic driver */
-static const unsigned int g1s_interrupt_array[] = {
- PLAT_ARM_G1S_IRQS
+static const interrupt_prop_t arm_interrupt_props[] = {
+ PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S),
+ PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0)
};
-/* Array of Group0 interrupts to be configured by the gic driver */
-static const unsigned int g0_interrupt_array[] = {
- PLAT_ARM_G0_IRQS
-};
+/*
+ * We save and restore the GICv3 context on system suspend. Allocate the
+ * data in the designated EL3 Secure carve-out memory
+ */
+gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram");
+gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram");
/*
* MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
@@ -58,10 +61,8 @@ static unsigned int arm_gicv3_mpidr_hash(u_register_t mpidr)
const gicv3_driver_data_t arm_gic_data = {
.gicd_base = PLAT_ARM_GICD_BASE,
.gicr_base = PLAT_ARM_GICR_BASE,
- .g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
- .g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
- .g0_interrupt_array = g0_interrupt_array,
- .g1s_interrupt_array = g1s_interrupt_array,
+ .interrupt_props = arm_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(arm_interrupt_props),
.rdistif_num = PLATFORM_CORE_COUNT,
.rdistif_base_addrs = rdistif_base_addrs,
.mpidr_to_core_pos = arm_gicv3_mpidr_hash
@@ -127,3 +128,58 @@ void plat_arm_gic_redistif_off(void)
{
gicv3_rdistif_off(plat_my_core_pos());
}
+
+/******************************************************************************
+ * ARM common helper to save & restore the GICv3 on resume from system suspend
+ *****************************************************************************/
+void plat_arm_gic_save(void)
+{
+
+ /*
+ * If an ITS is available, save its context before
+ * the Redistributor using:
+ * gicv3_its_save_disable(gits_base, &its_ctx[i])
+ * Additionnaly, an implementation-defined sequence may
+ * be required to save the whole ITS state.
+ */
+
+ /*
+ * Save the GIC Redistributors and ITS contexts before the
+ * Distributor context. As we only handle SYSTEM SUSPEND API,
+ * we only need to save the context of the CPU that is issuing
+ * the SYSTEM SUSPEND call, i.e. the current CPU.
+ */
+ gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+
+ /* Save the GIC Distributor context */
+ gicv3_distif_save(&dist_ctx);
+
+ /*
+ * From here, all the components of the GIC can be safely powered down
+ * as long as there is an alternate way to handle wakeup interrupt
+ * sources.
+ */
+}
+
+void plat_arm_gic_resume(void)
+{
+ /* Restore the GIC Distributor context */
+ gicv3_distif_init_restore(&dist_ctx);
+
+ /*
+ * Restore the GIC Redistributor and ITS contexts after the
+ * Distributor context. As we only handle SYSTEM SUSPEND API,
+ * we only need to restore the context of the CPU that issued
+ * the SYSTEM SUSPEND call.
+ */
+ gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+
+ /*
+ * If an ITS is available, restore its context after
+ * the Redistributor using:
+ * gicv3_its_restore(gits_base, &its_ctx[i])
+ * An implementation-defined sequence may be required to
+ * restore the whole ITS state. The ITS must also be
+ * re-enabled after this sequence has been executed.
+ */
+}
diff --git a/plat/arm/common/arm_gicv3_legacy.c b/plat/arm/common/arm_gicv3_legacy.c
index a014a8ee..e19799a0 100644
--- a/plat/arm/common/arm_gicv3_legacy.c
+++ b/plat/arm/common/arm_gicv3_legacy.c
@@ -84,3 +84,16 @@ void plat_arm_gic_redistif_off(void)
{
return;
}
+
+/******************************************************************************
+ * ARM common helper to save & restore the GICv3 on resume from system suspend.
+ *****************************************************************************/
+void plat_arm_gic_save(void)
+{
+ return;
+}
+
+void plat_arm_gic_resume(void)
+{
+ arm_gic_setup();
+}
diff --git a/plat/arm/common/arm_nor_psci_mem_protect.c b/plat/arm/common/arm_nor_psci_mem_protect.c
new file mode 100644
index 00000000..c5263fd8
--- /dev/null
+++ b/plat/arm/common/arm_nor_psci_mem_protect.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <mmio.h>
+#include <norflash.h>
+#include <plat_arm.h>
+#include <platform_def.h>
+#include <psci.h>
+#include <utils.h>
+
+mem_region_t arm_ram_ranges[] = {
+ {ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_SIZE},
+#ifdef AARCH64
+ {ARM_DRAM2_BASE, ARM_DRAM2_SIZE},
+#endif
+};
+
+/*******************************************************************************
+ * Function that reads the content of the memory protect variable that
+ * enables clearing of non secure memory when system boots. This variable
+ * should be stored in a secure NVRAM.
+ ******************************************************************************/
+int arm_psci_read_mem_protect(int *enabled)
+{
+ int tmp;
+
+ tmp = *(int *) PLAT_ARM_MEM_PROT_ADDR;
+ *enabled = (tmp == 1);
+ return 0;
+}
+
+/*******************************************************************************
+ * Function that writes the content of the memory protect variable that
+ * enables overwritten of non secure memory when system boots.
+ ******************************************************************************/
+int arm_nor_psci_write_mem_protect(int val)
+{
+ int enable = (val != 0);
+
+ if (nor_unlock(PLAT_ARM_MEM_PROT_ADDR) != 0) {
+ ERROR("unlocking memory protect variable\n");
+ return -1;
+ }
+
+ if (enable) {
+ /*
+ * If we want to write a value different than 0
+ * then we have to erase the full block because
+ * otherwise we cannot ensure that the value programmed
+ * into the flash is going to be the same than the value
+ * requested by the caller
+ */
+ if (nor_erase(PLAT_ARM_MEM_PROT_ADDR) != 0) {
+ ERROR("erasing block containing memory protect variable\n");
+ return -1;
+ }
+ }
+
+ if (nor_word_program(PLAT_ARM_MEM_PROT_ADDR, enable) != 0) {
+ ERROR("programming memory protection variable\n");
+ return -1;
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ * Function used for required psci operations performed when
+ * system boots
+ ******************************************************************************/
+void arm_nor_psci_do_mem_protect(void)
+{
+ int enable;
+
+ arm_psci_read_mem_protect(&enable);
+ if (!enable)
+ return;
+ INFO("PSCI: Overwritting non secure memory\n");
+ clear_mem_regions(arm_ram_ranges, ARRAY_SIZE(arm_ram_ranges));
+ arm_nor_psci_write_mem_protect(0);
+}
+
+/*******************************************************************************
+ * Function that checks if a region is protected by the memory protect
+ * mechanism
+ ******************************************************************************/
+int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length)
+{
+ return mem_region_in_array_chk(arm_ram_ranges,
+ ARRAY_SIZE(arm_ram_ranges),
+ base, length);
+}
diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c
index cc131a9f..44ac5b5d 100644
--- a/plat/arm/common/arm_pm.c
+++ b/plat/arm/common/arm_pm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,6 +11,7 @@
#include <console.h>
#include <errno.h>
#include <plat_arm.h>
+#include <platform.h>
#include <platform_def.h>
#include <psci.h>
@@ -111,7 +112,7 @@ int arm_validate_power_state(unsigned int power_state,
/*******************************************************************************
* ARM standard platform handler called to check the validity of the non secure
- * entrypoint.
+ * entrypoint. Returns 0 if the entrypoint is valid, or -1 otherwise.
******************************************************************************/
int arm_validate_ns_entrypoint(uintptr_t entrypoint)
{
@@ -120,15 +121,23 @@ int arm_validate_ns_entrypoint(uintptr_t entrypoint)
* secure DRAM.
*/
if ((entrypoint >= ARM_NS_DRAM1_BASE) && (entrypoint <
- (ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE)))
- return PSCI_E_SUCCESS;
+ (ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE))) {
+ return 0;
+ }
#ifndef AARCH32
if ((entrypoint >= ARM_DRAM2_BASE) && (entrypoint <
- (ARM_DRAM2_BASE + ARM_DRAM2_SIZE)))
- return PSCI_E_SUCCESS;
+ (ARM_DRAM2_BASE + ARM_DRAM2_SIZE))) {
+ return 0;
+ }
#endif
- return PSCI_E_INVALID_ADDRESS;
+ return -1;
+}
+
+int arm_validate_psci_entrypoint(uintptr_t entrypoint)
+{
+ return arm_validate_ns_entrypoint(entrypoint) == 0 ? PSCI_E_SUCCESS :
+ PSCI_E_INVALID_ADDRESS;
}
/******************************************************************************
@@ -140,6 +149,24 @@ const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
}
/******************************************************************************
+ * Helper function to save the platform state before a system suspend. Save the
+ * state of the system components which are not in the Always ON power domain.
+ *****************************************************************************/
+void arm_system_pwr_domain_save(void)
+{
+ /* Assert system power domain is available on the platform */
+ assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
+
+ plat_arm_gic_save();
+
+ /*
+ * All the other peripheral which are configured by ARM TF are
+ * re-initialized on resume from system suspend. Hence we
+ * don't save their state here.
+ */
+}
+
+/******************************************************************************
* Helper function to resume the platform from system suspend. Reinitialize
* the system components which are not in the Always ON power domain.
* TODO: Unify the platform setup when waking up from cold boot and system
@@ -153,12 +180,8 @@ void arm_system_pwr_domain_resume(void)
/* Assert system power domain is available on the platform */
assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
- /*
- * TODO: On GICv3 systems, figure out whether the core that wakes up
- * first from system suspend need to initialize the re-distributor
- * interface of all the other suspended cores.
- */
- plat_arm_gic_init();
+ plat_arm_gic_resume();
+
plat_arm_security_setup();
arm_configure_sys_timer();
}
diff --git a/plat/arm/common/arm_tzc400.c b/plat/arm/common/arm_tzc400.c
index 1d61c576..cf133268 100644
--- a/plat/arm/common/arm_tzc400.c
+++ b/plat/arm/common/arm_tzc400.c
@@ -1,10 +1,11 @@
/*
- * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arm_def.h>
+#include <arm_spm_def.h>
#include <debug.h>
#include <platform_def.h>
#include <tzc400.h>
@@ -40,7 +41,7 @@ void arm_tzc400_setup(void)
/* Region 1 set to cover Secure part of DRAM */
tzc400_configure_region(PLAT_ARM_TZC_FILTERS, 1,
- ARM_AP_TZC_DRAM1_BASE, ARM_AP_TZC_DRAM1_END,
+ ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END,
TZC_REGION_S_RDWR,
0);
@@ -56,9 +57,26 @@ void arm_tzc400_setup(void)
ARM_DRAM2_BASE, ARM_DRAM2_END,
ARM_TZC_NS_DRAM_S_ACCESS,
PLAT_ARM_TZC_NS_DEV_ACCESS);
-#else
- /* Allow secure access only to DRAM for EL3 payloads. */
- tzc400_configure_region0(TZC_REGION_S_RDWR, 0);
+
+#if ENABLE_SPM
+ /*
+ * Region 4 set to cover Non-Secure access to the communication buffer
+ * shared with the Secure world.
+ */
+ tzc400_configure_region(PLAT_ARM_TZC_FILTERS,
+ 4,
+ ARM_SP_IMAGE_NS_BUF_BASE,
+ (ARM_SP_IMAGE_NS_BUF_BASE +
+ ARM_SP_IMAGE_NS_BUF_SIZE) - 1,
+ TZC_REGION_S_NONE,
+ PLAT_ARM_TZC_NS_DEV_ACCESS);
+#endif
+
+#else /* if defined(EL3_PAYLOAD_BASE) */
+
+ /* Allow Secure and Non-secure access to DRAM for EL3 payloads */
+ tzc400_configure_region0(TZC_REGION_S_RDWR, PLAT_ARM_TZC_NS_DEV_ACCESS);
+
#endif /* EL3_PAYLOAD_BASE */
/*
diff --git a/plat/arm/common/arm_tzc_dmc500.c b/plat/arm/common/arm_tzc_dmc500.c
index 21ca4e8d..8e41391f 100644
--- a/plat/arm/common/arm_tzc_dmc500.c
+++ b/plat/arm/common/arm_tzc_dmc500.c
@@ -33,7 +33,7 @@ void arm_tzc_dmc500_setup(tzc_dmc500_driver_data_t *plat_driver_data)
/* Region 1 set to cover Secure part of DRAM */
tzc_dmc500_configure_region(1, ARM_AP_TZC_DRAM1_BASE,
- ARM_AP_TZC_DRAM1_END,
+ ARM_EL3_TZC_DRAM1_END,
TZC_REGION_S_RDWR,
0);
diff --git a/plat/arm/css/common/css_bl2_setup.c b/plat/arm/css/common/css_bl2_setup.c
index 9b4800e3..b4aafd46 100644
--- a/plat/arm/css/common/css_bl2_setup.c
+++ b/plat/arm/css/common/css_bl2_setup.c
@@ -49,13 +49,13 @@ int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
}
#if !CSS_USE_SCMI_SDS_DRIVER
-# ifdef EL3_PAYLOAD_BASE
+# if defined(EL3_PAYLOAD_BASE) || JUNO_AARCH32_EL3_RUNTIME
/*
* We need to override some of the platform functions when booting an EL3
- * payload. These needs to be done only for SCPI/BOM SCP systems as
- * in case of SDS, the structures remain in memory and doesn't need to be
- * overwritten.
+ * payload or SP_MIN on Juno AArch32. This needs to be done only for
+ * SCPI/BOM SCP systems as in case of SDS, the structures remain in memory and
+ * don't need to be overwritten.
*/
static unsigned int scp_boot_config;
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index e0e52004..4a615e1c 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -74,6 +74,9 @@ static void css_pwr_domain_on_finisher_common(
{
assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
+ /* Enable the gic cpu interface */
+ plat_arm_gic_cpuif_enable();
+
/*
* Perform the common cluster specific operations i.e enable coherency
* if this cluster was off.
@@ -95,13 +98,10 @@ void css_pwr_domain_on_finish(const psci_power_state_t *target_state)
/* Assert that the system power domain need not be initialized */
assert(CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_RUN);
- css_pwr_domain_on_finisher_common(target_state);
-
/* Program the gic per-cpu distributor or re-distributor interface */
plat_arm_gic_pcpu_init();
- /* Enable the gic cpu interface */
- plat_arm_gic_cpuif_enable();
+ css_pwr_domain_on_finisher_common(target_state);
}
/*******************************************************************************
@@ -144,8 +144,18 @@ void css_pwr_domain_suspend(const psci_power_state_t *target_state)
if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET)
return;
+
assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
css_power_down_common(target_state);
+
+ /* Perform system domain state saving if issuing system suspend */
+ if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) {
+ arm_system_pwr_domain_save();
+
+ /* Power off the Redistributor after having saved its context */
+ plat_arm_gic_redistif_off();
+ }
+
css_scp_suspend(target_state);
}
@@ -165,10 +175,12 @@ void css_pwr_domain_suspend_finish(
/* Perform system domain restore if woken up from system suspend */
if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
+ /*
+ * At this point, the Distributor must be powered on to be ready
+ * to have its state restored. The Redistributor will be powered
+ * on as part of gicv3_rdistif_init_restore.
+ */
arm_system_pwr_domain_resume();
- else
- /* Enable the gic cpu interface */
- plat_arm_gic_cpuif_enable();
css_pwr_domain_on_finisher_common(target_state);
}
@@ -287,8 +299,20 @@ plat_psci_ops_t plat_arm_psci_pm_ops = {
.system_off = css_system_off,
.system_reset = css_system_reset,
.validate_power_state = css_validate_power_state,
- .validate_ns_entrypoint = arm_validate_ns_entrypoint,
+ .validate_ns_entrypoint = arm_validate_psci_entrypoint,
.translate_power_state_by_mpidr = css_translate_power_state_by_mpidr,
.get_node_hw_state = css_node_hw_state,
- .get_sys_suspend_power_state = css_get_sys_suspend_power_state
+ .get_sys_suspend_power_state = css_get_sys_suspend_power_state,
+/*
+ * mem_protect is not supported in RESET_TO_BL31 and RESET_TO_SP_MIN,
+ * as that would require mapping in all of NS DRAM into BL31 or BL32.
+ */
+#if defined(PLAT_ARM_MEM_PROT_ADDR) && !RESET_TO_BL31 && !RESET_TO_SP_MIN
+ .mem_protect_chk = arm_psci_mem_protect_chk,
+ .read_mem_protect = arm_psci_read_mem_protect,
+ .write_mem_protect = arm_nor_psci_write_mem_protect,
+#endif
+#if CSS_USE_SCMI_SDS_DRIVER
+ .system_reset2 = css_system_reset2,
+#endif
};
diff --git a/plat/arm/css/drivers/scp/css_pm_scmi.c b/plat/arm/css/drivers/scp/css_pm_scmi.c
index c39bc4ba..e29cd867 100644
--- a/plat/arm/css/drivers/scp/css_pm_scmi.c
+++ b/plat/arm/css/drivers/scp/css_pm_scmi.c
@@ -259,10 +259,7 @@ int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
return HW_OFF;
}
-/*
- * Helper function to shutdown the system via SCMI.
- */
-void __dead2 css_scp_sys_shutdown(void)
+void __dead2 css_scp_system_off(int state)
{
int ret;
@@ -273,52 +270,37 @@ void __dead2 css_scp_sys_shutdown(void)
plat_arm_gic_cpuif_disable();
/*
- * Issue SCMI command for SYSTEM_SHUTDOWN. First issue a graceful
+ * Issue SCMI command. First issue a graceful
* request and if that fails force the request.
*/
ret = scmi_sys_pwr_state_set(scmi_handle,
SCMI_SYS_PWR_FORCEFUL_REQ,
- SCMI_SYS_PWR_SHUTDOWN);
+ state);
+
if (ret != SCMI_E_SUCCESS) {
- ERROR("SCMI system power domain shutdown return 0x%x unexpected\n",
- ret);
+ ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n",
+ state, ret);
panic();
}
-
wfi();
- ERROR("CSS System Shutdown: operation not handled.\n");
+ ERROR("CSS set power state: operation not handled.\n");
panic();
}
/*
+ * Helper function to shutdown the system via SCMI.
+ */
+void __dead2 css_scp_sys_shutdown(void)
+{
+ css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN);
+}
+
+/*
* Helper function to reset the system via SCMI.
*/
void __dead2 css_scp_sys_reboot(void)
{
- int ret;
-
- /*
- * Disable GIC CPU interface to prevent pending interrupt from waking
- * up the AP from WFI.
- */
- plat_arm_gic_cpuif_disable();
-
- /*
- * Issue SCMI command for SYSTEM_REBOOT. First issue a graceful
- * request and if that fails force the request.
- */
- ret = scmi_sys_pwr_state_set(scmi_handle,
- SCMI_SYS_PWR_FORCEFUL_REQ,
- SCMI_SYS_PWR_COLD_RESET);
- if (ret != SCMI_E_SUCCESS) {
- ERROR("SCMI system power domain reset return 0x%x unexpected\n",
- ret);
- panic();
- }
-
- wfi();
- ERROR("CSS System Reset: operation not handled.\n");
- panic();
+ css_scp_system_off(SCMI_SYS_PWR_COLD_RESET);
}
scmi_channel_plat_info_t plat_css_scmi_plat_info = {
@@ -376,13 +358,35 @@ const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
ops->system_off = NULL;
ops->system_reset = NULL;
ops->get_sys_suspend_power_state = NULL;
- } else if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) {
- /*
- * System power management protocol is available, but it does
- * not support SYSTEM SUSPEND.
- */
- ops->get_sys_suspend_power_state = NULL;
+ } else {
+ if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) {
+ /*
+ * System power management protocol is available, but
+ * it does not support SYSTEM SUSPEND.
+ */
+ ops->get_sys_suspend_power_state = NULL;
+ }
+ if (!(msg_attr & SCMI_SYS_PWR_WARM_RESET_SUPPORTED)) {
+ /*
+ * WARM reset is not available.
+ */
+ ops->system_reset2 = NULL;
+ }
}
return ops;
}
+
+int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie)
+{
+ if (is_vendor || (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET))
+ return PSCI_E_INVALID_PARAMS;
+
+ css_scp_system_off(SCMI_SYS_PWR_WARM_RESET);
+ /*
+ * css_scp_system_off cannot return (it is a __dead function),
+ * but css_system_reset2 has to return some value, even in
+ * this case.
+ */
+ return 0;
+}
diff --git a/plat/arm/css/drivers/scp/css_scp.h b/plat/arm/css/drivers/scp/css_scp.h
index 223e372a..1f0cf8e2 100644
--- a/plat/arm/css/drivers/scp/css_scp.h
+++ b/plat/arm/css/drivers/scp/css_scp.h
@@ -15,12 +15,14 @@
struct psci_power_state;
/* API for power management by SCP */
+int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie);
void css_scp_suspend(const struct psci_power_state *target_state);
void css_scp_off(const struct psci_power_state *target_state);
void css_scp_on(u_register_t mpidr);
int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level);
void __dead2 css_scp_sys_shutdown(void);
void __dead2 css_scp_sys_reboot(void);
+void __dead2 css_scp_system_off(int state);
/* API for SCP Boot Image transfer. Return 0 on success, -1 on error */
int css_scp_boot_image_xfer(void *image, unsigned int image_size);
diff --git a/plat/common/aarch32/platform_helpers.S b/plat/common/aarch32/platform_helpers.S
index b5f41ffb..0a0e9271 100644
--- a/plat/common/aarch32/platform_helpers.S
+++ b/plat/common/aarch32/platform_helpers.S
@@ -7,13 +7,27 @@
#include <arch.h>
#include <asm_macros.S>
+ .weak plat_report_exception
.weak plat_crash_console_init
.weak plat_crash_console_putc
.weak plat_crash_console_flush
.weak plat_reset_handler
.weak plat_disable_acp
+ .weak bl1_plat_prepare_exit
.weak platform_mem_init
+ .weak plat_error_handler
.weak plat_panic_handler
+ .weak bl2_plat_preload_setup
+ .weak plat_try_next_boot_source
+
+ /* -----------------------------------------------------
+ * Placeholder function which should be redefined by
+ * each platform.
+ * -----------------------------------------------------
+ */
+func plat_report_exception
+ bx lr
+endfunc plat_report_exception
/* -----------------------------------------------------
* Placeholder function which should be redefined by
@@ -72,6 +86,25 @@ func platform_mem_init
endfunc platform_mem_init
/* -----------------------------------------------------
+ * void bl1_plat_prepare_exit(entry_point_info_t *ep_info);
+ * Called before exiting BL1. Default: do nothing
+ * -----------------------------------------------------
+ */
+func bl1_plat_prepare_exit
+ bx lr
+endfunc bl1_plat_prepare_exit
+
+ /* -----------------------------------------------------
+ * void plat_error_handler(int err) __dead2;
+ * Endless loop by default.
+ * -----------------------------------------------------
+ */
+func plat_error_handler
+ wfi
+ b plat_error_handler
+endfunc plat_error_handler
+
+ /* -----------------------------------------------------
* void plat_panic_handler(void) __dead2;
* Endless loop by default.
* -----------------------------------------------------
@@ -79,3 +112,23 @@ endfunc platform_mem_init
func plat_panic_handler
b plat_panic_handler
endfunc plat_panic_handler
+
+
+ /* -----------------------------------------------------
+ * Placeholder function which should be redefined by
+ * each platfrom.
+ * -----------------------------------------------------
+ */
+func bl2_plat_preload_setup
+ bx lr
+endfunc bl2_plat_preload_setup
+
+ /* -----------------------------------------------------
+ * Placeholder function which should be redefined by
+ * each platfrom.
+ * -----------------------------------------------------
+ */
+func plat_try_next_boot_source
+ mov r0, #0
+ bx lr
+endfunc plat_try_next_boot_source
diff --git a/plat/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c
index 05084e19..a87e7c67 100644
--- a/plat/common/aarch64/plat_common.c
+++ b/plat/common/aarch64/plat_common.c
@@ -3,6 +3,8 @@
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+
+#include <arch_helpers.h>
#include <assert.h>
#include <console.h>
#include <platform.h>
@@ -20,6 +22,11 @@
#pragma weak plat_get_syscnt_freq2
#endif /* ERROR_DEPRECATED */
+#if SDEI_SUPPORT
+#pragma weak plat_sdei_handle_masked_trigger
+#pragma weak plat_sdei_validate_entry_point
+#endif
+
void bl31_plat_enable_mmu(uint32_t flags)
{
enable_mmu_el3(flags);
@@ -64,3 +71,22 @@ unsigned int plat_get_syscnt_freq2(void)
return (unsigned int)freq;
}
#endif /* ERROR_DEPRECATED */
+
+#if SDEI_SUPPORT
+/*
+ * Function that handles spurious SDEI interrupts while events are masked.
+ */
+void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr)
+{
+ WARN("Spurious SDEI interrupt %u on masked PE %lx\n", intr, mpidr);
+}
+
+/*
+ * Default Function to validate SDEI entry point, which returns success.
+ * Platforms may override this with their own validation mechanism.
+ */
+int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode)
+{
+ return 0;
+}
+#endif
diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S
index e60db201..797a9363 100644
--- a/plat/common/aarch64/platform_helpers.S
+++ b/plat/common/aarch64/platform_helpers.S
@@ -17,6 +17,8 @@
.weak bl1_plat_prepare_exit
.weak plat_error_handler
.weak plat_panic_handler
+ .weak bl2_plat_preload_setup
+ .weak plat_try_next_boot_source
#if !ENABLE_PLAT_COMPAT
.globl platform_get_core_pos
@@ -129,3 +131,22 @@ func plat_panic_handler
wfi
b plat_panic_handler
endfunc plat_panic_handler
+
+ /* -----------------------------------------------------
+ * Placeholder function which should be redefined by
+ * each platfrom.
+ * -----------------------------------------------------
+ */
+func bl2_plat_preload_setup
+ ret
+endfunc bl2_plat_preload_setup
+
+ /* -----------------------------------------------------
+ * Placeholder function which should be redefined by
+ * each platfrom.
+ * -----------------------------------------------------
+ */
+func plat_try_next_boot_source
+ mov x0, #0
+ ret
+endfunc plat_try_next_boot_source
diff --git a/plat/common/plat_gicv2.c b/plat/common/plat_gicv2.c
index 50a81818..38e1a61e 100644
--- a/plat/common/plat_gicv2.c
+++ b/plat/common/plat_gicv2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,7 @@
#include <gic_common.h>
#include <gicv2.h>
#include <interrupt_mgmt.h>
+#include <platform.h>
/*
* The following platform GIC functions are weakly defined. They
@@ -20,6 +21,18 @@
#pragma weak plat_ic_end_of_interrupt
#pragma weak plat_interrupt_type_to_line
+#pragma weak plat_ic_get_running_priority
+#pragma weak plat_ic_is_spi
+#pragma weak plat_ic_is_ppi
+#pragma weak plat_ic_is_sgi
+#pragma weak plat_ic_get_interrupt_active
+#pragma weak plat_ic_enable_interrupt
+#pragma weak plat_ic_disable_interrupt
+#pragma weak plat_ic_set_interrupt_priority
+#pragma weak plat_ic_set_interrupt_type
+#pragma weak plat_ic_raise_el3_sgi
+#pragma weak plat_ic_set_spi_routing
+
/*
* This function returns the highest priority pending interrupt at
* the Interrupt controller
@@ -53,8 +66,13 @@ uint32_t plat_ic_get_pending_interrupt_type(void)
id = gicv2_get_pending_interrupt_type();
/* Assume that all secure interrupts are S-EL1 interrupts */
- if (id < PENDING_G1_INTID)
+ if (id < PENDING_G1_INTID) {
+#if GICV2_G0_FOR_EL3
+ return INTR_TYPE_EL3;
+#else
return INTR_TYPE_S_EL1;
+#endif
+ }
if (id == GIC_SPURIOUS_INTERRUPT)
return INTR_TYPE_INVAL;
@@ -83,7 +101,12 @@ uint32_t plat_ic_get_interrupt_type(uint32_t id)
type = gicv2_get_interrupt_group(id);
/* Assume that all secure interrupts are S-EL1 interrupts */
- return (type) ? INTR_TYPE_NS : INTR_TYPE_S_EL1;
+ return type == GICV2_INTR_GROUP1 ? INTR_TYPE_NS :
+#if GICV2_G0_FOR_EL3
+ INTR_TYPE_EL3;
+#else
+ INTR_TYPE_S_EL1;
+#endif
}
/*
@@ -122,3 +145,145 @@ uint32_t plat_interrupt_type_to_line(uint32_t type,
return ((gicv2_is_fiq_enabled()) ? __builtin_ctz(SCR_FIQ_BIT) :
__builtin_ctz(SCR_IRQ_BIT));
}
+
+unsigned int plat_ic_get_running_priority(void)
+{
+ return gicv2_get_running_priority();
+}
+
+int plat_ic_is_spi(unsigned int id)
+{
+ return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
+}
+
+int plat_ic_is_ppi(unsigned int id)
+{
+ return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
+}
+
+int plat_ic_is_sgi(unsigned int id)
+{
+ return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
+}
+
+unsigned int plat_ic_get_interrupt_active(unsigned int id)
+{
+ return gicv2_get_interrupt_active(id);
+}
+
+void plat_ic_enable_interrupt(unsigned int id)
+{
+ gicv2_enable_interrupt(id);
+}
+
+void plat_ic_disable_interrupt(unsigned int id)
+{
+ gicv2_disable_interrupt(id);
+}
+
+void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
+{
+ gicv2_set_interrupt_priority(id, priority);
+}
+
+int plat_ic_has_interrupt_type(unsigned int type)
+{
+ switch (type) {
+#if GICV2_G0_FOR_EL3
+ case INTR_TYPE_EL3:
+#else
+ case INTR_TYPE_S_EL1:
+#endif
+ case INTR_TYPE_NS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
+{
+ int gicv2_type = 0;
+
+ /* Map canonical interrupt type to GICv2 type */
+ switch (type) {
+#if GICV2_G0_FOR_EL3
+ case INTR_TYPE_EL3:
+#else
+ case INTR_TYPE_S_EL1:
+#endif
+ gicv2_type = GICV2_INTR_GROUP0;
+ break;
+ case INTR_TYPE_NS:
+ gicv2_type = GICV2_INTR_GROUP1;
+ break;
+ default:
+ assert(0);
+ }
+
+ gicv2_set_interrupt_type(id, gicv2_type);
+}
+
+void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
+{
+#if GICV2_G0_FOR_EL3
+ int id;
+
+ /* Target must be a valid MPIDR in the system */
+ id = plat_core_pos_by_mpidr(target);
+ assert(id >= 0);
+
+ /* Verify that this is a secure SGI */
+ assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
+
+ gicv2_raise_sgi(sgi_num, id);
+#else
+ assert(0);
+#endif
+}
+
+void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
+ u_register_t mpidr)
+{
+ int proc_num = 0;
+
+ switch (routing_mode) {
+ case INTR_ROUTING_MODE_PE:
+ proc_num = plat_core_pos_by_mpidr(mpidr);
+ assert(proc_num >= 0);
+ break;
+ case INTR_ROUTING_MODE_ANY:
+ /* Bit mask selecting all 8 CPUs as candidates */
+ proc_num = -1;
+ break;
+ default:
+ assert(0);
+ }
+
+ gicv2_set_spi_routing(id, proc_num);
+}
+
+void plat_ic_set_interrupt_pending(unsigned int id)
+{
+ gicv2_set_interrupt_pending(id);
+}
+
+void plat_ic_clear_interrupt_pending(unsigned int id)
+{
+ gicv2_clear_interrupt_pending(id);
+}
+
+unsigned int plat_ic_set_priority_mask(unsigned int mask)
+{
+ return gicv2_set_pmr(mask);
+}
+
+unsigned int plat_ic_get_interrupt_id(unsigned int raw)
+{
+ unsigned int id = (raw & INT_ID_MASK);
+
+ if (id == GIC_SPURIOUS_INTERRUPT)
+ id = INTR_ID_UNAVAILABLE;
+
+ return id;
+}
diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c
index 030a1d90..030eea72 100644
--- a/plat/common/plat_gicv3.c
+++ b/plat/common/plat_gicv3.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -26,6 +26,20 @@
#pragma weak plat_ic_end_of_interrupt
#pragma weak plat_interrupt_type_to_line
+#pragma weak plat_ic_get_running_priority
+#pragma weak plat_ic_is_spi
+#pragma weak plat_ic_is_ppi
+#pragma weak plat_ic_is_sgi
+#pragma weak plat_ic_get_interrupt_active
+#pragma weak plat_ic_enable_interrupt
+#pragma weak plat_ic_disable_interrupt
+#pragma weak plat_ic_set_interrupt_priority
+#pragma weak plat_ic_set_interrupt_type
+#pragma weak plat_ic_raise_el3_sgi
+#pragma weak plat_ic_set_spi_routing
+#pragma weak plat_ic_set_interrupt_pending
+#pragma weak plat_ic_clear_interrupt_pending
+
CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
(INTR_TYPE_NS == INTR_GROUP1NS) &&
(INTR_TYPE_EL3 == INTR_GROUP0), assert_interrupt_type_mismatch);
@@ -155,6 +169,116 @@ uint32_t plat_interrupt_type_to_line(uint32_t type,
return __builtin_ctz(SCR_FIQ_BIT);
}
}
+
+unsigned int plat_ic_get_running_priority(void)
+{
+ return gicv3_get_running_priority();
+}
+
+int plat_ic_is_spi(unsigned int id)
+{
+ return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
+}
+
+int plat_ic_is_ppi(unsigned int id)
+{
+ return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
+}
+
+int plat_ic_is_sgi(unsigned int id)
+{
+ return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
+}
+
+unsigned int plat_ic_get_interrupt_active(unsigned int id)
+{
+ return gicv3_get_interrupt_active(id, plat_my_core_pos());
+}
+
+void plat_ic_enable_interrupt(unsigned int id)
+{
+ gicv3_enable_interrupt(id, plat_my_core_pos());
+}
+
+void plat_ic_disable_interrupt(unsigned int id)
+{
+ gicv3_disable_interrupt(id, plat_my_core_pos());
+}
+
+void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
+{
+ gicv3_set_interrupt_priority(id, plat_my_core_pos(), priority);
+}
+
+int plat_ic_has_interrupt_type(unsigned int type)
+{
+ assert((type == INTR_TYPE_EL3) || (type == INTR_TYPE_S_EL1) ||
+ (type == INTR_TYPE_NS));
+ return 1;
+}
+
+void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
+{
+ gicv3_set_interrupt_type(id, plat_my_core_pos(), type);
+}
+
+void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
+{
+ /* Target must be a valid MPIDR in the system */
+ assert(plat_core_pos_by_mpidr(target) >= 0);
+
+ /* Verify that this is a secure EL3 SGI */
+ assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
+
+ gicv3_raise_secure_g0_sgi(sgi_num, target);
+}
+
+void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
+ u_register_t mpidr)
+{
+ unsigned int irm = 0;
+
+ switch (routing_mode) {
+ case INTR_ROUTING_MODE_PE:
+ assert(plat_core_pos_by_mpidr(mpidr) >= 0);
+ irm = GICV3_IRM_PE;
+ break;
+ case INTR_ROUTING_MODE_ANY:
+ irm = GICV3_IRM_ANY;
+ break;
+ default:
+ assert(0);
+ }
+
+ gicv3_set_spi_routing(id, irm, mpidr);
+}
+
+void plat_ic_set_interrupt_pending(unsigned int id)
+{
+ /* Disallow setting SGIs pending */
+ assert(id >= MIN_PPI_ID);
+ gicv3_set_interrupt_pending(id, plat_my_core_pos());
+}
+
+void plat_ic_clear_interrupt_pending(unsigned int id)
+{
+ /* Disallow setting SGIs pending */
+ assert(id >= MIN_PPI_ID);
+ gicv3_clear_interrupt_pending(id, plat_my_core_pos());
+}
+
+unsigned int plat_ic_set_priority_mask(unsigned int mask)
+{
+ return gicv3_set_pmr(mask);
+}
+
+unsigned int plat_ic_get_interrupt_id(unsigned int raw)
+{
+ unsigned int id = (raw & INT_ID_MASK);
+
+ return (gicv3_is_intr_id_special_identifier(id) ?
+ INTR_ID_UNAVAILABLE : id);
+}
#endif
#ifdef IMAGE_BL32
diff --git a/plat/common/plat_psci_common.c b/plat/common/plat_psci_common.c
index 95adb051..0e818d0d 100644
--- a/plat/common/plat_psci_common.c
+++ b/plat/common/plat_psci_common.c
@@ -18,6 +18,13 @@
/* Ticks elapsed in one second by a signal of 1 MHz */
#define MHZ_TICKS_PER_SEC 1000000
+/* Maximum time-stamp value read from architectural counters */
+#ifdef AARCH32
+#define MAX_TS UINT32_MAX
+#else
+#define MAX_TS UINT64_MAX
+#endif
+
/* Following are used as ID's to capture time-stamp */
#define PSCI_STAT_ID_ENTER_LOW_PWR 0
#define PSCI_STAT_ID_EXIT_LOW_PWR 1
@@ -45,7 +52,7 @@ static u_register_t calc_stat_residency(unsigned long long pwrupts,
assert(residency_div);
if (pwrupts < pwrdnts)
- res = UINT64_MAX - pwrdnts + pwrupts;
+ res = MAX_TS - pwrdnts + pwrupts;
else
res = pwrupts - pwrdnts;
diff --git a/plat/compat/plat_compat.mk b/plat/compat/plat_compat.mk
index af885421..f1867da1 100644
--- a/plat/compat/plat_compat.mk
+++ b/plat/compat/plat_compat.mk
@@ -18,3 +18,6 @@ PLAT_BL_COMMON_SOURCES += plat/compat/aarch64/plat_helpers_compat.S
BL31_SOURCES += plat/common/plat_psci_common.c \
plat/compat/plat_pm_compat.c \
plat/compat/plat_topology_compat.c
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
diff --git a/plat/hisilicon/hikey/aarch64/hikey_common.c b/plat/hisilicon/hikey/aarch64/hikey_common.c
index 02a00ac8..d5b63cc6 100644
--- a/plat/hisilicon/hikey/aarch64/hikey_common.c
+++ b/plat/hisilicon/hikey/aarch64/hikey_common.c
@@ -59,7 +59,7 @@
* This doesn't include Trusted RAM as the 'mem_layout' argument passed to
* hikey_init_mmu_elx() will give the available subset of that,
*/
-#if IMAGE_BL1
+#ifdef IMAGE_BL1
static const mmap_region_t hikey_mmap[] = {
MAP_DEVICE,
MAP_ROM_PARAM,
@@ -68,7 +68,7 @@ static const mmap_region_t hikey_mmap[] = {
};
#endif
-#if IMAGE_BL2
+#ifdef IMAGE_BL2
static const mmap_region_t hikey_mmap[] = {
MAP_DDR,
MAP_DEVICE,
@@ -82,7 +82,7 @@ static const mmap_region_t hikey_mmap[] = {
};
#endif
-#if IMAGE_BL31
+#ifdef IMAGE_BL31
static const mmap_region_t hikey_mmap[] = {
MAP_DEVICE,
MAP_SRAM,
@@ -91,7 +91,7 @@ static const mmap_region_t hikey_mmap[] = {
};
#endif
-#if IMAGE_BL32
+#ifdef IMAGE_BL32
static const mmap_region_t hikey_mmap[] = {
MAP_DEVICE,
MAP_DDR,
diff --git a/plat/hisilicon/hikey/hikey_bl1_setup.c b/plat/hisilicon/hikey/hikey_bl1_setup.c
index f59a5451..df0ad8e0 100644
--- a/plat/hisilicon/hikey/hikey_bl1_setup.c
+++ b/plat/hisilicon/hikey/hikey_bl1_setup.c
@@ -489,6 +489,15 @@ static void hikey_mmc_pll_init(void)
reset_mmc1_clk();
}
+static void hikey_rtc_init(void)
+{
+ uint32_t data;
+
+ data = mmio_read_32(AO_SC_PERIPH_CLKEN4);
+ data |= AO_SC_PERIPH_RSTDIS4_RESET_RTC0_N;
+ mmio_write_32(AO_SC_PERIPH_CLKEN4, data);
+}
+
/*
* Function which will perform any remaining platform-specific setup that can
* occur after the MMU and data cache have been enabled.
@@ -505,6 +514,8 @@ void bl1_platform_setup(void)
hikey_pmussi_init();
hikey_hi6553_init();
+ hikey_rtc_init();
+
hikey_mmc_pll_init();
memset(&params, 0, sizeof(dw_mmc_params_t));
diff --git a/plat/hisilicon/hikey/hikey_bl31_setup.c b/plat/hisilicon/hikey/hikey_bl31_setup.c
index c592fc78..412b5935 100644
--- a/plat/hisilicon/hikey/hikey_bl31_setup.c
+++ b/plat/hisilicon/hikey/hikey_bl31_setup.c
@@ -16,6 +16,7 @@
#include <hi6220.h>
#include <hisi_ipc.h>
#include <hisi_pwrc.h>
+#include <mmio.h>
#include <platform_def.h>
#include "hikey_def.h"
@@ -152,6 +153,20 @@ void bl31_plat_arch_setup(void)
BL31_COHERENT_RAM_LIMIT);
}
+/* Initialize EDMAC controller with non-secure mode. */
+static void hikey_edma_init(void)
+{
+ int i;
+ uint32_t non_secure;
+
+ non_secure = EDMAC_SEC_CTRL_INTR_SEC | EDMAC_SEC_CTRL_GLOBAL_SEC;
+ mmio_write_32(EDMAC_SEC_CTRL, non_secure);
+
+ for (i = 0; i < EDMAC_CHANNEL_NUMS; i++) {
+ mmio_write_32(EDMAC_AXI_CONF(i), (1 << 6) | (1 << 18));
+ }
+}
+
void bl31_platform_setup(void)
{
/* Initialize the GIC driver, cpu and distributor interfaces */
@@ -160,6 +175,8 @@ void bl31_platform_setup(void)
gicv2_pcpu_distif_init();
gicv2_cpuif_enable();
+ hikey_edma_init();
+
hisi_ipc_init();
hisi_pwrc_setup();
}
diff --git a/plat/hisilicon/hikey/hikey_io_storage.c b/plat/hisilicon/hikey/hikey_io_storage.c
index 60ec42b7..57c66d50 100644
--- a/plat/hisilicon/hikey/hikey_io_storage.c
+++ b/plat/hisilicon/hikey/hikey_io_storage.c
@@ -47,7 +47,7 @@ static const io_block_spec_t emmc_fip_spec = {
static const io_block_dev_spec_t emmc_dev_spec = {
/* It's used as temp buffer in block driver. */
-#if IMAGE_BL1
+#ifdef IMAGE_BL1
.buffer = {
.offset = HIKEY_BL1_MMC_DATA_BASE,
.length = HIKEY_BL1_MMC_DATA_SIZE,
diff --git a/plat/hisilicon/hikey/include/hi6220.h b/plat/hisilicon/hikey/include/hi6220.h
index a9c408de..fe7720a6 100644
--- a/plat/hisilicon/hikey/include/hi6220.h
+++ b/plat/hisilicon/hikey/include/hi6220.h
@@ -42,6 +42,13 @@
#define DWUSB_BASE 0xF72C0000
+#define EDMAC_BASE 0xf7370000
+#define EDMAC_SEC_CTRL (EDMAC_BASE + 0x694)
+#define EDMAC_AXI_CONF(x) (EDMAC_BASE + 0x820 + (x << 6))
+#define EDMAC_SEC_CTRL_INTR_SEC (1 << 1)
+#define EDMAC_SEC_CTRL_GLOBAL_SEC (1 << 0)
+#define EDMAC_CHANNEL_NUMS 16
+
#define PMUSSI_BASE 0xF8000000
#define SP804_TIMER0_BASE 0xF8008000
diff --git a/plat/hisilicon/hikey/include/platform_def.h b/plat/hisilicon/hikey/include/platform_def.h
index 01806542..f4a3fd4e 100644
--- a/plat/hisilicon/hikey/include/platform_def.h
+++ b/plat/hisilicon/hikey/include/platform_def.h
@@ -151,15 +151,15 @@
*/
#define ADDR_SPACE_SIZE (1ull << 32)
-#if IMAGE_BL1 || IMAGE_BL32
+#if defined(IMAGE_BL1) || defined(IMAGE_BL32)
#define MAX_XLAT_TABLES 3
#endif
-#if IMAGE_BL31
+#ifdef IMAGE_BL31
#define MAX_XLAT_TABLES 4
#endif
-#if IMAGE_BL2
+#ifdef IMAGE_BL2
#if LOAD_IMAGE_V2
#ifdef SPD_opteed
#define MAX_XLAT_TABLES 4
diff --git a/plat/hisilicon/hikey/platform.mk b/plat/hisilicon/hikey/platform.mk
index 26218a40..18b5e15e 100644
--- a/plat/hisilicon/hikey/platform.mk
+++ b/plat/hisilicon/hikey/platform.mk
@@ -24,6 +24,7 @@ PLAT_PARTITION_MAX_ENTRIES := 12
PLAT_PL061_MAX_GPIOS := 160
COLD_BOOT_SINGLE_CPU := 1
PROGRAMMABLE_RESET_ADDRESS := 1
+ENABLE_SVE_FOR_NS := 0
# Process flags
$(eval $(call add_define,HIKEY_TSP_RAM_LOCATION_ID))
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_common.c b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
index bce0c96a..b1020a68 100644
--- a/plat/hisilicon/hikey960/aarch64/hikey960_common.c
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
@@ -55,7 +55,7 @@
* This doesn't include Trusted RAM as the 'mem_layout' argument passed to
* hikey960_init_mmu_elx() will give the available subset of that,
*/
-#if IMAGE_BL1
+#ifdef IMAGE_BL1
static const mmap_region_t hikey960_mmap[] = {
MAP_UFS_DATA,
MAP_BL1_RW,
@@ -65,7 +65,7 @@ static const mmap_region_t hikey960_mmap[] = {
};
#endif
-#if IMAGE_BL2
+#ifdef IMAGE_BL2
static const mmap_region_t hikey960_mmap[] = {
MAP_DDR,
MAP_DEVICE,
@@ -79,7 +79,7 @@ static const mmap_region_t hikey960_mmap[] = {
};
#endif
-#if IMAGE_BL31
+#ifdef IMAGE_BL31
static const mmap_region_t hikey960_mmap[] = {
MAP_DEVICE,
MAP_TSP_MEM,
@@ -87,7 +87,7 @@ static const mmap_region_t hikey960_mmap[] = {
};
#endif
-#if IMAGE_BL32
+#ifdef IMAGE_BL32
static const mmap_region_t hikey960_mmap[] = {
MAP_DEVICE,
MAP_DDR,
diff --git a/plat/hisilicon/hikey960/hikey960_pm.c b/plat/hisilicon/hikey960/hikey960_pm.c
index 348cdba5..078f0d81 100644
--- a/plat/hisilicon/hikey960/hikey960_pm.c
+++ b/plat/hisilicon/hikey960/hikey960_pm.c
@@ -26,6 +26,38 @@
#define SYSTEM_PWR_STATE(state) \
((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+#define PSTATE_WIDTH 4
+#define PSTATE_MASK ((1 << PSTATE_WIDTH) - 1)
+
+#define MAKE_PWRSTATE(lvl2_state, lvl1_state, lvl0_state, pwr_lvl, type) \
+ (((lvl2_state) << (PSTATE_ID_SHIFT + PSTATE_WIDTH * 2)) | \
+ ((lvl1_state) << (PSTATE_ID_SHIFT + PSTATE_WIDTH)) | \
+ ((lvl0_state) << (PSTATE_ID_SHIFT)) | \
+ ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
+ ((type) << PSTATE_TYPE_SHIFT))
+
+/*
+ * The table storing the valid idle power states. Ensure that the
+ * array entries are populated in ascending order of state-id to
+ * enable us to use binary search during power state validation.
+ * The table must be terminated by a NULL entry.
+ */
+const unsigned int hikey960_pwr_idle_states[] = {
+ /* State-id - 0x001 */
+ MAKE_PWRSTATE(PLAT_MAX_RUN_STATE, PLAT_MAX_RUN_STATE,
+ PLAT_MAX_STB_STATE, MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY),
+ /* State-id - 0x002 */
+ MAKE_PWRSTATE(PLAT_MAX_RUN_STATE, PLAT_MAX_RUN_STATE,
+ PLAT_MAX_RET_STATE, MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY),
+ /* State-id - 0x003 */
+ MAKE_PWRSTATE(PLAT_MAX_RUN_STATE, PLAT_MAX_RUN_STATE,
+ PLAT_MAX_OFF_STATE, MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN),
+ /* State-id - 0x033 */
+ MAKE_PWRSTATE(PLAT_MAX_RUN_STATE, PLAT_MAX_OFF_STATE,
+ PLAT_MAX_OFF_STATE, MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN),
+ 0,
+};
+
#define DMAC_GLB_REG_SEC 0x694
#define AXI_CONF_BASE 0x820
@@ -36,16 +68,21 @@ static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state)
unsigned long scr;
unsigned int val = 0;
- assert(cpu_state == PLAT_MAX_RET_STATE);
+ assert(cpu_state == PLAT_MAX_STB_STATE ||
+ cpu_state == PLAT_MAX_RET_STATE);
scr = read_scr_el3();
/* Enable Physical IRQ and FIQ to wake the CPU*/
write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
- set_retention_ticks(val);
+ if (cpu_state == PLAT_MAX_RET_STATE)
+ set_retention_ticks(val);
+
wfi();
- clr_retention_ticks(val);
+
+ if (cpu_state == PLAT_MAX_RET_STATE)
+ clr_retention_ticks(val);
/*
* Restore SCR to the original value, synchronisazion of
@@ -124,38 +161,34 @@ static void __dead2 hikey960_system_reset(void)
int hikey960_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
- int pstate = psci_get_pstate_type(power_state);
- int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+ unsigned int state_id;
int i;
assert(req_state);
- if (pwr_lvl > PLAT_MAX_PWR_LVL)
- return PSCI_E_INVALID_PARAMS;
-
- /* Sanity check the requested state */
- if (pstate == PSTATE_TYPE_STANDBY) {
- /*
- * It's possible to enter standby only on power level 0
- * Ignore any other power level.
- */
- if (pwr_lvl != MPIDR_AFFLVL0)
- return PSCI_E_INVALID_PARAMS;
-
- req_state->pwr_domain_state[MPIDR_AFFLVL0] =
- PLAT_MAX_RET_STATE;
- } else {
- for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
- req_state->pwr_domain_state[i] =
- PLAT_MAX_OFF_STATE;
- }
-
/*
- * We expect the 'state id' to be zero.
+ * Currently we are using a linear search for finding the matching
+ * entry in the idle power state array. This can be made a binary
+ * search if the number of entries justify the additional complexity.
*/
- if (psci_get_pstate_id(power_state))
+ for (i = 0; !!hikey960_pwr_idle_states[i]; i++) {
+ if (power_state == hikey960_pwr_idle_states[i])
+ break;
+ }
+
+ /* Return error if entry not found in the idle state array */
+ if (!hikey960_pwr_idle_states[i])
return PSCI_E_INVALID_PARAMS;
+ i = 0;
+ state_id = psci_get_pstate_id(power_state);
+
+ /* Parse the State ID and populate the state info parameter */
+ while (state_id) {
+ req_state->pwr_domain_state[i++] = state_id & PSTATE_MASK;
+ state_id >>= PSTATE_WIDTH;
+ }
+
return PSCI_E_SUCCESS;
}
diff --git a/plat/hisilicon/hikey960/include/platform_def.h b/plat/hisilicon/hikey960/include/platform_def.h
index 202952c5..2ac7f2a7 100644
--- a/plat/hisilicon/hikey960/include/platform_def.h
+++ b/plat/hisilicon/hikey960/include/platform_def.h
@@ -31,8 +31,10 @@
#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \
PLATFORM_CLUSTER_COUNT + 1)
-#define PLAT_MAX_RET_STATE 1
-#define PLAT_MAX_OFF_STATE 2
+#define PLAT_MAX_RUN_STATE 0
+#define PLAT_MAX_STB_STATE 1
+#define PLAT_MAX_RET_STATE 2
+#define PLAT_MAX_OFF_STATE 3
#define MAX_IO_DEVICES 3
#define MAX_IO_HANDLES 4
@@ -116,11 +118,11 @@
*/
#define ADDR_SPACE_SIZE (1ull << 32)
-#if IMAGE_BL1 || IMAGE_BL31 || IMAGE_BL32
+#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || defined(IMAGE_BL32)
#define MAX_XLAT_TABLES 3
#endif
-#if IMAGE_BL2
+#ifdef IMAGE_BL2
#if LOAD_IMAGE_V2
#ifdef SPD_opteed
#define MAX_XLAT_TABLES 4
diff --git a/plat/hisilicon/hikey960/platform.mk b/plat/hisilicon/hikey960/platform.mk
index da7bb825..695f0923 100644
--- a/plat/hisilicon/hikey960/platform.mk
+++ b/plat/hisilicon/hikey960/platform.mk
@@ -20,6 +20,7 @@ endif
CRASH_CONSOLE_BASE := PL011_UART6_BASE
COLD_BOOT_SINGLE_CPU := 1
PROGRAMMABLE_RESET_ADDRESS := 1
+ENABLE_SVE_FOR_NS := 0
# Process flags
$(eval $(call add_define,HIKEY960_TSP_RAM_LOCATION_ID))
diff --git a/plat/hisilicon/poplar/include/platform_def.h b/plat/hisilicon/poplar/include/platform_def.h
index 1b44dd75..b7afe820 100644
--- a/plat/hisilicon/poplar/include/platform_def.h
+++ b/plat/hisilicon/poplar/include/platform_def.h
@@ -9,6 +9,8 @@
#include <arch.h>
#include <common_def.h>
+#include <gic_common.h>
+#include <interrupt_props.h>
#include <tbbr/tbbr_img_def.h>
#include "hi3798cv200.h"
#include "poplar_layout.h" /* BL memory region sizes, etc */
@@ -69,20 +71,34 @@
#define PLAT_ARM_GICD_BASE GICD_BASE
#define PLAT_ARM_GICC_BASE GICC_BASE
-#define PLAT_ARM_G1S_IRQS HISI_IRQ_SEC_SGI_0, \
- HISI_IRQ_SEC_SGI_1, \
- HISI_IRQ_SEC_SGI_2, \
- HISI_IRQ_SEC_SGI_3, \
- HISI_IRQ_SEC_SGI_4, \
- HISI_IRQ_SEC_SGI_5, \
- HISI_IRQ_SEC_SGI_6, \
- HISI_IRQ_SEC_SGI_7, \
- HISI_IRQ_SEC_TIMER0, \
- HISI_IRQ_SEC_TIMER1, \
- HISI_IRQ_SEC_TIMER2, \
- HISI_IRQ_SEC_TIMER3, \
- HISI_IRQ_SEC_AXI
-
-#define PLAT_ARM_G0_IRQS
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_TIMER0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_TIMER1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_TIMER2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_TIMER3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(HISI_IRQ_SEC_AXI, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp)
#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/hisilicon/poplar/platform.mk b/plat/hisilicon/poplar/platform.mk
index fc75ff35..28e0d1f4 100644
--- a/plat/hisilicon/poplar/platform.mk
+++ b/plat/hisilicon/poplar/platform.mk
@@ -13,6 +13,7 @@ ENABLE_PLAT_COMPAT := 0
ERRATA_A53_855873 := 1
ERRATA_A53_835769 := 1
ERRATA_A53_843419 := 1
+ENABLE_SVE_FOR_NS := 0
ARM_GIC_ARCH := 2
$(eval $(call add_define,ARM_GIC_ARCH))
@@ -69,4 +70,3 @@ BL31_SOURCES += \
plat/hisilicon/poplar/bl31_plat_setup.c \
plat/hisilicon/poplar/plat_topology.c \
plat/hisilicon/poplar/plat_pm.c
-
diff --git a/plat/mediatek/mt6795/bl31.ld.S b/plat/mediatek/mt6795/bl31.ld.S
index 0f60a0c6..eacb1b27 100644
--- a/plat/mediatek/mt6795/bl31.ld.S
+++ b/plat/mediatek/mt6795/bl31.ld.S
@@ -5,6 +5,7 @@
*/
#include <platform_def.h>
+#include <xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
@@ -29,7 +30,7 @@ SECTIONS
*(.vectors)
} >RAM
- ASSERT(. == ALIGN(4096),
+ ASSERT(. == ALIGN(PAGE_SIZE),
"BL31_BASE address is not aligned on a page boundary.")
ro . : {
@@ -58,7 +59,7 @@ SECTIONS
* executable. No RW data from the next section must creep in.
* Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__RO_END__ = .;
} >RAM
@@ -144,7 +145,7 @@ SECTIONS
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
- coherent_ram (NOLOAD) : ALIGN(4096) {
+ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
/*
* Bakery locks are stored in coherent memory
@@ -159,7 +160,7 @@ SECTIONS
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
- . = NEXT(4096);
+ . = NEXT(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM2
#endif
diff --git a/plat/mediatek/mt6795/platform.mk b/plat/mediatek/mt6795/platform.mk
index 4ebc78e5..82300674 100644
--- a/plat/mediatek/mt6795/platform.mk
+++ b/plat/mediatek/mt6795/platform.mk
@@ -66,3 +66,5 @@ PROGRAMMABLE_RESET_ADDRESS := 1
$(eval $(call add_define,MTK_SIP_KERNEL_BOOT_ENABLE))
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
diff --git a/plat/mediatek/mt8173/include/platform_def.h b/plat/mediatek/mt8173/include/platform_def.h
index 2f0b1416..76e694bc 100644
--- a/plat/mediatek/mt8173/include/platform_def.h
+++ b/plat/mediatek/mt8173/include/platform_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,8 @@
#ifndef __PLATFORM_DEF_H__
#define __PLATFORM_DEF_H__
+#include <gic_common.h>
+#include <interrupt_props.h>
#include "mt8173_def.h"
@@ -115,15 +117,24 @@
#define PLAT_ARM_GICD_BASE BASE_GICD_BASE
#define PLAT_ARM_GICC_BASE BASE_GICC_BASE
-#define PLAT_ARM_G1S_IRQS MT_IRQ_SEC_SGI_0, \
- MT_IRQ_SEC_SGI_1, \
- MT_IRQ_SEC_SGI_2, \
- MT_IRQ_SEC_SGI_3, \
- MT_IRQ_SEC_SGI_4, \
- MT_IRQ_SEC_SGI_5, \
- MT_IRQ_SEC_SGI_6, \
- MT_IRQ_SEC_SGI_7
-
-#define PLAT_ARM_G0_IRQS
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(MT_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(MT_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(MT_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(MT_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(MT_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(MT_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(MT_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(MT_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE)
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp)
#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/mediatek/mt8173/platform.mk b/plat/mediatek/mt8173/platform.mk
index cd016451..2eef81bb 100644
--- a/plat/mediatek/mt8173/platform.mk
+++ b/plat/mediatek/mt8173/platform.mk
@@ -70,3 +70,6 @@ ERRATA_A53_855873 := 1
PROGRAMMABLE_RESET_ADDRESS := 1
$(eval $(call add_define,MTK_SIP_SET_AUTHORIZED_SECURE_REG_ENABLE))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
diff --git a/plat/nvidia/tegra/common/tegra_gic.c b/plat/nvidia/tegra/common/tegra_gic.c
index e480e772..3ace554d 100644
--- a/plat/nvidia/tegra/common/tegra_gic.c
+++ b/plat/nvidia/tegra/common/tegra_gic.c
@@ -237,10 +237,10 @@ static uint32_t tegra_gic_get_pending_interrupt_id(void)
id = gicc_read_hppir(TEGRA_GICC_BASE) & INT_ID_MASK;
- if (id < 1022UL) {
+ if (id < 1022U) {
ret = id;
- } else if (id == 1023UL) {
- ret = 0xFFFFFFFFUL; /* INTR_ID_UNAVAILABLE */
+ } else if (id == 1023U) {
+ ret = 0xFFFFFFFFU; /* INTR_ID_UNAVAILABLE */
} else {
/*
* Find out which non-secure interrupt it is under the assumption that
diff --git a/plat/nvidia/tegra/platform.mk b/plat/nvidia/tegra/platform.mk
index 9a9e79e2..ad60620a 100644
--- a/plat/nvidia/tegra/platform.mk
+++ b/plat/nvidia/tegra/platform.mk
@@ -29,6 +29,9 @@ SEPARATE_CODE_AND_RODATA := 1
# do not use coherent memory
USE_COHERENT_MEM := 0
+# do not enable SVE
+ENABLE_SVE_FOR_NS := 0
+
include plat/nvidia/tegra/common/tegra_common.mk
include ${SOC_DIR}/platform_${TARGET_SOC}.mk
diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c
index d34f7e28..7eb6c6c8 100644
--- a/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c
+++ b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c
@@ -435,7 +435,7 @@ uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data)
ret = ari_request_wait(ari_base, 0U, TEGRA_ARI_MCA,
(uint32_t)mca_arg_data,
- (uint32_t)(mca_arg_data >> 32UL));
+ (uint32_t)(mca_arg_data >> 32U));
if (ret == 0) {
resp_lo = ari_get_response_low(ari_base);
resp_hi = ari_get_response_high(ari_base);
@@ -450,7 +450,7 @@ uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data)
if (data != NULL) {
resp_lo = ari_get_request_low(ari_base);
resp_hi = ari_get_request_high(ari_base);
- *data = ((uint64_t)resp_hi << 32UL) |
+ *data = ((uint64_t)resp_hi << 32U) |
(uint64_t)resp_lo;
}
}
@@ -513,7 +513,7 @@ int32_t ari_read_write_uncore_perfmon(uint32_t ari_base, uint64_t req,
* to the uncore perfmon registers
*/
val = (req_cmd == UNCORE_PERFMON_CMD_WRITE) ?
- (uint32_t)*data : 0UL;
+ (uint32_t)*data : 0U;
ret = ari_request_wait(ari_base, 0U, TEGRA_ARI_PERFMON, val,
(uint32_t)req);
diff --git a/plat/qemu/aarch64/plat_helpers.S b/plat/qemu/aarch64/plat_helpers.S
index f287e5b5..ed553795 100644
--- a/plat/qemu/aarch64/plat_helpers.S
+++ b/plat/qemu/aarch64/plat_helpers.S
@@ -63,6 +63,7 @@ endfunc plat_is_my_cpu_primary
func plat_secondary_cold_boot_setup
/* Calculate address of our hold entry */
bl plat_my_core_pos
+ lsl x0, x0, #PLAT_QEMU_HOLD_ENTRY_SHIFT
mov_imm x2, PLAT_QEMU_HOLD_BASE
/* Wait until we have a go */
diff --git a/plat/qemu/include/platform_def.h b/plat/qemu/include/platform_def.h
index e91a7db9..0ae28ea6 100644
--- a/plat/qemu/include/platform_def.h
+++ b/plat/qemu/include/platform_def.h
@@ -73,9 +73,8 @@
#define SEC_DRAM_BASE 0x0e100000
#define SEC_DRAM_SIZE 0x00f00000
-/* Load pageable part of OP-TEE at end of secure DRAM */
-#define QEMU_OPTEE_PAGEABLE_LOAD_BASE (SEC_DRAM_BASE + SEC_DRAM_SIZE - \
- QEMU_OPTEE_PAGEABLE_LOAD_SIZE)
+/* Load pageable part of OP-TEE 2MB above secure DRAM base */
+#define QEMU_OPTEE_PAGEABLE_LOAD_BASE (SEC_DRAM_BASE + 0x00200000)
#define QEMU_OPTEE_PAGEABLE_LOAD_SIZE 0x00400000
/*
@@ -90,7 +89,8 @@
#define PLAT_QEMU_HOLD_BASE (PLAT_QEMU_TRUSTED_MAILBOX_BASE + 8)
#define PLAT_QEMU_HOLD_SIZE (PLATFORM_CORE_COUNT * \
PLAT_QEMU_HOLD_ENTRY_SIZE)
-#define PLAT_QEMU_HOLD_ENTRY_SIZE 8
+#define PLAT_QEMU_HOLD_ENTRY_SHIFT 3
+#define PLAT_QEMU_HOLD_ENTRY_SIZE (1 << PLAT_QEMU_HOLD_ENTRY_SHIFT)
#define PLAT_QEMU_HOLD_STATE_WAIT 0
#define PLAT_QEMU_HOLD_STATE_GO 1
diff --git a/plat/qemu/platform.mk b/plat/qemu/platform.mk
index ed197a1d..43ab846b 100644
--- a/plat/qemu/platform.mk
+++ b/plat/qemu/platform.mk
@@ -13,6 +13,7 @@ ifeq ($(NEED_BL32),yes)
$(eval $(call add_define,QEMU_LOAD_BL32))
endif
+PLAT_PATH := plat/qemu/
PLAT_INCLUDES := -Iinclude/plat/arm/common/ \
-Iinclude/plat/arm/common/aarch64/ \
-Iplat/qemu/include \
@@ -36,6 +37,51 @@ include lib/xlat_tables_v2/xlat_tables.mk
PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS}
endif
+ifneq (${TRUSTED_BOARD_BOOT},0)
+
+ include drivers/auth/mbedtls/mbedtls_crypto.mk
+ include drivers/auth/mbedtls/mbedtls_x509.mk
+
+ USE_TBBR_DEFS := 1
+
+ AUTH_SOURCES := drivers/auth/auth_mod.c \
+ drivers/auth/crypto_mod.c \
+ drivers/auth/img_parser_mod.c \
+ drivers/auth/tbbr/tbbr_cot.c
+
+ PLAT_INCLUDES += -Iinclude/bl1/tbbr
+
+ BL1_SOURCES += ${AUTH_SOURCES} \
+ bl1/tbbr/tbbr_img_desc.c \
+ plat/common/tbbr/plat_tbbr.c \
+ plat/qemu/qemu_trusted_boot.c \
+ $(PLAT_PATH)/qemu_rotpk.S
+
+ BL2_SOURCES += ${AUTH_SOURCES} \
+ plat/common/tbbr/plat_tbbr.c \
+ plat/qemu/qemu_trusted_boot.c \
+ $(PLAT_PATH)/qemu_rotpk.S
+
+ ROT_KEY = $(BUILD_PLAT)/rot_key.pem
+ ROTPK_HASH = $(BUILD_PLAT)/rotpk_sha256.bin
+
+ $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+
+ $(BUILD_PLAT)/bl1/qemu_rotpk.o: $(ROTPK_HASH)
+ $(BUILD_PLAT)/bl2/qemu_rotpk.o: $(ROTPK_HASH)
+
+ certificates: $(ROT_KEY)
+
+ $(ROT_KEY):
+ @echo " OPENSSL $@"
+ $(Q)openssl genrsa 2048 > $@ 2>/dev/null
+
+ $(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
+
BL1_SOURCES += drivers/io/io_semihosting.c \
drivers/io/io_storage.c \
drivers/io/io_fip.c \
@@ -107,3 +153,6 @@ endif
# Process flags
$(eval $(call add_define,BL32_RAM_LOCATION_ID))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
diff --git a/plat/qemu/qemu_bl31_setup.c b/plat/qemu/qemu_bl31_setup.c
index 5bf45895..f79a8854 100644
--- a/plat/qemu/qemu_bl31_setup.c
+++ b/plat/qemu/qemu_bl31_setup.c
@@ -7,6 +7,7 @@
#include <assert.h>
#include <bl_common.h>
#include <console.h>
+#include <gic_common.h>
#include <gicv2.h>
#include <platform_def.h>
#include "qemu_private.h"
@@ -112,22 +113,40 @@ void bl31_plat_arch_setup(void)
BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END);
}
-static const unsigned int irq_sec_array[] = {
- QEMU_IRQ_SEC_SGI_0,
- QEMU_IRQ_SEC_SGI_1,
- QEMU_IRQ_SEC_SGI_2,
- QEMU_IRQ_SEC_SGI_3,
- QEMU_IRQ_SEC_SGI_4,
- QEMU_IRQ_SEC_SGI_5,
- QEMU_IRQ_SEC_SGI_6,
- QEMU_IRQ_SEC_SGI_7,
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+#define PLATFORM_G1S_PROPS(grp) \
+ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, \
+ grp, GIC_INTR_CFG_EDGE)
+
+#define PLATFORM_G0_PROPS(grp)
+
+static const interrupt_prop_t qemu_interrupt_props[] = {
+ PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0),
+ PLATFORM_G0_PROPS(GICV2_INTR_GROUP0)
};
static const struct gicv2_driver_data plat_gicv2_driver_data = {
.gicd_base = GICD_BASE,
.gicc_base = GICC_BASE,
- .g0_interrupt_num = ARRAY_SIZE(irq_sec_array),
- .g0_interrupt_array = irq_sec_array,
+ .interrupt_props = qemu_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(qemu_interrupt_props),
};
void bl31_platform_setup(void)
diff --git a/plat/qemu/qemu_io_storage.c b/plat/qemu/qemu_io_storage.c
index e0f7e8ab..1918f21d 100644
--- a/plat/qemu/qemu_io_storage.c
+++ b/plat/qemu/qemu_io_storage.c
@@ -26,14 +26,14 @@
#define BL33_IMAGE_NAME "bl33.bin"
#if TRUSTED_BOARD_BOOT
-#define BL2_CERT_NAME "bl2.crt"
+#define TRUSTED_BOOT_FW_CERT_NAME "tb_fw.crt"
#define TRUSTED_KEY_CERT_NAME "trusted_key.crt"
-#define BL31_KEY_CERT_NAME "bl31_key.crt"
-#define BL32_KEY_CERT_NAME "bl32_key.crt"
-#define BL33_KEY_CERT_NAME "bl33_key.crt"
-#define BL31_CERT_NAME "bl31.crt"
-#define BL32_CERT_NAME "bl32.crt"
-#define BL33_CERT_NAME "bl33.crt"
+#define SOC_FW_KEY_CERT_NAME "soc_fw_key.crt"
+#define TOS_FW_KEY_CERT_NAME "tos_fw_key.crt"
+#define NT_FW_KEY_CERT_NAME "nt_fw_key.crt"
+#define SOC_FW_CONTENT_CERT_NAME "soc_fw_content.crt"
+#define TOS_FW_CONTENT_CERT_NAME "tos_fw_content.crt"
+#define NT_FW_CONTENT_CERT_NAME "nt_fw_content.crt"
#endif /* TRUSTED_BOARD_BOOT */
@@ -76,36 +76,36 @@ static const io_uuid_spec_t bl33_uuid_spec = {
};
#if TRUSTED_BOARD_BOOT
-static const io_uuid_spec_t bl2_cert_uuid_spec = {
- .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2_CERT,
+static const io_uuid_spec_t tb_fw_cert_uuid_spec = {
+ .uuid = UUID_TRUSTED_BOOT_FW_CERT,
};
static const io_uuid_spec_t trusted_key_cert_uuid_spec = {
.uuid = UUID_TRUSTED_KEY_CERT,
};
-static const io_uuid_spec_t bl31_key_cert_uuid_spec = {
- .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31_KEY_CERT,
+static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = {
+ .uuid = UUID_SOC_FW_KEY_CERT,
};
-static const io_uuid_spec_t bl32_key_cert_uuid_spec = {
- .uuid = UUID_SECURE_PAYLOAD_BL32_KEY_CERT,
+static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = {
+ .uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
};
-static const io_uuid_spec_t bl33_key_cert_uuid_spec = {
- .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33_KEY_CERT,
+static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = {
+ .uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
};
-static const io_uuid_spec_t bl31_cert_uuid_spec = {
- .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31_CERT,
+static const io_uuid_spec_t soc_fw_cert_uuid_spec = {
+ .uuid = UUID_SOC_FW_CONTENT_CERT,
};
-static const io_uuid_spec_t bl32_cert_uuid_spec = {
- .uuid = UUID_SECURE_PAYLOAD_BL32_CERT,
+static const io_uuid_spec_t tos_fw_cert_uuid_spec = {
+ .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
};
-static const io_uuid_spec_t bl33_cert_uuid_spec = {
- .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33_CERT,
+static const io_uuid_spec_t nt_fw_cert_uuid_spec = {
+ .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
};
#endif /* TRUSTED_BOARD_BOOT */
@@ -135,36 +135,36 @@ static const io_file_spec_t sh_file_spec[] = {
.mode = FOPEN_MODE_RB
},
#if TRUSTED_BOARD_BOOT
- [BL2_CERT_ID] = {
- .path = BL2_CERT_NAME,
+ [TRUSTED_BOOT_FW_CERT_ID] = {
+ .path = TRUSTED_BOOT_FW_CERT_NAME,
.mode = FOPEN_MODE_RB
},
[TRUSTED_KEY_CERT_ID] = {
.path = TRUSTED_KEY_CERT_NAME,
.mode = FOPEN_MODE_RB
},
- [BL31_KEY_CERT_ID] = {
- .path = BL31_KEY_CERT_NAME,
+ [SOC_FW_KEY_CERT_ID] = {
+ .path = SOC_FW_KEY_CERT_NAME,
.mode = FOPEN_MODE_RB
},
- [BL32_KEY_CERT_ID] = {
- .path = BL32_KEY_CERT_NAME,
+ [TRUSTED_OS_FW_KEY_CERT_ID] = {
+ .path = TOS_FW_KEY_CERT_NAME,
.mode = FOPEN_MODE_RB
},
- [BL33_KEY_CERT_ID] = {
- .path = BL33_KEY_CERT_NAME,
+ [NON_TRUSTED_FW_KEY_CERT_ID] = {
+ .path = NT_FW_KEY_CERT_NAME,
.mode = FOPEN_MODE_RB
},
- [BL31_CERT_ID] = {
- .path = BL31_CERT_NAME,
+ [SOC_FW_CONTENT_CERT_ID] = {
+ .path = SOC_FW_CONTENT_CERT_NAME,
.mode = FOPEN_MODE_RB
},
- [BL32_CERT_ID] = {
- .path = BL32_CERT_NAME,
+ [TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+ .path = TOS_FW_CONTENT_CERT_NAME,
.mode = FOPEN_MODE_RB
},
- [BL33_CERT_ID] = {
- .path = BL33_CERT_NAME,
+ [NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+ .path = NT_FW_CONTENT_CERT_NAME,
.mode = FOPEN_MODE_RB
},
#endif /* TRUSTED_BOARD_BOOT */
@@ -219,9 +219,9 @@ static const struct plat_io_policy policies[] = {
open_fip
},
#if TRUSTED_BOARD_BOOT
- [BL2_CERT_ID] = {
+ [TRUSTED_BOOT_FW_CERT_ID] = {
&fip_dev_handle,
- (uintptr_t)&bl2_cert_uuid_spec,
+ (uintptr_t)&tb_fw_cert_uuid_spec,
open_fip
},
[TRUSTED_KEY_CERT_ID] = {
@@ -229,34 +229,34 @@ static const struct plat_io_policy policies[] = {
(uintptr_t)&trusted_key_cert_uuid_spec,
open_fip
},
- [BL31_KEY_CERT_ID] = {
+ [SOC_FW_KEY_CERT_ID] = {
&fip_dev_handle,
- (uintptr_t)&bl31_key_cert_uuid_spec,
+ (uintptr_t)&soc_fw_key_cert_uuid_spec,
open_fip
},
- [BL32_KEY_CERT_ID] = {
+ [TRUSTED_OS_FW_KEY_CERT_ID] = {
&fip_dev_handle,
- (uintptr_t)&bl32_key_cert_uuid_spec,
+ (uintptr_t)&tos_fw_key_cert_uuid_spec,
open_fip
},
- [BL33_KEY_CERT_ID] = {
+ [NON_TRUSTED_FW_KEY_CERT_ID] = {
&fip_dev_handle,
- (uintptr_t)&bl33_key_cert_uuid_spec,
+ (uintptr_t)&nt_fw_key_cert_uuid_spec,
open_fip
},
- [BL31_CERT_ID] = {
+ [SOC_FW_CONTENT_CERT_ID] = {
&fip_dev_handle,
- (uintptr_t)&bl31_cert_uuid_spec,
+ (uintptr_t)&soc_fw_cert_uuid_spec,
open_fip
},
- [BL32_CERT_ID] = {
+ [TRUSTED_OS_FW_CONTENT_CERT_ID] = {
&fip_dev_handle,
- (uintptr_t)&bl32_cert_uuid_spec,
+ (uintptr_t)&tos_fw_cert_uuid_spec,
open_fip
},
- [BL33_CERT_ID] = {
+ [NON_TRUSTED_FW_CONTENT_CERT_ID] = {
&fip_dev_handle,
- (uintptr_t)&bl33_cert_uuid_spec,
+ (uintptr_t)&nt_fw_cert_uuid_spec,
open_fip
},
#endif /* TRUSTED_BOARD_BOOT */
diff --git a/plat/qemu/qemu_rotpk.S b/plat/qemu/qemu_rotpk.S
new file mode 100644
index 00000000..5d1b83f4
--- /dev/null
+++ b/plat/qemu/qemu_rotpk.S
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+ .global qemu_rotpk_hash
+ .global qemu_rotpk_hash_end
+qemu_rotpk_hash:
+ /* DER header */
+ .byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+ .byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+ /* SHA256 */
+ .incbin ROTPK_HASH
+qemu_rotpk_hash_end:
diff --git a/plat/qemu/qemu_trusted_boot.c b/plat/qemu/qemu_trusted_boot.c
new file mode 100644
index 00000000..7d8fed20
--- /dev/null
+++ b/plat/qemu/qemu_trusted_boot.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform.h>
+
+extern char qemu_rotpk_hash[], qemu_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ *key_ptr = qemu_rotpk_hash;
+ *key_len = qemu_rotpk_hash_end - qemu_rotpk_hash;
+ *flags = ROTPK_IS_HASH;
+
+ return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+ *nv_ctr = 0;
+
+ return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+ return 1;
+}
diff --git a/plat/rockchip/rk3328/include/platform_def.h b/plat/rockchip/rk3328/include/platform_def.h
index 7304dcfa..39d3c21e 100644
--- a/plat/rockchip/rk3328/include/platform_def.h
+++ b/plat/rockchip/rk3328/include/platform_def.h
@@ -26,13 +26,13 @@
/* Size of cacheable stacks */
#if DEBUG_XLAT_TABLE
#define PLATFORM_STACK_SIZE 0x800
-#elif IMAGE_BL1
+#elif defined(IMAGE_BL1)
#define PLATFORM_STACK_SIZE 0x440
-#elif IMAGE_BL2
+#elif defined(IMAGE_BL2)
#define PLATFORM_STACK_SIZE 0x400
-#elif IMAGE_BL31
+#elif defined(IMAGE_BL31)
#define PLATFORM_STACK_SIZE 0x800
-#elif IMAGE_BL32
+#elif defined(IMAGE_BL32)
#define PLATFORM_STACK_SIZE 0x440
#endif
diff --git a/plat/rockchip/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk
index 8863fb4f..5de4680e 100644
--- a/plat/rockchip/rk3328/platform.mk
+++ b/plat/rockchip/rk3328/platform.mk
@@ -48,7 +48,10 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \
${RK_PLAT_SOC}/drivers/pmu/pmu.c \
${RK_PLAT_SOC}/drivers/soc/soc.c
-ENABLE_PLAT_COMPAT := 0
+ENABLE_PLAT_COMPAT := 0
$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
$(eval $(call add_define,PLAT_SKIP_OPTEE_S_EL1_INT_REGISTER))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
diff --git a/plat/rockchip/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk
index f6960cf4..d3c6eeff 100644
--- a/plat/rockchip/rk3368/platform.mk
+++ b/plat/rockchip/rk3368/platform.mk
@@ -48,6 +48,9 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \
${RK_PLAT_SOC}/drivers/soc/soc.c \
${RK_PLAT_SOC}/drivers/ddr/ddr_rk3368.c \
-ENABLE_PLAT_COMPAT := 0
+ENABLE_PLAT_COMPAT := 0
$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
diff --git a/plat/rockchip/rk3399/include/plat.ld.S b/plat/rockchip/rk3399/include/plat.ld.S
index c42d9a9a..85f4dc33 100644
--- a/plat/rockchip/rk3399/include/plat.ld.S
+++ b/plat/rockchip/rk3399/include/plat.ld.S
@@ -6,6 +6,8 @@
#ifndef __ROCKCHIP_PLAT_LD_S__
#define __ROCKCHIP_PLAT_LD_S__
+#include <xlat_tables_defs.h>
+
MEMORY {
SRAM (rwx): ORIGIN = SRAM_BASE, LENGTH = SRAM_SIZE
PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
@@ -14,7 +16,7 @@ MEMORY {
SECTIONS
{
. = SRAM_BASE;
- ASSERT(. == ALIGN(4096),
+ ASSERT(. == ALIGN(PAGE_SIZE),
"SRAM_BASE address is not aligned on a page boundary.")
/*
@@ -27,40 +29,40 @@ SECTIONS
* | sram data
* ----------------
*/
- .incbin_sram : ALIGN(4096) {
+ .incbin_sram : ALIGN(PAGE_SIZE) {
__sram_incbin_start = .;
*(.sram.incbin)
__sram_incbin_real_end = .;
- . = ALIGN(4096);
+ . = ALIGN(PAGE_SIZE);
__sram_incbin_end = .;
} >SRAM
ASSERT((__sram_incbin_real_end - __sram_incbin_start) <=
SRAM_BIN_LIMIT, ".incbin_sram has exceeded its limit")
- .text_sram : ALIGN(4096) {
+ .text_sram : ALIGN(PAGE_SIZE) {
__bl31_sram_text_start = .;
*(.sram.text)
*(.sram.rodata)
__bl31_sram_text_real_end = .;
- . = ALIGN(4096);
+ . = ALIGN(PAGE_SIZE);
__bl31_sram_text_end = .;
} >SRAM
ASSERT((__bl31_sram_text_real_end - __bl31_sram_text_start) <=
SRAM_TEXT_LIMIT, ".text_sram has exceeded its limit")
- .data_sram : ALIGN(4096) {
+ .data_sram : ALIGN(PAGE_SIZE) {
__bl31_sram_data_start = .;
*(.sram.data)
__bl31_sram_data_real_end = .;
- . = ALIGN(4096);
+ . = ALIGN(PAGE_SIZE);
__bl31_sram_data_end = .;
} >SRAM
ASSERT((__bl31_sram_data_real_end - __bl31_sram_data_start) <=
SRAM_DATA_LIMIT, ".data_sram has exceeded its limit")
- .stack_sram : ALIGN(4096) {
+ .stack_sram : ALIGN(PAGE_SIZE) {
__bl31_sram_stack_start = .;
- . += 4096;
+ . += PAGE_SIZE;
__bl31_sram_stack_end = .;
} >SRAM
diff --git a/plat/rockchip/rk3399/plat_sip_calls.c b/plat/rockchip/rk3399/plat_sip_calls.c
index 074dc193..2fbda673 100644
--- a/plat/rockchip/rk3399/plat_sip_calls.c
+++ b/plat/rockchip/rk3399/plat_sip_calls.c
@@ -11,6 +11,7 @@
#include <plat_sip_calls.h>
#include <rockchip_sip_svc.h>
#include <runtime_svc.h>
+#include <stdint.h>
#define RK_SIP_DDR_CFG 0x82000008
#define DRAM_INIT 0x00
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
index 85cca1b6..33b9723d 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -88,7 +88,10 @@ ${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c: $(RK3399M0FW)
${BUILD_PLAT}/bl31/cdn_dp.o: CCACHE_EXTRAFILES=$(HDCPFW)
${RK_PLAT_SOC}/drivers/dp/cdn_dp.c: $(HDCPFW)
-$(eval $(call MAKE_PREREQ_DIR,${BUILD_M0},))
+$(eval $(call MAKE_PREREQ_DIR,${BUILD_M0},${BUILD_PLAT}))
.PHONY: $(RK3399M0FW)
$(RK3399M0FW): | ${BUILD_M0}
$(MAKE) -C ${RK_PLAT_SOC}/drivers/m0 BUILD=$(abspath ${BUILD_PLAT}/m0)
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
diff --git a/plat/rpi3/aarch64/plat_helpers.S b/plat/rpi3/aarch64/plat_helpers.S
new file mode 100644
index 00000000..76a542f5
--- /dev/null
+++ b/plat/rpi3/aarch64/plat_helpers.S
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+#include "../rpi3_hw.h"
+
+ .globl plat_crash_console_flush
+ .globl plat_crash_console_init
+ .globl plat_crash_console_putc
+ .globl platform_mem_init
+ .globl plat_get_my_entrypoint
+ .globl plat_is_my_cpu_primary
+ .globl plat_my_core_pos
+ .globl plat_reset_handler
+ .globl plat_rpi3_calc_core_pos
+ .globl plat_secondary_cold_boot_setup
+
+ /* -----------------------------------------------------
+ * unsigned int plat_my_core_pos(void)
+ *
+ * This function uses the plat_rpi3_calc_core_pos()
+ * definition to get the index of the calling CPU.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b plat_rpi3_calc_core_pos
+endfunc plat_my_core_pos
+
+ /* -----------------------------------------------------
+ * unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr);
+ *
+ * CorePos = (ClusterId * 4) + CoreId
+ * -----------------------------------------------------
+ */
+func plat_rpi3_calc_core_pos
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ add x0, x1, x0, LSR #6
+ ret
+endfunc plat_rpi3_calc_core_pos
+
+ /* -----------------------------------------------------
+ * unsigned int plat_is_my_cpu_primary (void);
+ *
+ * Find out whether the current cpu is the primary
+ * cpu.
+ * -----------------------------------------------------
+ */
+func plat_is_my_cpu_primary
+ mrs x0, mpidr_el1
+ and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+ cmp x0, #RPI3_PRIMARY_CPU
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary
+
+ /* -----------------------------------------------------
+ * void plat_secondary_cold_boot_setup (void);
+ *
+ * This function performs any platform specific actions
+ * needed for a secondary cpu after a cold reset e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ * -----------------------------------------------------
+ */
+func plat_secondary_cold_boot_setup
+ /* Calculate address of our hold entry */
+ bl plat_my_core_pos
+ lsl x0, x0, #3
+ mov_imm x2, PLAT_RPI3_TM_HOLD_BASE
+ add x0, x0, x2
+
+ /*
+ * This code runs way before requesting the warmboot of this core,
+ * so it is possible to clear the mailbox before getting a request
+ * to boot.
+ */
+ mov x1, PLAT_RPI3_TM_HOLD_STATE_WAIT
+ str x1,[x0]
+
+ /* Wait until we have a go */
+poll_mailbox:
+ wfe
+ ldr x1, [x0]
+ cmp x1, PLAT_RPI3_TM_HOLD_STATE_GO
+ bne poll_mailbox
+
+ /* Jump to the provided entrypoint */
+ mov_imm x0, PLAT_RPI3_TM_ENTRYPOINT
+ ldr x1, [x0]
+ br x1
+endfunc plat_secondary_cold_boot_setup
+
+ /* ---------------------------------------------------------------------
+ * uintptr_t plat_get_my_entrypoint (void);
+ *
+ * Main job of this routine is to distinguish between a cold and a warm
+ * boot.
+ *
+ * This functions returns:
+ * - 0 for a cold boot.
+ * - Any other value for a warm boot.
+ * ---------------------------------------------------------------------
+ */
+func plat_get_my_entrypoint
+ /* TODO: support warm boot */
+ mov x0, #0
+ ret
+endfunc plat_get_my_entrypoint
+
+ /* ---------------------------------------------
+ * void platform_mem_init (void);
+ *
+ * No need to carry out any memory initialization.
+ * ---------------------------------------------
+ */
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+ /* ---------------------------------------------
+ * int plat_crash_console_init(void)
+ * Function to initialize the crash console
+ * without a C Runtime to print crash report.
+ * Clobber list : x0 - x3
+ * ---------------------------------------------
+ */
+func plat_crash_console_init
+ mov_imm x0, PLAT_RPI3_UART_BASE
+ mov_imm x1, PLAT_RPI3_UART_CLK_IN_HZ
+ mov_imm x2, PLAT_RPI3_UART_BAUDRATE
+ b console_core_init
+endfunc plat_crash_console_init
+
+ /* ---------------------------------------------
+ * int plat_crash_console_putc(int c)
+ * Function to print a character on the crash
+ * console without a C Runtime.
+ * Clobber list : x1, x2
+ * ---------------------------------------------
+ */
+func plat_crash_console_putc
+ mov_imm x1, PLAT_RPI3_UART_BASE
+ b console_core_putc
+endfunc plat_crash_console_putc
+
+ /* ---------------------------------------------
+ * int plat_crash_console_flush()
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : return -1 on error else return 0.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func plat_crash_console_flush
+ mov_imm x1, PLAT_RPI3_UART_BASE
+ b console_core_flush
+endfunc plat_crash_console_flush
+
+ /* ---------------------------------------------
+ * void plat_reset_handler(void);
+ * ---------------------------------------------
+ */
+func plat_reset_handler
+ /* use the 19.2 MHz clock for the architected timer */
+ mov x0, #RPI3_INTC_BASE_ADDRESS
+ mov w1, #0x80000000
+ str wzr, [x0, #RPI3_INTC_CONTROL_OFFSET]
+ str w1, [x0, #RPI3_INTC_PRESCALER_OFFSET]
+
+ /* wire mailbox 3 to the FIQ line */
+ mov w1, RPI3_INTC_MBOX_CONTROL_SLOT3_FIQ
+ str w1, [x0, #RPI3_INTC_MBOX_CONTROL_OFFSET]
+ ret
+endfunc plat_reset_handler
diff --git a/plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c b/plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c
new file mode 100644
index 00000000..e3acfe9f
--- /dev/null
+++ b/plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <bl_common.h>
+#include <desc_image_load.h>
+#include <platform.h>
+#include <platform_def.h>
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+
+ /* Fill BL31 related information */
+ {
+ .image_id = BL31_IMAGE_ID,
+
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t,
+ SECURE | EXECUTABLE | EP_FIRST_EXE),
+ .ep_info.pc = BL31_BASE,
+ .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS),
+#if DEBUG
+ .ep_info.args.arg1 = RPI3_BL31_PLAT_PARAM_VAL,
+#endif
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t,
+ IMAGE_ATTRIB_PLAT_SETUP),
+ .image_info.image_base = BL31_BASE,
+ .image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+# ifdef BL32_BASE
+ .next_handoff_image_id = BL32_IMAGE_ID,
+# else
+ .next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+ },
+
+# ifdef BL32_BASE
+ /* Fill BL32 related information */
+ {
+ .image_id = BL32_IMAGE_ID,
+
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t,
+ SECURE | EXECUTABLE),
+ .ep_info.pc = BL32_BASE,
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t, 0),
+ .image_info.image_base = BL32_BASE,
+ .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+ .next_handoff_image_id = BL33_IMAGE_ID,
+ },
+
+ /*
+ * Fill BL32 external 1 related information.
+ * A typical use for extra1 image is with OP-TEE where it is the pager
+ * image.
+ */
+ {
+ .image_id = BL32_EXTRA1_IMAGE_ID,
+
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t,
+ SECURE | NON_EXECUTABLE),
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t,
+ IMAGE_ATTRIB_SKIP_LOADING),
+ .image_info.image_base = BL32_BASE,
+ .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ },
+
+ /*
+ * Fill BL32 external 2 related information.
+ * A typical use for extra2 image is with OP-TEE where it is the paged
+ * image.
+ */
+ {
+ .image_id = BL32_EXTRA2_IMAGE_ID,
+
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t,
+ SECURE | NON_EXECUTABLE),
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t,
+ IMAGE_ATTRIB_SKIP_LOADING),
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ },
+# endif /* BL32_BASE */
+
+ /* Fill BL33 related information */
+ {
+ .image_id = BL33_IMAGE_ID,
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t,
+ NON_SECURE | EXECUTABLE),
+# ifdef PRELOADED_BL33_BASE
+ .ep_info.pc = PRELOADED_BL33_BASE,
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t,
+ IMAGE_ATTRIB_SKIP_LOADING),
+# else
+ .ep_info.pc = PLAT_RPI3_NS_IMAGE_OFFSET,
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t, 0),
+ .image_info.image_base = PLAT_RPI3_NS_IMAGE_OFFSET,
+ .image_info.image_max_size = PLAT_RPI3_NS_IMAGE_MAX_SIZE,
+# endif /* PRELOADED_BL33_BASE */
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ }
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/rpi3/include/plat_macros.S b/plat/rpi3/include/plat_macros.S
new file mode 100644
index 00000000..f5e057ed
--- /dev/null
+++ b/plat/rpi3/include/plat_macros.S
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __PLAT_MACROS_S__
+#define __PLAT_MACROS_S__
+
+#include <arm_macros.S>
+#include <platform_def.h>
+
+ /* ---------------------------------------------
+ * The below required platform porting macro
+ * prints out relevant platform registers
+ * whenever an unhandled exception is taken in
+ * BL31.
+ * Clobbers: x0 - x10, x16, x17, sp
+ * ---------------------------------------------
+ */
+ .macro plat_crash_print_regs
+ .endm
+
+#endif /* __PLAT_MACROS_S__ */
diff --git a/plat/rpi3/include/platform_def.h b/plat/rpi3/include/platform_def.h
new file mode 100644
index 00000000..5e2f1da5
--- /dev/null
+++ b/plat/rpi3/include/platform_def.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+#include <arch.h>
+#include <common_def.h>
+#include <tbbr_img_def.h>
+#include <utils_def.h>
+
+#include "../rpi3_hw.h"
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define RPI3_BL31_PLAT_PARAM_VAL ULL(0x0F1E2D3C4B5A6978)
+
+#define PLATFORM_STACK_SIZE ULL(0x1000)
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CORE_COUNT PLATFORM_CLUSTER0_CORE_COUNT
+
+#define RPI3_PRIMARY_CPU U(0)
+
+#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1
+#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \
+ PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_RET_STATE U(1)
+#define PLAT_MAX_OFF_STATE U(2)
+
+/* Local power state for power domains in Run state. */
+#define PLAT_LOCAL_STATE_RUN U(0)
+/* Local power state for retention. Valid only for CPU power domains */
+#define PLAT_LOCAL_STATE_RET U(1)
+/*
+ * Local power state for OFF/power-down. Valid for CPU and cluster power
+ * domains.
+ */
+#define PLAT_LOCAL_STATE_OFF U(2)
+
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define PLAT_LOCAL_PSTATE_WIDTH U(4)
+#define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_SHIFT U(6)
+#define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Partition memory into secure ROM, non-secure DRAM, secure "SRAM", and
+ * secure DRAM. Note that this is all actually DRAM with different names,
+ * there is no Secure RAM in the Raspberry Pi 3.
+ */
+#define SEC_ROM_BASE ULL(0x00000000)
+#define SEC_ROM_SIZE ULL(0x00010000)
+
+/* FIP placed after ROM to append it to BL1 with very little padding. */
+#define PLAT_RPI3_FIP_BASE ULL(0x00010000)
+#define PLAT_RPI3_FIP_MAX_SIZE ULL(0x001F0000)
+
+/* We have 16M of memory reserved at at 256M */
+#define SEC_SRAM_BASE ULL(0x10000000)
+#define SEC_SRAM_SIZE ULL(0x00100000)
+
+#define SEC_DRAM0_BASE ULL(0x10100000)
+#define SEC_DRAM0_SIZE ULL(0x00200000)
+
+#define NS_DRAM0_BASE ULL(0x10300000)
+#define NS_DRAM0_SIZE ULL(0x00D00000)
+/* End of reserved memory */
+
+/*
+ * BL33 entrypoint.
+ */
+#define PLAT_RPI3_NS_IMAGE_OFFSET NS_DRAM0_BASE
+#define PLAT_RPI3_NS_IMAGE_MAX_SIZE NS_DRAM0_SIZE
+
+/*
+ * I/O registers.
+ */
+#define DEVICE0_BASE RPI3_IO_BASE
+#define DEVICE0_SIZE RPI3_IO_SIZE
+
+/*
+ * Arm TF lives in SRAM, partition it here
+ */
+#define SHARED_RAM_BASE SEC_SRAM_BASE
+#define SHARED_RAM_SIZE ULL(0x00001000)
+
+#define BL_RAM_BASE (SHARED_RAM_BASE + SHARED_RAM_SIZE)
+#define BL_RAM_SIZE (SEC_SRAM_SIZE - SHARED_RAM_SIZE)
+
+/*
+ * Mailbox to control the secondary cores.All secondary cores are held in a wait
+ * loop in cold boot. To release them perform the following steps (plus any
+ * additional barriers that may be needed):
+ *
+ * uint64_t *entrypoint = (uint64_t *)PLAT_RPI3_TM_ENTRYPOINT;
+ * *entrypoint = ADDRESS_TO_JUMP_TO;
+ *
+ * uint64_t *mbox_entry = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE;
+ * mbox_entry[cpu_id] = PLAT_RPI3_TM_HOLD_STATE_GO;
+ *
+ * sev();
+ */
+#define PLAT_RPI3_TRUSTED_MAILBOX_BASE SHARED_RAM_BASE
+
+#define PLAT_RPI3_TM_ENTRYPOINT PLAT_RPI3_TRUSTED_MAILBOX_BASE
+#define PLAT_RPI3_TM_ENTRYPOINT_SIZE ULL(8)
+
+#define PLAT_RPI3_TM_HOLD_BASE (PLAT_RPI3_TM_ENTRYPOINT + \
+ PLAT_RPI3_TM_ENTRYPOINT_SIZE)
+#define PLAT_RPI3_TM_HOLD_ENTRY_SIZE ULL(8)
+#define PLAT_RPI3_TM_HOLD_SIZE (PLAT_RPI3_TM_HOLD_ENTRY_SIZE * \
+ PLATFORM_CORE_COUNT)
+
+#define PLAT_RPI3_TRUSTED_MAILBOX_SIZE (PLAT_RPI3_TM_ENTRYPOINT_SIZE + \
+ PLAT_RPI3_TM_HOLD_SIZE)
+
+#define PLAT_RPI3_TM_HOLD_STATE_WAIT ULL(0)
+#define PLAT_RPI3_TM_HOLD_STATE_GO ULL(1)
+
+/*
+ * BL1 specific defines.
+ *
+ * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
+ * addresses.
+ *
+ * Put BL1 RW at the top of the Secure SRAM. BL1_RW_BASE is calculated using
+ * the current BL1 RW debug size plus a little space for growth.
+ */
+#define PLAT_MAX_BL1_RW_SIZE ULL(0x12000)
+
+#define BL1_RO_BASE SEC_ROM_BASE
+#define BL1_RO_LIMIT (SEC_ROM_BASE + SEC_ROM_SIZE)
+#define BL1_RW_BASE (BL1_RW_LIMIT - PLAT_MAX_BL1_RW_SIZE)
+#define BL1_RW_LIMIT (BL_RAM_BASE + BL_RAM_SIZE)
+
+/*
+ * BL2 specific defines.
+ *
+ * Put BL2 just below BL31. BL2_BASE is calculated using the current BL2 debug
+ * size plus a little space for growth.
+ */
+#define PLAT_MAX_BL2_SIZE ULL(0x2C000)
+
+#define BL2_BASE (BL2_LIMIT - PLAT_MAX_BL2_SIZE)
+#define BL2_LIMIT BL31_BASE
+
+/*
+ * BL31 specific defines.
+ *
+ * Put BL31 at the top of the Trusted SRAM. BL31_BASE is calculated using the
+ * current BL31 debug size plus a little space for growth.
+ */
+#define PLAT_MAX_BL31_SIZE ULL(0x20000)
+
+#define BL31_BASE (BL31_LIMIT - PLAT_MAX_BL31_SIZE)
+#define BL31_LIMIT (BL_RAM_BASE + BL_RAM_SIZE)
+#define BL31_PROGBITS_LIMIT BL1_RW_BASE
+
+/*
+ * BL32 specific defines.
+ *
+ * BL32 can execute from Secure SRAM or Secure DRAM.
+ */
+#define BL32_SRAM_BASE BL_RAM_BASE
+#define BL32_SRAM_LIMIT BL31_BASE
+#define BL32_DRAM_BASE SEC_DRAM0_BASE
+#define BL32_DRAM_LIMIT (SEC_DRAM0_BASE + SEC_DRAM0_SIZE)
+
+#define SEC_SRAM_ID 0
+#define SEC_DRAM_ID 1
+
+#if RPI3_BL32_RAM_LOCATION_ID == SEC_SRAM_ID
+# define BL32_MEM_BASE BL_RAM_BASE
+# define BL32_MEM_SIZE BL_RAM_SIZE
+# define BL32_BASE BL32_SRAM_BASE
+# define BL32_LIMIT BL32_SRAM_LIMIT
+#elif RPI3_BL32_RAM_LOCATION_ID == SEC_DRAM_ID
+# define BL32_MEM_BASE SEC_DRAM0_BASE
+# define BL32_MEM_SIZE SEC_DRAM0_SIZE
+# define BL32_BASE BL32_DRAM_BASE
+# define BL32_LIMIT BL32_DRAM_LIMIT
+#else
+# error "Unsupported RPI3_BL32_RAM_LOCATION_ID value"
+#endif
+#define BL32_SIZE (BL32_LIMIT - BL32_BASE)
+
+#ifdef SPD_none
+#undef BL32_BASE
+#endif /* SPD_none */
+
+/*
+ * Other memory-related defines.
+ */
+#define ADDR_SPACE_SIZE (ULL(1) << 32)
+
+#define MAX_MMAP_REGIONS U(8)
+#define MAX_XLAT_TABLES U(4)
+
+#define MAX_IO_DEVICES U(3)
+#define MAX_IO_HANDLES U(4)
+
+/*
+ * Serial-related constants.
+ */
+#define PLAT_RPI3_UART_BASE RPI3_MINI_UART_BASE
+#define PLAT_RPI3_UART_CLK_IN_HZ RPI3_MINI_UART_CLK_IN_HZ
+#define PLAT_RPI3_UART_BAUDRATE ULL(115200)
+
+/*
+ * System counter
+ */
+#define SYS_COUNTER_FREQ_IN_TICKS ULL(19200000)
+
+#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/rpi3/platform.mk b/plat/rpi3/platform.mk
new file mode 100644
index 00000000..821f8015
--- /dev/null
+++ b/plat/rpi3/platform.mk
@@ -0,0 +1,113 @@
+#
+# Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES := -Iinclude/common/tbbr \
+ -Iinclude/plat/arm/common/ \
+ -Iinclude/plat/arm/common/aarch64/ \
+ -Iplat/rpi3/include
+
+PLAT_BL_COMMON_SOURCES := drivers/console/aarch64/console.S \
+ drivers/ti/uart/aarch64/16550_console.S \
+ plat/rpi3/rpi3_common.c
+
+BL1_SOURCES += drivers/io/io_fip.c \
+ drivers/io/io_memmap.c \
+ drivers/io/io_storage.c \
+ lib/cpus/aarch64/cortex_a53.S \
+ plat/common/aarch64/platform_mp_stack.S \
+ plat/rpi3/aarch64/plat_helpers.S \
+ plat/rpi3/rpi3_bl1_setup.c \
+ plat/rpi3/rpi3_io_storage.c
+
+BL2_SOURCES += common/desc_image_load.c \
+ drivers/io/io_fip.c \
+ drivers/io/io_memmap.c \
+ drivers/io/io_storage.c \
+ plat/common/aarch64/platform_mp_stack.S \
+ plat/rpi3/aarch64/plat_helpers.S \
+ plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c \
+ plat/rpi3/rpi3_bl2_setup.c \
+ plat/rpi3/rpi3_image_load.c \
+ plat/rpi3/rpi3_io_storage.c
+
+BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \
+ plat/common/aarch64/plat_psci_common.c \
+ plat/rpi3/aarch64/plat_helpers.S \
+ plat/rpi3/rpi3_bl31_setup.c \
+ plat/rpi3/rpi3_pm.c \
+ plat/rpi3/rpi3_topology.c
+
+# Translation tables library
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS}
+
+# Tune compiler for Cortex-A53
+ifeq ($(notdir $(CC)),armclang)
+ TF_CFLAGS_aarch64 += -mcpu=cortex-a53
+else ifneq ($(findstring clang,$(notdir $(CC))),)
+ TF_CFLAGS_aarch64 += -mcpu=cortex-a53
+else
+ TF_CFLAGS_aarch64 += -mtune=cortex-a53
+endif
+
+# Build config flags
+# ------------------
+
+# Enable all errata workarounds for Cortex-A53
+ERRATA_A53_826319 := 1
+ERRATA_A53_835769 := 1
+ERRATA_A53_836870 := 1
+ERRATA_A53_843419 := 1
+ERRATA_A53_855873 := 1
+
+# Disable the PSCI platform compatibility layer by default
+ENABLE_PLAT_COMPAT := 0
+
+# Enable reset to BL31 by default
+RESET_TO_BL31 := 1
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA := 1
+
+# Use Coherent memory
+USE_COHERENT_MEM := 1
+
+# Enable new version of image loading
+LOAD_IMAGE_V2 := 1
+
+# Platform build flags
+# --------------------
+
+# BL33 images are in AArch64 by default
+RPI3_BL33_IN_AARCH32 := 0
+
+# BL32 location
+RPI3_BL32_RAM_LOCATION := tdram
+ifeq (${RPI3_BL32_RAM_LOCATION}, tsram)
+ RPI3_BL32_RAM_LOCATION_ID = SEC_SRAM_ID
+else ifeq (${RPI3_BL32_RAM_LOCATION}, tdram)
+ RPI3_BL32_RAM_LOCATION_ID = SEC_DRAM_ID
+else
+ $(error "Unsupported RPI3_BL32_RAM_LOCATION value")
+endif
+
+# Process platform flags
+# ----------------------
+
+$(eval $(call add_define,RPI3_BL32_RAM_LOCATION_ID))
+$(eval $(call add_define,RPI3_BL33_IN_AARCH32))
+
+# Verify build config
+# -------------------
+
+ifneq (${LOAD_IMAGE_V2}, 1)
+ $(error Error: rpi3 needs LOAD_IMAGE_V2=1)
+endif
+
+ifeq (${ARCH},aarch32)
+ $(error Error: AArch32 not supported on rpi3)
+endif
diff --git a/plat/rpi3/rpi3_bl1_setup.c b/plat/rpi3/rpi3_bl1_setup.c
new file mode 100644
index 00000000..11c0f4af
--- /dev/null
+++ b/plat/rpi3/rpi3_bl1_setup.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl_common.h>
+#include <console.h>
+#include <platform_def.h>
+#include <xlat_mmu_helpers.h>
+#include <xlat_tables_defs.h>
+
+#include "../../bl1/bl1_private.h"
+#include "rpi3_private.h"
+
+/* Data structure which holds the extents of the trusted SRAM for BL1 */
+static meminfo_t bl1_tzram_layout;
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+ return &bl1_tzram_layout;
+}
+
+/*******************************************************************************
+ * Perform any BL1 specific platform actions.
+ ******************************************************************************/
+void bl1_early_platform_setup(void)
+{
+ /* Initialize the console to provide early debug support */
+ console_init(PLAT_RPI3_UART_BASE, PLAT_RPI3_UART_CLK_IN_HZ,
+ PLAT_RPI3_UART_BAUDRATE);
+
+ /* Allow BL1 to see the whole Trusted RAM */
+ bl1_tzram_layout.total_base = BL_RAM_BASE;
+ bl1_tzram_layout.total_size = BL_RAM_SIZE;
+}
+
+/******************************************************************************
+ * Perform the very early platform specific architecture setup. This only
+ * does basic initialization. Later architectural setup (bl1_arch_setup())
+ * does not do anything platform specific.
+ *****************************************************************************/
+void bl1_plat_arch_setup(void)
+{
+ rpi3_setup_page_tables(bl1_tzram_layout.total_base,
+ bl1_tzram_layout.total_size,
+ BL_CODE_BASE, BL1_CODE_END,
+ BL1_RO_DATA_BASE, BL1_RO_DATA_END
+#if USE_COHERENT_MEM
+ , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END
+#endif
+ );
+
+ enable_mmu_el3(0);
+}
+
+void bl1_platform_setup(void)
+{
+ /* Initialise the IO layer and register platform IO devices */
+ plat_rpi3_io_setup();
+}
diff --git a/plat/rpi3/rpi3_bl2_setup.c b/plat/rpi3/rpi3_bl2_setup.c
new file mode 100644
index 00000000..1fd822e9
--- /dev/null
+++ b/plat/rpi3/rpi3_bl2_setup.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <console.h>
+#include <debug.h>
+#include <desc_image_load.h>
+#include <platform_def.h>
+#include <xlat_mmu_helpers.h>
+#include <xlat_tables_defs.h>
+
+#include "rpi3_private.h"
+
+/* Data structure which holds the extents of the trusted SRAM for BL2 */
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+/*******************************************************************************
+ * BL1 has passed the extents of the trusted SRAM that should be visible to BL2
+ * in x0. This memory layout is sitting at the base of the free trusted SRAM.
+ * Copy it to a safe location before its reclaimed by later BL2 functionality.
+ ******************************************************************************/
+void bl2_early_platform_setup(meminfo_t *mem_layout)
+{
+ /* Initialize the console to provide early debug support */
+ console_init(PLAT_RPI3_UART_BASE, PLAT_RPI3_UART_CLK_IN_HZ,
+ PLAT_RPI3_UART_BAUDRATE);
+
+ /* Setup the BL2 memory layout */
+ bl2_tzram_layout = *mem_layout;
+
+ plat_rpi3_io_setup();
+}
+
+void bl2_platform_setup(void)
+{
+ /*
+ * This is where a TrustZone address space controller and other
+ * security related peripherals, would be configured.
+ */
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here.
+ ******************************************************************************/
+void bl2_plat_arch_setup(void)
+{
+ rpi3_setup_page_tables(bl2_tzram_layout.total_base,
+ bl2_tzram_layout.total_size,
+ BL_CODE_BASE, BL_CODE_END,
+ BL_RO_DATA_BASE, BL_RO_DATA_END
+#if USE_COHERENT_MEM
+ , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END
+#endif
+ );
+
+ enable_mmu_el1(0);
+}
+
+/*******************************************************************************
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ ******************************************************************************/
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+ int err = 0;
+ bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+
+ assert(bl_mem_params != NULL);
+
+ switch (image_id) {
+ case BL32_IMAGE_ID:
+ bl_mem_params->ep_info.spsr = rpi3_get_spsr_for_bl32_entry();
+ break;
+
+ case BL33_IMAGE_ID:
+ /* BL33 expects to receive the primary CPU MPID (through r0) */
+ bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+ bl_mem_params->ep_info.spsr = rpi3_get_spsr_for_bl33_entry();
+ break;
+
+ }
+
+ return err;
+}
diff --git a/plat/rpi3/rpi3_bl31_setup.c b/plat/rpi3/rpi3_bl31_setup.c
new file mode 100644
index 00000000..39133564
--- /dev/null
+++ b/plat/rpi3/rpi3_bl31_setup.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <bl_common.h>
+#include <console.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <xlat_mmu_helpers.h>
+#include <xlat_tables_defs.h>
+
+#include "rpi3_private.h"
+
+#define BL31_END (uintptr_t)(&__BL31_END__)
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+ entry_point_info_t *next_image_info;
+
+ assert(sec_state_is_valid(type) != 0);
+
+ next_image_info = (type == NON_SECURE)
+ ? &bl33_image_ep_info : &bl32_image_ep_info;
+
+ /* None of the images can have 0x0 as the entrypoint. */
+ if (next_image_info->pc) {
+ return next_image_info;
+ } else {
+ return NULL;
+ }
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before
+ * they are lost (potentially). This needs to be done before the MMU is
+ * initialized so that the memory layout can be used while creating page
+ * tables. BL2 has flushed this information to memory, so we are guaranteed
+ * to pick up good data.
+ ******************************************************************************/
+void bl31_early_platform_setup(void *from_bl2,
+ void *plat_params_from_bl2)
+{
+ /* Initialize the console to provide early debug support */
+ console_init(PLAT_RPI3_UART_BASE, PLAT_RPI3_UART_CLK_IN_HZ,
+ PLAT_RPI3_UART_BAUDRATE);
+
+#if RESET_TO_BL31
+
+ /* There are no parameters from BL2 if BL31 is a reset vector */
+ assert(from_bl2 == NULL);
+ assert(plat_params_from_bl2 == NULL);
+
+#ifdef BL32_BASE
+ /* Populate entry point information for BL32 */
+ SET_PARAM_HEAD(&bl32_image_ep_info,
+ PARAM_EP,
+ VERSION_1,
+ 0);
+ SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+ bl32_image_ep_info.pc = BL32_BASE;
+ bl32_image_ep_info.spsr = rpi3_get_spsr_for_bl32_entry();
+#endif /* BL32_BASE */
+
+ /* Populate entry point information for BL33 */
+ SET_PARAM_HEAD(&bl33_image_ep_info,
+ PARAM_EP,
+ VERSION_1,
+ 0);
+ /*
+ * Tell BL31 where the non-trusted software image
+ * is located and the entry state information
+ */
+ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+
+ bl33_image_ep_info.spsr = rpi3_get_spsr_for_bl33_entry();
+ SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+#else /* RESET_TO_BL31 */
+
+ /*
+ * In debug builds, we pass a special value in 'plat_params_from_bl2'
+ * to verify platform parameters from BL2 to BL31.
+ * In release builds, it's not used.
+ */
+ assert(((uintptr_t)plat_params_from_bl2) == RPI3_BL31_PLAT_PARAM_VAL);
+
+ /*
+ * Check params passed from BL2 should not be NULL,
+ */
+ bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
+
+ assert(params_from_bl2 != NULL);
+ assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+ assert(params_from_bl2->h.version >= VERSION_2);
+
+ bl_params_node_t *bl_params = params_from_bl2->head;
+
+ /*
+ * Copy BL33 and BL32 (if present), entry point information.
+ * They are stored in Secure RAM, in BL2's address space.
+ */
+ while (bl_params) {
+ if (bl_params->image_id == BL32_IMAGE_ID) {
+ bl32_image_ep_info = *bl_params->ep_info;
+ }
+
+ if (bl_params->image_id == BL33_IMAGE_ID) {
+ bl33_image_ep_info = *bl_params->ep_info;
+ }
+
+ bl_params = bl_params->next_params_info;
+ }
+
+ if (bl33_image_ep_info.pc == 0) {
+ panic();
+ }
+
+#endif /* RESET_TO_BL31 */
+}
+
+void bl31_plat_arch_setup(void)
+{
+ rpi3_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE,
+ BL_CODE_BASE, BL_CODE_END,
+ BL_RO_DATA_BASE, BL_RO_DATA_END
+#if USE_COHERENT_MEM
+ , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END
+#endif
+ );
+
+ enable_mmu_el3(0);
+}
+
+void bl31_platform_setup(void)
+{
+#if RESET_TO_BL31
+ /*
+ * Do initial security configuration to allow DRAM/device access
+ * (if earlier BL has not already done so).
+ */
+#endif /* RESET_TO_BL31 */
+
+ return;
+}
+
+void bl31_plat_runtime_setup(void)
+{
+ /* Initialize the runtime console */
+ console_init(PLAT_RPI3_UART_BASE, PLAT_RPI3_UART_CLK_IN_HZ,
+ PLAT_RPI3_UART_BAUDRATE);
+}
diff --git a/plat/rpi3/rpi3_common.c b/plat/rpi3/rpi3_common.c
new file mode 100644
index 00000000..97dce091
--- /dev/null
+++ b/plat/rpi3/rpi3_common.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <bl_common.h>
+#include <debug.h>
+#include <interrupt_mgmt.h>
+#include <platform_def.h>
+#include <xlat_tables_v2.h>
+
+#include "rpi3_hw.h"
+#include "rpi3_private.h"
+
+#define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \
+ DEVICE0_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SHARED_RAM MAP_REGION_FLAT(SHARED_RAM_BASE, \
+ SHARED_RAM_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_NS_DRAM0 MAP_REGION_FLAT(NS_DRAM0_BASE, NS_DRAM0_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_FIP MAP_REGION_FLAT(PLAT_RPI3_FIP_BASE, \
+ PLAT_RPI3_FIP_MAX_SIZE, \
+ MT_MEMORY | MT_RO | MT_NS)
+
+#define MAP_BL32_MEM MAP_REGION_FLAT(BL32_MEM_BASE, BL32_MEM_SIZE, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+
+/*
+ * Table of regions for various BL stages to map using the MMU.
+ */
+#ifdef IMAGE_BL1
+static const mmap_region_t plat_rpi3_mmap[] = {
+ MAP_SHARED_RAM,
+ MAP_DEVICE0,
+ MAP_FIP,
+ {0}
+};
+#endif
+
+#ifdef IMAGE_BL2
+static const mmap_region_t plat_rpi3_mmap[] = {
+ MAP_SHARED_RAM,
+ MAP_DEVICE0,
+ MAP_FIP,
+ MAP_NS_DRAM0,
+#ifdef BL32_BASE
+ MAP_BL32_MEM,
+#endif
+ {0}
+};
+#endif
+
+#ifdef IMAGE_BL31
+static const mmap_region_t plat_rpi3_mmap[] = {
+ MAP_SHARED_RAM,
+ MAP_DEVICE0,
+#ifdef BL32_BASE
+ MAP_BL32_MEM,
+#endif
+ {0}
+};
+#endif
+
+/*******************************************************************************
+ * Function that sets up the translation tables.
+ ******************************************************************************/
+void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size,
+ uintptr_t code_start, uintptr_t code_limit,
+ uintptr_t rodata_start, uintptr_t rodata_limit
+#if USE_COHERENT_MEM
+ , uintptr_t coh_start, uintptr_t coh_limit
+#endif
+ )
+{
+ /*
+ * Map the Trusted SRAM with appropriate memory attributes.
+ * Subsequent mappings will adjust the attributes for specific regions.
+ */
+ VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n",
+ (void *) total_base, (void *) (total_base + total_size));
+ mmap_add_region(total_base, total_base,
+ total_size,
+ MT_MEMORY | MT_RW | MT_SECURE);
+
+ /* Re-map the code section */
+ VERBOSE("Code region: %p - %p\n",
+ (void *) code_start, (void *) code_limit);
+ mmap_add_region(code_start, code_start,
+ code_limit - code_start,
+ MT_CODE | MT_SECURE);
+
+ /* Re-map the read-only data section */
+ VERBOSE("Read-only data region: %p - %p\n",
+ (void *) rodata_start, (void *) rodata_limit);
+ mmap_add_region(rodata_start, rodata_start,
+ rodata_limit - rodata_start,
+ MT_RO_DATA | MT_SECURE);
+
+#if USE_COHERENT_MEM
+ /* Re-map the coherent memory region */
+ VERBOSE("Coherent region: %p - %p\n",
+ (void *) coh_start, (void *) coh_limit);
+ mmap_add_region(coh_start, coh_start,
+ coh_limit - coh_start,
+ MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+
+ mmap_add(plat_rpi3_mmap);
+
+ init_xlat_tables();
+}
+
+/*******************************************************************************
+ * Return entrypoint of BL33.
+ ******************************************************************************/
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+ return PRELOADED_BL33_BASE;
+#else
+ return PLAT_RPI3_NS_IMAGE_OFFSET;
+#endif
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL32 entry
+ ******************************************************************************/
+uint32_t rpi3_get_spsr_for_bl32_entry(void)
+{
+ /*
+ * The Secure Payload Dispatcher service is responsible for
+ * setting the SPSR prior to entry into the BL32 image.
+ */
+ return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+uint32_t rpi3_get_spsr_for_bl33_entry(void)
+{
+#if RPI3_BL33_IN_AARCH32
+ INFO("BL33 will boot in Non-secure AArch32 Hypervisor mode\n");
+ return SPSR_MODE32(MODE32_hyp, SPSR_T_ARM, SPSR_E_LITTLE,
+ DISABLE_ALL_EXCEPTIONS);
+#else
+ return SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+#endif
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+uint32_t plat_ic_get_pending_interrupt_type(void)
+{
+ return INTR_TYPE_INVAL;
+}
diff --git a/plat/rpi3/rpi3_hw.h b/plat/rpi3/rpi3_hw.h
new file mode 100644
index 00000000..70272e00
--- /dev/null
+++ b/plat/rpi3/rpi3_hw.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __RPI3_HW__
+#define __RPI3_HW__
+
+#include <utils_def.h>
+
+/*
+ * Peripherals
+ */
+
+#define RPI3_IO_BASE ULL(0x3F000000)
+#define RPI3_IO_SIZE ULL(0x01000000)
+
+/*
+ * Serial port (called 'Mini UART' in the BCM docucmentation).
+ */
+#define RPI3_IO_MINI_UART_OFFSET ULL(0x00215040)
+#define RPI3_MINI_UART_BASE (RPI3_IO_BASE + RPI3_IO_MINI_UART_OFFSET)
+#define RPI3_MINI_UART_CLK_IN_HZ ULL(500000000)
+
+/*
+ * Power management, reset controller, watchdog.
+ */
+#define RPI3_IO_PM_OFFSET ULL(0x00100000)
+#define RPI3_PM_BASE (RPI3_IO_BASE + RPI3_IO_PM_OFFSET)
+/* Registers on top of RPI3_PM_BASE. */
+#define RPI3_PM_RSTC_OFFSET ULL(0x0000001C)
+#define RPI3_PM_WDOG_OFFSET ULL(0x00000024)
+/* Watchdog constants */
+#define RPI3_PM_PASSWORD ULL(0x5A000000)
+#define RPI3_PM_RSTC_WRCFG_MASK ULL(0x00000030)
+#define RPI3_PM_RSTC_WRCFG_FULL_RESET ULL(0x00000020)
+
+/*
+ * Local interrupt controller
+ */
+#define RPI3_INTC_BASE_ADDRESS ULL(0x40000000)
+/* Registers on top of RPI3_INTC_BASE_ADDRESS */
+#define RPI3_INTC_CONTROL_OFFSET ULL(0x00000000)
+#define RPI3_INTC_PRESCALER_OFFSET ULL(0x00000008)
+#define RPI3_INTC_MBOX_CONTROL_OFFSET ULL(0x00000050)
+#define RPI3_INTC_MBOX_CONTROL_SLOT3_FIQ ULL(0x00000080)
+#define RPI3_INTC_PENDING_FIQ_OFFSET ULL(0x00000070)
+#define RPI3_INTC_PENDING_FIQ_MBOX3 ULL(0x00000080)
+
+#endif /* __RPI3_HW__ */
diff --git a/plat/rpi3/rpi3_image_load.c b/plat/rpi3/rpi3_image_load.c
new file mode 100644
index 00000000..fad9e4f3
--- /dev/null
+++ b/plat/rpi3/rpi3_image_load.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <bl_common.h>
+#include <desc_image_load.h>
+#include <platform.h>
+#include <platform_def.h>
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+ flush_bl_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+ return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+ return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/rpi3/rpi3_io_storage.c b/plat/rpi3/rpi3_io_storage.c
new file mode 100644
index 00000000..7ac45ef6
--- /dev/null
+++ b/plat/rpi3/rpi3_io_storage.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <bl_common.h>
+#include <debug.h>
+#include <firmware_image_package.h>
+#include <io_driver.h>
+#include <io_fip.h>
+#include <io_memmap.h>
+#include <platform_def.h>
+#include <string.h>
+
+/* Semihosting filenames */
+#define BL2_IMAGE_NAME "bl2.bin"
+#define BL31_IMAGE_NAME "bl31.bin"
+#define BL32_IMAGE_NAME "bl32.bin"
+#define BL33_IMAGE_NAME "bl33.bin"
+
+#if TRUSTED_BOARD_BOOT
+#define BL2_CERT_NAME "bl2.crt"
+#define TRUSTED_KEY_CERT_NAME "trusted_key.crt"
+#define BL31_KEY_CERT_NAME "bl31_key.crt"
+#define BL32_KEY_CERT_NAME "bl32_key.crt"
+#define BL33_KEY_CERT_NAME "bl33_key.crt"
+#define BL31_CERT_NAME "bl31.crt"
+#define BL32_CERT_NAME "bl32.crt"
+#define BL33_CERT_NAME "bl33.crt"
+#endif /* TRUSTED_BOARD_BOOT */
+
+/* IO devices */
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static const io_dev_connector_t *memmap_dev_con;
+static uintptr_t memmap_dev_handle;
+
+static const io_block_spec_t fip_block_spec = {
+ .offset = PLAT_RPI3_FIP_BASE,
+ .length = PLAT_RPI3_FIP_MAX_SIZE
+};
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+ .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+ .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl32_uuid_spec = {
+ .uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+ .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t bl2_cert_uuid_spec = {
+ .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2_CERT,
+};
+
+static const io_uuid_spec_t trusted_key_cert_uuid_spec = {
+ .uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t bl31_key_cert_uuid_spec = {
+ .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31_KEY_CERT,
+};
+
+static const io_uuid_spec_t bl32_key_cert_uuid_spec = {
+ .uuid = UUID_SECURE_PAYLOAD_BL32_KEY_CERT,
+};
+
+static const io_uuid_spec_t bl33_key_cert_uuid_spec = {
+ .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33_KEY_CERT,
+};
+
+static const io_uuid_spec_t bl31_cert_uuid_spec = {
+ .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31_CERT,
+};
+
+static const io_uuid_spec_t bl32_cert_uuid_spec = {
+ .uuid = UUID_SECURE_PAYLOAD_BL32_CERT,
+};
+
+static const io_uuid_spec_t bl33_cert_uuid_spec = {
+ .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+static int open_fip(const uintptr_t spec);
+static int open_memmap(const uintptr_t spec);
+
+struct plat_io_policy {
+ uintptr_t *dev_handle;
+ uintptr_t image_spec;
+ int (*check)(const uintptr_t spec);
+};
+
+/* By default, load images from the FIP */
+static const struct plat_io_policy policies[] = {
+ [FIP_IMAGE_ID] = {
+ &memmap_dev_handle,
+ (uintptr_t)&fip_block_spec,
+ open_memmap
+ },
+ [BL2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl2_uuid_spec,
+ open_fip
+ },
+ [BL31_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl31_uuid_spec,
+ open_fip
+ },
+ [BL32_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl32_uuid_spec,
+ open_fip
+ },
+ [BL33_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl33_uuid_spec,
+ open_fip
+ },
+#if TRUSTED_BOARD_BOOT
+ [BL2_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl2_cert_uuid_spec,
+ open_fip
+ },
+ [TRUSTED_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&trusted_key_cert_uuid_spec,
+ open_fip
+ },
+ [BL31_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl31_key_cert_uuid_spec,
+ open_fip
+ },
+ [BL32_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl32_key_cert_uuid_spec,
+ open_fip
+ },
+ [BL33_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl33_key_cert_uuid_spec,
+ open_fip
+ },
+ [BL31_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl31_cert_uuid_spec,
+ open_fip
+ },
+ [BL32_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl32_cert_uuid_spec,
+ open_fip
+ },
+ [BL33_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl33_cert_uuid_spec,
+ open_fip
+ },
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+static int open_fip(const uintptr_t spec)
+{
+ int result;
+ uintptr_t local_image_handle;
+
+ /* See if a Firmware Image Package is available */
+ result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+ if (result == 0) {
+ result = io_open(fip_dev_handle, spec, &local_image_handle);
+ if (result == 0) {
+ VERBOSE("Using FIP\n");
+ io_close(local_image_handle);
+ }
+ }
+ return result;
+}
+
+static int open_memmap(const uintptr_t spec)
+{
+ int result;
+ uintptr_t local_image_handle;
+
+ result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
+ if (result == 0) {
+ result = io_open(memmap_dev_handle, spec, &local_image_handle);
+ if (result == 0) {
+ VERBOSE("Using Memmap\n");
+ io_close(local_image_handle);
+ }
+ }
+ return result;
+}
+
+void plat_rpi3_io_setup(void)
+{
+ int io_result;
+
+ io_result = register_io_dev_fip(&fip_dev_con);
+ assert(io_result == 0);
+
+ io_result = register_io_dev_memmap(&memmap_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to devices and cache the handles */
+ io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+ &fip_dev_handle);
+ assert(io_result == 0);
+
+ io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+ &memmap_dev_handle);
+ assert(io_result == 0);
+
+ /* Ignore improbable errors in release builds */
+ (void)io_result;
+}
+
+/*
+ * Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+ uintptr_t *image_spec)
+{
+ int result;
+ const struct plat_io_policy *policy;
+
+ assert(image_id < ARRAY_SIZE(policies));
+
+ policy = &policies[image_id];
+ result = policy->check(policy->image_spec);
+ if (result == 0) {
+ *image_spec = policy->image_spec;
+ *dev_handle = *(policy->dev_handle);
+ }
+
+ return result;
+}
diff --git a/plat/rpi3/rpi3_pm.c b/plat/rpi3/rpi3_pm.c
new file mode 100644
index 00000000..1d067fb1
--- /dev/null
+++ b/plat/rpi3/rpi3_pm.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <console.h>
+#include <debug.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <platform.h>
+#include <psci.h>
+
+#include "rpi3_hw.h"
+
+/*
+ * The secure entry point to be used on warm reset.
+ */
+static uintptr_t secure_entrypoint;
+
+/* Make composite power state parameter till power level 0 */
+#if PSCI_EXTENDED_STATE_ID
+
+#define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+ (((lvl0_state) << PSTATE_ID_SHIFT) | \
+ ((type) << PSTATE_TYPE_SHIFT))
+
+#else
+
+#define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+ (((lvl0_state) << PSTATE_ID_SHIFT) | \
+ ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
+ ((type) << PSTATE_TYPE_SHIFT))
+
+#endif /* PSCI_EXTENDED_STATE_ID */
+
+#define rpi3_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \
+ (((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \
+ rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
+
+/*
+ * The table storing the valid idle power states. Ensure that the
+ * array entries are populated in ascending order of state-id to
+ * enable us to use binary search during power state validation.
+ * The table must be terminated by a NULL entry.
+ */
+static const unsigned int rpi3_pm_idle_states[] = {
+ /* State-id - 0x01 */
+ rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET,
+ MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY),
+ /* State-id - 0x02 */
+ rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF,
+ MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN),
+ /* State-id - 0x22 */
+ rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_OFF, PLAT_LOCAL_STATE_OFF,
+ MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN),
+ 0,
+};
+
+/*******************************************************************************
+ * Platform handler called to check the validity of the power state
+ * parameter. The power state parameter has to be a composite power state.
+ ******************************************************************************/
+static int rpi3_validate_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ unsigned int state_id;
+ int i;
+
+ assert(req_state != 0);
+
+ /*
+ * Currently we are using a linear search for finding the matching
+ * entry in the idle power state array. This can be made a binary
+ * search if the number of entries justify the additional complexity.
+ */
+ for (i = 0; rpi3_pm_idle_states[i] != 0; i++) {
+ if (power_state == rpi3_pm_idle_states[i]) {
+ break;
+ }
+ }
+
+ /* Return error if entry not found in the idle state array */
+ if (!rpi3_pm_idle_states[i]) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ i = 0;
+ state_id = psci_get_pstate_id(power_state);
+
+ /* Parse the State ID and populate the state info parameter */
+ while (state_id) {
+ req_state->pwr_domain_state[i++] = state_id &
+ PLAT_LOCAL_PSTATE_MASK;
+ state_id >>= PLAT_LOCAL_PSTATE_WIDTH;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * Platform handler called when a CPU is about to enter standby.
+ ******************************************************************************/
+static void rpi3_cpu_standby(plat_local_state_t cpu_state)
+{
+ assert(cpu_state == PLAT_LOCAL_STATE_RET);
+
+ /*
+ * Enter standby state.
+ * dsb is good practice before using wfi to enter low power states
+ */
+ dsb();
+ wfi();
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+static int rpi3_pwr_domain_on(u_register_t mpidr)
+{
+ int rc = PSCI_E_SUCCESS;
+ unsigned int pos = plat_core_pos_by_mpidr(mpidr);
+ uint64_t *hold_base = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE;
+
+ assert(pos < PLATFORM_CORE_COUNT);
+
+ hold_base[pos] = PLAT_RPI3_TM_HOLD_STATE_GO;
+
+ /* Make sure that the write has completed */
+ dsb();
+ isb();
+
+ sev();
+
+ return rc;
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ ******************************************************************************/
+void rpi3_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+ PLAT_LOCAL_STATE_OFF);
+}
+
+/*******************************************************************************
+ * Platform handler to reboot the system
+ ******************************************************************************/
+#define RESET_TIMEOUT 10
+
+static void __dead2 rpi3_system_reset(void)
+{
+ /* Setup watchdog for reset */
+
+ static const uintptr_t base = RPI3_PM_BASE;
+ uint32_t rstc;
+
+ INFO("rpi3: PSCI System Reset: invoking watchdog reset\n");
+
+ console_flush();
+
+ rstc = mmio_read_32(base + RPI3_PM_RSTC_OFFSET);
+ rstc &= ~RPI3_PM_RSTC_WRCFG_MASK;
+ rstc |= RPI3_PM_RSTC_WRCFG_FULL_RESET;
+
+ dmbst();
+
+ /*
+ * Watchdog timer = Timer clock / 16
+ * Password (31:16) | Value (11:0)
+ */
+ mmio_write_32(base + RPI3_PM_WDOG_OFFSET,
+ RPI3_PM_PASSWORD | RESET_TIMEOUT);
+ mmio_write_32(base + RPI3_PM_RSTC_OFFSET,
+ RPI3_PM_PASSWORD | rstc);
+
+ for (;;) {
+ wfi();
+ }
+}
+
+/*******************************************************************************
+ * Platform handlers and setup function.
+ ******************************************************************************/
+static const plat_psci_ops_t plat_rpi3_psci_pm_ops = {
+ .cpu_standby = rpi3_cpu_standby,
+ .pwr_domain_on = rpi3_pwr_domain_on,
+ .pwr_domain_on_finish = rpi3_pwr_domain_on_finish,
+ .system_reset = rpi3_system_reset,
+ .validate_power_state = rpi3_validate_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ uintptr_t *mailbox = (void *)PLAT_RPI3_TRUSTED_MAILBOX_BASE;
+
+ *mailbox = sec_entrypoint;
+ secure_entrypoint = (uintptr_t)sec_entrypoint;
+ *psci_ops = &plat_rpi3_psci_pm_ops;
+
+ return 0;
+}
diff --git a/plat/rpi3/rpi3_private.h b/plat/rpi3/rpi3_private.h
new file mode 100644
index 00000000..01c4055f
--- /dev/null
+++ b/plat/rpi3/rpi3_private.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __RPI3_PRIVATE_H__
+#define __RPI3_PRIVATE_H__
+
+#include <sys/types.h>
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+
+/* Utility functions */
+void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size,
+ uintptr_t code_start, uintptr_t code_limit,
+ uintptr_t rodata_start, uintptr_t rodata_limit
+#if USE_COHERENT_MEM
+ , uintptr_t coh_start, uintptr_t coh_limit
+#endif
+ );
+
+/* Optional functions required in the Raspberry Pi 3 port */
+unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr);
+
+/* BL2 utility functions */
+uint32_t rpi3_get_spsr_for_bl32_entry(void);
+uint32_t rpi3_get_spsr_for_bl33_entry(void);
+
+/* IO storage utility functions */
+void plat_rpi3_io_setup(void);
+
+#endif /*__RPI3_PRIVATE_H__ */
diff --git a/plat/rpi3/rpi3_topology.c b/plat/rpi3/rpi3_topology.c
new file mode 100644
index 00000000..0e03ec32
--- /dev/null
+++ b/plat/rpi3/rpi3_topology.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <platform_def.h>
+#include <sys/types.h>
+
+#include "rpi3_private.h"
+
+/* The power domain tree descriptor */
+static unsigned char power_domain_tree_desc[] = {
+ /* Number of root nodes */
+ PLATFORM_CLUSTER_COUNT,
+ /* Number of children for the first node */
+ PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+/*******************************************************************************
+ * This function returns the ARM default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ unsigned int cluster_id, cpu_id;
+
+ mpidr &= MPIDR_AFFINITY_MASK;
+ if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) {
+ return -1;
+ }
+
+ cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+ cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+ if (cluster_id >= PLATFORM_CLUSTER_COUNT) {
+ return -1;
+ }
+
+ if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) {
+ return -1;
+ }
+
+ return plat_rpi3_calc_core_pos(mpidr);
+}
diff --git a/plat/socionext/uniphier/platform.mk b/plat/socionext/uniphier/platform.mk
index 72792f8a..3c78054b 100644
--- a/plat/socionext/uniphier/platform.mk
+++ b/plat/socionext/uniphier/platform.mk
@@ -10,6 +10,7 @@ override ERROR_DEPRECATED := 1
override LOAD_IMAGE_V2 := 1
override USE_COHERENT_MEM := 1
override USE_TBBR_DEFS := 1
+override ENABLE_SVE_FOR_NS := 0
# Cortex-A53 revision r0p4-51rel0
# needed for LD20, unneeded for LD11, PXs3 (no ACE)
@@ -21,6 +22,9 @@ ifeq ($(NEED_BL32),yes)
$(eval $(call add_define,UNIPHIER_LOAD_BL32))
endif
+# Libraries
+include lib/xlat_tables_v2/xlat_tables.mk
+
PLAT_PATH := plat/socionext/uniphier
PLAT_INCLUDES := -I$(PLAT_PATH)/include
@@ -37,12 +41,11 @@ IO_SOURCES := drivers/io/io_block.c \
# common sources for BL1, BL2, BL31
PLAT_BL_COMMON_SOURCES += drivers/console/aarch64/console.S \
- lib/xlat_tables_v2/aarch64/xlat_tables_arch.c \
- lib/xlat_tables_v2/xlat_tables_internal.c \
$(PLAT_PATH)/uniphier_console.S \
$(PLAT_PATH)/uniphier_helpers.S \
$(PLAT_PATH)/uniphier_soc_info.c \
- $(PLAT_PATH)/uniphier_xlat_setup.c
+ $(PLAT_PATH)/uniphier_xlat_setup.c \
+ ${XLAT_TABLES_LIB_SRCS}
BL1_SOURCES += lib/cpus/aarch64/cortex_a53.S \
lib/cpus/aarch64/cortex_a72.S \
@@ -99,7 +102,7 @@ $(BUILD_PLAT)/bl1/uniphier_rotpk.o: $(ROTPK_HASH)
$(BUILD_PLAT)/bl2/uniphier_rotpk.o: $(ROTPK_HASH)
certificates: $(ROT_KEY)
-$(ROT_KEY):
+$(ROT_KEY): | $(BUILD_PLAT)
@echo " OPENSSL $@"
$(Q)openssl genrsa 2048 > $@ 2>/dev/null
diff --git a/plat/socionext/uniphier/uniphier_gicv3.c b/plat/socionext/uniphier/uniphier_gicv3.c
index 05a4e35f..93bc73ac 100644
--- a/plat/socionext/uniphier/uniphier_gicv3.c
+++ b/plat/socionext/uniphier/uniphier_gicv3.c
@@ -6,6 +6,7 @@
#include <assert.h>
#include <gicv3.h>
+#include <interrupt_props.h>
#include <platform.h>
#include <platform_def.h>
@@ -13,19 +14,39 @@
static uintptr_t uniphier_rdistif_base_addrs[PLATFORM_CORE_COUNT];
-static const unsigned int g0_interrupt_array[] = {
- 8, /* SGI0 */
- 14, /* SGI6 */
-};
+static const interrupt_prop_t uniphier_interrupt_props[] = {
+ /* G0 interrupts */
+
+ /* SGI0 */
+ INTR_PROP_DESC(8, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ /* SGI6 */
+ INTR_PROP_DESC(14, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+
+ /* G1S interrupts */
-static const unsigned int g1s_interrupt_array[] = {
- 29, /* Timer */
- 9, /* SGI1 */
- 10, /* SGI2 */
- 11, /* SGI3 */
- 12, /* SGI4 */
- 13, /* SGI5 */
- 15, /* SGI7 */
+ /* Timer */
+ INTR_PROP_DESC(29, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_LEVEL),
+ /* SGI1 */
+ INTR_PROP_DESC(9, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI2 */
+ INTR_PROP_DESC(10, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI3 */
+ INTR_PROP_DESC(11, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI4 */
+ INTR_PROP_DESC(12, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI5 */
+ INTR_PROP_DESC(13, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI7 */
+ INTR_PROP_DESC(15, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE)
};
static unsigned int uniphier_mpidr_to_core_pos(u_register_t mpidr)
@@ -37,10 +58,8 @@ static const struct gicv3_driver_data uniphier_gic_driver_data[] = {
[UNIPHIER_SOC_LD11] = {
.gicd_base = 0x5fe00000,
.gicr_base = 0x5fe40000,
- .g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
- .g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
- .g0_interrupt_array = g0_interrupt_array,
- .g1s_interrupt_array = g1s_interrupt_array,
+ .interrupt_props = uniphier_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props),
.rdistif_num = PLATFORM_CORE_COUNT,
.rdistif_base_addrs = uniphier_rdistif_base_addrs,
.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
@@ -48,10 +67,8 @@ static const struct gicv3_driver_data uniphier_gic_driver_data[] = {
[UNIPHIER_SOC_LD20] = {
.gicd_base = 0x5fe00000,
.gicr_base = 0x5fe80000,
- .g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
- .g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
- .g0_interrupt_array = g0_interrupt_array,
- .g1s_interrupt_array = g1s_interrupt_array,
+ .interrupt_props = uniphier_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props),
.rdistif_num = PLATFORM_CORE_COUNT,
.rdistif_base_addrs = uniphier_rdistif_base_addrs,
.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
@@ -59,10 +76,8 @@ static const struct gicv3_driver_data uniphier_gic_driver_data[] = {
[UNIPHIER_SOC_PXS3] = {
.gicd_base = 0x5fe00000,
.gicr_base = 0x5fe80000,
- .g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
- .g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
- .g0_interrupt_array = g0_interrupt_array,
- .g1s_interrupt_array = g1s_interrupt_array,
+ .interrupt_props = uniphier_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props),
.rdistif_num = PLATFORM_CORE_COUNT,
.rdistif_base_addrs = uniphier_rdistif_base_addrs,
.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
diff --git a/plat/socionext/uniphier/uniphier_rotpk.S b/plat/socionext/uniphier/uniphier_rotpk.S
index 0045a349..21c44b62 100644
--- a/plat/socionext/uniphier/uniphier_rotpk.S
+++ b/plat/socionext/uniphier/uniphier_rotpk.S
@@ -6,6 +6,7 @@
.global uniphier_rotpk_hash
.global uniphier_rotpk_hash_end
+ .section .rodata.uniphier_rotpk_hash, "a"
uniphier_rotpk_hash:
/* DER header */
.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
diff --git a/plat/xilinx/zynqmp/include/platform_def.h b/plat/xilinx/zynqmp/include/platform_def.h
index a09b5c62..5dd8d86e 100644
--- a/plat/xilinx/zynqmp/include/platform_def.h
+++ b/plat/xilinx/zynqmp/include/platform_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,6 +8,8 @@
#define __PLATFORM_DEF_H__
#include <arch.h>
+#include <gic_common.h>
+#include <interrupt_props.h>
#include "../zynqmp_def.h"
/*******************************************************************************
@@ -85,20 +87,30 @@
#define PLAT_ARM_GICD_BASE BASE_GICD_BASE
#define PLAT_ARM_GICC_BASE BASE_GICC_BASE
/*
- * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * Define properties of Group 1 Secure and Group 0 interrupts as per GICv3
* terminology. On a GICv2 system or mode, the lists will be merged and treated
* as Group 0 interrupts.
*/
-#define PLAT_ARM_G1S_IRQS ARM_IRQ_SEC_PHY_TIMER, \
- ARM_IRQ_SEC_SGI_0, \
- ARM_IRQ_SEC_SGI_1, \
- ARM_IRQ_SEC_SGI_2, \
- ARM_IRQ_SEC_SGI_3, \
- ARM_IRQ_SEC_SGI_4, \
- ARM_IRQ_SEC_SGI_5, \
- ARM_IRQ_SEC_SGI_6, \
- ARM_IRQ_SEC_SGI_7
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE)
-#define PLAT_ARM_G0_IRQS
+#define PLAT_ARM_G0_IRQ_PROPS(grp)
#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
index ca87cc8f..cb3b4421 100644
--- a/plat/xilinx/zynqmp/platform.mk
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -11,6 +11,9 @@ A53_DISABLE_NON_TEMPORAL_HINT := 0
SEPARATE_CODE_AND_RODATA := 1
override RESET_TO_BL31 := 1
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
+
ifdef ZYNQMP_ATF_MEM_BASE
$(eval $(call add_define,ZYNQMP_ATF_MEM_BASE))
diff --git a/services/spd/opteed/opteed_common.c b/services/spd/opteed/opteed_common.c
index 2693e7d1..e5e2be77 100644
--- a/services/spd/opteed/opteed_common.c
+++ b/services/spd/opteed/opteed_common.c
@@ -78,7 +78,7 @@ uint64_t opteed_synchronous_sp_entry(optee_context_t *optee_ctx)
cm_set_next_eret_context(SECURE);
rc = opteed_enter_sp(&optee_ctx->c_rt_ctx);
-#if DEBUG
+#if ENABLE_ASSERTIONS
optee_ctx->c_rt_ctx = 0;
#endif
diff --git a/services/spd/tlkd/tlkd_common.c b/services/spd/tlkd/tlkd_common.c
index 599d7a30..483d45b6 100644
--- a/services/spd/tlkd/tlkd_common.c
+++ b/services/spd/tlkd/tlkd_common.c
@@ -131,7 +131,7 @@ uint64_t tlkd_synchronous_sp_entry(tlk_context_t *tlk_ctx)
cm_set_next_eret_context(SECURE);
rc = tlkd_enter_sp(&tlk_ctx->c_rt_ctx);
-#if DEBUG
+#if ENABLE_ASSERTIONS
tlk_ctx->c_rt_ctx = 0;
#endif
diff --git a/services/spd/trusty/trusty.c b/services/spd/trusty/trusty.c
index e386f71c..ecbcfaea 100644
--- a/services/spd/trusty/trusty.c
+++ b/services/spd/trusty/trusty.c
@@ -99,6 +99,16 @@ static struct args trusty_context_switch(uint32_t security_state, uint64_t r0,
ret.r1 = r1;
ret.r0 = r0;
+ /*
+ * To avoid the additional overhead in PSCI flow, skip FP context
+ * saving/restoring in case of CPU suspend and resume, asssuming that
+ * when it's needed the PSCI caller has preserved FP context before
+ * going here.
+ */
+#if CTX_INCLUDE_FPREGS
+ if (r0 != SMC_FC_CPU_SUSPEND && r0 != SMC_FC_CPU_RESUME)
+ fpregs_context_save(get_fpregs_ctx(cm_get_context(security_state)));
+#endif
cm_el1_sysregs_context_save(security_state);
ctx->saved_security_state = security_state;
@@ -107,6 +117,11 @@ static struct args trusty_context_switch(uint32_t security_state, uint64_t r0,
assert(ctx->saved_security_state == !security_state);
cm_el1_sysregs_context_restore(security_state);
+#if CTX_INCLUDE_FPREGS
+ if (r0 != SMC_FC_CPU_SUSPEND && r0 != SMC_FC_CPU_RESUME)
+ fpregs_context_restore(get_fpregs_ctx(cm_get_context(security_state)));
+#endif
+
cm_set_next_eret_context(security_state);
return ret;
diff --git a/services/spd/tspd/tspd_common.c b/services/spd/tspd/tspd_common.c
index 1538232f..de54dbe9 100644
--- a/services/spd/tspd/tspd_common.c
+++ b/services/spd/tspd/tspd_common.c
@@ -79,7 +79,7 @@ uint64_t tspd_synchronous_sp_entry(tsp_context_t *tsp_ctx)
cm_set_next_eret_context(SECURE);
rc = tspd_enter_sp(&tsp_ctx->c_rt_ctx);
-#if DEBUG
+#if ENABLE_ASSERTIONS
tsp_ctx->c_rt_ctx = 0;
#endif
diff --git a/services/std_svc/sdei/sdei_event.c b/services/std_svc/sdei/sdei_event.c
new file mode 100644
index 00000000..bf0e779d
--- /dev/null
+++ b/services/std_svc/sdei/sdei_event.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <utils.h>
+#include "sdei_private.h"
+
+#define MAP_OFF(_map, _mapping) ((_map) - (_mapping)->map)
+
+/*
+ * Get SDEI entry with the given mapping: on success, returns pointer to SDEI
+ * entry. On error, returns NULL.
+ *
+ * Both shared and private maps are stored in single-dimensional array. Private
+ * event entries are kept for each PE forming a 2D array.
+ */
+sdei_entry_t *get_event_entry(sdei_ev_map_t *map)
+{
+ const sdei_mapping_t *mapping;
+ sdei_entry_t *cpu_priv_base;
+ unsigned int idx, base_idx;
+
+ if (is_event_private(map)) {
+ /*
+ * For a private map, find the index of the mapping in the
+ * array.
+ */
+ mapping = SDEI_PRIVATE_MAPPING();
+ idx = MAP_OFF(map, mapping);
+
+ /* Base of private mappings for this CPU */
+ base_idx = plat_my_core_pos() * mapping->num_maps;
+ cpu_priv_base = &sdei_private_event_table[base_idx];
+
+ /*
+ * Return the address of the entry at the same index in the
+ * per-CPU event entry.
+ */
+ return &cpu_priv_base[idx];
+ } else {
+ mapping = SDEI_SHARED_MAPPING();
+ idx = MAP_OFF(map, mapping);
+
+ return &sdei_shared_event_table[idx];
+ }
+}
+
+/*
+ * Find event mapping for a given interrupt number: On success, returns pointer
+ * to the event mapping. On error, returns NULL.
+ */
+sdei_ev_map_t *find_event_map_by_intr(int intr_num, int shared)
+{
+ const sdei_mapping_t *mapping;
+ sdei_ev_map_t *map;
+ unsigned int i;
+
+ /*
+ * Look for a match in private and shared mappings, as requested. This
+ * is a linear search. However, if the mappings are required to be
+ * sorted, for large maps, we could consider binary search.
+ */
+ mapping = shared ? SDEI_SHARED_MAPPING() : SDEI_PRIVATE_MAPPING();
+ iterate_mapping(mapping, i, map) {
+ if (map->intr == intr_num)
+ return map;
+ }
+
+ return NULL;
+}
+
+/*
+ * Find event mapping for a given event number: On success returns pointer to
+ * the event mapping. On error, returns NULL.
+ */
+sdei_ev_map_t *find_event_map(int ev_num)
+{
+ const sdei_mapping_t *mapping;
+ sdei_ev_map_t *map;
+ unsigned int i, j;
+
+ /*
+ * Iterate through mappings to find a match. This is a linear search.
+ * However, if the mappings are required to be sorted, for large maps,
+ * we could consider binary search.
+ */
+ for_each_mapping_type(i, mapping) {
+ iterate_mapping(mapping, j, map) {
+ if (map->ev_num == ev_num)
+ return map;
+ }
+ }
+
+ return NULL;
+}
diff --git a/services/std_svc/sdei/sdei_intr_mgmt.c b/services/std_svc/sdei/sdei_intr_mgmt.c
new file mode 100644
index 00000000..42bf46d0
--- /dev/null
+++ b/services/std_svc/sdei/sdei_intr_mgmt.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <cassert.h>
+#include <context_mgmt.h>
+#include <debug.h>
+#include <ehf.h>
+#include <interrupt_mgmt.h>
+#include <runtime_svc.h>
+#include <sdei.h>
+#include <string.h>
+#include "sdei_private.h"
+
+#define PE_MASKED 1
+#define PE_NOT_MASKED 0
+
+/* x0-x17 GPREGS context */
+#define SDEI_SAVED_GPREGS 18
+
+/* Maximum preemption nesting levels: Critical priority and Normal priority */
+#define MAX_EVENT_NESTING 2
+
+/* Per-CPU SDEI state access macro */
+#define sdei_get_this_pe_state() (&sdei_cpu_state[plat_my_core_pos()])
+
+/* Structure to store information about an outstanding dispatch */
+typedef struct sdei_dispatch_context {
+ sdei_ev_map_t *map;
+ unsigned int sec_state;
+ unsigned int intr_raw;
+ uint64_t x[SDEI_SAVED_GPREGS];
+
+ /* Exception state registers */
+ uint64_t elr_el3;
+ uint64_t spsr_el3;
+} sdei_dispatch_context_t;
+
+/* Per-CPU SDEI state data */
+typedef struct sdei_cpu_state {
+ sdei_dispatch_context_t dispatch_stack[MAX_EVENT_NESTING];
+ unsigned short stack_top; /* Empty ascending */
+ unsigned int pe_masked:1;
+ unsigned int pending_enables:1;
+} sdei_cpu_state_t;
+
+/* SDEI states for all cores in the system */
+static sdei_cpu_state_t sdei_cpu_state[PLATFORM_CORE_COUNT];
+
+unsigned int sdei_pe_mask(void)
+{
+ unsigned int ret;
+ sdei_cpu_state_t *state = sdei_get_this_pe_state();
+
+ /*
+ * Return value indicates whether this call had any effect in the mask
+ * status of this PE.
+ */
+ ret = (state->pe_masked ^ PE_MASKED);
+ state->pe_masked = PE_MASKED;
+
+ return ret;
+}
+
+void sdei_pe_unmask(void)
+{
+ int i;
+ sdei_ev_map_t *map;
+ sdei_entry_t *se;
+ sdei_cpu_state_t *state = sdei_get_this_pe_state();
+ uint64_t my_mpidr = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
+
+ /*
+ * If there are pending enables, iterate through the private mappings
+ * and enable those bound maps that are in enabled state. Also, iterate
+ * through shared mappings and enable interrupts of events that are
+ * targeted to this PE.
+ */
+ if (state->pending_enables) {
+ for_each_private_map(i, map) {
+ se = get_event_entry(map);
+ if (is_map_bound(map) && GET_EV_STATE(se, ENABLED))
+ plat_ic_enable_interrupt(map->intr);
+ }
+
+ for_each_shared_map(i, map) {
+ se = get_event_entry(map);
+
+ sdei_map_lock(map);
+ if (is_map_bound(map) &&
+ GET_EV_STATE(se, ENABLED) &&
+ (se->reg_flags == SDEI_REGF_RM_PE) &&
+ (se->affinity == my_mpidr)) {
+ plat_ic_enable_interrupt(map->intr);
+ }
+ sdei_map_unlock(map);
+ }
+ }
+
+ state->pending_enables = 0;
+ state->pe_masked = PE_NOT_MASKED;
+}
+
+/* Push a dispatch context to the dispatch stack */
+static sdei_dispatch_context_t *push_dispatch(void)
+{
+ sdei_cpu_state_t *state = sdei_get_this_pe_state();
+ sdei_dispatch_context_t *disp_ctx;
+
+ /* Cannot have more than max events */
+ assert(state->stack_top < MAX_EVENT_NESTING);
+
+ disp_ctx = &state->dispatch_stack[state->stack_top];
+ state->stack_top++;
+
+ return disp_ctx;
+}
+
+/* Pop a dispatch context to the dispatch stack */
+static sdei_dispatch_context_t *pop_dispatch(void)
+{
+ sdei_cpu_state_t *state = sdei_get_this_pe_state();
+
+ if (state->stack_top == 0)
+ return NULL;
+
+ assert(state->stack_top <= MAX_EVENT_NESTING);
+
+ state->stack_top--;
+
+ return &state->dispatch_stack[state->stack_top];
+}
+
+/* Retrieve the context at the top of dispatch stack */
+static sdei_dispatch_context_t *get_outstanding_dispatch(void)
+{
+ sdei_cpu_state_t *state = sdei_get_this_pe_state();
+
+ if (state->stack_top == 0)
+ return NULL;
+
+ assert(state->stack_top <= MAX_EVENT_NESTING);
+
+ return &state->dispatch_stack[state->stack_top - 1];
+}
+
+static void save_event_ctx(sdei_ev_map_t *map, void *tgt_ctx, int sec_state,
+ unsigned int intr_raw)
+{
+ sdei_dispatch_context_t *disp_ctx;
+ gp_regs_t *tgt_gpregs;
+ el3_state_t *tgt_el3;
+
+ assert(tgt_ctx);
+ tgt_gpregs = get_gpregs_ctx(tgt_ctx);
+ tgt_el3 = get_el3state_ctx(tgt_ctx);
+
+ disp_ctx = push_dispatch();
+ assert(disp_ctx);
+ disp_ctx->sec_state = sec_state;
+ disp_ctx->map = map;
+ disp_ctx->intr_raw = intr_raw;
+
+ /* Save general purpose and exception registers */
+ memcpy(disp_ctx->x, tgt_gpregs, sizeof(disp_ctx->x));
+ disp_ctx->spsr_el3 = read_ctx_reg(tgt_el3, CTX_SPSR_EL3);
+ disp_ctx->elr_el3 = read_ctx_reg(tgt_el3, CTX_ELR_EL3);
+}
+
+static void restore_event_ctx(sdei_dispatch_context_t *disp_ctx, void *tgt_ctx)
+{
+ gp_regs_t *tgt_gpregs;
+ el3_state_t *tgt_el3;
+
+ assert(tgt_ctx);
+ tgt_gpregs = get_gpregs_ctx(tgt_ctx);
+ tgt_el3 = get_el3state_ctx(tgt_ctx);
+
+ CASSERT(sizeof(disp_ctx->x) == (SDEI_SAVED_GPREGS * sizeof(uint64_t)),
+ foo);
+
+ /* Restore general purpose and exception registers */
+ memcpy(tgt_gpregs, disp_ctx->x, sizeof(disp_ctx->x));
+ write_ctx_reg(tgt_el3, CTX_SPSR_EL3, disp_ctx->spsr_el3);
+ write_ctx_reg(tgt_el3, CTX_ELR_EL3, disp_ctx->elr_el3);
+}
+
+static void save_secure_context(void)
+{
+ cm_el1_sysregs_context_save(SECURE);
+}
+
+/* Restore Secure context and arrange to resume it at the next ERET */
+static void restore_and_resume_secure_context(void)
+{
+ cm_el1_sysregs_context_restore(SECURE);
+ cm_set_next_eret_context(SECURE);
+}
+
+/*
+ * Restore Non-secure context and arrange to resume it at the next ERET. Return
+ * pointer to the Non-secure context.
+ */
+static cpu_context_t *restore_and_resume_ns_context(void)
+{
+ cpu_context_t *ns_ctx;
+
+ cm_el1_sysregs_context_restore(NON_SECURE);
+ cm_set_next_eret_context(NON_SECURE);
+
+ ns_ctx = cm_get_context(NON_SECURE);
+ assert(ns_ctx);
+
+ return ns_ctx;
+}
+
+/*
+ * Populate the Non-secure context so that the next ERET will dispatch to the
+ * SDEI client.
+ */
+static void setup_ns_dispatch(sdei_ev_map_t *map, sdei_entry_t *se,
+ cpu_context_t *ctx, int sec_state_to_resume,
+ unsigned int intr_raw)
+{
+ el3_state_t *el3_ctx = get_el3state_ctx(ctx);
+
+ /* Push the event and context */
+ save_event_ctx(map, ctx, sec_state_to_resume, intr_raw);
+
+ /*
+ * Setup handler arguments:
+ *
+ * - x0: Event number
+ * - x1: Handler argument supplied at the time of event registration
+ * - x2: Interrupted PC
+ * - x3: Interrupted SPSR
+ */
+ SMC_SET_GP(ctx, CTX_GPREG_X0, map->ev_num);
+ SMC_SET_GP(ctx, CTX_GPREG_X1, se->arg);
+ SMC_SET_GP(ctx, CTX_GPREG_X2, read_ctx_reg(el3_ctx, CTX_ELR_EL3));
+ SMC_SET_GP(ctx, CTX_GPREG_X3, read_ctx_reg(el3_ctx, CTX_SPSR_EL3));
+
+ /*
+ * Prepare for ERET:
+ *
+ * - Set PC to the registered handler address
+ * - Set SPSR to jump to client EL with exceptions masked
+ */
+ cm_set_elr_spsr_el3(NON_SECURE, (uintptr_t) se->ep,
+ SPSR_64(sdei_client_el(), MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS));
+}
+
+/* Handle a triggered SDEI interrupt while events were masked on this PE */
+static void handle_masked_trigger(sdei_ev_map_t *map, sdei_entry_t *se,
+ sdei_cpu_state_t *state, unsigned int intr_raw)
+{
+ uint64_t my_mpidr __unused = (read_mpidr_el1() & MPIDR_AFFINITY_MASK);
+ int disable = 0;
+
+ /* Nothing to do for event 0 */
+ if (map->ev_num == SDEI_EVENT_0)
+ return;
+
+ /*
+ * For a private event, or for a shared event specifically routed to
+ * this CPU, we disable interrupt, leave the interrupt pending, and do
+ * EOI.
+ */
+ if (is_event_private(map)) {
+ disable = 1;
+ } else if (se->reg_flags == SDEI_REGF_RM_PE) {
+ assert(se->affinity == my_mpidr);
+ disable = 1;
+ }
+
+ if (disable) {
+ plat_ic_disable_interrupt(map->intr);
+ plat_ic_set_interrupt_pending(map->intr);
+ plat_ic_end_of_interrupt(intr_raw);
+ state->pending_enables = 1;
+
+ return;
+ }
+
+ /*
+ * We just received a shared event with routing set to ANY PE. The
+ * interrupt can't be delegated on this PE as SDEI events are masked.
+ * However, because its routing mode is ANY, it is possible that the
+ * event can be delegated on any other PE that hasn't masked events.
+ * Therefore, we set the interrupt back pending so as to give other
+ * suitable PEs a chance of handling it.
+ */
+ assert(plat_ic_is_spi(map->intr));
+ plat_ic_set_interrupt_pending(map->intr);
+
+ /*
+ * Leaving the same interrupt pending also means that the same interrupt
+ * can target this PE again as soon as this PE leaves EL3. Whether and
+ * how often that happens depends on the implementation of GIC.
+ *
+ * We therefore call a platform handler to resolve this situation.
+ */
+ plat_sdei_handle_masked_trigger(my_mpidr, map->intr);
+
+ /* This PE is masked. We EOI the interrupt, as it can't be delegated */
+ plat_ic_end_of_interrupt(intr_raw);
+}
+
+/* SDEI main interrupt handler */
+int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle,
+ void *cookie)
+{
+ sdei_entry_t *se;
+ cpu_context_t *ctx;
+ sdei_ev_map_t *map;
+ sdei_dispatch_context_t *disp_ctx;
+ unsigned int sec_state;
+ sdei_cpu_state_t *state;
+ uint32_t intr;
+
+ /*
+ * To handle an event, the following conditions must be true:
+ *
+ * 1. Event must be signalled
+ * 2. Event must be enabled
+ * 3. This PE must be a target PE for the event
+ * 4. PE must be unmasked for SDEI
+ * 5. If this is a normal event, no event must be running
+ * 6. If this is a critical event, no critical event must be running
+ *
+ * (1) and (2) are true when this function is running
+ * (3) is enforced in GIC by selecting the appropriate routing option
+ * (4) is satisfied by client calling PE_UNMASK
+ * (5) and (6) is enforced using interrupt priority, the RPR, in GIC:
+ * - Normal SDEI events belong to Normal SDE priority class
+ * - Critical SDEI events belong to Critical CSDE priority class
+ *
+ * The interrupt has already been acknowledged, and therefore is active,
+ * so no other PE can handle this event while we are at it.
+ *
+ * Find if this is an SDEI interrupt. There must be an event mapped to
+ * this interrupt
+ */
+ intr = plat_ic_get_interrupt_id(intr_raw);
+ map = find_event_map_by_intr(intr, plat_ic_is_spi(intr));
+ if (!map) {
+ ERROR("No SDEI map for interrupt %u\n", intr);
+ panic();
+ }
+
+ /*
+ * Received interrupt number must either correspond to event 0, or must
+ * be bound interrupt.
+ */
+ assert((map->ev_num == SDEI_EVENT_0) || is_map_bound(map));
+
+ se = get_event_entry(map);
+ state = sdei_get_this_pe_state();
+
+ if (state->pe_masked == PE_MASKED) {
+ /*
+ * Interrupts received while this PE was masked can't be
+ * dispatched.
+ */
+ SDEI_LOG("interrupt %u on %lx while PE masked\n", map->intr,
+ read_mpidr_el1());
+ if (is_event_shared(map))
+ sdei_map_lock(map);
+
+ handle_masked_trigger(map, se, state, intr_raw);
+
+ if (is_event_shared(map))
+ sdei_map_unlock(map);
+
+ return 0;
+ }
+
+ /* Insert load barrier for signalled SDEI event */
+ if (map->ev_num == SDEI_EVENT_0)
+ dmbld();
+
+ if (is_event_shared(map))
+ sdei_map_lock(map);
+
+ /* Assert shared event routed to this PE had been configured so */
+ if (is_event_shared(map) && (se->reg_flags == SDEI_REGF_RM_PE)) {
+ assert(se->affinity ==
+ (read_mpidr_el1() & MPIDR_AFFINITY_MASK));
+ }
+
+ if (!can_sdei_state_trans(se, DO_DISPATCH)) {
+ SDEI_LOG("SDEI event 0x%x can't be dispatched; state=0x%x\n",
+ map->ev_num, se->state);
+
+ /*
+ * If the event is registered, leave the interrupt pending so
+ * that it's delivered when the event is enabled.
+ */
+ if (GET_EV_STATE(se, REGISTERED))
+ plat_ic_set_interrupt_pending(map->intr);
+
+ /*
+ * The interrupt was disabled or unregistered after the handler
+ * started to execute, which means now the interrupt is already
+ * disabled and we just need to EOI the interrupt.
+ */
+ plat_ic_end_of_interrupt(intr_raw);
+
+ if (is_event_shared(map))
+ sdei_map_unlock(map);
+
+ return 0;
+ }
+
+ disp_ctx = get_outstanding_dispatch();
+ if (is_event_critical(map)) {
+ /*
+ * If this event is Critical, and if there's an outstanding
+ * dispatch, assert the latter is a Normal dispatch. Critical
+ * events can preempt an outstanding Normal event dispatch.
+ */
+ if (disp_ctx)
+ assert(is_event_normal(disp_ctx->map));
+ } else {
+ /*
+ * If this event is Normal, assert that there are no outstanding
+ * dispatches. Normal events can't preempt any outstanding event
+ * dispatches.
+ */
+ assert(disp_ctx == NULL);
+ }
+
+ sec_state = get_interrupt_src_ss(flags);
+
+ if (is_event_shared(map))
+ sdei_map_unlock(map);
+
+ SDEI_LOG("ACK %lx, ev:%d ss:%d spsr:%lx ELR:%lx\n", read_mpidr_el1(),
+ map->ev_num, sec_state, read_spsr_el3(),
+ read_elr_el3());
+
+ ctx = handle;
+
+ /*
+ * Check if we interrupted secure state. Perform a context switch so
+ * that we can delegate to NS.
+ */
+ if (sec_state == SECURE) {
+ save_secure_context();
+ ctx = restore_and_resume_ns_context();
+ }
+
+ setup_ns_dispatch(map, se, ctx, sec_state, intr_raw);
+
+ /*
+ * End of interrupt is done in sdei_event_complete, when the client
+ * signals completion.
+ */
+ return 0;
+}
+
+/* Explicitly dispatch the given SDEI event */
+int sdei_dispatch_event(int ev_num, unsigned int preempted_sec_state)
+{
+ sdei_entry_t *se;
+ sdei_ev_map_t *map;
+ cpu_context_t *ctx;
+ sdei_dispatch_context_t *disp_ctx;
+ sdei_cpu_state_t *state;
+
+ /* Validate preempted security state */
+ if ((preempted_sec_state != SECURE) &&
+ (preempted_sec_state != NON_SECURE)) {
+ return -1;
+ }
+
+ /* Can't dispatch if events are masked on this PE */
+ state = sdei_get_this_pe_state();
+ if (state->pe_masked == PE_MASKED)
+ return -1;
+
+ /* Event 0 can't be dispatched */
+ if (ev_num == SDEI_EVENT_0)
+ return -1;
+
+ /* Locate mapping corresponding to this event */
+ map = find_event_map(ev_num);
+ if (!map)
+ return -1;
+
+ /*
+ * Statically-bound or dynamic maps are dispatched only as a result of
+ * interrupt, and not upon explicit request.
+ */
+ if (is_map_dynamic(map) || is_map_bound(map))
+ return -1;
+
+ /* The event must be private */
+ if (is_event_shared(map))
+ return -1;
+
+ /* Examine state of dispatch stack */
+ disp_ctx = get_outstanding_dispatch();
+ if (disp_ctx) {
+ /*
+ * There's an outstanding dispatch. If the outstanding dispatch
+ * is critical, no more dispatches are possible.
+ */
+ if (is_event_critical(disp_ctx->map))
+ return -1;
+
+ /*
+ * If the outstanding dispatch is Normal, only critical events
+ * can be dispatched.
+ */
+ if (is_event_normal(map))
+ return -1;
+ }
+
+ se = get_event_entry(map);
+ if (!can_sdei_state_trans(se, DO_DISPATCH))
+ return -1;
+
+ /* Activate the priority corresponding to the event being dispatched */
+ ehf_activate_priority(sdei_event_priority(map));
+
+ /*
+ * We assume the current context is SECURE, and that it's already been
+ * saved.
+ */
+ ctx = restore_and_resume_ns_context();
+
+ /*
+ * The caller has effectively terminated execution. Record to resume the
+ * preempted context later when the event completes or
+ * complete-and-resumes.
+ */
+ setup_ns_dispatch(map, se, ctx, preempted_sec_state, 0);
+
+ return 0;
+}
+
+int sdei_event_complete(int resume, uint64_t pc)
+{
+ sdei_dispatch_context_t *disp_ctx;
+ sdei_entry_t *se;
+ sdei_ev_map_t *map;
+ cpu_context_t *ctx;
+ sdei_action_t act;
+ unsigned int client_el = sdei_client_el();
+
+ /* Return error if called without an active event */
+ disp_ctx = pop_dispatch();
+ if (!disp_ctx)
+ return SDEI_EDENY;
+
+ /* Validate resumption point */
+ if (resume && (plat_sdei_validate_entry_point(pc, client_el) != 0))
+ return SDEI_EDENY;
+
+ map = disp_ctx->map;
+ assert(map);
+
+ se = get_event_entry(map);
+
+ SDEI_LOG("EOI:%lx, %d spsr:%lx elr:%lx\n", read_mpidr_el1(),
+ map->ev_num, read_spsr_el3(), read_elr_el3());
+
+ if (is_event_shared(map))
+ sdei_map_lock(map);
+
+ act = resume ? DO_COMPLETE_RESUME : DO_COMPLETE;
+ if (!can_sdei_state_trans(se, act)) {
+ if (is_event_shared(map))
+ sdei_map_unlock(map);
+ return SDEI_EDENY;
+ }
+
+ /*
+ * Restore Non-secure to how it was originally interrupted. Once done,
+ * it's up-to-date with the saved copy.
+ */
+ ctx = cm_get_context(NON_SECURE);
+ restore_event_ctx(disp_ctx, ctx);
+
+ if (resume) {
+ /*
+ * Complete-and-resume call. Prepare the Non-secure context
+ * (currently active) for complete and resume.
+ */
+ cm_set_elr_spsr_el3(NON_SECURE, pc, SPSR_64(client_el,
+ MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
+
+ /*
+ * Make it look as if a synchronous exception were taken at the
+ * supplied Non-secure resumption point. Populate SPSR and
+ * ELR_ELx so that an ERET from there works as expected.
+ *
+ * The assumption is that the client, if necessary, would have
+ * saved any live content in these registers before making this
+ * call.
+ */
+ if (client_el == MODE_EL2) {
+ write_elr_el2(disp_ctx->elr_el3);
+ write_spsr_el2(disp_ctx->spsr_el3);
+ } else {
+ /* EL1 */
+ write_elr_el1(disp_ctx->elr_el3);
+ write_spsr_el1(disp_ctx->spsr_el3);
+ }
+ }
+
+ /*
+ * If the cause of dispatch originally interrupted the Secure world, and
+ * if Non-secure world wasn't allowed to preempt Secure execution,
+ * resume Secure.
+ *
+ * No need to save the Non-secure context ahead of a world switch: the
+ * Non-secure context was fully saved before dispatch, and has been
+ * returned to its pre-dispatch state.
+ */
+ if ((disp_ctx->sec_state == SECURE) &&
+ (ehf_is_ns_preemption_allowed() == 0)) {
+ restore_and_resume_secure_context();
+ }
+
+ if ((map->ev_num == SDEI_EVENT_0) || is_map_bound(map)) {
+ /*
+ * The event was dispatched after receiving SDEI interrupt. With
+ * the event handling completed, EOI the corresponding
+ * interrupt.
+ */
+ plat_ic_end_of_interrupt(disp_ctx->intr_raw);
+ } else {
+ /*
+ * An unbound event must have been dispatched explicitly.
+ * Deactivate the priority level that was activated at the time
+ * of explicit dispatch.
+ */
+ ehf_deactivate_priority(sdei_event_priority(map));
+ }
+
+ if (is_event_shared(map))
+ sdei_map_unlock(map);
+
+ return 0;
+}
+
+int sdei_event_context(void *handle, unsigned int param)
+{
+ sdei_dispatch_context_t *disp_ctx;
+
+ if (param >= SDEI_SAVED_GPREGS)
+ return SDEI_EINVAL;
+
+ /* Get outstanding dispatch on this CPU */
+ disp_ctx = get_outstanding_dispatch();
+ if (!disp_ctx)
+ return SDEI_EDENY;
+
+ assert(disp_ctx->map);
+
+ if (!can_sdei_state_trans(get_event_entry(disp_ctx->map), DO_CONTEXT))
+ return SDEI_EDENY;
+
+ /*
+ * No locking is required for the Running status as this is the only CPU
+ * which can complete the event
+ */
+
+ return disp_ctx->x[param];
+}
diff --git a/services/std_svc/sdei/sdei_main.c b/services/std_svc/sdei/sdei_main.c
new file mode 100644
index 00000000..1969307f
--- /dev/null
+++ b/services/std_svc/sdei/sdei_main.c
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl31.h>
+#include <bl_common.h>
+#include <cassert.h>
+#include <context.h>
+#include <context_mgmt.h>
+#include <debug.h>
+#include <ehf.h>
+#include <interrupt_mgmt.h>
+#include <platform.h>
+#include <pubsub.h>
+#include <runtime_svc.h>
+#include <sdei.h>
+#include <stddef.h>
+#include <string.h>
+#include <utils.h>
+#include "sdei_private.h"
+
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 0
+#define VENDOR_VERSION 0
+
+#define MAKE_SDEI_VERSION(_major, _minor, _vendor) \
+ ((((unsigned long long)(_major)) << 48) | \
+ (((unsigned long long)(_minor)) << 32) | \
+ (_vendor))
+
+#define LOWEST_INTR_PRIORITY 0xff
+
+#define is_valid_affinity(_mpidr) (plat_core_pos_by_mpidr(_mpidr) >= 0)
+
+CASSERT(PLAT_SDEI_CRITICAL_PRI < PLAT_SDEI_NORMAL_PRI,
+ sdei_critical_must_have_higher_priority);
+
+static unsigned int num_dyn_priv_slots, num_dyn_shrd_slots;
+
+/* Initialise SDEI map entries */
+static void init_map(sdei_ev_map_t *map)
+{
+ map->reg_count = 0;
+}
+
+/* Convert mapping to SDEI class */
+sdei_class_t map_to_class(sdei_ev_map_t *map)
+{
+ return is_event_critical(map) ? SDEI_CRITICAL : SDEI_NORMAL;
+}
+
+/* Clear SDEI event entries except state */
+static void clear_event_entries(sdei_entry_t *se)
+{
+ se->ep = 0;
+ se->arg = 0;
+ se->affinity = 0;
+ se->reg_flags = 0;
+}
+
+/* Perform CPU-specific state initialisation */
+static void *sdei_cpu_on_init(const void *arg)
+{
+ int i;
+ sdei_ev_map_t *map;
+ sdei_entry_t *se;
+
+ /* Initialize private mappings on this CPU */
+ for_each_private_map(i, map) {
+ se = get_event_entry(map);
+ clear_event_entries(se);
+ se->state = 0;
+ }
+
+ SDEI_LOG("Private events initialized on %lx\n", read_mpidr_el1());
+
+ /* All PEs start with SDEI events masked */
+ sdei_pe_mask();
+
+ return 0;
+}
+
+/* Initialise an SDEI class */
+void sdei_class_init(sdei_class_t class)
+{
+ unsigned int i, zero_found __unused = 0;
+ int ev_num_so_far __unused;
+ sdei_ev_map_t *map;
+
+ /* Sanity check and configuration of shared events */
+ ev_num_so_far = -1;
+ for_each_shared_map(i, map) {
+#if ENABLE_ASSERTIONS
+ /* Ensure mappings are sorted */
+ assert((ev_num_so_far < 0) || (map->ev_num > ev_num_so_far));
+
+ ev_num_so_far = map->ev_num;
+
+ /* Event 0 must not be shared */
+ assert(map->ev_num != SDEI_EVENT_0);
+
+ /* Check for valid event */
+ assert(map->ev_num >= 0);
+
+ /* Make sure it's a shared event */
+ assert(is_event_shared(map));
+
+ /* No shared mapping should have signalable property */
+ assert(!is_event_signalable(map));
+#endif
+
+ /* Skip initializing the wrong priority */
+ if (map_to_class(map) != class)
+ continue;
+
+ /* Platform events are always bound, so set the bound flag */
+ if (is_map_dynamic(map)) {
+ assert(map->intr == SDEI_DYN_IRQ);
+ assert(is_event_normal(map));
+ num_dyn_shrd_slots++;
+ } else {
+ /* Shared mappings must be bound to shared interrupt */
+ assert(plat_ic_is_spi(map->intr));
+ set_map_bound(map);
+ }
+
+ init_map(map);
+ }
+
+ /* Sanity check and configuration of private events for this CPU */
+ ev_num_so_far = -1;
+ for_each_private_map(i, map) {
+#if ENABLE_ASSERTIONS
+ /* Ensure mappings are sorted */
+ assert((ev_num_so_far < 0) || (map->ev_num > ev_num_so_far));
+
+ ev_num_so_far = map->ev_num;
+
+ if (map->ev_num == SDEI_EVENT_0) {
+ zero_found = 1;
+
+ /* Event 0 must be a Secure SGI */
+ assert(is_secure_sgi(map->intr));
+
+ /*
+ * Event 0 can have only have signalable flag (apart
+ * from being private
+ */
+ assert(map->map_flags == (SDEI_MAPF_SIGNALABLE |
+ SDEI_MAPF_PRIVATE));
+ } else {
+ /* No other mapping should have signalable property */
+ assert(!is_event_signalable(map));
+ }
+
+ /* Check for valid event */
+ assert(map->ev_num >= 0);
+
+ /* Make sure it's a private event */
+ assert(is_event_private(map));
+#endif
+
+ /* Skip initializing the wrong priority */
+ if (map_to_class(map) != class)
+ continue;
+
+ /* Platform events are always bound, so set the bound flag */
+ if (map->ev_num != SDEI_EVENT_0) {
+ if (is_map_dynamic(map)) {
+ assert(map->intr == SDEI_DYN_IRQ);
+ assert(is_event_normal(map));
+ num_dyn_priv_slots++;
+ } else {
+ /*
+ * Private mappings must be bound to private
+ * interrupt.
+ */
+ assert(plat_ic_is_ppi(map->intr));
+ set_map_bound(map);
+ }
+ }
+
+ init_map(map);
+ }
+
+ /* Ensure event 0 is in the mapping */
+ assert(zero_found);
+
+ sdei_cpu_on_init(NULL);
+}
+
+/* SDEI dispatcher initialisation */
+void sdei_init(void)
+{
+ sdei_class_init(SDEI_CRITICAL);
+ sdei_class_init(SDEI_NORMAL);
+
+ /* Register priority level handlers */
+ ehf_register_priority_handler(PLAT_SDEI_CRITICAL_PRI,
+ sdei_intr_handler);
+ ehf_register_priority_handler(PLAT_SDEI_NORMAL_PRI,
+ sdei_intr_handler);
+}
+
+/* Populate SDEI event entry */
+static void set_sdei_entry(sdei_entry_t *se, uint64_t ep, uint64_t arg,
+ unsigned int flags, uint64_t affinity)
+{
+ assert(se != NULL);
+
+ se->ep = ep;
+ se->arg = arg;
+ se->affinity = (affinity & MPIDR_AFFINITY_MASK);
+ se->reg_flags = flags;
+}
+
+static unsigned long long sdei_version(void)
+{
+ return MAKE_SDEI_VERSION(MAJOR_VERSION, MINOR_VERSION, VENDOR_VERSION);
+}
+
+/* Validate flags and MPIDR values for REGISTER and ROUTING_SET calls */
+static int validate_flags(uint64_t flags, uint64_t mpidr)
+{
+ /* Validate flags */
+ switch (flags) {
+ case SDEI_REGF_RM_PE:
+ if (!is_valid_affinity(mpidr))
+ return SDEI_EINVAL;
+ break;
+ case SDEI_REGF_RM_ANY:
+ break;
+ default:
+ /* Unknown flags */
+ return SDEI_EINVAL;
+ }
+
+ return 0;
+}
+
+/* Set routing of an SDEI event */
+static int sdei_event_routing_set(int ev_num, uint64_t flags, uint64_t mpidr)
+{
+ int ret, routing;
+ sdei_ev_map_t *map;
+ sdei_entry_t *se;
+
+ ret = validate_flags(flags, mpidr);
+ if (ret)
+ return ret;
+
+ /* Check if valid event number */
+ map = find_event_map(ev_num);
+ if (!map)
+ return SDEI_EINVAL;
+
+ /* The event must not be private */
+ if (is_event_private(map))
+ return SDEI_EINVAL;
+
+ se = get_event_entry(map);
+
+ sdei_map_lock(map);
+
+ if (!is_map_bound(map) || is_event_private(map)) {
+ ret = SDEI_EINVAL;
+ goto finish;
+ }
+
+ if (!can_sdei_state_trans(se, DO_ROUTING)) {
+ ret = SDEI_EDENY;
+ goto finish;
+ }
+
+ /* Choose appropriate routing */
+ routing = (flags == SDEI_REGF_RM_ANY) ? INTR_ROUTING_MODE_ANY :
+ INTR_ROUTING_MODE_PE;
+
+ /* Update event registration flag */
+ se->reg_flags = flags;
+
+ /*
+ * ROUTING_SET is permissible only when event composite state is
+ * 'registered, disabled, and not running'. This means that the
+ * interrupt is currently disabled, and not active.
+ */
+ plat_ic_set_spi_routing(map->intr, routing, (u_register_t) mpidr);
+
+finish:
+ sdei_map_unlock(map);
+
+ return ret;
+}
+
+/* Register handler and argument for an SDEI event */
+static int sdei_event_register(int ev_num, uint64_t ep, uint64_t arg,
+ uint64_t flags, uint64_t mpidr)
+{
+ int ret;
+ sdei_entry_t *se;
+ sdei_ev_map_t *map;
+ sdei_state_t backup_state;
+
+ if (!ep || (plat_sdei_validate_entry_point(ep, sdei_client_el()) != 0))
+ return SDEI_EINVAL;
+
+ ret = validate_flags(flags, mpidr);
+ if (ret)
+ return ret;
+
+ /* Check if valid event number */
+ map = find_event_map(ev_num);
+ if (!map)
+ return SDEI_EINVAL;
+
+ /* Private events always target the PE */
+ if (is_event_private(map))
+ flags = SDEI_REGF_RM_PE;
+
+ se = get_event_entry(map);
+
+ /*
+ * Even though register operation is per-event (additionally for private
+ * events, registration is required individually), it has to be
+ * serialised with respect to bind/release, which are global operations.
+ * So we hold the lock throughout, unconditionally.
+ */
+ sdei_map_lock(map);
+
+ backup_state = se->state;
+ if (!can_sdei_state_trans(se, DO_REGISTER))
+ goto fallback;
+
+ /*
+ * When registering for dynamic events, make sure it's been bound
+ * already. This has to be the case as, without binding, the client
+ * can't know about the event number to register for.
+ */
+ if (is_map_dynamic(map) && !is_map_bound(map))
+ goto fallback;
+
+ if (is_event_private(map)) {
+ /* Multiple calls to register are possible for private events */
+ assert(map->reg_count >= 0);
+ } else {
+ /* Only single call to register is possible for shared events */
+ assert(map->reg_count == 0);
+ }
+
+ if (is_map_bound(map)) {
+ /* Meanwhile, did any PE ACK the interrupt? */
+ if (plat_ic_get_interrupt_active(map->intr))
+ goto fallback;
+
+ /* The interrupt must currently owned by Non-secure */
+ if (plat_ic_get_interrupt_type(map->intr) != INTR_TYPE_NS)
+ goto fallback;
+
+ /*
+ * Disable forwarding of new interrupt triggers to CPU
+ * interface.
+ */
+ plat_ic_disable_interrupt(map->intr);
+
+ /*
+ * Any events that are triggered after register and before
+ * enable should remain pending. Clear any previous interrupt
+ * triggers which are pending (except for SGIs). This has no
+ * affect on level-triggered interrupts.
+ */
+ if (ev_num != SDEI_EVENT_0)
+ plat_ic_clear_interrupt_pending(map->intr);
+
+ /* Map interrupt to EL3 and program the correct priority */
+ plat_ic_set_interrupt_type(map->intr, INTR_TYPE_EL3);
+
+ /* Program the appropriate interrupt priority */
+ plat_ic_set_interrupt_priority(map->intr, sdei_event_priority(map));
+
+ /*
+ * Set the routing mode for shared event as requested. We
+ * already ensure that shared events get bound to SPIs.
+ */
+ if (is_event_shared(map)) {
+ plat_ic_set_spi_routing(map->intr,
+ ((flags == SDEI_REGF_RM_ANY) ?
+ INTR_ROUTING_MODE_ANY :
+ INTR_ROUTING_MODE_PE),
+ (u_register_t) mpidr);
+ }
+ }
+
+ /* Populate event entries */
+ set_sdei_entry(se, ep, arg, flags, mpidr);
+
+ /* Increment register count */
+ map->reg_count++;
+
+ sdei_map_unlock(map);
+
+ return 0;
+
+fallback:
+ /* Reinstate previous state */
+ se->state = backup_state;
+
+ sdei_map_unlock(map);
+
+ return SDEI_EDENY;
+}
+
+/* Enable SDEI event */
+static int sdei_event_enable(int ev_num)
+{
+ sdei_ev_map_t *map;
+ sdei_entry_t *se;
+ int ret, before, after;
+
+ /* Check if valid event number */
+ map = find_event_map(ev_num);
+ if (!map)
+ return SDEI_EINVAL;
+
+ se = get_event_entry(map);
+ ret = SDEI_EDENY;
+
+ if (is_event_shared(map))
+ sdei_map_lock(map);
+
+ before = GET_EV_STATE(se, ENABLED);
+ if (!can_sdei_state_trans(se, DO_ENABLE))
+ goto finish;
+ after = GET_EV_STATE(se, ENABLED);
+
+ /*
+ * Enable interrupt for bound events only if there's a change in enabled
+ * state.
+ */
+ if (is_map_bound(map) && (!before && after))
+ plat_ic_enable_interrupt(map->intr);
+
+ ret = 0;
+
+finish:
+ if (is_event_shared(map))
+ sdei_map_unlock(map);
+
+ return ret;
+}
+
+/* Disable SDEI event */
+static int sdei_event_disable(int ev_num)
+{
+ sdei_ev_map_t *map;
+ sdei_entry_t *se;
+ int ret, before, after;
+
+ /* Check if valid event number */
+ map = find_event_map(ev_num);
+ if (!map)
+ return SDEI_EINVAL;
+
+ se = get_event_entry(map);
+ ret = SDEI_EDENY;
+
+ if (is_event_shared(map))
+ sdei_map_lock(map);
+
+ before = GET_EV_STATE(se, ENABLED);
+ if (!can_sdei_state_trans(se, DO_DISABLE))
+ goto finish;
+ after = GET_EV_STATE(se, ENABLED);
+
+ /*
+ * Disable interrupt for bound events only if there's a change in
+ * enabled state.
+ */
+ if (is_map_bound(map) && (before && !after))
+ plat_ic_disable_interrupt(map->intr);
+
+ ret = 0;
+
+finish:
+ if (is_event_shared(map))
+ sdei_map_unlock(map);
+
+ return ret;
+}
+
+/* Query SDEI event information */
+static uint64_t sdei_event_get_info(int ev_num, int info)
+{
+ sdei_entry_t *se;
+ sdei_ev_map_t *map;
+
+ unsigned int flags, registered;
+ uint64_t affinity;
+
+ /* Check if valid event number */
+ map = find_event_map(ev_num);
+ if (!map)
+ return SDEI_EINVAL;
+
+ se = get_event_entry(map);
+
+ if (is_event_shared(map))
+ sdei_map_lock(map);
+
+ /* Sample state under lock */
+ registered = GET_EV_STATE(se, REGISTERED);
+ flags = se->reg_flags;
+ affinity = se->affinity;
+
+ if (is_event_shared(map))
+ sdei_map_unlock(map);
+
+ switch (info) {
+ case SDEI_INFO_EV_TYPE:
+ return is_event_shared(map);
+
+ case SDEI_INFO_EV_NOT_SIGNALED:
+ return !is_event_signalable(map);
+
+ case SDEI_INFO_EV_PRIORITY:
+ return is_event_critical(map);
+
+ case SDEI_INFO_EV_ROUTING_MODE:
+ if (!is_event_shared(map))
+ return SDEI_EINVAL;
+ if (!registered)
+ return SDEI_EDENY;
+ return (flags == SDEI_REGF_RM_PE);
+
+ case SDEI_INFO_EV_ROUTING_AFF:
+ if (!is_event_shared(map))
+ return SDEI_EINVAL;
+ if (!registered)
+ return SDEI_EDENY;
+ if (flags != SDEI_REGF_RM_PE)
+ return SDEI_EINVAL;
+ return affinity;
+
+ default:
+ return SDEI_EINVAL;
+ }
+}
+
+/* Unregister an SDEI event */
+static int sdei_event_unregister(int ev_num)
+{
+ int ret = 0;
+ sdei_entry_t *se;
+ sdei_ev_map_t *map;
+
+ /* Check if valid event number */
+ map = find_event_map(ev_num);
+ if (!map)
+ return SDEI_EINVAL;
+
+ se = get_event_entry(map);
+
+ /*
+ * Even though unregister operation is per-event (additionally for
+ * private events, unregistration is required individually), it has to
+ * be serialised with respect to bind/release, which are global
+ * operations. So we hold the lock throughout, unconditionally.
+ */
+ sdei_map_lock(map);
+
+ if (!can_sdei_state_trans(se, DO_UNREGISTER)) {
+ /*
+ * Even if the call is invalid, and the handler is running (for
+ * example, having unregistered from a running handler earlier),
+ * return pending error code; otherwise, return deny.
+ */
+ ret = GET_EV_STATE(se, RUNNING) ? SDEI_EPEND : SDEI_EDENY;
+
+ goto finish;
+ }
+
+ map->reg_count--;
+ if (is_event_private(map)) {
+ /* Multiple calls to register are possible for private events */
+ assert(map->reg_count >= 0);
+ } else {
+ /* Only single call to register is possible for shared events */
+ assert(map->reg_count == 0);
+ }
+
+ if (is_map_bound(map)) {
+ plat_ic_disable_interrupt(map->intr);
+
+ /*
+ * Clear pending interrupt. Skip for SGIs as they may not be
+ * cleared on interrupt controllers.
+ */
+ if (ev_num != SDEI_EVENT_0)
+ plat_ic_clear_interrupt_pending(map->intr);
+
+ assert(plat_ic_get_interrupt_type(map->intr) == INTR_TYPE_EL3);
+ plat_ic_set_interrupt_type(map->intr, INTR_TYPE_NS);
+ plat_ic_set_interrupt_priority(map->intr, LOWEST_INTR_PRIORITY);
+ }
+
+ clear_event_entries(se);
+
+ /*
+ * If the handler is running at the time of unregister, return the
+ * pending error code.
+ */
+ if (GET_EV_STATE(se, RUNNING))
+ ret = SDEI_EPEND;
+
+finish:
+ sdei_map_unlock(map);
+
+ return ret;
+}
+
+/* Query status of an SDEI event */
+static int sdei_event_status(int ev_num)
+{
+ sdei_ev_map_t *map;
+ sdei_entry_t *se;
+ sdei_state_t state;
+
+ /* Check if valid event number */
+ map = find_event_map(ev_num);
+ if (!map)
+ return SDEI_EINVAL;
+
+ se = get_event_entry(map);
+
+ if (is_event_shared(map))
+ sdei_map_lock(map);
+
+ /* State value directly maps to the expected return format */
+ state = se->state;
+
+ if (is_event_shared(map))
+ sdei_map_unlock(map);
+
+ return state;
+}
+
+/* Bind an SDEI event to an interrupt */
+static int sdei_interrupt_bind(int intr_num)
+{
+ sdei_ev_map_t *map;
+ int retry = 1, shared_mapping;
+
+ /* SGIs are not allowed to be bound */
+ if (plat_ic_is_sgi(intr_num))
+ return SDEI_EINVAL;
+
+ shared_mapping = plat_ic_is_spi(intr_num);
+ do {
+ /*
+ * Bail out if there is already an event for this interrupt,
+ * either platform-defined or dynamic.
+ */
+ map = find_event_map_by_intr(intr_num, shared_mapping);
+ if (map) {
+ if (is_map_dynamic(map)) {
+ if (is_map_bound(map)) {
+ /*
+ * Dynamic event, already bound. Return
+ * event number.
+ */
+ return map->ev_num;
+ }
+ } else {
+ /* Binding non-dynamic event */
+ return SDEI_EINVAL;
+ }
+ }
+
+ /*
+ * The interrupt is not bound yet. Try to find a free slot to
+ * bind it. Free dynamic mappings have their interrupt set as
+ * SDEI_DYN_IRQ.
+ */
+ map = find_event_map_by_intr(SDEI_DYN_IRQ, shared_mapping);
+ if (!map)
+ return SDEI_ENOMEM;
+
+ /* The returned mapping must be dynamic */
+ assert(is_map_dynamic(map));
+
+ /*
+ * We cannot assert for bound maps here, as we might be racing
+ * with another bind.
+ */
+
+ /* The requested interrupt must already belong to NS */
+ if (plat_ic_get_interrupt_type(intr_num) != INTR_TYPE_NS)
+ return SDEI_EDENY;
+
+ /*
+ * Interrupt programming and ownership transfer are deferred
+ * until register.
+ */
+
+ sdei_map_lock(map);
+ if (!is_map_bound(map)) {
+ map->intr = intr_num;
+ set_map_bound(map);
+ retry = 0;
+ }
+ sdei_map_unlock(map);
+ } while (retry);
+
+ return map->ev_num;
+}
+
+/* Release a bound SDEI event previously to an interrupt */
+static int sdei_interrupt_release(int ev_num)
+{
+ int ret = 0;
+ sdei_ev_map_t *map;
+ sdei_entry_t *se;
+
+ /* Check if valid event number */
+ map = find_event_map(ev_num);
+ if (!map)
+ return SDEI_EINVAL;
+
+ if (!is_map_dynamic(map))
+ return SDEI_EINVAL;
+
+ se = get_event_entry(map);
+
+ sdei_map_lock(map);
+
+ /* Event must have been unregistered before release */
+ if (map->reg_count != 0) {
+ ret = SDEI_EDENY;
+ goto finish;
+ }
+
+ /*
+ * Interrupt release never causes the state to change. We only check
+ * whether it's permissible or not.
+ */
+ if (!can_sdei_state_trans(se, DO_RELEASE)) {
+ ret = SDEI_EDENY;
+ goto finish;
+ }
+
+ if (is_map_bound(map)) {
+ /*
+ * Deny release if the interrupt is active, which means it's
+ * probably being acknowledged and handled elsewhere.
+ */
+ if (plat_ic_get_interrupt_active(map->intr)) {
+ ret = SDEI_EDENY;
+ goto finish;
+ }
+
+ /*
+ * Interrupt programming and ownership transfer are already done
+ * during unregister.
+ */
+
+ map->intr = SDEI_DYN_IRQ;
+ clr_map_bound(map);
+ } else {
+ SDEI_LOG("Error release bound:%d cnt:%d\n", is_map_bound(map),
+ map->reg_count);
+ ret = SDEI_EINVAL;
+ }
+
+finish:
+ sdei_map_unlock(map);
+
+ return ret;
+}
+
+/* Perform reset of private SDEI events */
+static int sdei_private_reset(void)
+{
+ sdei_ev_map_t *map;
+ int ret = 0, final_ret = 0, i;
+
+ /* Unregister all private events */
+ for_each_private_map(i, map) {
+ /*
+ * The unregister can fail if the event is not registered, which
+ * is allowed, and a deny will be returned. But if the event is
+ * running or unregister pending, the call fails.
+ */
+ ret = sdei_event_unregister(map->ev_num);
+ if ((ret == SDEI_EPEND) && (final_ret == 0))
+ final_ret = SDEI_EDENY;
+ }
+
+ return final_ret;
+}
+
+/* Perform reset of shared SDEI events */
+static int sdei_shared_reset(void)
+{
+ const sdei_mapping_t *mapping;
+ sdei_ev_map_t *map;
+ int ret = 0, final_ret = 0, i, j;
+
+ /* Unregister all shared events */
+ for_each_shared_map(i, map) {
+ /*
+ * The unregister can fail if the event is not registered, which
+ * is allowed, and a deny will be returned. But if the event is
+ * running or unregister pending, the call fails.
+ */
+ ret = sdei_event_unregister(map->ev_num);
+ if ((ret == SDEI_EPEND) && (final_ret == 0))
+ final_ret = SDEI_EDENY;
+ }
+
+ if (final_ret != 0)
+ return final_ret;
+
+ /*
+ * Loop through both private and shared mappings, and release all
+ * bindings.
+ */
+ for_each_mapping_type(i, mapping) {
+ iterate_mapping(mapping, j, map) {
+ /*
+ * Release bindings for mappings that are dynamic and
+ * bound.
+ */
+ if (is_map_dynamic(map) && is_map_bound(map)) {
+ /*
+ * Any failure to release would mean there is at
+ * least a PE registered for the event.
+ */
+ ret = sdei_interrupt_release(map->ev_num);
+ if ((ret != 0) && (final_ret == 0))
+ final_ret = ret;
+ }
+ }
+ }
+
+ return final_ret;
+}
+
+/* Send a signal to another SDEI client PE */
+int sdei_signal(int event, uint64_t target_pe)
+{
+ sdei_ev_map_t *map;
+
+ /* Only event 0 can be signalled */
+ if (event != SDEI_EVENT_0)
+ return SDEI_EINVAL;
+
+ /* Find mapping for event 0 */
+ map = find_event_map(SDEI_EVENT_0);
+ if (!map)
+ return SDEI_EINVAL;
+
+ /* The event must be signalable */
+ if (!is_event_signalable(map))
+ return SDEI_EINVAL;
+
+ /* Validate target */
+ if (plat_core_pos_by_mpidr(target_pe) < 0)
+ return SDEI_EINVAL;
+
+ /* Raise SGI. Platform will validate target_pe */
+ plat_ic_raise_el3_sgi(map->intr, (u_register_t) target_pe);
+
+ return 0;
+}
+
+/* Query SDEI dispatcher features */
+uint64_t sdei_features(unsigned int feature)
+{
+ if (feature == SDEI_FEATURE_BIND_SLOTS) {
+ return FEATURE_BIND_SLOTS(num_dyn_priv_slots,
+ num_dyn_shrd_slots);
+ }
+
+ return SDEI_EINVAL;
+}
+
+/* SDEI top level handler for servicing SMCs */
+uint64_t sdei_smc_handler(uint32_t smc_fid,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+
+ uint64_t x5;
+ int ss = get_interrupt_src_ss(flags);
+ int64_t ret;
+ unsigned int resume = 0;
+
+ if (ss != NON_SECURE)
+ SMC_RET1(handle, SMC_UNK);
+
+ /* Verify the caller EL */
+ if (GET_EL(read_spsr_el3()) != sdei_client_el())
+ SMC_RET1(handle, SMC_UNK);
+
+ switch (smc_fid) {
+ case SDEI_VERSION:
+ SDEI_LOG("> VER\n");
+ ret = sdei_version();
+ SDEI_LOG("< VER:%lx\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_EVENT_REGISTER:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ SDEI_LOG("> REG(n:%d e:%lx a:%lx f:%x m:%lx)\n", (int) x1,
+ x2, x3, (int) x4, x5);
+ ret = sdei_event_register(x1, x2, x3, x4, x5);
+ SDEI_LOG("< REG:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_EVENT_ENABLE:
+ SDEI_LOG("> ENABLE(n:%d)\n", (int) x1);
+ ret = sdei_event_enable(x1);
+ SDEI_LOG("< ENABLE:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_EVENT_DISABLE:
+ SDEI_LOG("> DISABLE(n:%d)\n", (int) x1);
+ ret = sdei_event_disable(x1);
+ SDEI_LOG("< DISABLE:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_EVENT_CONTEXT:
+ SDEI_LOG("> CTX(p:%d):%lx\n", (int) x1, read_mpidr_el1());
+ ret = sdei_event_context(handle, x1);
+ SDEI_LOG("< CTX:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_EVENT_COMPLETE_AND_RESUME:
+ resume = 1;
+ /* Fall through */
+
+ case SDEI_EVENT_COMPLETE:
+ SDEI_LOG("> COMPLETE(r:%d sta/ep:%lx):%lx\n", resume, x1,
+ read_mpidr_el1());
+ ret = sdei_event_complete(resume, x1);
+ SDEI_LOG("< COMPLETE:%lx\n", ret);
+
+ /*
+ * Set error code only if the call failed. If the call
+ * succeeded, we discard the dispatched context, and restore the
+ * interrupted context to a pristine condition, and therefore
+ * shouldn't be modified. We don't return to the caller in this
+ * case anyway.
+ */
+ if (ret)
+ SMC_RET1(handle, ret);
+
+ SMC_RET0(handle);
+ break;
+
+ case SDEI_EVENT_STATUS:
+ SDEI_LOG("> STAT(n:%d)\n", (int) x1);
+ ret = sdei_event_status(x1);
+ SDEI_LOG("< STAT:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_EVENT_GET_INFO:
+ SDEI_LOG("> INFO(n:%d, %d)\n", (int) x1, (int) x2);
+ ret = sdei_event_get_info(x1, x2);
+ SDEI_LOG("< INFO:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_EVENT_UNREGISTER:
+ SDEI_LOG("> UNREG(n:%d)\n", (int) x1);
+ ret = sdei_event_unregister(x1);
+ SDEI_LOG("< UNREG:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_PE_UNMASK:
+ SDEI_LOG("> UNMASK:%lx\n", read_mpidr_el1());
+ sdei_pe_unmask();
+ SDEI_LOG("< UNMASK:%d\n", 0);
+ SMC_RET1(handle, 0);
+ break;
+
+ case SDEI_PE_MASK:
+ SDEI_LOG("> MASK:%lx\n", read_mpidr_el1());
+ ret = sdei_pe_mask();
+ SDEI_LOG("< MASK:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_INTERRUPT_BIND:
+ SDEI_LOG("> BIND(%d)\n", (int) x1);
+ ret = sdei_interrupt_bind(x1);
+ SDEI_LOG("< BIND:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_INTERRUPT_RELEASE:
+ SDEI_LOG("> REL(%d)\n", (int) x1);
+ ret = sdei_interrupt_release(x1);
+ SDEI_LOG("< REL:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_SHARED_RESET:
+ SDEI_LOG("> S_RESET():%lx\n", read_mpidr_el1());
+ ret = sdei_shared_reset();
+ SDEI_LOG("< S_RESET:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_PRIVATE_RESET:
+ SDEI_LOG("> P_RESET():%lx\n", read_mpidr_el1());
+ ret = sdei_private_reset();
+ SDEI_LOG("< P_RESET:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_EVENT_ROUTING_SET:
+ SDEI_LOG("> ROUTE_SET(n:%d f:%lx aff:%lx)\n", (int) x1, x2, x3);
+ ret = sdei_event_routing_set(x1, x2, x3);
+ SDEI_LOG("< ROUTE_SET:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_FEATURES:
+ SDEI_LOG("> FTRS(f:%lx)\n", x1);
+ ret = sdei_features(x1);
+ SDEI_LOG("< FTRS:%lx\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+
+ case SDEI_EVENT_SIGNAL:
+ SDEI_LOG("> SIGNAL(e:%lx t:%lx)\n", x1, x2);
+ ret = sdei_signal(x1, x2);
+ SDEI_LOG("< SIGNAL:%ld\n", ret);
+ SMC_RET1(handle, ret);
+ break;
+ default:
+ break;
+ }
+
+ WARN("Unimplemented SDEI Call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+}
+
+/* Subscribe to PSCI CPU on to initialize per-CPU SDEI configuration */
+SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, sdei_cpu_on_init);
diff --git a/services/std_svc/sdei/sdei_private.h b/services/std_svc/sdei/sdei_private.h
new file mode 100644
index 00000000..44db4193
--- /dev/null
+++ b/services/std_svc/sdei/sdei_private.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SDEI_PRIVATE_H__
+#define __SDEI_PRIVATE_H__
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <errno.h>
+#include <interrupt_mgmt.h>
+#include <platform.h>
+#include <sdei.h>
+#include <spinlock.h>
+#include <stdbool.h>
+#include <types.h>
+#include <utils_def.h>
+
+#ifdef AARCH32
+# error SDEI is implemented only for AArch64 systems
+#endif
+
+#ifndef PLAT_SDEI_CRITICAL_PRI
+# error Platform must define SDEI critical priority value
+#endif
+
+#ifndef PLAT_SDEI_NORMAL_PRI
+# error Platform must define SDEI normal priority value
+#endif
+
+/* Output SDEI logs as verbose */
+#define SDEI_LOG(...) VERBOSE("SDEI: " __VA_ARGS__)
+
+/* SDEI handler unregistered state. This is the default state. */
+#define SDEI_STATE_UNREGISTERED 0
+
+/* SDE event status values in bit position */
+#define SDEI_STATF_REGISTERED 0
+#define SDEI_STATF_ENABLED 1
+#define SDEI_STATF_RUNNING 2
+
+/* SDEI SMC error codes */
+#define SDEI_EINVAL (-2)
+#define SDEI_EDENY (-3)
+#define SDEI_EPEND (-5)
+#define SDEI_ENOMEM (-10)
+
+/*
+ * 'info' parameter to SDEI_EVENT_GET_INFO SMC.
+ *
+ * Note that the SDEI v1.0 speification mistakenly enumerates the
+ * SDEI_INFO_EV_SIGNALED as SDEI_INFO_SIGNALED. This will be corrected in a
+ * future version.
+ */
+#define SDEI_INFO_EV_TYPE 0
+#define SDEI_INFO_EV_NOT_SIGNALED 1
+#define SDEI_INFO_EV_PRIORITY 2
+#define SDEI_INFO_EV_ROUTING_MODE 3
+#define SDEI_INFO_EV_ROUTING_AFF 4
+
+#define SDEI_PRIVATE_MAPPING() (&sdei_global_mappings[_SDEI_MAP_IDX_PRIV])
+#define SDEI_SHARED_MAPPING() (&sdei_global_mappings[_SDEI_MAP_IDX_SHRD])
+
+#define for_each_mapping_type(_i, _mapping) \
+ for (_i = 0, _mapping = &sdei_global_mappings[i]; \
+ _i < _SDEI_MAP_IDX_MAX; \
+ _i++, _mapping = &sdei_global_mappings[i])
+
+#define iterate_mapping(_mapping, _i, _map) \
+ for (_map = (_mapping)->map, _i = 0; \
+ _i < (_mapping)->num_maps; \
+ _i++, _map++)
+
+#define for_each_private_map(_i, _map) \
+ iterate_mapping(SDEI_PRIVATE_MAPPING(), _i, _map)
+
+#define for_each_shared_map(_i, _map) \
+ iterate_mapping(SDEI_SHARED_MAPPING(), _i, _map)
+
+/* SDEI_FEATURES */
+#define SDEI_FEATURE_BIND_SLOTS 0
+#define BIND_SLOTS_MASK 0xffff
+#define FEATURES_SHARED_SLOTS_SHIFT 16
+#define FEATURES_PRIVATE_SLOTS_SHIFT 0
+#define FEATURE_BIND_SLOTS(_priv, _shrd) \
+ ((((_priv) & BIND_SLOTS_MASK) << FEATURES_PRIVATE_SLOTS_SHIFT) | \
+ (((_shrd) & BIND_SLOTS_MASK) << FEATURES_SHARED_SLOTS_SHIFT))
+
+#define GET_EV_STATE(_e, _s) get_ev_state_bit(_e, SDEI_STATF_##_s)
+#define SET_EV_STATE(_e, _s) clr_ev_state_bit(_e->state, SDEI_STATF_##_s)
+
+static inline int is_event_private(sdei_ev_map_t *map)
+{
+ return ((map->map_flags & BIT(_SDEI_MAPF_PRIVATE_SHIFT)) != 0);
+}
+
+static inline int is_event_shared(sdei_ev_map_t *map)
+{
+ return !is_event_private(map);
+}
+
+static inline int is_event_critical(sdei_ev_map_t *map)
+{
+ return ((map->map_flags & BIT(_SDEI_MAPF_CRITICAL_SHIFT)) != 0);
+}
+
+static inline int is_event_normal(sdei_ev_map_t *map)
+{
+ return !is_event_critical(map);
+}
+
+static inline int is_event_signalable(sdei_ev_map_t *map)
+{
+ return ((map->map_flags & BIT(_SDEI_MAPF_SIGNALABLE_SHIFT)) != 0);
+}
+
+static inline int is_map_dynamic(sdei_ev_map_t *map)
+{
+ return ((map->map_flags & BIT(_SDEI_MAPF_DYNAMIC_SHIFT)) != 0);
+}
+
+/*
+ * Checks whether an event is associated with an interrupt. Static events always
+ * return true, and dynamic events return whether SDEI_INTERRUPT_BIND had been
+ * called on them. This can be used on both static or dynamic events to check
+ * for an associated interrupt.
+ */
+static inline int is_map_bound(sdei_ev_map_t *map)
+{
+ return ((map->map_flags & BIT(_SDEI_MAPF_BOUND_SHIFT)) != 0);
+}
+
+static inline void set_map_bound(sdei_ev_map_t *map)
+{
+ map->map_flags |= BIT(_SDEI_MAPF_BOUND_SHIFT);
+}
+
+static inline void clr_map_bound(sdei_ev_map_t *map)
+{
+ map->map_flags &= ~(BIT(_SDEI_MAPF_BOUND_SHIFT));
+}
+
+static inline int is_secure_sgi(unsigned int intr)
+{
+ return (plat_ic_is_sgi(intr) &&
+ (plat_ic_get_interrupt_type(intr) == INTR_TYPE_EL3));
+}
+
+/*
+ * Determine EL of the client. If EL2 is implemented (hence the enabled HCE
+ * bit), deem EL2; otherwise, deem EL1.
+ */
+static inline unsigned int sdei_client_el(void)
+{
+ return read_scr_el3() & SCR_HCE_BIT ? MODE_EL2 : MODE_EL1;
+}
+
+static inline unsigned int sdei_event_priority(sdei_ev_map_t *map)
+{
+ return is_event_critical(map) ? PLAT_SDEI_CRITICAL_PRI :
+ PLAT_SDEI_NORMAL_PRI;
+}
+
+static inline int get_ev_state_bit(sdei_entry_t *se, unsigned int bit_no)
+{
+ return ((se->state & BIT(bit_no)) != 0);
+}
+
+static inline void clr_ev_state_bit(sdei_entry_t *se, unsigned int bit_no)
+{
+ se->state &= ~BIT(bit_no);
+}
+
+/* SDEI actions for state transition */
+typedef enum {
+ /*
+ * Actions resulting from client requests. These directly map to SMC
+ * calls. Note that the state table columns are listed in this order
+ * too.
+ */
+ DO_REGISTER = 0,
+ DO_RELEASE = 1,
+ DO_ENABLE = 2,
+ DO_DISABLE = 3,
+ DO_UNREGISTER = 4,
+ DO_ROUTING = 5,
+ DO_CONTEXT = 6,
+ DO_COMPLETE = 7,
+ DO_COMPLETE_RESUME = 8,
+
+ /* Action for event dispatch */
+ DO_DISPATCH = 9,
+
+ DO_MAX,
+} sdei_action_t;
+
+typedef enum {
+ SDEI_NORMAL,
+ SDEI_CRITICAL
+} sdei_class_t;
+
+static inline void sdei_map_lock(sdei_ev_map_t *map)
+{
+ spin_lock(&map->lock);
+}
+
+static inline void sdei_map_unlock(sdei_ev_map_t *map)
+{
+ spin_unlock(&map->lock);
+}
+
+extern const sdei_mapping_t sdei_global_mappings[];
+extern sdei_entry_t sdei_private_event_table[];
+extern sdei_entry_t sdei_shared_event_table[];
+
+void init_sdei_state(void);
+
+sdei_ev_map_t *find_event_map_by_intr(int intr_num, int shared);
+sdei_ev_map_t *find_event_map(int ev_num);
+sdei_entry_t *get_event_entry(sdei_ev_map_t *map);
+
+int sdei_event_context(void *handle, unsigned int param);
+int sdei_event_complete(int resume, uint64_t arg);
+
+void sdei_pe_unmask(void);
+unsigned int sdei_pe_mask(void);
+
+int sdei_intr_handler(uint32_t intr, uint32_t flags, void *handle,
+ void *cookie);
+bool can_sdei_state_trans(sdei_entry_t *se, sdei_action_t act);
+
+#endif /* __SDEI_PRIVATE_H__ */
diff --git a/services/std_svc/sdei/sdei_state.c b/services/std_svc/sdei/sdei_state.c
new file mode 100644
index 00000000..3f60dfd8
--- /dev/null
+++ b/services/std_svc/sdei/sdei_state.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cassert.h>
+#include <stdbool.h>
+#include "sdei_private.h"
+
+/* Aliases for SDEI handler states: 'R'unning, 'E'nabled, and re'G'istered */
+#define r_ 0
+#define R_ (1u << SDEI_STATF_RUNNING)
+
+#define e_ 0
+#define E_ (1u << SDEI_STATF_ENABLED)
+
+#define g_ 0
+#define G_ (1u << SDEI_STATF_REGISTERED)
+
+/* All possible composite handler states */
+#define reg_ (r_ | e_ | g_)
+#define reG_ (r_ | e_ | G_)
+#define rEg_ (r_ | E_ | g_)
+#define rEG_ (r_ | E_ | G_)
+#define Reg_ (R_ | e_ | g_)
+#define ReG_ (R_ | e_ | G_)
+#define REg_ (R_ | E_ | g_)
+#define REG_ (R_ | E_ | G_)
+
+#define MAX_STATES (REG_ + 1)
+
+/* Invalid state */
+#define SDEI_STATE_INVALID ((sdei_state_t) (-1))
+
+/* No change in state */
+#define SDEI_STATE_NOP ((sdei_state_t) (-2))
+
+#define X___ SDEI_STATE_INVALID
+#define NOP_ SDEI_STATE_NOP
+
+/* Ensure special states don't overlap with valid ones */
+CASSERT(X___ > REG_, sdei_state_overlap_invalid);
+CASSERT(NOP_ > REG_, sdei_state_overlap_nop);
+
+/*
+ * SDEI handler state machine: refer to sections 6.1 and 6.1.2 of the SDEI v1.0
+ * specification:
+ *
+ * http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
+ *
+ * Not all calls contribute to handler state transition. This table is also used
+ * to validate whether a call is permissible at a given handler state:
+ *
+ * - X___ denotes a forbidden transition;
+ * - NOP_ denotes a permitted transition, but there's no change in state;
+ * - Otherwise, XXX_ gives the new state.
+ *
+ * DISP[atch] is a transition added for the implementation, but is not mentioned
+ * in the spec.
+ *
+ * Those calls that the spec mentions as can be made any time don't picture in
+ * this table.
+ */
+
+static const sdei_state_t sdei_state_table[MAX_STATES][DO_MAX] = {
+/*
+ * Action: REG REL ENA DISA UREG ROUT CTX COMP COMPR DISP
+ * Notes: [3] [1] [3] [3][4] [2]
+ */
+ /* Handler unregistered, disabled, and not running. This is the default state. */
+/* 0 */ [reg_] = { reG_, NOP_, X___, X___, X___, X___, X___, X___, X___, X___, },
+
+ /* Handler unregistered and running */
+/* 4 */ [Reg_] = { X___, X___, X___, X___, X___, X___, NOP_, reg_, reg_, X___, },
+
+ /* Handler registered */
+/* 1 */ [reG_] = { X___, X___, rEG_, NOP_, reg_, NOP_, X___, X___, X___, X___, },
+
+ /* Handler registered and running */
+/* 5 */ [ReG_] = { X___, X___, REG_, NOP_, Reg_, X___, NOP_, reG_, reG_, X___, },
+
+ /* Handler registered and enabled */
+/* 3 */ [rEG_] = { X___, X___, NOP_, reG_, reg_, X___, X___, X___, X___, REG_, },
+
+ /* Handler registered, enabled, and running */
+/* 7 */ [REG_] = { X___, X___, NOP_, ReG_, Reg_, X___, NOP_, rEG_, rEG_, X___, },
+
+ /*
+ * Invalid states: no valid transition would leave the handler in these
+ * states; and no transition from these states is possible either.
+ */
+
+ /*
+ * Handler can't be enabled without being registered. I.e., XEg is
+ * impossible.
+ */
+/* 2 */ [rEg_] = { X___, X___, X___, X___, X___, X___, X___, X___, X___, X___, },
+/* 6 */ [REg_] = { X___, X___, X___, X___, X___, X___, X___, X___, X___, X___, },
+};
+
+/*
+ * [1] Unregister will always also disable the event, so the new state will have
+ * Xeg.
+ * [2] Event is considered for dispatch only when it's both registered and
+ * enabled.
+ * [3] Never causes change in state.
+ * [4] Only allowed when running.
+ */
+
+/*
+ * Given an action, transition the state of an event by looking up the state
+ * table above:
+ *
+ * - Return false for invalid transition;
+ * - Return true for valid transition that causes no change in state;
+ * - Otherwise, update state and return true.
+ *
+ * This function assumes that the caller holds necessary locks. If the
+ * transition has constrains other than the state table describes, the caller is
+ * expected to restore the previous state. See sdei_event_register() for
+ * example.
+ */
+bool can_sdei_state_trans(sdei_entry_t *se, sdei_action_t act)
+{
+ sdei_state_t next;
+
+ assert(act < DO_MAX);
+ if (se->state >= MAX_STATES) {
+ WARN(" event state invalid: %x\n", se->state);
+ return false;
+ }
+
+ next = sdei_state_table[se->state][act];
+ switch (next) {
+ case SDEI_STATE_INVALID:
+ return false;
+
+ case SDEI_STATE_NOP:
+ return true;
+
+ default:
+ /* Valid transition. Update state. */
+ SDEI_LOG(" event state 0x%x => 0x%x\n", se->state, next);
+ se->state = next;
+
+ return true;
+ }
+}
diff --git a/services/std_svc/spm/aarch64/spm_helpers.S b/services/std_svc/spm/aarch64/spm_helpers.S
new file mode 100644
index 00000000..aa35811f
--- /dev/null
+++ b/services/std_svc/spm/aarch64/spm_helpers.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include "../spm_private.h"
+
+ .global spm_secure_partition_enter
+ .global spm_secure_partition_exit
+
+ /* ---------------------------------------------------------------------
+ * This function is called with SP_EL0 as stack. Here we stash our EL3
+ * callee-saved registers on to the stack as a part of saving the C
+ * runtime and enter the secure payload.
+ * 'x0' contains a pointer to the memory where the address of the C
+ * runtime context is to be saved.
+ * ---------------------------------------------------------------------
+ */
+func spm_secure_partition_enter
+ /* Make space for the registers that we're going to save */
+ mov x3, sp
+ str x3, [x0, #0]
+ sub sp, sp, #SP_C_RT_CTX_SIZE
+
+ /* Save callee-saved registers on to the stack */
+ stp x19, x20, [sp, #SP_C_RT_CTX_X19]
+ stp x21, x22, [sp, #SP_C_RT_CTX_X21]
+ stp x23, x24, [sp, #SP_C_RT_CTX_X23]
+ stp x25, x26, [sp, #SP_C_RT_CTX_X25]
+ stp x27, x28, [sp, #SP_C_RT_CTX_X27]
+ stp x29, x30, [sp, #SP_C_RT_CTX_X29]
+
+ /* ---------------------------------------------------------------------
+ * Everything is setup now. el3_exit() will use the secure context to
+ * restore to the general purpose and EL3 system registers to ERET
+ * into the secure payload.
+ * ---------------------------------------------------------------------
+ */
+ b el3_exit
+endfunc spm_secure_partition_enter
+
+ /* ---------------------------------------------------------------------
+ * This function is called with 'x0' pointing to a C runtime context
+ * saved in spm_secure_partition_enter().
+ * It restores the saved registers and jumps to that runtime with 'x0'
+ * as the new SP register. This destroys the C runtime context that had
+ * been built on the stack below the saved context by the caller. Later
+ * the second parameter 'x1' is passed as a return value to the caller.
+ * ---------------------------------------------------------------------
+ */
+func spm_secure_partition_exit
+ /* Restore the previous stack */
+ mov sp, x0
+
+ /* Restore callee-saved registers on to the stack */
+ ldp x19, x20, [x0, #(SP_C_RT_CTX_X19 - SP_C_RT_CTX_SIZE)]
+ ldp x21, x22, [x0, #(SP_C_RT_CTX_X21 - SP_C_RT_CTX_SIZE)]
+ ldp x23, x24, [x0, #(SP_C_RT_CTX_X23 - SP_C_RT_CTX_SIZE)]
+ ldp x25, x26, [x0, #(SP_C_RT_CTX_X25 - SP_C_RT_CTX_SIZE)]
+ ldp x27, x28, [x0, #(SP_C_RT_CTX_X27 - SP_C_RT_CTX_SIZE)]
+ ldp x29, x30, [x0, #(SP_C_RT_CTX_X29 - SP_C_RT_CTX_SIZE)]
+
+ /* ---------------------------------------------------------------------
+ * This should take us back to the instruction after the call to the
+ * last spm_secure_partition_enter().* Place the second parameter to x0
+ * so that the caller will see it as a return value from the original
+ * entry call.
+ * ---------------------------------------------------------------------
+ */
+ mov x0, x1
+ ret
+endfunc spm_secure_partition_exit
diff --git a/services/std_svc/spm/aarch64/spm_shim_exceptions.S b/services/std_svc/spm/aarch64/spm_shim_exceptions.S
new file mode 100644
index 00000000..218245d8
--- /dev/null
+++ b/services/std_svc/spm/aarch64/spm_shim_exceptions.S
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl_common.h>
+#include <context.h>
+
+/* -----------------------------------------------------------------------------
+ * Very simple stackless exception handlers used by the spm shim layer.
+ * -----------------------------------------------------------------------------
+ */
+ .globl spm_shim_exceptions_ptr
+
+vector_base spm_shim_exceptions_ptr, .spm_shim_exceptions
+
+ /* -----------------------------------------------------
+ * Current EL with SP0 : 0x0 - 0x200
+ * -----------------------------------------------------
+ */
+vector_entry SynchronousExceptionSP0, .spm_shim_exceptions
+ b .
+ check_vector_size SynchronousExceptionSP0
+
+vector_entry IrqSP0, .spm_shim_exceptions
+ b .
+ check_vector_size IrqSP0
+
+vector_entry FiqSP0, .spm_shim_exceptions
+ b .
+ check_vector_size FiqSP0
+
+vector_entry SErrorSP0, .spm_shim_exceptions
+ b .
+ check_vector_size SErrorSP0
+
+ /* -----------------------------------------------------
+ * Current EL with SPx: 0x200 - 0x400
+ * -----------------------------------------------------
+ */
+vector_entry SynchronousExceptionSPx, .spm_shim_exceptions
+ b .
+ check_vector_size SynchronousExceptionSPx
+
+vector_entry IrqSPx, .spm_shim_exceptions
+ b .
+ check_vector_size IrqSPx
+
+vector_entry FiqSPx, .spm_shim_exceptions
+ b .
+ check_vector_size FiqSPx
+
+vector_entry SErrorSPx, .spm_shim_exceptions
+ b .
+ check_vector_size SErrorSPx
+
+ /* -----------------------------------------------------
+ * Lower EL using AArch64 : 0x400 - 0x600. No exceptions
+ * are handled since secure_partition does not implement
+ * a lower EL
+ * -----------------------------------------------------
+ */
+vector_entry SynchronousExceptionA64, .spm_shim_exceptions
+ msr tpidr_el1, x30
+ mrs x30, esr_el1
+ ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+
+ cmp x30, #EC_AARCH64_SVC
+ b.eq do_smc
+
+ cmp x30, #EC_AARCH32_SVC
+ b.eq do_smc
+
+ cmp x30, #EC_AARCH64_SYS
+ b.eq handle_sys_trap
+
+ /* Fail in all the other cases */
+ b panic
+
+ /* ---------------------------------------------
+ * Tell SPM that we are done initialising
+ * ---------------------------------------------
+ */
+do_smc:
+ mrs x30, tpidr_el1
+ smc #0
+ eret
+
+ /* AArch64 system instructions trap are handled as a panic for now */
+handle_sys_trap:
+panic:
+ b panic
+ check_vector_size SynchronousExceptionA64
+
+vector_entry IrqA64, .spm_shim_exceptions
+ b .
+ check_vector_size IrqA64
+
+vector_entry FiqA64, .spm_shim_exceptions
+ b .
+ check_vector_size FiqA64
+
+vector_entry SErrorA64, .spm_shim_exceptions
+ b .
+ check_vector_size SErrorA64
+
+ /* -----------------------------------------------------
+ * Lower EL using AArch32 : 0x600 - 0x800
+ * -----------------------------------------------------
+ */
+vector_entry SynchronousExceptionA32, .spm_shim_exceptions
+ b .
+ check_vector_size SynchronousExceptionA32
+
+vector_entry IrqA32, .spm_shim_exceptions
+ b .
+ check_vector_size IrqA32
+
+vector_entry FiqA32, .spm_shim_exceptions
+ b .
+ check_vector_size FiqA32
+
+vector_entry SErrorA32, .spm_shim_exceptions
+ b .
+ check_vector_size SErrorA32
diff --git a/services/std_svc/spm/secure_partition_setup.c b/services/std_svc/spm/secure_partition_setup.c
new file mode 100644
index 00000000..c1f0edf6
--- /dev/null
+++ b/services/std_svc/spm/secure_partition_setup.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common_def.h>
+#include <context.h>
+#include <context_mgmt.h>
+#include <debug.h>
+#include <platform_def.h>
+#include <platform.h>
+#include <secure_partition.h>
+#include <string.h>
+#include <types.h>
+#include <xlat_tables_v2.h>
+
+#include "spm_private.h"
+#include "spm_shim_private.h"
+
+/* Place translation tables by default along with the ones used by BL31. */
+#ifndef PLAT_SP_IMAGE_XLAT_SECTION_NAME
+#define PLAT_SP_IMAGE_XLAT_SECTION_NAME "xlat_table"
+#endif
+
+/* Allocate and initialise the translation context for the secure partition. */
+REGISTER_XLAT_CONTEXT2(secure_partition,
+ PLAT_SP_IMAGE_MMAP_REGIONS,
+ PLAT_SP_IMAGE_MAX_XLAT_TABLES,
+ PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE,
+ EL1_EL0_REGIME, PLAT_SP_IMAGE_XLAT_SECTION_NAME);
+
+/* Export a handle on the secure partition translation context */
+xlat_ctx_t *secure_partition_xlat_ctx_handle = &secure_partition_xlat_ctx;
+
+/* Setup context of the Secure Partition */
+void secure_partition_setup(void)
+{
+ VERBOSE("S-EL1/S-EL0 context setup start...\n");
+
+ cpu_context_t *ctx = cm_get_context(SECURE);
+
+ /* Make sure that we got a Secure context. */
+ assert(ctx != NULL);
+
+ /* Assert we are in Secure state. */
+ assert((read_scr_el3() & SCR_NS_BIT) == 0);
+
+ /* Disable MMU at EL1. */
+ disable_mmu_icache_el1();
+
+ /* Invalidate TLBs at EL1. */
+ tlbivmalle1();
+
+ /*
+ * General-Purpose registers
+ * -------------------------
+ */
+
+ /*
+ * X0: Virtual address of a buffer shared between EL3 and Secure EL0.
+ * The buffer will be mapped in the Secure EL1 translation regime
+ * with Normal IS WBWA attributes and RO data and Execute Never
+ * instruction access permissions.
+ *
+ * X1: Size of the buffer in bytes
+ *
+ * X2: cookie value (Implementation Defined)
+ *
+ * X3: cookie value (Implementation Defined)
+ *
+ * X4 to X30 = 0 (already done by cm_init_my_context())
+ */
+ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X0, PLAT_SPM_BUF_BASE);
+ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X1, PLAT_SPM_BUF_SIZE);
+ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X2, PLAT_SPM_COOKIE_0);
+ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X3, PLAT_SPM_COOKIE_1);
+
+ /*
+ * SP_EL0: A non-zero value will indicate to the SP that the SPM has
+ * initialized the stack pointer for the current CPU through
+ * implementation defined means. The value will be 0 otherwise.
+ */
+ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_SP_EL0,
+ PLAT_SP_IMAGE_STACK_BASE + PLAT_SP_IMAGE_STACK_PCPU_SIZE);
+
+ /*
+ * Setup translation tables
+ * ------------------------
+ */
+
+#if ENABLE_ASSERTIONS
+
+ /* Get max granularity supported by the platform. */
+
+ u_register_t id_aa64mmfr0_el1 = read_id_aa64mmfr0_el1();
+
+ int tgran64_supported =
+ ((id_aa64mmfr0_el1 >> ID_AA64MMFR0_EL1_TGRAN64_SHIFT) &
+ ID_AA64MMFR0_EL1_TGRAN64_MASK) ==
+ ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED;
+
+ int tgran16_supported =
+ ((id_aa64mmfr0_el1 >> ID_AA64MMFR0_EL1_TGRAN16_SHIFT) &
+ ID_AA64MMFR0_EL1_TGRAN16_MASK) ==
+ ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED;
+
+ int tgran4_supported =
+ ((id_aa64mmfr0_el1 >> ID_AA64MMFR0_EL1_TGRAN4_SHIFT) &
+ ID_AA64MMFR0_EL1_TGRAN4_MASK) ==
+ ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED;
+
+ uintptr_t max_granule_size;
+
+ if (tgran64_supported) {
+ max_granule_size = 64 * 1024;
+ } else if (tgran16_supported) {
+ max_granule_size = 16 * 1024;
+ } else {
+ assert(tgran4_supported);
+ max_granule_size = 4 * 1024;
+ }
+
+ VERBOSE("Max translation granule supported: %lu KiB\n",
+ max_granule_size / 1024);
+
+ uintptr_t max_granule_size_mask = max_granule_size - 1;
+
+ /* Base must be aligned to the max granularity */
+ assert((ARM_SP_IMAGE_NS_BUF_BASE & max_granule_size_mask) == 0);
+
+ /* Size must be a multiple of the max granularity */
+ assert((ARM_SP_IMAGE_NS_BUF_SIZE & max_granule_size_mask) == 0);
+
+#endif /* ENABLE_ASSERTIONS */
+
+ /* This region contains the exception vectors used at S-EL1. */
+ const mmap_region_t sel1_exception_vectors =
+ MAP_REGION_FLAT(SPM_SHIM_EXCEPTIONS_START,
+ SPM_SHIM_EXCEPTIONS_SIZE,
+ MT_CODE | MT_SECURE | MT_PRIVILEGED);
+ mmap_add_region_ctx(&secure_partition_xlat_ctx,
+ &sel1_exception_vectors);
+
+ mmap_add_ctx(&secure_partition_xlat_ctx,
+ plat_get_secure_partition_mmap(NULL));
+
+ init_xlat_tables_ctx(&secure_partition_xlat_ctx);
+
+ /*
+ * MMU-related registers
+ * ---------------------
+ */
+
+ /* Set attributes in the right indices of the MAIR */
+ u_register_t mair_el1 =
+ MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX) |
+ MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, ATTR_IWBWA_OWBWA_NTR_INDEX) |
+ MAIR_ATTR_SET(ATTR_NON_CACHEABLE, ATTR_NON_CACHEABLE_INDEX);
+
+ write_ctx_reg(get_sysregs_ctx(ctx), CTX_MAIR_EL1, mair_el1);
+
+ /* Setup TCR_EL1. */
+ u_register_t tcr_ps_bits = tcr_physical_addr_size_bits(PLAT_PHY_ADDR_SPACE_SIZE);
+
+ u_register_t tcr_el1 =
+ /* Size of region addressed by TTBR0_EL1 = 2^(64-T0SZ) bytes. */
+ (64 - __builtin_ctzl(PLAT_VIRT_ADDR_SPACE_SIZE)) |
+ /* Inner and outer WBWA, shareable. */
+ TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WBA | TCR_RGN_INNER_WBA |
+ /* Set the granularity to 4KB. */
+ TCR_TG0_4K |
+ /* Limit Intermediate Physical Address Size. */
+ tcr_ps_bits << TCR_EL1_IPS_SHIFT |
+ /* Disable translations using TBBR1_EL1. */
+ TCR_EPD1_BIT
+ /* The remaining fields related to TBBR1_EL1 are left as zero. */
+ ;
+
+ tcr_el1 &= ~(
+ /* Enable translations using TBBR0_EL1 */
+ TCR_EPD0_BIT
+ );
+
+ write_ctx_reg(get_sysregs_ctx(ctx), CTX_TCR_EL1, tcr_el1);
+
+ /* Setup SCTLR_EL1 */
+ u_register_t sctlr_el1 = read_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1);
+
+ sctlr_el1 |=
+ /*SCTLR_EL1_RES1 |*/
+ /* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */
+ SCTLR_UCI_BIT |
+ /* RW regions at xlat regime EL1&0 are forced to be XN. */
+ SCTLR_WXN_BIT |
+ /* Don't trap to EL1 execution of WFI or WFE at EL0. */
+ SCTLR_NTWI_BIT | SCTLR_NTWE_BIT |
+ /* Don't trap to EL1 accesses to CTR_EL0 from EL0. */
+ SCTLR_UCT_BIT |
+ /* Don't trap to EL1 execution of DZ ZVA at EL0. */
+ SCTLR_DZE_BIT |
+ /* Enable SP Alignment check for EL0 */
+ SCTLR_SA0_BIT |
+ /* Allow cacheable data and instr. accesses to normal memory. */
+ SCTLR_C_BIT | SCTLR_I_BIT |
+ /* Alignment fault checking enabled when at EL1 and EL0. */
+ SCTLR_A_BIT |
+ /* Enable MMU. */
+ SCTLR_M_BIT
+ ;
+
+ sctlr_el1 &= ~(
+ /* Explicit data accesses at EL0 are little-endian. */
+ SCTLR_E0E_BIT |
+ /* Accesses to DAIF from EL0 are trapped to EL1. */
+ SCTLR_UMA_BIT
+ );
+
+ write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
+
+ /* Point TTBR0_EL1 at the tables of the context created for the SP. */
+ write_ctx_reg(get_sysregs_ctx(ctx), CTX_TTBR0_EL1,
+ (u_register_t)secure_partition_base_xlat_table);
+
+ /*
+ * Setup other system registers
+ * ----------------------------
+ */
+
+ /* Shim Exception Vector Base Address */
+ write_ctx_reg(get_sysregs_ctx(ctx), CTX_VBAR_EL1,
+ SPM_SHIM_EXCEPTIONS_PTR);
+
+ /*
+ * FPEN: Forbid the Secure Partition to access FP/SIMD registers.
+ * TTA: Enable access to trace registers.
+ * ZEN (v8.2): Trap SVE instructions and access to SVE registers.
+ */
+ write_ctx_reg(get_sysregs_ctx(ctx), CTX_CPACR_EL1,
+ CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_ALL));
+
+ /*
+ * Prepare information in buffer shared between EL3 and S-EL0
+ * ----------------------------------------------------------
+ */
+
+ void *shared_buf_ptr = (void *) PLAT_SPM_BUF_BASE;
+
+ /* Copy the boot information into the shared buffer with the SP. */
+ assert((uintptr_t)shared_buf_ptr + sizeof(secure_partition_boot_info_t)
+ <= (PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE));
+
+ assert(PLAT_SPM_BUF_BASE <= (UINTPTR_MAX - PLAT_SPM_BUF_SIZE + 1));
+
+ const secure_partition_boot_info_t *sp_boot_info =
+ plat_get_secure_partition_boot_info(NULL);
+
+ assert(sp_boot_info != NULL);
+
+ memcpy((void *) shared_buf_ptr, (const void *) sp_boot_info,
+ sizeof(secure_partition_boot_info_t));
+
+ /* Pointer to the MP information from the platform port. */
+ secure_partition_mp_info_t *sp_mp_info =
+ ((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info;
+
+ assert(sp_mp_info != NULL);
+
+ /*
+ * Point the shared buffer MP information pointer to where the info will
+ * be populated, just after the boot info.
+ */
+ ((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info =
+ (secure_partition_mp_info_t *) ((uintptr_t)shared_buf_ptr
+ + sizeof(secure_partition_boot_info_t));
+
+ /*
+ * Update the shared buffer pointer to where the MP information for the
+ * payload will be populated
+ */
+ shared_buf_ptr = ((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info;
+
+ /*
+ * Copy the cpu information into the shared buffer area after the boot
+ * information.
+ */
+ assert(sp_boot_info->num_cpus <= PLATFORM_CORE_COUNT);
+
+ assert((uintptr_t)shared_buf_ptr
+ <= (PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE -
+ (sp_boot_info->num_cpus * sizeof(*sp_mp_info))));
+
+ memcpy(shared_buf_ptr, (const void *) sp_mp_info,
+ sp_boot_info->num_cpus * sizeof(*sp_mp_info));
+
+ /*
+ * Calculate the linear indices of cores in boot information for the
+ * secure partition and flag the primary CPU
+ */
+ sp_mp_info = (secure_partition_mp_info_t *) shared_buf_ptr;
+
+ for (unsigned int index = 0; index < sp_boot_info->num_cpus; index++) {
+ u_register_t mpidr = sp_mp_info[index].mpidr;
+
+ sp_mp_info[index].linear_id = plat_core_pos_by_mpidr(mpidr);
+ if (plat_my_core_pos() == sp_mp_info[index].linear_id)
+ sp_mp_info[index].flags |= MP_INFO_FLAG_PRIMARY_CPU;
+ }
+
+ VERBOSE("S-EL1/S-EL0 context setup end.\n");
+}
diff --git a/services/std_svc/spm/spm.mk b/services/std_svc/spm/spm.mk
new file mode 100644
index 00000000..562eaee4
--- /dev/null
+++ b/services/std_svc/spm/spm.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${SPD},none)
+ $(error "Error: SPD and SPM are incompatible build options.")
+endif
+ifneq (${ARCH},aarch64)
+ $(error "Error: SPM is only supported on aarch64.")
+endif
+
+# SPM sources
+
+
+SPM_SOURCES := $(addprefix services/std_svc/spm/, \
+ spm_main.c \
+ ${ARCH}/spm_helpers.S \
+ secure_partition_setup.c \
+ ${ARCH}/spm_shim_exceptions.S)
+
+
+# Let the top-level Makefile know that we intend to include a BL32 image
+NEED_BL32 := yes
diff --git a/services/std_svc/spm/spm_main.c b/services/std_svc/spm/spm_main.c
new file mode 100644
index 00000000..00f3a30c
--- /dev/null
+++ b/services/std_svc/spm/spm_main.c
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl31.h>
+#include <context_mgmt.h>
+#include <debug.h>
+#include <errno.h>
+#include <platform.h>
+#include <runtime_svc.h>
+#include <secure_partition.h>
+#include <smcc.h>
+#include <smcc_helpers.h>
+#include <spinlock.h>
+#include <spm_svc.h>
+#include <utils.h>
+#include <xlat_tables_v2.h>
+
+#include "spm_private.h"
+
+/* Lock used for SP_MEMORY_ATTRIBUTES_GET and SP_MEMORY_ATTRIBUTES_SET */
+static spinlock_t mem_attr_smc_lock;
+
+/*******************************************************************************
+ * Secure Partition context information.
+ ******************************************************************************/
+static secure_partition_context_t sp_ctx;
+unsigned int sp_init_in_progress;
+
+/*******************************************************************************
+ * Replace the S-EL1 re-entry information with S-EL0 re-entry
+ * information
+ ******************************************************************************/
+void spm_setup_next_eret_into_sel0(cpu_context_t *secure_context)
+{
+ assert(secure_context == cm_get_context(SECURE));
+
+ cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
+}
+
+/*******************************************************************************
+ * This function takes an SP context pointer and:
+ * 1. Applies the S-EL1 system register context from sp_ctx->cpu_ctx.
+ * 2. Saves the current C runtime state (callee-saved registers) on the stack
+ * frame and saves a reference to this state.
+ * 3. Calls el3_exit() so that the EL3 system and general purpose registers
+ * from the sp_ctx->cpu_ctx are used to enter the secure payload image.
+ ******************************************************************************/
+static uint64_t spm_synchronous_sp_entry(secure_partition_context_t *sp_ctx_ptr)
+{
+ uint64_t rc;
+
+ assert(sp_ctx_ptr != NULL);
+ assert(sp_ctx_ptr->c_rt_ctx == 0);
+ assert(cm_get_context(SECURE) == &sp_ctx_ptr->cpu_ctx);
+
+ /* Apply the Secure EL1 system register context and switch to it */
+ cm_el1_sysregs_context_restore(SECURE);
+ cm_set_next_eret_context(SECURE);
+
+ VERBOSE("%s: We're about to enter the Secure partition...\n", __func__);
+
+ rc = spm_secure_partition_enter(&sp_ctx_ptr->c_rt_ctx);
+#if ENABLE_ASSERTIONS
+ sp_ctx_ptr->c_rt_ctx = 0;
+#endif
+
+ return rc;
+}
+
+
+/*******************************************************************************
+ * This function takes a Secure partition context pointer and:
+ * 1. Saves the S-EL1 system register context tp sp_ctx->cpu_ctx.
+ * 2. Restores the current C runtime state (callee saved registers) from the
+ * stack frame using the reference to this state saved in
+ * spm_secure_partition_enter().
+ * 3. It does not need to save any general purpose or EL3 system register state
+ * as the generic smc entry routine should have saved those.
+ ******************************************************************************/
+static void __dead2 spm_synchronous_sp_exit(
+ secure_partition_context_t *sp_ctx_ptr, uint64_t ret)
+{
+ assert(sp_ctx_ptr != NULL);
+ /* Save the Secure EL1 system register context */
+ assert(cm_get_context(SECURE) == &sp_ctx_ptr->cpu_ctx);
+ cm_el1_sysregs_context_save(SECURE);
+
+ assert(sp_ctx_ptr->c_rt_ctx != 0);
+ spm_secure_partition_exit(sp_ctx_ptr->c_rt_ctx, ret);
+
+ /* Should never reach here */
+ assert(0);
+}
+
+/*******************************************************************************
+ * This function passes control to the Secure Partition image (BL32) for the
+ * first time on the primary cpu after a cold boot. It assumes that a valid
+ * secure context has already been created by spm_setup() which can be directly
+ * used. This function performs a synchronous entry into the Secure payload.
+ * The SP passes control back to this routine through a SMC.
+ ******************************************************************************/
+int32_t spm_init(void)
+{
+ entry_point_info_t *secure_partition_ep_info;
+ uint64_t rc;
+
+ VERBOSE("%s entry\n", __func__);
+
+ /*
+ * Get information about the Secure Partition (BL32) image. Its
+ * absence is a critical failure.
+ */
+ secure_partition_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+ assert(secure_partition_ep_info);
+
+ /*
+ * Initialise the common context and then overlay the S-EL0 specific
+ * context on top of it.
+ */
+ cm_init_my_context(secure_partition_ep_info);
+ secure_partition_setup();
+
+ /*
+ * Arrange for an entry into the secure payload.
+ */
+ sp_init_in_progress = 1;
+ rc = spm_synchronous_sp_entry(&sp_ctx);
+ assert(rc == 0);
+ sp_init_in_progress = 0;
+ VERBOSE("SP_MEMORY_ATTRIBUTES_SET_AARCH64 availability has been revoked\n");
+
+ return rc;
+}
+
+/*******************************************************************************
+ * Given a secure payload entrypoint info pointer, entry point PC & pointer to
+ * a context data structure, this function will initialize the SPM context and
+ * entry point info for the secure payload
+ ******************************************************************************/
+void spm_init_sp_ep_state(struct entry_point_info *sp_ep_info,
+ uint64_t pc,
+ secure_partition_context_t *sp_ctx_ptr)
+{
+ uint32_t ep_attr;
+
+ assert(sp_ep_info);
+ assert(pc);
+ assert(sp_ctx_ptr);
+
+ cm_set_context(&sp_ctx_ptr->cpu_ctx, SECURE);
+
+ /* initialise an entrypoint to set up the CPU context */
+ ep_attr = SECURE | EP_ST_ENABLE;
+ if (read_sctlr_el3() & SCTLR_EE_BIT)
+ ep_attr |= EP_EE_BIG;
+ SET_PARAM_HEAD(sp_ep_info, PARAM_EP, VERSION_1, ep_attr);
+
+ sp_ep_info->pc = pc;
+ /* The SPM payload runs in S-EL0 */
+ sp_ep_info->spsr = SPSR_64(MODE_EL0,
+ MODE_SP_EL0,
+ DISABLE_ALL_EXCEPTIONS);
+
+ zeromem(&sp_ep_info->args, sizeof(sp_ep_info->args));
+}
+
+/*******************************************************************************
+ * Secure Partition Manager setup. The SPM finds out the SP entrypoint if not
+ * already known and initialises the context for entry into the SP for its
+ * initialisation.
+ ******************************************************************************/
+int32_t spm_setup(void)
+{
+ entry_point_info_t *secure_partition_ep_info;
+
+ VERBOSE("%s entry\n", __func__);
+
+ /*
+ * Get information about the Secure Partition (BL32) image. Its
+ * absence is a critical failure.
+ */
+ secure_partition_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+ if (!secure_partition_ep_info) {
+ WARN("No SPM provided by BL2 boot loader, Booting device"
+ " without SPM initialization. SMCs destined for SPM"
+ " will return SMC_UNK\n");
+ return 1;
+ }
+
+ /*
+ * If there's no valid entry point for SP, we return a non-zero value
+ * signalling failure initializing the service. We bail out without
+ * registering any handlers
+ */
+ if (!secure_partition_ep_info->pc) {
+ return 1;
+ }
+
+ spm_init_sp_ep_state(secure_partition_ep_info,
+ secure_partition_ep_info->pc,
+ &sp_ctx);
+
+ /*
+ * All SPM initialization done. Now register our init function with
+ * BL31 for deferred invocation
+ */
+ bl31_register_bl32_init(&spm_init);
+
+ VERBOSE("%s exit\n", __func__);
+
+ return 0;
+}
+
+/*
+ * Attributes are encoded using a different format in the SMC interface than in
+ * the Trusted Firmware, where the mmap_attr_t enum type is used. This function
+ * converts an attributes value from the SMC format to the mmap_attr_t format by
+ * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER.
+ * The other fields are left as 0 because they are ignored by the function
+ * change_mem_attributes().
+ */
+static mmap_attr_t smc_attr_to_mmap_attr(unsigned int attributes)
+{
+ mmap_attr_t tf_attr = 0;
+
+ unsigned int access = (attributes & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
+ >> SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
+
+ if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RW) {
+ tf_attr |= MT_RW | MT_USER;
+ } else if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RO) {
+ tf_attr |= MT_RO | MT_USER;
+ } else {
+ /* Other values are reserved. */
+ assert(access == SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS);
+ /* The only requirement is that there's no access from EL0 */
+ tf_attr |= MT_RO | MT_PRIVILEGED;
+ }
+
+ if ((attributes & SP_MEMORY_ATTRIBUTES_NON_EXEC) == 0) {
+ tf_attr |= MT_EXECUTE;
+ } else {
+ tf_attr |= MT_EXECUTE_NEVER;
+ }
+
+ return tf_attr;
+}
+
+/*
+ * This function converts attributes from the Trusted Firmware format into the
+ * SMC interface format.
+ */
+static int smc_mmap_to_smc_attr(mmap_attr_t attr)
+{
+ int smc_attr = 0;
+
+ int data_access;
+
+ if ((attr & MT_USER) == 0) {
+ /* No access from EL0. */
+ data_access = SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS;
+ } else {
+ if ((attr & MT_RW) != 0) {
+ assert(MT_TYPE(attr) != MT_DEVICE);
+ data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RW;
+ } else {
+ data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RO;
+ }
+ }
+
+ smc_attr |= (data_access & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
+ << SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
+
+ if (attr & MT_EXECUTE_NEVER) {
+ smc_attr |= SP_MEMORY_ATTRIBUTES_NON_EXEC;
+ }
+
+ return smc_attr;
+}
+
+static int spm_memory_attributes_get_smc_handler(uintptr_t base_va)
+{
+ spin_lock(&mem_attr_smc_lock);
+
+ mmap_attr_t attributes;
+ int rc = get_mem_attributes(secure_partition_xlat_ctx_handle,
+ base_va, &attributes);
+
+ spin_unlock(&mem_attr_smc_lock);
+
+ /* Convert error codes of get_mem_attributes() into SPM ones. */
+ assert(rc == 0 || rc == -EINVAL);
+
+ if (rc == 0) {
+ return smc_mmap_to_smc_attr(attributes);
+ } else {
+ return SPM_INVALID_PARAMETER;
+ }
+}
+
+static int spm_memory_attributes_set_smc_handler(u_register_t page_address,
+ u_register_t pages_count,
+ u_register_t smc_attributes)
+{
+ uintptr_t base_va = (uintptr_t) page_address;
+ size_t size = (size_t) (pages_count * PAGE_SIZE);
+ unsigned int attributes = (unsigned int) smc_attributes;
+
+ INFO(" Start address : 0x%lx\n", base_va);
+ INFO(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size);
+ INFO(" Attributes : 0x%x\n", attributes);
+
+ spin_lock(&mem_attr_smc_lock);
+
+ int ret = change_mem_attributes(secure_partition_xlat_ctx_handle,
+ base_va, size, smc_attr_to_mmap_attr(attributes));
+
+ spin_unlock(&mem_attr_smc_lock);
+
+ /* Convert error codes of change_mem_attributes() into SPM ones. */
+ assert(ret == 0 || ret == -EINVAL);
+
+ return (ret == 0) ? SPM_SUCCESS : SPM_INVALID_PARAMETER;
+}
+
+
+uint64_t spm_smc_handler(uint32_t smc_fid,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ cpu_context_t *ns_cpu_context;
+ unsigned int ns;
+
+ /* Determine which security state this SMC originated from */
+ ns = is_caller_non_secure(flags);
+
+ if (ns == SMC_FROM_SECURE) {
+
+ /* Handle SMCs from Secure world. */
+
+ switch (smc_fid) {
+
+ case SPM_VERSION_AARCH32:
+ SMC_RET1(handle, SPM_VERSION_COMPILED);
+
+ case SP_EVENT_COMPLETE_AARCH64:
+ assert(handle == cm_get_context(SECURE));
+ cm_el1_sysregs_context_save(SECURE);
+ spm_setup_next_eret_into_sel0(handle);
+
+ if (sp_init_in_progress) {
+ /*
+ * SPM reports completion. The SPM must have
+ * initiated the original request through a
+ * synchronous entry into the secure
+ * partition. Jump back to the original C
+ * runtime context.
+ */
+ spm_synchronous_sp_exit(&sp_ctx, x1);
+ assert(0);
+ }
+
+ /*
+ * This is the result from the Secure partition of an
+ * earlier request. Copy the result into the non-secure
+ * context, save the secure state and return to the
+ * non-secure state.
+ */
+
+ /* Get a reference to the non-secure context */
+ ns_cpu_context = cm_get_context(NON_SECURE);
+ assert(ns_cpu_context);
+
+ /* Restore non-secure state */
+ cm_el1_sysregs_context_restore(NON_SECURE);
+ cm_set_next_eret_context(NON_SECURE);
+
+ /* Return to normal world */
+ SMC_RET1(ns_cpu_context, x1);
+
+ case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
+ INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
+
+ if (!sp_init_in_progress) {
+ WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
+ SMC_RET1(handle, SPM_NOT_SUPPORTED);
+ }
+ SMC_RET1(handle, spm_memory_attributes_get_smc_handler(x1));
+
+ case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
+ INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
+
+ if (!sp_init_in_progress) {
+ WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
+ SMC_RET1(handle, SPM_NOT_SUPPORTED);
+ }
+ SMC_RET1(handle, spm_memory_attributes_set_smc_handler(x1, x2, x3));
+ default:
+ break;
+ }
+ } else {
+
+ /* Handle SMCs from Non-secure world. */
+
+ switch (smc_fid) {
+
+ case SP_VERSION_AARCH64:
+ case SP_VERSION_AARCH32:
+ SMC_RET1(handle, SP_VERSION_COMPILED);
+
+ case MM_COMMUNICATE_AARCH32:
+ case MM_COMMUNICATE_AARCH64:
+
+ /* Save the Normal world context */
+ cm_el1_sysregs_context_save(NON_SECURE);
+
+ /*
+ * Restore the secure world context and prepare for
+ * entry in S-EL0
+ */
+ assert(&sp_ctx.cpu_ctx == cm_get_context(SECURE));
+ cm_el1_sysregs_context_restore(SECURE);
+ cm_set_next_eret_context(SECURE);
+
+ /* Cookie. Reserved for future use. It must be zero. */
+ assert(x1 == 0);
+
+ if (x3 != 0) {
+ VERBOSE("MM_COMMUNICATE_AARCH32/64: X3 is not 0 as recommended.\n");
+ }
+
+ SMC_RET4(&sp_ctx.cpu_ctx, smc_fid, x1, x2, x3);
+
+ case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
+ case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
+ /* SMC interfaces reserved for secure callers. */
+ SMC_RET1(handle, SPM_NOT_SUPPORTED);
+
+ default:
+ break;
+ }
+ }
+
+ SMC_RET1(handle, SMC_UNK);
+}
diff --git a/services/std_svc/spm/spm_private.h b/services/std_svc/spm/spm_private.h
new file mode 100644
index 00000000..16993e8c
--- /dev/null
+++ b/services/std_svc/spm/spm_private.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SPM_PRIVATE_H__
+#define __SPM_PRIVATE_H__
+
+#include <context.h>
+
+/*******************************************************************************
+ * Constants that allow assembler code to preserve callee-saved registers of the
+ * C runtime context while performing a security state switch.
+ ******************************************************************************/
+#define SP_C_RT_CTX_X19 0x0
+#define SP_C_RT_CTX_X20 0x8
+#define SP_C_RT_CTX_X21 0x10
+#define SP_C_RT_CTX_X22 0x18
+#define SP_C_RT_CTX_X23 0x20
+#define SP_C_RT_CTX_X24 0x28
+#define SP_C_RT_CTX_X25 0x30
+#define SP_C_RT_CTX_X26 0x38
+#define SP_C_RT_CTX_X27 0x40
+#define SP_C_RT_CTX_X28 0x48
+#define SP_C_RT_CTX_X29 0x50
+#define SP_C_RT_CTX_X30 0x58
+
+#define SP_C_RT_CTX_SIZE 0x60
+#define SP_C_RT_CTX_ENTRIES (SP_C_RT_CTX_SIZE >> DWORD_SHIFT)
+
+
+#ifndef __ASSEMBLY__
+
+#include <stdint.h>
+#include <xlat_tables_v2.h>
+
+/* Handle on the Secure partition translation context */
+extern xlat_ctx_t *secure_partition_xlat_ctx_handle;
+
+struct entry_point_info;
+
+typedef struct secure_partition_context {
+ uint64_t c_rt_ctx;
+ cpu_context_t cpu_ctx;
+} secure_partition_context_t;
+
+uint64_t spm_secure_partition_enter(uint64_t *c_rt_ctx);
+void __dead2 spm_secure_partition_exit(uint64_t c_rt_ctx, uint64_t ret);
+void spm_init_sp_ep_state(struct entry_point_info *sp_ep_info,
+ uint64_t pc,
+ secure_partition_context_t *sp_ctx_ptr);
+#endif /* __ASSEMBLY__ */
+
+#endif /* __SPM_PRIVATE_H__ */
diff --git a/services/std_svc/spm/spm_shim_private.h b/services/std_svc/spm/spm_shim_private.h
new file mode 100644
index 00000000..ad953cde
--- /dev/null
+++ b/services/std_svc/spm/spm_shim_private.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SPM_SHIM_PRIVATE__
+#define __SPM_SHIM_PRIVATE__
+
+#include <types.h>
+
+/* Assembly source */
+extern uintptr_t spm_shim_exceptions_ptr;
+
+/* Linker symbols */
+extern uintptr_t __SPM_SHIM_EXCEPTIONS_START__;
+extern uintptr_t __SPM_SHIM_EXCEPTIONS_END__;
+
+/* Definitions */
+#define SPM_SHIM_EXCEPTIONS_PTR (uintptr_t)(&spm_shim_exceptions_ptr)
+
+#define SPM_SHIM_EXCEPTIONS_START \
+ (uintptr_t)(&__SPM_SHIM_EXCEPTIONS_START__)
+#define SPM_SHIM_EXCEPTIONS_END \
+ (uintptr_t)(&__SPM_SHIM_EXCEPTIONS_END__)
+#define SPM_SHIM_EXCEPTIONS_SIZE \
+ (SPM_SHIM_EXCEPTIONS_END - SPM_SHIM_EXCEPTIONS_START)
+
+#endif /* __SPM_SHIM_PRIVATE__ */
diff --git a/services/std_svc/std_svc_setup.c b/services/std_svc/std_svc_setup.c
index 8e690467..ffc34716 100644
--- a/services/std_svc/std_svc_setup.c
+++ b/services/std_svc/std_svc_setup.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,7 +11,9 @@
#include <psci.h>
#include <runtime_instr.h>
#include <runtime_svc.h>
+#include <sdei.h>
#include <smcc_helpers.h>
+#include <spm_svc.h>
#include <std_svc.h>
#include <stdint.h>
#include <uuid.h>
@@ -25,15 +27,31 @@ DEFINE_SVC_UUID(arm_svc_uid,
static int32_t std_svc_setup(void)
{
uintptr_t svc_arg;
+ int ret = 0;
svc_arg = get_arm_std_svc_args(PSCI_FID_MASK);
assert(svc_arg);
/*
- * PSCI is the only specification implemented as a Standard Service.
+ * PSCI is one of the specifications implemented as a Standard Service.
* The `psci_setup()` also does EL3 architectural setup.
*/
- return psci_setup((const psci_lib_args_t *)svc_arg);
+ if (psci_setup((const psci_lib_args_t *)svc_arg) != PSCI_E_SUCCESS) {
+ ret = 1;
+ }
+
+#if ENABLE_SPM
+ if (spm_setup() != 0) {
+ ret = 1;
+ }
+#endif
+
+#if SDEI_SUPPORT
+ /* SDEI initialisation */
+ sdei_init();
+#endif
+
+ return ret;
}
/*
@@ -80,6 +98,24 @@ uintptr_t std_svc_smc_handler(uint32_t smc_fid,
SMC_RET1(handle, ret);
}
+#if ENABLE_SPM
+ /*
+ * Dispatch SPM calls to SPM SMC handler and return its return
+ * value
+ */
+ if (is_spm_fid(smc_fid)) {
+ return spm_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+ handle, flags);
+ }
+#endif
+
+#if SDEI_SUPPORT
+ if (is_sdei_fid(smc_fid)) {
+ return sdei_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ }
+#endif
+
switch (smc_fid) {
case ARM_STD_SVC_CALL_COUNT:
/*
diff --git a/tools/cert_create/include/cert.h b/tools/cert_create/include/cert.h
index 256e7afd..9b4ef5af 100644
--- a/tools/cert_create/include/cert.h
+++ b/tools/cert_create/include/cert.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -48,7 +48,13 @@ struct cert_s {
int cert_init(void);
cert_t *cert_get_by_opt(const char *opt);
int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value);
-int cert_new(int key_alg, cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSION) * sk);
+int cert_new(
+ int key_alg,
+ int md_alg,
+ cert_t *cert,
+ int days,
+ int ca,
+ STACK_OF(X509_EXTENSION) * sk);
/* Macro to register the certificates used in the CoT */
#define REGISTER_COT(_certs) \
diff --git a/tools/cert_create/include/key.h b/tools/cert_create/include/key.h
index 304fa615..1a253cc7 100644
--- a/tools/cert_create/include/key.h
+++ b/tools/cert_create/include/key.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -30,6 +30,13 @@ enum {
KEY_ALG_MAX_NUM
};
+/* Supported hash algorithms */
+enum{
+ HASH_ALG_SHA256,
+ HASH_ALG_SHA384,
+ HASH_ALG_SHA512,
+};
+
/*
* This structure contains the relevant information to create the keys
* required to sign the certificates.
diff --git a/tools/cert_create/include/sha.h b/tools/cert_create/include/sha.h
index 6907fa19..4d07a1e7 100644
--- a/tools/cert_create/include/sha.h
+++ b/tools/cert_create/include/sha.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,6 @@
#ifndef SHA_H_
#define SHA_H_
-int sha_file(const char *filename, unsigned char *md);
+int sha_file(int md_alg, const char *filename, unsigned char *md);
#endif /* SHA_H_ */
diff --git a/tools/cert_create/src/cert.c b/tools/cert_create/src/cert.c
index 1b84e36d..8e8aee69 100644
--- a/tools/cert_create/src/cert.c
+++ b/tools/cert_create/src/cert.c
@@ -56,6 +56,19 @@ error:
return ret;
}
+const EVP_MD *get_digest(int alg)
+{
+ switch (alg) {
+ case HASH_ALG_SHA256:
+ return EVP_sha256();
+ case HASH_ALG_SHA384:
+ return EVP_sha384();
+ case HASH_ALG_SHA512:
+ return EVP_sha512();
+ default:
+ return NULL;
+ }
+}
int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value)
{
@@ -79,7 +92,13 @@ int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value)
return 1;
}
-int cert_new(int key_alg, cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSION) * sk)
+int cert_new(
+ int key_alg,
+ int md_alg,
+ cert_t *cert,
+ int days,
+ int ca,
+ STACK_OF(X509_EXTENSION) * sk)
{
EVP_PKEY *pkey = keys[cert->key].key;
cert_t *issuer_cert = &certs[cert->issuer];
@@ -90,7 +109,7 @@ int cert_new(int key_alg, cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSIO
X509_NAME *name;
ASN1_INTEGER *sno;
int i, num, rc = 0;
- EVP_MD_CTX mdCtx;
+ EVP_MD_CTX *mdCtx;
EVP_PKEY_CTX *pKeyCtx = NULL;
/* Create the certificate structure */
@@ -111,10 +130,14 @@ int cert_new(int key_alg, cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSIO
issuer = x;
}
- EVP_MD_CTX_init(&mdCtx);
+ mdCtx = EVP_MD_CTX_create();
+ if (mdCtx == NULL) {
+ ERR_print_errors_fp(stdout);
+ goto END;
+ }
/* Sign the certificate with the issuer key */
- if (!EVP_DigestSignInit(&mdCtx, &pKeyCtx, EVP_sha256(), NULL, ikey)) {
+ if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) {
ERR_print_errors_fp(stdout);
goto END;
}
@@ -134,7 +157,7 @@ int cert_new(int key_alg, cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSIO
goto END;
}
- if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, EVP_sha256())) {
+ if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) {
ERR_print_errors_fp(stdout);
goto END;
}
@@ -184,7 +207,7 @@ int cert_new(int key_alg, cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSIO
}
}
- if (!X509_sign_ctx(x, &mdCtx)) {
+ if (!X509_sign_ctx(x, mdCtx)) {
ERR_print_errors_fp(stdout);
goto END;
}
@@ -194,7 +217,7 @@ int cert_new(int key_alg, cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSIO
cert->x = x;
END:
- EVP_MD_CTX_cleanup(&mdCtx);
+ EVP_MD_CTX_destroy(mdCtx);
return rc;
}
diff --git a/tools/cert_create/src/ext.c b/tools/cert_create/src/ext.c
index 8ae6640d..055ddbfd 100644
--- a/tools/cert_create/src/ext.c
+++ b/tools/cert_create/src/ext.c
@@ -166,7 +166,7 @@ X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md,
int sz;
/* OBJECT_IDENTIFIER with hash algorithm */
- algorithm = OBJ_nid2obj(md->type);
+ algorithm = OBJ_nid2obj(EVP_MD_type(md));
if (algorithm == NULL) {
return NULL;
}
diff --git a/tools/cert_create/src/key.c b/tools/cert_create/src/key.c
index c1bde5de..871f9ee8 100644
--- a/tools/cert_create/src/key.c
+++ b/tools/cert_create/src/key.c
@@ -43,13 +43,31 @@ int key_new(key_t *key)
static int key_create_rsa(key_t *key)
{
- RSA *rsa;
+ BIGNUM *e;
+ RSA *rsa = NULL;
- rsa = RSA_generate_key(RSA_KEY_BITS, RSA_F4, NULL, NULL);
+ e = BN_new();
+ if (e == NULL) {
+ printf("Cannot create RSA exponent\n");
+ goto err;
+ }
+
+ if (!BN_set_word(e, RSA_F4)) {
+ printf("Cannot assign RSA exponent\n");
+ goto err;
+ }
+
+ rsa = RSA_new();
if (rsa == NULL) {
printf("Cannot create RSA key\n");
goto err;
}
+
+ if (!RSA_generate_key_ex(rsa, RSA_KEY_BITS, e, NULL)) {
+ printf("Cannot generate RSA key\n");
+ goto err;
+ }
+
if (!EVP_PKEY_assign_RSA(key->key, rsa)) {
printf("Cannot assign RSA key\n");
goto err;
@@ -58,6 +76,7 @@ static int key_create_rsa(key_t *key)
return 1;
err:
RSA_free(rsa);
+ BN_free(e);
return 0;
}
@@ -91,9 +110,10 @@ err:
typedef int (*key_create_fn_t)(key_t *key);
static const key_create_fn_t key_create_fn[KEY_ALG_MAX_NUM] = {
- key_create_rsa,
+ key_create_rsa, /* KEY_ALG_RSA */
+ key_create_rsa, /* KEY_ALG_RSA_1_5 */
#ifndef OPENSSL_NO_EC
- key_create_ecdsa,
+ key_create_ecdsa, /* KEY_ALG_ECDSA */
#endif /* OPENSSL_NO_EC */
};
diff --git a/tools/cert_create/src/main.c b/tools/cert_create/src/main.c
index df59961b..4abfe6dd 100644
--- a/tools/cert_create/src/main.c
+++ b/tools/cert_create/src/main.c
@@ -68,6 +68,7 @@
/* Global options */
static int key_alg;
+static int hash_alg;
static int new_keys;
static int save_keys;
static int print_cert;
@@ -95,6 +96,12 @@ static const char *key_algs_str[] = {
#endif /* OPENSSL_NO_EC */
};
+static const char *hash_algs_str[] = {
+ [HASH_ALG_SHA256] = "sha256",
+ [HASH_ALG_SHA384] = "sha384",
+ [HASH_ALG_SHA512] = "sha512",
+};
+
static void print_help(const char *cmd, const struct option *long_opt)
{
int rem, i = 0;
@@ -150,6 +157,19 @@ static int get_key_alg(const char *key_alg_str)
return -1;
}
+static int get_hash_alg(const char *hash_alg_str)
+{
+ int i;
+
+ for (i = 0 ; i < NUM_ELEM(hash_algs_str) ; i++) {
+ if (0 == strcmp(hash_alg_str, hash_algs_str[i])) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
static void check_cmd_params(void)
{
cert_t *cert;
@@ -228,6 +248,10 @@ static const cmd_opt_t common_cmd_opt[] = {
PKCS#1 v2.1, 'rsa_1_5' - RSA PKCS#1 v1.5, 'ecdsa'"
},
{
+ { "hash-alg", required_argument, NULL, 's' },
+ "Hash algorithm : 'sha256' (default), 'sha384', 'sha512'"
+ },
+ {
{ "save-keys", no_argument, NULL, 'k' },
"Save key pairs into files. Filenames must be provided"
},
@@ -244,7 +268,7 @@ PKCS#1 v2.1, 'rsa_1_5' - RSA PKCS#1 v1.5, 'ecdsa'"
int main(int argc, char *argv[])
{
STACK_OF(X509_EXTENSION) * sk;
- X509_EXTENSION *cert_ext;
+ X509_EXTENSION *cert_ext = NULL;
ext_t *ext;
key_t *key;
cert_t *cert;
@@ -254,7 +278,8 @@ int main(int argc, char *argv[])
const struct option *cmd_opt;
const char *cur_opt;
unsigned int err_code;
- unsigned char md[SHA256_DIGEST_LENGTH];
+ unsigned char md[SHA512_DIGEST_LENGTH];
+ unsigned int md_len;
const EVP_MD *md_info;
NOTICE("CoT Generation Tool: %s\n", build_msg);
@@ -262,6 +287,7 @@ int main(int argc, char *argv[])
/* Set default options */
key_alg = KEY_ALG_RSA;
+ hash_alg = HASH_ALG_SHA256;
/* Add common command line options */
for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
@@ -291,7 +317,7 @@ int main(int argc, char *argv[])
while (1) {
/* getopt_long stores the option index here. */
- c = getopt_long(argc, argv, "a:hknp", cmd_opt, &opt_idx);
+ c = getopt_long(argc, argv, "a:hknps:", cmd_opt, &opt_idx);
/* Detect the end of the options. */
if (c == -1) {
@@ -318,6 +344,13 @@ int main(int argc, char *argv[])
case 'p':
print_cert = 1;
break;
+ case 's':
+ hash_alg = get_hash_alg(optarg);
+ if (hash_alg < 0) {
+ ERROR("Invalid hash algorithm '%s'\n", optarg);
+ exit(1);
+ }
+ break;
case CMD_OPT_EXT:
cur_opt = cmd_opt_get_name(opt_idx);
ext = ext_get_by_opt(cur_opt);
@@ -343,9 +376,18 @@ int main(int argc, char *argv[])
/* Check command line arguments */
check_cmd_params();
- /* Indicate SHA256 as image hash algorithm in the certificate
+ /* Indicate SHA as image hash algorithm in the certificate
* extension */
- md_info = EVP_sha256();
+ if (hash_alg == HASH_ALG_SHA384) {
+ md_info = EVP_sha384();
+ md_len = SHA384_DIGEST_LENGTH;
+ } else if (hash_alg == HASH_ALG_SHA512) {
+ md_info = EVP_sha512();
+ md_len = SHA512_DIGEST_LENGTH;
+ } else {
+ md_info = EVP_sha256();
+ md_len = SHA256_DIGEST_LENGTH;
+ }
/* Load private keys from files (or generate new ones) */
for (i = 0 ; i < num_keys ; i++) {
@@ -421,14 +463,14 @@ int main(int argc, char *argv[])
if (ext->arg == NULL) {
if (ext->optional) {
/* Include a hash filled with zeros */
- memset(md, 0x0, SHA256_DIGEST_LENGTH);
+ memset(md, 0x0, SHA512_DIGEST_LENGTH);
} else {
/* Do not include this hash in the certificate */
break;
}
} else {
/* Calculate the hash of the file */
- if (!sha_file(ext->arg, md)) {
+ if (!sha_file(hash_alg, ext->arg, md)) {
ERROR("Cannot calculate hash of %s\n",
ext->arg);
exit(1);
@@ -436,7 +478,7 @@ int main(int argc, char *argv[])
}
CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
EXT_CRIT, md_info, md,
- SHA256_DIGEST_LENGTH));
+ md_len));
break;
case EXT_TYPE_PKEY:
CHECK_NULL(cert_ext, ext_new_key(ext_nid,
@@ -453,7 +495,7 @@ int main(int argc, char *argv[])
}
/* Create certificate. Signed with corresponding key */
- if (cert->fn && !cert_new(key_alg, cert, VAL_DAYS, 0, sk)) {
+ if (cert->fn && !cert_new(key_alg, hash_alg, cert, VAL_DAYS, 0, sk)) {
ERROR("Cannot create %s\n", cert->cn);
exit(1);
}
diff --git a/tools/cert_create/src/sha.c b/tools/cert_create/src/sha.c
index 29715930..3d977fbf 100644
--- a/tools/cert_create/src/sha.c
+++ b/tools/cert_create/src/sha.c
@@ -1,20 +1,21 @@
/*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <openssl/sha.h>
#include <stdio.h>
-
#include "debug.h"
+#include "key.h"
#define BUFFER_SIZE 256
-int sha_file(const char *filename, unsigned char *md)
+int sha_file(int md_alg, const char *filename, unsigned char *md)
{
FILE *inFile;
SHA256_CTX shaContext;
+ SHA512_CTX sha512Context;
int bytes;
unsigned char data[BUFFER_SIZE];
@@ -29,11 +30,25 @@ int sha_file(const char *filename, unsigned char *md)
return 0;
}
- SHA256_Init(&shaContext);
- while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) {
- SHA256_Update(&shaContext, data, bytes);
+ if (md_alg == HASH_ALG_SHA384) {
+ SHA384_Init(&sha512Context);
+ while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) {
+ SHA384_Update(&sha512Context, data, bytes);
+ }
+ SHA384_Final(md, &sha512Context);
+ } else if (md_alg == HASH_ALG_SHA512) {
+ SHA512_Init(&sha512Context);
+ while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) {
+ SHA512_Update(&sha512Context, data, bytes);
+ }
+ SHA512_Final(md, &sha512Context);
+ } else {
+ SHA256_Init(&shaContext);
+ while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) {
+ SHA256_Update(&shaContext, data, bytes);
+ }
+ SHA256_Final(md, &shaContext);
}
- SHA256_Final(md, &shaContext);
fclose(inFile);
return 1;
diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c
index 02223d99..1dcb7e8e 100644
--- a/tools/fiptool/fiptool.c
+++ b/tools/fiptool/fiptool.c
@@ -9,18 +9,12 @@
#include <assert.h>
#include <errno.h>
-#include <getopt.h>
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-
-#include <openssl/sha.h>
-
-#include <firmware_image_package.h>
#include "fiptool.h"
#include "tbbr_config.h"
@@ -161,7 +155,7 @@ static void set_image_desc_action(image_desc_t *desc, int action,
{
assert(desc != NULL);
- if (desc->action_arg != DO_UNSPEC)
+ if (desc->action_arg != (char *)DO_UNSPEC)
free(desc->action_arg);
desc->action = action;
desc->action_arg = NULL;
@@ -278,7 +272,7 @@ static void uuid_from_str(uuid_t *u, const char *s)
static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
{
- struct stat st;
+ struct BLD_PLAT_STAT st;
FILE *fp;
char *buf, *bufend;
fip_toc_header_t *toc_header;
@@ -370,11 +364,12 @@ static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
static image_t *read_image_from_file(const uuid_t *uuid, const char *filename)
{
- struct stat st;
+ struct BLD_PLAT_STAT st;
image_t *image;
FILE *fp;
assert(uuid != NULL);
+ assert(filename != NULL);
fp = fopen(filename, "rb");
if (fp == NULL)
@@ -469,6 +464,7 @@ static int info_cmd(int argc, char *argv[])
(unsigned long long)image->toc_e.offset_address,
(unsigned long long)image->toc_e.size,
desc->cmdline_name);
+#ifndef _MSC_VER /* We don't have SHA256 for Visual Studio. */
if (verbose) {
unsigned char md[SHA256_DIGEST_LENGTH];
@@ -476,6 +472,7 @@ static int info_cmd(int argc, char *argv[])
printf(", sha256=");
md_print(md, sizeof(md));
}
+#endif
putchar('\n');
}
diff --git a/tools/fiptool/fiptool.h b/tools/fiptool/fiptool.h
index 4b5cdd91..d8a5d2ca 100644
--- a/tools/fiptool/fiptool.h
+++ b/tools/fiptool/fiptool.h
@@ -13,6 +13,8 @@
#include <firmware_image_package.h>
#include <uuid.h>
+#include "fiptool_platform.h"
+
#define NELEM(x) (sizeof (x) / sizeof *(x))
enum {
diff --git a/tools/fiptool/fiptool_platform.h b/tools/fiptool/fiptool_platform.h
new file mode 100644
index 00000000..fd0a1204
--- /dev/null
+++ b/tools/fiptool/fiptool_platform.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Build platform specific handling.
+ * This allows for builds on non-Posix platforms
+ * e.g. Visual Studio on Windows
+ */
+
+#ifndef __FIPTOOL_PLATFORM_H__
+# define __FIPTOOL_PLATFORM_H__
+
+# ifndef _MSC_VER
+
+ /* Not Visual Studio, so include Posix Headers. */
+# include <getopt.h>
+# include <openssl/sha.h>
+# include <unistd.h>
+
+# define BLD_PLAT_STAT stat
+
+# else
+
+ /* Visual Studio. */
+# include "win_posix.h"
+
+# endif
+
+#endif /* __FIPTOOL_PLATFORM_H__ */
diff --git a/tools/fiptool/win_posix.c b/tools/fiptool/win_posix.c
new file mode 100644
index 00000000..48feb162
--- /dev/null
+++ b/tools/fiptool/win_posix.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include "win_posix.h"
+
+/*
+ * This variable is set by getopt to the index of the next element of the
+ * argv array to be processed. Once getopt has found all of the option
+ * arguments, you can use this variable to determine where the remaining
+ * non-option arguments begin. The initial value of this variable is 1.
+ */
+int optind = 1;
+
+/*
+ * If the value of this variable is nonzero, then getopt prints an error
+ * message to the standard error stream if it encounters an unknown option
+ * default character or an option with a missing required argument.
+ * If you set this variable to zero, getopt does not print any messages,
+ * but it still returns the character ? to indicate an error.
+ */
+const int opterr; /* = 0; */
+/* const because we do not implement error printing.*/
+/* Not initialised to conform with the coding standard. */
+
+/*
+ * When getopt encounters an unknown option character or an option with a
+ * missing required argument, it stores that option character in this
+ * variable.
+ */
+int optopt; /* = 0; */
+
+/*
+ * This variable is set by getopt to point at the value of the option
+ * argument, for those options that accept arguments.
+ */
+char *optarg; /* = 0; */
+
+enum return_flags {
+ RET_ERROR = -1,
+ RET_END_OPT_LIST = -1,
+ RET_NO_PARAM = '?',
+ RET_NO_PARAM2 = ':',
+ RET_UNKNOWN_OPT = '?'
+};
+
+/*
+ * Common initialisation on entry.
+ */
+static
+void getopt_init(void)
+{
+ optarg = (char *)0;
+ optopt = 0;
+ /* optind may be zero with some POSIX uses.
+ * For our purposes we just change it to 1.
+ */
+ if (optind == 0)
+ optind = 1;
+}
+
+/*
+ * Common handling for a single letter option.
+ */
+static
+int getopt_1char(int argc,
+ char *const argv[],
+ const char *const opstring,
+ const int optchar)
+{
+ size_t nlen = (opstring == 0) ? 0 : strlen(opstring);
+ size_t loptn;
+
+ for (loptn = 0; loptn < nlen; loptn++) {
+ if (optchar == opstring[loptn]) {
+ if (opstring[loptn + 1] == ':') {
+ /* Option has argument */
+ if (optind < argc) {
+ /* Found argument. */
+ assert(argv != 0);
+ optind++;
+ optarg = argv[optind++];
+ return optchar;
+ }
+ /* Missing argument. */
+ if (opstring[loptn + 2] == ':') {
+ /* OK if optional "x::". */
+ optind++;
+ return optchar;
+ }
+ /* Actual missing value. */
+ optopt = optchar;
+ return ((opstring[0] == ':')
+ ? RET_NO_PARAM2
+ : RET_NO_PARAM);
+ }
+ /* No argument, just return option char */
+ optind++;
+ return optchar;
+ }
+ }
+ /*
+ * If getopt finds an option character in argv that was not included in
+ * options, ... it returns '?' and sets the external variable optopt to
+ * the actual option character.
+ */
+ optopt = optchar;
+ return RET_UNKNOWN_OPT;
+}
+
+int getopt(int argc,
+ char *argv[],
+ char *opstring)
+{
+ int result = RET_END_OPT_LIST;
+ size_t argn = 0;
+ size_t nlen = strlen(opstring);
+
+ getopt_init();
+ /* If we have an argument left to play with */
+ if ((argc > optind) && (argv != 0)) {
+ const char *arg = (const char *)argv[optind];
+
+ if ((arg != 0) && (arg[0] == '-'))
+ result = getopt_1char(argc, argv, opstring, arg[1]);
+ }
+
+ return result;
+}
+
+/*
+ * Match an argument value against an option name.
+ * Note that we only match over the shorter length of the pair, to allow
+ * for abbreviation or say --match=value
+ * Long option names may be abbreviated if the abbreviation is unique or an
+ * exact match for some defined option.
+ * A long option may take a parameter, of the form --opt=param or --opt param.
+*/
+static
+int optmatch(const char *argval, const char *optname)
+{
+ int result = 0;
+
+ while ((result == 0) && (*optname != 0) && (*argval != 0))
+ result = (*argval++) - (*optname++);
+ return result;
+}
+
+/* Handling for a single long option. */
+static
+int getopt_1long(const int argc,
+ char *const argv[],
+ const struct option *const longopts,
+ const char *const optname,
+ int *const indexptr)
+{
+ int result = RET_UNKNOWN_OPT;
+ size_t loptn = 0;
+
+ while (longopts[loptn].name != 0) {
+ if (optmatch(optname, longopts[loptn].name) == 0) {
+ /* We found a match. */
+ result = longopts[loptn].val;
+ if (indexptr != 0)
+ *indexptr = loptn;
+ switch (longopts[loptn].has_arg) {
+ case required_argument:
+ if ((optind + 1) >= argc) {
+ /* Missing argument. */
+ optopt = result;
+ return RET_NO_PARAM;
+ }
+ /* Fallthrough to get option value. */
+
+ case optional_argument:
+ if ((argc - optind) > 0) {
+ /* Found argument. */
+ optarg = argv[++optind];
+ }
+ /* Fallthrough to handle flag. */
+
+ case no_argument:
+ optind++;
+ if (longopts[loptn].flag != 0) {
+ *longopts[loptn].flag = result;
+ result = 0;
+ }
+ break;
+
+ }
+ return result;
+ }
+ ++loptn;
+ }
+ /*
+ * If getopt finds an option character in argv that was not included
+ * in options, ... it returns '?' and sets the external variable
+ * optopt to the actual option character.
+ */
+ return RET_UNKNOWN_OPT;
+}
+
+/*
+ * getopt_long gets the next option argument from the argument list
+ * specified by the argv and argc arguments. Options may be either short
+ * (single letter) as for getopt, or longer names (preceded by --).
+ */
+int getopt_long(int argc,
+ char *argv[],
+ const char *shortopts,
+ const struct option *longopts,
+ int *indexptr)
+{
+ int result = RET_END_OPT_LIST;
+
+ getopt_init();
+ /* If we have an argument left to play with */
+ if ((argc > optind) && (argv != 0)) {
+ const char *arg = argv[optind];
+
+ if ((arg != 0) && (arg[0] == '-')) {
+ if (arg[1] == '-') {
+ /* Looks like a long option. */
+ result = getopt_1long(argc,
+ argv,
+ longopts,
+ &arg[2],
+ indexptr);
+ } else {
+ result = getopt_1char(argc,
+ argv,
+ shortopts,
+ arg[1]);
+ }
+ }
+ }
+ return result;
+}
+
+/*
+ * getopt_long_only gets the next option argument from the argument list
+ * specified by the argv and argc arguments. Options may be either short
+ * or long as for getopt_long, but the long names may have a single '-'
+ * prefix too.
+ */
+int getopt_long_only(int argc,
+ char *argv[],
+ const char *shortopts,
+ const struct option *longopts,
+ int *indexptr)
+{
+ int result = RET_END_OPT_LIST;
+
+ getopt_init();
+ /* If we have an argument left to play with */
+ if ((argc > optind) && (argv != 0)) {
+ const char *arg = argv[optind];
+
+ if ((arg != 0) && (arg[0] == '-')) {
+ if (arg[1] == '-') {
+ /* Looks like a long option. */
+ result = getopt_1long(argc,
+ argv,
+ longopts,
+ &arg[2],
+ indexptr);
+ } else {
+ result = getopt_1long(argc,
+ argv,
+ longopts,
+ &arg[1],
+ indexptr);
+ if (result == RET_UNKNOWN_OPT) {
+ result = getopt_1char(argc,
+ argv,
+ shortopts,
+ arg[1]);
+ }
+ }
+ }
+ }
+ return result;
+}
diff --git a/tools/fiptool/win_posix.h b/tools/fiptool/win_posix.h
new file mode 100644
index 00000000..c3fc3995
--- /dev/null
+++ b/tools/fiptool/win_posix.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __WINPOSIX_H__
+# define __WINPOSIX_H__
+
+# define _CRT_SECURE_NO_WARNINGS
+
+# include <direct.h>
+# include <io.h>
+# include <stdint.h>
+# include <stdlib.h>
+# include <string.h>
+# include <sys/stat.h>
+
+# include "uuid.h"
+
+
+/* Derive or provide Windows equivalents of Posix/GCC/Unix stuff. */
+# ifndef PATH_MAX
+# ifdef MAX_PATH
+# define PATH_MAX MAX_PATH
+# else
+# ifdef _MAX_PATH
+# define MAX_PATH _MAX_PATH
+# define PATH_MAX _MAX_PATH
+# else
+# define PATH_MAX 260
+# endif
+# endif
+# endif
+
+# ifndef _CRT_SECURE_NO_WARNINGS
+# define _CRT_SECURE_NO_WARNINGS 1
+# endif
+
+/*
+ * Platform specific names.
+ *
+ * Visual Studio deprecates a number of POSIX functions and only provides
+ * ISO C++ compliant alternatives (distinguished by their '_' prefix).
+ * These macros help provide a stopgap for that.
+ */
+
+/* fileno cannot be an inline function, because _fileno is a macro. */
+# define fileno(fileptr) _fileno(fileptr)
+
+/* _fstat uses the _stat structure, not stat. */
+# define BLD_PLAT_STAT _stat
+
+/* Define flag values for _access. */
+# define F_OK 0
+
+
+/* getopt implementation for Windows: Data. */
+
+/* Legitimate values for option.has_arg. */
+enum has_arg_values {
+ no_argument, /* No argument value required */
+ required_argument, /* value must be specified. */
+ optional_argument /* value may be specified. */
+};
+
+/* Long option table entry for get_opt_long. */
+struct option {
+ /* The name of the option. */
+ const char *name;
+
+ /*
+ * Indicates whether the option takes an argument.
+ * Possible values: see has_arg_values above.
+ */
+ int has_arg;
+
+ /* If not null, when option present, *flag is set to val. */
+ int *flag;
+
+ /*
+ * The value associated with this option to return
+ * (and save in *flag when not null)
+ */
+ int val;
+};
+
+/*
+ * This variable is set by getopt to point at the value of the option
+ * argument, for those options that accept arguments.
+ */
+extern char *optarg;
+
+/*
+ * When this variable is not zero, getopt emits an error message to stderr
+ * if it encounters an unspecified option, or a missing argument.
+ * Otherwise no message is reported.
+ */
+extern const int opterr; /* const as NOT used in this implementation. */
+
+/*
+ * This variable is set by getopt to the index of the next element of the
+ * argv array to be processed. Once getopt has found all of the option
+ * arguments, you can use this variable to determine where the remaining
+ * non-option arguments begin. The initial value of this variable is 1.
+ */
+extern int optind;
+
+/*
+ * When getopt encounters an unknown option character or an option with a
+ * missing required argument, it stores that option character in this
+ * variable.
+ */
+extern int optopt;
+
+
+/*
+ * Platform specific names.
+ *
+ * Visual Studio deprecates a number of POSIX functions and only provides
+ * ISO C++ compliant alternatives (distinguished by their '_' prefix).
+ * These inline functions provide a stopgap for that.
+ */
+
+inline int access(const char *path, int mode)
+{
+ return _access(path, mode);
+}
+
+inline int chdir(const char *s)
+{
+ return _chdir(s);
+}
+
+inline int fstat(int fd, struct _stat *buffer)
+{
+ return _fstat(fd, buffer);
+}
+
+inline char *strdup(const char *s)
+{
+ return _strdup(s);
+}
+
+/*
+ * getopt implementation for Windows: Functions.
+ *
+ * Windows does not have the getopt family of functions, as it normally
+ * uses '/' instead of '-' as the command line option delimiter.
+ * These functions provide a Windows version that uses '-', which precludes
+ * using '-' as the intial letter of a program argument.
+ * This is not seen as a problem in the specific instance of fiptool,
+ * and enables existing makefiles to work on a Windows build environment.
+ */
+
+/*
+ * The getopt function gets the next option argument from the argument list
+ * specified by the argv and argc arguments.
+ */
+int getopt(int argc,
+ char *argv[],
+ char *options);
+
+/*
+ * getopt_long gets the next option argument from the argument list
+ * specified by the argv and argc arguments. Options may be either short
+ * (single letter) as for getopt, or longer names (preceded by --).
+ */
+int getopt_long(int argc,
+ char *argv[],
+ const char *shortopts,
+ const struct option *longopts,
+ int *indexptr);
+
+/*
+ * getopt_long_only gets the next option argument from the argument list
+ * specified by the argv and argc arguments. Options may be either short
+ * or long as for getopt_long, but the long names may have a single '-'
+ * prefix, too.
+ */
+int getopt_long_only(int argc,
+ char *argv[],
+ const char *shortopts,
+ const struct option *longopts,
+ int *indexptr);
+
+#endif /* __WINPOSIX_H__ */