aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile52
-rw-r--r--docs/about/contact.rst6
-rw-r--r--docs/change-log.rst218
-rw-r--r--docs/getting_started/requirements.rst12
-rw-r--r--drivers/arm/sp805/sp805.c58
-rw-r--r--fwu/ns_bl1u/aarch32/ns_bl1u_entrypoint.S15
-rw-r--r--fwu/ns_bl1u/aarch64/ns_bl1u_entrypoint.S15
-rw-r--r--fwu/ns_bl1u/ns_bl1u.ld.S4
-rw-r--r--fwu/ns_bl2u/aarch32/ns_bl2u_entrypoint.S15
-rw-r--r--fwu/ns_bl2u/aarch64/ns_bl2u_entrypoint.S15
-rw-r--r--fwu/ns_bl2u/ns_bl2u.ld.S5
-rw-r--r--include/common/aarch64/asm_macros.S11
-rw-r--r--include/common/test_helpers.h158
-rw-r--r--include/drivers/arm/sp805.h10
-rw-r--r--include/lib/aarch32/arch.h32
-rw-r--r--include/lib/aarch32/arch_features.h26
-rw-r--r--include/lib/aarch32/arch_helpers.h23
-rw-r--r--include/lib/aarch64/arch.h181
-rw-r--r--include/lib/aarch64/arch_features.h140
-rw-r--r--include/lib/aarch64/arch_helpers.h100
-rw-r--r--include/lib/aarch64/sync.h14
-rw-r--r--include/lib/extensions/sme.h22
-rw-r--r--include/lib/extensions/sve.h41
-rw-r--r--include/plat/common/common_def.h35
-rw-r--r--include/plat/common/platform.h9
-rw-r--r--include/runtime_services/cactus_message_loop.h12
-rw-r--r--include/runtime_services/cactus_test_cmds.h393
-rw-r--r--include/runtime_services/ffa_endpoints.h17
-rw-r--r--include/runtime_services/ffa_helpers.h395
-rw-r--r--include/runtime_services/ffa_svc.h100
-rw-r--r--include/runtime_services/realm_payload/realm_payload_test.h49
-rw-r--r--include/runtime_services/secure_el1_payloads/tsp.h3
-rw-r--r--include/runtime_services/spm_common.h59
-rw-r--r--lib/aarch64/exception_stubs.S39
-rw-r--r--lib/exceptions/aarch64/sync.c45
-rw-r--r--lib/exceptions/irq.c (renamed from lib/irq/irq.c)0
-rw-r--r--lib/extensions/sme/aarch64/sme.c117
-rw-r--r--lib/extensions/sme/aarch64/sme_helpers.S39
-rw-r--r--lib/xlat_tables_v2/aarch64/xlat_tables_arch.c3
-rw-r--r--plat/arm/corstone1000/corstone1000_def.h48
-rw-r--r--plat/arm/corstone1000/corstone1000_mem_prot.c23
-rw-r--r--plat/arm/corstone1000/corstone1000_pwr_state.c66
-rw-r--r--plat/arm/corstone1000/corstone1000_topology.c48
-rw-r--r--plat/arm/corstone1000/include/platform_def.h174
-rw-r--r--plat/arm/corstone1000/plat_helpers.S91
-rw-r--r--plat/arm/corstone1000/plat_setup.c40
-rw-r--r--plat/arm/corstone1000/platform.mk28
-rw-r--r--plat/arm/corstone1000/tests_to_skip.txt15
-rw-r--r--plat/arm/fvp/include/platform_def.h45
-rw-r--r--plat/arm/fvp/platform.mk28
-rw-r--r--plat/arm/juno/include/platform_def.h4
-rw-r--r--plat/arm/n1sdp/aarch64/plat_helpers.S90
-rw-r--r--plat/arm/n1sdp/include/platform_def.h158
-rw-r--r--plat/arm/n1sdp/n1sdp_mem_prot.c20
-rw-r--r--plat/arm/n1sdp/n1sdp_pwr_state.c43
-rw-r--r--plat/arm/n1sdp/n1sdp_topology.c52
-rw-r--r--plat/arm/n1sdp/plat_setup.c28
-rw-r--r--plat/arm/n1sdp/platform.mk38
-rw-r--r--plat/arm/n1sdp/tests_to_skip.txt30
-rw-r--r--plat/arm/rdinfra/rdn1edge/include/platform_def.h19
-rw-r--r--plat/arm/rdinfra/rdn1edge/platform.mk7
-rw-r--r--plat/arm/rdinfra/rdn1edge/topology.c6
-rw-r--r--plat/arm/rdinfra/rdn2/include/platform_def.h39
-rw-r--r--plat/arm/rdinfra/rdn2/platform.mk21
-rw-r--r--plat/arm/rdinfra/rdn2/tests_to_skip.txt13
-rw-r--r--plat/arm/rdinfra/rdn2/topology.c111
-rw-r--r--plat/arm/rdinfra/rdv1/include/platform_def.h25
-rw-r--r--plat/arm/rdinfra/rdv1/platform.mk18
-rw-r--r--plat/arm/rdinfra/rdv1/tests_to_skip.txt19
-rw-r--r--plat/arm/rdinfra/rdv1/topology.c107
-rw-r--r--plat/arm/sgi/common/aarch64/plat_helpers.S10
-rw-r--r--plat/arm/sgi/common/include/sgi_base_platform_def.h108
-rw-r--r--plat/arm/sgi/common/include/sgi_soc_css_def.h19
-rw-r--r--plat/arm/sgi/common/include/sgi_soc_css_def_v2.h20
-rw-r--r--plat/arm/sgi/common/include/sgi_soc_platform_def.h16
-rw-r--r--plat/arm/sgi/common/include/sgi_soc_platform_def_v2.h16
-rw-r--r--plat/arm/sgi/common/plat_setup.c2
-rw-r--r--plat/arm/sgi/common/sgi_common.mk5
-rw-r--r--plat/arm/sgi/sgi575/include/platform_def.h19
-rw-r--r--plat/arm/sgi/sgi575/platform.mk7
-rw-r--r--plat/arm/sgi/sgi575/sgi575_topology.c6
-rw-r--r--plat/arm/tc0/include/platform_def.h11
-rw-r--r--plat/arm/tc0/platform.mk1
-rw-r--r--plat/arm/tc0/tests_to_skip.txt7
-rw-r--r--plat/nvidia/tegra186/include/platform_def.h1
-rw-r--r--plat/nvidia/tegra194/include/platform_def.h1
-rw-r--r--plat/nvidia/tegra210/include/platform_def.h1
-rw-r--r--smc_fuzz/src/randsmcmod.c66
-rw-r--r--spm/cactus/aarch64/cactus_entrypoint.S29
-rw-r--r--spm/cactus/aarch64/cactus_exceptions.S29
-rw-r--r--spm/cactus/cactus.h7
-rw-r--r--spm/cactus/cactus.ld.S6
-rw-r--r--spm/cactus/cactus.mk40
-rw-r--r--spm/cactus/cactus_def.h39
-rw-r--r--spm/cactus/cactus_interrupt.c82
-rw-r--r--spm/cactus/cactus_main.c144
-rw-r--r--spm/cactus/cactus_tests/cactus_message_loop.c52
-rw-r--r--spm/cactus/cactus_tests/cactus_test_direct_messaging.c32
-rw-r--r--spm/cactus/cactus_tests/cactus_test_ffa.c177
-rw-r--r--spm/cactus/cactus_tests/cactus_test_interrupts.c147
-rw-r--r--spm/cactus/cactus_tests/cactus_test_memory_sharing.c161
-rw-r--r--spm/cactus/cactus_tests/cactus_test_notifications.c174
-rw-r--r--spm/cactus/cactus_tests/cactus_tests_smmuv3.c12
-rw-r--r--spm/cactus/plat/arm/fvp/fdts/cactus-secondary.dts39
-rw-r--r--spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts45
-rw-r--r--spm/cactus/plat/arm/fvp/fdts/cactus.dts44
-rw-r--r--spm/cactus/plat/arm/fvp/include/cactus_platform_def.h33
-rw-r--r--spm/cactus/plat/arm/fvp/include/sp_platform_def.h41
-rw-r--r--spm/cactus/plat/arm/tc0/fdts/cactus-secondary.dts20
-rw-r--r--spm/cactus/plat/arm/tc0/fdts/cactus-tertiary.dts22
-rw-r--r--spm/cactus/plat/arm/tc0/fdts/cactus.dts26
-rw-r--r--spm/cactus/plat/arm/tc0/include/cactus_platform_def.h24
-rw-r--r--spm/cactus/plat/arm/tc0/include/sp_platform_def.h43
-rw-r--r--spm/cactus_mm/cactus_mm.mk3
-rw-r--r--spm/common/sp_debug.c (renamed from spm/cactus/cactus_debug.c)21
-rw-r--r--spm/common/sp_debug.h13
-rw-r--r--spm/common/sp_def.h46
-rw-r--r--spm/common/sp_helpers.c53
-rw-r--r--spm/common/sp_helpers.h23
-rw-r--r--spm/common/sp_tests/sp_test_ffa.c218
-rw-r--r--spm/common/sp_tests/sp_tests.h (renamed from spm/cactus/cactus_tests.h)0
-rw-r--r--spm/common/spm_helpers.c17
-rw-r--r--spm/common/spm_helpers.h2
-rw-r--r--spm/ivy/aarch64/ivy_entrypoint.S27
-rw-r--r--spm/ivy/app/aarch64/ivy_entrypoint.S78
-rw-r--r--spm/ivy/app/ivy.h46
-rw-r--r--spm/ivy/app/ivy_def.h (renamed from spm/ivy/ivy_def.h)4
-rw-r--r--spm/ivy/app/ivy_main.c65
-rw-r--r--spm/ivy/app/plat/arm/fvp/fdts/ivy-sel0.dts30
-rw-r--r--spm/ivy/app/plat/arm/fvp/fdts/ivy-sel1.dts31
-rw-r--r--spm/ivy/app/plat/arm/fvp/include/sp_platform_def.h18
-rw-r--r--spm/ivy/app/plat/arm/fvp/platform.mk19
-rw-r--r--spm/ivy/app/plat/arm/tc0/fdts/ivy-sel0.dts29
-rw-r--r--spm/ivy/app/plat/arm/tc0/fdts/ivy-sel1.dts30
-rw-r--r--spm/ivy/app/plat/arm/tc0/include/sp_platform_def.h18
-rw-r--r--spm/ivy/app/plat/arm/tc0/platform.mk19
-rw-r--r--spm/ivy/ivy.dts95
-rw-r--r--spm/ivy/ivy.h29
-rw-r--r--spm/ivy/ivy.ld.S73
-rw-r--r--spm/ivy/ivy.mk89
-rw-r--r--spm/ivy/ivy_main.c135
-rw-r--r--spm/ivy/shim/aarch64/spm_shim_entrypoint.S83
-rw-r--r--spm/ivy/shim/aarch64/spm_shim_exceptions.S96
-rw-r--r--spm/ivy/shim/shim_main.c106
-rw-r--r--spm/quark/quark.mk4
-rw-r--r--tftf/framework/aarch64/exceptions.S54
-rw-r--r--tftf/framework/framework.mk7
-rw-r--r--tftf/framework/main.c25
-rw-r--r--tftf/tests/common/test_helpers.c127
-rw-r--r--tftf/tests/extensions/afp/test_afp.c35
-rw-r--r--tftf/tests/extensions/brbe/test_brbe.c36
-rw-r--r--tftf/tests/extensions/hcx/test_hcx.c30
-rw-r--r--tftf/tests/extensions/pauth/test_pauth.c10
-rw-r--r--tftf/tests/extensions/rng_trap/test_rndr_trap.c35
-rw-r--r--tftf/tests/extensions/rng_trap/test_rndrrs_trap.c35
-rw-r--r--tftf/tests/extensions/sme/test_sme.c104
-rw-r--r--tftf/tests/extensions/spe/test_spe.c71
-rw-r--r--tftf/tests/extensions/sve/test_sve.c7
-rw-r--r--tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.c59
-rw-r--r--tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.h15
-rw-r--r--tftf/tests/extensions/trbe/test_trbe.c33
-rw-r--r--tftf/tests/extensions/trf/test_trf.c31
-rw-r--r--tftf/tests/extensions/wfxt/test_wfxt.c89
-rw-r--r--tftf/tests/misc_tests/inject_serror.S2
-rw-r--r--tftf/tests/misc_tests/test_invalid_access.c394
-rw-r--r--tftf/tests/performance_tests/test_psci_latencies.c21
-rw-r--r--tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c466
-rw-r--r--tftf/tests/runtime_services/realm_payload/realm_payload_test.c317
-rw-r--r--tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c65
-rw-r--r--tftf/tests/runtime_services/secure_service/aarch32/ffa_arch_helpers.S42
-rw-r--r--tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S53
-rw-r--r--tftf/tests/runtime_services/secure_service/ffa_helpers.c371
-rw-r--r--tftf/tests/runtime_services/secure_service/spm_common.c407
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c70
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c107
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_features.c47
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c24
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c198
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_notifications.c1634
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_rxtx_map.c67
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c456
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_setup_and_discovery.c431
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_version.c88
-rw-r--r--tftf/tests/runtime_services/secure_service/test_spci_blocking_request.c3
-rw-r--r--tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c100
-rw-r--r--tftf/tests/runtime_services/secure_service/test_spm_smmu.c4
-rw-r--r--tftf/tests/runtime_services/standard_service/psci/system_tests/test_psci_on_off_suspend_stress.c21
-rw-r--r--tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S30
-rw-r--r--tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_pstate.c318
-rw-r--r--tftf/tests/runtime_services/trusted_os/tsp/test_pstate_after_exception.c75
-rw-r--r--tftf/tests/tests-cpu-extensions.mk18
-rw-r--r--tftf/tests/tests-cpu-extensions.xml11
-rw-r--r--tftf/tests/tests-hcx.mk9
-rw-r--r--tftf/tests/tests-hcx.xml15
-rw-r--r--tftf/tests/tests-invalid-access.mk20
-rw-r--r--tftf/tests/tests-invalid-access.xml24
-rw-r--r--tftf/tests/tests-realm-payload.mk24
-rw-r--r--tftf/tests/tests-realm-payload.xml21
-rw-r--r--tftf/tests/tests-rndr_trap.mk9
-rw-r--r--tftf/tests/tests-rndr_trap.xml15
-rw-r--r--tftf/tests/tests-rndrrs_trap.mk9
-rw-r--r--tftf/tests/tests-rndrrs_trap.xml15
-rw-r--r--tftf/tests/tests-sdei.mk3
-rw-r--r--tftf/tests/tests-sdei.xml3
-rw-r--r--tftf/tests/tests-smcfuzzing.mk31
-rw-r--r--tftf/tests/tests-spm.mk15
-rw-r--r--tftf/tests/tests-spm.xml129
-rw-r--r--tftf/tests/tests-standard.mk1
-rw-r--r--tftf/tests/tests-standard.xml2
-rw-r--r--tftf/tests/tests-tsp.mk3
-rw-r--r--tftf/tests/tests-tsp.xml7
-rwxr-xr-xtools/generate_dtb/generate_dtb.sh5
-rwxr-xr-xtools/generate_json/generate_json.sh95
213 files changed, 12470 insertions, 1874 deletions
diff --git a/Makefile b/Makefile
index 8eba9403..55f96903 100644
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,12 @@
#
-# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# TFTF Version
VERSION_MAJOR := 2
-VERSION_MINOR := 5
+VERSION_MINOR := 7
MAKE_HELPERS_DIRECTORY := make_helpers/
include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
@@ -67,7 +67,7 @@ endif
# Default build string (git branch and commit)
ifeq (${BUILD_STRING},)
- BUILD_STRING := $(shell git log -n 1 --pretty=format:"%h")
+ BUILD_STRING := $(shell git describe --always --dirty --tags 2> /dev/null)
endif
VERSION_STRING := v${VERSION_MAJOR}.${VERSION_MINOR}(${PLAT},${BUILD_TYPE}):${BUILD_STRING}
@@ -94,6 +94,10 @@ ifeq ($(wildcard ${PLAT_MAKEFILE_FULL}),)
$(error "Error: Invalid platform. The following platforms are available: ${PLATFORMS}")
endif
+
+EL3_PAYLOAD_PLAT_PATH := $(shell find el3_payload/plat/ -wholename '*/${PLAT}')
+EL3_PAYLOAD_PLAT_MAKEFILE_FULL := ${EL3_PAYLOAD_PLAT_PATH}/${PLAT_MAKEFILE}
+
.PHONY: all
all: msg_start
@@ -108,16 +112,19 @@ include tftf/tests/tests.mk
include fwu/ns_bl1u/ns_bl1u.mk
include fwu/ns_bl2u/ns_bl2u.mk
-# Only platform fvp supports cactus_mm, ivy, quark
+# List of secure partitions present.
+SECURE_PARTITIONS :=
+
+# Only platform fvp supports cactus_mm, quark
ifeq (${ARCH}-${PLAT},aarch64-fvp)
include spm/cactus_mm/cactus_mm.mk
-include spm/ivy/ivy.mk
include spm/quark/quark.mk
endif
-# cactus is supported on platforms: fvp, tc0
+# cactus and ivy are supported on platforms: fvp, tc0
ifeq (${ARCH}-${PLAT},$(filter ${ARCH}-${PLAT},aarch64-fvp aarch64-tc0))
include spm/cactus/cactus.mk
+include spm/ivy/ivy.mk
endif
################################################################################
@@ -174,8 +181,8 @@ COMMON_CFLAGS :=
COMMON_LDFLAGS :=
ifeq (${DEBUG},1)
-COMMON_CFLAGS += -g
-COMMON_ASFLAGS += -g -Wa,--gdwarf-2
+COMMON_CFLAGS += -g -gdwarf-4
+COMMON_ASFLAGS += -g -Wa,--gdwarf-4
endif
# Set the compiler's target architecture profile based on ARM_ARCH_MINOR option
@@ -289,9 +296,9 @@ CACTUS_LDFLAGS += ${COMMON_LDFLAGS} $(PIE_LDFLAGS)
IVY_SOURCES += ${LIBC_SRCS}
IVY_INCLUDES += ${PLAT_INCLUDES}
-IVY_CFLAGS += ${COMMON_CFLAGS}
+IVY_CFLAGS += ${COMMON_CFLAGS} -fpie
IVY_ASFLAGS += ${COMMON_ASFLAGS}
-IVY_LDFLAGS += ${COMMON_LDFLAGS}
+IVY_LDFLAGS += ${COMMON_LDFLAGS} $(PIE_LDFLAGS)
QUARK_SOURCES += ${LIBC_SRCS}
QUARK_INCLUDES += ${PLAT_INCLUDES}
@@ -313,14 +320,18 @@ endif
clean:
@echo " CLEAN"
${Q}rm -rf ${BUILD_PLAT}
+ifneq ($(wildcard ${EL3_PAYLOAD_PLAT_MAKEFILE_FULL}),)
${MAKE} -C el3_payload clean
+endif
.PHONY: realclean distclean
realclean distclean:
@echo " REALCLEAN"
${Q}rm -rf ${BUILD_BASE}
${Q}rm -f ${CURDIR}/cscope.*
+ifneq ($(wildcard ${EL3_PAYLOAD_PLAT_MAKEFILE_FULL}),)
${MAKE} -C el3_payload distclean
+endif
.PHONY: checkcodebase
checkcodebase: locate-checkpatch
@@ -367,11 +378,6 @@ cactus_mm:
@echo "ERROR: $@ is supported only on AArch64 FVP."
@exit 1
-.PHONY: ivy
-ivy:
- @echo "ERROR: $@ is supported only on AArch64 FVP."
- @exit 1
-
.PHONY: quark
quark:
@echo "ERROR: $@ is supported only on AArch64 FVP."
@@ -383,6 +389,11 @@ ifneq (${ARCH}-${PLAT},$(filter ${ARCH}-${PLAT},aarch64-fvp aarch64-tc0))
cactus:
@echo "ERROR: $@ is supported only on AArch64 FVP or TC0."
@exit 1
+
+.PHONY: ivy
+ivy:
+ @echo "ERROR: $@ is supported only on AArch64 FVP or TC0."
+ @exit 1
endif
MAKE_DEP = -Wp,-MD,$(DEP) -MT $$@
@@ -504,8 +515,8 @@ ifeq ($(SMC_FUZZING), 1)
$(Q)mkdir -p ${BUILD_PLAT}/smcf
dtc ${SMC_FUZZ_DTS} >> ${BUILD_PLAT}/smcf/dtb
$(OC) -I binary -O elf64-littleaarch64 -B aarch64 ${BUILD_PLAT}/smcf/dtb ${BUILD_PLAT}/smcf/dtb.o \
- --redefine-sym _binary___build_fvp_debug_smcf_dtb_start=_binary___dtb_start \
- --redefine-sym _binary___build_fvp_debug_smcf_dtb_end=_binary___dtb_end
+ --redefine-sym _binary___build_$(PLAT)_$(BUILD_TYPE)_smcf_dtb_start=_binary___dtb_start \
+ --redefine-sym _binary___build_$(PLAT)_$(BUILD_TYPE)_smcf_dtb_end=_binary___dtb_end
endif
$(eval $(call MAKE_IMG,tftf))
@@ -524,18 +535,25 @@ endif
ifeq (${ARCH}-${PLAT},aarch64-tc0)
$(eval $(call MAKE_IMG,cactus))
+ $(eval $(call MAKE_IMG,ivy))
endif
+SP_LAYOUT:
+ ${Q}tools/generate_json/generate_json.sh \
+ $(BUILD_PLAT) $(SECURE_PARTITIONS)
+
# The EL3 test payload is only supported in AArch64. It has an independent build
# system.
.PHONY: el3_payload
ifneq (${ARCH},aarch32)
+ifneq ($(wildcard ${EL3_PAYLOAD_PLAT_MAKEFILE_FULL}),)
el3_payload: $(BUILD_DIR)
${Q}${MAKE} -C el3_payload PLAT=${PLAT}
${Q}find "el3_payload/build/${PLAT}" -name '*.bin' -exec cp {} "${BUILD_PLAT}" \;
all: el3_payload
endif
+endif
doc:
@echo " BUILD DOCUMENTATION"
diff --git a/docs/about/contact.rst b/docs/about/contact.rst
index a84dc521..2b1778cb 100644
--- a/docs/about/contact.rst
+++ b/docs/about/contact.rst
@@ -26,8 +26,8 @@ maintainers to prioritise and respond to your ticket.
--------------
-*Copyright (c) 2019, Arm Limited. All rights reserved.*
+*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
.. _`issue tracker`: https://developer.trustedfirmware.org
-.. _`TF-A-Tests development`: https://lists.trustedfirmware.org/pipermail/tf-a-tests/
-.. _`summary of all the lists`: https://lists.trustedfirmware.org
+.. _`TF-A-Tests development`: https://lists.trustedfirmware.org/mailman3/lists/tf-a-tests.lists.trustedfirmware.org/
+.. _`summary of all the lists`: https://lists.trustedfirmware.org/mailman3/lists/
diff --git a/docs/change-log.rst b/docs/change-log.rst
index 136bbd49..49bd2432 100644
--- a/docs/change-log.rst
+++ b/docs/change-log.rst
@@ -7,6 +7,222 @@ Firmware-A version for simplicity. At any point in time, TF-A Tests version
Tests are not guaranteed to be compatible. This also means that a version
upgrade on the TF-A-Tests side might not necessarily introduce any new feature.
+Version 2.7
+-----------
+
+New features
+^^^^^^^^^^^^
+- More tests are made available in this release to help validate the
+ functionalities in the following areas:
+
+ - FF-A Features
+ - New Architecture Specific features related to v8.7
+ - New platform port
+
+TFTF
+~~~~
+
+- FF-A testing:
+
+ - FF-A partition information structure is updated to include UUIDs.
+ - Memory Management helper functions are refactored to fetch the details
+ of smc call failures in tftf and cactus.
+ - Added test to validate memory sharing operations from SP to NS-endpoint
+ are denied by SPMC.
+ - Added test to ensure an endpoint that sets its version to v1.0 receives
+ v1.0 partition information descriptors as defined in v1.0 FF-A
+ specification.
+ - Added test to validate that memory is cleared on memory sharing operations
+ between normal world and secure world.
+
+ - FF-A v1.1 Secure interrupts
+
+ - Added support to enhance the secure interrupt handling test.
+ - Support for registering and unregistering custom handler that is
+ invoked by SP at the tail end of the virtual interrupt processing.
+ - Added support for querying the ID of the last serviced virtual interrupt.
+
+- New tests:
+
+ - Added test to validate that realm region access is being prevented from
+ normal world.
+ - Added test to validate that secure region access is being prevented from
+ normal world.
+ - Added test to validate that secure region access is being prevented from
+ realm world.
+ - Added test to validate that root region access is being prevented from
+ realm world.
+ - Added a test for v8.7 Advanced floating-point behavior (FEAT_AFP).
+ - Added a SPE test that reads static profiling system registers
+ of available SPE version i.e. FEAT_SPE/FEAT_SPEv1p1/FEAT_SPEv1p2.
+ - Added a test to validate functionality of WFET and WFIT instructions
+ introduced by v8.7 FEAT_WFxT.
+ - Added basic SME tests to ensure feature enablement by EL3 is proper for
+ its usage at lower non-secure ELs.
+ - Added test to check Data Independent timing (DIT) field of PSTATE is
+ retained on exception.
+ - Added test to ensure that EL3 has properly enabled access to FEAT_BRBE
+ from non-secure ELs.
+
+- Platforms:
+
+ - Add initial platform support for corstone1000.
+
+ - TC:
+
+ - Support for notification in tertiary SP manifest.
+
+ - FVP:
+
+ - Support to provide test memory addresses to validate the invalid
+ memory access test from tftf(ns-el2).
+
+- Miscellaneous:
+
+ - Added support to configure the physical/virtual address space for FVP.
+ - Added common header file for defining macros with size to support all the
+ platforms.
+ - Introduced handler for synchronous exceptions (AArch64).
+ - Added macros to extract the ISS portion of an ELx ESR exception syndrome
+ register.
+ - Support to dynamically map/unmap test region to validate invalid memory
+ access tests.
+ - Added support to receive boot information through secure partitions,
+ according to the FF-A v1.1 EAC0 specification.
+ - Added an helper API function from SPM test suite to initialize FFA-mailbox
+ and enable FF-A based message with SP.
+ - Updated the build string to display the rc-tagged version.
+
+Cactus (Secure-EL1 test partition)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ - Added test for nonsecure memory sharing between Secure Partitions(SPs).
+ - Added test to validate that a realm region cannot be accessed from secure
+ world.
+ - Added test to permit checking a root region cannot be accessed from secure
+ world.
+ - Extended the test command CACTUS_MEM_SEND_CMD to add support for memory
+ sharing flags.
+ - Added support to save the state of general purpose registers x0-x4 at the
+ entry to cold boot and restore them before jumping to entrypoint of cactus.
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ - Fixed a bug to align RMI FIDs with SMCCC.
+ - Fixed encoding of vCPU and receiver IDs in the FFA_NOTIFICATION_GET
+ interface to comply with the FF-A v1.1 beta0 specification.
+ - Fixed memory retrieve request attributes by enforcing them to be inner
+ shareable rather than outer.
+ - Fixed static memory mapping of EL3 in EL2.
+ - Fixed a spurious error log message with memory share test.
+ - Aligning RMI FIDs with SMCCC.
+ - Fixed PSCI system suspend test suite execution in a four world system.
+ - Configured the build system to use DWARF 4 standard for debug builds with
+ ArmDS.
+ - Introduced macro IRQ_TWDOG_INTID for the Tegra210, Tegra186 and Tegra194
+ platforms to fix the compilation failures.
+
+Version 2.6
+-----------
+
+New features
+^^^^^^^^^^^^
+- More tests are made available in this release to help validate the
+ functionalities in the following areas:
+
+ - Firmware Framework for Arm A-profile(FF-A)
+ - Realm Management Extensions(RME)
+ - Embedded Trace Extension and Trace Buffer Extension (ETE and TRBE)
+
+TFTF
+~~~~
+
+- FF-A testing:
+
+ - Update FF-A version to v1.1
+ - Added helpers for SPM tests to check partition info of SPs from normal
+ world.
+ - Added tests to check for ffa_features supported.
+ - Added test for FFA_RXTX_UNMAP ABI.
+ - Added test for FFA_SPM_ID_GET.
+ - FF-A v1.1 Notifications
+
+ - Added test for notifications bitmap create and destroy ABIs.
+ - Added test for notifications set and get ABIs.
+ - Added test for notification INFO_GET ABI.
+ - Added test to check notifications pending interrupt is injected into
+ and handled by the expected vCPU in a MP setup.
+ - Added test for signaling from MP SP to UP SP.
+ - Added test to check notifications interrupt IDs retrieved with
+ FFA_FEATURES ABI.
+ - Added test to check functionality of notifications scheduled receiver
+ interrupt.
+
+ - FF-A v1.1 Secure interrupts
+
+ - Added support for handling secure interrupts in Cactus SP.
+ - Added several tests to exercise secure interrupt handling while SP
+ is in WAITING/RUNNING/BLOCKED state.
+
+- New tests:
+
+ - Enabled SVE tests
+ - Added test for trace system registers access.
+ - Added test for trace filter control registers access.
+ - Added test for trace buffer control registers access.
+ - Added test to check PSTATE in SDEI handler.
+ - Added test to check if HCRX_EL2 is accessible.
+
+- Platforms:
+
+ - TC0:
+
+ - Support for direct messaging with managed exit.
+ - Support for building S-EL0 Ivy partition.
+
+ - FVP:
+
+ - Update Cactus secure partitions to indicate Managed exit support.
+
+- Miscellaneous
+
+ - Added random seed generation capability and ability to specify build
+ parameters for SMC Fuzzer tool.
+
+Cactus (Secure-EL1 test partition)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ - Added helper for Cactus SP sleep.
+ - Added test commands to request use of notifications interfaces.
+ - Added several commands that generate direct message requests to assist in
+ testing secure interrupt handling and notifications features in FF-A v1.1
+ - Added support for SP805 Trusted Watchdog module.
+
+Ivy (Secure-EL1 test partition)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ - Add shim layer to Ivy partition and enable PIE.
+ - Define Ivy partition manifest and use FF-A for message handling.
+ - Prepare S-EL1/0 enviroment for enabling S-EL0 application.
+
+Realm Management Extension(RME)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ - Added tests to run RMI and SPM on multiple CPUs concurrently.
+ - Added tests for multi CPU delegation and fail conditions.
+ - Added tests to query RMI version on multiple CPUs.
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ - Fixed Ivy partition start address for TC0.
+ - Fixed SP manifests to use little endian format UUID.
+ - Fixed a bug in memory sharing test for Cactus SP.
+ - Invalidate data cache for NS_BL1U and NS_BL2U images.
+ - Fixed attributes to Read-Write only for memory regions described in partition
+ manifests.
+
Version 2.5
-----------
@@ -1127,7 +1343,7 @@ All test images
--------------
-*Copyright (c) 2018-2020, Arm Limited. All rights reserved.*
+*Copyright (c) 2018-2022, Arm Limited. All rights reserved.*
.. _Arm Neoverse Reference Design N1 Edge (RD-N1-Edge): https://developer.arm.com/products/system-design/reference-design/neoverse-reference-design
.. _Arm SGI-575: https://developer.arm.com/products/system-design/fixed-virtual-platforms
diff --git a/docs/getting_started/requirements.rst b/docs/getting_started/requirements.rst
index f9417c75..f7868dbc 100644
--- a/docs/getting_started/requirements.rst
+++ b/docs/getting_started/requirements.rst
@@ -12,7 +12,7 @@ Build Host
----------
TF-A Tests may be built using a Linux build host machine with a recent Linux
-distribution. We have performed tests using Ubuntu 16.04 LTS (64-bit), but other
+distribution. We have performed tests using Ubuntu 20.04 LTS (64-bit), but other
distributions should also work fine, provided that the tools and libraries
can be installed.
@@ -26,17 +26,17 @@ Install the required packages to build TF-A Tests with the following command:
sudo apt-get install device-tree-compiler build-essential git perl libxml-libxml-perl
Download and install the GNU cross-toolchain from Linaro. The TF-A Tests have
-been tested with version 9.2-2019.12 (gcc 9.2):
+been tested with version 11.3.Rel1 (gcc 11.3):
- `GCC cross-toolchain`_
In addition, the following optional packages and tools may be needed:
-- For debugging, Arm `Development Studio 5 (DS-5)`_.
+- For debugging, Arm `Development Studio (Arm-DS)`_.
-.. _GCC cross-toolchain: https://developer.arm.com/open-source/gnu-toolchain/gnu-a/downloads
-.. _Development Studio 5 (DS-5): https://developer.arm.com/products/software-development-tools/ds-5-development-studio
+.. _GCC cross-toolchain: https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/downloads
+.. _Development Studio (Arm-DS): https://developer.arm.com/Tools%20and%20Software/Arm%20Development%20Studio
--------------
-*Copyright (c) 2019, Arm Limited. All rights reserved.*
+*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
diff --git a/drivers/arm/sp805/sp805.c b/drivers/arm/sp805/sp805.c
index 2318c40d..85da43ae 100644
--- a/drivers/arm/sp805/sp805.c
+++ b/drivers/arm/sp805/sp805.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -109,45 +109,75 @@ static inline uint32_t sp805_read_wdog_pcell_id(unsigned long base, unsigned int
return mmio_read_32(base + SP805_WDOG_PCELL_ID_OFF + (id << 2));
}
-void sp805_wdog_start(uint32_t wdog_cycles)
+static void sp805_wdog_start_(unsigned long base, uint32_t wdog_cycles)
{
/* Unlock to access the watchdog registers */
- sp805_write_wdog_lock(SP805_WDOG_BASE, SP805_WDOG_UNLOCK_ACCESS);
+ sp805_write_wdog_lock(base, SP805_WDOG_UNLOCK_ACCESS);
/* Write the number of cycles needed */
- sp805_write_wdog_load(SP805_WDOG_BASE, wdog_cycles);
+ sp805_write_wdog_load(base, wdog_cycles);
/* Enable reset interrupt and watchdog interrupt on expiry */
- sp805_write_wdog_ctrl(SP805_WDOG_BASE,
+ sp805_write_wdog_ctrl(base,
SP805_WDOG_CTRL_RESEN | SP805_WDOG_CTRL_INTEN);
/* Lock registers so that they can't be accidently overwritten */
- sp805_write_wdog_lock(SP805_WDOG_BASE, 0x0);
+ sp805_write_wdog_lock(base, 0x0);
}
-void sp805_wdog_stop(void)
+static void sp805_wdog_stop_(unsigned long base)
{
/* Unlock to access the watchdog registers */
- sp805_write_wdog_lock(SP805_WDOG_BASE, SP805_WDOG_UNLOCK_ACCESS);
+ sp805_write_wdog_lock(base, SP805_WDOG_UNLOCK_ACCESS);
/* Clearing INTEN bit stops the counter */
- sp805_write_wdog_ctrl(SP805_WDOG_BASE, 0x00);
+ sp805_write_wdog_ctrl(base, 0x00);
/* Lock registers so that they can't be accidently overwritten */
- sp805_write_wdog_lock(SP805_WDOG_BASE, 0x0);
+ sp805_write_wdog_lock(base, 0x0);
}
-void sp805_wdog_refresh(void)
+static void sp805_wdog_refresh_(unsigned long base)
{
/* Unlock to access the watchdog registers */
- sp805_write_wdog_lock(SP805_WDOG_BASE, SP805_WDOG_UNLOCK_ACCESS);
+ sp805_write_wdog_lock(base, SP805_WDOG_UNLOCK_ACCESS);
/*
* Write of any value to WdogIntClr clears interrupt and reloads
* the counter from the value in WdogLoad Register.
*/
- sp805_write_wdog_int_clr(SP805_WDOG_BASE, 1);
+ sp805_write_wdog_int_clr(base, 1);
/* Lock registers so that they can't be accidently overwritten */
- sp805_write_wdog_lock(SP805_WDOG_BASE, 0x0);
+ sp805_write_wdog_lock(base, 0x0);
+}
+
+void sp805_wdog_start(uint32_t wdog_cycles)
+{
+ sp805_wdog_start_(SP805_WDOG_BASE, wdog_cycles);
+}
+
+void sp805_wdog_stop(void)
+{
+ sp805_wdog_stop_(SP805_WDOG_BASE);
+}
+
+void sp805_wdog_refresh(void)
+{
+ sp805_wdog_refresh_(SP805_WDOG_BASE);
+}
+
+void sp805_twdog_start(uint32_t wdog_cycles)
+{
+ sp805_wdog_start_(SP805_TWDOG_BASE, wdog_cycles);
+}
+
+void sp805_twdog_stop(void)
+{
+ sp805_wdog_stop_(SP805_TWDOG_BASE);
+}
+
+void sp805_twdog_refresh(void)
+{
+ sp805_wdog_refresh_(SP805_TWDOG_BASE);
}
diff --git a/fwu/ns_bl1u/aarch32/ns_bl1u_entrypoint.S b/fwu/ns_bl1u/aarch32/ns_bl1u_entrypoint.S
index b9c0d871..74c56008 100644
--- a/fwu/ns_bl1u/aarch32/ns_bl1u_entrypoint.S
+++ b/fwu/ns_bl1u/aarch32/ns_bl1u_entrypoint.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -28,6 +28,17 @@ func ns_bl1u_entrypoint
stcopr r0, HSCTLR
isb
+ /* --------------------------------------------------------------------
+ * Invalidate the cache in the RW memory range to safeguard
+ * against possible stale data in the cache from previous
+ * firmware stage.
+ * --------------------------------------------------------------------
+ */
+ ldr r0, =__RW_START__
+ ldr r1, =__RW_END__
+ sub r1, r1, r0
+ bl inv_dcache_range
+
/* ---------------------------------------------------------------------
* Init C runtime environment.
* - Zero-initialise the .bss section;
@@ -48,8 +59,6 @@ func ns_bl1u_entrypoint
* Allocate a stack whose memory will be marked as Normal
* Inner-Shareable, Write-Back, Write-Allocate memory when the MMU is
* enabled.
- * There is no risk of reading stale stack memory after enabling the MMU
- * as only the primary CPU is running at the moment.
* ---------------------------------------------------------------------
*/
ldcopr r0, MPIDR
diff --git a/fwu/ns_bl1u/aarch64/ns_bl1u_entrypoint.S b/fwu/ns_bl1u/aarch64/ns_bl1u_entrypoint.S
index d971e4ad..a73435bb 100644
--- a/fwu/ns_bl1u/aarch64/ns_bl1u_entrypoint.S
+++ b/fwu/ns_bl1u/aarch64/ns_bl1u_entrypoint.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -28,6 +28,17 @@ func ns_bl1u_entrypoint
asm_write_sctlr_el1_or_el2 x1
isb
+ /* --------------------------------------------------------------------
+ * Invalidate the cache in the RW memory range to safeguard
+ * against possible stale data in the cache from previous
+ * firmware stage.
+ * --------------------------------------------------------------------
+ */
+ ldr x0, =__RW_START__
+ ldr x1, =__RW_END__
+ sub x1, x1, x0
+ bl inv_dcache_range
+
/* ---------------------------------------------------------------------
* Init C runtime environment.
* - Zero-initialise the .bss section;
@@ -48,8 +59,6 @@ func ns_bl1u_entrypoint
* Allocate a stack whose memory will be marked as Normal
* Inner-Shareable, Write-Back, Write-Allocate memory when the MMU is
* enabled.
- * There is no risk of reading stale stack memory after enabling the MMU
- * as only the primary CPU is running at the moment.
* ---------------------------------------------------------------------
*/
mrs x0, mpidr_el1
diff --git a/fwu/ns_bl1u/ns_bl1u.ld.S b/fwu/ns_bl1u/ns_bl1u.ld.S
index 52d80dea..5021dafe 100644
--- a/fwu/ns_bl1u/ns_bl1u.ld.S
+++ b/fwu/ns_bl1u/ns_bl1u.ld.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -43,6 +43,7 @@ SECTIONS
* Its VMA must be page-aligned as it marks the first read/write page.
*/
. = NS_BL1U_RW_BASE;
+ __RW_START__ = .;
ASSERT(. == ALIGN(PAGE_SIZE),
"NS_BL1U_RW_BASE address is not aligned on a page boundary.")
.data . : ALIGN(16) {
@@ -79,6 +80,7 @@ SECTIONS
__NS_BL1U_RAM_START__ = ADDR(.data);
__NS_BL1U_RAM_END__ = .;
+ __RW_END__ = .;
__DATA_ROM_START__ = LOADADDR(.data);
__DATA_SIZE__ = SIZEOF(.data);
diff --git a/fwu/ns_bl2u/aarch32/ns_bl2u_entrypoint.S b/fwu/ns_bl2u/aarch32/ns_bl2u_entrypoint.S
index 28a45725..76116428 100644
--- a/fwu/ns_bl2u/aarch32/ns_bl2u_entrypoint.S
+++ b/fwu/ns_bl2u/aarch32/ns_bl2u_entrypoint.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -28,6 +28,17 @@ func ns_bl2u_entrypoint
stcopr r0, HSCTLR
isb
+ /* --------------------------------------------------------------------
+ * Invalidate the cache in the RW memory range to safeguard
+ * against possible stale data in the cache from previous
+ * firmware stage.
+ * --------------------------------------------------------------------
+ */
+ ldr r0, =__RW_START__
+ ldr r1, =__RW_END__
+ sub r1, r1, r0
+ bl inv_dcache_range
+
/* ---------------------------------------------------------------------
* Zero-initialise the .bss section.
* ---------------------------------------------------------------------
@@ -40,8 +51,6 @@ func ns_bl2u_entrypoint
* Allocate a stack whose memory will be marked as Normal
* Inner-Shareable, Write-Back, Write-Allocate memory when the MMU is
* enabled.
- * There is no risk of reading stale stack memory after enabling the MMU
- * as only the primary CPU is running at the moment.
* ---------------------------------------------------------------------
*/
ldcopr r0, MPIDR
diff --git a/fwu/ns_bl2u/aarch64/ns_bl2u_entrypoint.S b/fwu/ns_bl2u/aarch64/ns_bl2u_entrypoint.S
index 28d6dfac..1bc057c6 100644
--- a/fwu/ns_bl2u/aarch64/ns_bl2u_entrypoint.S
+++ b/fwu/ns_bl2u/aarch64/ns_bl2u_entrypoint.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -28,6 +28,17 @@ func ns_bl2u_entrypoint
asm_write_sctlr_el1_or_el2 x1
isb
+ /* --------------------------------------------------------------------
+ * Invalidate the cache in the RW memory range to safeguard
+ * against possible stale data in the cache from previous
+ * firmware stage.
+ * --------------------------------------------------------------------
+ */
+ ldr x0, =__RW_START__
+ ldr x1, =__RW_END__
+ sub x1, x1, x0
+ bl inv_dcache_range
+
/* ---------------------------------------------------------------------
* Zero-initialise the .bss section.
* ---------------------------------------------------------------------
@@ -40,8 +51,6 @@ func ns_bl2u_entrypoint
* Allocate a stack whose memory will be marked as Normal
* Inner-Shareable, Write-Back, Write-Allocate memory when the MMU is
* enabled.
- * There is no risk of reading stale stack memory after enabling the MMU
- * as only the primary CPU is running at the moment.
* ---------------------------------------------------------------------
*/
mrs x0, mpidr_el1
diff --git a/fwu/ns_bl2u/ns_bl2u.ld.S b/fwu/ns_bl2u/ns_bl2u.ld.S
index a6c6d2e8..d8949f3c 100644
--- a/fwu/ns_bl2u/ns_bl2u.ld.S
+++ b/fwu/ns_bl2u/ns_bl2u.ld.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -42,6 +42,8 @@ SECTIONS
__RODATA_END__ = .;
} >RAM
+ __RW_START__ = .;
+
.data . : {
__DATA_START__ = .;
*(.data*)
@@ -75,6 +77,7 @@ SECTIONS
} >RAM
__NS_BL2U_END__ = .;
+ __RW_END__ = .;
__BSS_SIZE__ = SIZEOF(.bss);
diff --git a/include/common/aarch64/asm_macros.S b/include/common/aarch64/asm_macros.S
index d829133f..8a69c38d 100644
--- a/include/common/aarch64/asm_macros.S
+++ b/include/common/aarch64/asm_macros.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -79,6 +79,15 @@
.endm
/*
+ * Create a vector entry that just spins making the exception unrecoverable.
+ */
+ .macro vector_entry_spin name
+ vector_entry \name
+ b \name
+ end_vector_entry \name
+ .endm
+
+ /*
* This macro calculates the base address of an MP stack using the
* platform_get_core_pos() index, the name of the stack storage and
* the size of each stack
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index 3ee2b531..b1349ddc 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,7 +8,9 @@
#define TEST_HELPERS_H__
#include <arch_features.h>
+#include <ffa_helpers.h>
#include <ffa_svc.h>
+#include <events.h>
#include <plat_topology.h>
#include <psci.h>
#include <spm_common.h>
@@ -89,6 +91,15 @@ typedef test_result_t (*test_function_arg_t)(void *arg);
} \
} while (0)
+#define SKIP_TEST_IF_DIT_NOT_SUPPORTED() \
+ do { \
+ if (!is_armv8_4_dit_present()) { \
+ tftf_testcase_printf( \
+ "DIT not supported\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (0)
+
#define SKIP_TEST_IF_PAUTH_NOT_SUPPORTED() \
do { \
if (!is_armv8_3_pauth_present()) { \
@@ -107,6 +118,14 @@ typedef test_result_t (*test_function_arg_t)(void *arg);
} \
} while (0)
+#define SKIP_TEST_IF_SVE_NOT_SUPPORTED() \
+ do { \
+ if (!is_armv8_2_sve_present()) { \
+ tftf_testcase_printf("SVE not supported\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (0)
+
#define SKIP_TEST_IF_ECV_NOT_SELF_SYNC() \
do { \
if (get_armv8_6_ecv_support() != \
@@ -164,16 +183,16 @@ typedef test_result_t (*test_function_arg_t)(void *arg);
#define SKIP_TEST_IF_FFA_VERSION_LESS_THAN(major, minor) \
do { \
- smc_ret_values smc_ret = ffa_version( \
+ struct ffa_value ret = ffa_version( \
MAKE_FFA_VERSION(major, minor)); \
- uint32_t version = smc_ret.ret0; \
+ uint32_t version = ret.fid; \
\
if (version == FFA_ERROR_NOT_SUPPORTED) { \
tftf_testcase_printf("FFA_VERSION not supported.\n"); \
return TEST_RESULT_SKIPPED; \
} \
\
- if ((version & FFA_VERSION_BIT31_MASK) != 0U) { \
+ if ((version & FFA_VERSION_BIT31_MASK) != 0U) { \
tftf_testcase_printf("FFA_VERSION bad response: %x\n", \
version); \
return TEST_RESULT_FAIL; \
@@ -204,13 +223,13 @@ typedef test_result_t (*test_function_arg_t)(void *arg);
#define SKIP_TEST_IF_FFA_ENDPOINT_NOT_DEPLOYED(mb, ffa_uuid) \
do { \
- smc_ret_values smc_ret = ffa_partition_info_get(ffa_uuid); \
+ struct ffa_value sc_ret = ffa_partition_info_get(ffa_uuid); \
ffa_rx_release(); \
- if (smc_ret.ret0 == FFA_ERROR && \
- smc_ret.ret2 == FFA_ERROR_INVALID_PARAMETER) { \
+ if (ffa_func_id(sc_ret) == FFA_ERROR && \
+ ffa_error_code(sc_ret) == FFA_ERROR_INVALID_PARAMETER) { \
tftf_testcase_printf("FFA endpoint not deployed!\n"); \
return TEST_RESULT_SKIPPED; \
- } else if (smc_ret.ret0 != FFA_SUCCESS_SMC32) { \
+ } else if (ffa_func_id(sc_ret) != FFA_SUCCESS_SMC32) { \
ERROR("ffa_partition_info_get failed!\n"); \
return TEST_RESULT_FAIL; \
} \
@@ -226,8 +245,17 @@ typedef test_result_t (*test_function_arg_t)(void *arg);
} \
} while (false);
+#define INIT_TFTF_MAILBOX(mb) \
+ do { \
+ if (!mailbox_init(mb)) { \
+ ERROR("Mailbox not configured properly!\n"); \
+ return TEST_RESULT_FAIL; \
+ } \
+ } while (false);
+
#define CHECK_SPMC_TESTING_SETUP(ffa_major, ffa_minor, expected_uuids) \
do { \
+ SKIP_TEST_IF_AARCH32(); \
const size_t expected_uuids_size = \
sizeof(expected_uuids) / sizeof(struct ffa_uuid); \
test_result_t ret = check_spmc_testing_set_up( \
@@ -238,6 +266,83 @@ typedef test_result_t (*test_function_arg_t)(void *arg);
} \
} while (false);
+#define SKIP_TEST_IF_TRBE_NOT_SUPPORTED() \
+ do { \
+ if (!get_armv9_0_trbe_support()) { \
+ tftf_testcase_printf("ARMv9-TRBE not supported\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (false)
+
+#define SKIP_TEST_IF_TRF_NOT_SUPPORTED() \
+ do { \
+ if (!get_armv8_4_trf_support()) { \
+ tftf_testcase_printf("ARMv8.4-TRF not supported\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (false)
+
+#define SKIP_TEST_IF_SYS_REG_TRACE_NOT_SUPPORTED() \
+ do { \
+ if (!get_armv8_0_sys_reg_trace_support()) { \
+ tftf_testcase_printf("ARMv8-system register" \
+ "trace not supported\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (false)
+
+#define SKIP_TEST_IF_AFP_NOT_SUPPORTED() \
+ do { \
+ if (!get_feat_afp_present()) { \
+ tftf_testcase_printf("ARMv8.7-afp not supported\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (false)
+
+#ifdef __aarch64__
+#define SKIP_TEST_IF_PA_SIZE_LESS_THAN(n) \
+ do { \
+ static const unsigned int pa_range_bits_arr[] = { \
+ PARANGE_0000, PARANGE_0001, PARANGE_0010, PARANGE_0011,\
+ PARANGE_0100, PARANGE_0101, PARANGE_0110 \
+ }; \
+ if (pa_range_bits_arr[get_pa_range()] < n) { \
+ tftf_testcase_printf("PA size less than %d bit\n", n); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (false)
+#else
+#define SKIP_TEST_IF_PA_SIZE_LESS_THAN(n) \
+ do { \
+ return TEST_RESULT_SKIPPED; \
+ } while (false)
+#endif
+
+#define SKIP_TEST_IF_BRBE_NOT_SUPPORTED() \
+ do { \
+ if (!get_feat_brbe_support()) { \
+ tftf_testcase_printf("FEAT_BRBE not supported\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (false)
+
+#define SKIP_TEST_IF_WFXT_NOT_SUPPORTED() \
+ do { \
+ if (!get_feat_wfxt_present()) { \
+ tftf_testcase_printf("ARMv8.7-WFxT not supported\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (false)
+
+#define SKIP_TEST_IF_RNG_TRAP_NOT_SUPPORTED() \
+ do { \
+ if (!is_feat_rng_trap_present()) { \
+ tftf_testcase_printf("ARMv8.5-RNG_TRAP not" \
+ "supported\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (false)
+
/* Helper macro to verify if system suspend API is supported */
#define is_psci_sys_susp_supported() \
(tftf_get_psci_feature_info(SMC_PSCI_SYSTEM_SUSPEND) \
@@ -307,4 +412,41 @@ test_result_t check_spmc_testing_set_up(uint32_t ffa_version_major,
uint32_t ffa_version_minor, const struct ffa_uuid *ffa_uuids,
size_t ffa_uuids_size);
+/**
+ * Turn on all cpus to execute a test in all.
+ * - 'cpu_on_handler' should have the code containing the test.
+ * - 'cpu_booted' is used for notifying which cores the test has been executed.
+ * This should be used in the test executed by cpu_on_handler at the end of
+ * processing to make sure it complies with this function's implementation.
+ */
+test_result_t spm_run_multi_core_test(uintptr_t cpu_on_handler,
+ event_t *cpu_booted);
+
+/**
+ * Call FFA_RUN in the designated SP to make it reach the message loop.
+ * Used within CPU_ON handlers, to bring up the SP in the current core.
+ */
+bool spm_core_sp_init(ffa_id_t sp_id);
+
+/**
+ * Enable/Disable managed exit interrupt for the provided SP.
+ */
+bool spm_set_managed_exit_int(ffa_id_t sp_id, bool enable);
+
+/**
+ * Initializes the Mailbox for other SPM related tests that need to use
+ * RXTX buffers.
+ */
+bool mailbox_init(struct mailbox_buffers mb);
+/*
+ * Utility function to wait for all CPUs other than the caller to be
+ * OFF.
+ */
+void wait_for_non_lead_cpus(void);
+
+/*
+ * Utility function to wait for a given CPU other than the caller to be
+ * OFF.
+ */
+void wait_for_core_to_turn_off(unsigned int mpidr);
#endif /* __TEST_HELPERS_H__ */
diff --git a/include/drivers/arm/sp805.h b/include/drivers/arm/sp805.h
index c033ccfd..75bcc123 100644
--- a/include/drivers/arm/sp805.h
+++ b/include/drivers/arm/sp805.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -47,9 +47,17 @@
#define SP805_WDOG_PCELL_ID_SHIFT 0
#define SP805_WDOG_PCELL_ID_MASK 0xff
+#define ARM_SP805_TWDG_CLK_HZ 32768
+
+/* Public APIs for non-trusted watchdog module. */
void sp805_wdog_start(unsigned int wdog_cycles);
void sp805_wdog_stop(void);
void sp805_wdog_refresh(void);
+/* Public APIs for trusted watchdog module. */
+void sp805_twdog_start(unsigned int wdog_cycles);
+void sp805_twdog_stop(void);
+void sp805_twdog_refresh(void);
+
#endif /* __SP805_H__ */
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
index 640457b5..a4b7d7d1 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -99,6 +99,16 @@
#define ID_MMFR4_CNP_LENGTH U(4)
#define ID_MMFR4_CNP_MASK U(0xf)
+/* ID_DFR0_EL1 definitions */
+#define ID_DFR0_TRACEFILT_SHIFT U(28)
+#define ID_DFR0_TRACEFILT_MASK U(0xf)
+#define ID_DFR0_TRACEFILT_SUPPORTED U(1)
+
+/* ID_DFR0_EL1 definitions */
+#define ID_DFR0_COPTRC_SHIFT U(12)
+#define ID_DFR0_COPTRC_MASK U(0xf)
+#define ID_DFR0_COPTRC_SUPPORTED U(1)
+
/* ID_PFR0 definitions */
#define ID_PFR0_AMU_SHIFT U(20)
#define ID_PFR0_AMU_LENGTH U(4)
@@ -522,6 +532,7 @@
#define ID_MMFR4 p15, 0, c0, c2, 6
#define ID_PFR0 p15, 0, c0, c1, 0
#define ID_PFR1 p15, 0, c0, c1, 1
+#define ID_DFR0 p15, 0, c0, c1, 2
#define MAIR0 p15, 0, c10, c2, 0
#define MAIR1 p15, 0, c10, c2, 1
#define TTBCR p15, 0, c2, c0, 2
@@ -725,4 +736,25 @@
#define AMEVTYPER1E p15, 0, c13, c15, 6
#define AMEVTYPER1F p15, 0, c13, c15, 7
+/*******************************************************************************
+ * Armv8.4 - Trace Filter System Registers
+ ******************************************************************************/
+#define TRFCR p15, 0, c1, c2, 1
+#define HTRFCR p15, 4, c1, c2, 1
+
+/*******************************************************************************
+ * Trace System Registers
+ ******************************************************************************/
+#define TRCAUXCTLR p14, 1, c0, c6, 0
+#define TRCRSR p14, 1, c0, c10, 0
+#define TRCCCCTLR p14, 1, c0, c14, 0
+#define TRCBBCTLR p14, 1, c0, c15, 0
+#define TRCEXTINSELR0 p14, 1, c0, c8, 4
+#define TRCEXTINSELR1 p14, 1, c0, c9, 4
+#define TRCEXTINSELR2 p14, 1, c0, c10, 4
+#define TRCEXTINSELR3 p14, 1, c0, c11, 4
+#define TRCCLAIMSET p14, 1, c7, c8, 6
+#define TRCCLAIMCLR p14, 1, c7, c9, 6
+#define TRCDEVARCH p14, 1, c7, c15, 6
+
#endif /* ARCH_H */
diff --git a/include/lib/aarch32/arch_features.h b/include/lib/aarch32/arch_features.h
index e2c2f2cc..3c6a338d 100644
--- a/include/lib/aarch32/arch_features.h
+++ b/include/lib/aarch32/arch_features.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -35,4 +35,28 @@ static inline uint32_t arch_get_debug_version(void)
DBGDIDR_VERSION_SHIFT);
}
+static inline bool get_armv8_4_trf_support(void)
+{
+ return ((read_id_dfr0() >> ID_DFR0_TRACEFILT_SHIFT) &
+ ID_DFR0_TRACEFILT_MASK) ==
+ ID_DFR0_TRACEFILT_SUPPORTED;
+}
+
+static inline bool is_armv8_4_dit_present(void)
+{
+ return ((read_id_pfr0() >> ID_PFR0_DIT_SHIFT) &
+ ID_PFR0_DIT_MASK) != 0;
+}
+
+static inline bool get_armv8_0_sys_reg_trace_support(void)
+{
+ return ((read_id_dfr0() >> ID_DFR0_COPTRC_SHIFT) &
+ ID_DFR0_COPTRC_MASK) ==
+ ID_DFR0_COPTRC_SUPPORTED;
+}
+
+static inline unsigned int get_armv9_2_feat_rme_support(void)
+{
+ return 0;
+}
#endif /* ARCH_FEATURES_H */
diff --git a/include/lib/aarch32/arch_helpers.h b/include/lib/aarch32/arch_helpers.h
index f2e3e009..aca3952f 100644
--- a/include/lib/aarch32/arch_helpers.h
+++ b/include/lib/aarch32/arch_helpers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -209,6 +209,7 @@ DEFINE_SYSREG_RW_FUNCS(elr_hyp)
DEFINE_COPROCR_READ_FUNC(mpidr, MPIDR)
DEFINE_COPROCR_READ_FUNC(midr, MIDR)
DEFINE_COPROCR_READ_FUNC(id_mmfr4, ID_MMFR4)
+DEFINE_COPROCR_READ_FUNC(id_dfr0, ID_DFR0)
DEFINE_COPROCR_READ_FUNC(id_pfr0, ID_PFR0)
DEFINE_COPROCR_READ_FUNC(id_pfr1, ID_PFR1)
DEFINE_COPROCR_READ_FUNC(isr, ISR)
@@ -294,6 +295,23 @@ DEFINE_COPROCR_RW_FUNCS_64(par, PAR_64)
DEFINE_COPROCR_RW_FUNCS(nsacr, NSACR)
+/* AArch32 coproc registers for trace filter */
+DEFINE_COPROCR_RW_FUNCS(htrfcr, HTRFCR)
+DEFINE_COPROCR_RW_FUNCS(trfcr, TRFCR)
+
+/* AArch32 Trace System Registers */
+DEFINE_COPROCR_RW_FUNCS(trcauxctlr, TRCAUXCTLR)
+DEFINE_COPROCR_RW_FUNCS(trcrsr, TRCRSR)
+DEFINE_COPROCR_RW_FUNCS(trcbbctlr, TRCBBCTLR)
+DEFINE_COPROCR_RW_FUNCS(trcccctlr, TRCCCCTLR)
+DEFINE_COPROCR_RW_FUNCS(trcextinselr0, TRCEXTINSELR0)
+DEFINE_COPROCR_RW_FUNCS(trcextinselr1, TRCEXTINSELR1)
+DEFINE_COPROCR_RW_FUNCS(trcextinselr2, TRCEXTINSELR2)
+DEFINE_COPROCR_RW_FUNCS(trcextinselr3, TRCEXTINSELR3)
+DEFINE_COPROCR_RW_FUNCS(trcclaimset, TRCCLAIMSET)
+DEFINE_COPROCR_RW_FUNCS(trcclaimclr, TRCCLAIMCLR)
+DEFINE_COPROCR_READ_FUNC(trcdevarch, TRCDEVARCH)
+
/* AArch32 coproc registers for 32bit MMU descriptor support */
DEFINE_COPROCR_RW_FUNCS(prrr, PRRR)
DEFINE_COPROCR_RW_FUNCS(nmrr, NMRR)
@@ -404,6 +422,9 @@ static inline unsigned int get_current_el(void)
#define read_daif() read_cpsr()
#define write_daif(flags) write_cpsr(flags)
+#define read_dit() read_cpsr()
+#define write_dit(flags) write_cpsr(flags)
+
#define read_cnthp_cval_el2() read64_cnthp_cval_el2()
#define write_cnthp_cval_el2(v) write64_cnthp_cval_el2(v)
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index f2681676..534e1cf2 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -145,6 +145,11 @@
#define ID_AA64PFR0_CSV2_SHIFT U(56)
#define ID_AA64PFR0_CSV2_MASK ULL(0xf)
#define ID_AA64PFR0_CSV2_LENGTH U(4)
+#define ID_AA64PFR0_FEAT_RME_SHIFT U(52)
+#define ID_AA64PFR0_FEAT_RME_MASK ULL(0xf)
+#define ID_AA64PFR0_FEAT_RME_LENGTH U(4)
+#define ID_AA64PFR0_FEAT_RME_NOT_SUPPORTED U(0)
+#define ID_AA64PFR0_FEAT_RME_V1 U(1)
/* ID_AA64DFR0_EL1.PMS definitions (for ARMv8.2+) */
#define ID_AA64DFR0_PMS_SHIFT U(32)
@@ -162,6 +167,26 @@
#define ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED U(8)
#define ID_AA64DFR0_V8_4_DEBUG_ARCH_SUPPORTED U(9)
+/* ID_AA64DFR0_EL1.BRBE definitions */
+#define ID_AA64DFR0_BRBE_SHIFT U(52)
+#define ID_AA64DFR0_BRBE_MASK ULL(0xf)
+#define ID_AA64DFR0_BRBE_SUPPORTED ULL(1)
+
+/* ID_AA64DFR0_EL1.TraceBuffer definitions */
+#define ID_AA64DFR0_TRACEBUFFER_SHIFT U(44)
+#define ID_AA64DFR0_TRACEBUFFER_MASK ULL(0xf)
+#define ID_AA64DFR0_TRACEBUFFER_SUPPORTED ULL(1)
+
+/* ID_DFR0_EL1.Tracefilt definitions */
+#define ID_AA64DFR0_TRACEFILT_SHIFT U(40)
+#define ID_AA64DFR0_TRACEFILT_MASK U(0xf)
+#define ID_AA64DFR0_TRACEFILT_SUPPORTED U(1)
+
+/* ID_AA64DFR0_EL1.TraceVer definitions */
+#define ID_AA64DFR0_TRACEVER_SHIFT U(4)
+#define ID_AA64DFR0_TRACEVER_MASK ULL(0xf)
+#define ID_AA64DFR0_TRACEVER_SUPPORTED ULL(1)
+
#define EL_IMPL_NONE ULL(0)
#define EL_IMPL_A64ONLY ULL(1)
#define EL_IMPL_A64_A32 ULL(2)
@@ -185,6 +210,16 @@
#define ID_AA64ISAR1_APA_WIDTH U(4)
#define ID_AA64ISAR1_APA_MASK ULL(0xf)
+/* ID_AA64ISAR2_EL1 definitions */
+#define ID_AA64ISAR2_EL1 S3_0_C0_C6_2
+#define ID_AA64ISAR2_WFXT_MASK ULL(0xf)
+#define ID_AA64ISAR2_WFXT_SHIFT U(0x0)
+#define ID_AA64ISAR2_WFXT_SUPPORTED ULL(0x2)
+#define ID_AA64ISAR2_GPA3_SHIFT U(8)
+#define ID_AA64ISAR2_GPA3_MASK ULL(0xf)
+#define ID_AA64ISAR2_APA3_SHIFT U(12)
+#define ID_AA64ISAR2_APA3_MASK ULL(0xf)
+
/* ID_AA64MMFR0_EL1 definitions */
#define ID_AA64MMFR0_EL1_PARANGE_SHIFT U(0)
#define ID_AA64MMFR0_EL1_PARANGE_MASK ULL(0xf)
@@ -223,6 +258,21 @@
#define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED ULL(0x1)
#define ID_AA64MMFR0_EL1_TGRAN16_NOT_SUPPORTED ULL(0x0)
+/* ID_AA64MMFR1_EL1 definitions */
+#define ID_AA64MMFR1_EL1_PAN_SHIFT U(20)
+#define ID_AA64MMFR1_EL1_PAN_MASK ULL(0xf)
+#define ID_AA64MMFR1_EL1_PAN_NOT_SUPPORTED ULL(0x0)
+#define ID_AA64MMFR1_EL1_PAN_SUPPORTED ULL(0x1)
+#define ID_AA64MMFR1_EL1_PAN2_SUPPORTED ULL(0x2)
+#define ID_AA64MMFR1_EL1_PAN3_SUPPORTED ULL(0x3)
+#define ID_AA64MMFR1_EL1_HCX_SHIFT U(40)
+#define ID_AA64MMFR1_EL1_HCX_MASK ULL(0xf)
+#define ID_AA64MMFR1_EL1_HCX_SUPPORTED ULL(0x1)
+#define ID_AA64MMFR1_EL1_HCX_NOT_SUPPORTED ULL(0x0)
+#define ID_AA64MMFR1_EL1_AFP_SHIFT U(44)
+#define ID_AA64MMFR1_EL1_AFP_MASK ULL(0xf)
+#define ID_AA64MMFR1_EL1_AFP_SUPPORTED ULL(0x1)
+
/* ID_AA64MMFR2_EL1 definitions */
#define ID_AA64MMFR2_EL1 S3_0_C0_C7_2
@@ -246,10 +296,19 @@
#define ID_AA64PFR1_EL1_MTE_SHIFT U(8)
#define ID_AA64PFR1_EL1_MTE_MASK ULL(0xf)
+#define ID_AA64PFR1_EL1_RNDR_TRAP_SHIFT U(28)
+#define ID_AA64PFR1_EL1_RNDR_TRAP_MASK ULL(0xf)
+
+#define ID_AA64PFR1_EL1_RNG_TRAP_SUPPORTED ULL(0x1)
+#define ID_AA64PFR1_EL1_RNG_TRAP_NOT_SUPPORTED ULL(0x0)
+
#define MTE_UNIMPLEMENTED ULL(0)
#define MTE_IMPLEMENTED_EL0 ULL(1) /* MTE is only implemented at EL0 */
#define MTE_IMPLEMENTED_ELX ULL(2) /* MTE is implemented at all ELs */
+#define ID_AA64PFR1_EL1_SME_SHIFT U(24)
+#define ID_AA64PFR1_EL1_SME_MASK ULL(0xf)
+
/* ID_PFR1_EL1 definitions */
#define ID_PFR1_VIRTEXT_SHIFT U(12)
#define ID_PFR1_VIRTEXT_MASK U(0xf)
@@ -289,6 +348,7 @@
#define SCTLR_WXN_BIT (ULL(1) << 19)
#define SCTLR_UWXN_BIT (ULL(1) << 20)
#define SCTLR_IESB_BIT (ULL(1) << 21)
+#define SCTLR_SPAN_BIT (ULL(1) << 23)
#define SCTLR_E0E_BIT (ULL(1) << 24)
#define SCTLR_EE_BIT (ULL(1) << 25)
#define SCTLR_UCI_BIT (ULL(1) << 26)
@@ -371,6 +431,7 @@
#define HCR_AMVOFFEN_BIT (ULL(1) << 51)
#define HCR_API_BIT (ULL(1) << 41)
#define HCR_APK_BIT (ULL(1) << 40)
+#define HCR_E2H_BIT (ULL(1) << 34)
#define HCR_TGE_BIT (ULL(1) << 27)
#define HCR_RW_SHIFT U(31)
#define HCR_RW_BIT (ULL(1) << HCR_RW_SHIFT)
@@ -403,6 +464,7 @@
#define TCPAC_BIT (U(1) << 31)
#define TAM_BIT (U(1) << 30)
#define TTA_BIT (U(1) << 20)
+#define ESM_BIT (U(1) << 12)
#define TFP_BIT (U(1) << 10)
#define CPTR_EZ_BIT (U(1) << 8)
#define CPTR_EL3_RESET_VAL U(0x0)
@@ -411,7 +473,10 @@
#define CPTR_EL2_RES1 ((ULL(3) << 12) | (ULL(1) << 9) | (ULL(0xff)))
#define CPTR_EL2_TCPAC_BIT (ULL(1) << 31)
#define CPTR_EL2_TAM_BIT (ULL(1) << 30)
+#define CPTR_EL2_SMEN_MASK ULL(0x3)
+#define CPTR_EL2_SMEN_SHIFT U(24)
#define CPTR_EL2_TTA_BIT (ULL(1) << 20)
+#define CPTR_EL2_TSM_BIT (ULL(1) << 12)
#define CPTR_EL2_TFP_BIT (ULL(1) << 10)
#define CPTR_EL2_TZ_BIT (ULL(1) << 8)
#define CPTR_EL2_RESET_VAL CPTR_EL2_RES1
@@ -600,6 +665,13 @@
#define MAX_CACHE_LINE_SIZE U(0x800) /* 2KB */
+/*
+ * FPCR definitions
+ */
+#define FPCR_FIZ_BIT (ULL(1) << 0)
+#define FPCR_AH_BIT (ULL(1) << 1)
+#define FPCR_NEP_BIT (ULL(1) << 2)
+
/* Physical timer control register bit fields shifts and masks */
#define CNTP_CTL_ENABLE_SHIFT U(0)
#define CNTP_CTL_IMASK_SHIFT U(1)
@@ -613,6 +685,8 @@
#define ESR_EC_SHIFT U(26)
#define ESR_EC_MASK U(0x3f)
#define ESR_EC_LENGTH U(6)
+#define ESR_ISS_SHIFT U(0x0)
+#define ESR_ISS_MASK U(0x1ffffff)
#define EC_UNKNOWN U(0x0)
#define EC_WFE_WFI U(0x1)
#define EC_AARCH32_CP15_MRC_MCR U(0x3)
@@ -639,6 +713,10 @@
#define EC_AARCH32_FP U(0x28)
#define EC_AARCH64_FP U(0x2c)
#define EC_SERROR U(0x2f)
+/* Data Fault Status code, not all error codes listed */
+#define ISS_DFSC_MASK U(0x3f)
+#define DFSC_EXT_DABORT U(0x10)
+#define DFSC_GPF_DABORT U(0x28)
/*
* External Abort bit in Instruction and Data Aborts synchronous exception
@@ -647,6 +725,7 @@
#define ESR_ISS_EABORT_EA_BIT U(9)
#define EC_BITS(x) (((x) >> ESR_EC_SHIFT) & ESR_EC_MASK)
+#define ISS_BITS(x) (((x) >> ESR_ISS_SHIFT) & ESR_ISS_MASK)
/* Reset bit inside the Reset management register for EL3 (RMR_EL3) */
#define RMR_RESET_REQUEST_SHIFT U(0x1)
@@ -738,6 +817,35 @@
#define ZCR_EL2_LEN_MASK U(0xf)
/*******************************************************************************
+ * Definitions for system register interface to SME
+ ******************************************************************************/
+#define ID_AA64SMFR0_EL1 S3_0_C0_C4_5
+#define SVCR S3_3_C4_C2_2
+#define TPIDR2_EL0 S3_3_C13_C0_5
+#define SMCR_EL2 S3_4_C1_C2_6
+
+/* ID_AA64SMFR0_EL1 definitions */
+#define ID_AA64SMFR0_EL1_FA64_BIT (UL(1) << 63)
+
+/* SVCR definitions */
+#define SVCR_ZA_BIT (U(1) << 1)
+#define SVCR_SM_BIT (U(1) << 0)
+
+/* SMPRI_EL1 definitions */
+#define SMPRI_EL1_PRIORITY_SHIFT U(0)
+#define SMPRI_EL1_PRIORITY_MASK U(0xf)
+
+/* SMPRIMAP_EL2 definitions */
+/* Register is composed of 16 priority map fields of 4 bits numbered 0-15. */
+#define SMPRIMAP_EL2_MAP_SHIFT(pri) U((pri) * 4)
+#define SMPRIMAP_EL2_MAP_MASK U(0xf)
+
+/* SMCR_ELx definitions */
+#define SMCR_ELX_LEN_SHIFT U(0)
+#define SMCR_ELX_LEN_MASK U(0x1ff)
+#define SMCR_ELX_FA64_BIT (U(1) << 31)
+
+/*******************************************************************************
* Definitions of MAIR encodings for device and normal memory
******************************************************************************/
/*
@@ -796,7 +904,18 @@
/*******************************************************************************
* Definitions for system register interface to SPE
******************************************************************************/
+#define PMSCR_EL1 S3_0_C9_C9_0
+#define PMSNEVFR_EL1 S3_0_C9_C9_1
+#define PMSICR_EL1 S3_0_C9_C9_2
+#define PMSIRR_EL1 S3_0_C9_C9_3
+#define PMSFCR_EL1 S3_0_C9_C9_4
+#define PMSEVFR_EL1 S3_0_C9_C9_5
+#define PMSLATFR_EL1 S3_0_C9_C9_6
+#define PMSIDR_EL1 S3_0_C9_C9_7
#define PMBLIMITR_EL1 S3_0_C9_C10_0
+#define PMBPTR_EL1 S3_0_C9_C10_1
+#define PMBSR_EL1 S3_0_C9_C10_3
+#define PMSCR_EL2 S3_4_C9_C9_0
/*******************************************************************************
* Definitions for system register interface to MPAM
@@ -952,6 +1071,12 @@
#define ERXPFGCTL_CDEN_BIT (U(1) << 31)
/*******************************************************************************
+ * Armv8.1 Registers - Privileged Access Never Registers
+ ******************************************************************************/
+#define PAN S3_0_C4_C2_3
+#define PAN_BIT BIT(22)
+
+/*******************************************************************************
* Armv8.3 Pointer Authentication Registers
******************************************************************************/
#define APIAKeyLo_EL1 S3_0_C2_C1_0
@@ -998,5 +1123,59 @@
******************************************************************************/
#define CNTPOFF_EL2 S3_4_C14_C0_6
+/*******************************************************************************
+ * Armv9.0 - Trace Buffer Extension System Registers
+ ******************************************************************************/
+#define TRBLIMITR_EL1 S3_0_C9_C11_0
+#define TRBPTR_EL1 S3_0_C9_C11_1
+#define TRBBASER_EL1 S3_0_C9_C11_2
+#define TRBSR_EL1 S3_0_C9_C11_3
+#define TRBMAR_EL1 S3_0_C9_C11_4
+#define TRBTRG_EL1 S3_0_C9_C11_6
+#define TRBIDR_EL1 S3_0_C9_C11_7
+
+/*******************************************************************************
+ * FEAT_BRBE - Branch Record Buffer Extension System Registers
+ ******************************************************************************/
+
+#define BRBCR_EL1 S2_1_C9_C0_0
+#define BRBCR_EL2 S2_4_C9_C0_0
+#define BRBFCR_EL1 S2_1_C9_C0_1
+#define BRBTS_EL1 S2_1_C9_C0_2
+#define BRBINFINJ_EL1 S2_1_C9_C1_0
+#define BRBSRCINJ_EL1 S2_1_C9_C1_1
+#define BRBTGTINJ_EL1 S2_1_C9_C1_2
+#define BRBIDR0_EL1 S2_1_C9_C2_0
+
+/*******************************************************************************
+ * Armv8.4 - Trace Filter System Registers
+ ******************************************************************************/
+#define TRFCR_EL1 S3_0_C1_C2_1
+#define TRFCR_EL2 S3_4_C1_C2_1
+
+/*******************************************************************************
+ * Trace System Registers
+ ******************************************************************************/
+#define TRCAUXCTLR S2_1_C0_C6_0
+#define TRCRSR S2_1_C0_C10_0
+#define TRCCCCTLR S2_1_C0_C14_0
+#define TRCBBCTLR S2_1_C0_C15_0
+#define TRCEXTINSELR0 S2_1_C0_C8_4
+#define TRCEXTINSELR1 S2_1_C0_C9_4
+#define TRCEXTINSELR2 S2_1_C0_C10_4
+#define TRCEXTINSELR3 S2_1_C0_C11_4
+#define TRCCLAIMSET S2_1_c7_c8_6
+#define TRCCLAIMCLR S2_1_c7_c9_6
+#define TRCDEVARCH S2_1_c7_c15_6
+
+/*******************************************************************************
+ * FEAT_HCX - Extended Hypervisor Configuration Register
+ ******************************************************************************/
+#define HCRX_EL2 S3_4_C1_C2_2
+#define HCRX_EL2_FGTnXS_BIT (UL(1) << 4)
+#define HCRX_EL2_FnXS_BIT (UL(1) << 3)
+#define HCRX_EL2_EnASR_BIT (UL(1) << 2)
+#define HCRX_EL2_EnALS_BIT (UL(1) << 1)
+#define HCRX_EL2_EnAS0_BIT (UL(1) << 0)
#endif /* ARCH_H */
diff --git a/include/lib/aarch64/arch_features.h b/include/lib/aarch64/arch_features.h
index 15eb784a..761a42ee 100644
--- a/include/lib/aarch64/arch_features.h
+++ b/include/lib/aarch64/arch_features.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,7 +8,6 @@
#define ARCH_FEATURES_H
#include <stdbool.h>
-
#include <arch_helpers.h>
static inline bool is_armv7_gentimer_present(void)
@@ -17,6 +16,12 @@ static inline bool is_armv7_gentimer_present(void)
return true;
}
+static inline bool is_armv8_1_pan_present(void)
+{
+ return ((read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_PAN_SHIFT) &
+ ID_AA64MMFR1_EL1_PAN_MASK) != 0U;
+}
+
static inline bool is_armv8_2_sve_present(void)
{
return ((read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT) &
@@ -29,31 +34,62 @@ static inline bool is_armv8_2_ttcnp_present(void)
ID_AA64MMFR2_EL1_CNP_MASK) != 0U;
}
-static inline bool is_armv8_3_pauth_present(void)
+static inline bool is_feat_pacqarma3_present(void)
{
- uint64_t mask = (ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) |
- (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT) |
- (ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) |
- (ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT);
+ uint64_t mask_id_aa64isar2 =
+ (ID_AA64ISAR2_GPA3_MASK << ID_AA64ISAR2_GPA3_SHIFT) |
+ (ID_AA64ISAR2_APA3_MASK << ID_AA64ISAR2_APA3_SHIFT);
- /* If any of the fields is not zero, PAuth is present */
- return (read_id_aa64isar1_el1() & mask) != 0U;
+ /* If any of the fields is not zero, QARMA3 algorithm is present */
+ return (read_id_aa64isar2_el1() & mask_id_aa64isar2) != 0U;
}
-static inline bool is_armv8_3_pauth_apa_api_present(void)
+static inline bool is_armv8_3_pauth_present(void)
{
- uint64_t mask = (ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) |
- (ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT);
+ uint64_t mask_id_aa64isar1 =
+ (ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) |
+ (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT) |
+ (ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) |
+ (ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT);
+
+ /*
+ * If any of the fields is not zero or QARMA3 is present,
+ * PAuth is present.
+ */
+ return ((read_id_aa64isar1_el1() & mask_id_aa64isar1) != 0U ||
+ is_feat_pacqarma3_present());
+}
+
+static inline bool is_armv8_3_pauth_apa_api_apa3_present(void)
+{
+ uint64_t mask_id_aa64isar1 =
+ (ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) |
+ (ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT);
- return (read_id_aa64isar1_el1() & mask) != 0U;
+ uint64_t mask_id_aa64isar2 =
+ (ID_AA64ISAR2_APA3_MASK << ID_AA64ISAR2_APA3_SHIFT);
+
+ return ((read_id_aa64isar1_el1() & mask_id_aa64isar1) |
+ (read_id_aa64isar2_el1() & mask_id_aa64isar2)) != 0U;
}
-static inline bool is_armv8_3_pauth_gpa_gpi_present(void)
+static inline bool is_armv8_3_pauth_gpa_gpi_gpa3_present(void)
{
- uint64_t mask = (ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) |
- (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT);
+ uint64_t mask_id_aa64isar1 =
+ (ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) |
+ (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT);
+
+ uint64_t mask_id_aa64isar2 =
+ (ID_AA64ISAR2_GPA3_MASK << ID_AA64ISAR2_GPA3_SHIFT);
- return (read_id_aa64isar1_el1() & mask) != 0U;
+ return ((read_id_aa64isar1_el1() & mask_id_aa64isar1) |
+ (read_id_aa64isar2_el1() & mask_id_aa64isar2)) != 0U;
+}
+
+static inline bool is_armv8_4_dit_present(void)
+{
+ return ((read_id_aa64pfr0_el1() >> ID_AA64PFR0_DIT_SHIFT) &
+ ID_AA64PFR0_DIT_MASK) == 1U;
}
static inline bool is_armv8_4_ttst_present(void)
@@ -86,10 +122,80 @@ static inline unsigned long int get_armv8_6_ecv_support(void)
ID_AA64MMFR0_EL1_ECV_MASK);
}
+static inline unsigned long int get_pa_range(void)
+{
+ return ((read_id_aa64mmfr0_el1() >> ID_AA64MMFR0_EL1_PARANGE_SHIFT) &
+ ID_AA64MMFR0_EL1_PARANGE_MASK);
+}
+
static inline uint32_t arch_get_debug_version(void)
{
return ((read_id_aa64dfr0_el1() & ID_AA64DFR0_DEBUG_BITS) >>
ID_AA64DFR0_DEBUG_SHIFT);
}
+static inline bool get_armv9_0_trbe_support(void)
+{
+ return ((read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEBUFFER_SHIFT) &
+ ID_AA64DFR0_TRACEBUFFER_MASK) ==
+ ID_AA64DFR0_TRACEBUFFER_SUPPORTED;
+}
+
+static inline bool get_armv8_4_trf_support(void)
+{
+ return ((read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEFILT_SHIFT) &
+ ID_AA64DFR0_TRACEFILT_MASK) ==
+ ID_AA64DFR0_TRACEFILT_SUPPORTED;
+}
+
+static inline bool get_armv8_0_sys_reg_trace_support(void)
+{
+ return ((read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEVER_SHIFT) &
+ ID_AA64DFR0_TRACEVER_MASK) ==
+ ID_AA64DFR0_TRACEVER_SUPPORTED;
+}
+
+static inline unsigned int get_armv9_2_feat_rme_support(void)
+{
+ /*
+ * Return the RME version, zero if not supported. This function can be
+ * used as both an integer value for the RME version or compared to zero
+ * to detect RME presence.
+ */
+ return (unsigned int)(read_id_aa64pfr0_el1() >>
+ ID_AA64PFR0_FEAT_RME_SHIFT) & ID_AA64PFR0_FEAT_RME_MASK;
+}
+
+static inline bool get_feat_hcx_support(void)
+{
+ return (((read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_HCX_SHIFT) &
+ ID_AA64MMFR1_EL1_HCX_MASK) == ID_AA64MMFR1_EL1_HCX_SUPPORTED);
+}
+
+static inline bool get_feat_afp_present(void)
+{
+ return (((read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_AFP_SHIFT) &
+ ID_AA64MMFR1_EL1_AFP_MASK) == ID_AA64MMFR1_EL1_AFP_SUPPORTED);
+}
+
+static inline bool get_feat_brbe_support(void)
+{
+ return ((read_id_aa64dfr0_el1() >> ID_AA64DFR0_BRBE_SHIFT) &
+ ID_AA64DFR0_BRBE_MASK) ==
+ ID_AA64DFR0_BRBE_SUPPORTED;
+}
+
+static inline bool get_feat_wfxt_present(void)
+{
+ return (((read_id_aa64isar2_el1() >> ID_AA64ISAR2_WFXT_SHIFT) &
+ ID_AA64ISAR2_WFXT_MASK) == ID_AA64ISAR2_WFXT_SUPPORTED);
+}
+
+static inline bool is_feat_rng_trap_present(void)
+{
+ return (((read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_RNDR_TRAP_SHIFT) &
+ ID_AA64PFR1_EL1_RNDR_TRAP_MASK)
+ == ID_AA64PFR1_EL1_RNG_TRAP_SUPPORTED);
+}
+
#endif /* ARCH_FEATURES_H */
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index 39f1e3b8..e10ddab2 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -75,6 +75,13 @@ static inline void _op ## _type(void) \
__asm__ (#_op " " #_type); \
}
+/* Define function for system instruction with register with variable parameter */
+#define DEFINE_SYSOP_PARAM_FUNC(_op) \
+static inline void _op(uint64_t v) \
+{ \
+ __asm__ (#_op " " "%0" : : "r" (v)); \
+}
+
/* Define function for system instruction with register parameter */
#define DEFINE_SYSOP_TYPE_PARAM_FUNC(_op, _type) \
static inline void _op ## _type(uint64_t v) \
@@ -187,6 +194,8 @@ DEFINE_SYSREG_READ_FUNC(id_afr0_el1)
DEFINE_SYSREG_READ_FUNC(CurrentEl)
DEFINE_SYSREG_READ_FUNC(ctr_el0)
DEFINE_SYSREG_RW_FUNCS(daif)
+DEFINE_SYSREG_RW_FUNCS(nzcv)
+DEFINE_SYSREG_READ_FUNC(spsel)
DEFINE_SYSREG_RW_FUNCS(spsr_el1)
DEFINE_SYSREG_RW_FUNCS(spsr_el2)
DEFINE_SYSREG_RW_FUNCS(spsr_el3)
@@ -197,6 +206,7 @@ DEFINE_SYSREG_RW_FUNCS(elr_el3)
DEFINE_SYSOP_FUNC(wfi)
DEFINE_SYSOP_FUNC(wfe)
DEFINE_SYSOP_FUNC(sev)
+DEFINE_SYSOP_FUNC(sevl)
DEFINE_SYSOP_TYPE_FUNC(dsb, sy)
DEFINE_SYSOP_TYPE_FUNC(dmb, sy)
DEFINE_SYSOP_TYPE_FUNC(dmb, st)
@@ -215,6 +225,9 @@ DEFINE_SYSOP_TYPE_FUNC(dmb, ishst)
DEFINE_SYSOP_TYPE_FUNC(dmb, ish)
DEFINE_SYSOP_FUNC(isb)
+DEFINE_SYSOP_PARAM_FUNC(wfit)
+DEFINE_SYSOP_PARAM_FUNC(wfet)
+
static inline void enable_irq(void)
{
/*
@@ -292,6 +305,7 @@ void __dead2 smc(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3,
DEFINE_SYSREG_READ_FUNC(midr_el1)
DEFINE_SYSREG_READ_FUNC(mpidr_el1)
DEFINE_SYSREG_READ_FUNC(id_aa64mmfr0_el1)
+DEFINE_SYSREG_READ_FUNC(id_aa64mmfr1_el1)
DEFINE_SYSREG_RW_FUNCS(scr_el3)
DEFINE_SYSREG_RW_FUNCS(hcr_el2)
@@ -403,6 +417,10 @@ DEFINE_SYSREG_RW_FUNCS(pmccfiltr_el0)
DEFINE_SYSREG_RW_FUNCS(pmevtyper0_el0)
DEFINE_SYSREG_READ_FUNC(pmevcntr0_el0)
+/* Armv8.5 FEAT_RNG Registers */
+DEFINE_SYSREG_READ_FUNC(rndr)
+DEFINE_SYSREG_READ_FUNC(rndrrs)
+
/* GICv3 System Registers */
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el1, ICC_SRE_EL1)
@@ -436,11 +454,28 @@ DEFINE_RENAME_SYSREG_RW_FUNCS(mpam3_el3, MPAM3_EL3)
DEFINE_RENAME_SYSREG_RW_FUNCS(mpam2_el2, MPAM2_EL2)
DEFINE_RENAME_SYSREG_RW_FUNCS(mpamhcr_el2, MPAMHCR_EL2)
+/* Static profiling control registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmscr_el1, PMSCR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmsevfr_el1, PMSEVFR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmsfcr_el1, PMSFCR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmsicr_el1, PMSICR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmsidr_el1, PMSIDR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmsirr_el1, PMSIRR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmslatfr_el1, PMSLATFR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmsnevfr_el1, PMSNEVFR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(pmblimitr_el1, PMBLIMITR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmbptr_el1, PMBPTR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmbsr_el1, PMBSR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmscr_el2, PMSCR_EL2)
DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el3, ZCR_EL3)
DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el2, ZCR_EL2)
+DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64smfr0_el1, ID_AA64SMFR0_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(svcr, SVCR)
+DEFINE_RENAME_SYSREG_RW_FUNCS(tpidr2_el0, TPIDR2_EL0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(smcr_el2, SMCR_EL2)
+
DEFINE_RENAME_SYSREG_READ_FUNC(erridr_el1, ERRIDR_EL1)
DEFINE_RENAME_SYSREG_WRITE_FUNC(errselr_el1, ERRSELR_EL1)
@@ -451,6 +486,9 @@ DEFINE_RENAME_SYSREG_READ_FUNC(erxaddr_el1, ERXADDR_EL1)
DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc0_el1, ERXMISC0_EL1)
DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc1_el1, ERXMISC1_EL1)
+/* Armv8.1 Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(pan, PAN)
+
/* Armv8.2 Registers */
DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64mmfr2_el1, ID_AA64MMFR2_EL1)
@@ -479,6 +517,9 @@ DEFINE_RENAME_SYSREG_RW_FUNCS(tfsr_el1, TFSR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(rgsr_el1, RGSR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(gcr_el1, GCR_EL1)
+/* Armv8.4 Data Independent Timing */
+DEFINE_RENAME_SYSREG_RW_FUNCS(dit, DIT)
+
/* Armv8.6 Fine Grained Virtualization Traps Registers */
DEFINE_RENAME_SYSREG_RW_FUNCS(hfgrtr_el2, HFGRTR_EL2)
DEFINE_RENAME_SYSREG_RW_FUNCS(hfgwtr_el2, HFGWTR_EL2)
@@ -489,6 +530,51 @@ DEFINE_RENAME_SYSREG_RW_FUNCS(hdfgwtr_el2, HDFGWTR_EL2)
/* Armv8.6 Enhanced Counter Virtualization Register */
DEFINE_RENAME_SYSREG_RW_FUNCS(cntpoff_el2, CNTPOFF_EL2)
+/* Armv9.0 Trace buffer extension System Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(trblimitr_el1, TRBLIMITR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trbptr_el1, TRBPTR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trbbaser_el1, TRBBASER_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trbsr_el1, TRBSR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trbmar_el1, TRBMAR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trbtrg_el1, TRBTRG_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(trbidr_el1, TRBIDR_EL1)
+
+/* FEAT_BRBE Branch record buffer extension system registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(brbcr_el1, BRBCR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(brbcr_el2, BRBCR_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(brbfcr_el1, BRBFCR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(brbts_el1, BRBTS_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(brbinfinj_el1, BRBINFINJ_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(brbsrcinj_el1, BRBSRCINJ_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(brbtgtinj_el1, BRBTGTINJ_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(brbidr0_el1, BRBIDR0_EL1)
+
+/* Armv8.4 Trace filter control System Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(trfcr_el1, TRFCR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trfcr_el2, TRFCR_EL2)
+
+/* Trace System Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(trcauxctlr, TRCAUXCTLR)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trcrsr, TRCRSR)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trcbbctlr, TRCBBCTLR)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trcccctlr, TRCCCCTLR)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trcextinselr0, TRCEXTINSELR0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trcextinselr1, TRCEXTINSELR1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trcextinselr2, TRCEXTINSELR2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trcextinselr3, TRCEXTINSELR3)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trcclaimset, TRCCLAIMSET)
+DEFINE_RENAME_SYSREG_RW_FUNCS(trcclaimclr, TRCCLAIMCLR)
+DEFINE_RENAME_SYSREG_READ_FUNC(trcdevarch, TRCDEVARCH)
+
+/* FEAT_HCX HCRX_EL2 */
+DEFINE_RENAME_SYSREG_RW_FUNCS(hcrx_el2, HCRX_EL2)
+
+/* Control floating point behaviour */
+DEFINE_RENAME_SYSREG_RW_FUNCS(fpcr, FPCR)
+
+/* ID_AA64ISAR2_EL1 */
+DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64isar2_el1, ID_AA64ISAR2_EL1)
+
#define IS_IN_EL(x) \
(GET_EL(read_CurrentEl()) == MODE_EL##x)
@@ -527,4 +613,16 @@ static inline uint64_t syscounter_read(void)
return read_cntpct_el0();
}
+/* Read the value of the Counter-timer virtual count. */
+static inline uint64_t virtualcounter_read(void)
+{
+ /*
+ * The instruction barrier is needed to guarantee that we read an
+ * accurate value. Otherwise, the CPU might speculatively read it and
+ * return a stale value.
+ */
+ isb();
+ return read_cntvct_el0();
+}
+
#endif /* ARCH_HELPERS_H */
diff --git a/include/lib/aarch64/sync.h b/include/lib/aarch64/sync.h
new file mode 100644
index 00000000..5058980c
--- /dev/null
+++ b/include/lib/aarch64/sync.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SYNC_H__
+#define __SYNC_H__
+
+typedef bool (*exception_handler_t)(void);
+void register_custom_sync_exception_handler(exception_handler_t handler);
+void unregister_custom_sync_exception_handler(void);
+
+#endif /* __SYNC_H__ */
diff --git a/include/lib/extensions/sme.h b/include/lib/extensions/sme.h
new file mode 100644
index 00000000..d1a17c55
--- /dev/null
+++ b/include/lib/extensions/sme.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SME_H
+#define SME_H
+
+#define SME_SMCR_LEN_MAX U(0x1FF)
+
+bool feat_sme_supported(void);
+bool feat_sme_fa64_supported(void);
+int sme_enable(void);
+void sme_smstart(bool enable_za);
+void sme_smstop(bool disable_za);
+
+/* Assembly function prototypes */
+uint64_t sme_rdvl_1(void);
+void sme_try_illegal_instruction(void);
+
+#endif /* SME_H */
diff --git a/include/lib/extensions/sve.h b/include/lib/extensions/sve.h
new file mode 100644
index 00000000..45481d74
--- /dev/null
+++ b/include/lib/extensions/sve.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SVE_H
+#define SVE_H
+
+#define fill_sve_helper(num) "ldr z"#num", [%0, #"#num", MUL VL];"
+#define read_sve_helper(num) "str z"#num", [%0, #"#num", MUL VL];"
+
+/*
+ * Max. vector length permitted by the architecture:
+ * SVE: 2048 bits = 256 bytes
+ */
+#define SVE_VECTOR_LEN_BYTES 256
+#define SVE_NUM_VECTORS 32
+
+typedef uint8_t sve_vector_t[SVE_VECTOR_LEN_BYTES];
+
+#ifdef __aarch64__
+
+/* Returns the SVE implemented VL in bytes (constrained by ZCR_EL3.LEN) */
+static inline uint64_t sve_vector_length_get(void)
+{
+ uint64_t vl;
+
+ __asm__ volatile(
+ ".arch_extension sve\n"
+ "rdvl %0, #1;"
+ ".arch_extension nosve\n"
+ : "=r" (vl)
+ );
+
+ return vl;
+}
+
+#endif /* __aarch64__ */
+
+#endif /* SVE_H */
diff --git a/include/plat/common/common_def.h b/include/plat/common/common_def.h
new file mode 100644
index 00000000..844c0c8b
--- /dev/null
+++ b/include/plat/common/common_def.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _COMMON_DEF_H_
+#define _COMMON_DEF_H_
+
+#define SZ_1K 0x00000400
+#define SZ_2K 0x00000800
+#define SZ_4K 0x00001000
+#define SZ_8K 0x00002000
+#define SZ_16K 0x00004000
+#define SZ_32K 0x00008000
+#define SZ_64K 0x00010000
+#define SZ_128K 0x00020000
+#define SZ_256K 0x00040000
+#define SZ_512K 0x00080000
+
+#define SZ_1M 0x00100000
+#define SZ_2M 0x00200000
+#define SZ_4M 0x00400000
+#define SZ_8M 0x00800000
+#define SZ_16M 0x01000000
+#define SZ_32M 0x02000000
+#define SZ_64M 0x04000000
+#define SZ_128M 0x08000000
+#define SZ_256M 0x10000000
+#define SZ_512M 0x20000000
+
+#define SZ_1G 0x40000000
+#define SZ_2G 0x80000000
+
+#endif /* _COMMON_DEF_H_ */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index f3536bab..c8b785cc 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -8,6 +8,7 @@
#define __PLATFORM_H__
#include <stdint.h>
+#include <arch_helpers.h>
#include <timer.h>
#include <xlat_tables_v2.h>
@@ -184,4 +185,12 @@ int plat_get_image_source(unsigned int image_id,
void plat_fwu_io_setup(void);
+/**
+ * Returns current executing core.
+ */
+static inline uint32_t get_current_core_id(void)
+{
+ return platform_get_core_pos(read_mpidr_el1() & MPID_MASK);
+}
+
#endif /* __PLATFORM_H__ */
diff --git a/include/runtime_services/cactus_message_loop.h b/include/runtime_services/cactus_message_loop.h
index d69e77ce..4d963ac4 100644
--- a/include/runtime_services/cactus_message_loop.h
+++ b/include/runtime_services/cactus_message_loop.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,8 +12,8 @@
*/
struct cactus_cmd_handler {
const uint64_t id;
- smc_ret_values (*fn)(const smc_ret_values *args,
- struct mailbox_buffers *mb);
+ struct ffa_value (*fn)(const struct ffa_value *args,
+ struct mailbox_buffers *mb);
};
/**
@@ -25,8 +25,8 @@ struct cactus_cmd_handler {
* Define handler's function signature.
*/
#define CACTUS_HANDLER_FN(name) \
- static smc_ret_values CACTUS_HANDLER_FN_NAME(name)( \
- const smc_ret_values *args, struct mailbox_buffers *mb)
+ static struct ffa_value CACTUS_HANDLER_FN_NAME(name)( \
+ const struct ffa_value *args, struct mailbox_buffers *mb)
/**
* Helper to define Cactus command handler, and pair it with a command ID.
@@ -40,5 +40,5 @@ struct cactus_cmd_handler {
}; \
CACTUS_HANDLER_FN(name)
-bool cactus_handle_cmd(smc_ret_values *cmd_args, smc_ret_values *ret,
+bool cactus_handle_cmd(struct ffa_value *cmd_args, struct ffa_value *ret,
struct mailbox_buffers *mb);
diff --git a/include/runtime_services/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h
index 483a7f49..1e60e0e0 100644
--- a/include/runtime_services/cactus_test_cmds.h
+++ b/include/runtime_services/cactus_test_cmds.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,19 +25,19 @@
#define CACTUS_ERROR_UNHANDLED U(4)
/**
- * Get command from struct smc_ret_values.
+ * Get command from struct ffa_value.
*/
-static inline uint64_t cactus_get_cmd(smc_ret_values ret)
+static inline uint64_t cactus_get_cmd(struct ffa_value ret)
{
- return (uint64_t)ret.ret3;
+ return (uint64_t)ret.arg3;
}
/**
* Template for commands to be sent to CACTUS partitions over direct
* messages interfaces.
*/
-static inline smc_ret_values cactus_send_cmd(
- ffa_vm_id_t source, ffa_vm_id_t dest, uint64_t cmd, uint64_t val0,
+static inline struct ffa_value cactus_send_cmd(
+ ffa_id_t source, ffa_id_t dest, uint64_t cmd, uint64_t val0,
uint64_t val1, uint64_t val2, uint64_t val3)
{
return ffa_msg_send_direct_req64(source, dest, cmd, val0, val1, val2,
@@ -49,8 +49,8 @@ static inline smc_ret_values cactus_send_cmd(
* 'cactus_send_response' is the template for custom responses, in case there is
* a need to propagate more than one value in the response of a command.
*/
-static inline smc_ret_values cactus_send_response(
- ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t resp, uint32_t val0,
+static inline struct ffa_value cactus_send_response(
+ ffa_id_t source, ffa_id_t dest, uint32_t resp, uint64_t val0,
uint64_t val1, uint64_t val2, uint64_t val3)
{
return ffa_msg_send_direct_resp64(source, dest, resp, val0, val1,
@@ -60,15 +60,15 @@ static inline smc_ret_values cactus_send_response(
/**
* For responses of one value only.
*/
-static inline smc_ret_values cactus_response(
- ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t response)
+static inline struct ffa_value cactus_response(
+ ffa_id_t source, ffa_id_t dest, uint32_t response)
{
- return ffa_msg_send_direct_resp64(source, dest, response, 0, 0, 0, 0);
+ return cactus_send_response(source, dest, response, 0, 0, 0, 0);
}
-static inline uint32_t cactus_get_response(smc_ret_values ret)
+static inline uint32_t cactus_get_response(struct ffa_value ret)
{
- return (uint32_t)ret.ret3;
+ return (uint32_t)ret.arg3;
}
/**
@@ -77,8 +77,8 @@ static inline uint32_t cactus_get_response(smc_ret_values ret)
* If more arguments are needed, a custom response should be defined for the
* specific test.
*/
-static inline smc_ret_values cactus_success_resp(
- ffa_vm_id_t source, ffa_vm_id_t dest, uint64_t value)
+static inline struct ffa_value cactus_success_resp(
+ ffa_id_t source, ffa_id_t dest, uint64_t value)
{
return cactus_send_response(source, dest, CACTUS_SUCCESS, value,
0, 0, 0);
@@ -89,16 +89,16 @@ static inline smc_ret_values cactus_success_resp(
* the reason, which can be specific to the test, or general ones as defined
* in the error code list.
*/
-static inline smc_ret_values cactus_error_resp(
- ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t error_code)
+static inline struct ffa_value cactus_error_resp(
+ ffa_id_t source, ffa_id_t dest, uint32_t error_code)
{
return cactus_send_response(source, dest, CACTUS_ERROR, error_code,
0, 0, 0);
}
-static inline uint32_t cactus_error_code(smc_ret_values ret)
+static inline uint32_t cactus_error_code(struct ffa_value ret)
{
- return (uint32_t) ret.ret4;
+ return (uint32_t) ret.arg4;
}
/**
@@ -109,16 +109,16 @@ static inline uint32_t cactus_error_code(smc_ret_values ret)
*/
#define CACTUS_ECHO_CMD U(0x6563686f)
-static inline smc_ret_values cactus_echo_send_cmd(
- ffa_vm_id_t source, ffa_vm_id_t dest, uint64_t echo_val)
+static inline struct ffa_value cactus_echo_send_cmd(
+ ffa_id_t source, ffa_id_t dest, uint64_t echo_val)
{
return cactus_send_cmd(source, dest, CACTUS_ECHO_CMD, echo_val, 0, 0,
0);
}
-static inline uint64_t cactus_echo_get_val(smc_ret_values ret)
+static inline uint64_t cactus_echo_get_val(struct ffa_value ret)
{
- return (uint64_t)ret.ret4;
+ return (uint64_t)ret.arg4;
}
/**
@@ -130,17 +130,17 @@ static inline uint64_t cactus_echo_get_val(smc_ret_values ret)
*/
#define CACTUS_REQ_ECHO_CMD (CACTUS_ECHO_CMD + 1)
-static inline smc_ret_values cactus_req_echo_send_cmd(
- ffa_vm_id_t source, ffa_vm_id_t dest, ffa_vm_id_t echo_dest,
+static inline struct ffa_value cactus_req_echo_send_cmd(
+ ffa_id_t source, ffa_id_t dest, ffa_id_t echo_dest,
uint64_t echo_val)
{
return cactus_send_cmd(source, dest, CACTUS_REQ_ECHO_CMD, echo_val,
echo_dest, 0, 0);
}
-static inline ffa_vm_id_t cactus_req_echo_get_echo_dest(smc_ret_values ret)
+static inline ffa_id_t cactus_req_echo_get_echo_dest(struct ffa_value ret)
{
- return (ffa_vm_id_t)ret.ret5;
+ return (ffa_id_t)ret.arg5;
}
/**
@@ -154,16 +154,16 @@ static inline ffa_vm_id_t cactus_req_echo_get_echo_dest(smc_ret_values ret)
*/
#define CACTUS_DEADLOCK_CMD U(0x64656164)
-static inline smc_ret_values cactus_deadlock_send_cmd(
- ffa_vm_id_t source, ffa_vm_id_t dest, ffa_vm_id_t next_dest)
+static inline struct ffa_value cactus_deadlock_send_cmd(
+ ffa_id_t source, ffa_id_t dest, ffa_id_t next_dest)
{
return cactus_send_cmd(source, dest, CACTUS_DEADLOCK_CMD, next_dest, 0,
0, 0);
}
-static inline ffa_vm_id_t cactus_deadlock_get_next_dest(smc_ret_values ret)
+static inline ffa_id_t cactus_deadlock_get_next_dest(struct ffa_value ret)
{
- return (ffa_vm_id_t)ret.ret4;
+ return (ffa_id_t)ret.arg4;
}
/**
@@ -172,18 +172,18 @@ static inline ffa_vm_id_t cactus_deadlock_get_next_dest(smc_ret_values ret)
*/
#define CACTUS_REQ_DEADLOCK_CMD (CACTUS_DEADLOCK_CMD + 1)
-static inline smc_ret_values cactus_req_deadlock_send_cmd(
- ffa_vm_id_t source, ffa_vm_id_t dest, ffa_vm_id_t next_dest1,
- ffa_vm_id_t next_dest2)
+static inline struct ffa_value cactus_req_deadlock_send_cmd(
+ ffa_id_t source, ffa_id_t dest, ffa_id_t next_dest1,
+ ffa_id_t next_dest2)
{
return cactus_send_cmd(source, dest, CACTUS_REQ_DEADLOCK_CMD,
next_dest1, next_dest2, 0, 0);
}
/* To get next_dest1 use CACTUS_DEADLOCK_GET_NEXT_DEST */
-static inline ffa_vm_id_t cactus_deadlock_get_next_dest2(smc_ret_values ret)
+static inline ffa_id_t cactus_deadlock_get_next_dest2(struct ffa_value ret)
{
- return (ffa_vm_id_t)ret.ret5;
+ return (ffa_id_t)ret.arg5;
}
/**
@@ -194,17 +194,40 @@ static inline ffa_vm_id_t cactus_deadlock_get_next_dest2(smc_ret_values ret)
*/
#define CACTUS_MEM_SEND_CMD U(0x6d656d)
-static inline smc_ret_values cactus_mem_send_cmd(
- ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t mem_func,
- ffa_memory_handle_t handle)
+static inline struct ffa_value cactus_mem_send_cmd(
+ ffa_id_t source, ffa_id_t dest, uint32_t mem_func,
+ ffa_memory_handle_t handle, ffa_memory_region_flags_t retrieve_flags,
+ bool non_secure, uint16_t word_to_write)
{
+ /*
+ * `non_secure` and `word_to_write` are packed in the same register.
+ * Packed in a 32-bit value to support AArch32 platforms (eg Juno).
+ */
+ uint32_t val3 = ((uint32_t)non_secure << 16) | word_to_write;
return cactus_send_cmd(source, dest, CACTUS_MEM_SEND_CMD, mem_func,
- handle, 0, 0);
+ handle, retrieve_flags, val3);
}
-static inline ffa_memory_handle_t cactus_mem_send_get_handle(smc_ret_values ret)
+static inline ffa_memory_handle_t cactus_mem_send_get_handle(
+ struct ffa_value ret)
{
- return (ffa_memory_handle_t)ret.ret5;
+ return (ffa_memory_handle_t)ret.arg5;
+}
+
+static inline ffa_memory_region_flags_t cactus_mem_send_get_retrv_flags(
+ struct ffa_value ret)
+{
+ return (ffa_memory_region_flags_t)ret.arg6;
+}
+
+static inline uint16_t cactus_mem_send_words_to_write(struct ffa_value ret)
+{
+ return (uint16_t)ret.arg7;
+}
+
+static inline bool cactus_mem_send_get_non_secure(struct ffa_value ret)
+{
+ return (bool)(ret.arg7 >> 16);
}
/**
@@ -216,22 +239,27 @@ static inline ffa_memory_handle_t cactus_mem_send_get_handle(smc_ret_values ret)
*/
#define CACTUS_REQ_MEM_SEND_CMD U(0x6d656d6f7279)
-static inline smc_ret_values cactus_req_mem_send_send_cmd(
- ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t mem_func,
- ffa_vm_id_t receiver)
+static inline struct ffa_value cactus_req_mem_send_send_cmd(
+ ffa_id_t source, ffa_id_t dest, uint32_t mem_func,
+ ffa_id_t receiver, bool non_secure)
{
return cactus_send_cmd(source, dest, CACTUS_REQ_MEM_SEND_CMD, mem_func,
- receiver, 0, 0);
+ receiver, non_secure, 0);
+}
+
+static inline uint32_t cactus_req_mem_send_get_mem_func(struct ffa_value ret)
+{
+ return (uint32_t)ret.arg4;
}
-static inline uint32_t cactus_req_mem_send_get_mem_func(smc_ret_values ret)
+static inline ffa_id_t cactus_req_mem_send_get_receiver(struct ffa_value ret)
{
- return (uint32_t)ret.ret4;
+ return (ffa_id_t)ret.arg5;
}
-static inline ffa_vm_id_t cactus_req_mem_send_get_receiver(smc_ret_values ret)
+static inline bool cactus_req_mem_send_get_non_secure(struct ffa_value ret)
{
- return (ffa_vm_id_t)ret.ret5;
+ return (bool)ret.arg6;
}
/**
@@ -243,8 +271,8 @@ static inline ffa_vm_id_t cactus_req_mem_send_get_receiver(smc_ret_values ret)
*/
#define CACTUS_REQ_SIMD_FILL_CMD U(0x53494d44)
-static inline smc_ret_values cactus_req_simd_fill_send_cmd(
- ffa_vm_id_t source, ffa_vm_id_t dest)
+static inline struct ffa_value cactus_req_simd_fill_send_cmd(
+ ffa_id_t source, ffa_id_t dest)
{
return cactus_send_cmd(source, dest, CACTUS_REQ_SIMD_FILL_CMD, 0, 0, 0,
0);
@@ -257,16 +285,60 @@ static inline smc_ret_values cactus_req_simd_fill_send_cmd(
*/
#define CACTUS_SLEEP_CMD U(0x736c656570)
-static inline smc_ret_values cactus_sleep_cmd(
- ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t sleep_time)
+static inline struct ffa_value cactus_sleep_cmd(
+ ffa_id_t source, ffa_id_t dest, uint32_t sleep_time)
{
return cactus_send_cmd(source, dest, CACTUS_SLEEP_CMD, sleep_time, 0, 0,
0);
}
-static inline uint32_t cactus_get_sleep_time(smc_ret_values ret)
+/**
+ * Command to request cactus to forward sleep command for the given time in ms
+ *
+ * The sender of this command expects to receive CACTUS_SUCCESS if the requested
+ * echo interaction happened successfully, or CACTUS_ERROR otherwise.
+ */
+#define CACTUS_FWD_SLEEP_CMD (CACTUS_SLEEP_CMD + 1)
+
+static inline struct ffa_value cactus_fwd_sleep_cmd(
+ ffa_id_t source, ffa_id_t dest, ffa_id_t fwd_dest,
+ uint32_t sleep_time)
+{
+ return cactus_send_cmd(source, dest, CACTUS_FWD_SLEEP_CMD, sleep_time,
+ fwd_dest, 0, 0);
+}
+
+static inline uint32_t cactus_get_sleep_time(struct ffa_value ret)
+{
+ return (uint32_t)ret.arg4;
+}
+
+static inline ffa_id_t cactus_get_fwd_sleep_dest(struct ffa_value ret)
{
- return (uint32_t)ret.ret4;
+ return (ffa_id_t)ret.arg5;
+}
+
+/**
+ * Command to request cactus to sleep for half the given time in ms, trigger
+ * trusted watchdog timer and then sleep again for another half the given time.
+ *
+ * The sender of this command expects to receive CACTUS_SUCCESS if the requested
+ * echo interaction happened successfully, or CACTUS_ERROR otherwise.
+ */
+#define CACTUS_SLEEP_TRIGGER_TWDOG_CMD (CACTUS_SLEEP_CMD + 2)
+
+static inline struct ffa_value cactus_sleep_trigger_wdog_cmd(
+ ffa_id_t source, ffa_id_t dest, uint32_t sleep_time,
+ uint64_t wdog_time)
+{
+ return cactus_send_cmd(source, dest, CACTUS_SLEEP_TRIGGER_TWDOG_CMD, sleep_time,
+ wdog_time, 0, 0);
+}
+
+
+static inline uint32_t cactus_get_wdog_trigger_duration(struct ffa_value ret)
+{
+ return (uint32_t)ret.arg5;
}
/**
@@ -276,27 +348,27 @@ static inline uint32_t cactus_get_sleep_time(smc_ret_values ret)
*/
#define CACTUS_INTERRUPT_CMD U(0x696e7472)
-static inline smc_ret_values cactus_interrupt_cmd(
- ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t interrupt_id,
+static inline struct ffa_value cactus_interrupt_cmd(
+ ffa_id_t source, ffa_id_t dest, uint32_t interrupt_id,
bool enable, uint32_t pin)
{
return cactus_send_cmd(source, dest, CACTUS_INTERRUPT_CMD, interrupt_id,
enable, pin, 0);
}
-static inline uint32_t cactus_get_interrupt_id(smc_ret_values ret)
+static inline uint32_t cactus_get_interrupt_id(struct ffa_value ret)
{
- return (uint32_t)ret.ret4;
+ return (uint32_t)ret.arg4;
}
-static inline bool cactus_get_interrupt_enable(smc_ret_values ret)
+static inline bool cactus_get_interrupt_enable(struct ffa_value ret)
{
- return (bool)ret.ret5;
+ return (bool)ret.arg5;
}
-static inline enum interrupt_pin cactus_get_interrupt_pin(smc_ret_values ret)
+static inline enum interrupt_pin cactus_get_interrupt_pin(struct ffa_value ret)
{
- return (enum interrupt_pin)ret.ret6;
+ return (enum interrupt_pin)ret.arg6;
}
/**
@@ -306,10 +378,199 @@ static inline enum interrupt_pin cactus_get_interrupt_pin(smc_ret_values ret)
*/
#define CACTUS_DMA_SMMUv3_CMD (0x534d4d55)
-static inline smc_ret_values cactus_send_dma_cmd(
- ffa_vm_id_t source, ffa_vm_id_t dest)
+static inline struct ffa_value cactus_send_dma_cmd(
+ ffa_id_t source, ffa_id_t dest)
{
return cactus_send_cmd(source, dest, CACTUS_DMA_SMMUv3_CMD, 0, 0, 0,
0);
}
+
+/*
+ * Request SP to bind a notification to a FF-A endpoint. In case of error
+ * when using the FFA_NOTIFICATION_BIND interface, include the error code
+ * in the response to the command's request. The receiver and sender arguments
+ * are propagated through the command's arguments, to allow the test of
+ * erroneous uses of the FFA_NOTIFICATION_BIND interface.
+ *
+ * The command id is the hex representation of the string "bind".
+ */
+#define CACTUS_NOTIFICATION_BIND_CMD U(0x62696e64)
+
+static inline struct ffa_value cactus_notification_bind_send_cmd(
+ ffa_id_t source, ffa_id_t dest, ffa_id_t receiver,
+ ffa_id_t sender, ffa_notification_bitmap_t notifications, uint32_t flags)
+{
+ return cactus_send_cmd(source, dest, CACTUS_NOTIFICATION_BIND_CMD,
+ receiver, sender, notifications, flags);
+}
+
+/**
+ * Request to SP unbind a notification. In case of error when using the
+ * FFA_NOTIFICATION_UNBIND interface, the test includes the error code in the
+ * response. The receiver and sender arguments are propagated throught the
+ * command's arguments, to allow the test of erroneous uses of the
+ * FFA_NOTIFICATION_BIND interface.
+ *
+ * The command id is the hex representation of the string "unbind".
+ */
+#define CACTUS_NOTIFICATION_UNBIND_CMD U(0x756e62696e64)
+
+static inline struct ffa_value cactus_notification_unbind_send_cmd(
+ ffa_id_t source, ffa_id_t dest, ffa_id_t receiver,
+ ffa_id_t sender, ffa_notification_bitmap_t notifications)
+{
+ return cactus_send_cmd(source, dest, CACTUS_NOTIFICATION_UNBIND_CMD,
+ receiver, sender, notifications, 0);
+}
+
+static inline ffa_id_t cactus_notification_get_receiver(struct ffa_value ret)
+{
+ return (ffa_id_t)ret.arg4;
+}
+
+static inline ffa_id_t cactus_notification_get_sender(struct ffa_value ret)
+{
+ return (ffa_id_t)ret.arg5;
+}
+
+static inline ffa_notification_bitmap_t cactus_notification_get_notifications(
+ struct ffa_value ret)
+{
+ return (uint64_t)ret.arg6;
+}
+
+/**
+ * Request SP to get notifications. The arguments to use in ffa_notification_get
+ * are propagated on the command to test erroneous uses of the interface.
+ * In a successful call to the interface, the SP's response payload should
+ * include all bitmaps returned by the SPMC.
+ *
+ * The command id is the hex representation of the string "getnot".
+ */
+#define CACTUS_NOTIFICATION_GET_CMD U(0x6765746e6f74)
+
+static inline struct ffa_value cactus_notification_get_send_cmd(
+ ffa_id_t source, ffa_id_t dest, ffa_id_t receiver,
+ uint32_t vcpu_id, uint32_t flags, bool check_npi_handled)
+{
+ return cactus_send_cmd(source, dest, CACTUS_NOTIFICATION_GET_CMD,
+ receiver, vcpu_id, check_npi_handled, flags);
+}
+
+static inline uint32_t cactus_notification_get_vcpu(struct ffa_value ret)
+{
+ return (uint32_t)ret.arg5;
+}
+
+static inline uint32_t cactus_notification_get_flags(struct ffa_value ret)
+{
+ return (uint32_t)ret.arg7;
+}
+
+static inline struct ffa_value cactus_notifications_get_success_resp(
+ ffa_id_t source, ffa_id_t dest, uint64_t from_sp,
+ uint64_t from_vm)
+{
+ return cactus_send_response(source, dest, CACTUS_SUCCESS, from_sp,
+ from_vm, 0, 0);
+}
+
+static inline uint64_t cactus_notifications_get_from_sp(struct ffa_value ret)
+{
+ return (uint64_t)ret.arg4;
+}
+
+static inline uint64_t cactus_notifications_get_from_vm(struct ffa_value ret)
+{
+ return (uint64_t)ret.arg5;
+}
+
+static inline bool cactus_notifications_check_npi_handled(struct ffa_value ret)
+{
+ return (bool)ret.arg6;
+}
+
+/**
+ * Request SP to set notifications. The arguments to use in ffa_notification_set
+ * are propagated on the command to test erroneous uses of the interface.
+ * In case of error while calling the interface, the response should include the
+ * error code. If in the flags a delay SRI is requested, cactus should
+ * send a CACTUS_ECHO_CMD to the SP specified as `echo_dest`. This should help
+ * validate that the SRI is only sent when returning execution to the NWd.
+ */
+#define CACTUS_NOTIFICATIONS_SET_CMD U(0x6e6f74736574)
+
+static inline struct ffa_value cactus_notifications_set_send_cmd(
+ ffa_id_t source, ffa_id_t dest, ffa_id_t receiver,
+ ffa_id_t sender, uint32_t flags, ffa_notification_bitmap_t notifications,
+ ffa_id_t echo_dest)
+{
+ return cactus_send_cmd(source, dest, CACTUS_NOTIFICATIONS_SET_CMD,
+ (uint32_t)receiver | ((uint32_t)sender << 16),
+ echo_dest,
+ notifications, flags);
+}
+
+static inline ffa_id_t cactus_notifications_set_get_receiver(
+ struct ffa_value ret)
+{
+ return (ffa_id_t)(ret.arg4 & 0xFFFFU);
+}
+
+static inline ffa_id_t cactus_notifications_set_get_sender(struct ffa_value ret)
+{
+ return (ffa_id_t)((ret.arg4 >> 16U) & 0xFFFFU);
+}
+
+/**
+ * Request to start trusted watchdog timer.
+ *
+ * The command id is the hex representaton of the string "WDOG"
+ */
+#define CACTUS_TWDOG_START_CMD U(0x57444f47)
+
+static inline struct ffa_value cactus_send_twdog_cmd(
+ ffa_id_t source, ffa_id_t dest, uint64_t time)
+{
+ return cactus_send_cmd(source, dest, CACTUS_TWDOG_START_CMD, time, 0, 0,
+ 0);
+}
+
+static inline uint32_t cactus_get_wdog_duration(struct ffa_value ret)
+{
+ return (uint32_t)ret.arg4;
+}
+
+/**
+ * Request SP to return the current count of handled requests.
+ *
+ * The command id is the hex representation of the string "getnot".
+ */
+#define CACTUS_GET_REQ_COUNT_CMD U(0x726571636f756e74)
+
+static inline struct ffa_value cactus_get_req_count_send_cmd(
+ ffa_id_t source, ffa_id_t dest)
+{
+ return cactus_send_cmd(source, dest, CACTUS_GET_REQ_COUNT_CMD, 0, 0, 0,
+ 0);
+}
+
+static inline uint32_t cactus_get_req_count(struct ffa_value ret)
+{
+ return (uint32_t)ret.arg4;
+}
+
+/**
+ * Request SP to return the last serviced secure virtual interrupt.
+ *
+ * The command id is the hex representaton of the string "vINT"
+ */
+#define CACTUS_LAST_INTERRUPT_SERVICED_CMD U(0x76494e54)
+
+static inline struct ffa_value cactus_get_last_interrupt_cmd(
+ ffa_id_t source, ffa_id_t dest)
+{
+ return cactus_send_cmd(source, dest, CACTUS_LAST_INTERRUPT_SERVICED_CMD,
+ 0, 0, 0, 0);
+}
#endif
diff --git a/include/runtime_services/ffa_endpoints.h b/include/runtime_services/ffa_endpoints.h
index 7a6cd4f7..88055c49 100644
--- a/include/runtime_services/ffa_endpoints.h
+++ b/include/runtime_services/ffa_endpoints.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,10 +7,19 @@
#ifndef FFA_ENDPOINTS_H
#define FFA_ENDPOINTS_H
+#include <platform_def.h>
+
/* UUID of cactus SPs as defined in the respective manifests. */
-#define PRIMARY_UUID {0xb4b5671e, 0x4a904fe1, 0xb81ffb13, 0xdae1dacb}
-#define SECONDARY_UUID {0xd1582309, 0xf02347b9, 0x827c4464, 0xf5578fc8}
-#define TERTIARY_UUID {0x79b55c73, 0x1d8c44b9, 0x859361e1, 0x770ad8d2}
+#define PRIMARY_UUID {0x1e67b5b4, 0xe14f904a, 0x13fb1fb8, 0xcbdae1da}
+#define SECONDARY_UUID {0x092358d1, 0xb94723f0, 0x64447c82, 0xc88f57f5}
+#define TERTIARY_UUID {0x735cb579, 0xb9448c1d, 0xe1619385, 0xd2d80a77}
+#define IVY_UUID {0xd883baea, 0xaf4eafba, 0xfdf74481, 0xa744e5cb}
+
+/* vcpu_count of cactus SPs. */
+#define PRIMARY_EXEC_CTX_COUNT PLATFORM_CORE_COUNT
+#define SECONDARY_EXEC_CTX_COUNT PLATFORM_CORE_COUNT
+#define TERTIARY_EXEC_CTX_COUNT (1)
+#define IVY_EXEC_CTX_COUNT (1)
/* UUID of OPTEE SP as defined in the respective manifest. */
#define OPTEE_UUID {0x486178e0, 0xe7f811e3, 0xbc5e0002, 0xa5d5c51b}
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index 592327af..1635bf82 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -14,7 +14,7 @@
/* This error code must be different to the ones used by FFA */
#define FFA_TFTF_ERROR -42
-typedef unsigned short ffa_vm_id_t;
+typedef unsigned short ffa_id_t;
typedef unsigned short ffa_vm_count_t;
typedef unsigned short ffa_vcpu_count_t;
typedef uint64_t ffa_memory_handle_t;
@@ -25,25 +25,283 @@ struct ffa_uuid {
const uint32_t uuid[4];
};
+/** Length in bytes of the name in boot information descriptor. */
+#define FFA_BOOT_INFO_NAME_LEN 16
+
+/**
+ * The FF-A boot info descriptor, as defined in table 5.8 of section 5.4.1, of
+ * the FF-A v1.1 EAC0 specification.
+ */
+struct ffa_boot_info_desc {
+ char name[FFA_BOOT_INFO_NAME_LEN];
+ uint8_t type;
+ uint8_t reserved;
+ uint16_t flags;
+ uint32_t size;
+ uint64_t content;
+};
+
+/** FF-A boot information type mask. */
+#define FFA_BOOT_INFO_TYPE_SHIFT 7
+#define FFA_BOOT_INFO_TYPE_MASK (0x1U << FFA_BOOT_INFO_TYPE_SHIFT)
+#define FFA_BOOT_INFO_TYPE_STD 0U
+#define FFA_BOOT_INFO_TYPE_IMPDEF 1U
+
+/** Standard boot info type IDs. */
+#define FFA_BOOT_INFO_TYPE_ID_MASK 0x7FU
+#define FFA_BOOT_INFO_TYPE_ID_FDT 0U
+#define FFA_BOOT_INFO_TYPE_ID_HOB 1U
+
+/** FF-A Boot Info descriptors flags. */
+#define FFA_BOOT_INFO_FLAG_MBZ_MASK 0xFFF0U
+
+/** Bits [1:0] encode the format of the name field in ffa_boot_info_desc. */
+#define FFA_BOOT_INFO_FLAG_NAME_FORMAT_SHIFT 0U
+#define FFA_BOOT_INFO_FLAG_NAME_FORMAT_MASK \
+ (0x3U << FFA_BOOT_INFO_FLAG_NAME_FORMAT_SHIFT)
+#define FFA_BOOT_INFO_FLAG_NAME_FORMAT_STRING 0x0U
+#define FFA_BOOT_INFO_FLAG_NAME_FORMAT_UUID 0x1U
+
+/** Bits [3:2] encode the format of the content field in ffa_boot_info_desc. */
+#define FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_SHIFT 2
+#define FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_MASK \
+ (0x3U << FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_SHIFT)
+#define FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_VALUE 0x1U
+#define FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_ADDR 0x0U
+
+static inline uint16_t ffa_boot_info_content_format(
+ struct ffa_boot_info_desc *desc)
+{
+ return (desc->flags & FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_MASK) >>
+ FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_SHIFT;
+}
+
+static inline uint16_t ffa_boot_info_name_format(
+ struct ffa_boot_info_desc *desc)
+{
+ return (desc->flags & FFA_BOOT_INFO_FLAG_NAME_FORMAT_MASK) >>
+ FFA_BOOT_INFO_FLAG_NAME_FORMAT_SHIFT;
+}
+
+static inline uint8_t ffa_boot_info_type_id(struct ffa_boot_info_desc *desc)
+{
+ return desc->type & FFA_BOOT_INFO_TYPE_ID_MASK;
+}
+
+static inline uint8_t ffa_boot_info_type(struct ffa_boot_info_desc *desc)
+{
+ return (desc->type & FFA_BOOT_INFO_TYPE_MASK) >>
+ FFA_BOOT_INFO_TYPE_SHIFT;
+}
+
+/** Length in bytes of the signature in the boot descriptor. */
+#define FFA_BOOT_INFO_HEADER_SIGNATURE_LEN 4
+
+/**
+ * The FF-A boot information header, as defined in table 5.9 of section 5.4.2,
+ * of the FF-A v1.1 EAC0 specification.
+ */
+struct ffa_boot_info_header {
+ uint32_t signature;
+ uint32_t version;
+ uint32_t info_blob_size;
+ uint32_t desc_size;
+ uint32_t desc_count;
+ uint32_t desc_offset;
+ uint64_t reserved;
+ struct ffa_boot_info_desc boot_info[];
+};
+
#ifndef __ASSEMBLY__
+#include <cassert.h>
#include <stdint.h>
+/**
+ * FF-A Feature ID, to be used with interface FFA_FEATURES.
+ * As defined in the FF-A v1.1 Beta specification, table 13.10, in section
+ * 13.2.
+ */
+
+/** Query interrupt ID of Notification Pending Interrupt. */
+#define FFA_FEATURE_NPI 0x1U
+
+/** Query interrupt ID of Schedule Receiver Interrupt. */
+#define FFA_FEATURE_SRI 0x2U
+
+/** Query interrupt ID of the Managed Exit Interrupt. */
+#define FFA_FEATURE_MEI 0x3U
+
+/** Partition property: partition supports receipt of direct requests. */
+#define FFA_PARTITION_DIRECT_REQ_RECV 0x1
+
+/** Partition property: partition can send direct requests. */
+#define FFA_PARTITION_DIRECT_REQ_SEND 0x2
+
+/** Partition property: partition can send and receive indirect messages. */
+#define FFA_PARTITION_INDIRECT_MSG 0x4
+
+/** Partition property: partition can receive notifications. */
+#define FFA_PARTITION_NOTIFICATION 0x8
+
+/**
+ * Partition info descriptor as defined in Table 13.34 of the v1.1 BETA0
+ * FF-A Specification
+ */
struct ffa_partition_info {
/** The ID of the VM the information is about */
- ffa_vm_id_t id;
+ ffa_id_t id;
+ /** The number of execution contexts implemented by the partition */
+ uint16_t exec_context;
+ /** The Partition's properties, e.g. supported messaging methods */
+ uint32_t properties;
+ /** The uuid of the partition */
+ struct ffa_uuid uuid;
+};
+
+/**
+ * Partition info descriptor as defined in Table 8.25 of the v1.0
+ * FF-A Specification
+ */
+struct ffa_partition_info_v1_0 {
+ /** The ID of the VM the information is about */
+ ffa_id_t id;
/** The number of execution contexts implemented by the partition */
uint16_t exec_context;
/** The Partition's properties, e.g. supported messaging methods */
uint32_t properties;
};
-static inline uint32_t ffa_func_id(smc_ret_values val) {
- return (uint32_t) val.ret0;
+struct ffa_value {
+ u_register_t fid;
+ u_register_t arg1;
+ u_register_t arg2;
+ u_register_t arg3;
+ u_register_t arg4;
+ u_register_t arg5;
+ u_register_t arg6;
+ u_register_t arg7;
+};
+
+/* Function to make an SMC or SVC service call depending on the exception
+ * level of the SP.
+ */
+struct ffa_value ffa_service_call(struct ffa_value *args);
+
+/*
+ * Functions to trigger a service call.
+ *
+ * The arguments to pass through the service call must be stored in the
+ * ffa_value structure. The return values of the service call will be stored
+ * in the same structure (overriding the input arguments).
+ *
+ * Return the first return value. It is equivalent to args.fid but is also
+ * provided as the return value for convenience.
+ */
+u_register_t ffa_svc(struct ffa_value *args);
+u_register_t ffa_smc(struct ffa_value *args);
+
+static inline uint32_t ffa_func_id(struct ffa_value val)
+{
+ return (uint32_t)val.fid;
+}
+
+static inline int32_t ffa_error_code(struct ffa_value val)
+{
+ return (int32_t)val.arg2;
+}
+
+static inline ffa_id_t ffa_endpoint_id(struct ffa_value val) {
+ return (ffa_id_t)val.arg2 & 0xffff;
+}
+
+static inline uint32_t ffa_partition_info_count(struct ffa_value val)
+{
+ return (uint32_t)val.arg2;
+}
+
+static inline uint32_t ffa_partition_info_desc_size(struct ffa_value val)
+{
+ return (uint32_t)val.arg3;
+}
+
+static inline uint32_t ffa_feature_intid(struct ffa_value val)
+{
+ return (uint32_t)val.arg2;
+}
+
+typedef uint64_t ffa_notification_bitmap_t;
+
+#define FFA_NOTIFICATION(ID) (UINT64_C(1) << ID)
+
+#define MAX_FFA_NOTIFICATIONS UINT32_C(64)
+
+#define FFA_NOTIFICATIONS_FLAG_PER_VCPU UINT32_C(0x1 << 0)
+
+/** Flag to delay Schedule Receiver Interrupt. */
+#define FFA_NOTIFICATIONS_FLAG_DELAY_SRI UINT32_C(0x1 << 1)
+
+#define FFA_NOTIFICATIONS_FLAGS_VCPU_ID(id) UINT32_C((id & 0xFFFF) << 16)
+
+#define FFA_NOTIFICATIONS_FLAG_BITMAP_SP UINT32_C(0x1 << 0)
+#define FFA_NOTIFICATIONS_FLAG_BITMAP_VM UINT32_C(0x1 << 1)
+#define FFA_NOTIFICATIONS_FLAG_BITMAP_SPM UINT32_C(0x1 << 2)
+#define FFA_NOTIFICATIONS_FLAG_BITMAP_HYP UINT32_C(0x1 << 3)
+
+/**
+ * The following is an SGI ID, that the SPMC configures as non-secure, as
+ * suggested by the FF-A v1.1 specification, in section 9.4.1.
+ */
+#define FFA_SCHEDULE_RECEIVER_INTERRUPT_ID 8
+
+#define FFA_NOTIFICATIONS_BITMAP(lo, hi) \
+ (ffa_notification_bitmap_t)(lo) | \
+ (((ffa_notification_bitmap_t)hi << 32) & 0xFFFFFFFF00000000ULL)
+
+#define FFA_NOTIFICATIONS_FLAGS_VCPU_ID(id) UINT32_C((id & 0xFFFF) << 16)
+
+static inline ffa_notification_bitmap_t ffa_notifications_get_from_sp(
+ struct ffa_value val)
+{
+ return FFA_NOTIFICATIONS_BITMAP(val.arg2, val.arg3);
+}
+
+static inline ffa_notification_bitmap_t ffa_notifications_get_from_vm(
+ struct ffa_value val)
+{
+ return FFA_NOTIFICATIONS_BITMAP(val.arg4, val.arg5);
}
-static inline int32_t ffa_error_code(smc_ret_values val) {
- return (int32_t) val.ret2;
+/*
+ * FFA_NOTIFICATION_INFO_GET is a SMC64 interface.
+ * The following macros are defined for SMC64 implementation.
+ */
+#define FFA_NOTIFICATIONS_INFO_GET_MAX_IDS 20U
+
+#define FFA_NOTIFICATIONS_INFO_GET_FLAG_MORE_PENDING UINT64_C(0x1)
+
+#define FFA_NOTIFICATIONS_LISTS_COUNT_SHIFT 0x7U
+#define FFA_NOTIFICATIONS_LISTS_COUNT_MASK 0x1FU
+#define FFA_NOTIFICATIONS_LIST_SHIFT(l) (2 * (l - 1) + 12)
+#define FFA_NOTIFICATIONS_LIST_SIZE_MASK 0x3U
+
+static inline uint32_t ffa_notifications_info_get_lists_count(
+ struct ffa_value ret)
+{
+ return (uint32_t)(ret.arg2 >> FFA_NOTIFICATIONS_LISTS_COUNT_SHIFT)
+ & FFA_NOTIFICATIONS_LISTS_COUNT_MASK;
+}
+
+static inline uint32_t ffa_notifications_info_get_list_size(
+ struct ffa_value ret, uint32_t list)
+{
+ return (uint32_t)(ret.arg2 >> FFA_NOTIFICATIONS_LIST_SHIFT(list)) &
+ FFA_NOTIFICATIONS_LIST_SIZE_MASK;
+}
+
+static inline bool ffa_notifications_info_get_more_pending(struct ffa_value ret)
+{
+ return (ret.arg2 & FFA_NOTIFICATIONS_INFO_GET_FLAG_MORE_PENDING) != 0U;
}
enum ffa_data_access {
@@ -196,7 +454,7 @@ struct ffa_composite_memory_region {
*/
struct ffa_memory_region_attributes {
/** The ID of the VM to which the memory is being given or shared. */
- ffa_vm_id_t receiver;
+ ffa_id_t receiver;
/**
* The permissions with which the memory region should be mapped in the
* receiver's page table.
@@ -264,7 +522,7 @@ struct ffa_memory_region {
* The ID of the VM which originally sent the memory region, i.e. the
* owner.
*/
- ffa_vm_id_t sender;
+ ffa_id_t sender;
ffa_memory_attributes_t attributes;
/** Reserved field, must be 0. */
uint8_t reserved_0;
@@ -300,17 +558,18 @@ struct ffa_mem_relinquish {
ffa_memory_handle_t handle;
ffa_memory_region_flags_t flags;
uint32_t endpoint_count;
- ffa_vm_id_t endpoints[];
+ ffa_id_t endpoints[];
};
static inline ffa_memory_handle_t ffa_assemble_handle(uint32_t h1, uint32_t h2)
{
- return (uint64_t)h1 | (uint64_t)h2 << 32;
+ return (ffa_notification_bitmap_t)h1 |
+ (ffa_notification_bitmap_t)h2 << 32;
}
-static inline ffa_memory_handle_t ffa_mem_success_handle(smc_ret_values r)
+static inline ffa_memory_handle_t ffa_mem_success_handle(struct ffa_value r)
{
- return ffa_assemble_handle(r.ret2, r.ret3);
+ return ffa_assemble_handle(r.arg2, r.arg3);
}
/**
@@ -335,18 +594,18 @@ ffa_memory_region_get_composite(struct ffa_memory_region *memory_region,
static inline uint32_t ffa_mem_relinquish_init(
struct ffa_mem_relinquish *relinquish_request,
ffa_memory_handle_t handle, ffa_memory_region_flags_t flags,
- ffa_vm_id_t sender)
+ ffa_id_t sender)
{
relinquish_request->handle = handle;
relinquish_request->flags = flags;
relinquish_request->endpoint_count = 1;
relinquish_request->endpoints[0] = sender;
- return sizeof(struct ffa_mem_relinquish) + sizeof(ffa_vm_id_t);
+ return sizeof(struct ffa_mem_relinquish) + sizeof(ffa_id_t);
}
uint32_t ffa_memory_retrieve_request_init(
struct ffa_memory_region *memory_region, ffa_memory_handle_t handle,
- ffa_vm_id_t sender, ffa_vm_id_t receiver, uint32_t tag,
+ ffa_id_t sender, ffa_id_t receiver, uint32_t tag,
ffa_memory_region_flags_t flags, enum ffa_data_access data_access,
enum ffa_instruction_access instruction_access,
enum ffa_memory_type type, enum ffa_memory_cacheability cacheability,
@@ -354,7 +613,7 @@ uint32_t ffa_memory_retrieve_request_init(
uint32_t ffa_memory_region_init(
struct ffa_memory_region *memory_region, size_t memory_region_max_size,
- ffa_vm_id_t sender, ffa_vm_id_t receiver,
+ ffa_id_t sender, ffa_id_t receiver,
const struct ffa_memory_region_constituent constituents[],
uint32_t constituent_count, uint32_t tag,
ffa_memory_region_flags_t flags, enum ffa_data_access data_access,
@@ -363,53 +622,71 @@ uint32_t ffa_memory_region_init(
enum ffa_memory_shareability shareability, uint32_t *total_length,
uint32_t *fragment_length);
-static inline ffa_vm_id_t ffa_dir_msg_dest(smc_ret_values val) {
- return (ffa_vm_id_t)val.ret1 & U(0xFFFF);
+static inline ffa_id_t ffa_dir_msg_dest(struct ffa_value val) {
+ return (ffa_id_t)val.arg1 & U(0xFFFF);
}
-static inline ffa_vm_id_t ffa_dir_msg_source(smc_ret_values val) {
- return (ffa_vm_id_t)(val.ret1 >> 16U);
+static inline ffa_id_t ffa_dir_msg_source(struct ffa_value val) {
+ return (ffa_id_t)(val.arg1 >> 16U);
}
-smc_ret_values ffa_msg_send_direct_req64(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint64_t arg0,
- uint64_t arg1, uint64_t arg2,
- uint64_t arg3, uint64_t arg4);
-
-smc_ret_values ffa_msg_send_direct_req32(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint32_t arg0,
- uint32_t arg1, uint32_t arg2,
- uint32_t arg3, uint32_t arg4);
-
-smc_ret_values ffa_msg_send_direct_resp64(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint64_t arg0,
- uint64_t arg1, uint64_t arg2,
- uint64_t arg3, uint64_t arg4);
-
-smc_ret_values ffa_msg_send_direct_resp32(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint32_t arg0,
- uint32_t arg1, uint32_t arg2,
- uint32_t arg3, uint32_t arg4);
-
-smc_ret_values ffa_run(uint32_t dest_id, uint32_t vcpu_id);
-smc_ret_values ffa_version(uint32_t input_version);
-smc_ret_values ffa_id_get(void);
-smc_ret_values ffa_msg_wait(void);
-smc_ret_values ffa_error(int32_t error_code);
-smc_ret_values ffa_features(uint32_t feature);
-smc_ret_values ffa_partition_info_get(const uint32_t uuid[4]);
-smc_ret_values ffa_rx_release(void);
-smc_ret_values ffa_rxtx_map(uintptr_t send, uintptr_t recv, uint32_t pages);
-smc_ret_values ffa_mem_donate(uint32_t descriptor_length,
+struct ffa_value ffa_msg_send_direct_req64(ffa_id_t source_id,
+ ffa_id_t dest_id, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4);
+
+struct ffa_value ffa_msg_send_direct_req32(ffa_id_t source_id,
+ ffa_id_t dest_id, uint32_t arg0,
+ uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t arg4);
+
+struct ffa_value ffa_msg_send_direct_resp64(ffa_id_t source_id,
+ ffa_id_t dest_id, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4);
+
+struct ffa_value ffa_msg_send_direct_resp32(ffa_id_t source_id,
+ ffa_id_t dest_id, uint32_t arg0,
+ uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t arg4);
+
+struct ffa_value ffa_run(uint32_t dest_id, uint32_t vcpu_id);
+struct ffa_value ffa_version(uint32_t input_version);
+struct ffa_value ffa_id_get(void);
+struct ffa_value ffa_spm_id_get(void);
+struct ffa_value ffa_msg_wait(void);
+struct ffa_value ffa_error(int32_t error_code);
+struct ffa_value ffa_features(uint32_t feature);
+struct ffa_value ffa_partition_info_get(const struct ffa_uuid uuid);
+struct ffa_value ffa_rx_release(void);
+struct ffa_value ffa_rxtx_map(uintptr_t send, uintptr_t recv, uint32_t pages);
+struct ffa_value ffa_rxtx_unmap(void);
+struct ffa_value ffa_mem_donate(uint32_t descriptor_length,
+ uint32_t fragment_length);
+struct ffa_value ffa_mem_lend(uint32_t descriptor_length,
uint32_t fragment_length);
-smc_ret_values ffa_mem_lend(uint32_t descriptor_length,
- uint32_t fragment_length);
-smc_ret_values ffa_mem_share(uint32_t descriptor_length,
- uint32_t fragment_length);
-smc_ret_values ffa_mem_retrieve_req(uint32_t descriptor_length,
- uint32_t fragment_length);
-smc_ret_values ffa_mem_relinquish(void);
-smc_ret_values ffa_mem_reclaim(uint64_t handle, uint32_t flags);
+struct ffa_value ffa_mem_share(uint32_t descriptor_length,
+ uint32_t fragment_length);
+struct ffa_value ffa_mem_retrieve_req(uint32_t descriptor_length,
+ uint32_t fragment_length);
+struct ffa_value ffa_mem_relinquish(void);
+struct ffa_value ffa_mem_reclaim(uint64_t handle, uint32_t flags);
+struct ffa_value ffa_notification_bitmap_create(ffa_id_t vm_id,
+ ffa_vcpu_count_t vcpu_count);
+struct ffa_value ffa_notification_bitmap_destroy(ffa_id_t vm_id);
+struct ffa_value ffa_notification_bind(ffa_id_t sender, ffa_id_t receiver,
+ uint32_t flags,
+ ffa_notification_bitmap_t notifications);
+struct ffa_value ffa_notification_unbind(ffa_id_t sender, ffa_id_t receiver,
+ ffa_notification_bitmap_t notifications);
+struct ffa_value ffa_notification_set(ffa_id_t sender, ffa_id_t receiver,
+ uint32_t flags,
+ ffa_notification_bitmap_t bitmap);
+struct ffa_value ffa_notification_get(ffa_id_t receiver, uint32_t vcpu_id,
+ uint32_t flags);
+struct ffa_value ffa_notification_info_get(void);
+
+struct ffa_value ffa_console_log(const char* message, size_t char_count);
#endif /* __ASSEMBLY__ */
diff --git a/include/runtime_services/ffa_svc.h b/include/runtime_services/ffa_svc.h
index c9702658..21b03336 100644
--- a/include/runtime_services/ffa_svc.h
+++ b/include/runtime_services/ffa_svc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,17 +12,19 @@
#include <uuid.h>
/* FFA error codes. */
-#define FFA_ERROR_NOT_SUPPORTED -1
+#define FFA_ERROR_NOT_SUPPORTED -1
#define FFA_ERROR_INVALID_PARAMETER -2
#define FFA_ERROR_NO_MEMORY -3
#define FFA_ERROR_BUSY -4
#define FFA_ERROR_INTERRUPTED -5
#define FFA_ERROR_DENIED -6
-#define FFA_ERROR_RETRY -7
+#define FFA_ERROR_RETRY -7
+#define FFA_ERROR_ABORTED -8
+#define FFA_ERROR_NO_DATA -9
/* The macros below are used to identify FFA calls from the SMC function ID */
#define FFA_FNUM_MIN_VALUE U(0x60)
-#define FFA_FNUM_MAX_VALUE U(0x84)
+#define FFA_FNUM_MAX_VALUE U(0x87)
#define is_ffa_fid(fid) __extension__ ({ \
__typeof__(fid) _fid = (fid); \
((GET_SMC_NUM(_fid) >= FFA_FNUM_MIN_VALUE) && \
@@ -32,7 +34,7 @@
#define FFA_VERSION_MAJOR U(1)
#define FFA_VERSION_MAJOR_SHIFT 16
#define FFA_VERSION_MAJOR_MASK U(0x7FFF)
-#define FFA_VERSION_MINOR U(0)
+#define FFA_VERSION_MINOR U(1)
#define FFA_VERSION_MINOR_SHIFT 0
#define FFA_VERSION_MINOR_MASK U(0xFFFF)
#define FFA_VERSION_BIT31_MASK U(1 << 31)
@@ -60,31 +62,47 @@
((func_num) << FUNCID_NUM_SHIFT))
/* FFA function numbers */
-#define FFA_FNUM_ERROR U(0x60)
-#define FFA_FNUM_SUCCESS U(0x61)
-#define FFA_FNUM_INTERRUPT U(0x62)
-#define FFA_FNUM_VERSION U(0x63)
-#define FFA_FNUM_FEATURES U(0x64)
-#define FFA_FNUM_RX_RELEASE U(0x65)
-#define FFA_FNUM_RXTX_MAP U(0x66)
-#define FFA_FNUM_RXTX_UNMAP U(0x67)
-#define FFA_FNUM_PARTITION_INFO_GET U(0x68)
-#define FFA_FNUM_ID_GET U(0x69)
-#define FFA_FNUM_MSG_POLL U(0x6A)
-#define FFA_FNUM_MSG_WAIT U(0x6B)
-#define FFA_FNUM_MSG_YIELD U(0x6C)
-#define FFA_FNUM_MSG_RUN U(0x6D)
-#define FFA_FNUM_MSG_SEND U(0x6E)
-#define FFA_FNUM_MSG_SEND_DIRECT_REQ U(0x6F)
-#define FFA_FNUM_MSG_SEND_DIRECT_RESP U(0x70)
-#define FFA_FNUM_MEM_DONATE U(0x71)
-#define FFA_FNUM_MEM_LEND U(0x72)
-#define FFA_FNUM_MEM_SHARE U(0x73)
-#define FFA_FNUM_MEM_RETRIEVE_REQ U(0x74)
-#define FFA_FNUM_MEM_RETRIEVE_RESP U(0x75)
-#define FFA_FNUM_MEM_RELINQUISH U(0x76)
-#define FFA_FNUM_MEM_RECLAIM U(0x77)
-#define FFA_FNUM_SECONDARY_EP_REGISTER U(0x84)
+#define FFA_FNUM_ERROR U(0x60)
+#define FFA_FNUM_SUCCESS U(0x61)
+#define FFA_FNUM_INTERRUPT U(0x62)
+#define FFA_FNUM_VERSION U(0x63)
+#define FFA_FNUM_FEATURES U(0x64)
+#define FFA_FNUM_RX_RELEASE U(0x65)
+#define FFA_FNUM_RXTX_MAP U(0x66)
+#define FFA_FNUM_RXTX_UNMAP U(0x67)
+#define FFA_FNUM_PARTITION_INFO_GET U(0x68)
+#define FFA_FNUM_ID_GET U(0x69)
+#define FFA_FNUM_MSG_POLL U(0x6A) /* Legacy FF-A v1.0 */
+#define FFA_FNUM_MSG_WAIT U(0x6B)
+#define FFA_FNUM_MSG_YIELD U(0x6C)
+#define FFA_FNUM_RUN U(0x6D)
+#define FFA_FNUM_MSG_SEND U(0x6E) /* Legacy FF-A v1.0 */
+#define FFA_FNUM_MSG_SEND_DIRECT_REQ U(0x6F)
+#define FFA_FNUM_MSG_SEND_DIRECT_RESP U(0x70)
+#define FFA_FNUM_MEM_DONATE U(0x71)
+#define FFA_FNUM_MEM_LEND U(0x72)
+#define FFA_FNUM_MEM_SHARE U(0x73)
+#define FFA_FNUM_MEM_RETRIEVE_REQ U(0x74)
+#define FFA_FNUM_MEM_RETRIEVE_RESP U(0x75)
+#define FFA_FNUM_MEM_RELINQUISH U(0x76)
+#define FFA_FNUM_MEM_RECLAIM U(0x77)
+#define FFA_FNUM_NORMAL_WORLD_RESUME U(0x7C)
+
+/* FF-A v1.1 */
+#define FFA_FNUM_NOTIFICATION_BITMAP_CREATE U(0x7D)
+#define FFA_FNUM_NOTIFICATION_BITMAP_DESTROY U(0x7E)
+#define FFA_FNUM_NOTIFICATION_BIND U(0x7F)
+#define FFA_FNUM_NOTIFICATION_UNBIND U(0x80)
+#define FFA_FNUM_NOTIFICATION_SET U(0x81)
+#define FFA_FNUM_NOTIFICATION_GET U(0x82)
+#define FFA_FNUM_NOTIFICATION_INFO_GET U(0x83)
+#define FFA_FNUM_RX_ACQUIRE U(0x84)
+#define FFA_FNUM_SPM_ID_GET U(0x85)
+#define FFA_FNUM_MSG_SEND2 U(0x86)
+#define FFA_FNUM_SECONDARY_EP_REGISTER U(0x87)
+
+/* Implementation defined function numbers */
+#define FFA_FNUM_CONSOLE_LOG U(0x8A)
/* FFA SMC32 FIDs */
#define FFA_ERROR FFA_FID(SMC_32, FFA_FNUM_ERROR)
@@ -100,7 +118,7 @@
#define FFA_MSG_POLL FFA_FID(SMC_32, FFA_FNUM_MSG_POLL)
#define FFA_MSG_WAIT FFA_FID(SMC_32, FFA_FNUM_MSG_WAIT)
#define FFA_MSG_YIELD FFA_FID(SMC_32, FFA_FNUM_MSG_YIELD)
-#define FFA_MSG_RUN FFA_FID(SMC_32, FFA_FNUM_MSG_RUN)
+#define FFA_RUN FFA_FID(SMC_32, FFA_FNUM_RUN)
#define FFA_MSG_SEND FFA_FID(SMC_32, FFA_FNUM_MSG_SEND)
#define FFA_MSG_SEND_DIRECT_REQ_SMC32 \
FFA_FID(SMC_32, FFA_FNUM_MSG_SEND_DIRECT_REQ)
@@ -113,7 +131,21 @@
FFA_FID(SMC_32, FFA_FNUM_MEM_RETRIEVE_REQ)
#define FFA_MEM_RETRIEVE_RESP FFA_FID(SMC_32, FFA_FNUM_MEM_RETRIEVE_RESP)
#define FFA_MEM_RELINQUISH FFA_FID(SMC_32, FFA_FNUM_MEM_RELINQUISH)
-#define FFA_MEM_RECLAIM FFA_FID(SMC_32, FFA_FNUM_MEM_RECLAIM)
+#define FFA_MEM_RECLAIM FFA_FID(SMC_32, FFA_FNUM_MEM_RECLAIM)
+#define FFA_NOTIFICATION_BITMAP_CREATE \
+ FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_BITMAP_CREATE)
+#define FFA_NOTIFICATION_BITMAP_DESTROY \
+ FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_BITMAP_DESTROY)
+#define FFA_NOTIFICATION_BIND FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_BIND)
+#define FFA_NOTIFICATION_UNBIND FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_UNBIND)
+#define FFA_NOTIFICATION_SET FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_SET)
+#define FFA_NOTIFICATION_GET FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_GET)
+#define FFA_NOTIFICATION_INFO_GET \
+ FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_INFO_GET)
+#define FFA_SPM_ID_GET FFA_FID(SMC_32, FFA_FNUM_SPM_ID_GET)
+
+/* Implementation defined SMC32 FIDs */
+#define FFA_CONSOLE_LOG_SMC32 FFA_FID(SMC_32, FFA_FNUM_CONSOLE_LOG)
/* FFA SMC64 FIDs */
#define FFA_SUCCESS_SMC64 FFA_FID(SMC_64, FFA_FNUM_SUCCESS)
@@ -129,7 +161,11 @@
FFA_FID(SMC_64, FFA_FNUM_MEM_RETRIEVE_REQ)
#define FFA_SECONDARY_EP_REGISTER_SMC64 \
FFA_FID(SMC_64, FFA_FNUM_SECONDARY_EP_REGISTER)
+#define FFA_NOTIFICATION_INFO_GET_SMC64 \
+ FFA_FID(SMC_64, FFA_FNUM_NOTIFICATION_INFO_GET)
+/* Implementation defined SMC64 FIDs */
+#define FFA_CONSOLE_LOG_SMC64 FFA_FID(SMC_64, FFA_FNUM_CONSOLE_LOG)
/*
* Reserve a special value for traffic targeted to the Hypervisor or SPM.
*/
diff --git a/include/runtime_services/realm_payload/realm_payload_test.h b/include/runtime_services/realm_payload/realm_payload_test.h
new file mode 100644
index 00000000..048dda17
--- /dev/null
+++ b/include/runtime_services/realm_payload/realm_payload_test.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <smccc.h>
+#include <tftf_lib.h>
+
+#define RMI_FNUM_MIN_VALUE U(0x150)
+#define RMI_FNUM_MAX_VALUE U(0x18F)
+
+/* Get RMI fastcall std FID from offset */
+#define SMC64_RMI_FID(_offset) \
+ ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) | \
+ (SMC_64 << FUNCID_CC_SHIFT) | \
+ (OEN_STD_START << FUNCID_OEN_SHIFT) | \
+ (((RMI_FNUM_MIN_VALUE + (_offset)) & FUNCID_NUM_MASK) \
+ << FUNCID_NUM_SHIFT))
+
+/* RMI SMC64 FIDs handled by the RMMD */
+#define RMI_RMM_REQ_VERSION SMC64_RMI_FID(U(0))
+#define SMC_RMM_GRANULE_DELEGATE SMC64_RMI_FID(U(1))
+#define SMC_RMM_GRANULE_UNDELEGATE SMC64_RMI_FID(U(2))
+#define SMC_RMM_REALM_CREATE SMC64_RMI_FID(U(8))
+#define SMC_RMM_REALM_DESTROY SMC64_RMI_FID(U(9))
+
+#define RMI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16)
+#define RMI_ABI_VERSION_GET_MINOR(_version) ((_version) & 0xFFFF)
+
+#define NUM_GRANULES 5
+#define NUM_RANDOM_ITERATIONS 7
+#define GRANULE_SIZE 4096
+
+#define B_DELEGATED 0
+#define B_UNDELEGATED 1
+
+#define NUM_CPU_DED_SPM PLATFORM_CORE_COUNT / 2
+/*
+ * The error code 513 is the packed version of the
+ * rmm error {RMM_STATUS_ERROR_INPUT,2}
+ * happened when Granule(params_ptr).pas != NS
+ */
+#define RMM_STATUS_ERROR_INPUT 513UL
+u_register_t realm_version(void);
+u_register_t realm_granule_delegate(uintptr_t);
+u_register_t realm_granule_undelegate(uintptr_t);
+u_register_t realm_create(uintptr_t, uintptr_t);
+u_register_t realm_destroy(uintptr_t); \ No newline at end of file
diff --git a/include/runtime_services/secure_el1_payloads/tsp.h b/include/runtime_services/secure_el1_payloads/tsp.h
index 87ee6f74..19db911a 100644
--- a/include/runtime_services/secure_el1_payloads/tsp.h
+++ b/include/runtime_services/secure_el1_payloads/tsp.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -32,6 +32,7 @@ static const uuid_t tsp_uuid = {
#define TSP_MUL 0x2002
#define TSP_DIV 0x2003
#define TSP_HANDLE_SEL1_INTR_AND_RETURN 0x2004
+#define TSP_CHECK_DIT 0x2005
/*
* Identify a TSP service from function ID filtering the last 16 bits from the
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index 50159ecb..7a81e9cb 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,12 +7,19 @@
#ifndef SPM_COMMON_H
#define SPM_COMMON_H
-#include <ffa_helpers.h>
+#include <plat/common/platform.h>
+
#include <stdint.h>
#include <string.h>
+#include <ffa_helpers.h>
+
+#include <lib/extensions/sve.h>
+
/* Hypervisor ID at physical FFA instance */
#define HYP_ID (0)
+/* SPMC ID */
+#define SPMC_ID U(0x8000)
/* ID for the first Secure Partition. */
#define SPM_VM_ID_FIRST SP_ID(1)
@@ -20,6 +27,9 @@
/* INTID for the managed exit virtual interrupt. */
#define MANAGED_EXIT_INTERRUPT_ID U(4)
+/* INTID for the notification pending interrupt. */
+#define NOTIFICATION_PENDING_INTERRUPT_INTID 5
+
/** IRQ/FIQ pin used for signaling a virtual interrupt. */
enum interrupt_pin {
INTERRUPT_TYPE_IRQ,
@@ -36,12 +46,16 @@ enum interrupt_pin {
*/
#define SP_ID_MASK U(1 << 15)
#define SP_ID(x) ((x) | SP_ID_MASK)
+#define VM_ID(x) (x & ~SP_ID_MASK)
#define IS_SP_ID(x) ((x & SP_ID_MASK) != 0U)
+#define NULL_UUID (const struct ffa_uuid) { .uuid = {0} }
+
struct ffa_features_test {
const char *test_name;
unsigned int feature;
unsigned int expected_ret;
+ unsigned int version_added;
};
struct mailbox_buffers {
@@ -73,29 +87,37 @@ struct mailbox_buffers {
/**
* Helpers to evaluate returns of FF-A calls.
*/
-bool is_ffa_call_error(smc_ret_values val);
-bool is_ffa_direct_response(smc_ret_values ret);
-bool is_expected_ffa_return(smc_ret_values ret, uint32_t func_id);
+bool is_ffa_call_error(struct ffa_value val);
+bool is_expected_ffa_error(struct ffa_value ret, int32_t error_code);
+bool is_ffa_direct_response(struct ffa_value ret);
+bool is_expected_ffa_return(struct ffa_value ret, uint32_t func_id);
+bool is_expected_cactus_response(struct ffa_value ret, uint32_t expected_resp,
+ uint32_t arg);
+void dump_ffa_value(struct ffa_value ret);
/*
- * Vector length:
+ * Max. vector length:
* SIMD: 128 bits = 16 bytes
*/
#define SIMD_VECTOR_LEN_BYTES 16
+
#define SIMD_NUM_VECTORS 32
+
typedef uint8_t simd_vector_t[SIMD_VECTOR_LEN_BYTES];
/*
- * Fills SIMD registers with the content of the container v.
- * Number of vectors is assumed to be SIMD_NUM_VECTORS.
+ * Fills SIMD/SVE registers with the content of the container v.
+ * Number of vectors is assumed to be SIMD/SVE_NUM_VECTORS.
*/
void fill_simd_vector_regs(const simd_vector_t v[SIMD_NUM_VECTORS]);
+void fill_sve_vector_regs(const sve_vector_t v[SVE_NUM_VECTORS]);
/*
- * Reads contents of SIMD registers into the provided container v.
- * Number of vectors is assumed to be SIMD_NUM_VECTORS.
+ * Reads contents of SIMD/SVE registers into the provided container v.
+ * Number of vectors is assumed to be SIMD/SVE_NUM_VECTORS.
*/
void read_simd_vector_regs(simd_vector_t v[SIMD_NUM_VECTORS]);
+void read_sve_vector_regs(sve_vector_t v[SVE_NUM_VECTORS]);
bool check_spmc_execution_level(void);
@@ -107,24 +129,29 @@ unsigned int get_ffa_feature_test_target(const struct ffa_features_test **test_t
*/
bool memory_retrieve(struct mailbox_buffers *mb,
struct ffa_memory_region **retrieved, uint64_t handle,
- ffa_vm_id_t sender, ffa_vm_id_t receiver,
- uint32_t mem_func);
+ ffa_id_t sender, ffa_id_t receiver,
+ ffa_memory_region_flags_t flags);
/**
* Helper to conduct a memory relinquish. The caller is usually the receiver,
* after it being done with the memory shared, identified by the 'handle'.
*/
bool memory_relinquish(struct ffa_mem_relinquish *m, uint64_t handle,
- ffa_vm_id_t id);
+ ffa_id_t id);
ffa_memory_handle_t memory_send(
struct ffa_memory_region *memory_region, uint32_t mem_func,
- uint32_t fragment_length, uint32_t total_length);
+ uint32_t fragment_length, uint32_t total_length, struct ffa_value *ret);
ffa_memory_handle_t memory_init_and_send(
struct ffa_memory_region *memory_region, size_t memory_region_max_size,
- ffa_vm_id_t sender, ffa_vm_id_t receiver,
+ ffa_id_t sender, ffa_id_t receiver,
const struct ffa_memory_region_constituent* constituents,
- uint32_t constituents_count, uint32_t mem_func);
+ uint32_t constituents_count, uint32_t mem_func, struct ffa_value *ret);
+
+bool ffa_partition_info_helper(struct mailbox_buffers *mb,
+ const struct ffa_uuid uuid,
+ const struct ffa_partition_info *expected,
+ const uint16_t expected_size);
#endif /* SPM_COMMON_H */
diff --git a/lib/aarch64/exception_stubs.S b/lib/aarch64/exception_stubs.S
index d418451a..b186e82b 100644
--- a/lib/aarch64/exception_stubs.S
+++ b/lib/aarch64/exception_stubs.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,26 +12,21 @@
* Simplistic exceptions vector table.
* All entries spin, which means all types of exceptions are unrecoverable.
*/
- .macro vector_entry_spin name
- vector_entry \name
- b \name
- end_vector_entry \name
- .endm
vector_base exception_stubs
-vector_entry_spin SynchronousExceptionSP0
-vector_entry_spin IrqSP0
-vector_entry_spin FiqSP0
-vector_entry_spin SErrorSP0
-vector_entry_spin SynchronousExceptionSPx
-vector_entry_spin IrqSPx
-vector_entry_spin FiqSPx
-vector_entry_spin SErrorSPx
-vector_entry_spin SynchronousExceptionA64
-vector_entry_spin IrqA64
-vector_entry_spin FiqA64
-vector_entry_spin SErrorA64
-vector_entry_spin SynchronousExceptionA32
-vector_entry_spin IrqA32
-vector_entry_spin FiqA32
-vector_entry_spin SErrorA32
+vector_entry_spin sync_exception_sp_el0
+vector_entry_spin irq_sp_el0
+vector_entry_spin fiq_sp_el0
+vector_entry_spin serror_sp_el0
+vector_entry_spin sync_exception_sp_elx
+vector_entry_spin irq_sp_elx
+vector_entry_spin fiq_sp_elx
+vector_entry_spin serror_sp_elx
+vector_entry_spin sync_exception_aarch64
+vector_entry_spin irq_aarch64
+vector_entry_spin fiq_aarch64
+vector_entry_spin serror_aarch64
+vector_entry_spin sync_exception_aarch32
+vector_entry_spin irq_aarch32
+vector_entry_spin fiq_aarch32
+vector_entry_spin serror_aarch32
diff --git a/lib/exceptions/aarch64/sync.c b/lib/exceptions/aarch64/sync.c
new file mode 100644
index 00000000..49b6bd8d
--- /dev/null
+++ b/lib/exceptions/aarch64/sync.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <sync.h>
+
+static exception_handler_t custom_sync_exception_handler;
+
+void register_custom_sync_exception_handler(exception_handler_t handler)
+{
+ custom_sync_exception_handler = handler;
+}
+
+void unregister_custom_sync_exception_handler(void)
+{
+ custom_sync_exception_handler = NULL;
+}
+
+bool tftf_sync_exception_handler(void)
+{
+ uint64_t elr_elx = IS_IN_EL2() ? read_elr_el2() : read_elr_el1();
+ bool resume = false;
+
+ if (custom_sync_exception_handler == NULL) {
+ return false;
+ }
+
+ resume = custom_sync_exception_handler();
+
+ if (resume) {
+ /* Move ELR to next instruction to allow tftf to continue */
+ if (IS_IN_EL2()) {
+ write_elr_el2(elr_elx + 4U);
+ } else {
+ write_elr_el1(elr_elx + 4U);
+ }
+ }
+
+ return resume;
+}
diff --git a/lib/irq/irq.c b/lib/exceptions/irq.c
index 70c321b1..70c321b1 100644
--- a/lib/irq/irq.c
+++ b/lib/exceptions/irq.c
diff --git a/lib/extensions/sme/aarch64/sme.c b/lib/extensions/sme/aarch64/sme.c
new file mode 100644
index 00000000..28ddcd66
--- /dev/null
+++ b/lib/extensions/sme/aarch64/sme.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/extensions/sme.h>
+
+#ifdef __aarch64__
+
+/*
+ * feat_sme_supported
+ * Check if SME is supported on this platform.
+ * Return
+ * true if SME supported, false if not.
+ */
+bool feat_sme_supported(void)
+{
+ uint64_t features;
+
+ features = read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_SME_SHIFT;
+ return (features & ID_AA64PFR1_EL1_SME_MASK) != 0U;
+}
+
+/*
+ * feat_sme_fa64_supported
+ * Check if FEAT_SME_FA64 is supported.
+ * Return
+ * True if supported, false if not.
+ */
+bool feat_sme_fa64_supported(void)
+{
+ uint64_t features;
+
+ features = read_id_aa64smfr0_el1();
+ return (features & ID_AA64SMFR0_EL1_FA64_BIT) != 0U;
+}
+
+/*
+ * sme_enable
+ * Enable SME for nonsecure use at EL2 for TFTF cases.
+ * Return
+ * 0 if successful.
+ */
+int sme_enable(void)
+{
+ u_register_t reg;
+
+ /* Make sure SME is supported. */
+ if (!feat_sme_supported()) {
+ return -1;
+ }
+
+ /*
+ * Make sure SME accesses don't cause traps by setting appropriate fields
+ * in CPTR_EL2.
+ */
+ reg = read_cptr_el2();
+ if ((read_hcr_el2() & HCR_E2H_BIT) == 0U) {
+ /* When HCR_EL2.E2H == 0, clear TSM bit in CPTR_EL2. */
+ reg = reg & ~CPTR_EL2_TSM_BIT;
+ } else {
+ /* When HCR_EL2.E2H == 1, set SMEN bits in CPTR_EL2. */
+ reg = reg | (CPTR_EL2_SMEN_MASK << CPTR_EL2_SMEN_SHIFT);
+ }
+ write_cptr_el2(reg);
+
+ return 0;
+}
+
+/*
+ * sme_smstart
+ * This function enables streaming mode and optinally enables ZA array access
+ * at the same time.
+ * Parameters
+ * enable_za: If set, ZA access is enabled. If cleared, ZA bit is untouched.
+ */
+void sme_smstart(bool enable_za)
+{
+ u_register_t svcr = SVCR_SM_BIT;
+
+ if (enable_za) {
+ svcr |= SVCR_ZA_BIT;
+ }
+
+ write_svcr(read_svcr() | svcr);
+}
+
+/*
+ * sme_smstop
+ * This function disables streaming mode OR disables ZA array access but not
+ * both. It might seem strange but this is the functionality of the SMSTOP
+ * assembly instruction.
+ * Parameters
+ * disable_za: If set, ZA access is disabled but streaming mode is not
+ * affected. If clear, streaming mode is exited and ZA bit is
+ * left alone.
+ */
+void sme_smstop(bool disable_za)
+{
+ u_register_t svcr;
+
+ if (disable_za) {
+ svcr = ~SVCR_ZA_BIT;
+ } else {
+ svcr = ~SVCR_SM_BIT;
+ }
+
+ write_svcr(read_svcr() & svcr);
+}
+
+#endif /* __aarch64__ */
diff --git a/lib/extensions/sme/aarch64/sme_helpers.S b/lib/extensions/sme/aarch64/sme_helpers.S
new file mode 100644
index 00000000..6261c90a
--- /dev/null
+++ b/lib/extensions/sme/aarch64/sme_helpers.S
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+
+#ifdef __aarch64__
+
+ .arch armv8-a+sve
+ .globl sme_rdvl_1
+ .globl sme_try_illegal_instruction
+
+/*
+ * uint64_t sme_rdvl_1(void);
+ *
+ * Run rdvl instruction with imm #1.
+ */
+func sme_rdvl_1
+ rdvl x0, #1
+ ret
+endfunc sme_rdvl_1
+
+/*
+ * void sme_try_illegal_instruction(void);
+ *
+ * This function tests that illegal instructions are allowed to run when
+ * FA64 is supported. RDFFR is explicitly stated to be illegal in the SME
+ * specification section F1.1.2 unless FA64 is supported and enabled.
+ */
+func sme_try_illegal_instruction
+ rdffr p0.b
+ ret
+endfunc sme_try_illegal_instruction
+
+#endif /* __aarch64__ */
diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
index 037dbf81..ced9b369 100644
--- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
@@ -91,8 +91,7 @@ static const unsigned int pa_range_bits_arr[] = {
unsigned long long xlat_arch_get_max_supported_pa(void)
{
- u_register_t pa_range = read_id_aa64mmfr0_el1() &
- ID_AA64MMFR0_EL1_PARANGE_MASK;
+ u_register_t pa_range = get_pa_range();
/* All other values are reserved */
assert(pa_range < ARRAY_SIZE(pa_range_bits_arr));
diff --git a/plat/arm/corstone1000/corstone1000_def.h b/plat/arm/corstone1000/corstone1000_def.h
new file mode 100644
index 00000000..3e6f036a
--- /dev/null
+++ b/plat/arm/corstone1000/corstone1000_def.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CORSTONE1000_DEF_H__
+#define __CORSTONE1000_DEF_H__
+
+#include <common_def.h>
+#include <platform_def.h>
+
+/*******************************************************************************
+ * HOST memory map related constants
+ ******************************************************************************/
+
+#define HOST_PERIPHERAL_BASE (0x1A000000)
+#define HOST_PERIPHERAL_SIZE (608 * SZ_1M)
+
+#define ON_CHIP_MEM_BASE (0x02000000)
+#define ON_CHIP_MEM_SIZE (SZ_4M)
+
+#define DRAM_BASE (0x80000000)
+#define DRAM_SIZE (SZ_2G)
+/*******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+/* GIC memory map */
+#define GICD_BASE 0x1C010000
+#define GICC_BASE 0x1C02F000
+/* GIC re-distributor doesn't exits on gic-400, but we still need to
+ * provide GICR_BASE as the gic driver needs it
+ */
+#define GICR_BASE 0x0
+
+/*******************************************************************************
+ * PL011 related constants
+ ******************************************************************************/
+#define PL011_UART0_BASE 0x1A510000
+#define PL011_UART1_BASE 0x1A520000
+
+#define PL011_UART0_CLK_IN_HZ 50000000
+#define PL011_UART1_CLK_IN_HZ 50000000
+
+#define PLAT_ARM_UART_BASE PL011_UART0_BASE
+#define PLAT_ARM_UART_CLK_IN_HZ PL011_UART0_CLK_IN_HZ
+
+#endif /* __CORSTONE1000_DEF_H__ */
diff --git a/plat/arm/corstone1000/corstone1000_mem_prot.c b/plat/arm/corstone1000/corstone1000_mem_prot.c
new file mode 100644
index 00000000..8e4a2702
--- /dev/null
+++ b/plat/arm/corstone1000/corstone1000_mem_prot.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform.h>
+#include <psci.h>
+#include <utils_def.h>
+#include <xlat_tables_v2.h>
+
+#define NS_IMAGE_OFFSET TFTF_BASE
+#define NS_IMAGE_LIMIT (NS_IMAGE_OFFSET + (32 << TWO_MB_SHIFT))
+
+static const mem_region_t corstone1000_ram_ranges[] = {
+ {NS_IMAGE_LIMIT, 128 << TWO_MB_SHIFT},
+};
+
+const mem_region_t *plat_get_prot_regions(int *nelem)
+{
+ *nelem = ARRAY_SIZE(corstone1000_ram_ranges);
+ return corstone1000_ram_ranges;
+}
diff --git a/plat/arm/corstone1000/corstone1000_pwr_state.c b/plat/arm/corstone1000/corstone1000_pwr_state.c
new file mode 100644
index 00000000..b2f0bc82
--- /dev/null
+++ b/plat/arm/corstone1000/corstone1000_pwr_state.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <arch.h>
+#include <platform.h>
+#include <psci.h>
+
+/*
+ * State IDs for local power states on Corstone1000.
+ */
+#define CORSTONE1000_RUN_STATE_ID 0 /* Valid for CPUs and Clusters */
+#define CORSTONE1000_RETENTION_STATE_ID 1 /* Valid for only CPUs */
+#define CORSTONE1000_OFF_STATE_ID 2 /* Valid for CPUs and Clusters */
+
+/*
+ * Suspend depth definitions for each power state
+ */
+typedef enum {
+ CORSTONE1000_RUN_DEPTH = 0,
+ CORSTONE1000_RETENTION_DEPTH,
+ CORSTONE1000_OFF_DEPTH,
+} suspend_depth_t;
+
+/* The state property array with details of idle state possible for the core */
+static const plat_state_prop_t core_state_prop[] = {
+ {CORSTONE1000_RETENTION_DEPTH, CORSTONE1000_RETENTION_STATE_ID, PSTATE_TYPE_STANDBY},
+ {CORSTONE1000_OFF_DEPTH, CORSTONE1000_OFF_STATE_ID, PSTATE_TYPE_POWERDOWN},
+ {0},
+};
+
+/*
+ * The state property array with details of idle state possible
+ * for the cluster
+ */
+static const plat_state_prop_t cluster_state_prop[] = {
+ {CORSTONE1000_OFF_DEPTH, CORSTONE1000_OFF_STATE_ID, PSTATE_TYPE_POWERDOWN},
+ {0},
+};
+
+/*
+ * The state property array with details of idle state possible
+ * for the system. Currently Corstone1000 does not support CPU SUSPEND
+ * at system power level.
+ */
+static const plat_state_prop_t system_state_prop[] = {
+ {CORSTONE1000_OFF_DEPTH, CORSTONE1000_OFF_STATE_ID, PSTATE_TYPE_POWERDOWN},
+ {0},
+};
+
+const plat_state_prop_t *plat_get_state_prop(unsigned int level)
+{
+ switch (level) {
+ case MPIDR_AFFLVL0:
+ return core_state_prop;
+ case MPIDR_AFFLVL1:
+ return cluster_state_prop;
+ case MPIDR_AFFLVL2:
+ return system_state_prop;
+ default:
+ return NULL;
+ }
+}
diff --git a/plat/arm/corstone1000/corstone1000_topology.c b/plat/arm/corstone1000/corstone1000_topology.c
new file mode 100644
index 00000000..37055ec4
--- /dev/null
+++ b/plat/arm/corstone1000/corstone1000_topology.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <arch.h>
+#include <tftf_lib.h>
+#include <plat_topology.h>
+#include <platform_def.h>
+
+static const struct {
+ unsigned int cluster_id;
+ unsigned int cpu_id;
+} corstone1000_cores[] = {
+ /* SMP with single core, cluster_id is same as cpu_id */
+ { 0, 0 },
+};
+
+/*
+ * The Corstone1000 power domain tree descriptor. Corstone1000 implements a system
+ * power domain at the level 2. The first entry in the power domain descriptor
+ * specifies the number of power domains at the highest power level. For Corstone1000
+ * this is 1 i.e. the number of system power domain.
+ */
+static const unsigned char corstone1000_power_domain_tree_desc[] = {
+ /* Number of root nodes */
+ PLATFORM_SYSTEM_COUNT,
+ /* Number of children of root node */
+ PLATFORM_CLUSTER_COUNT,
+ /* Number of children for the second cluster */
+ PLATFORM_CLUSTER0_CORE_COUNT
+};
+
+const unsigned char *tftf_plat_get_pwr_domain_tree_desc(void)
+{
+ return corstone1000_power_domain_tree_desc;
+}
+
+uint64_t tftf_plat_get_mpidr(unsigned int core_pos)
+{
+ assert(core_pos < PLATFORM_CORE_COUNT);
+
+ return make_mpid(corstone1000_cores[core_pos].cluster_id,
+ corstone1000_cores[core_pos].cpu_id);
+}
diff --git a/plat/arm/corstone1000/include/platform_def.h b/plat/arm/corstone1000/include/platform_def.h
new file mode 100644
index 00000000..a0d6f7b3
--- /dev/null
+++ b/plat/arm/corstone1000/include/platform_def.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <utils_def.h>
+
+#include "../corstone1000_def.h"
+
+/*******************************************************************************
+ * Platform definitions used by common code
+ ******************************************************************************/
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#ifdef __aarch64__
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH aarch64
+#else
+#define PLATFORM_LINKER_FORMAT "elf32-littlearm"
+#define PLATFORM_LINKER_ARCH arm
+#endif
+
+/*******************************************************************************
+ * Run-time address of the TFTF image.
+ * It has to match the location where the Trusted Firmware-A loads the BL33
+ * image.
+ ******************************************************************************/
+#define TFTF_BASE 0x80000000
+
+/******************************************************************************
+ * Memory mapped Generic timer interfaces
+ *******************************************************************************/
+/* REFCLK CNTControl, Generic Timer. Secure Access only. */
+#define SYS_CNT_CONTROL_BASE 0x1A200000
+/* REFCLK CNTRead, Generic Timer. */
+#define SYS_CNT_READ_BASE 0x1A210000
+/* AP_REFCLK CNTBase1, Generic Timer. */
+#define SYS_CNT_BASE1 0x1A240000
+
+/*******************************************************************************
+ * Base address and size of external NVM flash
+ ******************************************************************************/
+#define FLASH_BASE 0x08000000
+
+#define NOR_FLASH_BLOCK_SIZE 0x40000
+#define NOR_FLASH_BLOCKS_COUNT 255
+#define FLASH_SIZE (NOR_FLASH_BLOCK_SIZE * NOR_FLASH_BLOCKS_COUNT)
+
+/* watchdog timer */
+#define IRQ_TWDOG_INTID 56
+
+/* Size of cacheable stacks */
+#if IMAGE_NS_BL1U
+#define PLATFORM_STACK_SIZE 0x1000
+#elif IMAGE_NS_BL2U
+#define PLATFORM_STACK_SIZE 0x1000
+#elif IMAGE_TFTF
+#define PLATFORM_STACK_SIZE 0x1400
+#endif
+
+/* Size of coherent stacks for debug and release builds */
+#if DEBUG
+#define PCPU_DV_MEM_STACK_SIZE 0x600
+#else
+#define PCPU_DV_MEM_STACK_SIZE 0x500
+#endif
+
+#define PLATFORM_SYSTEM_COUNT 1
+#define PLATFORM_CLUSTER_COUNT 1
+#define PLATFORM_CLUSTER0_CORE_COUNT 1 /* Cortex-A35 Cluster */
+#define PLATFORM_CORE_COUNT 1
+#define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \
+ PLATFORM_CLUSTER_COUNT + \
+ PLATFORM_CORE_COUNT)
+#define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL2
+#define PLAT_MAX_PWR_LEVEL PLATFORM_MAX_AFFLVL
+#define PLAT_MAX_PWR_STATES_PER_LVL 2
+
+#define CORSTONE1000_MAX_CPUS_PER_CLUSTER 4
+#define CORSTONE1000_MAX_PE_PER_CPU 1
+
+/* Local state bit width for each level in the state-ID field of power state */
+#define PLAT_LOCAL_PSTATE_WIDTH 4
+
+#if IMAGE_NS_BL1U
+#define MAX_IO_DEVICES 2
+#define MAX_IO_HANDLES 2
+#else
+#define MAX_IO_DEVICES 1
+#define MAX_IO_HANDLES 1
+#endif
+
+/*
+ * USE 0x200000 DRAM offset to store TFTF data
+ *
+ * Please note that this won't be suitable for all test scenarios and
+ * for this reason some tests will be disabled in this configuration.
+ */
+#define TFTF_NVM_OFFSET 0x40000
+#define TFTF_NVM_SIZE (128 * SZ_1M) /* 128 MB */
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 34)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 34)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32)
+#endif
+
+#if IMAGE_TFTF
+/* For testing xlat tables lib v2 */
+#define MAX_XLAT_TABLES 20
+#define MAX_MMAP_REGIONS 50
+#else
+#define MAX_XLAT_TABLES 5
+#define MAX_MMAP_REGIONS 16
+#endif
+
+/*******************************************************************************
+ * Used to align variables 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 6
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+/*******************************************************************************
+ * Non-Secure Software Generated Interupts IDs
+ ******************************************************************************/
+#define IRQ_NS_SGI_0 0
+#define IRQ_NS_SGI_1 1
+#define IRQ_NS_SGI_2 2
+#define IRQ_NS_SGI_3 3
+#define IRQ_NS_SGI_4 4
+#define IRQ_NS_SGI_5 5
+#define IRQ_NS_SGI_6 6
+#define IRQ_NS_SGI_7 7
+
+#define PLAT_MAX_SPI_OFFSET_ID 220
+
+/* The IRQ generated by Ethernet controller */
+#define IRQ_ETHERNET 116
+
+#define IRQ_CNTPSIRQ1 92
+/* Per-CPU Hypervisor Timer Interrupt ID */
+#define IRQ_PCPU_HP_TIMER 26
+/* Per-CPU Non-Secure Timer Interrupt ID */
+#define IRQ_PCPU_NS_TIMER 30
+
+/*
+ * Times(in ms) used by test code for completion of different events.
+ * Suspend entry time for debug build is high due to the time taken
+ * by the VERBOSE/INFO prints. The value considers the worst case scenario
+ * where all CPUs are going and coming out of suspend continuously.
+ */
+#if DEBUG
+#define PLAT_SUSPEND_ENTRY_TIME 0x100
+#define PLAT_SUSPEND_ENTRY_EXIT_TIME 0x200
+#else
+#define PLAT_SUSPEND_ENTRY_TIME 10
+#define PLAT_SUSPEND_ENTRY_EXIT_TIME 20
+#endif
+
+#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/arm/corstone1000/plat_helpers.S b/plat/arm/corstone1000/plat_helpers.S
new file mode 100644
index 00000000..a87f36f1
--- /dev/null
+++ b/plat/arm/corstone1000/plat_helpers.S
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/pl011.h>
+#include "corstone1000_def.h"
+
+ .globl platform_get_core_pos
+ .globl plat_crash_console_init
+ .globl plat_crash_console_putc
+ .globl plat_crash_console_flush
+
+/*----------------------------------------------------------------------
+ * unsigned int platform_get_core_pos(unsigned long mpid)
+ *
+ * Function to calculate the core position on FVP.
+ *
+ * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU) +
+ * (CPUId * FVP_MAX_PE_PER_CPU) +
+ * ThreadId
+ *
+ * which can be simplified as:
+ *
+ * ((ClusterId * FVP_MAX_CPUS_PER_CLUSTER + CPUId) * FVP_MAX_PE_PER_CPU)
+ * + ThreadId
+ * ---------------------------------------------------------------------
+ */
+func platform_get_core_pos
+ /*
+ * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
+ * look as if in a multi-threaded implementation.
+ */
+ tst x0, #MPIDR_MT_MASK
+ lsl x3, x0, #MPIDR_AFFINITY_BITS
+ csel x3, x3, x0, eq
+
+ /* Extract individual affinity fields from MPIDR */
+ ubfx x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+
+ /* Compute linear position */
+ mov x3, #CORSTONE1000_MAX_CPUS_PER_CLUSTER
+ madd x1, x2, x3, x1
+ mov x3, #CORSTONE1000_MAX_PE_PER_CPU
+ madd x0, x1, x3, x0
+ ret
+endfunc platform_get_core_pos
+
+ /* ---------------------------------------------
+ * int plat_crash_console_init(void)
+ * Function to initialize the crash console
+ * without a C Runtime to print crash report.
+ * Clobber list : x0 - x4
+ * ---------------------------------------------
+ */
+func plat_crash_console_init
+ mov_imm x0, PLAT_ARM_UART_BASE
+ mov_imm x1, PLAT_ARM_UART_CLK_IN_HZ
+ mov_imm x2, PL011_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_ARM_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 : r0 - r1
+ * ---------------------------------------------
+ */
+func plat_crash_console_flush
+ mov_imm x1, PLAT_ARM_UART_BASE
+ b console_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/arm/corstone1000/plat_setup.c b/plat/arm/corstone1000/plat_setup.c
new file mode 100644
index 00000000..342885d7
--- /dev/null
+++ b/plat/arm/corstone1000/plat_setup.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/arm_gic.h>
+#include <mmio.h>
+#include <platform.h>
+#include <xlat_tables_v2.h>
+#include <plat_arm.h>
+
+/*
+ * Table of regions to map using the MMU.
+ */
+static const mmap_region_t mmap[] = {
+ MAP_REGION_FLAT(HOST_PERIPHERAL_BASE, HOST_PERIPHERAL_SIZE,
+ MT_DEVICE | MT_RW | MT_NS),
+ MAP_REGION_FLAT(ON_CHIP_MEM_BASE, ON_CHIP_MEM_SIZE, MT_MEMORY | MT_RW | MT_SECURE),
+#if USE_NVM
+ MAP_REGION_FLAT(FLASH_BASE, FLASH_SIZE, MT_DEVICE | MT_RW | MT_NS),
+#endif
+ MAP_REGION_FLAT(DRAM_BASE, TFTF_BASE - DRAM_BASE, MT_MEMORY | MT_RW | MT_NS),
+ {0}
+};
+
+const mmap_region_t *tftf_platform_get_mmap(void)
+{
+ return mmap;
+}
+
+void tftf_platform_setup(void)
+{
+ arm_platform_setup();
+}
+
+void plat_arm_gic_init(void)
+{
+ arm_gic_init(GICC_BASE, GICD_BASE, GICR_BASE);
+}
diff --git a/plat/arm/corstone1000/platform.mk b/plat/arm/corstone1000/platform.mk
new file mode 100644
index 00000000..a5a011d5
--- /dev/null
+++ b/plat/arm/corstone1000/platform.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES := -Iplat/arm/corstone1000/include/
+
+PLAT_SOURCES := drivers/arm/gic/arm_gic_v2.c \
+ drivers/arm/gic/gic_v2.c \
+ drivers/arm/timer/private_timer.c \
+ drivers/arm/timer/system_timer.c \
+ plat/arm/corstone1000/plat_helpers.S \
+ plat/arm/corstone1000/corstone1000_pwr_state.c \
+ plat/arm/corstone1000/corstone1000_topology.c \
+ plat/arm/corstone1000/corstone1000_mem_prot.c \
+ plat/arm/corstone1000/plat_setup.c
+
+PLAT_SUPPORTS_NS_RESET := 1
+
+# Process PLAT_SUPPORTS_NS_RESET flag
+$(eval $(call assert_boolean,PLAT_SUPPORTS_NS_RESET))
+$(eval $(call add_define,TFTF_DEFINES,PLAT_SUPPORTS_NS_RESET))
+
+FIRMWARE_UPDATE := 0
+PLAT_TESTS_SKIP_LIST := plat/arm/corstone1000/tests_to_skip.txt
+
+include plat/arm/common/arm_common.mk
diff --git a/plat/arm/corstone1000/tests_to_skip.txt b/plat/arm/corstone1000/tests_to_skip.txt
new file mode 100644
index 00000000..fdab2309
--- /dev/null
+++ b/plat/arm/corstone1000/tests_to_skip.txt
@@ -0,0 +1,15 @@
+Realm payload tests
+Realm payload boot
+Realm payload multi CPU request
+Realm payload Delegate and Undelegate
+Multi CPU Realm payload Delegate and Undelegate
+Testing delegation fails
+Realm testing with SPM tests
+PSCI System Suspend Validation
+PSCI STAT/Stats test cases after system suspend
+IRQ support in TSP/Resume preempted STD SMC after PSCI SYSTEM SUSPEND
+PSCI SYSTEM SUSPEND stress tests
+Timer framework Validation/Verify the timer interrupt generation
+CPU Hotplug/CPU hotplug
+PSCI CPU Suspend
+PSCI STAT/for valid composite state CPU suspend
diff --git a/plat/arm/fvp/include/platform_def.h b/plat/arm/fvp/include/platform_def.h
index 3afc9b8b..b8871c48 100644
--- a/plat/arm/fvp/include/platform_def.h
+++ b/plat/arm/fvp/include/platform_def.h
@@ -37,6 +37,10 @@
/* Base address of non-trusted watchdog (SP805) */
#define SP805_WDOG_BASE 0x1C0F0000
+/* Base address of trusted watchdog (SP805) */
+#define SP805_TWDOG_BASE 0x2A490000
+#define IRQ_TWDOG_INTID 56
+
/*******************************************************************************
* Base address and size of external NVM flash
******************************************************************************/
@@ -53,6 +57,37 @@
#define NOR_FLASH_BLOCKS_COUNT 255
#define FLASH_SIZE (NOR_FLASH_BLOCK_SIZE * NOR_FLASH_BLOCKS_COUNT)
+/**********************************
+ * Addresses to test invalid access
+ **********************************/
+/*
+ * The top 16MB (or 64MB if RME is enabled) of DRAM1 is configured as
+ * follows for FVP platform:
+ * - L1 GPT DRAM: Reserved for L1 GPT if RME is enabled
+ * - REALM DRAM: Reserved for Realm world if RME is enabled
+ * - AP TZC DRAM: The remaining TZC secured DRAM reserved for AP use
+ *
+ * RME enabled(64MB) RME not enabled(16MB)
+ * 0xFC00_0000 -------------------- ------------------- 0xFF00_0000
+ * | | | |
+ * 0xFD000000 | AP Secure (~28MB)| | AP TZC (~14MB) |
+ * -------------------- ------------------- 0xFFE0_0000
+ * | | | |
+ * | REALM (32MB) | | EL3 TZC (2MB) |
+ * -------------------- ------------------- 0xFFFF_FFFF
+ * | |
+ * 0xFFE0_0000 | EL3 Root (3MB) |
+ * --------------------
+ * | L1 GPT (1MB) |
+ * | |
+ * 0xFFFF_FFFF --------------------
+ *
+ *
+ */
+/* For both RME & non-RME case top 2MB will be EL3 memory */
+#define EL3_MEMORY_ACCESS_ADDR U(0xFFE00000)
+#define SECURE_MEMORY_ACCESS_ADDR U(0xFD000000)
+
/*******************************************************************************
* Base address and size for the FIP that contains FWU images.
******************************************************************************/
@@ -103,7 +138,7 @@
* calculated using the current NS_BL1U RW debug size plus a little space
* for growth.
******************************************************************************/
-#define NS_BL1U_RW_SIZE (0x7000)
+#define NS_BL1U_RW_SIZE (0x9000)
#define NS_BL1U_RW_BASE (NSRAM_BASE)
#define NS_BL1U_RW_LIMIT (NS_BL1U_RW_BASE + NS_BL1U_RW_SIZE)
@@ -119,7 +154,7 @@
* Base address and limit for NS_BL2U image.
******************************************************************************/
#define NS_BL2U_BASE DRAM_BASE
-#define NS_BL2U_LIMIT (NS_BL2U_BASE + 0x4D000)
+#define NS_BL2U_LIMIT (NS_BL2U_BASE + 0x4E000)
/******************************************************************************
* Memory mapped Generic timer interfaces
@@ -205,8 +240,8 @@
* Platform specific page table and MMU setup constants
******************************************************************************/
#ifdef __aarch64__
-#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 34)
-#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 34)
+#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << PA_SIZE)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << PA_SIZE)
#else
#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32)
#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32)
@@ -218,7 +253,7 @@
#define MAX_MMAP_REGIONS 50
#else
#if IMAGE_CACTUS
-#define MAX_XLAT_TABLES 6
+#define MAX_XLAT_TABLES 9
#else
#define MAX_XLAT_TABLES 5
#endif
diff --git a/plat/arm/fvp/platform.mk b/plat/arm/fvp/platform.mk
index 42779c72..e467cd68 100644
--- a/plat/arm/fvp/platform.mk
+++ b/plat/arm/fvp/platform.mk
@@ -56,9 +56,17 @@ ifneq ($(FVP_MAX_CPUS_PER_CLUSTER),$(filter $(FVP_MAX_CPUS_PER_CLUSTER),$(CPU)))
endif
# Pass FVP topology definitions to the build system
-$(eval $(call add_define,TFTF_DEFINES,FVP_CLUSTER_COUNT))
-$(eval $(call add_define,TFTF_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
-$(eval $(call add_define,TFTF_DEFINES,FVP_MAX_PE_PER_CPU))
+$(eval $(call add_define,CACTUS_DEFINES,FVP_CLUSTER_COUNT))
+$(eval $(call add_define,CACTUS_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
+$(eval $(call add_define,CACTUS_DEFINES,FVP_MAX_PE_PER_CPU))
+
+$(eval $(call add_define,CACTUS_MM_DEFINES,FVP_CLUSTER_COUNT))
+$(eval $(call add_define,CACTUS_MM_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
+$(eval $(call add_define,CACTUS_MM_DEFINES,FVP_MAX_PE_PER_CPU))
+
+$(eval $(call add_define,IVY_DEFINES,FVP_CLUSTER_COUNT))
+$(eval $(call add_define,IVY_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
+$(eval $(call add_define,IVY_DEFINES,FVP_MAX_PE_PER_CPU))
$(eval $(call add_define,NS_BL1U_DEFINES,FVP_CLUSTER_COUNT))
$(eval $(call add_define,NS_BL1U_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
@@ -68,6 +76,19 @@ $(eval $(call add_define,NS_BL2U_DEFINES,FVP_CLUSTER_COUNT))
$(eval $(call add_define,NS_BL2U_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
$(eval $(call add_define,NS_BL2U_DEFINES,FVP_MAX_PE_PER_CPU))
+$(eval $(call add_define,TFTF_DEFINES,FVP_CLUSTER_COUNT))
+$(eval $(call add_define,TFTF_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
+$(eval $(call add_define,TFTF_DEFINES,FVP_MAX_PE_PER_CPU))
+
+# Default PA size for FVP platform
+PA_SIZE := 34
+
+$(eval $(call add_define,CACTUS_DEFINES,PA_SIZE))
+$(eval $(call add_define,IVY_DEFINES,PA_SIZE))
+$(eval $(call add_define,NS_BL1U_DEFINES,PA_SIZE))
+$(eval $(call add_define,NS_BL2U_DEFINES,PA_SIZE))
+$(eval $(call add_define,TFTF_DEFINES,PA_SIZE))
+
PLAT_INCLUDES += -Iplat/arm/fvp/include/
PLAT_SOURCES := drivers/arm/gic/arm_gic_v2v3.c \
@@ -83,6 +104,7 @@ PLAT_SOURCES := drivers/arm/gic/arm_gic_v2v3.c \
plat/arm/fvp/plat_setup.c
CACTUS_SOURCES += plat/arm/fvp/${ARCH}/plat_helpers.S
+IVY_SOURCES += plat/arm/fvp/${ARCH}/plat_helpers.S
# Firmware update is implemented on FVP.
FIRMWARE_UPDATE := 1
diff --git a/plat/arm/juno/include/platform_def.h b/plat/arm/juno/include/platform_def.h
index 0f9bb778..2de11fd3 100644
--- a/plat/arm/juno/include/platform_def.h
+++ b/plat/arm/juno/include/platform_def.h
@@ -42,6 +42,10 @@
/* Base address of non-trusted watchdog (SP805) */
#define SP805_WDOG_BASE 0x1C0F0000
+/* Base address of trusted watchdog (SP805) */
+#define SP805_TWDOG_BASE 0x2A4A0000
+#define IRQ_TWDOG_INTID 86
+
/* Memory mapped Generic timer interfaces */
#define SYS_CNT_BASE1 0x2a830000
diff --git a/plat/arm/n1sdp/aarch64/plat_helpers.S b/plat/arm/n1sdp/aarch64/plat_helpers.S
new file mode 100644
index 00000000..d0c6347a
--- /dev/null
+++ b/plat/arm/n1sdp/aarch64/plat_helpers.S
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <drivers/arm/pl011.h>
+#include <platform_def.h>
+
+ .globl platform_get_core_pos
+ .globl plat_crash_console_init
+ .globl plat_crash_console_putc
+ .globl plat_crash_console_flush
+
+/*----------------------------------------------------------------------
+ * unsigned int platform_get_core_pos(unsigned long mpid)
+ *
+ * Function to calculate the core position on N1SDP platforms.
+ *
+ * (ClusterId * N1SDP_MAX_CPUS_PER_CLUSTER * N1SDP_MAX_PE_PER_CPU) +
+ * (CPUId * N1SDP_MAX_PE_PER_CPU) +
+ * ThreadId
+ *
+ * which can be simplified as:
+ *
+ * ((ClusterId * N1SDP_MAX_CPUS_PER_CLUSTER + CPUId) * N1SDP_MAX_PE_PER_CPU)
+ * + ThreadId
+ * ---------------------------------------------------------------------
+ */
+func platform_get_core_pos
+ /*
+ * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
+ * look as if in a multi-threaded implementation.
+ */
+ tst x0, #MPIDR_MT_MASK
+ lsl x3, x0, #MPIDR_AFFINITY_BITS
+ csel x3, x3, x0, eq
+
+ /* Extract individual affinity fields from MPIDR */
+ ubfx x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+
+ /* Compute linear position */
+ mov x3, #N1SDP_MAX_CPUS_PER_CLUSTER
+ madd x1, x2, x3, x1
+ mov x3, #N1SDP_MAX_PE_PER_CPU
+ madd x0, x1, x3, x0
+ ret
+endfunc platform_get_core_pos
+
+/* ---------------------------------------------
+ * int plat_crash_console_init(void)
+ * Function to initialize the crash console
+ * without a C Runtime to print crash report.
+ * Clobber list : x0 - x4
+ * ---------------------------------------------
+ */
+func plat_crash_console_init
+ mov_imm x0, PLAT_ARM_UART_BASE
+ mov_imm x1, PLAT_ARM_UART_CLK_IN_HZ
+ mov_imm x2, PL011_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_ARM_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_ARM_UART_BASE
+ b console_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/arm/n1sdp/include/platform_def.h b/plat/arm/n1sdp/include/platform_def.h
new file mode 100644
index 00000000..71409fc0
--- /dev/null
+++ b/plat/arm/n1sdp/include/platform_def.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+/* Platform binary types for linking */
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH aarch64
+
+#define N1SDP_CLUSTER_COUNT 2
+#define N1SDP_MAX_CPUS_PER_CLUSTER 2
+#define N1SDP_MAX_PE_PER_CPU 1
+
+/*******************************************************************************
+ * Run-time address of the TFTF image.
+ * It has to match the location where the Trusted Firmware-A loads the BL33
+ * image.
+ ******************************************************************************/
+#define TFTF_BASE 0xE0000000
+
+#define N1SDP_DRAM1_BASE 0x80000000
+#define N1SDP_DRAM1_SIZE 0x80000000
+#define DRAM_BASE N1SDP_DRAM1_BASE
+
+/*
+ * TF-A reserves DRAM space 0xFD000000 - 0xFEFFFFFF for Trusted DRAM
+ * TF-A reserves DRAM space 0xFF000000 - 0xFFFFFFFF for TZC
+ */
+#define ARM_TZC_DRAM1_SIZE 0x00200000 /* 2MB */
+#define ARM_TRUSTED_DRAM1_SIZE 0x0E000000 /* 16MB */
+
+#define DRAM_SIZE (N1SDP_DRAM1_SIZE - \
+ ARM_TRUSTED_DRAM1_SIZE - \
+ ARM_TZC_DRAM1_SIZE)
+
+/* REFCLK CNTControl, Generic Timer. Secure Access only. */
+#define SYS_CNT_CONTROL_BASE 0x2a430000
+/* REFCLK CNTRead, Generic Timer. */
+#define SYS_CNT_READ_BASE 0x2a800000
+/* AP_REFCLK CNTBase1, Generic Timer. */
+#define SYS_CNT_BASE1 0x2A830000
+
+/* Base address of non-trusted watchdog (SP805) */
+#define SP805_WDOG_BASE 0x1C0F0000
+
+/* Base address of trusted watchdog (SP805) */
+#define SP805_TWDOG_BASE 0x2A480000
+#define IRQ_TWDOG_INTID 86
+
+/* Base address and size of external NVM flash */
+#define FLASH_BASE 0x08000000
+
+#define NOR_FLASH_BLOCK_SIZE 0x40000 /* 256KB */
+#define FLASH_SIZE 0x4000000 /* 64MB */
+
+/*
+ * If you want to use DRAM for non-volatile memory then the first 128MB
+ * can be used. However for tests that involve power resets this is not
+ * suitable since the state will be lost.
+ */
+#define TFTF_NVM_OFFSET 0x0
+#define TFTF_NVM_SIZE 0x8000000 /* 128 MB */
+
+/* Sub-system Peripherals */
+#define N1SDP_DEVICE0_BASE 0x08000000
+#define N1SDP_DEVICE0_SIZE 0x48000000
+
+/* N1SDP remote chip at 4 TB offset */
+#define PLAT_ARM_REMOTE_CHIP_OFFSET (ULL(1) << 42)
+
+/* Following covers remote n1sdp */
+#define N1SDP_DEVICE1_BASE (N1SDP_DEVICE0_BASE + PLAT_ARM_REMOTE_CHIP_OFFSET)
+#define N1SDP_DEVICE1_SIZE N1SDP_DEVICE0_SIZE
+
+/* GIC-600 & interrupt handling related constants */
+#define N1SDP_GICD_BASE 0x30000000
+#define N1SDP_GICR_BASE 0x300C0000
+#define N1SDP_GICC_BASE 0x2C000000
+
+/* SoC's PL011 UART0 related constants */
+#define PL011_UART0_BASE 0x2A400000
+#define PL011_UART0_CLK_IN_HZ 50000000
+
+/*
+ * SoC's PL011 UART1 related constants (duplicated from UART0 since AP UART1
+ * isn't accessible on N1SDP)
+ */
+#define PL011_UART1_BASE 0x2A400000
+#define PL011_UART1_CLK_IN_HZ 50000000
+
+#define PLAT_ARM_UART_BASE PL011_UART0_BASE
+#define PLAT_ARM_UART_CLK_IN_HZ PL011_UART0_CLK_IN_HZ
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE 0x1400
+
+/* Size of coherent stacks */
+#define PCPU_DV_MEM_STACK_SIZE 0x600
+
+#define PLATFORM_CORE_COUNT (N1SDP_CLUSTER_COUNT * N1SDP_MAX_CPUS_PER_CLUSTER)
+#define PLATFORM_NUM_AFFS (N1SDP_CLUSTER_COUNT + PLATFORM_CORE_COUNT)
+#define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL1
+
+#define PLAT_MAX_PWR_LEVEL PLATFORM_MAX_AFFLVL
+#define PLAT_MAX_PWR_STATES_PER_LVL 2
+
+/* I/O Storage NOR flash device */
+#define MAX_IO_DEVICES 1
+#define MAX_IO_HANDLES 1
+
+/* Local state bit width for each level in the state-ID field of power state */
+#define PLAT_LOCAL_PSTATE_WIDTH 4
+
+/* Platform specific page table and MMU setup constants */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 36)
+
+#if IMAGE_CACTUS
+#define MAX_XLAT_TABLES 6
+#else
+#define MAX_XLAT_TABLES 5
+#endif
+#define MAX_MMAP_REGIONS 16
+
+/*******************************************************************************
+ * Used to align variables 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 6
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+/* Non-Secure Software Generated Interupts IDs */
+#define IRQ_NS_SGI_0 0
+#define IRQ_NS_SGI_7 7
+
+/*
+ * AP UART1 interrupt is considered as the maximum SPI.
+ * MAX_SPI_ID = MIN_SPI_ID + PLAT_MAX_SPI_OFFSET_ID = 96
+ */
+#define PLAT_MAX_SPI_OFFSET_ID 64
+
+/* AP_REFCLK Generic Timer, Non-secure. */
+#define IRQ_CNTPSIRQ1 92
+
+/* Per-CPU Hypervisor Timer Interrupt ID */
+#define IRQ_PCPU_HP_TIMER 26
+
+/* Times(in ms) used by test code for completion of different events */
+#define PLAT_SUSPEND_ENTRY_TIME 0x100
+#define PLAT_SUSPEND_ENTRY_EXIT_TIME 0x200
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/n1sdp/n1sdp_mem_prot.c b/plat/arm/n1sdp/n1sdp_mem_prot.c
new file mode 100644
index 00000000..1ee602d3
--- /dev/null
+++ b/plat/arm/n1sdp/n1sdp_mem_prot.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform.h>
+
+#define N1SDP_DRAM1_NS_START (TFTF_BASE + 0x4000000)
+#define N1SDP_DRAM1_NS_SIZE 0x10000000
+
+static const mem_region_t n1sdp_ram_ranges[] = {
+ { N1SDP_DRAM1_NS_START, N1SDP_DRAM1_NS_SIZE }
+};
+
+const mem_region_t *plat_get_prot_regions(int *nelem)
+{
+ *nelem = ARRAY_SIZE(n1sdp_ram_ranges);
+ return n1sdp_ram_ranges;
+}
diff --git a/plat/arm/n1sdp/n1sdp_pwr_state.c b/plat/arm/n1sdp/n1sdp_pwr_state.c
new file mode 100644
index 00000000..fcee7c4a
--- /dev/null
+++ b/plat/arm/n1sdp/n1sdp_pwr_state.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform.h>
+#include <psci.h>
+
+/* State IDs for local power states on SGI platforms. */
+#define N1SDP_PS_RUN_STATE_ID 0 /* Valid for CPUs and Clusters */
+#define N1SDP_PS_RETENTION_STATE_ID 1 /* Valid for only CPUs */
+#define N1SDP_PS_OFF_STATE_ID 2 /* Valid for CPUs and Clusters */
+
+/* Suspend depth definitions for each power state */
+#define N1SDP_PS_RUN_DEPTH 0
+#define N1SDP_PS_RETENTION_DEPTH 1
+#define N1SDP_PS_OFF_DEPTH 2
+
+/* The state property array with details of idle state possible for the core */
+static const plat_state_prop_t core_state_prop[] = {
+ {N1SDP_PS_RETENTION_DEPTH, N1SDP_PS_RETENTION_STATE_ID, PSTATE_TYPE_STANDBY},
+ {N1SDP_PS_OFF_DEPTH, N1SDP_PS_OFF_STATE_ID, PSTATE_TYPE_POWERDOWN},
+ {0}
+};
+
+/* The state property array with details of idle state possible for the cluster */
+static const plat_state_prop_t cluster_state_prop[] = {
+ {N1SDP_PS_OFF_DEPTH, N1SDP_PS_OFF_STATE_ID, PSTATE_TYPE_POWERDOWN},
+ {0}
+};
+
+const plat_state_prop_t *plat_get_state_prop(unsigned int level)
+{
+ switch (level) {
+ case MPIDR_AFFLVL0:
+ return core_state_prop;
+ case MPIDR_AFFLVL1:
+ return cluster_state_prop;
+ default:
+ return NULL;
+ }
+}
diff --git a/plat/arm/n1sdp/n1sdp_topology.c b/plat/arm/n1sdp/n1sdp_topology.c
new file mode 100644
index 00000000..40750ced
--- /dev/null
+++ b/plat/arm/n1sdp/n1sdp_topology.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <plat_topology.h>
+#include <tftf_lib.h>
+
+static const struct {
+ unsigned int cluster_id;
+ unsigned int cpu_id;
+} n1sdp_cores[] = {
+ /* N1SDP has 2 clusters with 2 cores each */
+ { 0, 0 },
+ { 0, 1 },
+ { 1, 0 },
+ { 1, 1 },
+};
+
+/*
+ * The power domain tree descriptor. The cluster power domains are
+ * arranged so that when the PSCI generic code creates the power domain tree,
+ * the indices of the CPU power domain nodes it allocates match the linear
+ * indices returned by plat_core_pos_by_mpidr().
+ */
+const unsigned char n1sdp_pd_tree_desc[] = {
+ /* Number of root nodes */
+ N1SDP_CLUSTER_COUNT,
+ /* Number of children for the 1st node */
+ N1SDP_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 2nd node */
+ N1SDP_MAX_CPUS_PER_CLUSTER
+};
+
+const unsigned char *tftf_plat_get_pwr_domain_tree_desc(void)
+{
+ return n1sdp_pd_tree_desc;
+}
+
+uint64_t tftf_plat_get_mpidr(unsigned int core_pos)
+{
+ uint64_t mpid;
+
+ assert(core_pos < PLATFORM_CORE_COUNT);
+
+ mpid = (uint64_t)make_mpid(n1sdp_cores[core_pos].cluster_id,
+ n1sdp_cores[core_pos].cpu_id);
+
+ return mpid;
+}
diff --git a/plat/arm/n1sdp/plat_setup.c b/plat/arm/n1sdp/plat_setup.c
new file mode 100644
index 00000000..1c04c264
--- /dev/null
+++ b/plat/arm/n1sdp/plat_setup.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/arm_gic.h>
+#include <xlat_tables_v2.h>
+
+static const mmap_region_t mmap[] = {
+ MAP_REGION_FLAT(N1SDP_DEVICE0_BASE, N1SDP_DEVICE0_SIZE,
+ MT_DEVICE | MT_RW | MT_NS),
+ /*MAP_REGION_FLAT(N1SDP_DEVICE1_BASE, N1SDP_DEVICE1_SIZE,
+ MT_DEVICE | MT_RW | MT_NS),*/
+ MAP_REGION_FLAT(DRAM_BASE, TFTF_BASE - DRAM_BASE,
+ MT_MEMORY | MT_RW | MT_NS),
+ {0}
+};
+
+const mmap_region_t *tftf_platform_get_mmap(void)
+{
+ return mmap;
+}
+
+void plat_arm_gic_init(void)
+{
+ arm_gic_init(N1SDP_GICC_BASE, N1SDP_GICD_BASE, N1SDP_GICR_BASE);
+}
diff --git a/plat/arm/n1sdp/platform.mk b/plat/arm/n1sdp/platform.mk
new file mode 100644
index 00000000..39c33ab8
--- /dev/null
+++ b/plat/arm/n1sdp/platform.mk
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+N1SDP_MAX_PE_PER_CPU := 1
+
+$(eval $(call add_define,TFTF_DEFINES,N1SDP_MAX_PE_PER_CPU))
+$(eval $(call add_define,NS_BL1U_DEFINES,N1SDP_MAX_PE_PER_CPU))
+$(eval $(call add_define,NS_BL2U_DEFINES,N1SDP_MAX_PE_PER_CPU))
+
+PLAT_INCLUDES += -Iplat/arm/n1sdp/include/
+
+PLAT_SOURCES := drivers/arm/gic/arm_gic_v2v3.c \
+ drivers/arm/gic/gic_v2.c \
+ drivers/arm/gic/gic_v3.c \
+ drivers/arm/sp805/sp805.c \
+ drivers/arm/timer/private_timer.c \
+ drivers/arm/timer/system_timer.c \
+ plat/arm/n1sdp/${ARCH}/plat_helpers.S \
+ plat/arm/n1sdp/plat_setup.c \
+ plat/arm/n1sdp/n1sdp_mem_prot.c \
+ plat/arm/n1sdp/n1sdp_pwr_state.c \
+ plat/arm/n1sdp/n1sdp_topology.c
+
+CACTUS_SOURCES += plat/arm/n1sdp/${ARCH}/plat_helpers.S
+IVY_SOURCES += plat/arm/n1sdp/${ARCH}/plat_helpers.S
+
+PLAT_TESTS_SKIP_LIST := plat/arm/n1sdp/tests_to_skip.txt
+
+ifeq (${USE_NVM},1)
+$(error "USE_NVM is not supported on N1SDP platforms")
+endif
+
+$(warning "TFTF on N1SDP is still in development and there may be issues")
+
+include plat/arm/common/arm_common.mk
diff --git a/plat/arm/n1sdp/tests_to_skip.txt b/plat/arm/n1sdp/tests_to_skip.txt
new file mode 100644
index 00000000..21417e0a
--- /dev/null
+++ b/plat/arm/n1sdp/tests_to_skip.txt
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Disable SMMUv3 tests
+SMMUv3 tests
+
+# PSCI is enabled but not tested
+PSCI STAT/Stats test cases after system suspend
+PSCI System Suspend Validation
+
+# Disable FF-A Interrupt tests as TWDOG is not supported by TC platform
+FF-A Interrupt
+
+# The following tests were disabled to make TFTF successfully run on N1SDP
+#
+# There is an issue where issuing an SGI to a powered off core will not wake it up
+#
+# Most of these tests should work but something is likely wrong with the plat
+# files in TFTF, since the port was done purely to test the spectre workaround
+# performance impact. Once that was done no further work was done on the port.
+
+Timer framework Validation/Target timer to a power down cpu
+Timer framework Validation/Test scenario where multiple CPUs call same timeout
+Timer framework Validation/Stress test the timer framework
+PSCI Affinity Info/Affinity info level0 powerdown
+PSCI CPU Suspend
+PSCI STAT/for valid composite state CPU suspend
diff --git a/plat/arm/rdinfra/rdn1edge/include/platform_def.h b/plat/arm/rdinfra/rdn1edge/include/platform_def.h
index 45816f5e..0ae8ec50 100644
--- a/plat/arm/rdinfra/rdn1edge/include/platform_def.h
+++ b/plat/arm/rdinfra/rdn1edge/include/platform_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,10 +7,19 @@
#ifndef PLATFORM_DEF_H
#define PLATFORM_DEF_H
-#include <sgi_base_platform_def.h>
+#include "sgi_soc_platform_def.h"
-#define SGI_CLUSTER_COUNT 2
-#define SGI_MAX_CPUS_PER_CLUSTER 4
-#define SGI_MAX_PE_PER_CPU 1
+#define PLAT_ARM_CLUSTER_COUNT U(2)
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER U(4)
+#define CSS_SGI_MAX_PE_PER_CPU U(1)
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE UL(0x30000000)
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+#define PLAT_ARM_GICR_BASE UL(0x300C0000)
+
+/* Platform specific page table and MMU setup constants */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/rdinfra/rdn1edge/platform.mk b/plat/arm/rdinfra/rdn1edge/platform.mk
index 3e25a047..d44e5a04 100644
--- a/plat/arm/rdinfra/rdn1edge/platform.mk
+++ b/plat/arm/rdinfra/rdn1edge/platform.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2019, Arm Limited. All rights reserved.
+# Copyright (c) 2019-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -11,3 +11,8 @@ PLAT_INCLUDES += -Iplat/arm/rdinfra/rdn1edge/include/
PLAT_SOURCES += plat/arm/rdinfra/rdn1edge/topology.c
PLAT_TESTS_SKIP_LIST := plat/arm/rdinfra/rdn1edge/tests_to_skip.txt
+
+ifdef CSS_SGI_PLATFORM_VARIANT
+$(error "CSS_SGI_PLATFORM_VARIANT should not be set for RD-N1-Edge, \
+ currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+endif
diff --git a/plat/arm/rdinfra/rdn1edge/topology.c b/plat/arm/rdinfra/rdn1edge/topology.c
index 5521de45..6f206951 100644
--- a/plat/arm/rdinfra/rdn1edge/topology.c
+++ b/plat/arm/rdinfra/rdn1edge/topology.c
@@ -32,11 +32,11 @@ static const struct {
*/
const unsigned char plat_pd_tree_desc[] = {
/* Number of root nodes */
- SGI_CLUSTER_COUNT,
+ PLAT_ARM_CLUSTER_COUNT,
/* Number of children for the 1st node */
- SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
/* Number of children for the 2nd node */
- SGI_MAX_CPUS_PER_CLUSTER
+ CSS_SGI_MAX_CPUS_PER_CLUSTER
};
const unsigned char *tftf_plat_get_pwr_domain_tree_desc(void)
diff --git a/plat/arm/rdinfra/rdn2/include/platform_def.h b/plat/arm/rdinfra/rdn2/include/platform_def.h
new file mode 100644
index 00000000..ab4149d2
--- /dev/null
+++ b/plat/arm/rdinfra/rdn2/include/platform_def.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <sgi_soc_platform_def_v2.h>
+
+/*
+ * The RD-N2 Cfg1 platform is a variant of the RD-N2 platform with a
+ * reduced interconnect mesh size (3x3) and core count (8-cores).
+ *
+ * The $CSS_SGI_PLATFORM_VARIANT flag is set to 1 for RD-N2-Cfg1 platform.
+ */
+#if (CSS_SGI_PLATFORM_VARIANT == 1)
+#define PLAT_ARM_CLUSTER_COUNT U(8)
+#else
+#define PLAT_ARM_CLUSTER_COUNT U(16)
+#endif
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER U(1)
+#define CSS_SGI_MAX_PE_PER_CPU U(1)
+
+/* GIC-600 & interrupt handling related constants */
+#define PLAT_ARM_GICD_BASE UL(0x30000000)
+#if (CSS_SGI_PLATFORM_VARIANT == 1)
+#define PLAT_ARM_GICR_BASE UL(0x30100000)
+#else
+#define PLAT_ARM_GICR_BASE UL(0x301C0000)
+#endif
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+
+/* Platform specific page table and MMU setup constants */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 46)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 46)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/rdinfra/rdn2/platform.mk b/plat/arm/rdinfra/rdn2/platform.mk
new file mode 100644
index 00000000..01f56b3f
--- /dev/null
+++ b/plat/arm/rdinfra/rdn2/platform.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include plat/arm/sgi/common/sgi_common.mk
+
+PLAT_INCLUDES += -Iplat/arm/rdinfra/rdn2/include/
+
+PLAT_SOURCES += plat/arm/rdinfra/rdn2/topology.c
+
+PLAT_TESTS_SKIP_LIST := plat/arm/rdinfra/rdn2/tests_to_skip.txt
+
+RD_N2_VARIANTS := 0 1
+
+ifneq ($(CSS_SGI_PLATFORM_VARIANT), \
+ $(filter $(CSS_SGI_PLATFORM_VARIANT),$(RD_N2_VARIANTS)))
+ $(error "CSS_SGI_PLATFORM_VARIANT for RD-N2 should be 0 or 1, currently set \
+ to ${CSS_SGI_PLATFORM_VARIANT}.")
+endif
diff --git a/plat/arm/rdinfra/rdn2/tests_to_skip.txt b/plat/arm/rdinfra/rdn2/tests_to_skip.txt
new file mode 100644
index 00000000..370f2b7e
--- /dev/null
+++ b/plat/arm/rdinfra/rdn2/tests_to_skip.txt
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# System suspend is not supported as there are no wakeup sources in RD-N2 FVP
+PSCI STAT/Stats test cases after system suspend
+PSCI System Suspend Validation
+
+# The following test cases result in unhandled exception at EL3
+CPU extensions/Use trace buffer control Registers
+CPU extensions/Use trace filter control Registers
diff --git a/plat/arm/rdinfra/rdn2/topology.c b/plat/arm/rdinfra/rdn2/topology.c
new file mode 100644
index 00000000..6918638c
--- /dev/null
+++ b/plat/arm/rdinfra/rdn2/topology.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <plat_topology.h>
+#include <tftf_lib.h>
+
+static const struct {
+ unsigned int cluster_id;
+ unsigned int cpu_id;
+} plat_cores[] = {
+ /* Cluster0: 1 core */
+ { 0, 0 },
+ /* Cluster1: 1 core */
+ { 1, 0 },
+ /* Cluster2: 1 core */
+ { 2, 0 },
+ /* Cluster3: 1 core */
+ { 3, 0 },
+ /* Cluster4: 1 core */
+ { 4, 0 },
+ /* Cluster5: 1 core */
+ { 5, 0 },
+ /* Cluster6: 1 core */
+ { 6, 0 },
+ /* Cluster7: 1 core */
+ { 7, 0 },
+#if (CSS_SGI_PLATFORM_VARIANT == 0)
+ /* Cluster8: 1 core */
+ { 8, 0 },
+ /* Cluster9: 1 core */
+ { 9, 0 },
+ /* Cluster10: 1 core */
+ { 10, 0 },
+ /* Cluster11: 1 core */
+ { 11, 0 },
+ /* Cluster12: 1 core */
+ { 12, 0 },
+ /* Cluster13: 1 core */
+ { 13, 0 },
+ /* Cluster14: 1 core */
+ { 14, 0 },
+ /* Cluster15: 1 core */
+ { 15, 0 },
+#endif
+};
+
+/*
+ * The power domain tree descriptor. The cluster power domains are
+ * arranged so that when the PSCI generic code creates the power domain tree,
+ * the indices of the CPU power domain nodes it allocates match the linear
+ * indices returned by plat_core_pos_by_mpidr().
+ */
+const unsigned char plat_pd_tree_desc[] = {
+ /* Number of root nodes */
+ PLAT_ARM_CLUSTER_COUNT,
+ /* Number of children for the 1st node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 2nd node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 3rd node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 4th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 5th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 6th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 7th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 8th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#if (CSS_SGI_PLATFORM_VARIANT == 0)
+ /* Number of children for the 9th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 10th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 11th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 12th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 13th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 14th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 15th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 16th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER
+#endif
+};
+
+const unsigned char *tftf_plat_get_pwr_domain_tree_desc(void)
+{
+ return plat_pd_tree_desc;
+}
+
+uint64_t tftf_plat_get_mpidr(unsigned int core_pos)
+{
+ unsigned int mpid;
+
+ assert(core_pos < PLATFORM_CORE_COUNT);
+
+ mpid = make_mpid(plat_cores[core_pos].cluster_id,
+ plat_cores[core_pos].cpu_id);
+
+ return (uint64_t)mpid;
+}
diff --git a/plat/arm/rdinfra/rdv1/include/platform_def.h b/plat/arm/rdinfra/rdv1/include/platform_def.h
new file mode 100644
index 00000000..7869551f
--- /dev/null
+++ b/plat/arm/rdinfra/rdv1/include/platform_def.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <sgi_soc_platform_def.h>
+
+#define PLAT_ARM_CLUSTER_COUNT U(16)
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER U(1)
+#define CSS_SGI_MAX_PE_PER_CPU U(1)
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE UL(0x30000000)
+#define PLAT_ARM_GICR_BASE UL(0x30140000)
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+
+/* Platform specific page table and MMU setup constants */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 42)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 42)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/rdinfra/rdv1/platform.mk b/plat/arm/rdinfra/rdv1/platform.mk
new file mode 100644
index 00000000..8001ec54
--- /dev/null
+++ b/plat/arm/rdinfra/rdv1/platform.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include plat/arm/sgi/common/sgi_common.mk
+
+PLAT_INCLUDES += -Iplat/arm/rdinfra/rdv1/include/
+
+PLAT_SOURCES += plat/arm/rdinfra/rdv1/topology.c
+
+PLAT_TESTS_SKIP_LIST := plat/arm/rdinfra/rdv1/tests_to_skip.txt
+
+ifdef CSS_SGI_PLATFORM_VARIANT
+$(error "CSS_SGI_PLATFORM_VARIANT should not be set for RD-V1, \
+ currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+endif
diff --git a/plat/arm/rdinfra/rdv1/tests_to_skip.txt b/plat/arm/rdinfra/rdv1/tests_to_skip.txt
new file mode 100644
index 00000000..25e34147
--- /dev/null
+++ b/plat/arm/rdinfra/rdv1/tests_to_skip.txt
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# System suspend is not supported as there are no wakeup sources in RD-V1 FVP
+PSCI STAT/Stats test cases after system suspend
+PSCI System Suspend Validation
+
+# The following tests hang during the test execution
+Timer framework Validation/Stress test the timer framework
+PSCI Affinity Info/Affinity info level0 powerdown
+PSCI CPU Suspend/CPU suspend to powerdown at level 0
+PSCI CPU Suspend/CPU suspend to powerdown at level 1
+
+# The following tests are not supported on RD-V1
+CPU extensions/Use trace buffer control Registers
+CPU extensions/Use trace filter control Registers
diff --git a/plat/arm/rdinfra/rdv1/topology.c b/plat/arm/rdinfra/rdv1/topology.c
new file mode 100644
index 00000000..ad132851
--- /dev/null
+++ b/plat/arm/rdinfra/rdv1/topology.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <plat_topology.h>
+#include <tftf_lib.h>
+
+static const struct {
+ unsigned int cluster_id;
+ unsigned int cpu_id;
+} plat_cores[] = {
+ /* Cluster0: 1 core */
+ { 0, 0 },
+ /* Cluster1: 1 core */
+ { 1, 0 },
+ /* Cluster2: 1 core */
+ { 2, 0 },
+ /* Cluster3: 1 core */
+ { 3, 0 },
+ /* Cluster4: 1 core */
+ { 4, 0 },
+ /* Cluster5: 1 core */
+ { 5, 0 },
+ /* Cluster6: 1 core */
+ { 6, 0 },
+ /* Cluster7: 1 core */
+ { 7, 0 },
+ /* Cluster8: 1 core */
+ { 8, 0 },
+ /* Cluster9: 1 core */
+ { 9, 0 },
+ /* Cluster10: 1 core */
+ { 10, 0 },
+ /* Cluster11: 1 core */
+ { 11, 0 },
+ /* Cluster12: 1 core */
+ { 12, 0 },
+ /* Cluster13: 1 core */
+ { 13, 0 },
+ /* Cluster14: 1 core */
+ { 14, 0 },
+ /* Cluster15: 1 core */
+ { 15, 0 },
+};
+
+/*
+ * The power domain tree descriptor. The cluster power domains are
+ * arranged so that when the PSCI generic code creates the power domain tree,
+ * the indices of the CPU power domain nodes it allocates match the linear
+ * indices returned by plat_core_pos_by_mpidr().
+ */
+const unsigned char plat_pd_tree_desc[] = {
+ /* Number of root nodes */
+ PLAT_ARM_CLUSTER_COUNT,
+ /* Number of children for the 1st node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 2nd node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 3rd node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 4th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 5th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 6th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 7th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 8th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 9th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 10th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 11th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 12th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 13th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 14th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 15th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ /* Number of children for the 16th node */
+ CSS_SGI_MAX_CPUS_PER_CLUSTER
+};
+
+const unsigned char *tftf_plat_get_pwr_domain_tree_desc(void)
+{
+ return plat_pd_tree_desc;
+}
+
+uint64_t tftf_plat_get_mpidr(unsigned int core_pos)
+{
+ unsigned int mpid;
+
+ assert(core_pos < PLATFORM_CORE_COUNT);
+
+ mpid = make_mpid(plat_cores[core_pos].cluster_id,
+ plat_cores[core_pos].cpu_id);
+
+ return (uint64_t)mpid;
+}
diff --git a/plat/arm/sgi/common/aarch64/plat_helpers.S b/plat/arm/sgi/common/aarch64/plat_helpers.S
index 9fe2ba96..e17c5096 100644
--- a/plat/arm/sgi/common/aarch64/plat_helpers.S
+++ b/plat/arm/sgi/common/aarch64/plat_helpers.S
@@ -18,13 +18,13 @@
*
* Function to calculate the core position on sgi platforms.
*
- * (ClusterId * SGI_MAX_CPUS_PER_CLUSTER * SGI_MAX_PE_PER_CPU) +
- * (CPUId * SGI_MAX_PE_PER_CPU) +
+ * (ClusterId * CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU) +
+ * (CPUId * CSS_SGI_MAX_PE_PER_CPU) +
* ThreadId
*
* which can be simplified as:
*
- * ((ClusterId * SGI_MAX_CPUS_PER_CLUSTER + CPUId) * SGI_MAX_PE_PER_CPU)
+ * ((ClusterId * CSS_SGI_MAX_CPUS_PER_CLUSTER + CPUId) * CSS_SGI_MAX_PE_PER_CPU)
* + ThreadId
* ---------------------------------------------------------------------
*/
@@ -43,9 +43,9 @@ func platform_get_core_pos
ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
/* Compute linear position */
- mov x3, #SGI_MAX_CPUS_PER_CLUSTER
+ mov x3, #CSS_SGI_MAX_CPUS_PER_CLUSTER
madd x1, x2, x3, x1
- mov x3, #SGI_MAX_PE_PER_CPU
+ mov x3, #CSS_SGI_MAX_PE_PER_CPU
madd x0, x1, x3, x0
ret
endfunc platform_get_core_pos
diff --git a/plat/arm/sgi/common/include/sgi_base_platform_def.h b/plat/arm/sgi/common/include/sgi_base_platform_def.h
index 8e025ab9..10d1841a 100644
--- a/plat/arm/sgi/common/include/sgi_base_platform_def.h
+++ b/plat/arm/sgi/common/include/sgi_base_platform_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,35 +7,52 @@
#ifndef SGI_BASE_PLATFORM_DEF_H
#define SGI_BASE_PLATFORM_DEF_H
+#include <lib/utils_def.h>
+
/* Platform binary types for linking */
#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
#define PLATFORM_LINKER_ARCH aarch64
-/*******************************************************************************
- * Run-time address of the TFTF image.
- * It has to match the location where the Trusted Firmware-A loads the BL33
- * image.
- ******************************************************************************/
-#define TFTF_BASE 0xE0000000
+/* Sub-system Peripherals */
+#define SGI_DEVICE0_BASE UL(0x2A000000)
+#define SGI_DEVICE0_SIZE UL(0x26000000)
-#define SGI_DRAM1_BASE 0x80000000
-#define SGI_DRAM1_SIZE 0x80000000
-#define DRAM_BASE SGI_DRAM1_BASE
+/* Peripherals and PCIe expansion area */
+#define SGI_DEVICE1_BASE UL(0x60000000)
+#define SGI_DEVICE1_SIZE UL(0x20000000)
-/* TF-A reserves DRAM space 0xFF000000- 0xFFFFFFFF for TZC */
-#define DRAM_SIZE (SGI_DRAM1_SIZE - 0x1000000)
+/* AP Non-Secure UART related constants */
+#define SGI_CSS_NSEC_UART_BASE UL(0x2A400000)
+#define SGI_CSS_NSEC_CLK_IN_HZ 7372800
+
+#define PLAT_ARM_UART_BASE SGI_CSS_NSEC_UART_BASE
+#define PLAT_ARM_UART_CLK_IN_HZ SGI_CSS_NSEC_CLK_IN_HZ
+
+/* Base address of trusted watchdog (SP805) */
+#define SP805_TWDOG_BASE UL(0x2A480000)
/* Memory mapped Generic timer interfaces */
-#define SYS_CNT_BASE1 0x2A830000
+#define SYS_CNT_BASE1 UL(0x2A830000)
-/* Base address of non-trusted watchdog (SP805) */
-#define SP805_WDOG_BASE 0x1C0F0000
+/* DRAM base address and size */
+#define PLAT_ARM_DRAM1_BASE UL(0x80000000)
+#define PLAT_ARM_DRAM1_SIZE UL(0x80000000)
+#define DRAM_BASE PLAT_ARM_DRAM1_BASE
+
+/* TF-A reserves DRAM space 0xFF000000- 0xFFFFFFFF for TZC */
+#define DRAM_SIZE (PLAT_ARM_DRAM1_SIZE - 0x1000000)
/* Base address and size of external NVM flash */
-#define FLASH_BASE 0x08000000
+#define FLASH_BASE UL(0x08000000)
+#define FLASH_SIZE UL(0x04000000) /* 64MB */
+#define NOR_FLASH_BLOCK_SIZE UL(0x40000) /* 256KB */
-#define NOR_FLASH_BLOCK_SIZE 0x40000 /* 256KB */
-#define FLASH_SIZE 0x4000000 /* 64MB */
+/*******************************************************************************
+ * Run-time address of the TFTF image.
+ * It has to match the location where the Trusted Firmware-A loads the BL33
+ * image.
+ ******************************************************************************/
+#define TFTF_BASE UL(0xE0000000)
/*
* If you want to use DRAM for non-volatile memory then the first 128MB
@@ -43,27 +60,7 @@
* suitable since the state will be lost.
*/
#define TFTF_NVM_OFFSET 0x0
-#define TFTF_NVM_SIZE 0x8000000 /* 128 MB */
-
-/* Sub-system Peripherals */
-#define SGI_DEVICE0_BASE 0x2A000000
-#define SGI_DEVICE0_SIZE 0x26000000
-
-/* Following covers Peripherals and PCIe expansion area */
-#define SGI_DEVICE1_BASE 0x60000000
-#define SGI_DEVICE1_SIZE 0x20000000
-
-/* GIC-600 & interrupt handling related constants */
-#define SGI_GICD_BASE 0x30000000
-#define SGI_GICR_BASE 0x300C0000
-#define SGI_GICC_BASE 0x2C000000
-
-/* SoC's PL011 UART0 related constants */
-#define SGI_PL011_UART0_BASE 0x7FF80000
-#define SGI_PL011_UART0_CLK_IN_HZ 7372800
-
-#define PLAT_ARM_UART_BASE SGI_PL011_UART0_BASE
-#define PLAT_ARM_UART_CLK_IN_HZ SGI_PL011_UART0_CLK_IN_HZ
+#define TFTF_NVM_SIZE UL(0x08000000) /* 128 MB */
/* Size of cacheable stacks */
#define PLATFORM_STACK_SIZE 0x1400
@@ -71,23 +68,18 @@
/* Size of coherent stacks */
#define PCPU_DV_MEM_STACK_SIZE 0x600
-#define PLATFORM_CORE_COUNT (SGI_CLUSTER_COUNT * SGI_MAX_CPUS_PER_CLUSTER)
-#define PLATFORM_NUM_AFFS (SGI_CLUSTER_COUNT + PLATFORM_CORE_COUNT)
+#define PLATFORM_CORE_COUNT (PLAT_ARM_CLUSTER_COUNT * \
+ CSS_SGI_MAX_CPUS_PER_CLUSTER)
+#define PLATFORM_NUM_AFFS (PLAT_ARM_CLUSTER_COUNT + PLATFORM_CORE_COUNT)
#define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL1
#define PLAT_MAX_PWR_LEVEL PLATFORM_MAX_AFFLVL
#define PLAT_MAX_PWR_STATES_PER_LVL 2
-/* I/O Storage NOR flash device */
-#define MAX_IO_DEVICES 1
-#define MAX_IO_HANDLES 1
-
/* Local state bit width for each level in the state-ID field of power state */
#define PLAT_LOCAL_PSTATE_WIDTH 4
/* Platform specific page table and MMU setup constants */
-#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32)
-#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32)
#define MAX_XLAT_TABLES 5
#define MAX_MMAP_REGIONS 16
@@ -96,24 +88,22 @@
* This is known only to the platform as it might have a combination of
* integrated and external caches.
******************************************************************************/
-#define CACHE_WRITEBACK_SHIFT 6
-#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+#define CACHE_WRITEBACK_SHIFT 6
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+/* Times(in ms) used by test code for completion of different events */
+#define PLAT_SUSPEND_ENTRY_TIME 15
+#define PLAT_SUSPEND_ENTRY_EXIT_TIME 30
+
+/* I/O Storage NOR flash device */
+#define MAX_IO_DEVICES 1
+#define MAX_IO_HANDLES 1
/* Non-Secure Software Generated Interupts IDs */
#define IRQ_NS_SGI_0 0
#define IRQ_NS_SGI_7 7
-/* AP UART1 interrupt is considered as the maximum SPI */
-#define PLAT_MAX_SPI_OFFSET_ID 64
-
-/* AP_REFCLK Generic Timer, Non-secure. */
-#define IRQ_CNTPSIRQ1 92
-
/* Per-CPU Hypervisor Timer Interrupt ID */
#define IRQ_PCPU_HP_TIMER 26
-/* Times(in ms) used by test code for completion of different events */
-#define PLAT_SUSPEND_ENTRY_TIME 15
-#define PLAT_SUSPEND_ENTRY_EXIT_TIME 30
-
#endif /* SGI_BASE_PLATFORM_DEF_H */
diff --git a/plat/arm/sgi/common/include/sgi_soc_css_def.h b/plat/arm/sgi/common/include/sgi_soc_css_def.h
new file mode 100644
index 00000000..da73b3e2
--- /dev/null
+++ b/plat/arm/sgi/common/include/sgi_soc_css_def.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_SOC_CSS_DEF_H
+#define SGI_SOC_CSS_DEF_H
+
+/* Trusted watchdog (SP805) Interrupt ID */
+#define IRQ_TWDOG_INTID 86
+
+/* Maximum SPI */
+#define PLAT_MAX_SPI_OFFSET_ID 64
+
+/* AP_REFCLK Generic Timer, Non-secure. */
+#define IRQ_CNTPSIRQ1 92
+
+#endif /* SGI_SOC_CSS_DEF_H */
diff --git a/plat/arm/sgi/common/include/sgi_soc_css_def_v2.h b/plat/arm/sgi/common/include/sgi_soc_css_def_v2.h
new file mode 100644
index 00000000..e834386f
--- /dev/null
+++ b/plat/arm/sgi/common/include/sgi_soc_css_def_v2.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_SOC_CSS_DEF_V2_H
+#define SGI_SOC_CSS_DEF_V2_H
+
+/* Trusted watchdog (SP805) Interrupt ID */
+#define IRQ_TWDOG_INTID 107
+
+/* Maximum SPI */
+#define PLAT_MAX_SPI_OFFSET_ID 256
+
+/* AP_REFCLK Generic Timer, Non-secure. */
+#define IRQ_CNTPSIRQ1 109
+
+#endif /* SGI_SOC_CSS_DEF_V2_H */
+
diff --git a/plat/arm/sgi/common/include/sgi_soc_platform_def.h b/plat/arm/sgi/common/include/sgi_soc_platform_def.h
new file mode 100644
index 00000000..fc60999c
--- /dev/null
+++ b/plat/arm/sgi/common/include/sgi_soc_platform_def.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_SOC_PLATFORM_H
+#define SGI_SOC_PLATFORM_H
+
+#include <sgi_base_platform_def.h>
+#include <sgi_soc_css_def.h>
+
+/* Base address of non-trusted watchdog (SP805) */
+#define SP805_WDOG_BASE UL(0x1C0F0000)
+
+#endif /* SGI_SOC_PLATFORM_H */
diff --git a/plat/arm/sgi/common/include/sgi_soc_platform_def_v2.h b/plat/arm/sgi/common/include/sgi_soc_platform_def_v2.h
new file mode 100644
index 00000000..fad31ca2
--- /dev/null
+++ b/plat/arm/sgi/common/include/sgi_soc_platform_def_v2.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_SOC_PLATFORM_V2_H
+#define SGI_SOC_PLATFORM_V2_H
+
+#include <sgi_base_platform_def.h>
+#include <sgi_soc_css_def_v2.h>
+
+/* Base address of non-trusted watchdog (SP805) */
+#define SP805_WDOG_BASE UL(0x0C0F0000)
+
+#endif /* SGI_SOC_PLATFORM_V2_H */
diff --git a/plat/arm/sgi/common/plat_setup.c b/plat/arm/sgi/common/plat_setup.c
index 4b15f1a7..f343f8dc 100644
--- a/plat/arm/sgi/common/plat_setup.c
+++ b/plat/arm/sgi/common/plat_setup.c
@@ -24,5 +24,5 @@ const mmap_region_t *tftf_platform_get_mmap(void)
void plat_arm_gic_init(void)
{
- arm_gic_init(SGI_GICC_BASE, SGI_GICD_BASE, SGI_GICR_BASE);
+ arm_gic_init(PLAT_ARM_GICC_BASE, PLAT_ARM_GICD_BASE, PLAT_ARM_GICR_BASE);
}
diff --git a/plat/arm/sgi/common/sgi_common.mk b/plat/arm/sgi/common/sgi_common.mk
index f19445fb..45d8485c 100644
--- a/plat/arm/sgi/common/sgi_common.mk
+++ b/plat/arm/sgi/common/sgi_common.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2018, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -22,3 +22,6 @@ include plat/arm/common/arm_common.mk
ifeq (${USE_NVM},1)
$(error "USE_NVM is not supported on SGI platforms")
endif
+
+# Pass CSS_SGI_PLATFORM_VARIANT flag to the build system
+$(eval $(call add_define,TFTF_DEFINES,CSS_SGI_PLATFORM_VARIANT))
diff --git a/plat/arm/sgi/sgi575/include/platform_def.h b/plat/arm/sgi/sgi575/include/platform_def.h
index 3bceec3a..237978c4 100644
--- a/plat/arm/sgi/sgi575/include/platform_def.h
+++ b/plat/arm/sgi/sgi575/include/platform_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,10 +7,19 @@
#ifndef PLATFORM_DEF_H
#define PLATFORM_DEF_H
-#include <sgi_base_platform_def.h>
+#include <sgi_soc_platform_def.h>
-#define SGI_CLUSTER_COUNT 2
-#define SGI_MAX_CPUS_PER_CLUSTER 4
-#define SGI_MAX_PE_PER_CPU 1
+#define PLAT_ARM_CLUSTER_COUNT U(2)
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER U(4)
+#define CSS_SGI_MAX_PE_PER_CPU U(1)
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE UL(0x30000000)
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+#define PLAT_ARM_GICR_BASE UL(0x300C0000)
+
+/* Platform specific page table and MMU setup constants */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/sgi/sgi575/platform.mk b/plat/arm/sgi/sgi575/platform.mk
index 8472d7e0..7c8194fe 100644
--- a/plat/arm/sgi/sgi575/platform.mk
+++ b/plat/arm/sgi/sgi575/platform.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2018, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -11,3 +11,8 @@ PLAT_INCLUDES += -Iplat/arm/sgi/sgi575/include/
PLAT_SOURCES += plat/arm/sgi/sgi575/sgi575_topology.c
PLAT_TESTS_SKIP_LIST := plat/arm/sgi/sgi575/tests_to_skip.txt
+
+ifdef CSS_SGI_PLATFORM_VARIANT
+$(error "CSS_SGI_PLATFORM_VARIANT should not be set for SGI-575, \
+ currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+endif
diff --git a/plat/arm/sgi/sgi575/sgi575_topology.c b/plat/arm/sgi/sgi575/sgi575_topology.c
index bda06d3f..c01ad83a 100644
--- a/plat/arm/sgi/sgi575/sgi575_topology.c
+++ b/plat/arm/sgi/sgi575/sgi575_topology.c
@@ -32,11 +32,11 @@ static const struct {
*/
const unsigned char sgi575_pd_tree_desc[] = {
/* Number of root nodes */
- SGI_CLUSTER_COUNT,
+ PLAT_ARM_CLUSTER_COUNT,
/* Number of children for the 1st node */
- SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
/* Number of children for the 2nd node */
- SGI_MAX_CPUS_PER_CLUSTER
+ CSS_SGI_MAX_CPUS_PER_CLUSTER
};
const unsigned char *tftf_plat_get_pwr_domain_tree_desc(void)
diff --git a/plat/arm/tc0/include/platform_def.h b/plat/arm/tc0/include/platform_def.h
index acdf370d..2fa17e63 100644
--- a/plat/arm/tc0/include/platform_def.h
+++ b/plat/arm/tc0/include/platform_def.h
@@ -48,6 +48,10 @@
/* Base address of non-trusted watchdog (SP805) */
#define SP805_WDOG_BASE 0x1C0F0000
+/* Base address of trusted watchdog (SP805) */
+#define SP805_TWDOG_BASE 0x2A480000
+#define IRQ_TWDOG_INTID 86
+
/* Base address and size of external NVM flash */
#define FLASH_BASE 0x08000000
@@ -72,7 +76,7 @@
/* GIC-600 & interrupt handling related constants */
#define TC0_GICD_BASE 0x30000000
-#define TC0_GICR_BASE 0x30140000
+#define TC0_GICR_BASE 0x30080000
#define TC0_GICC_BASE 0x2C000000
/* SoC's PL011 UART0 related constants */
@@ -109,7 +113,12 @@
/* Platform specific page table and MMU setup constants */
#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 36)
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 36)
+
+#if IMAGE_CACTUS
+#define MAX_XLAT_TABLES 6
+#else
#define MAX_XLAT_TABLES 5
+#endif
#define MAX_MMAP_REGIONS 16
/*******************************************************************************
diff --git a/plat/arm/tc0/platform.mk b/plat/arm/tc0/platform.mk
index faf0d195..1cfe9eea 100644
--- a/plat/arm/tc0/platform.mk
+++ b/plat/arm/tc0/platform.mk
@@ -32,6 +32,7 @@ PLAT_SOURCES := drivers/arm/gic/arm_gic_v2v3.c \
plat/arm/tc0/tc0_topology.c
CACTUS_SOURCES += plat/arm/tc0/${ARCH}/plat_helpers.S
+IVY_SOURCES += plat/arm/tc0/${ARCH}/plat_helpers.S
PLAT_TESTS_SKIP_LIST := plat/arm/tc0/tests_to_skip.txt
diff --git a/plat/arm/tc0/tests_to_skip.txt b/plat/arm/tc0/tests_to_skip.txt
index f039eeda..5830c142 100644
--- a/plat/arm/tc0/tests_to_skip.txt
+++ b/plat/arm/tc0/tests_to_skip.txt
@@ -4,9 +4,12 @@
# SPDX-License-Identifier: BSD-3-Clause
#
-# System suspend is not supported as there are no wakeup sources in tc0 FVP
+# Disable SMMUv3 tests
+SMMUv3 tests
# PSCI is enabled but not tested
PSCI STAT/Stats test cases after system suspend
PSCI System Suspend Validation
-PSCI NODE_HW_STATE
+
+# Disable FF-A Interrupt tests as TWDOG is not supported by TC platform
+FF-A Interrupt
diff --git a/plat/nvidia/tegra186/include/platform_def.h b/plat/nvidia/tegra186/include/platform_def.h
index d21d83c0..8ad93ad8 100644
--- a/plat/nvidia/tegra186/include/platform_def.h
+++ b/plat/nvidia/tegra186/include/platform_def.h
@@ -124,6 +124,7 @@
* IRQ value for Tegra Timer0
******************************************************************************/
#define TEGRA_RTC_IRQ U(42)
+#define IRQ_TWDOG_INTID TEGRA_RTC_IRQ
/*******************************************************************************
* Platform specific page table and MMU setup constants
diff --git a/plat/nvidia/tegra194/include/platform_def.h b/plat/nvidia/tegra194/include/platform_def.h
index 9b27da3d..0cd3ecda 100644
--- a/plat/nvidia/tegra194/include/platform_def.h
+++ b/plat/nvidia/tegra194/include/platform_def.h
@@ -125,6 +125,7 @@
* IRQ value for Tegra Timer0
******************************************************************************/
#define TEGRA_RTC_IRQ U(42)
+#define IRQ_TWDOG_INTID TEGRA_RTC_IRQ
/*******************************************************************************
* Platform specific page table and MMU setup constants
diff --git a/plat/nvidia/tegra210/include/platform_def.h b/plat/nvidia/tegra210/include/platform_def.h
index f629053d..0e369b36 100644
--- a/plat/nvidia/tegra210/include/platform_def.h
+++ b/plat/nvidia/tegra210/include/platform_def.h
@@ -123,6 +123,7 @@
* IRQ value for Tegra RTC
******************************************************************************/
#define TEGRA_RTC_IRQ U(34)
+#define IRQ_TWDOG_INTID TEGRA_RTC_IRQ
/*******************************************************************************
* Platform specific page table and MMU setup constants
diff --git a/smc_fuzz/src/randsmcmod.c b/smc_fuzz/src/randsmcmod.c
index 2b8d0172..bbd5edfe 100644
--- a/smc_fuzz/src/randsmcmod.c
+++ b/smc_fuzz/src/randsmcmod.c
@@ -470,9 +470,9 @@ void runtestfunction(char *funcstr)
}
/*
- * Top of SMC fuzzing module
+ * Function executes a single SMC fuzz test instance with a supplied seed.
*/
-test_result_t smc_fuzzing_top(void)
+test_result_t smc_fuzzing_instance(uint32_t seed)
{
/*
* Setting up malloc block parameters
@@ -508,9 +508,9 @@ test_result_t smc_fuzzing_top(void)
}
/*
- * Hard coded seed, will change in the near future for better strategy
+ * Initialize pseudo random number generator with supplied seed.
*/
- srand(89758389);
+ srand(seed);
/*
* Code to traverse the bias tree and select function based on the biaes within
@@ -532,7 +532,7 @@ test_result_t smc_fuzzing_top(void)
* another loop to continue the process of selection until an eventual leaf
* node is found.
*/
- for (unsigned int i = 0U; i < 100U; i++) {
+ for (unsigned int i = 0U; i < SMC_FUZZ_CALLS_PER_INSTANCE; i++) {
tlnode = &ndarray[cntndarray - 1];
int nd = 0;
while (nd == 0) {
@@ -568,3 +568,59 @@ test_result_t smc_fuzzing_top(void)
return TEST_RESULT_SUCCESS;
}
+
+/*
+ * Top of SMC fuzzing module
+ */
+test_result_t smc_fuzzing_top(void)
+{
+ /* These SMC_FUZZ_x macros are supplied by the build system. */
+ test_result_t results[SMC_FUZZ_INSTANCE_COUNT];
+ uint32_t seeds[SMC_FUZZ_INSTANCE_COUNT] = {SMC_FUZZ_SEEDS};
+ test_result_t result = TEST_RESULT_SUCCESS;
+ unsigned int i;
+
+ /* Run each instance. */
+ for (i = 0U; i < SMC_FUZZ_INSTANCE_COUNT; i++) {
+ printf("Starting SMC fuzz test with seed 0x%x\n", seeds[i]);
+ results[i] = smc_fuzzing_instance(seeds[i]);
+ }
+
+ /* Report successes and failures. */
+ printf("SMC Fuzz Test Results Summary\n");
+ for (i = 0U; i < SMC_FUZZ_INSTANCE_COUNT; i++) {
+ /* Display instance number. */
+ printf(" Instance #%d\n", i);
+
+ /* Print test results. */
+ printf(" Result: ");
+ if (results[i] == TEST_RESULT_SUCCESS) {
+ printf("SUCCESS\n");
+ } else if (results[i] == TEST_RESULT_FAIL) {
+ printf("FAIL\n");
+ /* If we got a failure, update the result value. */
+ result = TEST_RESULT_FAIL;
+ } else if (results[i] == TEST_RESULT_SKIPPED) {
+ printf("SKIPPED\n");
+ }
+
+ /* Print seed used */
+ printf(" Seed: 0x%x\n", seeds[i]);
+ }
+
+ /*
+ * Print out the smc fuzzer parameters so this test can be replicated.
+ */
+ printf("SMC fuzz build parameters to recreate this test:\n");
+ printf(" SMC_FUZZ_INSTANCE_COUNT=%u\n",
+ SMC_FUZZ_INSTANCE_COUNT);
+ printf(" SMC_FUZZ_CALLS_PER_INSTANCE=%u\n",
+ SMC_FUZZ_CALLS_PER_INSTANCE);
+ printf(" SMC_FUZZ_SEEDS=0x%x", seeds[0]);
+ for (i = 1U; i < SMC_FUZZ_INSTANCE_COUNT; i++) {
+ printf(",0x%x", seeds[i]);
+ }
+ printf("\n");
+
+ return result;
+}
diff --git a/spm/cactus/aarch64/cactus_entrypoint.S b/spm/cactus/aarch64/cactus_entrypoint.S
index 15410633..6eff65ea 100644
--- a/spm/cactus/aarch64/cactus_entrypoint.S
+++ b/spm/cactus/aarch64/cactus_entrypoint.S
@@ -1,13 +1,12 @@
/*
- * Copyright (c) 2017-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
-#include <cactus_def.h>
-#include <cactus_platform_def.h>
+#include <sp_def.h>
.globl cactus_entrypoint
.globl secondary_cold_entry
@@ -15,20 +14,30 @@
/* Provision one stack per Execution Context (or vCPU) */
.section .bss.stacks
.balign CACHE_WRITEBACK_GRANULE
- .fill CACTUS_STACKS_SIZE * PLAT_CACTUS_CORE_COUNT
+ .fill SP_STACKS_SIZE * PLAT_SP_CORE_COUNT
stacks_end:
func cactus_entrypoint
/* Entry reason is primary EC cold boot */
mov x19, #1
secondary_cold_entry:
+ /*
+ * x0 holds a pointer to the Boot Information Blob.
+ * Save it for later usage.
+ */
+ mov x20, x0
+
+ /* Get the vMPIDR. The SPMC passes the vCPU linear id in lower bits. */
+ mrs x0, mpidr_el1
+ bic x0, x0, #0x80000000
+
/* Entry reason is secondary EC cold boot */
mrs x0, mpidr_el1
bl platform_get_core_pos
/* Setup the stack pointer. */
adr x1, stacks_end
- mov x2, #CACTUS_STACKS_SIZE
+ mov x2, #SP_STACKS_SIZE
mul x2, x0, x2
sub sp, x1, x2
@@ -71,11 +80,17 @@ secondary_cold_entry:
pie_fixup:
ldr x0, =pie_fixup
and x0, x0, #~(0x1000 - 1)
- mov x1, #CACTUS_IMAGE_SIZE
+ mov x1, #SP_IMAGE_SIZE
add x1, x1, x0
bl fixup_gdt_reloc
- /* Jump to the C entrypoint (it does not return) */
+ /*
+ * Jump to the C entrypoint (it does not return).
+ * Pass the cold boot reason and BIB address.
+ */
0: mov x0, x19
+ mov x1, x20
+
+ /* And jump to the C entrypoint. */
b cactus_main
endfunc cactus_entrypoint
diff --git a/spm/cactus/aarch64/cactus_exceptions.S b/spm/cactus/aarch64/cactus_exceptions.S
index 31cdbf9a..9b024f85 100644
--- a/spm/cactus/aarch64/cactus_exceptions.S
+++ b/spm/cactus/aarch64/cactus_exceptions.S
@@ -31,14 +31,16 @@ unhandled_exception serr_sp0
/*
* Current EL with SPx : 0x200 - 0x400.
*/
-unhandled_exception sync_spx
+vector_entry sync_spx
+ b sync_exception_vector_entry
+end_vector_entry sync_spx
vector_entry irq_spx
- b irq_vector_entry
+ b interrupt_vector_entry
end_vector_entry irq_spx
vector_entry fiq_spx
- b fiq_vector_entry
+ b interrupt_vector_entry
end_vector_entry fiq_spx
unhandled_exception serr_spx
@@ -98,23 +100,30 @@ unhandled_exception serr_a32
ldp x0, x1, [sp, #0x0]
.endm
-func irq_vector_entry
+func sync_exception_vector_entry
sub sp, sp, #0x100
save_gp_regs
- bl cactus_irq_handler
- restore_gp_regs
+ mov x19, sp
+ bl tftf_sync_exception_handler
+ cbnz x0, 0f
+ mov x0, x19
+ /* Save original stack pointer value on the stack */
+ add x1, x0, #0x100
+ str x1, [x0, #0xf8]
+ b print_exception
+0: restore_gp_regs
add sp, sp, #0x100
eret
-endfunc irq_vector_entry
+endfunc sync_exception_vector_entry
-func fiq_vector_entry
+func interrupt_vector_entry
sub sp, sp, #0x100
save_gp_regs
- bl cactus_fiq_handler
+ bl cactus_interrupt_handler
restore_gp_regs
add sp, sp, #0x100
eret
-endfunc fiq_vector_entry
+endfunc interrupt_vector_entry
func crash_dump
/* Save general-purpose registers on the stack. */
diff --git a/spm/cactus/cactus.h b/spm/cactus/cactus.h
index cbf2dcb2..c7176c27 100644
--- a/spm/cactus/cactus.h
+++ b/spm/cactus/cactus.h
@@ -26,11 +26,4 @@ extern uintptr_t __BSS_START__, __BSS_END__;
#define CACTUS_BSS_START ((uintptr_t)&__BSS_START__)
#define CACTUS_BSS_END ((uintptr_t)&__BSS_END__)
-enum stdout_route {
- PL011_AS_STDOUT = 0,
- HVC_CALL_AS_STDOUT,
-};
-
-void set_putc_impl(enum stdout_route);
-
#endif /* __CACTUS_H__ */
diff --git a/spm/cactus/cactus.ld.S b/spm/cactus/cactus.ld.S
index 50fc576e..afd72cbc 100644
--- a/spm/cactus/cactus.ld.S
+++ b/spm/cactus/cactus.ld.S
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2017-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <cactus_def.h>
+#include <sp_def.h>
#include <platform_def.h>
#include <xlat_tables_defs.h>
@@ -14,7 +14,7 @@ ENTRY(cactus_entrypoint)
SECTIONS
{
- . = CACTUS_IMAGE_BASE;
+ . = SP_IMAGE_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"TEXT_START address is not aligned to PAGE_SIZE.")
diff --git a/spm/cactus/cactus.mk b/spm/cactus/cactus.mk
index ae66c1de..c3bbe594 100644
--- a/spm/cactus/cactus.mk
+++ b/spm/cactus/cactus.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -13,7 +13,8 @@ ifneq (${CACTUS_PLAT_PATH},)
include ${CACTUS_PLAT_PATH}/platform.mk
endif
-CACTUS_DTB := $(BUILD_PLAT)/cactus.dtb
+CACTUS_DTB := $(BUILD_PLAT)/cactus.dtb
+SECURE_PARTITIONS += cactus
CACTUS_INCLUDES := \
-Itftf/framework/include \
@@ -27,45 +28,51 @@ CACTUS_INCLUDES := \
-Iinclude/plat/common \
-Iinclude/runtime_services \
-Ispm/cactus \
- -Ispm/common
+ -Ispm/common \
+ -Ispm/common/sp_tests
CACTUS_SOURCES := \
$(addprefix spm/cactus/, \
aarch64/cactus_entrypoint.S \
aarch64/cactus_exceptions.S \
- cactus_debug.c \
cactus_interrupt.c \
cactus_main.c \
) \
$(addprefix spm/common/, \
- aarch64/sp_arch_helpers.S \
+ sp_debug.c \
sp_helpers.c \
- spm_helpers.c \
+ spm_helpers.c \
+ ) \
+ $(addprefix spm/common/sp_tests/, \
+ sp_test_ffa.c \
) \
$(addprefix spm/cactus/cactus_tests/, \
cactus_message_loop.c \
cactus_test_cpu_features.c \
cactus_test_direct_messaging.c \
- cactus_test_ffa.c \
cactus_test_interrupts.c \
cactus_test_memory_sharing.c \
cactus_tests_smmuv3.c \
+ cactus_test_notifications.c \
)
# TODO: Remove dependency on TFTF files.
-CACTUS_SOURCES += \
- tftf/framework/debug.c \
- tftf/framework/${ARCH}/asm_debug.S \
- tftf/tests/runtime_services/secure_service/ffa_helpers.c \
- tftf/tests/runtime_services/secure_service/spm_common.c \
+CACTUS_SOURCES += \
+ tftf/framework/debug.c \
+ tftf/framework/${ARCH}/asm_debug.S \
+ tftf/tests/runtime_services/secure_service/${ARCH}/ffa_arch_helpers.S \
+ tftf/tests/runtime_services/secure_service/ffa_helpers.c \
+ tftf/tests/runtime_services/secure_service/spm_common.c \
tftf/framework/${ARCH}/exception_report.c
CACTUS_SOURCES += drivers/arm/pl011/${ARCH}/pl011_console.S \
+ drivers/arm/sp805/sp805.c \
lib/${ARCH}/cache_helpers.S \
lib/${ARCH}/misc_helpers.S \
lib/smc/${ARCH}/asm_smc.S \
lib/smc/${ARCH}/smc.c \
lib/smc/${ARCH}/hvc.c \
+ lib/exceptions/${ARCH}/sync.c \
lib/locks/${ARCH}/spinlock.S \
lib/utils/mp_printf.c \
${XLAT_TABLES_LIB_SRCS}
@@ -80,9 +87,6 @@ $(eval $(call add_define,CACTUS_DEFINES,DEBUG))
$(eval $(call add_define,CACTUS_DEFINES,ENABLE_ASSERTIONS))
$(eval $(call add_define,CACTUS_DEFINES,ENABLE_BTI))
$(eval $(call add_define,CACTUS_DEFINES,ENABLE_PAUTH))
-$(eval $(call add_define,CACTUS_DEFINES,FVP_CLUSTER_COUNT))
-$(eval $(call add_define,CACTUS_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
-$(eval $(call add_define,CACTUS_DEFINES,FVP_MAX_PE_PER_CPU))
$(eval $(call add_define,CACTUS_DEFINES,LOG_LEVEL))
$(eval $(call add_define,CACTUS_DEFINES,PLAT_${PLAT}))
$(eval $(call add_define,CACTUS_DEFINES,PLAT_XLAT_TABLES_DYNAMIC))
@@ -91,14 +95,12 @@ $(CACTUS_DTB) : $(BUILD_PLAT)/cactus $(BUILD_PLAT)/cactus/cactus.elf
$(CACTUS_DTB) : $(CACTUS_DTS)
@echo " DTBGEN $@"
${Q}tools/generate_dtb/generate_dtb.sh \
- cactus ${CACTUS_DTS} $(BUILD_PLAT)
- ${Q}tools/generate_json/generate_json.sh \
- cactus $(BUILD_PLAT)
+ cactus ${CACTUS_DTS} $(BUILD_PLAT) $(CACTUS_DTB)
@echo
@echo "Built $@ successfully"
@echo
-cactus: $(CACTUS_DTB)
+cactus: $(CACTUS_DTB) SP_LAYOUT
# FDTS_CP copies flattened device tree sources
# $(1) = output directory
diff --git a/spm/cactus/cactus_def.h b/spm/cactus/cactus_def.h
deleted file mode 100644
index 190f0631..00000000
--- a/spm/cactus/cactus_def.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef CACTUS_DEF_H
-#define CACTUS_DEF_H
-
-#include <utils_def.h>
-
-/*
- * Layout of the Secure Partition image.
- */
-
-/* Up to 2 MiB at an arbitrary address that doesn't overlap the devices. */
-#define CACTUS_IMAGE_BASE ULL(0x1000)
-#define CACTUS_IMAGE_SIZE ULL(0x200000)
-
-/* Memory reserved for stacks */
-#define CACTUS_STACKS_SIZE ULL(0x1000)
-
-/*
- * RX/TX buffer used by VM's in SPM for memory sharing
- * Each VM allocated 2 pages, one for RX and one for TX buffer.
- */
-#define CACTUS_RX_BASE PLAT_CACTUS_RX_BASE
-#define CACTUS_TX_BASE CACTUS_RX_BASE + PAGE_SIZE
-#define CACTUS_RX_TX_SIZE PAGE_SIZE * 2
-
-/*
- * RX/TX buffer helpers.
- */
-#define get_sp_rx_start(sp_id) (CACTUS_RX_BASE + (((sp_id & 0x7FFFU) - 1U) * CACTUS_RX_TX_SIZE))
-#define get_sp_rx_end(sp_id) (CACTUS_RX_BASE + (((sp_id & 0x7FFFU) - 1U) * CACTUS_RX_TX_SIZE) + PAGE_SIZE)
-#define get_sp_tx_start(sp_id) (CACTUS_TX_BASE + (((sp_id & 0x7FFFU) - 1U) * CACTUS_RX_TX_SIZE))
-#define get_sp_tx_end(sp_id) (CACTUS_TX_BASE + (((sp_id & 0x7FFFU) - 1U) * CACTUS_RX_TX_SIZE) + PAGE_SIZE)
-
-#endif /* CACTUS_DEF_H */
diff --git a/spm/cactus/cactus_interrupt.c b/spm/cactus/cactus_interrupt.c
index 7de36cf0..02d1fbfe 100644
--- a/spm/cactus/cactus_interrupt.c
+++ b/spm/cactus/cactus_interrupt.c
@@ -1,51 +1,77 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
+#include "cactus_message_loop.h"
+#include "cactus_test_cmds.h"
+#include <drivers/arm/sp805.h>
#include <ffa_helpers.h>
#include <sp_helpers.h>
-#include <spm_helpers.h>
-
-#include "cactus_test_cmds.h"
#include "spm_common.h"
+#include <spm_helpers.h>
-extern ffa_vm_id_t g_ffa_id;
+#include <platform_def.h>
-static void managed_exit_handler(void)
-{
- /*
- * Real SP will save its context here.
- * Send interrupt ID for acknowledgement
- */
- cactus_response(g_ffa_id, HYP_ID, MANAGED_EXIT_INTERRUPT_ID);
-}
+#define NOTIFICATION_PENDING_INTERRUPT_INTID 5
-int cactus_irq_handler(void)
-{
- uint32_t irq_num;
+extern void notification_pending_interrupt_handler(void);
- irq_num = spm_interrupt_get();
+extern ffa_id_t g_ffa_id;
- ERROR("%s: Interrupt ID %u not handled!\n", __func__, irq_num);
+/* Secure virtual interrupt that was last handled by Cactus SP. */
+uint32_t last_serviced_interrupt[PLATFORM_CORE_COUNT];
- return 0;
-}
+extern spinlock_t sp_handler_lock[NUM_VINT_ID];
-int cactus_fiq_handler(void)
+void cactus_interrupt_handler(void)
{
- uint32_t fiq_num;
+ uint32_t intid = spm_interrupt_get();
+ unsigned int core_pos = get_current_core_id();
- fiq_num = spm_interrupt_get();
+ switch (intid) {
+ case MANAGED_EXIT_INTERRUPT_ID:
+ /*
+ * A secure partition performs its housekeeping and sends a
+ * direct response to signal interrupt completion.
+ * This is a pure virtual interrupt, no need for deactivation.
+ */
+ cactus_response(g_ffa_id, HYP_ID, MANAGED_EXIT_INTERRUPT_ID);
+ break;
+ case IRQ_TWDOG_INTID:
+ /*
+ * Interrupt triggered due to Trusted watchdog timer expiry.
+ * Clear the interrupt and stop the timer.
+ */
+ VERBOSE("Trusted WatchDog timer stopped\n");
+ sp805_twdog_stop();
- if (fiq_num == MANAGED_EXIT_INTERRUPT_ID) {
- managed_exit_handler();
- } else {
- ERROR("%s: Interrupt ID %u not handled!\n", __func__, fiq_num);
+ /* Perform secure interrupt de-activation. */
+ spm_interrupt_deactivate(intid);
+
+ break;
+ case NOTIFICATION_PENDING_INTERRUPT_INTID:
+ notification_pending_interrupt_handler();
+ break;
+ default:
+ /*
+ * Currently the only source of secure interrupt is Trusted
+ * Watchdog timer.
+ */
+ ERROR("%s: Interrupt ID %x not handled!\n", __func__,
+ intid);
+ panic();
}
- return 0;
+ last_serviced_interrupt[core_pos] = intid;
+
+ /* Invoke the tail end handler registered by the SP. */
+ spin_lock(&sp_handler_lock[intid]);
+ if (sp_interrupt_tail_end_handler[intid]) {
+ sp_interrupt_tail_end_handler[intid]();
+ }
+ spin_unlock(&sp_handler_lock[intid]);
}
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index ff3f6187..5a274f60 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,22 +9,24 @@
#include <debug.h>
#include <cactus_message_loop.h>
-#include <cactus_platform_def.h>
#include <drivers/arm/pl011.h>
#include <drivers/console.h>
#include <lib/aarch64/arch_helpers.h>
#include <lib/tftf_lib.h>
#include <lib/xlat_tables/xlat_mmu_helpers.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <ffa_helpers.h>
#include <plat_arm.h>
#include <plat/common/platform.h>
#include <platform_def.h>
+#include <sp_debug.h>
#include <sp_helpers.h>
#include <spm_helpers.h>
#include <std_svc.h>
-#include "cactus_def.h"
-#include "cactus_tests.h"
+#include "sp_def.h"
+#include "sp_tests.h"
#include "cactus.h"
/* Host machine information injected by the build system in the ELF file. */
@@ -34,7 +36,7 @@ extern const char version_string[];
extern void secondary_cold_entry(void);
/* Global ffa_id */
-ffa_vm_id_t g_ffa_id;
+ffa_id_t g_ffa_id;
/*
*
@@ -45,10 +47,10 @@ ffa_vm_id_t g_ffa_id;
*
*/
-static void __dead2 message_loop(ffa_vm_id_t vm_id, struct mailbox_buffers *mb)
+static void __dead2 message_loop(ffa_id_t vm_id, struct mailbox_buffers *mb)
{
- smc_ret_values ffa_ret;
- ffa_vm_id_t destination;
+ struct ffa_value ffa_ret;
+ ffa_id_t destination;
/*
* This initial wait call is necessary to inform SPMD that
@@ -67,14 +69,31 @@ static void __dead2 message_loop(ffa_vm_id_t vm_id, struct mailbox_buffers *mb)
}
if (ffa_func_id(ffa_ret) != FFA_MSG_SEND_DIRECT_REQ_SMC32 &&
- ffa_func_id(ffa_ret) != FFA_MSG_SEND_DIRECT_REQ_SMC64) {
+ ffa_func_id(ffa_ret) != FFA_MSG_SEND_DIRECT_REQ_SMC64 &&
+ ffa_func_id(ffa_ret) != FFA_INTERRUPT &&
+ ffa_func_id(ffa_ret) != FFA_RUN) {
ERROR("%s(%u) unknown func id 0x%x\n",
__func__, vm_id, ffa_func_id(ffa_ret));
break;
}
- destination = ffa_dir_msg_dest(ffa_ret);
+ if ((ffa_func_id(ffa_ret) == FFA_INTERRUPT) ||
+ (ffa_func_id(ffa_ret) == FFA_RUN)) {
+ /*
+ * Received FFA_INTERRUPT in waiting state.
+ * The interrupt id is passed although this is just
+ * informational as we're running with virtual
+ * interrupts unmasked and the interrupt is processed
+ * by the interrupt handler.
+ *
+ * Received FFA_RUN in waiting state, the endpoint
+ * simply returns by FFA_MSG_WAIT.
+ */
+ ffa_ret = ffa_msg_wait();
+ continue;
+ }
+ destination = ffa_dir_msg_dest(ffa_ret);
if (destination != vm_id) {
ERROR("%s(%u) invalid vm id 0x%x\n",
__func__, vm_id, destination);
@@ -124,6 +143,45 @@ static void cactus_print_memory_layout(unsigned int vm_id)
(void *)get_sp_tx_end(vm_id));
}
+static void cactus_print_boot_info(struct ffa_boot_info_header *boot_info_header)
+{
+ struct ffa_boot_info_desc *boot_info_desc;
+
+ if (boot_info_header == NULL) {
+ NOTICE("SP doesn't have boot information!\n");
+ return;
+ }
+
+ VERBOSE("SP boot info:\n");
+ VERBOSE(" Signature: %x\n", boot_info_header->signature);
+ VERBOSE(" Version: %x\n", boot_info_header->version);
+ VERBOSE(" Blob Size: %u\n", boot_info_header->info_blob_size);
+ VERBOSE(" Descriptor Size: %u\n", boot_info_header->desc_size);
+ VERBOSE(" Descriptor Count: %u\n", boot_info_header->desc_count);
+
+ boot_info_desc = boot_info_header->boot_info;
+
+ if (boot_info_desc == NULL) {
+ ERROR("Boot data arguments error...\n");
+ return;
+ }
+
+ for (uint32_t i = 0; i < boot_info_header->desc_count; i++) {
+ VERBOSE(" Boot Data:\n");
+ VERBOSE(" Type: %u\n",
+ ffa_boot_info_type(&boot_info_desc[i]));
+ VERBOSE(" Type ID: %u\n",
+ ffa_boot_info_type_id(&boot_info_desc[i]));
+ VERBOSE(" Flags:\n");
+ VERBOSE(" Name Format: %x\n",
+ ffa_boot_info_name_format(&boot_info_desc[i]));
+ VERBOSE(" Content Format: %x\n",
+ ffa_boot_info_content_format(&boot_info_desc[i]));
+ VERBOSE(" Size: %u\n", boot_info_desc[i].size);
+ VERBOSE(" Value: %llx\n", boot_info_desc[i].content);
+ }
+}
+
static void cactus_plat_configure_mmu(unsigned int vm_id)
{
mmap_add_region(CACTUS_TEXT_START,
@@ -145,12 +203,12 @@ static void cactus_plat_configure_mmu(unsigned int vm_id)
mmap_add_region(get_sp_rx_start(vm_id),
get_sp_rx_start(vm_id),
- (CACTUS_RX_TX_SIZE / 2),
+ (SP_RX_TX_SIZE / 2),
MT_RO_DATA);
mmap_add_region(get_sp_tx_start(vm_id),
get_sp_tx_start(vm_id),
- (CACTUS_RX_TX_SIZE / 2),
+ (SP_RX_TX_SIZE / 2),
MT_RW_DATA);
mmap_add(cactus_mmap);
@@ -167,22 +225,17 @@ static void register_secondary_entrypoint(void)
tftf_smc(&args);
}
-int tftf_irq_handler_dispatcher(void)
-{
- ERROR("%s\n", __func__);
-
- return 0;
-}
-
-void __dead2 cactus_main(bool primary_cold_boot)
+void __dead2 cactus_main(bool primary_cold_boot,
+ struct ffa_boot_info_header *boot_info_header)
{
assert(IS_IN_EL1() != 0);
struct mailbox_buffers mb;
+ struct ffa_value ret;
/* Get current FFA id */
- smc_ret_values ffa_id_ret = ffa_id_get();
- ffa_vm_id_t ffa_id = (ffa_vm_id_t)(ffa_id_ret.ret2 & 0xffff);
+ struct ffa_value ffa_id_ret = ffa_id_get();
+ ffa_id_t ffa_id = ffa_endpoint_id(ffa_id_ret);
if (ffa_func_id(ffa_id_ret) != FFA_SUCCESS_SMC32) {
ERROR("FFA_ID_GET failed.\n");
panic();
@@ -198,6 +251,23 @@ void __dead2 cactus_main(bool primary_cold_boot)
/* Configure and enable Stage-1 MMU, enable D-Cache */
cactus_plat_configure_mmu(ffa_id);
+
+ /* Initialize locks for tail end interrupt handler */
+ sp_handler_spin_lock_init();
+
+ if (boot_info_header != NULL) {
+ /*
+ * TODO: Currently just validating that cactus can
+ * access the boot info descriptors. In case we want to
+ * use the boot info contents, we should check the
+ * blob and remap if the size is bigger than one page.
+ * Only then access the contents.
+ */
+ mmap_add_dynamic_region(
+ (unsigned long long)boot_info_header,
+ (uintptr_t)boot_info_header,
+ PAGE_SIZE, MT_RO_DATA);
+ }
}
/*
@@ -223,28 +293,26 @@ void __dead2 cactus_main(bool primary_cold_boot)
set_putc_impl(PL011_AS_STDOUT);
- NOTICE("Booting Primary Cactus Secure Partition\n%s\n%s\n",
- build_message, version_string);
+ cactus_print_boot_info(boot_info_header);
} else {
- smc_ret_values ret;
set_putc_impl(HVC_CALL_AS_STDOUT);
+ }
- NOTICE("Booting Secondary Cactus Secure Partition (ID: %x)\n%s\n%s\n",
- ffa_id, build_message, version_string);
-
- if (ffa_id == (SPM_VM_ID_FIRST + 2)) {
- VERBOSE("Mapping RXTX Region\n");
- CONFIGURE_AND_MAP_MAILBOX(mb, PAGE_SIZE, ret);
- if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
- ERROR(
- "Failed to map RXTX buffers. Error: %x\n",
- ffa_error_code(ret));
- panic();
- }
+ /* Below string is monitored by CI expect script. */
+ NOTICE("Booting Secure Partition (ID: %x)\n%s\n%s\n",
+ ffa_id, build_message, version_string);
+
+ if (ffa_id == (SPM_VM_ID_FIRST + 2)) {
+ VERBOSE("Mapping RXTX Region\n");
+ CONFIGURE_AND_MAP_MAILBOX(mb, PAGE_SIZE, ret);
+ if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
+ ERROR(
+ "Failed to map RXTX buffers. Error: %x\n",
+ ffa_error_code(ret));
+ panic();
}
}
- INFO("FF-A id: %x\n", ffa_id);
cactus_print_memory_layout(ffa_id);
register_secondary_entrypoint();
diff --git a/spm/cactus/cactus_tests/cactus_message_loop.c b/spm/cactus/cactus_tests/cactus_message_loop.c
index fde70744..01ea32f5 100644
--- a/spm/cactus/cactus_tests/cactus_message_loop.c
+++ b/spm/cactus/cactus_tests/cactus_message_loop.c
@@ -1,14 +1,23 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include "cactus_message_loop.h"
-#include "cactus_test_cmds.h"
-#include <ffa_helpers.h>
#include <debug.h>
+#include <cactus_message_loop.h>
+#include <cactus_test_cmds.h>
+#include <ffa_helpers.h>
+#include <events.h>
+#include <platform.h>
+
+/**
+ * Counter of the number of handled requests, for each CPU. The number of
+ * requests can be accessed from another Cactus SP, or from the normal world
+ * using a special test command.
+ */
+static uint32_t requests_counter[PLATFORM_CORE_COUNT];
/**
* Begin and end of command handler table, respectively. Both symbols defined by
@@ -19,20 +28,24 @@ extern struct cactus_cmd_handler cactus_cmd_handler_end[];
#define PRINT_CMD(smc_ret) \
VERBOSE("cmd %lx; args: %lx, %lx, %lx, %lx\n", \
- smc_ret.ret3, smc_ret.ret4, smc_ret.ret5, \
- smc_ret.ret6, smc_ret.ret7)
+ smc_ret.arg3, smc_ret.arg4, smc_ret.arg5, \
+ smc_ret.arg6, smc_ret.arg7)
/**
* Traverses command table from section ".cactus_handler", searches for a
* registered command and invokes the respective handler.
*/
-bool cactus_handle_cmd(smc_ret_values *cmd_args, smc_ret_values *ret,
+bool cactus_handle_cmd(struct ffa_value *cmd_args, struct ffa_value *ret,
struct mailbox_buffers *mb)
{
uint64_t in_cmd;
+ /* Get which core it is running from. */
+ unsigned int core_pos = platform_get_core_pos(
+ read_mpidr_el1() & MPID_MASK);
+
if (cmd_args == NULL || ret == NULL) {
- ERROR("Invalid argumentos passed to %s!\n", __func__);
+ ERROR("Invalid arguments passed to %s!\n", __func__);
return false;
}
@@ -45,10 +58,33 @@ bool cactus_handle_cmd(smc_ret_values *cmd_args, smc_ret_values *ret,
it_cmd++) {
if (it_cmd->id == in_cmd) {
*ret = it_cmd->fn(cmd_args, mb);
+
+ /*
+ * Increment the number of requests handled in current
+ * core.
+ */
+ requests_counter[core_pos]++;
+
return true;
}
}
+ /* Handle special command. */
+ if (in_cmd == CACTUS_GET_REQ_COUNT_CMD) {
+ uint32_t requests_counter_resp;
+
+ /* Read value from array. */
+ requests_counter_resp = requests_counter[core_pos];
+ VERBOSE("Requests Counter %u, core: %u\n", requests_counter_resp,
+ core_pos);
+
+ *ret = cactus_success_resp(
+ ffa_dir_msg_dest(*cmd_args),
+ ffa_dir_msg_source(*cmd_args),
+ requests_counter_resp);
+ return true;
+ }
+
*ret = cactus_error_resp(ffa_dir_msg_dest(*cmd_args),
ffa_dir_msg_source(*cmd_args),
CACTUS_ERROR_UNHANDLED);
diff --git a/spm/cactus/cactus_tests/cactus_test_direct_messaging.c b/spm/cactus/cactus_tests/cactus_test_direct_messaging.c
index a59cfa24..93bcba17 100644
--- a/spm/cactus/cactus_tests/cactus_test_direct_messaging.c
+++ b/spm/cactus/cactus_tests/cactus_test_direct_messaging.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -23,9 +23,9 @@ CACTUS_CMD_HANDLER(echo_cmd, CACTUS_ECHO_CMD)
CACTUS_CMD_HANDLER(req_echo_cmd, CACTUS_REQ_ECHO_CMD)
{
- smc_ret_values ffa_ret;
- ffa_vm_id_t vm_id = ffa_dir_msg_dest(*args);
- ffa_vm_id_t echo_dest = cactus_req_echo_get_echo_dest(*args);
+ struct ffa_value ffa_ret;
+ ffa_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_id_t echo_dest = cactus_req_echo_get_echo_dest(*args);
uint64_t echo_val = cactus_echo_get_val(*args);
VERBOSE("%x requested to send echo to %x, value %llx\n",
@@ -48,12 +48,12 @@ CACTUS_CMD_HANDLER(req_echo_cmd, CACTUS_REQ_ECHO_CMD)
return cactus_success_resp(vm_id, ffa_dir_msg_source(*args), 0);
}
-static smc_ret_values base_deadlock_handler(ffa_vm_id_t vm_id,
- ffa_vm_id_t source,
- ffa_vm_id_t deadlock_dest,
- ffa_vm_id_t deadlock_next_dest)
+static struct ffa_value base_deadlock_handler(ffa_id_t vm_id,
+ ffa_id_t source,
+ ffa_id_t deadlock_dest,
+ ffa_id_t deadlock_next_dest)
{
- smc_ret_values ffa_ret;
+ struct ffa_value ffa_ret;
ffa_ret = cactus_deadlock_send_cmd(vm_id, deadlock_dest,
deadlock_next_dest);
@@ -92,9 +92,9 @@ static smc_ret_values base_deadlock_handler(ffa_vm_id_t vm_id,
CACTUS_CMD_HANDLER(deadlock_cmd, CACTUS_DEADLOCK_CMD)
{
- ffa_vm_id_t source = ffa_dir_msg_source(*args);
- ffa_vm_id_t deadlock_dest = cactus_deadlock_get_next_dest(*args);
- ffa_vm_id_t deadlock_next_dest = source;
+ ffa_id_t source = ffa_dir_msg_source(*args);
+ ffa_id_t deadlock_dest = cactus_deadlock_get_next_dest(*args);
+ ffa_id_t deadlock_next_dest = source;
VERBOSE("%x is creating deadlock. next: %x\n", source, deadlock_dest);
@@ -104,10 +104,10 @@ CACTUS_CMD_HANDLER(deadlock_cmd, CACTUS_DEADLOCK_CMD)
CACTUS_CMD_HANDLER(req_deadlock_cmd, CACTUS_REQ_DEADLOCK_CMD)
{
- ffa_vm_id_t vm_id = ffa_dir_msg_dest(*args);
- ffa_vm_id_t source = ffa_dir_msg_source(*args);
- ffa_vm_id_t deadlock_dest = cactus_deadlock_get_next_dest(*args);
- ffa_vm_id_t deadlock_next_dest = cactus_deadlock_get_next_dest2(*args);
+ ffa_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_id_t source = ffa_dir_msg_source(*args);
+ ffa_id_t deadlock_dest = cactus_deadlock_get_next_dest(*args);
+ ffa_id_t deadlock_next_dest = cactus_deadlock_get_next_dest2(*args);
VERBOSE("%x requested deadlock with %x and %x\n",
ffa_dir_msg_source(*args), deadlock_dest, deadlock_next_dest);
diff --git a/spm/cactus/cactus_tests/cactus_test_ffa.c b/spm/cactus/cactus_tests/cactus_test_ffa.c
deleted file mode 100644
index 2ade7bd9..00000000
--- a/spm/cactus/cactus_tests/cactus_test_ffa.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-#include <assert.h>
-#include <debug.h>
-#include <errno.h>
-
-#include <cactus_def.h>
-#include <cactus_platform_def.h>
-#include <ffa_endpoints.h>
-#include <sp_helpers.h>
-#include <spm_helpers.h>
-#include <spm_common.h>
-
-#include <lib/libc/string.h>
-
-/* FFA version test helpers */
-#define FFA_MAJOR 1U
-#define FFA_MINOR 0U
-
-static const uint32_t primary_uuid[4] = PRIMARY_UUID;
-static const uint32_t secondary_uuid[4] = SECONDARY_UUID;
-static const uint32_t tertiary_uuid[4] = TERTIARY_UUID;
-static const uint32_t null_uuid[4] = {0};
-
-/*
- * Test FFA_FEATURES interface.
- */
-static void ffa_features_test(void)
-{
- const char *test_features = "FFA Features interface";
- smc_ret_values ffa_ret;
- const struct ffa_features_test *ffa_feature_test_target;
- unsigned int i, test_target_size =
- get_ffa_feature_test_target(&ffa_feature_test_target);
-
-
- announce_test_section_start(test_features);
-
- for (i = 0U; i < test_target_size; i++) {
- announce_test_start(ffa_feature_test_target[i].test_name);
-
- ffa_ret = ffa_features(ffa_feature_test_target[i].feature);
- expect(ffa_func_id(ffa_ret), ffa_feature_test_target[i].expected_ret);
- if (ffa_feature_test_target[i].expected_ret == FFA_ERROR) {
- expect(ffa_error_code(ffa_ret), FFA_ERROR_NOT_SUPPORTED);
- }
-
- announce_test_end(ffa_feature_test_target[i].test_name);
- }
-
- announce_test_section_end(test_features);
-}
-
-static void ffa_partition_info_helper(struct mailbox_buffers *mb, const uint32_t uuid[4],
- const struct ffa_partition_info *expected,
- const uint16_t expected_size)
-{
- smc_ret_values ret = ffa_partition_info_get(uuid);
- unsigned int i;
- expect(ffa_func_id(ret), FFA_SUCCESS_SMC32);
-
- struct ffa_partition_info *info = (struct ffa_partition_info *)(mb->recv);
- for (i = 0U; i < expected_size; i++) {
- expect(info[i].id, expected[i].id);
- expect(info[i].exec_context, expected[i].exec_context);
- expect(info[i].properties, expected[i].properties);
- }
-
- ret = ffa_rx_release();
- expect(ffa_func_id(ret), FFA_SUCCESS_SMC32);
-}
-
-static void ffa_partition_info_wrong_test(void)
-{
- const char *test_wrong_uuid = "Request wrong UUID";
- uint32_t uuid[4] = {1};
-
- announce_test_start(test_wrong_uuid);
-
- smc_ret_values ret = ffa_partition_info_get(uuid);
- expect(ffa_func_id(ret), FFA_ERROR);
- expect(ffa_error_code(ret), FFA_ERROR_INVALID_PARAMETER);
-
- announce_test_end(test_wrong_uuid);
-}
-
-static void ffa_partition_info_get_test(struct mailbox_buffers *mb)
-{
- const char *test_partition_info = "FFA Partition info interface";
- const char *test_primary = "Get primary partition info";
- const char *test_secondary = "Get secondary partition info";
- const char *test_tertiary = "Get tertiary partition info";
- const char *test_all = "Get all partitions info";
-
- const struct ffa_partition_info expected_info[] = {
- /* Primary partition info */
- {
- .id = SPM_VM_ID_FIRST,
- .exec_context = CACTUS_PRIMARY_EC_COUNT,
- /* Supports receipt of direct message requests. */
- .properties = 1U
- },
- /* Secondary partition info */
- {
- .id = SPM_VM_ID_FIRST + 1U,
- .exec_context = CACTUS_SECONDARY_EC_COUNT,
- .properties = 1U
- },
- /* Tertiary partition info */
- {
- .id = SPM_VM_ID_FIRST + 2U,
- .exec_context = CACTUS_TERTIARY_EC_COUNT,
- .properties = 1U
- }
- };
-
- announce_test_section_start(test_partition_info);
-
- announce_test_start(test_tertiary);
- ffa_partition_info_helper(mb, tertiary_uuid, &expected_info[2], 1);
- announce_test_end(test_tertiary);
-
- announce_test_start(test_secondary);
- ffa_partition_info_helper(mb, secondary_uuid, &expected_info[1], 1);
- announce_test_end(test_secondary);
-
- announce_test_start(test_primary);
- ffa_partition_info_helper(mb, primary_uuid, &expected_info[0], 1);
- announce_test_end(test_primary);
-
- announce_test_start(test_all);
- ffa_partition_info_helper(mb, null_uuid, expected_info, 3);
- announce_test_end(test_all);
-
- ffa_partition_info_wrong_test();
-
- announce_test_section_end(test_partition_info);
-}
-
-void ffa_version_test(void)
-{
- const char *test_ffa_version = "FFA Version interface";
-
- announce_test_start(test_ffa_version);
-
- smc_ret_values ret = ffa_version(MAKE_FFA_VERSION(FFA_MAJOR, FFA_MINOR));
- uint32_t spm_version = (uint32_t)ret.ret0;
-
- bool ffa_version_compatible =
- ((spm_version >> FFA_VERSION_MAJOR_SHIFT) == FFA_MAJOR &&
- (spm_version & FFA_VERSION_MINOR_MASK) >= FFA_MINOR);
-
- NOTICE("FFA_VERSION returned %u.%u; Compatible: %i\n",
- spm_version >> FFA_VERSION_MAJOR_SHIFT,
- spm_version & FFA_VERSION_MINOR_MASK,
- (int)ffa_version_compatible);
-
- expect((int)ffa_version_compatible, (int)true);
-
- announce_test_end(test_ffa_version);
-}
-
-void ffa_tests(struct mailbox_buffers *mb)
-{
- const char *test_ffa = "FFA Interfaces";
-
- announce_test_section_start(test_ffa);
-
- ffa_features_test();
- ffa_version_test();
- ffa_partition_info_get_test(mb);
-
- announce_test_section_end(test_ffa);
-}
diff --git a/spm/cactus/cactus_tests/cactus_test_interrupts.c b/spm/cactus/cactus_tests/cactus_test_interrupts.c
index b675dfc1..31ba7cae 100644
--- a/spm/cactus/cactus_tests/cactus_test_interrupts.c
+++ b/spm/cactus/cactus_tests/cactus_test_interrupts.c
@@ -1,36 +1,84 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
+#include <drivers/arm/sp805.h>
#include <sp_helpers.h>
#include <spm_helpers.h>
#include "cactus_message_loop.h"
#include "cactus_test_cmds.h"
+#include <platform.h>
+
+/* Secure virtual interrupt that was last handled by Cactus SP. */
+extern uint32_t last_serviced_interrupt[PLATFORM_CORE_COUNT];
+static int flag_set;
+
+static void sec_wdog_interrupt_handled(void)
+{
+ expect(flag_set, 0);
+ flag_set = 1;
+}
+
CACTUS_CMD_HANDLER(sleep_cmd, CACTUS_SLEEP_CMD)
{
- uint64_t timer_freq = read_cntfrq_el0();
- uint64_t time1, time2, time_lapsed;
+ uint64_t time_lapsed;
uint32_t sleep_time = cactus_get_sleep_time(*args);
- VERBOSE("Request to sleep %x for %ums.\n", ffa_dir_msg_dest(*args), sleep_time);
+ VERBOSE("Request to sleep %x for %ums.\n", ffa_dir_msg_dest(*args),
+ sleep_time);
- time1 = read_cntvct_el0();
- sp_sleep(sleep_time);
- time2 = read_cntvct_el0();
+ time_lapsed = sp_sleep_elapsed_time(sleep_time);
- /* Lapsed time should be at least equal to sleep time */
- time_lapsed = ((time2 - time1) * 1000) / timer_freq;
+ /* Lapsed time should be at least equal to sleep time. */
+ VERBOSE("Sleep complete: %llu\n", time_lapsed);
return cactus_response(ffa_dir_msg_dest(*args),
ffa_dir_msg_source(*args),
time_lapsed);
}
+CACTUS_CMD_HANDLER(sleep_fwd_cmd, CACTUS_FWD_SLEEP_CMD)
+{
+ struct ffa_value ffa_ret;
+ ffa_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_id_t fwd_dest = cactus_get_fwd_sleep_dest(*args);
+ uint32_t sleep_ms = cactus_get_sleep_time(*args);
+
+ VERBOSE("VM%x requested %x to sleep for value %u\n",
+ ffa_dir_msg_source(*args), fwd_dest, sleep_ms);
+
+ ffa_ret = cactus_sleep_cmd(vm_id, fwd_dest, sleep_ms);
+
+ while (ffa_func_id(ffa_ret) == FFA_INTERRUPT) {
+ /* Received FFA_INTERRUPT in blocked state. */
+ VERBOSE("Processing FFA_INTERRUPT while blocked on direct response\n");
+ unsigned int my_core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ ffa_ret = ffa_run(fwd_dest, my_core_pos);
+ }
+
+ if (!is_ffa_direct_response(ffa_ret)) {
+ ERROR("Encountered error in CACTUS_FWD_SLEEP_CMD response\n");
+ return cactus_error_resp(vm_id, ffa_dir_msg_source(*args),
+ CACTUS_ERROR_FFA_CALL);
+ }
+
+ if (cactus_get_response(ffa_ret) != sleep_ms) {
+ ERROR("Request returned: %u ms!\n",
+ cactus_get_response(ffa_ret));
+ return cactus_error_resp(vm_id, ffa_dir_msg_source(*args),
+ CACTUS_ERROR_TEST);
+
+ }
+
+ return cactus_success_resp(vm_id, ffa_dir_msg_source(*args), 0);
+}
+
CACTUS_CMD_HANDLER(interrupt_cmd, CACTUS_INTERRUPT_CMD)
{
uint32_t int_id = cactus_get_interrupt_id(*args);
@@ -49,3 +97,84 @@ CACTUS_CMD_HANDLER(interrupt_cmd, CACTUS_INTERRUPT_CMD)
ffa_dir_msg_source(*args),
CACTUS_SUCCESS);
}
+
+CACTUS_CMD_HANDLER(twdog_cmd, CACTUS_TWDOG_START_CMD)
+{
+ ffa_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_id_t source = ffa_dir_msg_source(*args);
+
+ uint64_t time_ms = cactus_get_wdog_duration(*args);
+
+ VERBOSE("Starting TWDOG: %llums\n", time_ms);
+ sp805_twdog_refresh();
+ sp805_twdog_start((time_ms * ARM_SP805_TWDG_CLK_HZ) / 1000);
+
+ return cactus_success_resp(vm_id, source, time_ms);
+}
+
+bool handle_twdog_interrupt_sp_sleep(uint32_t sleep_time, uint64_t *time_lapsed)
+{
+ sp_register_interrupt_tail_end_handler(sec_wdog_interrupt_handled,
+ IRQ_TWDOG_INTID);
+ *time_lapsed += sp_sleep_elapsed_time(sleep_time);
+
+ if (flag_set == 0) {
+ return false;
+ }
+
+ /* Reset the flag and unregister the handler. */
+ flag_set = 0;
+ sp_unregister_interrupt_tail_end_handler(IRQ_TWDOG_INTID);
+
+ return true;
+}
+
+CACTUS_CMD_HANDLER(sleep_twdog_cmd, CACTUS_SLEEP_TRIGGER_TWDOG_CMD)
+{
+ uint64_t time_lapsed = 0;
+ uint32_t sleep_time = cactus_get_sleep_time(*args) / 2;
+ uint64_t time_ms = cactus_get_wdog_trigger_duration(*args);
+
+ VERBOSE("Request to sleep %x for %ums.\n", ffa_dir_msg_dest(*args),
+ sleep_time);
+
+ if (!handle_twdog_interrupt_sp_sleep(sleep_time, &time_lapsed)) {
+ goto fail;
+ }
+
+ /* Lapsed time should be at least equal to sleep time. */
+ VERBOSE("Sleep complete: %llu\n", time_lapsed);
+
+ VERBOSE("Starting TWDOG: %llums\n", time_ms);
+ sp805_twdog_refresh();
+ sp805_twdog_start((time_ms * ARM_SP805_TWDG_CLK_HZ) / 1000);
+
+ VERBOSE("2nd Request to sleep %x for %ums.\n", ffa_dir_msg_dest(*args),
+ sleep_time);
+
+ if (!handle_twdog_interrupt_sp_sleep(sleep_time, &time_lapsed)) {
+ goto fail;
+ }
+
+ /* Lapsed time should be at least equal to sleep time. */
+ VERBOSE("2nd Sleep complete: %llu\n", time_lapsed);
+
+ return cactus_response(ffa_dir_msg_dest(*args),
+ ffa_dir_msg_source(*args),
+ time_lapsed);
+fail:
+ /* Test failed. */
+ ERROR("Watchdog interrupt not handled\n");
+ return cactus_error_resp(ffa_dir_msg_dest(*args),
+ ffa_dir_msg_source(*args),
+ CACTUS_ERROR_TEST);
+}
+
+CACTUS_CMD_HANDLER(interrupt_serviced_cmd, CACTUS_LAST_INTERRUPT_SERVICED_CMD)
+{
+ unsigned int core_pos = get_current_core_id();
+
+ return cactus_response(ffa_dir_msg_dest(*args),
+ ffa_dir_msg_source(*args),
+ last_serviced_interrupt[core_pos]);
+}
diff --git a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
index e7bce50f..715433ed 100644
--- a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
+++ b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
@@ -1,21 +1,70 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <cactus_def.h>
+#include <sp_def.h>
#include "cactus_message_loop.h"
#include "cactus_test_cmds.h"
-#include "cactus_tests.h"
#include <debug.h>
#include <ffa_helpers.h>
#include <sp_helpers.h>
+#include "sp_tests.h"
#include <xlat_tables_defs.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <sync.h>
-/* Memory section to be used for memory share operations */
-static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE];
+static volatile uint32_t data_abort_gpf_triggered;
+
+static bool data_abort_gpf_handler(void)
+{
+ uint64_t esr_el1 = read_esr_el1();
+
+ VERBOSE("%s count %u esr_el1 %llx elr_el1 %lx\n",
+ __func__, data_abort_gpf_triggered, esr_el1,
+ read_elr_el1());
+
+ /* Expect a data abort because of a GPF. */
+ if ((EC_BITS(esr_el1) == EC_DABORT_CUR_EL) &&
+ ((ISS_BITS(esr_el1) & ISS_DFSC_MASK) == DFSC_GPF_DABORT)) {
+ data_abort_gpf_triggered++;
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Each Cactus SP has a memory region dedicated to memory sharing tests
+ * described in their partition manifest.
+ * This function returns the expected base address depending on the
+ * SP ID (should be the same as the manifest).
+ */
+static void *share_page(ffa_id_t cactus_sp_id)
+{
+ switch (cactus_sp_id) {
+ case SP_ID(1):
+ return (void *)CACTUS_SP1_MEM_SHARE_BASE;
+ case SP_ID(2):
+ return (void *)CACTUS_SP2_MEM_SHARE_BASE;
+ case SP_ID(3):
+ return (void *)CACTUS_SP3_MEM_SHARE_BASE;
+ default:
+ ERROR("Helper function expecting a valid Cactus SP ID!\n");
+ panic();
+ }
+}
+
+static void *share_page_non_secure(ffa_id_t cactus_sp_id)
+{
+ if (cactus_sp_id != SP_ID(3)) {
+ ERROR("Helper function expecting a valid Cactus SP ID!\n");
+ panic();
+ }
+
+ return (void *)CACTUS_SP3_NS_MEM_SHARE_BASE;
+}
CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
{
@@ -24,12 +73,17 @@ CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
int ret;
unsigned int mem_attrs;
uint32_t *ptr;
- ffa_vm_id_t source = ffa_dir_msg_source(*args);
- ffa_vm_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_id_t source = ffa_dir_msg_source(*args);
+ ffa_id_t vm_id = ffa_dir_msg_dest(*args);
uint32_t mem_func = cactus_req_mem_send_get_mem_func(*args);
uint64_t handle = cactus_mem_send_get_handle(*args);
+ ffa_memory_region_flags_t retrv_flags =
+ cactus_mem_send_get_retrv_flags(*args);
+ uint32_t words_to_write = cactus_mem_send_words_to_write(*args);
+ bool non_secure = cactus_mem_send_get_non_secure(*args);
- expect(memory_retrieve(mb, &m, handle, source, vm_id, mem_func), true);
+ expect(memory_retrieve(mb, &m, handle, source, vm_id,
+ retrv_flags), true);
composite = ffa_memory_region_get_composite(m, 0);
@@ -47,7 +101,7 @@ CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
mem_attrs = MT_RW_DATA | MT_EXECUTE_NEVER;
- if (!IS_SP_ID(source)) {
+ if (non_secure) {
mem_attrs |= MT_NS;
}
@@ -58,7 +112,7 @@ CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
mem_attrs);
if (ret != 0) {
- ERROR("Failed first mmap_add_dynamic_region!\n");
+ ERROR("Failed to map received memory region(%d)!\n", ret);
return cactus_error_resp(vm_id, source, CACTUS_ERROR_TEST);
}
@@ -66,10 +120,31 @@ CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
ptr = (uint32_t *) composite->constituents[0].address;
+ /* Check that memory has been cleared by the SPMC before using it. */
+ if ((retrv_flags & FFA_MEMORY_REGION_FLAG_CLEAR) != 0U) {
+ VERBOSE("Check if memory has been cleared!\n");
+ for (uint32_t i = 0; i < words_to_write; i++) {
+ if (ptr[i] != 0) {
+ /*
+ * If it hasn't been cleared, shouldn't be used.
+ */
+ ERROR("Memory should have been cleared!\n");
+ return cactus_error_resp(
+ vm_id, source, CACTUS_ERROR_TEST);
+ }
+ }
+ }
+
+ data_abort_gpf_triggered = 0;
+ register_custom_sync_exception_handler(data_abort_gpf_handler);
+
/* Write mem_func to retrieved memory region for validation purposes. */
VERBOSE("Writing: %x\n", mem_func);
- for (unsigned int i = 0U; i < 5U; i++)
+ for (unsigned int i = 0U; i < words_to_write; i++) {
ptr[i] = mem_func;
+ }
+
+ unregister_custom_sync_exception_handler();
/*
* A FFA_MEM_DONATE changes the ownership of the page, as such no
@@ -81,7 +156,7 @@ CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
composite->constituents[0].page_count * PAGE_SIZE);
if (ret != 0) {
- ERROR("Failed first mmap_add_dynamic_region!\n");
+ ERROR("Failed to unmap received memory region(%d)!\n", ret);
return cactus_error_resp(vm_id, source,
CACTUS_ERROR_TEST);
}
@@ -100,43 +175,69 @@ CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
}
return cactus_success_resp(vm_id,
- source, 0);
+ source, data_abort_gpf_triggered);
}
CACTUS_CMD_HANDLER(req_mem_send_cmd, CACTUS_REQ_MEM_SEND_CMD)
{
- smc_ret_values ffa_ret;
+ struct ffa_value ffa_ret;
uint32_t mem_func = cactus_req_mem_send_get_mem_func(*args);
- ffa_vm_id_t receiver = cactus_req_mem_send_get_receiver(*args);
+ ffa_id_t receiver = cactus_req_mem_send_get_receiver(*args);
ffa_memory_handle_t handle;
- ffa_vm_id_t vm_id = ffa_dir_msg_dest(*args);
- ffa_vm_id_t source = ffa_dir_msg_source(*args);
+ ffa_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_id_t source = ffa_dir_msg_source(*args);
+ bool non_secure = cactus_req_mem_send_get_non_secure(*args);
+ void *share_page_addr =
+ non_secure ? share_page_non_secure(vm_id) : share_page(vm_id);
+ unsigned int mem_attrs;
+ int ret;
- VERBOSE("%x requested to send memory to %x (func: %x)\n",
- source, receiver, mem_func);
+ VERBOSE("%x requested to send memory to %x (func: %x), page: %llx\n",
+ source, receiver, mem_func, (uint64_t)share_page_addr);
const struct ffa_memory_region_constituent constituents[] = {
- {(void *)share_page, 1, 0}
+ {share_page_addr, 1, 0}
};
const uint32_t constituents_count = (sizeof(constituents) /
sizeof(constituents[0]));
+ VERBOSE("Sharing at 0x%llx\n", (uint64_t)constituents[0].address);
+ mem_attrs = MT_RW_DATA;
+
+ if (non_secure) {
+ mem_attrs |= MT_NS;
+ }
+
+ ret = mmap_add_dynamic_region(
+ (uint64_t)constituents[0].address,
+ (uint64_t)constituents[0].address,
+ constituents[0].page_count * PAGE_SIZE,
+ mem_attrs);
+
+ if (ret != 0) {
+ ERROR("Failed map share memory before sending (%d)!\n",
+ ret);
+ return cactus_error_resp(vm_id, source,
+ CACTUS_ERROR_TEST);
+ }
+
handle = memory_init_and_send(
(struct ffa_memory_region *)mb->send, PAGE_SIZE,
vm_id, receiver, constituents,
- constituents_count, mem_func);
+ constituents_count, mem_func, &ffa_ret);
/*
* If returned an invalid handle, we should break the test.
*/
if (handle == FFA_MEMORY_HANDLE_INVALID) {
- ERROR("Received an invalid FF-A memory Handle!\n");
+ VERBOSE("Received an invalid FF-A memory Handle!\n");
return cactus_error_resp(vm_id, source,
- CACTUS_ERROR_TEST);
+ ffa_error_code(ffa_ret));
}
- ffa_ret = cactus_mem_send_cmd(vm_id, receiver, mem_func, handle);
+ ffa_ret = cactus_mem_send_cmd(vm_id, receiver, mem_func, handle,
+ 0, non_secure, 10);
if (!is_ffa_direct_response(ffa_ret)) {
return cactus_error_resp(vm_id, source, CACTUS_ERROR_FFA_CALL);
@@ -175,5 +276,17 @@ CACTUS_CMD_HANDLER(req_mem_send_cmd, CACTUS_REQ_MEM_SEND_CMD)
#endif
}
+ /* Always unmap the sent memory region, will be remapped by another
+ * test if needed. */
+ ret = mmap_remove_dynamic_region(
+ (uint64_t)constituents[0].address,
+ constituents[0].page_count * PAGE_SIZE);
+
+ if (ret != 0) {
+ ERROR("Failed to unmap share memory region (%d)!\n", ret);
+ return cactus_error_resp(vm_id, source,
+ CACTUS_ERROR_TEST);
+ }
+
return cactus_success_resp(vm_id, source, 0);
}
diff --git a/spm/cactus/cactus_tests/cactus_test_notifications.c b/spm/cactus/cactus_tests/cactus_test_notifications.c
new file mode 100644
index 00000000..d8b88ed0
--- /dev/null
+++ b/spm/cactus/cactus_tests/cactus_test_notifications.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "cactus_message_loop.h"
+#include "cactus_test_cmds.h"
+#include "sp_tests.h"
+
+#include <ffa_helpers.h>
+#include <debug.h>
+
+/* Booleans to keep track of which CPUs handled NPI. */
+static bool npi_handled[PLATFORM_CORE_COUNT];
+
+/**
+ * Helper to access the above array and set the boolean for the specific CPU.
+ */
+void set_npi_handled(uint32_t vcpu_id, bool val)
+{
+ npi_handled[vcpu_id] = val;
+}
+
+/**
+ * Helper to get state of the boolean from `npi_handled` from the respective
+ * CPU.
+ */
+bool get_npi_handled(uint32_t vcpu_id)
+{
+ return npi_handled[vcpu_id];
+}
+
+void notification_pending_interrupt_handler(void)
+{
+ /* Get which core it is running from. */
+ unsigned int core_pos = platform_get_core_pos(
+ read_mpidr_el1() & MPID_MASK);
+
+ VERBOSE("NPI handled in core %u\n", core_pos);
+
+ set_npi_handled(core_pos, true);
+}
+
+
+CACTUS_CMD_HANDLER(notifications_bind, CACTUS_NOTIFICATION_BIND_CMD)
+{
+ ffa_id_t source = ffa_dir_msg_source(*args);
+ ffa_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_id_t receiver = cactus_notification_get_receiver(*args);
+ ffa_id_t sender = cactus_notification_get_sender(*args);
+ ffa_notification_bitmap_t notifications =
+ cactus_notification_get_notifications(*args);
+ uint32_t flags = cactus_notification_get_flags(*args);
+ struct ffa_value ret;
+
+ VERBOSE("Partition %x requested to bind notifications '%llx' to %x\n",
+ source, notifications, receiver);
+
+ ret = ffa_notification_bind(sender, receiver, flags, notifications);
+
+ if (is_ffa_call_error(ret)) {
+ return cactus_error_resp(vm_id, source, ffa_error_code(ret));
+ }
+
+ return cactus_response(vm_id, source, CACTUS_SUCCESS);
+}
+
+CACTUS_CMD_HANDLER(notifications_unbind, CACTUS_NOTIFICATION_UNBIND_CMD)
+{
+ ffa_id_t source = ffa_dir_msg_source(*args);
+ ffa_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_id_t receiver = cactus_notification_get_receiver(*args);
+ ffa_id_t sender = cactus_notification_get_sender(*args);
+ ffa_notification_bitmap_t notifications =
+ cactus_notification_get_notifications(*args);
+ struct ffa_value ret;
+
+ VERBOSE("Partition %x requested to unbind notifications '%llx' to %x\n",
+ source, notifications, receiver);
+
+ ret = ffa_notification_unbind(sender, receiver, notifications);
+
+ if (is_ffa_call_error(ret)) {
+ return cactus_error_resp(vm_id, source, ffa_error_code(ret));
+ }
+
+ return cactus_response(vm_id, source, CACTUS_SUCCESS);
+}
+
+CACTUS_CMD_HANDLER(notifications_get, CACTUS_NOTIFICATION_GET_CMD)
+{
+ ffa_id_t source = ffa_dir_msg_source(*args);
+ ffa_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_id_t notification_receiver =
+ cactus_notification_get_receiver(*args);
+ uint32_t flags = cactus_notification_get_flags(*args);
+ uint32_t vcpu_id = cactus_notification_get_vcpu(*args);
+ struct ffa_value ret;
+
+ VERBOSE("Partition %x requested to get notifications.\n", source);
+
+ ret = ffa_notification_get(notification_receiver, vcpu_id, flags);
+
+ if (is_ffa_call_error(ret)) {
+ return cactus_error_resp(vm_id, source, ffa_error_code(ret));
+ }
+
+ VERBOSE("Notifications returned:\n"
+ " from sp: %llx\n"
+ " from vm: %llx\n",
+ ffa_notifications_get_from_sp(ret),
+ ffa_notifications_get_from_vm(ret));
+
+ /* If requested to check the status of NPI, for the respective CPU. */
+ if (cactus_notifications_check_npi_handled(*args)) {
+
+ /* If NPI hasn't been handled return error for this test. */
+ if (!get_npi_handled(vcpu_id)) {
+ return cactus_error_resp(vm_id, source,
+ CACTUS_ERROR_TEST);
+ }
+
+ /* Reset NPI flag for the respective core. */
+ set_npi_handled(vcpu_id, false);
+ }
+
+ return cactus_notifications_get_success_resp(
+ vm_id, source, ffa_notifications_get_from_sp(ret),
+ ffa_notifications_get_from_vm(ret));
+}
+
+CACTUS_CMD_HANDLER(notifications_set, CACTUS_NOTIFICATIONS_SET_CMD)
+{
+ ffa_id_t source = ffa_dir_msg_source(*args);
+ ffa_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_notification_bitmap_t notifications =
+ cactus_notification_get_notifications(*args);
+ ffa_id_t receiver = cactus_notifications_set_get_receiver(*args);
+ ffa_id_t sender = cactus_notifications_set_get_sender(*args);
+ ffa_id_t echo_dest = cactus_req_echo_get_echo_dest(*args);
+ uint32_t flags = cactus_notification_get_flags(*args);
+ struct ffa_value ret;
+
+ VERBOSE("Partition %x requested to set notifications.\n", source);
+
+ ret = ffa_notification_set(sender, receiver, flags, notifications);
+
+ if (is_ffa_call_error(ret)) {
+ return cactus_error_resp(vm_id, source, ffa_error_code(ret));
+ }
+
+ /*
+ * If flag to delay notification pending interrupt, an echo test command
+ * should be sent to another SP, to validate SWd is not preempted.
+ */
+ if ((flags & FFA_NOTIFICATIONS_FLAG_DELAY_SRI) != 0 &&
+ IS_SP_ID(echo_dest)) {
+ VERBOSE("Delay SRI. Test Echo to %x.\n", echo_dest);
+ ret = cactus_echo_send_cmd(vm_id, echo_dest,
+ FFA_NOTIFICATION_SET);
+
+ if (!is_expected_cactus_response(ret, CACTUS_SUCCESS,
+ FFA_NOTIFICATION_SET)) {
+ ERROR("Echo Failed!\n");
+ return cactus_error_resp(vm_id, source,
+ CACTUS_ERROR_TEST);
+ }
+ }
+
+ VERBOSE("Set notifications handled (core %u)!\n", get_current_core_id());
+
+ return cactus_response(vm_id, source, CACTUS_SUCCESS);
+}
diff --git a/spm/cactus/cactus_tests/cactus_tests_smmuv3.c b/spm/cactus/cactus_tests/cactus_tests_smmuv3.c
index ce53dc64..3e6740b9 100644
--- a/spm/cactus/cactus_tests/cactus_tests_smmuv3.c
+++ b/spm/cactus/cactus_tests/cactus_tests_smmuv3.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,14 +9,14 @@
#include <arch_helpers.h>
#include "cactus.h"
#include "cactus_message_loop.h"
-#include <cactus_platform_def.h>
+#include <sp_platform_def.h>
#include "cactus_test_cmds.h"
-#include "cactus_tests.h"
#include <debug.h>
#include <ffa_helpers.h>
#include <mmio.h>
#include "smmuv3_test_engine.h"
#include <sp_helpers.h>
+#include "sp_tests.h"
#include <spm_common.h>
/* Source and target address for memcopy operation */
@@ -150,9 +150,9 @@ static bool run_smmuv3_test(void)
CACTUS_CMD_HANDLER(smmuv3_cmd, CACTUS_DMA_SMMUv3_CMD)
{
- smc_ret_values ffa_ret;
- ffa_vm_id_t vm_id = ffa_dir_msg_dest(*args);
- ffa_vm_id_t source = ffa_dir_msg_source(*args);
+ struct ffa_value ffa_ret;
+ ffa_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_id_t source = ffa_dir_msg_source(*args);
VERBOSE("Received request through direct message for DMA service\n");
diff --git a/spm/cactus/plat/arm/fvp/fdts/cactus-secondary.dts b/spm/cactus/plat/arm/fvp/fdts/cactus-secondary.dts
index 661684bd..12d21752 100644
--- a/spm/cactus/plat/arm/fvp/fdts/cactus-secondary.dts
+++ b/spm/cactus/plat/arm/fvp/fdts/cactus-secondary.dts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -15,8 +15,8 @@
/* Properties */
description = "Base-1";
- ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
- uuid = <0xd1582309 0xf02347b9 0x827c4464 0xf5578fc8>;
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0x092358d1 0xb94723f0 0x64447c82 0xc88f57f5>;
id = <2>;
auxiliary-id = <0xae>;
stream-endpoint-ids = <0 1 2 3>;
@@ -24,15 +24,13 @@
exception-level = <2>; /* S-EL1 */
execution-state = <0>; /* AARCH64 */
load-address = <0x7100000>;
- entrypoint-offset = <0x00001000>;
+ entrypoint-offset = <0x00004000>;
xlat-granule = <0>; /* 4KiB */
boot-order = <0>;
- messaging-method = <0>; /* Direct messaging only */
+ messaging-method = <3>; /* Direct messaging only */
+ notification-support; /* Support receipt of notifications. */
run-time-model = <0>; /* Run to completion */
- /* Boot protocol */
- gp-register-num = <0x0>;
-
rx_tx-info {
compatible = "arm,ffa-manifest-rx_tx-buffer";
rx-buffer = <&rxbuffer>;
@@ -56,28 +54,19 @@
attributes = <0x3>; /* read-write */
};
+ /* Memory to be shared in memory sharing tests. */
+ share-memory {
+ description = "share-memory";
+ pages-count = <1>;
+ base-address = <0x00000000 0x7501000>;
+ attributes = <0x3>; /* read-write */
+ };
+
/* Without optional base-address */
test-memory {
description = "test-memory";
pages-count = <4>;
- attributes = <0x7>; /* read-write-execute */
- };
- };
-
- device-regions {
- compatible = "arm,ffa-manifest-device-regions";
-
- test-reg {
- /* Dummy values */
- base-address = <0x00000000 0x24000000>;
- pages-count = <16>;
attributes = <0x3>; /* read-write */
- reg = <0x10000008 0x00000001 1>;
- smmu-id = <1>;
- stream-ids = <0x0 0x1>;
- interrupts = <0x2 0x3>,
- <0x4 0x5>;
};
};
-
};
diff --git a/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts b/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts
index ea7d5d6f..92517637 100644
--- a/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts
+++ b/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -15,24 +15,22 @@
/* Properties */
description = "Base-1";
- ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
- uuid = <0x79b55c73 0x1d8c44b9 0x859361e1 0x770ad8d2>;
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0x735cb579 0xb9448c1d 0xe1619385 0xd2d80a77>;
id = <3>;
auxiliary-id = <0xae>;
stream-endpoint-ids = <0 1 2 3>;
- execution-ctx-count = <8>;
+ execution-ctx-count = <1>;
exception-level = <2>; /* S-EL1 */
execution-state = <0>; /* AARCH64 */
load-address = <0x7200000>;
- entrypoint-offset = <0x00001000>;
+ entrypoint-offset = <0x00004000>;
xlat-granule = <0>; /* 4KiB */
boot-order = <0>;
- messaging-method = <0>; /* Direct messaging only */
+ notification-support;
+ messaging-method = <3>; /* Direct messaging only */
run-time-model = <0>; /* Run to completion */
- /* Boot protocol */
- gp-register-num = <0x0>;
-
memory-regions {
compatible = "arm,ffa-manifest-memory-regions";
@@ -40,24 +38,23 @@
test-memory {
description = "test-memory";
pages-count = <4>;
- attributes = <0x7>; /* read-write-execute */
+ attributes = <0x3>; /* read-write */
};
- };
-
- device-regions {
- compatible = "arm,ffa-manifest-device-regions";
- test-reg {
- /* Dummy values */
- base-address = <0x00000000 0x25000000>;
- pages-count = <16>;
+ /* Memory to be shared in memory sharing tests. */
+ share-memory {
+ description = "share-memory";
+ pages-count = <1>;
+ base-address = <0x00000000 0x7502000>;
attributes = <0x3>; /* read-write */
- reg = <0x10000008 0x00000001 1>;
- smmu-id = <1>;
- stream-ids = <0x0 0x1>;
- interrupts = <0x2 0x3>,
- <0x4 0x5>;
};
- };
+ /* Memory to be shared in memory sharing tests. */
+ share-memory-ns {
+ description = "NS share memory";
+ pages-count = <1>;
+ base-address = <0x00008800 0x80001000>;
+ attributes = <0x83>; /* NS / read-write */
+ };
+ };
};
diff --git a/spm/cactus/plat/arm/fvp/fdts/cactus.dts b/spm/cactus/plat/arm/fvp/fdts/cactus.dts
index 1c28fde4..3c011c91 100644
--- a/spm/cactus/plat/arm/fvp/fdts/cactus.dts
+++ b/spm/cactus/plat/arm/fvp/fdts/cactus.dts
@@ -15,8 +15,8 @@
/* Properties */
description = "Base-1";
- ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
- uuid = <0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>;
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0x1e67b5b4 0xe14f904a 0x13fb1fb8 0xcbdae1da>;
id = <1>;
auxiliary-id = <0xae>;
stream-endpoint-ids = <0 1 2 3>;
@@ -24,14 +24,22 @@
exception-level = <2>; /* S-EL1 */
execution-state = <0>; /* AARCH64 */
load-address = <0x7000000>;
- entrypoint-offset = <0x00001000>;
+ entrypoint-offset = <0x00002000>;
xlat-granule = <0>; /* 4KiB */
boot-order = <0>;
- messaging-method = <3>; /* Direct messaging with managed exit */
+ messaging-method = <3>; /* Direct messaging only */
+ managed-exit; /* Managed exit is supported */
+ notification-support; /* Support receipt of notifications. */
run-time-model = <0>; /* Run to completion */
/* Boot protocol */
- gp-register-num = <0x0>;
+ gp-register-num = <0>;
+
+ /* Boot Info */
+ boot-info {
+ compatible = "arm,ffa-manifest-boot-info";
+ ffa_manifest;
+ };
rx_tx-info {
compatible = "arm,ffa-manifest-rx_tx-buffer";
@@ -56,11 +64,19 @@
attributes = <0x3>; /* read-write */
};
+ /* Memory to be shared in memory sharing tests. */
+ share-memory {
+ description = "share-memory";
+ pages-count = <1>;
+ base-address =<0x00000000 0x7500000>;
+ attributes = <0x3>; /* read-write */
+ };
+
/* Without optional base-address */
test-memory {
description = "test-memory";
pages-count = <4>;
- attributes = <0x7>; /* read-write-execute */
+ attributes = <0x3>; /* read-write */
};
/*
@@ -105,18 +121,12 @@
stream-ids = <0x0 0x1>;
};
- test-reg {
- /* Dummy Values */
- base-address = <0x00000000 0x22000000>;
- pages-count = <64>;
+ sec_wdog {
+ /* SP805 Trusted Watchdog Module */
+ base-address = <0x00000000 0x2a490000>;
+ pages-count = <32>; /* Two 64KB pages */
attributes = <0x3>; /* read-write */
- reg = <0x10000008 0x00000001 1>;
- smmu-id = <1>;
- stream-ids = <0x0 0x1>;
- interrupts = <0x2 0x3>,
- <0x4 0x5>;
- exclusive-access;
+ interrupts = <56 0x900>;
};
};
-
};
diff --git a/spm/cactus/plat/arm/fvp/include/cactus_platform_def.h b/spm/cactus/plat/arm/fvp/include/cactus_platform_def.h
deleted file mode 100644
index 8940c83f..00000000
--- a/spm/cactus/plat/arm/fvp/include/cactus_platform_def.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <platform_def.h>
-
-#ifndef CACTUS_PLATFORM_DEF_H
-#define CACTUS_PLATFORM_DEF_H
-
-#define PLAT_ARM_DEVICE0_BASE DEVICE0_BASE
-#define PLAT_ARM_DEVICE0_SIZE DEVICE0_SIZE
-
-#define CACTUS_PL011_UART_BASE PL011_UART2_BASE
-#define CACTUS_PL011_UART_CLK_IN_HZ PL011_UART2_CLK_IN_HZ
-
-#define PLAT_CACTUS_RX_BASE ULL(0x7300000)
-#define PLAT_CACTUS_CORE_COUNT (8U)
-
-/* Scratch memory used for SMMUv3 driver testing purposes in Cactus SP */
-#define PLAT_CACTUS_MEMCPY_BASE ULL(0x7400000)
-#define PLAT_CACTUS_MEMCPY_RANGE ULL(0x8000)
-
-#define CACTUS_PRIMARY_EC_COUNT (8U)
-#define CACTUS_SECONDARY_EC_COUNT (8U)
-#define CACTUS_TERTIARY_EC_COUNT (1U)
-
-/* Base address of user and PRIV frames in SMMUv3TestEngine */
-#define USR_BASE_FRAME ULL(0x2BFE0000)
-#define PRIV_BASE_FRAME ULL(0x2BFF0000)
-
-#endif /* CACTUS_PLATFORM_DEF_H */
diff --git a/spm/cactus/plat/arm/fvp/include/sp_platform_def.h b/spm/cactus/plat/arm/fvp/include/sp_platform_def.h
new file mode 100644
index 00000000..0b231893
--- /dev/null
+++ b/spm/cactus/plat/arm/fvp/include/sp_platform_def.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * This file contains common defines for a secure partition. The correct
+ * platform_def.h header file is selected according to the secure partition
+ * and platform being built using the make scripts.
+ */
+
+#ifndef SP_PLATFORM_DEF_H
+#define SP_PLATFORM_DEF_H
+
+#include <platform_def.h>
+
+#define PLAT_SP_RX_BASE ULL(0x7300000)
+#define PLAT_SP_CORE_COUNT U(8)
+
+#define PLAT_ARM_DEVICE0_BASE DEVICE0_BASE
+#define PLAT_ARM_DEVICE0_SIZE DEVICE0_SIZE
+
+#define CACTUS_PL011_UART_BASE PL011_UART2_BASE
+#define CACTUS_PL011_UART_CLK_IN_HZ PL011_UART2_CLK_IN_HZ
+
+/* Scratch memory used for SMMUv3 driver testing purposes in Cactus SP */
+#define PLAT_CACTUS_MEMCPY_BASE ULL(0x7400000)
+#define PLAT_CACTUS_MEMCPY_RANGE ULL(0x8000)
+
+/* Base address of user and PRIV frames in SMMUv3TestEngine */
+#define USR_BASE_FRAME ULL(0x2BFE0000)
+#define PRIV_BASE_FRAME ULL(0x2BFF0000)
+
+/* Base address for memory sharing tests. */
+#define CACTUS_SP1_MEM_SHARE_BASE 0x7500000
+#define CACTUS_SP2_MEM_SHARE_BASE 0x7501000
+#define CACTUS_SP3_MEM_SHARE_BASE 0x7502000
+#define CACTUS_SP3_NS_MEM_SHARE_BASE 0x880080001000ULL
+
+#endif /* SP_PLATFORM_DEF_H */
diff --git a/spm/cactus/plat/arm/tc0/fdts/cactus-secondary.dts b/spm/cactus/plat/arm/tc0/fdts/cactus-secondary.dts
index 5b90eb8f..13d489c9 100644
--- a/spm/cactus/plat/arm/tc0/fdts/cactus-secondary.dts
+++ b/spm/cactus/plat/arm/tc0/fdts/cactus-secondary.dts
@@ -15,22 +15,20 @@
/* Properties */
description = "cactus-2";
- ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
- uuid = <0xd1582309 0xf02347b9 0x827c4464 0xf5578fc8>;
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0x092358d1 0xb94723f0 0x64447c82 0xc88f57f5>;
id = <2>;
execution-ctx-count = <8>;
exception-level = <2>; /* S-EL1 */
execution-state = <0>; /* AARCH64 */
load-address = <0xfe100000>;
- entrypoint-offset = <0x00001000>;
+ entrypoint-offset = <0x00004000>;
xlat-granule = <0>; /* 4KiB */
boot-order = <0>;
- messaging-method = <0>; /* Direct messaging only */
+ messaging-method = <3>; /* Direct messaging only */
+ notification-support; /* Support receipt of notifications. */
run-time-model = <1>; /* Run to completion */
- /* Boot protocol */
- gp-register-num = <0x0>;
-
rx_tx-info {
compatible = "arm,ffa-manifest-rx_tx-buffer";
rx-buffer = <&rxbuffer>;
@@ -53,5 +51,13 @@
base-address = <0x00000000 0xfe303000>;
attributes = <0x3>; /* read-write */
};
+
+ /* Memory to be shared in memory sharing tests. */
+ share-memory {
+ description = "share-memory";
+ pages-count = <1>;
+ base-address =<0x00000000 0xfe501000>;
+ attributes = <0x3>; /* read-write */
+ };
};
};
diff --git a/spm/cactus/plat/arm/tc0/fdts/cactus-tertiary.dts b/spm/cactus/plat/arm/tc0/fdts/cactus-tertiary.dts
index 3b50530e..807d1ddd 100644
--- a/spm/cactus/plat/arm/tc0/fdts/cactus-tertiary.dts
+++ b/spm/cactus/plat/arm/tc0/fdts/cactus-tertiary.dts
@@ -15,22 +15,20 @@
/* Properties */
description = "cactus-3";
- ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
- uuid = <0x79b55c73 0x1d8c44b9 0x859361e1 0x770ad8d2>;
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0x735cb579 0xb9448c1d 0xe1619385 0xd2d80a77>;
id = <3>;
execution-ctx-count = <1>;
exception-level = <2>; /* S-EL1 */
execution-state = <0>; /* AARCH64 */
load-address = <0xfe200000>;
- entrypoint-offset = <0x00001000>;
+ entrypoint-offset = <0x00004000>;
xlat-granule = <0>; /* 4KiB */
boot-order = <0>;
- messaging-method = <0>; /* Direct messaging only */
+ messaging-method = <3>; /* Direct messaging only */
+ notification-support; /* Support receipt of notifications. */
run-time-model = <1>; /* Run to completion */
- /* Boot protocol */
- gp-register-num = <0x0>;
-
memory-regions {
compatible = "arm,ffa-manifest-memory-regions";
@@ -38,7 +36,15 @@
test-memory {
description = "test-memory";
pages-count = <4>;
- attributes = <0x7>; /* read-write-execute */
+ attributes = <0x3>; /* read-write */
+ };
+
+ /* Memory to be shared in memory sharing tests. */
+ share-memory {
+ description = "share-memory";
+ pages-count = <1>;
+ base-address =<0x00000000 0xfe502000>;
+ attributes = <0x3>; /* read-write */
};
};
diff --git a/spm/cactus/plat/arm/tc0/fdts/cactus.dts b/spm/cactus/plat/arm/tc0/fdts/cactus.dts
index bd7c5465..99d3ae87 100644
--- a/spm/cactus/plat/arm/tc0/fdts/cactus.dts
+++ b/spm/cactus/plat/arm/tc0/fdts/cactus.dts
@@ -15,21 +15,29 @@
/* Properties */
description = "cactus-1";
- ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
- uuid = <0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>;
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0x1e67b5b4 0xe14f904a 0x13fb1fb8 0xcbdae1da>;
id = <1>;
execution-ctx-count = <8>;
exception-level = <2>; /* S-EL1 */
execution-state = <0>; /* AARCH64 */
load-address = <0xfe000000>;
- entrypoint-offset = <0x00001000>;
+ entrypoint-offset = <0x00002000>;
xlat-granule = <0>; /* 4KiB */
boot-order = <0>;
- messaging-method = <0>; /* Direct messaging only */
+ messaging-method = <3>; /* Direct messaging only */
+ notification-support; /* Support receipt of notifications. */
+ managed-exit; /* Managed exit supported */
run-time-model = <1>; /* Run to completion */
/* Boot protocol */
- gp-register-num = <0x0>;
+ gp-register-num = <0>;
+
+ /* Boot Info */
+ boot-info {
+ compatible = "arm,ffa-manifest-boot-info";
+ ffa_manifest;
+ };
rx_tx-info {
compatible = "arm,ffa-manifest-rx_tx-buffer";
@@ -53,6 +61,14 @@
base-address = <0x00000000 0xfe301000>;
attributes = <0x3>; /* read-write */
};
+
+ /* Memory to be shared in memory sharing tests. */
+ share-memory {
+ description = "share-memory";
+ pages-count = <1>;
+ base-address =<0x00000000 0xfe500000>;
+ attributes = <0x3>; /* read-write */
+ };
};
device-regions {
diff --git a/spm/cactus/plat/arm/tc0/include/cactus_platform_def.h b/spm/cactus/plat/arm/tc0/include/cactus_platform_def.h
deleted file mode 100644
index 42dd2915..00000000
--- a/spm/cactus/plat/arm/tc0/include/cactus_platform_def.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <platform_def.h>
-
-#ifndef CACTUS_PLATFORM_DEF_H
-#define CACTUS_PLATFORM_DEF_H
-
-#define PLAT_ARM_DEVICE0_BASE TC0_DEVICE0_BASE
-#define PLAT_ARM_DEVICE0_SIZE TC0_DEVICE0_SIZE
-
-#define CACTUS_PL011_UART_BASE PL011_UART1_BASE
-#define CACTUS_PL011_UART_CLK_IN_HZ PL011_UART1_CLK_IN_HZ
-
-#define PLAT_CACTUS_RX_BASE ULL(0xfe300000)
-
-#define CACTUS_PRIMARY_EC_COUNT (8U)
-#define CACTUS_SECONDARY_EC_COUNT (8U)
-#define CACTUS_TERTIARY_EC_COUNT (1U)
-
-#endif /* CACTUS_PLATFORM_DEF_H */
diff --git a/spm/cactus/plat/arm/tc0/include/sp_platform_def.h b/spm/cactus/plat/arm/tc0/include/sp_platform_def.h
new file mode 100644
index 00000000..3d288e6a
--- /dev/null
+++ b/spm/cactus/plat/arm/tc0/include/sp_platform_def.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * This file contains common defines for a secure partition. The correct
+ * platform_def.h header file is selected according to the secure partition
+ * and platform being built using the make scripts.
+ */
+
+#ifndef SP_PLATFORM_DEF_H
+#define SP_PLATFORM_DEF_H
+
+#include <platform_def.h>
+
+#define PLAT_SP_RX_BASE ULL(0xfe300000)
+#define PLAT_SP_CORE_COUNT U(8)
+
+#define PLAT_ARM_DEVICE0_BASE TC0_DEVICE0_BASE
+#define PLAT_ARM_DEVICE0_SIZE TC0_DEVICE0_SIZE
+
+#define CACTUS_PL011_UART_BASE PL011_UART1_BASE
+#define CACTUS_PL011_UART_CLK_IN_HZ PL011_UART1_CLK_IN_HZ
+
+/* Scratch memory used for SMMUv3 driver testing purposes in Cactus SP */
+/* SMMUv3 tests are disabled for TC platform */
+#define PLAT_CACTUS_MEMCPY_BASE ULL(0xfe400000)
+#define PLAT_CACTUS_MEMCPY_RANGE ULL(0x8000)
+
+/* Base address of user and PRIV frames in SMMUv3TestEngine */
+/* SMMUv3 tests are disabled for TC platform */
+#define USR_BASE_FRAME ULL(0x0)
+#define PRIV_BASE_FRAME ULL(0x0)
+
+/* Base address for memory sharing tests. */
+#define CACTUS_SP1_MEM_SHARE_BASE 0xfe500000
+#define CACTUS_SP2_MEM_SHARE_BASE 0xfe501000
+#define CACTUS_SP3_MEM_SHARE_BASE 0xfe502000
+#define CACTUS_SP3_NS_MEM_SHARE_BASE 0x880080001000ULL
+
+#endif /* SP_PLATFORM_DEF_H */
diff --git a/spm/cactus_mm/cactus_mm.mk b/spm/cactus_mm/cactus_mm.mk
index 3156c1cf..9d98d626 100644
--- a/spm/cactus_mm/cactus_mm.mk
+++ b/spm/cactus_mm/cactus_mm.mk
@@ -59,9 +59,6 @@ $(eval $(call add_define,CACTUS_MM_DEFINES,ARM_ARCH_MINOR))
$(eval $(call add_define,CACTUS_MM_DEFINES,DEBUG))
$(eval $(call add_define,CACTUS_MM_DEFINES,ENABLE_BTI))
$(eval $(call add_define,CACTUS_MM_DEFINES,ENABLE_PAUTH))
-$(eval $(call add_define,CACTUS_MM_DEFINES,FVP_CLUSTER_COUNT))
-$(eval $(call add_define,CACTUS_MM_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
-$(eval $(call add_define,CACTUS_MM_DEFINES,FVP_MAX_PE_PER_CPU))
$(eval $(call add_define,CACTUS_MM_DEFINES,LOG_LEVEL))
$(eval $(call add_define,CACTUS_MM_DEFINES,PLAT_${PLAT}))
diff --git a/spm/cactus/cactus_debug.c b/spm/common/sp_debug.c
index 30a25278..2e67be38 100644
--- a/spm/cactus/cactus_debug.c
+++ b/spm/common/sp_debug.c
@@ -1,15 +1,15 @@
/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <drivers/arm/pl011.h>
#include <drivers/console.h>
+#include <ffa_helpers.h>
+#include <sp_debug.h>
#include <spm_helpers.h>
-#include "cactus.h"
-
static int (*putc_impl)(int);
static int putc_hypcall(int c)
@@ -19,6 +19,17 @@ static int putc_hypcall(int c)
return c;
}
+static int putc_svccall(int c)
+{
+ struct ffa_value args = {
+ .fid = SPM_DEBUG_LOG,
+ .arg1 = c
+ };
+ ffa_svc(&args);
+
+ return c;
+}
+
static int putc_uart(int c)
{
console_pl011_putc(c);
@@ -34,6 +45,10 @@ void set_putc_impl(enum stdout_route route)
putc_impl = putc_hypcall;
return;
+ case SVC_CALL_AS_STDOUT:
+ putc_impl = putc_svccall;
+ return;
+
case PL011_AS_STDOUT:
default:
break;
diff --git a/spm/common/sp_debug.h b/spm/common/sp_debug.h
new file mode 100644
index 00000000..e35c6027
--- /dev/null
+++ b/spm/common/sp_debug.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+enum stdout_route {
+ PL011_AS_STDOUT = 0,
+ HVC_CALL_AS_STDOUT,
+ SVC_CALL_AS_STDOUT,
+};
+
+void set_putc_impl(enum stdout_route);
diff --git a/spm/common/sp_def.h b/spm/common/sp_def.h
new file mode 100644
index 00000000..2b26b68c
--- /dev/null
+++ b/spm/common/sp_def.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SP_DEF_H
+#define SP_DEF_H
+
+#include <utils_def.h>
+#include <sp_platform_def.h>
+
+/*
+ * Layout of the Secure Partition image.
+ */
+
+/* Up to 2 MiB at an arbitrary address that doesn't overlap the devices. */
+#define SP_IMAGE_BASE ULL(0x1000)
+#define SP_IMAGE_SIZE ULL(0x200000)
+
+/* Memory reserved for stacks */
+#define SP_STACKS_SIZE ULL(0x1000)
+
+/*
+ * RX/TX buffer used by VM's in SPM for memory sharing
+ * Each VM allocated 2 pages, one for RX and one for TX buffer.
+ */
+#define SP_RX_BASE PLAT_SP_RX_BASE
+#define SP_TX_BASE SP_RX_BASE + PAGE_SIZE
+#define SP_RX_TX_SIZE PAGE_SIZE * 2
+
+/*
+ * RX/TX buffer helpers.
+ */
+#define get_sp_rx_start(sp_id) (SP_RX_BASE \
+ + (((sp_id & 0x7FFFU) - 1U) * SP_RX_TX_SIZE))
+#define get_sp_rx_end(sp_id) (SP_RX_BASE \
+ + (((sp_id & 0x7FFFU) - 1U) * SP_RX_TX_SIZE) \
+ + PAGE_SIZE)
+#define get_sp_tx_start(sp_id) (SP_TX_BASE + \
+ (((sp_id & 0x7FFFU) - 1U) * SP_RX_TX_SIZE))
+#define get_sp_tx_end(sp_id) (SP_TX_BASE \
+ + (((sp_id & 0x7FFFU) - 1U) * SP_RX_TX_SIZE) \
+ + PAGE_SIZE)
+
+#endif /* SP_DEF_H */
diff --git a/spm/common/sp_helpers.c b/spm/common/sp_helpers.c
index a6b6bc5d..448084f1 100644
--- a/spm/common/sp_helpers.c
+++ b/spm/common/sp_helpers.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,6 +13,10 @@
#include "sp_helpers.h"
+spinlock_t sp_handler_lock[NUM_VINT_ID];
+
+void (*sp_interrupt_tail_end_handler[NUM_VINT_ID])(void);
+
uintptr_t bound_rand(uintptr_t min, uintptr_t max)
{
/*
@@ -58,16 +62,57 @@ void announce_test_end(const char *test_desc)
INFO("Test \"%s\" end.\n", test_desc);
}
-void sp_sleep(uint32_t ms)
+uint64_t sp_sleep_elapsed_time(uint32_t ms)
{
uint64_t timer_freq = read_cntfrq_el0();
VERBOSE("%s: Timer frequency = %llu\n", __func__, timer_freq);
VERBOSE("%s: Sleeping for %u milliseconds...\n", __func__, ms);
- uint64_t time1 = read_cntvct_el0();
+
+ uint64_t time1 = virtualcounter_read();
volatile uint64_t time2 = time1;
+
while ((time2 - time1) < ((ms * timer_freq) / 1000U)) {
- time2 = read_cntvct_el0();
+ time2 = virtualcounter_read();
+ }
+
+ return ((time2 - time1) * 1000) / timer_freq;
+}
+
+void sp_sleep(uint32_t ms)
+{
+ (void)sp_sleep_elapsed_time(ms);
+}
+
+void sp_handler_spin_lock_init(void)
+{
+ for (uint32_t i = 0; i < NUM_VINT_ID; i++) {
+ init_spinlock(&sp_handler_lock[i]);
+ }
+}
+
+void sp_register_interrupt_tail_end_handler(void (*handler)(void),
+ uint32_t interrupt_id)
+{
+ if (interrupt_id >= NUM_VINT_ID) {
+ ERROR("Cannot register handler for interrupt %u\n", interrupt_id);
+ panic();
}
+
+ spin_lock(&sp_handler_lock[interrupt_id]);
+ sp_interrupt_tail_end_handler[interrupt_id] = handler;
+ spin_unlock(&sp_handler_lock[interrupt_id]);
+}
+
+void sp_unregister_interrupt_tail_end_handler(uint32_t interrupt_id)
+{
+ if (interrupt_id >= NUM_VINT_ID) {
+ ERROR("Cannot unregister handler for interrupt %u\n", interrupt_id);
+ panic();
+ }
+
+ spin_lock(&sp_handler_lock[interrupt_id]);
+ sp_interrupt_tail_end_handler[interrupt_id] = NULL;
+ spin_unlock(&sp_handler_lock[interrupt_id]);
}
diff --git a/spm/common/sp_helpers.h b/spm/common/sp_helpers.h
index 399200a0..ef602213 100644
--- a/spm/common/sp_helpers.h
+++ b/spm/common/sp_helpers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,7 +9,11 @@
#include <stdint.h>
#include <tftf_lib.h>
-#include <ffa_helpers.h>
+#include <spm_common.h>
+#include <spinlock.h>
+
+/* Currently, Hafnium/SPM supports only 64 virtual interrupt IDs. */
+#define NUM_VINT_ID 64
typedef struct {
u_register_t fid;
@@ -56,7 +60,22 @@ void announce_test_section_end(const char *test_sect_desc);
void announce_test_start(const char *test_desc);
void announce_test_end(const char *test_desc);
+/* Sleep for at least 'ms' milliseconds and return the elapsed time(ms). */
+uint64_t sp_sleep_elapsed_time(uint32_t ms);
+
/* Sleep for at least 'ms' milliseconds. */
void sp_sleep(uint32_t ms);
+void sp_handler_spin_lock_init(void);
+
+/* Handler invoked at the tail end of interrupt processing by SP. */
+extern void (*sp_interrupt_tail_end_handler[NUM_VINT_ID])(void);
+
+/* Register the handler. */
+void sp_register_interrupt_tail_end_handler(void (*handler)(void),
+ uint32_t interrupt_id);
+
+/* Un-register the handler. */
+void sp_unregister_interrupt_tail_end_handler(uint32_t interrupt_id);
+
#endif /* SP_HELPERS_H */
diff --git a/spm/common/sp_tests/sp_test_ffa.c b/spm/common/sp_tests/sp_test_ffa.c
new file mode 100644
index 00000000..dd984592
--- /dev/null
+++ b/spm/common/sp_tests/sp_test_ffa.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <sp_def.h>
+#include <ffa_endpoints.h>
+#include <sp_helpers.h>
+#include <spm_helpers.h>
+#include <spm_common.h>
+
+#include <lib/libc/string.h>
+
+/* FFA version test helpers */
+#define FFA_MAJOR 1U
+#define FFA_MINOR 1U
+
+static uint32_t spm_version;
+
+static const struct ffa_uuid sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}, {IVY_UUID}
+ };
+
+static const struct ffa_partition_info ffa_expected_partition_info[] = {
+ /* Primary partition info */
+ {
+ .id = SP_ID(1),
+ .exec_context = PRIMARY_EXEC_CTX_COUNT,
+ .properties = (FFA_PARTITION_DIRECT_REQ_RECV |
+ FFA_PARTITION_DIRECT_REQ_SEND |
+ FFA_PARTITION_NOTIFICATION),
+ .uuid = sp_uuids[0]
+ },
+ /* Secondary partition info */
+ {
+ .id = SP_ID(2),
+ .exec_context = SECONDARY_EXEC_CTX_COUNT,
+ .properties = (FFA_PARTITION_DIRECT_REQ_RECV |
+ FFA_PARTITION_DIRECT_REQ_SEND |
+ FFA_PARTITION_NOTIFICATION),
+ .uuid = sp_uuids[1]
+ },
+ /* Tertiary partition info */
+ {
+ .id = SP_ID(3),
+ .exec_context = TERTIARY_EXEC_CTX_COUNT,
+ .properties = (FFA_PARTITION_DIRECT_REQ_RECV |
+ FFA_PARTITION_DIRECT_REQ_SEND |
+ FFA_PARTITION_NOTIFICATION),
+ .uuid = sp_uuids[2]
+ },
+ /* Ivy partition info */
+ {
+ .id = SP_ID(4),
+ .exec_context = IVY_EXEC_CTX_COUNT,
+ .properties = (FFA_PARTITION_DIRECT_REQ_RECV |
+ FFA_PARTITION_DIRECT_REQ_SEND),
+ .uuid = sp_uuids[3]
+ }
+};
+
+/*
+ * Test FFA_FEATURES interface.
+ */
+static void ffa_features_test(void)
+{
+ const char *test_features = "FFA Features interface";
+ struct ffa_value ffa_ret;
+ unsigned int expected_ret;
+ const struct ffa_features_test *ffa_feature_test_target;
+ unsigned int i, test_target_size =
+ get_ffa_feature_test_target(&ffa_feature_test_target);
+ struct ffa_features_test test_target;
+
+
+ announce_test_section_start(test_features);
+
+ for (i = 0U; i < test_target_size; i++) {
+ test_target = ffa_feature_test_target[i];
+
+ announce_test_start(test_target.test_name);
+
+ ffa_ret = ffa_features(test_target.feature);
+ expected_ret = FFA_VERSION_COMPILED
+ >= test_target.version_added ?
+ test_target.expected_ret : FFA_ERROR;
+
+ expect(ffa_func_id(ffa_ret), expected_ret);
+ if (expected_ret == FFA_ERROR) {
+ expect(ffa_error_code(ffa_ret), FFA_ERROR_NOT_SUPPORTED);
+ }
+
+ announce_test_end(test_target.test_name);
+ }
+
+ announce_test_section_end(test_features);
+}
+
+static void ffa_partition_info_wrong_test(void)
+{
+ const char *test_wrong_uuid = "Request wrong UUID";
+ const struct ffa_uuid uuid = { .uuid = {1} };
+
+ announce_test_start(test_wrong_uuid);
+
+ struct ffa_value ret = ffa_partition_info_get(uuid);
+ expect(ffa_func_id(ret), FFA_ERROR);
+ expect(ffa_error_code(ret), FFA_ERROR_INVALID_PARAMETER);
+
+ announce_test_end(test_wrong_uuid);
+}
+
+static void ffa_partition_info_get_test(struct mailbox_buffers *mb)
+{
+ const char *test_partition_info = "FFA Partition info interface";
+
+ announce_test_section_start(test_partition_info);
+
+ expect(ffa_partition_info_helper(mb, sp_uuids[2],
+ &ffa_expected_partition_info[2], 1), true);
+
+ expect(ffa_partition_info_helper(mb, sp_uuids[1],
+ &ffa_expected_partition_info[1], 1), true);
+
+ expect(ffa_partition_info_helper(mb, sp_uuids[0],
+ &ffa_expected_partition_info[0], 1), true);
+
+ expect(ffa_partition_info_helper(mb, NULL_UUID,
+ ffa_expected_partition_info,
+ ARRAY_SIZE(ffa_expected_partition_info)), true);
+
+ ffa_partition_info_wrong_test();
+
+ announce_test_section_end(test_partition_info);
+}
+
+void ffa_version_test(void)
+{
+ const char *test_ffa_version = "FFA Version interface";
+
+ announce_test_start(test_ffa_version);
+
+ struct ffa_value ret = ffa_version(MAKE_FFA_VERSION(FFA_MAJOR,
+ FFA_MINOR));
+
+ spm_version = (uint32_t)ret.fid;
+
+ bool ffa_version_compatible =
+ ((spm_version >> FFA_VERSION_MAJOR_SHIFT) == FFA_MAJOR &&
+ (spm_version & FFA_VERSION_MINOR_MASK) >= FFA_MINOR);
+
+ VERBOSE("FFA_VERSION returned %u.%u; Compatible: %i\n",
+ spm_version >> FFA_VERSION_MAJOR_SHIFT,
+ spm_version & FFA_VERSION_MINOR_MASK,
+ (int)ffa_version_compatible);
+
+ expect((int)ffa_version_compatible, (int)true);
+
+ announce_test_end(test_ffa_version);
+}
+
+void ffa_spm_id_get_test(void)
+{
+ const char *test_spm_id_get = "FFA_SPM_ID_GET SMC Function";
+
+ announce_test_start(test_spm_id_get);
+
+ if (spm_version >= MAKE_FFA_VERSION(1, 1)) {
+ struct ffa_value ret = ffa_spm_id_get();
+
+ expect(ffa_func_id(ret), FFA_SUCCESS_SMC32);
+
+ ffa_id_t spm_id = ffa_endpoint_id(ret);
+
+ VERBOSE("SPM ID = 0x%x\n", spm_id);
+ /*
+ * Check the SPMC value given in the fvp_spmc_manifest
+ * is returned.
+ */
+ expect(spm_id, SPMC_ID);
+ } else {
+ NOTICE("FFA_SPM_ID_GET not supported in this version of FF-A."
+ " Test skipped.\n");
+ }
+ announce_test_end(test_spm_id_get);
+}
+
+void ffa_console_log_test(void)
+{
+ const char *test_name = "FFA_CONSOLE_LOG SMC Function";
+ announce_test_start(test_name);
+
+ const char test_string[] = "[FFA_CONSOLE_LOG]: Hello World!\n";
+ struct ffa_value ret = ffa_console_log(test_string, sizeof(test_string));
+
+ expect(ffa_func_id(ret), FFA_SUCCESS_SMC32);
+
+ announce_test_end(test_name);
+}
+
+void ffa_tests(struct mailbox_buffers *mb)
+{
+ const char *test_ffa = "FFA Interfaces";
+
+ announce_test_section_start(test_ffa);
+
+ ffa_features_test();
+ ffa_version_test();
+ ffa_spm_id_get_test();
+ ffa_console_log_test();
+ ffa_partition_info_get_test(mb);
+
+ announce_test_section_end(test_ffa);
+}
diff --git a/spm/cactus/cactus_tests.h b/spm/common/sp_tests/sp_tests.h
index 1039ba5d..1039ba5d 100644
--- a/spm/cactus/cactus_tests.h
+++ b/spm/common/sp_tests/sp_tests.h
diff --git a/spm/common/spm_helpers.c b/spm/common/spm_helpers.c
index 2ccf3f7d..82fdae5c 100644
--- a/spm/common/spm_helpers.c
+++ b/spm/common/spm_helpers.c
@@ -49,3 +49,20 @@ int64_t spm_interrupt_enable(uint32_t int_id, bool enable, enum interrupt_pin pi
return (int64_t)ret.ret0;
}
+
+/**
+ * Hypervisor call to drop the priority and de-activate a secure interrupt.
+ * Returns 0 on success, or -1 if passing an invalid interrupt id.
+ */
+int64_t spm_interrupt_deactivate(uint32_t vint_id)
+{
+ hvc_args args = {
+ .fid = SPM_INTERRUPT_DEACTIVATE,
+ .arg1 = vint_id, /* pint_id */
+ .arg2 = vint_id
+ };
+
+ hvc_ret_values ret = tftf_hvc(&args);
+
+ return (int64_t)ret.ret0;
+}
diff --git a/spm/common/spm_helpers.h b/spm/common/spm_helpers.h
index 10f73161..25c6493c 100644
--- a/spm/common/spm_helpers.h
+++ b/spm/common/spm_helpers.h
@@ -13,6 +13,7 @@
/* Should match with IDs defined in SPM/Hafnium */
#define SPM_INTERRUPT_ENABLE (0xFF03)
#define SPM_INTERRUPT_GET (0xFF04)
+#define SPM_INTERRUPT_DEACTIVATE (0xFF08)
#define SPM_DEBUG_LOG (0xBD000000)
/*
@@ -21,6 +22,7 @@
uint32_t spm_interrupt_get(void);
int64_t spm_interrupt_enable(uint32_t int_id, bool enable, enum interrupt_pin pin);
+int64_t spm_interrupt_deactivate(uint32_t vint_id);
void spm_debug_log(char c);
#endif /* SPMC_H */
diff --git a/spm/ivy/aarch64/ivy_entrypoint.S b/spm/ivy/aarch64/ivy_entrypoint.S
deleted file mode 100644
index c6cb8b34..00000000
--- a/spm/ivy/aarch64/ivy_entrypoint.S
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <asm_macros.S>
-#include <ivy_def.h>
-#include <platform_def.h>
-
- .globl ivy_entrypoint
-
-.section .bss.stacks
- .balign CACHE_WRITEBACK_GRANULE
- .fill IVY_STACKS_SIZE
-stacks_end:
-
-func ivy_entrypoint
-
- /* Setup the stack pointer. */
- adr x0, stacks_end
- mov sp, x0
-
- /* And jump to the C entrypoint. */
- b ivy_main
-
-endfunc ivy_entrypoint
diff --git a/spm/ivy/app/aarch64/ivy_entrypoint.S b/spm/ivy/app/aarch64/ivy_entrypoint.S
new file mode 100644
index 00000000..062225c7
--- /dev/null
+++ b/spm/ivy/app/aarch64/ivy_entrypoint.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <ivy_def.h>
+#include <platform_def.h>
+
+ .globl ivy_entrypoint
+
+.section .bss.stacks
+ .balign CACHE_WRITEBACK_GRANULE
+ .fill IVY_STACKS_SIZE
+stacks_end:
+
+/* Call FFA_MEM_PERM_SET_32 to set the permissions of a given memory region. */
+.macro ffa_mem_perm_set start:req end:req perm:req
+ adrp x29, \start
+ add x29, x29, :lo12:\start
+
+ adrp x30, \end
+ add x30, x30, :lo12:\end
+
+ /* x30 = end - start */
+ sub x30, x30, x29
+ /* x28 = x30 >> 12 (number of pages) */
+ mov x28, #12
+ lsrv x28, x30, x28
+
+ /* 0x84000089 is function identifier for FFA_MEM_PERM_SET_32 */
+ mov w0, #0x89
+ movk w0, 0x8400, lsl #16
+ mov x1, x29 /* Base VA */
+ mov x2, x28 /* Page count */
+ mov w3, #\perm /* Memory permissions */
+ svc #0
+
+ /* 0x84000061 is function identifier for FFA_SUCCESS_32 */
+ mov w1, #0x61
+ movk w1, #0x8400, lsl #16
+ cmp w1, w0
+ b.ne .
+.endm
+
+func ivy_entrypoint
+
+ /* Setup the stack pointer. */
+ adr x0, stacks_end
+ mov sp, x0
+
+#if IVY_SHIM == 0
+ /* RODATA+DATA+BSS marked RW so relocations can succeed. */
+ ffa_mem_perm_set __RODATA_START__ __BSS_END__ 5
+
+ /* Relocate symbols */
+ivy_pie_fixup:
+ mov x0, #0x1000
+ mov x1, #IVY_IMAGE_SIZE
+ add x1, x1, x0
+ bl fixup_gdt_reloc
+
+ /* Clear S-EL0 partition BSS */
+ adrp x0, __BSS_START__
+ adrp x2, __BSS_END__
+ sub x2, x2, x0
+ mov x1, xzr
+ bl memset
+
+ /* Then mark RODATA as RO */
+ ffa_mem_perm_set __RODATA_START__ __RODATA_END__ 7
+#endif /* IVY_SHIM == 0 */
+
+ /* And jump to the C entrypoint. */
+ b ivy_main
+
+endfunc ivy_entrypoint
diff --git a/spm/ivy/app/ivy.h b/spm/ivy/app/ivy.h
new file mode 100644
index 00000000..a40f7e12
--- /dev/null
+++ b/spm/ivy/app/ivy.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IVY_H
+#define IVY_H
+
+#include <stdint.h>
+
+/* Linker symbols used to figure out the memory layout of the S-EL1 shim. */
+extern uintptr_t __SHIM_TEXT_START__, __SHIM_TEXT_END__;
+#define SHIM_TEXT_START ((uintptr_t)&__SHIM_TEXT_START__)
+#define SHIM_TEXT_END ((uintptr_t)&__SHIM_TEXT_END__)
+
+extern uintptr_t __SHIM_RODATA_START__, __SHIM_RODATA_END__;
+#define SHIM_RODATA_START ((uintptr_t)&__SHIM_RODATA_START__)
+#define SHIM_RODATA_END ((uintptr_t)&__SHIM_RODATA_END__)
+
+extern uintptr_t __SHIM_DATA_START__, __SHIM_DATA_END__;
+#define SHIM_DATA_START ((uintptr_t)&__SHIM_DATA_START__)
+#define SHIM_DATA_END ((uintptr_t)&__SHIM_DATA_END__)
+
+extern uintptr_t __SHIM_BSS_START__, __SHIM_BSS_END__;
+#define SHIM_BSS_START ((uintptr_t)&__SHIM_BSS_START__)
+#define SHIM_BSS_END ((uintptr_t)&__SHIM_BSS_END__)
+
+/* Linker symbols used to figure out the memory layout of Ivy (S-EL0). */
+extern uintptr_t __TEXT_START__, __TEXT_END__;
+#define IVY_TEXT_START ((uintptr_t)&__TEXT_START__)
+#define IVY_TEXT_END ((uintptr_t)&__TEXT_END__)
+
+extern uintptr_t __RODATA_START__, __RODATA_END__;
+#define IVY_RODATA_START ((uintptr_t)&__RODATA_START__)
+#define IVY_RODATA_END ((uintptr_t)&__RODATA_END__)
+
+extern uintptr_t __DATA_START__, __DATA_END__;
+#define IVY_DATA_START ((uintptr_t)&__DATA_START__)
+#define IVY_DATA_END ((uintptr_t)&__DATA_END__)
+
+extern uintptr_t __BSS_START__, __BSS_END__;
+#define IVY_BSS_START ((uintptr_t)&__BSS_START__)
+#define IVY_BSS_END ((uintptr_t)&__BSS_END__)
+
+#endif /* __IVY_H__ */
diff --git a/spm/ivy/ivy_def.h b/spm/ivy/app/ivy_def.h
index 729c46da..815a59e5 100644
--- a/spm/ivy/ivy_def.h
+++ b/spm/ivy/app/ivy_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,7 +12,7 @@
*/
/* Up to 2 MiB at an arbitrary address that doesn't overlap the devices. */
-#define IVY_IMAGE_BASE ULL(0x90000000)
+#define IVY_IMAGE_BASE ULL(0x1000)
#define IVY_IMAGE_SIZE ULL(0x200000)
/* Memory reserved for stacks */
diff --git a/spm/ivy/app/ivy_main.c b/spm/ivy/app/ivy_main.c
new file mode 100644
index 00000000..00988096
--- /dev/null
+++ b/spm/ivy/app/ivy_main.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <ffa_helpers.h>
+#include <sp_debug.h>
+#include <sp_helpers.h>
+
+#include "ivy.h"
+#include "sp_tests.h"
+
+/* Host machine information injected by the build system in the ELF file. */
+extern const char build_message[];
+extern const char version_string[];
+
+void __dead2 ivy_main(void)
+{
+ struct ffa_value ret;
+ ffa_id_t my_id;
+ struct mailbox_buffers mb;
+
+ set_putc_impl(SVC_CALL_AS_STDOUT);
+
+ /* Get FF-A id. */
+ ret = ffa_id_get();
+ if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
+ ERROR("Cannot get FF-A id.\n");
+ panic();
+ }
+ my_id = ffa_endpoint_id(ret);
+
+ NOTICE("Booting Secure Partition (ID: %x)\n", my_id);
+ NOTICE("%s\n", build_message);
+ NOTICE("%s\n", version_string);
+
+init:
+ VERBOSE("Mapping RXTX Regions\n");
+ CONFIGURE_AND_MAP_MAILBOX(mb, PAGE_SIZE, ret);
+ if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
+ ERROR("Failed to map RXTX buffers. Error %x\n",
+ ffa_error_code(ret));
+ panic();
+ }
+
+ ffa_tests(&mb);
+
+ ret = ffa_msg_wait();
+
+ while (1) {
+ if (ffa_func_id(ret) != FFA_MSG_SEND_DIRECT_REQ_SMC32) {
+ ERROR("unknown FF-A request %x\n", ffa_func_id(ret));
+ goto init;
+ }
+
+ VERBOSE("Received request: %lx\n", ret.arg3);
+
+ ret = ffa_msg_send_direct_resp32(my_id, ffa_dir_msg_source(ret),
+ 0, 0, 0, 0, 0);
+ }
+}
diff --git a/spm/ivy/app/plat/arm/fvp/fdts/ivy-sel0.dts b/spm/ivy/app/plat/arm/fvp/fdts/ivy-sel0.dts
new file mode 100644
index 00000000..76a5e3ce
--- /dev/null
+++ b/spm/ivy/app/plat/arm/fvp/fdts/ivy-sel0.dts
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file is a Partition Manifest (PM) for a minimal Secure Partition (SP)
+ * running in S-EL0 on top of Hafnium with VHE enabled (no S-EL1 shim included).
+ */
+
+
+/dts-v1/;
+
+/ {
+ compatible = "arm,ffa-manifest-1.0";
+
+ /* Properties */
+ description = "ivy-sel0-fvp";
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0xd883baea 0xaf4eafba 0xfdf74481 0xa744e5cb>;
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AARCH64 */
+ load-address = <0x7600000>;
+ entrypoint-offset = <0x00004000>;
+ boot-order = <0>;
+ messaging-method = <3>; /* Direct messaging only */
+
+ /* Boot protocol */
+ gp-register-num = <0x0>;
+};
diff --git a/spm/ivy/app/plat/arm/fvp/fdts/ivy-sel1.dts b/spm/ivy/app/plat/arm/fvp/fdts/ivy-sel1.dts
new file mode 100644
index 00000000..62f59b99
--- /dev/null
+++ b/spm/ivy/app/plat/arm/fvp/fdts/ivy-sel1.dts
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file is a Partition Manifest (PM) for a minimal Secure Partition (SP)
+ * intended to run at S-EL0 utilising a shim to run at S-EL1 on a
+ * non VHE enabled hafnium.
+ */
+
+
+/dts-v1/;
+
+/ {
+ compatible = "arm,ffa-manifest-1.0";
+
+ /* Properties */
+ description = "ivy-sel1-fvp";
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0xd883baea 0xaf4eafba 0xfdf74481 0xa744e5cb>;
+ execution-ctx-count = <1>;
+ exception-level = <2>; /* S-EL1 */
+ execution-state = <0>; /* AARCH64 */
+ load-address = <0x7600000>;
+ entrypoint-offset = <0x00004000>;
+ boot-order = <0>;
+ messaging-method = <3>; /* Direct messaging only */
+
+ /* Boot protocol */
+ gp-register-num = <0x0>;
+};
diff --git a/spm/ivy/app/plat/arm/fvp/include/sp_platform_def.h b/spm/ivy/app/plat/arm/fvp/include/sp_platform_def.h
new file mode 100644
index 00000000..b17f006f
--- /dev/null
+++ b/spm/ivy/app/plat/arm/fvp/include/sp_platform_def.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * This file contains common defines for a secure partition. The correct
+ * platform_def.h header file is selected according to the secure partition
+ * and platform being built using the make scripts.
+ */
+
+#ifndef SP_PLATFORM_DEF_H
+#define SP_PLATFORM_DEF_H
+
+#define PLAT_SP_RX_BASE ULL(0x7300000)
+
+#endif /* SP_PLATFORM_DEF_H */
diff --git a/spm/ivy/app/plat/arm/fvp/platform.mk b/spm/ivy/app/plat/arm/fvp/platform.mk
new file mode 100644
index 00000000..3b9be337
--- /dev/null
+++ b/spm/ivy/app/plat/arm/fvp/platform.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+FVP_IVY_BASE = spm/ivy/app/plat/arm/fvp
+
+PLAT_INCLUDES += -I${FVP_IVY_BASE}/include/
+
+# Add the FDT source
+ifeq ($(IVY_SHIM),0)
+IVY_DTS = ${FVP_IVY_BASE}/fdts/ivy-sel0.dts
+else
+IVY_DTS = ${FVP_IVY_BASE}/fdts/ivy-sel1.dts
+endif
+
+# List of FDTS to copy
+FDTS_CP_LIST = $(IVY_DTS)
diff --git a/spm/ivy/app/plat/arm/tc0/fdts/ivy-sel0.dts b/spm/ivy/app/plat/arm/tc0/fdts/ivy-sel0.dts
new file mode 100644
index 00000000..93e7da3f
--- /dev/null
+++ b/spm/ivy/app/plat/arm/tc0/fdts/ivy-sel0.dts
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file is a Partition Manifest (PM) for a minimal Secure Partition (SP)
+ * running in S-EL0 on top of Hafnium with VHE enabled (no S-EL1 shim included).
+ */
+
+/dts-v1/;
+
+/ {
+ compatible = "arm,ffa-manifest-1.0";
+
+ /* Properties */
+ description = "ivy-sel0-tc0";
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0xd883baea 0xaf4eafba 0xfdf74481 0xa744e5cb>;
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AARCH64 */
+ load-address = <0xfe280000>;
+ entrypoint-offset = <0x00004000>;
+ boot-order = <0>;
+ messaging-method = <3>; /* Direct messaging only */
+
+ /* Boot protocol */
+ gp-register-num = <0x0>;
+};
diff --git a/spm/ivy/app/plat/arm/tc0/fdts/ivy-sel1.dts b/spm/ivy/app/plat/arm/tc0/fdts/ivy-sel1.dts
new file mode 100644
index 00000000..1d4df602
--- /dev/null
+++ b/spm/ivy/app/plat/arm/tc0/fdts/ivy-sel1.dts
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file is a Partition Manifest (PM) for a minimal Secure Partition (SP)
+ * intended to run at S-EL0 utilising a shim to run at S-EL1 on a
+ * non VHE enabled hadnium.
+ */
+
+/dts-v1/;
+
+/ {
+ compatible = "arm,ffa-manifest-1.0";
+
+ /* Properties */
+ description = "ivy-sel1-tc0";
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0xd883baea 0xaf4eafba 0xfdf74481 0xa744e5cb>;
+ execution-ctx-count = <1>;
+ exception-level = <2>; /* S-EL1 */
+ execution-state = <0>; /* AARCH64 */
+ load-address = <0xfe280000>;
+ entrypoint-offset = <0x00004000>;
+ boot-order = <0>;
+ messaging-method = <3>; /* Direct messaging only */
+
+ /* Boot protocol */
+ gp-register-num = <0x0>;
+};
diff --git a/spm/ivy/app/plat/arm/tc0/include/sp_platform_def.h b/spm/ivy/app/plat/arm/tc0/include/sp_platform_def.h
new file mode 100644
index 00000000..326cb134
--- /dev/null
+++ b/spm/ivy/app/plat/arm/tc0/include/sp_platform_def.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * This file contains common defines for a secure partition. The correct
+ * platform_def.h header file is selected according to the secure partition
+ * and platform being built using the make scripts.
+ */
+
+#ifndef SP_PLATFORM_DEF_H
+#define SP_PLATFORM_DEF_H
+
+#define PLAT_SP_RX_BASE ULL(0x7300000)
+
+#endif /* SP_PLATFORM_DEF_H */
diff --git a/spm/ivy/app/plat/arm/tc0/platform.mk b/spm/ivy/app/plat/arm/tc0/platform.mk
new file mode 100644
index 00000000..72b15217
--- /dev/null
+++ b/spm/ivy/app/plat/arm/tc0/platform.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TC0_IVY_BASE = spm/ivy/app/plat/arm/tc0
+
+PLAT_INCLUDES += -I${TC0_IVY_BASE}/include/
+
+# Add the FDT source
+ifeq ($(IVY_SHIM),0)
+IVY_DTS = ${TC0_IVY_BASE}/fdts/ivy-sel0.dts
+else
+IVY_DTS = ${TC0_IVY_BASE}/fdts/ivy-sel1.dts
+endif
+
+# List of FDTS to copy
+FDTS_CP_LIST = $(IVY_DTS)
diff --git a/spm/ivy/ivy.dts b/spm/ivy/ivy.dts
deleted file mode 100644
index 4c5a11a1..00000000
--- a/spm/ivy/ivy.dts
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <sp_res_desc_def.h>
-
-#include "ivy_def.h"
-
-/* 4 KiB pages */
-#define PAGE_SIZE U(0x1000)
-
-/*
- * FVP platform layout. The defines are hardcoded here because including the
- * platform headers have too many dependencies.
- * TODO: Move this to the platform layer.
- */
-#define V2M_IOFPGA_BASE ULL(0x1c000000)
-#define V2M_IOFPGA_SIZE ULL(0x03000000)
-
-/* Aggregate of all devices in the first GB. */
-#define DEVICE0_BASE ULL(0x20000000)
-#define DEVICE0_SIZE ULL(0x0c200000)
-
-/dts-v1/;
-
-/ {
- compatible = "arm,sp_rd";
-
- attribute {
- version = <0x00000001>;
- sp_type = <RD_ATTR_TYPE_UP_MIGRATABLE>;
- pe_mpidr = <0>; /* Unused */
- runtime_el = <RD_ATTR_RUNTIME_SEL0>;
- exec_type = <RD_ATTR_RUNTIME>;
- panic_policy = <RD_ATTR_PANIC_ONESHOT>;
- xlat_granule = <RD_ATTR_XLAT_GRANULE_4KB>;
- binary_size = <IVY_IMAGE_SIZE>;
- load_address = <0x00000000 IVY_IMAGE_BASE>;
- entrypoint = <0x00000000 IVY_IMAGE_BASE>;
- };
-
- memory_regions {
- v2m_iofpga {
- str = "V2M IOFPGA";
- base = <0x00000000 V2M_IOFPGA_BASE>;
- size = <0x00000000 V2M_IOFPGA_SIZE>;
- attr = <RD_MEM_DEVICE>;
- };
-
- device0 {
- str = "Device 0";
- base = <0x00000000 DEVICE0_BASE>;
- size = <0x00000000 DEVICE0_SIZE>;
- attr = <RD_MEM_DEVICE>;
- };
-
- spm_buffer {
- str = "SPM buffer";
- base = <0x00000000 IVY_SPM_BUF_BASE>;
- size = <0x00000000 IVY_SPM_BUF_SIZE>;
- attr = <RD_MEM_NORMAL_SPM_SP_SHARED_MEM>;
- };
-
- ns_buffer {
- str = "NS buffer";
- base = <0x00000000 IVY_NS_BUF_BASE>;
- size = <0x00000000 IVY_NS_BUF_SIZE>;
- attr = <RD_MEM_NORMAL_CLIENT_SHARED_MEM>;
- };
- };
-
- notifications {
- notification_0 {
- attr = <0>;
- pe = <0>;
- };
- };
-
- services {
- test_service_1 {
- uuid = <IVY_SERVICE1_UUID_RD>;
-
- accessibility = <(RD_SERV_ACCESS_SECURE |
- RD_SERV_ACCESS_EL3 |
- RD_SERV_ACCESS_NORMAL)>;
- request_type = <(RD_SERV_SUPPORT_BLOCKING |
- RD_SERV_SUPPORT_NON_BLOCKING)>;
- connection_quota = <10>;
- sec_mem_size = <0>;
- interrupt_num = <0>;
- };
- };
-};
diff --git a/spm/ivy/ivy.h b/spm/ivy/ivy.h
deleted file mode 100644
index c5cac2e0..00000000
--- a/spm/ivy/ivy.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef IVY_H
-#define IVY_H
-
-#include <stdint.h>
-
-/* Linker symbols used to figure out the memory layout of Ivy. */
-extern uintptr_t __TEXT_START__, __TEXT_END__;
-#define IVY_TEXT_START ((uintptr_t)&__TEXT_START__)
-#define IVY_TEXT_END ((uintptr_t)&__TEXT_END__)
-
-extern uintptr_t __RODATA_START__, __RODATA_END__;
-#define IVY_RODATA_START ((uintptr_t)&__RODATA_START__)
-#define IVY_RODATA_END ((uintptr_t)&__RODATA_END__)
-
-extern uintptr_t __DATA_START__, __DATA_END__;
-#define IVY_DATA_START ((uintptr_t)&__DATA_START__)
-#define IVY_DATA_END ((uintptr_t)&__DATA_END__)
-
-extern uintptr_t __BSS_START__, __BSS_END__;
-#define IVY_BSS_START ((uintptr_t)&__BSS_START__)
-#define IVY_BSS_END ((uintptr_t)&__BSS_END__)
-
-#endif /* __IVY_H__ */
diff --git a/spm/ivy/ivy.ld.S b/spm/ivy/ivy.ld.S
index 634db155..b21201ba 100644
--- a/spm/ivy/ivy.ld.S
+++ b/spm/ivy/ivy.ld.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,7 +10,13 @@
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+
+#if IVY_SHIM == 1
+ENTRY(shim_entrypoint)
+#else
ENTRY(ivy_entrypoint)
+#endif
+
SECTIONS
{
@@ -19,6 +25,48 @@ SECTIONS
ASSERT(. == ALIGN(PAGE_SIZE),
"TEXT_START address is not aligned to PAGE_SIZE.")
+#if IVY_SHIM == 1
+
+ .shim_text : {
+ __SHIM_TEXT_START__ = .;
+ *spm_shim_entrypoint.o(.text*)
+ *(.vectors)
+ . = NEXT(PAGE_SIZE);
+ __SHIM_TEXT_END__ = .;
+ }
+
+ .shim_rodata : {
+ . = ALIGN(PAGE_SIZE);
+ __SHIM_RODATA_START__ = .;
+
+ . = NEXT(PAGE_SIZE);
+ __SHIM_RODATA_END__ = .;
+ }
+
+ .shim_data : {
+ . = ALIGN(PAGE_SIZE);
+ __SHIM_DATA_START__ = .;
+
+ . = NEXT(PAGE_SIZE);
+ __SHIM_DATA_END__ = .;
+ }
+
+ .shim_bss (NOLOAD) : {
+ . = ALIGN(PAGE_SIZE);
+ __SHIM_BSS_START__ = .;
+
+ *(.bss.shim_stacks)
+ *(.bss.tf_base_xlat_table)
+ *(.bss.tf_mmap)
+ *xlat_tables_context.o(COMMON)
+ *xlat_tables_context.o(xlat_table)
+
+ . = NEXT(PAGE_SIZE);
+ __SHIM_BSS_END__ = .;
+ }
+
+#endif
+
.text : {
__TEXT_START__ = .;
*ivy_entrypoint.o(.text*)
@@ -32,6 +80,17 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
__RODATA_START__ = .;
*(.rodata*)
+
+ /*
+ * Keep the .got section in the RO section as it is patched
+ * prior to enabling the MMU, so having it in RO is better for
+ * security. GOT is a table of addresses so ensure 8-byte alignment.
+ */
+ . = ALIGN(8);
+ __GOT_START__ = .;
+ *(.got)
+ __GOT_END__ = .;
+
. = NEXT(PAGE_SIZE);
__RODATA_END__ = .;
}
@@ -44,6 +103,18 @@ SECTIONS
__DATA_END__ = .;
}
+ /*
+ * .rela.dyn needs to come after .data for the read-elf utility
+ * to parse this section correctly. Ensure 8-byte alignment so
+ * that the fields of RELA data structure are aligned.
+ */
+ . = ALIGN(8);
+ __RELA_START__ = .;
+ .rela.dyn . : {
+ }
+ __RELA_END__ = .;
+
+
.bss (NOLOAD) : {
. = ALIGN(PAGE_SIZE);
__BSS_START__ = .;
diff --git a/spm/ivy/ivy.mk b/spm/ivy/ivy.mk
index a5000496..2e6cbfa8 100644
--- a/spm/ivy/ivy.mk
+++ b/spm/ivy/ivy.mk
@@ -1,51 +1,85 @@
#
-# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
include branch_protection.mk
-include lib/sprt/sprt_client.mk
+include lib/xlat_tables_v2/xlat_tables.mk
-IVY_DTB := $(BUILD_PLAT)/ivy.dtb
+# Include ivy platform Makefile
+IVY_PLAT_PATH := $(shell find spm/ivy/app/plat -wholename '*/${PLAT}')
+ifneq (${IVY_PLAT_PATH},)
+ include ${IVY_PLAT_PATH}/platform.mk
+endif
+
+IVY_SHIM := 1
+
+ifeq (${IVY_SHIM},1)
+ IVY_DTB := $(BUILD_PLAT)/ivy-sel1.dtb
+ SECURE_PARTITIONS += ivy_shim
+else
+ IVY_DTB := $(BUILD_PLAT)/ivy-sel0.dtb
+ SECURE_PARTITIONS += ivy
+endif
IVY_INCLUDES := \
+ -Itftf/framework/include \
-Iinclude \
-Iinclude/common \
-Iinclude/common/${ARCH} \
-Iinclude/lib \
-Iinclude/lib/${ARCH} \
- -Iinclude/lib/sprt \
-Iinclude/lib/utils \
-Iinclude/lib/xlat_tables \
+ -Iinclude/plat/common \
-Iinclude/runtime_services \
-Iinclude/runtime_services/secure_el0_payloads \
- -Ispm/ivy \
+ -Ispm/ivy/app \
+ -Ispm/ivy/shim \
-Ispm/common \
- ${SPRT_LIB_INCLUDES}
+ -Ispm/common/sp_tests/
IVY_SOURCES := \
- $(addprefix spm/ivy/, \
+ $(addprefix spm/ivy/app/, \
aarch64/ivy_entrypoint.S \
ivy_main.c \
) \
$(addprefix spm/common/, \
- aarch64/sp_arch_helpers.S \
+ sp_debug.c \
sp_helpers.c \
+ spm_helpers.c \
) \
+ $(addprefix spm/common/sp_tests/, \
+ sp_test_ffa.c \
+ )
-# TODO: Remove dependency on TFTF files.
+ifeq ($(IVY_SHIM),1)
IVY_SOURCES += \
- tftf/framework/debug.c \
- tftf/framework/${ARCH}/asm_debug.S
+ $(addprefix spm/ivy/shim/, \
+ aarch64/spm_shim_entrypoint.S \
+ aarch64/spm_shim_exceptions.S \
+ shim_main.c \
+ )
+endif
+
+# TODO: Remove dependency on TFTF files.
+IVY_SOURCES += \
+ tftf/framework/debug.c \
+ tftf/framework/${ARCH}/asm_debug.S \
+ tftf/tests/runtime_services/secure_service/${ARCH}/ffa_arch_helpers.S \
+ tftf/tests/runtime_services/secure_service/ffa_helpers.c \
+ tftf/tests/runtime_services/secure_service/spm_common.c
IVY_SOURCES += drivers/arm/pl011/${ARCH}/pl011_console.S \
- drivers/console/console.c \
lib/${ARCH}/cache_helpers.S \
lib/${ARCH}/misc_helpers.S \
+ lib/smc/${ARCH}/asm_smc.S \
+ lib/smc/${ARCH}/smc.c \
+ lib/smc/${ARCH}/hvc.c \
lib/locks/${ARCH}/spinlock.S \
lib/utils/mp_printf.c \
- ${SPRT_LIB_SOURCES}
+ ${XLAT_TABLES_LIB_SRCS}
IVY_LINKERFILE := spm/ivy/ivy.ld.S
@@ -57,19 +91,34 @@ $(eval $(call add_define,IVY_DEFINES,DEBUG))
$(eval $(call add_define,IVY_DEFINES,ENABLE_ASSERTIONS))
$(eval $(call add_define,IVY_DEFINES,ENABLE_BTI))
$(eval $(call add_define,IVY_DEFINES,ENABLE_PAUTH))
-$(eval $(call add_define,IVY_DEFINES,FVP_CLUSTER_COUNT))
-$(eval $(call add_define,IVY_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
-$(eval $(call add_define,IVY_DEFINES,FVP_MAX_PE_PER_CPU))
$(eval $(call add_define,IVY_DEFINES,LOG_LEVEL))
$(eval $(call add_define,IVY_DEFINES,PLAT_${PLAT}))
+$(eval $(call add_define,IVY_DEFINES,IVY_SHIM))
$(IVY_DTB) : $(BUILD_PLAT)/ivy $(BUILD_PLAT)/ivy/ivy.elf
-$(IVY_DTB) : spm/ivy/ivy.dts
- @echo " DTBGEN spm/ivy/ivy.dts"
+$(IVY_DTB) : $(IVY_DTS)
+ @echo " DTBGEN $@"
${Q}tools/generate_dtb/generate_dtb.sh \
- ivy spm/ivy/ivy.dts $(BUILD_PLAT)
+ ivy ${IVY_DTS} $(BUILD_PLAT) $(IVY_DTB)
@echo
@echo "Built $@ successfully"
@echo
-ivy: $(IVY_DTB)
+ivy: $(IVY_DTB) SP_LAYOUT
+
+# FDTS_CP copies flattened device tree sources
+# $(1) = output directory
+# $(2) = flattened device tree source file to copy
+define FDTS_CP
+ $(eval FDTS := $(addprefix $(1)/,$(notdir $(2))))
+FDTS_LIST += $(FDTS)
+$(FDTS): $(2) $(IVY_DTB)
+ @echo " CP $$<"
+ ${Q}cp $$< $$@
+endef
+
+ifdef FDTS_CP_LIST
+ $(eval files := $(filter %.dts,$(FDTS_CP_LIST)))
+ $(eval $(foreach file,$(files),$(call FDTS_CP,$(BUILD_PLAT),$(file))))
+ivy: $(FDTS_LIST)
+endif
diff --git a/spm/ivy/ivy_main.c b/spm/ivy/ivy_main.c
deleted file mode 100644
index 8542150b..00000000
--- a/spm/ivy/ivy_main.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <debug.h>
-#include <drivers/console.h>
-#include <drivers/arm/pl011.h>
-#include <errno.h>
-#include <ivy_def.h>
-#include <plat_arm.h>
-#include <platform_def.h>
-#include <sp_helpers.h>
-#include <sprt_client.h>
-#include <sprt_svc.h>
-
-#include "ivy.h"
-#include "ivy_def.h"
-
-/* Host machine information injected by the build system in the ELF file. */
-extern const char build_message[];
-extern const char version_string[];
-
-static void ivy_print_memory_layout(void)
-{
- NOTICE("Secure Partition memory layout:\n");
-
- NOTICE(" Image regions\n");
- NOTICE(" Text region : %p - %p\n",
- (void *)IVY_TEXT_START, (void *)IVY_TEXT_END);
- NOTICE(" Read-only data region : %p - %p\n",
- (void *)IVY_RODATA_START, (void *)IVY_RODATA_END);
- NOTICE(" Data region : %p - %p\n",
- (void *)IVY_DATA_START, (void *)IVY_DATA_END);
- NOTICE(" BSS region : %p - %p\n",
- (void *)IVY_BSS_START, (void *)IVY_BSS_END);
- NOTICE(" Total image memory : %p - %p\n",
- (void *)IVY_IMAGE_BASE,
- (void *)(IVY_IMAGE_BASE + IVY_IMAGE_SIZE));
- NOTICE(" SPM regions\n");
- NOTICE(" SPM <-> SP buffer : %p - %p\n",
- (void *)IVY_SPM_BUF_BASE,
- (void *)(IVY_SPM_BUF_BASE + IVY_SPM_BUF_SIZE));
- NOTICE(" NS <-> SP buffer : %p - %p\n",
- (void *)IVY_NS_BUF_BASE,
- (void *)(IVY_NS_BUF_BASE + IVY_NS_BUF_SIZE));
-}
-
-void ivy_message_handler(struct sprt_queue_entry_message *message)
-{
- u_register_t ret0 = 0U, ret1 = 0U, ret2 = 0U, ret3 = 0U;
-
- if (message->type == SPRT_MSG_TYPE_SERVICE_REQUEST) {
- switch (message->args[1]) {
-
- case IVY_PRINT_MAGIC:
- INFO("IVY: Magic: 0x%x\n", IVY_MAGIC_NUMBER);
- ret0 = SPRT_SUCCESS;
- break;
-
- case IVY_GET_MAGIC:
- ret1 = IVY_MAGIC_NUMBER;
- ret0 = SPRT_SUCCESS;
- break;
-
- case IVY_SLEEP_MS:
- sp_sleep(message->args[2]);
- ret0 = SPRT_SUCCESS;
- break;
-
- default:
- NOTICE("IVY: Unhandled Service ID 0x%x\n",
- (unsigned int)message->args[1]);
- ret0 = SPRT_NOT_SUPPORTED;
- break;
- }
- } else {
- NOTICE("Ivy: Unhandled Service type 0x%x\n",
- (unsigned int)message->type);
- ret0 = SPRT_NOT_SUPPORTED;
- }
-
-
- sprt_message_end(message, ret0, ret1, ret2, ret3);
-}
-
-void __dead2 ivy_main(void)
-{
- console_init(PL011_UART3_BASE,
- PL011_UART3_CLK_IN_HZ,
- PL011_BAUDRATE);
-
- NOTICE("Booting test Secure Partition Ivy\n");
- NOTICE("%s\n", build_message);
- NOTICE("%s\n", version_string);
- NOTICE("Running at S-EL0\n");
-
- ivy_print_memory_layout();
-
- /*
- * Handle secure service requests.
- */
- sprt_initialize_queues((void *)IVY_SPM_BUF_BASE);
-
- while (1) {
- struct sprt_queue_entry_message message;
-
- /*
- * Try to fetch a message from the blocking requests queue. If
- * it is empty, try to fetch from the non-blocking requests
- * queue. Repeat until both of them are empty.
- */
- while (1) {
- int err = sprt_get_next_message(&message,
- SPRT_QUEUE_NUM_BLOCKING);
- if (err == -ENOENT) {
- err = sprt_get_next_message(&message,
- SPRT_QUEUE_NUM_NON_BLOCKING);
- if (err == -ENOENT) {
- break;
- } else {
- assert(err == 0);
- ivy_message_handler(&message);
- }
- } else {
- assert(err == 0);
- ivy_message_handler(&message);
- }
- }
-
- sprt_wait_for_messages();
- }
-}
diff --git a/spm/ivy/shim/aarch64/spm_shim_entrypoint.S b/spm/ivy/shim/aarch64/spm_shim_entrypoint.S
new file mode 100644
index 00000000..55d8dd8a
--- /dev/null
+++ b/spm/ivy/shim/aarch64/spm_shim_entrypoint.S
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <ivy_def.h>
+#include <platform_def.h>
+
+ .globl shim_entrypoint
+
+.section .bss.shim_stacks
+ .balign CACHE_WRITEBACK_GRANULE
+ .fill IVY_STACKS_SIZE
+shim_stacks_end:
+
+func shim_entrypoint
+
+ /* Setup the stack pointer. */
+ adr x0, shim_stacks_end
+ mov sp, x0
+
+ /* Setup vector base address */
+ adr x0, spm_shim_exceptions_ptr
+ msr vbar_el1, x0
+ isb
+
+ /*
+ * Invalidate the data cache for the shim and whole partition.
+ * This prevents re-use of stale data cache entries from prior
+ * bootloader stages.
+ */
+ adrp x0, __SHIM_TEXT_START__
+ adrp x1, __BSS_END__
+ sub x1, x1, x0
+ bl inv_dcache_range
+
+ /* Enable I-Cache */
+ mrs x0, sctlr_el1
+ orr x0, x0, #SCTLR_I_BIT
+ msr sctlr_el1, x0
+ isb
+
+ /* Relocate symbols */
+shim_pie_fixup:
+ ldr x0, =shim_pie_fixup
+ and x0, x0, #~(0x1000 - 1)
+ mov x1, #IVY_IMAGE_SIZE
+ add x1, x1, x0
+ bl fixup_gdt_reloc
+
+ /* Clear S-EL1 shim BSS */
+ adrp x0, __SHIM_BSS_START__
+ adrp x2, __SHIM_BSS_END__
+ sub x2, x2, x0
+ mov x1, xzr
+ bl memset
+
+ /* Clear S-EL0 partition BSS */
+ adrp x0, __BSS_START__
+ adrp x2, __BSS_END__
+ sub x2, x2, x0
+ mov x1, xzr
+ bl memset
+
+ /* And jump to the C entrypoint. */
+ bl shim_main
+
+ /* Exception return to S-EL0 Ivy application code */
+ adrp x0, ivy_entrypoint
+ msr elr_el1, x0
+
+ /* AArch64 EL0t */
+ mov x0, #((DAIF_FIQ_BIT | DAIF_IRQ_BIT) << SPSR_DAIF_SHIFT)
+ msr spsr_el1, x0
+
+ /* TODO: clear GP/SIMD registers */
+ /* TODO: tune EL0 system registers */
+
+ eret
+
+endfunc shim_entrypoint
diff --git a/spm/ivy/shim/aarch64/spm_shim_exceptions.S b/spm/ivy/shim/aarch64/spm_shim_exceptions.S
new file mode 100644
index 00000000..07527e6e
--- /dev/null
+++ b/spm/ivy/shim/aarch64/spm_shim_exceptions.S
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+/* -----------------------------------------------------------------------------
+ * Very simple stackless exception handlers used by the spm shim layer.
+ * -----------------------------------------------------------------------------
+ */
+ .globl spm_shim_exceptions_ptr
+
+vector_base spm_shim_exceptions_ptr
+
+ /* -----------------------------------------------------
+ * Current EL with SP0 : 0x0 - 0x200
+ * -----------------------------------------------------
+ */
+vector_entry_spin sync_exception_sp_el0
+
+vector_entry_spin irq_sp_el0
+
+vector_entry_spin fiq_ep_el0
+
+vector_entry_spin serror_ep_el0
+
+ /* -----------------------------------------------------
+ * Current EL with SPx: 0x200 - 0x400
+ * -----------------------------------------------------
+ */
+vector_entry_spin sync_exception_sp_elx
+
+vector_entry_spin irq_sp_elx
+
+vector_entry_spin fiq_sp_elx
+
+vector_entry_spin serror_sp_elx
+
+ /* -----------------------------------------------------
+ * Lower EL using AArch64 : 0x400 - 0x600. No exceptions
+ * are handled since secure_partition does not implement
+ * a lower EL
+ * -----------------------------------------------------
+ */
+vector_entry sync_exception_aarch64
+ 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
+end_vector_entry sync_exception_aarch64
+
+vector_entry_spin irq_aarch64
+
+vector_entry_spin fiq_aarch64
+
+vector_entry_spin serror_aarch64
+
+ /* -----------------------------------------------------
+ * Lower EL using AArch32 : 0x600 - 0x800
+ * -----------------------------------------------------
+ */
+vector_entry_spin sync_exception_aarch32
+
+vector_entry_spin irq_aarch32
+
+vector_entry_spin fiq_aarch32
+
+vector_entry_spin serror_aarch32
diff --git a/spm/ivy/shim/shim_main.c b/spm/ivy/shim/shim_main.c
new file mode 100644
index 00000000..1d6c7239
--- /dev/null
+++ b/spm/ivy/shim/shim_main.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <errno.h>
+#include <ffa_helpers.h>
+#include <lib/aarch64/arch_helpers.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <sp_debug.h>
+#include <sp_helpers.h>
+#include <std_svc.h>
+
+#include "ivy.h"
+#include "ivy_def.h"
+
+static void shim_print_memory_layout(void)
+{
+ INFO("Secure Partition memory layout:\n");
+
+ INFO(" Image regions\n");
+ INFO(" Text region : %p - %p\n",
+ (void *)IVY_TEXT_START, (void *)IVY_TEXT_END);
+ INFO(" Read-only data region : %p - %p\n",
+ (void *)IVY_RODATA_START, (void *)IVY_RODATA_END);
+ INFO(" Data region : %p - %p\n",
+ (void *)IVY_DATA_START, (void *)IVY_DATA_END);
+ INFO(" BSS region : %p - %p\n",
+ (void *)IVY_BSS_START, (void *)IVY_BSS_END);
+ INFO(" Total image memory : %p - %p\n",
+ (void *)IVY_IMAGE_BASE,
+ (void *)(IVY_IMAGE_BASE + IVY_IMAGE_SIZE));
+ INFO(" SPM regions\n");
+ INFO(" SPM <-> SP buffer : %p - %p\n",
+ (void *)IVY_SPM_BUF_BASE,
+ (void *)(IVY_SPM_BUF_BASE + IVY_SPM_BUF_SIZE));
+ INFO(" NS <-> SP buffer : %p - %p\n",
+ (void *)IVY_NS_BUF_BASE,
+ (void *)(IVY_NS_BUF_BASE + IVY_NS_BUF_SIZE));
+}
+
+static void shim_plat_configure_mmu(void)
+{
+ mmap_add_region(SHIM_TEXT_START,
+ SHIM_TEXT_START,
+ SHIM_TEXT_END - SHIM_TEXT_START,
+ MT_CODE | MT_PRIVILEGED);
+ mmap_add_region(SHIM_RODATA_START,
+ SHIM_RODATA_START,
+ SHIM_RODATA_END - SHIM_RODATA_START,
+ MT_RO_DATA | MT_PRIVILEGED);
+ mmap_add_region(SHIM_DATA_START,
+ SHIM_DATA_START,
+ SHIM_DATA_END - SHIM_DATA_START,
+ MT_RW_DATA | MT_PRIVILEGED);
+ mmap_add_region(SHIM_BSS_START,
+ SHIM_BSS_START,
+ SHIM_BSS_END - SHIM_BSS_START,
+ MT_RW_DATA | MT_PRIVILEGED);
+ mmap_add_region(IVY_TEXT_START,
+ IVY_TEXT_START,
+ IVY_TEXT_END - IVY_TEXT_START,
+ MT_CODE | MT_USER);
+ mmap_add_region(IVY_RODATA_START,
+ IVY_RODATA_START,
+ IVY_RODATA_END - IVY_RODATA_START,
+ MT_RO_DATA | MT_USER);
+ mmap_add_region(IVY_DATA_START,
+ IVY_DATA_START,
+ IVY_DATA_END - IVY_DATA_START,
+ MT_RW_DATA | MT_USER);
+ mmap_add_region(IVY_BSS_START,
+ IVY_BSS_START,
+ IVY_BSS_END - IVY_BSS_START,
+ MT_RW_DATA | MT_USER);
+
+ init_xlat_tables();
+}
+
+int shim_main(void)
+{
+ assert(IS_IN_EL1() != 0);
+
+ /* Initialise console */
+ set_putc_impl(HVC_CALL_AS_STDOUT);
+
+ /* Configure and enable Stage-1 MMU, enable D-Cache */
+ shim_plat_configure_mmu();
+ enable_mmu_el1(0);
+
+ INFO("Booting S-EL1 Shim\n");
+
+ shim_print_memory_layout();
+
+ return 0;
+}
diff --git a/spm/quark/quark.mk b/spm/quark/quark.mk
index 0fe1646a..fb2851dc 100644
--- a/spm/quark/quark.mk
+++ b/spm/quark/quark.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -63,7 +63,7 @@ $(QUARK_DTB) : $(BUILD_PLAT)/quark $(BUILD_PLAT)/quark/quark.elf
$(QUARK_DTB) : spm/quark/quark.dts
@echo " DTBGEN spm/quark/quark.dts"
${Q}tools/generate_dtb/generate_dtb.sh \
- quark spm/quark/quark.dts $(BUILD_PLAT)
+ quark spm/quark/quark.dts $(BUILD_PLAT) $(QUARK_DTB)
@echo
@echo "Built $@ successfully"
@echo
diff --git a/tftf/framework/aarch64/exceptions.S b/tftf/framework/aarch64/exceptions.S
index 677b30fe..3dedb923 100644
--- a/tftf/framework/aarch64/exceptions.S
+++ b/tftf/framework/aarch64/exceptions.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -23,38 +23,40 @@ vector_base tftf_vector
/*
* Current EL with SP0 : 0x0 - 0x200.
*/
-unhandled_exception SynchronousExceptionSP0
-unhandled_exception IrqSP0
-unhandled_exception FiqSP0
-unhandled_exception SErrorSP0
+unhandled_exception sync_exception_sp_el0
+unhandled_exception irq_sp_el0
+unhandled_exception fiq_sp_el0
+unhandled_exception serror_sp_el0
/*
* Current EL with SPx : 0x200 - 0x400.
*/
-unhandled_exception SynchronousExceptionSPx
+vector_entry sync_spx
+ b sync_exception_vector_entry
+end_vector_entry sync_spx
-vector_entry IrqSPx
+vector_entry irq_sp_elx
b irq_vector_entry
-end_vector_entry IrqSPx
+end_vector_entry irq_sp_elx
-unhandled_exception FiqSPx
-unhandled_exception SErrorSPx
+unhandled_exception fiq_sp_elx
+unhandled_exception serror_sp_elx
/*
* Lower EL using AArch64 : 0x400 - 0x600.
*/
-unhandled_exception SynchronousExceptionA64
-unhandled_exception IrqA64
-unhandled_exception FiqA64
-unhandled_exception SErrorA64
+unhandled_exception sync_exception_aarch64
+unhandled_exception irq_aarch64
+unhandled_exception fiq_aarch64
+unhandled_exception serror_aarch64
/*
* Lower EL using AArch32 : 0x600 - 0x800.
*/
-unhandled_exception SynchronousExceptionA32
-unhandled_exception IrqA32
-unhandled_exception FiqA32
-unhandled_exception SErrorA32
+unhandled_exception sync_exception_aarch32
+unhandled_exception irq_aarch32
+unhandled_exception fiq_aarch32
+unhandled_exception serror_aarch32
.macro save_gp_regs
stp x0, x1, [sp, #0x0]
@@ -95,6 +97,22 @@ unhandled_exception SErrorA32
ldp x0, x1, [sp, #0x0]
.endm
+func sync_exception_vector_entry
+ sub sp, sp, #0x100
+ save_gp_regs
+ mov x19, sp
+ bl tftf_sync_exception_handler
+ cbnz x0, 0f
+ mov x0, x19
+ /* Save original stack pointer value on the stack */
+ add x1, x0, #0x100
+ str x1, [x0, #0xf8]
+ b print_exception
+0: restore_gp_regs
+ add sp, sp, #0x100
+ eret
+endfunc sync_exception_vector_entry
+
func irq_vector_entry
sub sp, sp, #0x100
save_gp_regs
diff --git a/tftf/framework/framework.mk b/tftf/framework/framework.mk
index 8ec18ea9..11026f2d 100644
--- a/tftf/framework/framework.mk
+++ b/tftf/framework/framework.mk
@@ -53,7 +53,7 @@ FRAMEWORK_SOURCES += \
lib/events/events.c \
lib/extensions/amu/${ARCH}/amu.c \
lib/extensions/amu/${ARCH}/amu_helpers.S \
- lib/irq/irq.c \
+ lib/exceptions/irq.c \
lib/locks/${ARCH}/spinlock.S \
lib/power_management/hotplug/hotplug.c \
lib/power_management/suspend/${ARCH}/asm_tftf_suspend.S \
@@ -79,8 +79,11 @@ FRAMEWORK_SOURCES += ${COMPILER_RT_SRCS}
ifeq (${ARCH},aarch64)
# ARMv8.3 Pointer Authentication support files
FRAMEWORK_SOURCES += \
+ lib/exceptions/aarch64/sync.c \
lib/extensions/pauth/aarch64/pauth.c \
- lib/extensions/pauth/aarch64/pauth_helpers.S
+ lib/extensions/pauth/aarch64/pauth_helpers.S \
+ lib/extensions/sme/aarch64/sme.c \
+ lib/extensions/sme/aarch64/sme_helpers.S
endif
TFTF_LINKERFILE := tftf/framework/tftf.ld.S
diff --git a/tftf/framework/main.c b/tftf/framework/main.c
index 2350b962..a203bd2f 100644
--- a/tftf/framework/main.c
+++ b/tftf/framework/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,6 +25,8 @@
#include <tftf_lib.h>
#include <timer.h>
+#define MIN_RETRY_TO_POWER_ON_LEAD_CPU 10
+
/* version information for TFTF */
extern const char version_string[];
@@ -309,6 +311,7 @@ static unsigned int close_test(void)
static void __dead2 hand_over_to_lead_cpu(void)
{
int ret;
+ unsigned int tftf_cpu_pwr_on_ctr = 0U;
unsigned int mpid = read_mpidr_el1() & MPID_MASK;
unsigned int core_pos = platform_get_core_pos(mpid);
@@ -321,8 +324,24 @@ static void __dead2 hand_over_to_lead_cpu(void)
* doesn't matter because it will be overwritten by prepare_next_test().
* Pass a NULL pointer to easily catch the problem in case something
* goes wrong.
+ *
+ * In CI with four world system (Normal, Secure, Root and Realm), on few
+ * instances, while the framework tries to turn on the CPU for next-test
+ * it fails to do so and receives error code (-4 : ALREADY_ON).
+ * This is due to the fact that the lead-cpu is still powering down as
+ * per EL-3 but invisible to EL-2. Hence retrying it in a loop with a
+ * small delay in bewteen for certain iterations will resolve it.
*/
- ret = tftf_cpu_on(lead_cpu_mpid, 0, 0);
+ while (tftf_cpu_pwr_on_ctr < MIN_RETRY_TO_POWER_ON_LEAD_CPU) {
+ ret = tftf_cpu_on(lead_cpu_mpid, 0, 0);
+ if (ret == PSCI_E_SUCCESS) {
+ break;
+ } else {
+ tftf_cpu_pwr_on_ctr += 1;
+ waitms(1);
+ }
+ }
+
if (ret != PSCI_E_SUCCESS) {
ERROR("CPU%u: Failed to power on lead CPU%u (%d)\n",
core_pos, platform_get_core_pos(lead_cpu_mpid), ret);
@@ -531,7 +550,7 @@ void __dead2 tftf_cold_boot_main(void)
* authentication would fail then.
*/
#if ENABLE_PAUTH
- assert(is_armv8_3_pauth_apa_api_present());
+ assert(is_armv8_3_pauth_apa_api_apa3_present());
/*
* Program APIAKey_EL1 key and enable ARMv8.3-PAuth here as this
diff --git a/tftf/tests/common/test_helpers.c b/tftf/tests/common/test_helpers.c
index d794bebc..f4995796 100644
--- a/tftf/tests/common/test_helpers.c
+++ b/tftf/tests/common/test_helpers.c
@@ -1,10 +1,11 @@
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
+#include <cactus_test_cmds.h>
#include <plat_topology.h>
#include <platform.h>
#include <power_management.h>
@@ -172,7 +173,129 @@ test_result_t check_spmc_testing_set_up(
GET_TFTF_MAILBOX(mb);
for (unsigned int i = 0U; i < ffa_uuids_size; i++)
- SKIP_TEST_IF_FFA_ENDPOINT_NOT_DEPLOYED(*mb, ffa_uuids[i].uuid);
+ SKIP_TEST_IF_FFA_ENDPOINT_NOT_DEPLOYED(*mb, ffa_uuids[i]);
return TEST_RESULT_SUCCESS;
}
+
+test_result_t spm_run_multi_core_test(uintptr_t cpu_on_handler,
+ event_t *cpu_done)
+{
+ unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos, cpu_node, mpidr;
+ int32_t ret;
+
+ VERBOSE("Powering on all cpus.\n");
+
+ for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+ tftf_init_event(&cpu_done[i]);
+ }
+
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+
+ ret = tftf_cpu_on(mpidr, cpu_on_handler, 0U);
+ if (ret != 0) {
+ ERROR("tftf_cpu_on mpidr 0x%x returns %d\n",
+ mpidr, ret);
+ }
+ }
+
+ VERBOSE("Waiting secondary CPUs to turn off ...\n");
+
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+
+ core_pos = platform_get_core_pos(mpidr);
+ tftf_wait_for_event(&cpu_done[core_pos]);
+ }
+
+ VERBOSE("Done exiting.\n");
+
+ return TEST_RESULT_SUCCESS;
+}
+
+bool spm_core_sp_init(ffa_id_t sp_id)
+{
+ /*
+ * Secure Partitions secondary ECs need one round of ffa_run to reach
+ * the message loop.
+ */
+ if (sp_id != SP_ID(1)) {
+ uint32_t core_pos = get_current_core_id();
+ struct ffa_value ret = ffa_run(sp_id, core_pos);
+
+ if (ffa_func_id(ret) != FFA_MSG_WAIT) {
+ ERROR("Failed to run SP%x on core %u\n",
+ sp_id, core_pos);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool spm_set_managed_exit_int(ffa_id_t sp_id, bool enable)
+{
+ struct ffa_value ret;
+
+ ret = cactus_interrupt_cmd(HYP_ID, sp_id, MANAGED_EXIT_INTERRUPT_ID,
+ enable, INTERRUPT_TYPE_FIQ);
+
+ if (!is_ffa_direct_response(ret) ||
+ cactus_get_response(ret) != CACTUS_SUCCESS) {
+ ERROR("Failed to enable Managed exit interrupt\n");
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Initializes the Mailbox for other SPM related tests that need to use
+ * RXTX buffers.
+ */
+bool mailbox_init(struct mailbox_buffers mb)
+{
+ struct ffa_value ret;
+
+ ffa_rxtx_unmap();
+ CONFIGURE_AND_MAP_MAILBOX(mb, PAGE_SIZE, ret);
+ if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
+ ERROR("Failed to map RXTX buffers %x!\n", ffa_error_code(ret));
+ return false;
+ }
+ set_tftf_mailbox(&mb);
+ return true;
+}
+
+/*
+ * Utility function to wait for all CPUs other than the caller to be
+ * OFF.
+ */
+void wait_for_non_lead_cpus(void)
+{
+ unsigned int target_mpid, target_node;
+
+ for_each_cpu(target_node) {
+ target_mpid = tftf_get_mpidr_from_node(target_node);
+ wait_for_core_to_turn_off(target_mpid);
+ }
+}
+
+void wait_for_core_to_turn_off(unsigned int mpidr)
+{
+ /* Skip lead CPU, as it is powered on */
+ if (mpidr == (read_mpidr_el1() & MPID_MASK))
+ return;
+
+ while (tftf_psci_affinity_info(mpidr, MPIDR_AFFLVL0) != PSCI_STATE_OFF) {
+ continue;
+ }
+}
diff --git a/tftf/tests/extensions/afp/test_afp.c b/tftf/tests/extensions/afp/test_afp.c
new file mode 100644
index 00000000..625d9cf4
--- /dev/null
+++ b/tftf/tests/extensions/afp/test_afp.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <test_helpers.h>
+
+test_result_t test_afp_support(void)
+{
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ test_result_t ret;
+ uint64_t saved_fpcr, fpcr;
+
+ SKIP_TEST_IF_AFP_NOT_SUPPORTED();
+
+ saved_fpcr = read_fpcr();
+ /* Write advanced floating point controlling bits */
+ write_fpcr(saved_fpcr | FPCR_FIZ_BIT | FPCR_AH_BIT | FPCR_NEP_BIT);
+
+ fpcr = read_fpcr();
+ /* Check if all bits got written successfully */
+ if ((fpcr | ~(FPCR_FIZ_BIT | FPCR_AH_BIT | FPCR_NEP_BIT)) == ~0ULL) {
+ ret = TEST_RESULT_SUCCESS;
+ } else {
+ ret = TEST_RESULT_FAIL;
+ }
+
+ write_fpcr(saved_fpcr);
+
+ return ret;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/extensions/brbe/test_brbe.c b/tftf/tests/extensions/brbe/test_brbe.c
new file mode 100644
index 00000000..f2c244a3
--- /dev/null
+++ b/tftf/tests/extensions/brbe/test_brbe.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <tftf.h>
+
+/*
+ * EL3 is expected to allow access to branch record buffer control registers
+ * from NS world. Accessing these registers will trap to EL3 and crash when EL3
+ * has not properly enabled it.
+ */
+test_result_t test_brbe_enabled(void)
+{
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ SKIP_TEST_IF_BRBE_NOT_SUPPORTED();
+
+ read_brbcr_el1();
+ read_brbcr_el2();
+ read_brbfcr_el1();
+ read_brbts_el1();
+ read_brbinfinj_el1();
+ read_brbsrcinj_el1();
+ read_brbtgtinj_el1();
+ read_brbidr0_el1();
+
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/extensions/hcx/test_hcx.c b/tftf/tests/extensions/hcx/test_hcx.c
new file mode 100644
index 00000000..ebc6e818
--- /dev/null
+++ b/tftf/tests/extensions/hcx/test_hcx.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <tftf_lib.h>
+#include <tftf.h>
+#include <arch_helpers.h>
+#include <arch_features.h>
+
+/* This very simple test just ensures that HCRX_EL2 access does not trap. */
+test_result_t test_feat_hcx_enabled(void)
+{
+#ifdef __aarch64__
+ /* Make sure FEAT_HCX is supported. */
+ if (!get_feat_hcx_support()) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /* Attempt to read HCRX_EL2, if not enabled this should trap to EL3. */
+ read_hcrx_el2();
+
+ /* If we make it this far, the test was successful. */
+ return TEST_RESULT_SUCCESS;
+#else
+ /* Skip test if AArch32 */
+ return TEST_RESULT_SKIPPED;
+#endif
+}
diff --git a/tftf/tests/extensions/pauth/test_pauth.c b/tftf/tests/extensions/pauth/test_pauth.c
index 30b78ef1..b7434a81 100644
--- a/tftf/tests/extensions/pauth/test_pauth.c
+++ b/tftf/tests/extensions/pauth/test_pauth.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -60,7 +60,7 @@ static void set_store_pauth_keys(void)
memset(pauth_keys_before, 0, NUM_KEYS * sizeof(uint128_t));
- if (is_armv8_3_pauth_apa_api_present()) {
+ if (is_armv8_3_pauth_apa_api_apa3_present()) {
if (is_pauth_key_enabled(SCTLR_EnIA_BIT)) {
/* Read APIAKey_EL1 */
plat_key = read_apiakeylo_el1() |
@@ -119,7 +119,7 @@ static void set_store_pauth_keys(void)
* APGAKey_EL1 can be re-programmed, as this key is not set in
* TF-A Test suite and PACGA instruction is not used.
*/
- if (is_armv8_3_pauth_gpa_gpi_present()) {
+ if (is_armv8_3_pauth_gpa_gpi_gpa3_present()) {
/* Program APGAKey_EL1 */
plat_key = init_apkey();
write_apgakeylo_el1((uint64_t)plat_key);
@@ -138,7 +138,7 @@ static void read_pauth_keys(void)
{
memset(pauth_keys_after, 0, NUM_KEYS * sizeof(uint128_t));
- if (is_armv8_3_pauth_apa_api_present()) {
+ if (is_armv8_3_pauth_apa_api_apa3_present()) {
/* Read APIAKey_EL1 */
pauth_keys_after[0] = read_apiakeylo_el1() |
((uint128_t)(read_apiakeyhi_el1()) << 64);
@@ -156,7 +156,7 @@ static void read_pauth_keys(void)
((uint128_t)(read_apdbkeyhi_el1()) << 64);
}
- if (is_armv8_3_pauth_gpa_gpi_present()) {
+ if (is_armv8_3_pauth_gpa_gpi_gpa3_present()) {
/* Read APGAKey_EL1 */
pauth_keys_after[4] = read_apgakeylo_el1() |
((uint128_t)(read_apgakeyhi_el1()) << 64);
diff --git a/tftf/tests/extensions/rng_trap/test_rndr_trap.c b/tftf/tests/extensions/rng_trap/test_rndr_trap.c
new file mode 100644
index 00000000..423c78f5
--- /dev/null
+++ b/tftf/tests/extensions/rng_trap/test_rndr_trap.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <test_helpers.h>
+#include <tftf.h>
+#include <tftf_lib.h>
+
+/*
+ * This very simple test just ensures that a RNDR read access causes a trap
+ * to EL3.
+ */
+test_result_t test_rndr_trap_enabled(void)
+{
+#if defined __aarch64__
+ /* Make sure FEAT_RNG_TRAP is supported. */
+ SKIP_TEST_IF_RNG_TRAP_NOT_SUPPORTED();
+
+ /* Attempt to read RNDR. */
+ read_rndr();
+
+ /*
+ * If we make it this far, the test fails, as there was no trap
+ * to EL3 triggered.
+ */
+ return TEST_RESULT_FAIL;
+#else
+ /* Skip test if AArch32 */
+ SKIP_TEST_IF_AARCH32();
+#endif
+}
diff --git a/tftf/tests/extensions/rng_trap/test_rndrrs_trap.c b/tftf/tests/extensions/rng_trap/test_rndrrs_trap.c
new file mode 100644
index 00000000..e9beb537
--- /dev/null
+++ b/tftf/tests/extensions/rng_trap/test_rndrrs_trap.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <test_helpers.h>
+#include <tftf.h>
+#include <tftf_lib.h>
+
+/*
+ * This very simple test just ensures that a RNDRRS read access causes a trap
+ * to EL3.
+ */
+test_result_t test_rndrrs_trap_enabled(void)
+{
+#if defined __aarch64__
+ /* Make sure FEAT_RNG_TRAP is supported. */
+ SKIP_TEST_IF_RNG_TRAP_NOT_SUPPORTED();
+
+ /* Attempt to read RNDR. */
+ read_rndrrs();
+
+ /*
+ * If we make it this far, the test fails, as there was no trap
+ * to EL3 triggered.
+ */
+ return TEST_RESULT_FAIL;
+#else
+ /* Skip test if AArch32 */
+ SKIP_TEST_IF_AARCH32();
+#endif
+}
diff --git a/tftf/tests/extensions/sme/test_sme.c b/tftf/tests/extensions/sme/test_sme.c
new file mode 100644
index 00000000..4bf6e59e
--- /dev/null
+++ b/tftf/tests/extensions/sme/test_sme.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/extensions/sme.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+test_result_t test_sme_support(void)
+{
+ /* SME is an AArch64-only feature.*/
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ u_register_t reg;
+ unsigned int current_vector_len;
+ unsigned int requested_vector_len;
+ unsigned int len_max;
+
+ /* Skip the test if SME is not supported. */
+ if (!feat_sme_supported()) {
+ INFO("SME not supported, skipping.\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /* Enable SME for use at NS EL2. */
+ if (sme_enable() != 0) {
+ ERROR("Could not enable SME.\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure TPIDR2_EL0 is accessible. */
+ write_tpidr2_el0(0);
+ if (read_tpidr2_el0() != 0) {
+ ERROR("Could not read TPIDR2_EL0.\n");
+ return TEST_RESULT_FAIL;
+ }
+ write_tpidr2_el0(0xb0bafe77);
+ if (read_tpidr2_el0() != 0xb0bafe77) {
+ ERROR("Could not write TPIDR2_EL0.\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure we can start and stop streaming mode. */
+ VERBOSE("Entering Streaming SVE mode.\n");
+ sme_smstart(false);
+ read_smcr_el2();
+ sme_smstop(false);
+ sme_smstart(true);
+ read_smcr_el2();
+ sme_smstop(true);
+
+ /*
+ * Iterate through values for LEN to detect supported vector lengths.
+ * SME instructions aren't supported by GCC yet so for now this is all
+ * we'll do.
+ */
+ sme_smstart(false);
+
+ /* Write SMCR_EL2 with the LEN max to find implemented width. */
+ write_smcr_el2(SME_SMCR_LEN_MAX);
+ len_max = (unsigned int)read_smcr_el2();
+ VERBOSE("Maximum SMCR_EL2.LEN value: 0x%x\n", len_max);
+ VERBOSE("Enumerating supported vector lengths...\n");
+ for (unsigned int i = 0; i <= len_max; i++) {
+ /* Load new value into SMCR_EL2.LEN */
+ reg = read_smcr_el2();
+ reg &= ~(SMCR_ELX_LEN_MASK << SMCR_ELX_LEN_SHIFT);
+ reg |= (i << SMCR_ELX_LEN_SHIFT);
+ write_smcr_el2(reg);
+
+ /* Compute current and requested vector lengths in bits. */
+ current_vector_len = ((unsigned int)sme_rdvl_1() * 8U);
+ requested_vector_len = (i+1U)*128U;
+
+ /*
+ * We count down from the maximum SMLEN value, so if the values
+ * match, we've found the largest supported value for SMLEN.
+ */
+ if (current_vector_len == requested_vector_len) {
+ VERBOSE("SUPPORTED: %u bits (LEN=%u)\n", requested_vector_len, i);
+ } else {
+ VERBOSE("NOT SUPPORTED: %u bits (LEN=%u)\n", requested_vector_len, i);
+ }
+ }
+ sme_smstop(false);
+
+ /* If FEAT_SME_FA64 then attempt to execute an illegal instruction. */
+ if (feat_sme_fa64_supported()) {
+ VERBOSE("FA64 supported, trying illegal instruction.\n");
+ sme_try_illegal_instruction();
+ }
+
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/extensions/spe/test_spe.c b/tftf/tests/extensions/spe/test_spe.c
new file mode 100644
index 00000000..8b18654f
--- /dev/null
+++ b/tftf/tests/extensions/spe/test_spe.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <test_helpers.h>
+
+#ifdef __aarch64__
+/*
+ * Get SPE version value from id_aa64dfr0_el1.
+ * Return values
+ * ID_AA64DFR0_SPE_NOT_SUPPORTED: not supported
+ * ID_AA64DFR0_SPE: FEAT_SPE supported (introduced in ARM v8.2)
+ * ID_AA64DFR0_SPE_V1P1: FEAT_SPEv1p1 supported (introduced in ARM v8.5)
+ * ID_AA64DFR0_SPE_V1P2: FEAT_SPEv1p2 supported (introduced in ARM v8.7)
+ */
+
+typedef enum {
+ ID_AA64DFR0_SPE_NOT_SUPPORTED = 0,
+ ID_AA64DFR0_SPE,
+ ID_AA64DFR0_SPE_V1P1,
+ ID_AA64DFR0_SPE_V1P2
+} spe_ver_t;
+
+static spe_ver_t spe_get_version(void)
+{
+ return (spe_ver_t)((read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT) &
+ ID_AA64DFR0_PMS_MASK);
+}
+#endif /* __aarch64__ */
+
+test_result_t test_spe_support(void)
+{
+ /* SPE is an AArch64-only feature.*/
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ spe_ver_t spe_ver = spe_get_version();
+
+ assert(spe_ver <= ID_AA64DFR0_SPE_V1P2);
+
+ if (spe_ver == ID_AA64DFR0_SPE_NOT_SUPPORTED) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /*
+ * If runtime-EL3 does not enable access to SPE system
+ * registers from NS-EL2/NS-EL1 then read of these
+ * registers traps in EL3
+ */
+ read_pmscr_el1();
+ read_pmsfcr_el1();
+ read_pmsicr_el1();
+ read_pmsidr_el1();
+ read_pmsirr_el1();
+ read_pmslatfr_el1();
+ read_pmblimitr_el1();
+ read_pmbptr_el1();
+ read_pmbsr_el1();
+ read_pmsevfr_el1();
+ if (IS_IN_EL2()) {
+ read_pmscr_el2();
+ }
+ if (spe_ver == ID_AA64DFR0_SPE_V1P2) {
+ read_pmsnevfr_el1();
+ }
+
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/extensions/sve/test_sve.c b/tftf/tests/extensions/sve/test_sve.c
index 235e2b8e..eabc0de4 100644
--- a/tftf/tests/extensions/sve/test_sve.c
+++ b/tftf/tests/extensions/sve/test_sve.c
@@ -8,6 +8,7 @@
#include <arch_helpers.h>
#include <debug.h>
#include <stdlib.h>
+#include <test_helpers.h>
#include <tftf_lib.h>
#include "./test_sve.h"
@@ -32,11 +33,7 @@ static int sve_op_2[SVE_ARRAYSIZE];
*/
test_result_t test_sve_support(void)
{
- /* Check if SVE is implemented and usable */
- if (is_armv8_2_sve_present() == false) {
- tftf_testcase_printf("SVE support absent\n");
- return TEST_RESULT_SKIPPED;
- }
+ SKIP_TEST_IF_SVE_NOT_SUPPORTED();
for (int i = 0; i < SVE_ARRAYSIZE; i++) {
/* Generate a random number between 200 and 299 */
diff --git a/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.c b/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.c
new file mode 100644
index 00000000..6c28c871
--- /dev/null
+++ b/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <tftf.h>
+
+#include "./test_sys_reg_trace.h"
+
+static uint32_t get_trace_arch_ver(void)
+{
+ uint32_t val = read_trcdevarch();
+ val = (val >> TRCDEVARCH_ARCHVER_SHIFT) & TRCDEVARCH_ARCHVER_MASK;
+
+ return val;
+}
+
+/*
+ * EL3 is expected to allow access to trace system registers from EL2.
+ * Reading these register will trap to EL3 and crash when EL3 has not
+ * allowed access.
+ */
+test_result_t test_sys_reg_trace_enabled(void)
+{
+ SKIP_TEST_IF_SYS_REG_TRACE_NOT_SUPPORTED();
+
+ /*
+ * Read few ETMv4 system trace registers to verify correct access
+ * been provided from EL3.
+ */
+ uint32_t trace_arch_ver __unused = get_trace_arch_ver();
+ read_trcauxctlr();
+ read_trcccctlr();
+ read_trcbbctlr();
+ read_trcclaimset();
+ read_trcclaimclr();
+
+ /*
+ * Read few ETE system trace registers to verify correct access
+ * been provided from EL3. ETE system trace register access are
+ * not possible from NS-EL2 in aarch32 state.
+ */
+#if __aarch64__
+ if (trace_arch_ver == TRCDEVARCH_ARCHVER_ETE) {
+ read_trcrsr();
+ read_trcextinselr0();
+ read_trcextinselr1();
+ read_trcextinselr2();
+ read_trcextinselr3();
+ }
+#endif /* __aarch64__ */
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.h b/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.h
new file mode 100644
index 00000000..640b82c2
--- /dev/null
+++ b/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEST_SYS_REG_TRACE_H
+#define TEST_SYS_REG_TRACE_H
+
+/* TRCEDEVARCH definitions */
+#define TRCDEVARCH_ARCHVER_SHIFT U(12)
+#define TRCDEVARCH_ARCHVER_MASK U(0xf)
+#define TRCDEVARCH_ARCHVER_ETE U(0x5)
+
+#endif /* TEST_SYS_REG_TRACE_H */
diff --git a/tftf/tests/extensions/trbe/test_trbe.c b/tftf/tests/extensions/trbe/test_trbe.c
new file mode 100644
index 00000000..8ef9576e
--- /dev/null
+++ b/tftf/tests/extensions/trbe/test_trbe.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <tftf.h>
+
+/*
+ * EL3 is expected to allow access to trace control registers from EL2.
+ * Reading these register will trap to EL3 and crash when EL3 has not
+ * allowed access.
+ */
+test_result_t test_trbe_enabled(void)
+{
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ SKIP_TEST_IF_TRBE_NOT_SUPPORTED();
+ read_trblimitr_el1();
+ read_trbptr_el1();
+ read_trbbaser_el1();
+ read_trbsr_el1();
+ read_trbmar_el1();
+ read_trbtrg_el1();
+ read_trbidr_el1();
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/extensions/trf/test_trf.c b/tftf/tests/extensions/trf/test_trf.c
new file mode 100644
index 00000000..eeb967db
--- /dev/null
+++ b/tftf/tests/extensions/trf/test_trf.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <tftf.h>
+
+/*
+ * EL3 is expected to allow access to trace filter control registers from EL2.
+ * Reading these register will trap to EL3 and crash when EL3 has not
+ * allowed access.
+ */
+test_result_t test_trf_enabled(void)
+{
+ SKIP_TEST_IF_TRF_NOT_SUPPORTED();
+
+#ifdef __aarch64__
+ read_trfcr_el1();
+ read_trfcr_el2();
+#else
+ read_htrfcr();
+ read_trfcr();
+#endif /* __aarch64__ */
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/extensions/wfxt/test_wfxt.c b/tftf/tests/extensions/wfxt/test_wfxt.c
new file mode 100644
index 00000000..bb3e4866
--- /dev/null
+++ b/tftf/tests/extensions/wfxt/test_wfxt.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <arch.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+typedef enum {
+ EXEC_WFIT = 0,
+ EXEC_WFET
+} exec_wfxt;
+
+#ifdef __aarch64__
+static test_result_t test_wfxt_inst(exec_wfxt val, uint64_t ms)
+{
+ __asm__ volatile(".arch armv8.7-a");
+ uint64_t timer_cnt1, timer_cnt2, feed_cnt;
+ uint64_t timer_freq = read_cntfrq_el0();
+ uint64_t ms_to_counts = ((ms * timer_freq) / 1000U);
+
+ timer_cnt1 = virtualcounter_read();
+ feed_cnt = timer_cnt1 + ms_to_counts;
+
+ if (val == EXEC_WFIT) {
+ wfit(feed_cnt);
+ } else {
+ wfet(feed_cnt);
+ }
+
+ timer_cnt2 = virtualcounter_read();
+
+ /* Lapsed time should be at least equal to sleep time */
+ if ((timer_cnt2 - timer_cnt1) >= ms_to_counts) {
+ return TEST_RESULT_SUCCESS;
+ } else {
+ /* unlikely ends up here */
+ uint64_t lapsed_ms = ((timer_cnt2 - timer_cnt1) * 1000) / timer_freq;
+
+ ERROR("Time elapsed: actual(%llu)ms vs requested(%llu)ms \n",
+ lapsed_ms, ms);
+ return TEST_RESULT_FAIL;
+ }
+}
+#endif /* __aarch64__ */
+
+test_result_t test_wfet_instruction(void)
+{
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ SKIP_TEST_IF_WFXT_NOT_SUPPORTED();
+
+ /*
+ * first invocation of wfe returns immediately clearing the event
+ * register
+ */
+ sevl();
+ wfe();
+
+ return test_wfxt_inst(EXEC_WFET, 10);
+#endif /* __aarch64__ */
+}
+
+test_result_t test_wfit_instruction(void)
+{
+ test_result_t ret;
+
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ SKIP_TEST_IF_WFXT_NOT_SUPPORTED();
+
+ /* disable irqs to run wfi till timeout */
+ disable_irq();
+
+ ret = test_wfxt_inst(EXEC_WFIT, 10);
+
+ /* enable irq back */
+ enable_irq();
+#endif /* __aarch64__ */
+
+ return ret;
+}
diff --git a/tftf/tests/misc_tests/inject_serror.S b/tftf/tests/misc_tests/inject_serror.S
index d42441dd..fd51f855 100644
--- a/tftf/tests/misc_tests/inject_serror.S
+++ b/tftf/tests/misc_tests/inject_serror.S
@@ -27,6 +27,7 @@ func inject_serror_record
/* Clear SError received flag if necessary */
cbz x3, 1f
str xzr, [x3, #0]
+ dsb st
1:
/* Choose Error record 0 on the PE */
msr ERRSELR_EL1, x0
@@ -52,6 +53,7 @@ func inject_serror_record
2:
wfe
+ dsb st
ldr x0, [x3, #0]
cbz x0, 2b
diff --git a/tftf/tests/misc_tests/test_invalid_access.c b/tftf/tests/misc_tests/test_invalid_access.c
new file mode 100644
index 00000000..14be340d
--- /dev/null
+++ b/tftf/tests/misc_tests/test_invalid_access.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <debug.h>
+#ifdef __aarch64__
+#include <sync.h>
+#endif
+#include <test_helpers.h>
+#include <lib/aarch64/arch_features.h>
+#include <runtime_services/realm_payload/realm_payload_test.h>
+#include <tftf_lib.h>
+#include <xlat_tables_v2.h>
+
+#include <platform_def.h>
+#include <cactus_test_cmds.h>
+#include <ffa_endpoints.h>
+
+
+/*
+ * Using "__aarch64__" here looks weird but its unavoidable because of following reason
+ * This test is part of standard test which runs on all platforms but pre-requisite
+ * to run this test (custom sync exception handler) is only implemented for aarch64.
+ * TODO: Write a framework so that tests kept in standard list can be selectively
+ * run on a given architecture
+ */
+#ifdef __aarch64__
+
+#define SENDER HYP_ID
+#define RECEIVER SP_ID(1)
+
+static volatile bool sync_exception_triggered;
+static volatile bool data_abort_triggered;
+static const struct ffa_uuid expected_sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
+};
+
+static __aligned(PAGE_SIZE) uint64_t share_page[PAGE_SIZE / sizeof(uint64_t)];
+
+static bool data_abort_handler(void)
+{
+ uint64_t esr_elx = IS_IN_EL2() ? read_esr_el2() : read_esr_el1();
+ unsigned int rme_supported = get_armv9_2_feat_rme_support();
+
+ sync_exception_triggered = true;
+
+ VERBOSE("%s esr_elx %llx\n", __func__, esr_elx);
+
+ if (EC_BITS(esr_elx) == EC_DABORT_CUR_EL) {
+ if (rme_supported == 0) {
+ /* Synchronous external data abort triggered by trustzone controller */
+ if ((ISS_BITS(esr_elx) & ISS_DFSC_MASK) == DFSC_EXT_DABORT) {
+ VERBOSE("%s TZC Data Abort caught\n", __func__);
+ data_abort_triggered = true;
+ return true;
+ }
+ } else {
+ /* Synchronous data abort triggered by Granule protection */
+ if ((ISS_BITS(esr_elx) & ISS_DFSC_MASK) == DFSC_GPF_DABORT) {
+ VERBOSE("%s GPF Data Abort caught\n", __func__);
+ data_abort_triggered = true;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+test_result_t el3_memory_cannot_be_accessed_in_ns(void)
+{
+ const uintptr_t test_address = EL3_MEMORY_ACCESS_ADDR;
+
+ VERBOSE("Attempt to access el3 memory (0x%lx)\n", test_address);
+
+ sync_exception_triggered = false;
+ data_abort_triggered = false;
+
+ int rc = mmap_add_dynamic_region(test_address, test_address, PAGE_SIZE,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (rc != 0) {
+ tftf_testcase_printf("%d: mmap_add_dynamic_region() = %d\n", __LINE__, rc);
+ return TEST_RESULT_FAIL;
+ }
+
+ register_custom_sync_exception_handler(data_abort_handler);
+ *((volatile uint64_t *)test_address);
+ unregister_custom_sync_exception_handler();
+
+ rc = mmap_remove_dynamic_region(test_address, PAGE_SIZE);
+ if (rc != 0) {
+ tftf_testcase_printf("%d: mmap_remove_dynamic_region() = %d\n", __LINE__, rc);
+ return TEST_RESULT_FAIL;
+ }
+
+ if (sync_exception_triggered == false) {
+ tftf_testcase_printf("No sync exception while accessing (0x%lx)\n", test_address);
+ return TEST_RESULT_SKIPPED;
+ }
+
+ if (data_abort_triggered == false) {
+ tftf_testcase_printf("Sync exception is not data abort\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * @Test_Aim@ Check a realm region cannot be accessed from normal world.
+ *
+ * This test delegates a TFTF allocated buffer to Realm. It then attempts
+ * a read access to the region from normal world. This results in the PE
+ * triggering a GPF caught by a custom synchronous abort handler.
+ *
+ */
+test_result_t rl_memory_cannot_be_accessed_in_ns(void)
+{
+ test_result_t result = TEST_RESULT_FAIL;
+ u_register_t retmm;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ sync_exception_triggered = false;
+ data_abort_triggered = false;
+ register_custom_sync_exception_handler(data_abort_handler);
+
+ /* First read access to the test region must not fail. */
+ *((volatile uint64_t *)share_page);
+
+ if ((sync_exception_triggered != false) ||
+ (data_abort_triggered != false)) {
+ goto out_unregister;
+ }
+
+ /* Delegate the shared page to Realm. */
+ retmm = realm_granule_delegate((u_register_t)&share_page);
+ if (retmm != 0UL) {
+ ERROR("Granule delegate failed!\n");
+ goto out_unregister;
+ }
+
+ /* This access shall trigger a GPF. */
+ *((volatile uint64_t *)share_page);
+
+ if ((sync_exception_triggered != true) ||
+ (data_abort_triggered != true)) {
+ goto out_undelegate;
+ }
+
+ result = TEST_RESULT_SUCCESS;
+
+out_undelegate:
+ /* Undelegate the shared page. */
+ retmm = realm_granule_undelegate((u_register_t)&share_page);
+ if (retmm != 0UL) {
+ ERROR("Granule undelegate failed!\n");
+ }
+
+out_unregister:
+ unregister_custom_sync_exception_handler();
+
+ return result;
+}
+
+/**
+ * @Test_Aim@ Check a secure region cannot be accessed from normal world.
+ *
+ * Following test intends to run on RME enabled platforms when EL3
+ * is Root world. In a non RME platform, EL3 is secure.
+ * Access to secure memory from NS world is already covered
+ * by el3_memory_cannot_be_accessed_in_ns.
+ */
+test_result_t s_memory_cannot_be_accessed_in_ns(void)
+{
+ const uintptr_t test_address = SECURE_MEMORY_ACCESS_ADDR;
+
+ /* skipp non RME platforms */
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ VERBOSE("Attempt to access secure memory (0x%lx)\n", test_address);
+
+ data_abort_triggered = false;
+ sync_exception_triggered = false;
+ register_custom_sync_exception_handler(data_abort_handler);
+ dsbsy();
+
+ int rc = mmap_add_dynamic_region(test_address, test_address, PAGE_SIZE,
+ MT_MEMORY | MT_RW | MT_NS);
+
+ if (rc != 0) {
+ tftf_testcase_printf("%d: mmap_add_dynamic_region() = %d\n", __LINE__, rc);
+ return TEST_RESULT_FAIL;
+ }
+
+ *((volatile uint64_t *)test_address);
+
+ mmap_remove_dynamic_region(test_address, PAGE_SIZE);
+
+ dsbsy();
+ unregister_custom_sync_exception_handler();
+
+ if (sync_exception_triggered == false) {
+ tftf_testcase_printf("No sync exception while accessing (0x%lx)\n", test_address);
+ return TEST_RESULT_SKIPPED;
+ }
+
+ if (data_abort_triggered == false) {
+ tftf_testcase_printf("Sync exception is not data abort\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+static test_result_t memory_cannot_be_accessed_in_rl(u_register_t params)
+{
+ u_register_t retrmm;
+ static char rd[GRANULE_SIZE] __aligned(GRANULE_SIZE);
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ retrmm = realm_version();
+
+ VERBOSE("RMM version is: %lu.%lu\n",
+ RMI_ABI_VERSION_GET_MAJOR(retrmm),
+ RMI_ABI_VERSION_GET_MINOR(retrmm));
+
+ /*
+ * TODO: Remove this once SMC_RMM_REALM_CREATE is implemented in TRP
+ * For the moment skip the test if RMM is TRP, TRP version is always null.
+ */
+ if (retrmm == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ retrmm = realm_granule_delegate((u_register_t)&rd[0]);
+ if (retrmm != 0UL) {
+ ERROR("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Create a realm using a parameter in a secure physical address space should fail. */
+ retrmm = realm_create((u_register_t)&rd[0], params);
+ if (retrmm == 0UL) {
+ ERROR("Realm create operation should fail, %lx\n", retrmm);
+ retrmm = realm_destroy((u_register_t)&rd[0]);
+ if (retrmm != 0UL) {
+ ERROR("Realm destroy operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ return TEST_RESULT_FAIL;
+ } else if (retrmm != RMM_STATUS_ERROR_INPUT) {
+ ERROR("Realm create operation should fail with code:%ld retrmm:%ld\n",
+ RMM_STATUS_ERROR_INPUT, retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ retrmm = realm_granule_undelegate((u_register_t)&rd[0]);
+ if (retrmm != 0UL) {
+ INFO("Undelegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * @Test_Aim@ Check a root region cannot be accessed from a secure partition.
+ *
+ * This change adds TFTF and cactus test to permit checking a root region
+ * cannot be accessed from secure world.
+ * A hardcoded address marked Root in the GPT is shared to a secure
+ * partition. The SP retrieves the region from the SPM, maps it and
+ * attempts a read access to the region. It is expected to trigger a GPF
+ * data abort on the PE caught by a custom exception handler.
+ *
+ */
+test_result_t rt_memory_cannot_be_accessed_in_s(void)
+{
+ const uintptr_t test_address = EL3_MEMORY_ACCESS_ADDR;
+ struct ffa_memory_region_constituent constituents[] = {
+ {
+ (void *)test_address, 1, 0
+ }
+ };
+ const uint32_t constituents_count = sizeof(constituents) /
+ sizeof(struct ffa_memory_region_constituent);
+ ffa_memory_handle_t handle;
+ struct mailbox_buffers mb;
+ struct ffa_value ret;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ INIT_TFTF_MAILBOX(mb);
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ handle = memory_init_and_send((struct ffa_memory_region *)mb.send,
+ PAGE_SIZE, SENDER, RECEIVER,
+ constituents, constituents_count,
+ FFA_MEM_SHARE_SMC32, &ret);
+
+ if (handle == FFA_MEMORY_HANDLE_INVALID) {
+ return TEST_RESULT_FAIL;
+ }
+
+ VERBOSE("TFTF - Handle: %llx Address: %p\n",
+ handle, constituents[0].address);
+
+ /* Retrieve the shared page and attempt accessing it. */
+ ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_SHARE_SMC32,
+ handle, 0, true, 1);
+
+ if (is_ffa_call_error(ffa_mem_reclaim(handle, 0))) {
+ ERROR("Memory reclaim failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Expect success response with value 1 hinting an exception
+ * triggered while the SP accessed the region.
+ */
+ if (!(cactus_get_response(ret) == CACTUS_SUCCESS &&
+ cactus_error_code(ret) == 1)) {
+ ERROR("Exceptions test failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+test_result_t s_memory_cannot_be_accessed_in_rl(void)
+{
+ u_register_t params = (u_register_t)SECURE_MEMORY_ACCESS_ADDR;
+ return memory_cannot_be_accessed_in_rl(params);
+}
+
+test_result_t rt_memory_cannot_be_accessed_in_rl(void)
+{
+ u_register_t params = (u_register_t)EL3_MEMORY_ACCESS_ADDR;
+ return memory_cannot_be_accessed_in_rl(params);
+}
+
+#else
+
+test_result_t el3_memory_cannot_be_accessed_in_ns(void)
+{
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+}
+
+test_result_t rl_memory_cannot_be_accessed_in_ns(void)
+{
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+}
+
+test_result_t s_memory_cannot_be_accessed_in_ns(void)
+{
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+}
+
+test_result_t s_memory_cannot_be_accessed_in_rl(void)
+{
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+}
+
+test_result_t rt_memory_cannot_be_accessed_in_rl(void)
+{
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+}
+
+#endif /* __aarch64__ */
diff --git a/tftf/tests/performance_tests/test_psci_latencies.c b/tftf/tests/performance_tests/test_psci_latencies.c
index 8a7a1d03..b20fe887 100644
--- a/tftf/tests/performance_tests/test_psci_latencies.c
+++ b/tftf/tests/performance_tests/test_psci_latencies.c
@@ -34,27 +34,6 @@ static event_t target_booted, target_keep_on_booted, target_keep_on;
*/
#define BASELINE_VARIANCE 10
-/*
- * Utility function to wait for all CPUs other than the caller to be
- * OFF.
- */
-static void wait_for_non_lead_cpus(void)
-{
- unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
- unsigned int target_mpid, target_node;
-
- for_each_cpu(target_node) {
- target_mpid = tftf_get_mpidr_from_node(target_node);
- /* Skip lead CPU, as it is powered on */
- if (target_mpid == lead_mpid)
- continue;
-
- while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0)
- != PSCI_STATE_OFF)
- ;
- }
-}
-
static test_result_t test_target_function(void)
{
tftf_send_event(&target_booted);
diff --git a/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c b/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c
new file mode 100644
index 00000000..1aaa12c0
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <debug.h>
+#include <smccc.h>
+
+#include <arch_helpers.h>
+#include <cactus_test_cmds.h>
+#include <ffa_endpoints.h>
+#include <ffa_svc.h>
+#include <lib/events.h>
+#include <lib/power_management.h>
+#include <platform.h>
+#include <test_helpers.h>
+
+#include <plat_topology.h>
+#include <runtime_services/realm_payload/realm_payload_test.h>
+
+static test_result_t realm_multi_cpu_payload_del_undel(void);
+
+#define ECHO_VAL1 U(0xa0a0a0a0)
+#define ECHO_VAL2 U(0xb0b0b0b0)
+#define ECHO_VAL3 U(0xc0c0c0c0)
+#define MAX_REPEATED_TEST 3
+
+/* Buffer to delegate and undelegate */
+static char bufferdelegate[NUM_GRANULES * GRANULE_SIZE * PLATFORM_CORE_COUNT] __aligned(GRANULE_SIZE);
+static char bufferstate[NUM_GRANULES * PLATFORM_CORE_COUNT];
+static int cpu_test_spm_rmi[PLATFORM_CORE_COUNT];
+static event_t cpu_booted[PLATFORM_CORE_COUNT];
+static unsigned int lead_mpid;
+/*
+ * The following test conducts SPM(direct messaging) tests on a subset of selected CPUs while
+ * simultaneously performing another set of tests of the RMI(delegation)
+ * on the remaining CPU's to the full platform count. Once that test completes
+ * the same test is run again with a different assignment for what CPU does
+ * SPM versus RMI.
+ */
+
+/*
+ * Function that randomizes the CPU assignment of tests, SPM or RMI
+ */
+static void rand_cpu_spm_rmi(void)
+{
+ int fentry;
+ int seln = 0;
+ for (int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+ cpu_test_spm_rmi[i] = -1;
+ }
+ for (int i = 0; i < NUM_CPU_DED_SPM; i++) {
+ fentry = 0;
+ while (fentry == 0) {
+#if (PLATFORM_CORE_COUNT > 1)
+ seln = (rand() % (PLATFORM_CORE_COUNT - 1)) + 1;
+#endif
+ if (cpu_test_spm_rmi[seln] == -1) {
+ cpu_test_spm_rmi[seln] = 1;
+ fentry = 1;
+ }
+ }
+ }
+ for (int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+ if (cpu_test_spm_rmi[i] == -1) {
+ cpu_test_spm_rmi[i] = 0;
+ }
+ }
+}
+
+/*
+ * Get function to determine what has been assigned to a given CPU
+ */
+static int spm_rmi_test(unsigned int mpidr)
+{
+ return cpu_test_spm_rmi[platform_get_core_pos(mpidr)];
+}
+
+/*
+ * RMI function to randomize the initial state of granules allocated for the test.
+ * A certain subset will be delegated leaving the rest undelegated
+ */
+static test_result_t init_buffer_del_spm_rmi(void)
+{
+ u_register_t retrmm;
+
+ for (int i = 0; i < (NUM_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+ if ((rand() % 2) == 0) {
+ retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+ bufferstate[i] = B_DELEGATED;
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ } else {
+ bufferstate[i] = B_UNDELEGATED;
+ }
+ }
+ return TEST_RESULT_SUCCESS;
+}
+
+static test_result_t reset_buffer_del_spm_rmi(void)
+{
+ u_register_t retrmm;
+
+ for (uint32_t i = 0; i < (NUM_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+ if (bufferstate[i] == B_DELEGATED) {
+ retrmm = realm_granule_undelegate(
+ (u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+ if (retrmm != 0UL) {
+ ERROR("Undelegate operation returns fail, %lx\n",
+ retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ bufferstate[i] = B_UNDELEGATED;
+ }
+ }
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Each CPU reaching this function will send a ready event to all other CPUs
+ * and wait for others CPUs before start executing its callback in parallel
+ * with all others CPUs
+ */
+static test_result_t wait_then_call(test_result_t (*callback)(void))
+{
+ unsigned int mpidr, this_mpidr = read_mpidr_el1() & MPID_MASK;
+ unsigned int cpu_node, core_pos, this_core_pos = platform_get_core_pos(this_mpidr);
+ tftf_send_event_to_all(&cpu_booted[this_core_pos]);
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ /* Ignore myself and the lead core */
+ if (mpidr == this_mpidr || mpidr == lead_mpid) {
+ continue;
+ }
+ core_pos = platform_get_core_pos(mpidr);
+ tftf_wait_for_event(&cpu_booted[core_pos]);
+ }
+ /* All cores reach this call in approximately "same" time */
+ return (*callback)();
+}
+
+/*
+ * Power on the given cpu and provide it with entrypoint to run and return result
+ */
+static test_result_t run_on_cpu(unsigned int mpidr, uintptr_t cpu_on_handler)
+{
+ int32_t ret;
+
+ ret = tftf_cpu_on(mpidr, cpu_on_handler, 0U);
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
+ return TEST_RESULT_FAIL;
+ }
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * SPM functions for the direct messaging
+ */
+static const struct ffa_uuid expected_sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
+ };
+
+static test_result_t send_cactus_echo_cmd(ffa_id_t sender,
+ ffa_id_t dest,
+ uint64_t value)
+{
+ struct ffa_value ret;
+ ret = cactus_echo_send_cmd(sender, dest, value);
+
+ /*
+ * Return responses may be FFA_MSG_SEND_DIRECT_RESP or FFA_INTERRUPT,
+ * but only expect the former. Expect SMC32 convention from SP.
+ */
+ if (!is_ffa_direct_response(ret)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (cactus_get_response(ret) != CACTUS_SUCCESS ||
+ cactus_echo_get_val(ret) != value) {
+ ERROR("Echo Failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Handler that is passed during tftf_cpu_on to individual CPU cores.
+ * Runs a specific core and send a direct message request.
+ * Expects core_pos | SP_ID as a response.
+ */
+static test_result_t run_spm_direct_message(void)
+{
+ unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos = platform_get_core_pos(mpid);
+ test_result_t ret = TEST_RESULT_SUCCESS;
+ struct ffa_value ffa_ret;
+
+ /*
+ * Send a direct message request to SP1 (MP SP) from current physical
+ * CPU. Notice SP1 ECs are already woken as a result of the PSCI_CPU_ON
+ * invocation so they already reached the message loop.
+ * The SPMC uses the MP pinned context corresponding to the physical
+ * CPU emitting the request.
+ */
+ ret = send_cactus_echo_cmd(HYP_ID, SP_ID(1), ECHO_VAL1);
+ if (ret != TEST_RESULT_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Secure Partitions beyond the first SP only have their first
+ * EC (or vCPU0) woken up at boot time by the SPMC.
+ * Other ECs need one round of ffa_run to reach the message loop.
+ */
+ ffa_ret = ffa_run(SP_ID(2), core_pos);
+ if (ffa_func_id(ffa_ret) != FFA_MSG_WAIT) {
+ ERROR("Failed to run SP%x on core %u\n", SP_ID(2),
+ core_pos);
+ ret = TEST_RESULT_FAIL;
+ goto out;
+ }
+
+ /*
+ * Send a direct message request to SP2 (MP SP) from current physical
+ * CPU. The SPMC uses the MP pinned context corresponding to the
+ * physical CPU emitting the request.
+ */
+ ret = send_cactus_echo_cmd(HYP_ID, SP_ID(2), ECHO_VAL2);
+ if (ret != TEST_RESULT_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Send a direct message request to SP3 (UP SP) from current physical CPU.
+ * The SPMC uses the single vCPU migrated to the new physical core.
+ * The single SP vCPU may receive requests from multiple physical CPUs.
+ * Thus it is possible one message is being processed on one core while
+ * another (or multiple) cores attempt sending a new direct message
+ * request. In such case the cores attempting the new request receive
+ * a busy response from the SPMC. To handle this case a retry loop is
+ * implemented permitting some fairness.
+ */
+ uint32_t trial_loop = 5U;
+ while (trial_loop--) {
+ ffa_ret = cactus_echo_send_cmd(HYP_ID, SP_ID(3), ECHO_VAL3);
+ if ((ffa_func_id(ffa_ret) == FFA_ERROR) &&
+ (ffa_error_code(ffa_ret) == FFA_ERROR_BUSY)) {
+ VERBOSE("%s(%u) trial %u\n", __func__, core_pos, trial_loop);
+ waitms(1);
+ continue;
+ }
+
+ if (is_ffa_direct_response(ffa_ret) == true) {
+ if (cactus_get_response(ffa_ret) != CACTUS_SUCCESS ||
+ cactus_echo_get_val(ffa_ret) != ECHO_VAL3) {
+ ERROR("Echo Failed!\n");
+ ret = TEST_RESULT_FAIL;
+ }
+
+ goto out;
+ }
+ }
+
+ ret = TEST_RESULT_FAIL;
+
+out:
+ return ret;
+}
+
+/*
+ * Secondary core will perform sequentially a call to secure and realm worlds.
+ */
+test_result_t non_secure_call_secure_and_realm(void)
+{
+ test_result_t result = run_spm_direct_message();
+ if (result != TEST_RESULT_SUCCESS)
+ return result;
+ return realm_multi_cpu_payload_del_undel();
+}
+
+/*
+ * Non secure call secure synchronously in parallel
+ * with all other cores in this test
+ */
+static test_result_t non_secure_call_secure_multi_cpu_sync(void)
+{
+ return wait_then_call(run_spm_direct_message);
+}
+
+/*
+ * Multi CPU testing of delegate and undelegate of granules
+ * The granules are first randomly initialized to either realm or non secure
+ * using the function init_buffer_del and then the function below
+ * assigns NUM_GRANULES to each CPU for delegation or undelgation
+ * depending upon the initial state
+ */
+static test_result_t realm_multi_cpu_payload_del_undel(void)
+{
+ u_register_t retrmm;
+ unsigned int cpu_node;
+
+ cpu_node = platform_get_core_pos(read_mpidr_el1() & MPID_MASK);
+
+ for (int i = 0; i < NUM_GRANULES; i++) {
+ if (bufferstate[((cpu_node * NUM_GRANULES) + i)] == B_UNDELEGATED) {
+ retrmm = realm_granule_delegate((u_register_t)
+ &bufferdelegate[((cpu_node *
+ NUM_GRANULES) + i) * GRANULE_SIZE]);
+ bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_DELEGATED;
+ } else {
+ retrmm = realm_granule_undelegate((u_register_t)
+ &bufferdelegate[((cpu_node *
+ NUM_GRANULES) + i) * GRANULE_SIZE]);
+ bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_UNDELEGATED;
+ }
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ }
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Non secure call realm synchronously in parallel
+ * with all other cores in this test
+ */
+static test_result_t non_secure_call_realm_multi_cpu_sync(void)
+{
+ return wait_then_call(realm_multi_cpu_payload_del_undel);
+}
+
+/*
+ * NS world communicate with S and RL worlds in series via SMC from a single core.
+ */
+test_result_t test_spm_rmm_serial_smc(void)
+{
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ lead_mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int mpidr;
+
+ /**********************************************************************
+ * Check SPMC has ffa_version and expected FFA endpoints are deployed.
+ **********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+ /*
+ * Randomize the initial state of the RMI granules to realm or non-secure
+ */
+ if (init_buffer_del_spm_rmi() == TEST_RESULT_FAIL) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Preparation step:
+ * Find another CPU than the lead CPU and power it on.
+ */
+ mpidr = tftf_find_any_cpu_other_than(lead_mpid);
+ assert(mpidr != INVALID_MPID);
+
+ /*
+ * Run SPM direct message call and RMI call in serial on a second core.
+ * wait for core power cycle between each call.
+ */
+ for (size_t i = 0; i < MAX_REPEATED_TEST; i++) {
+ /* SPM FF-A direct message call */
+ if (TEST_RESULT_SUCCESS != run_on_cpu(mpidr,
+ (uintptr_t)non_secure_call_secure_and_realm)) {
+ return TEST_RESULT_FAIL;
+ }
+ /* Wait for the target CPU to finish the test execution */
+ wait_for_core_to_turn_off(mpidr);
+ }
+
+ if (TEST_RESULT_SUCCESS != reset_buffer_del_spm_rmi()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ VERBOSE("Done exiting.\n");
+
+ /**********************************************************************
+ * All tests passed.
+ **********************************************************************/
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Test function to let NS world communicate with S and RL worlds in parallel
+ * via SMC using multiple cores
+ */
+test_result_t test_spm_rmm_parallel_smc(void)
+{
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ lead_mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int cpu_node, mpidr;
+
+ /**********************************************************************
+ * Check SPMC has ffa_version and expected FFA endpoints are deployed.
+ **********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+ /*
+ * Randomize the initial state of the RMI granules to realm or non-secure
+ */
+ if (init_buffer_del_spm_rmi() == TEST_RESULT_FAIL) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Main test to run both SPM and RMM or TRP together in parallel
+ */
+ for (int i = 0; i < MAX_REPEATED_TEST; i++) {
+ VERBOSE("Main test(%d) to run both SPM and RMM or TRP together in parallel...\n", i);
+
+ /* Reinitialize all CPUs event */
+ for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+ tftf_init_event(&cpu_booted[i]);
+ }
+
+ /*
+ * Randomise the assignment of the CPU's to either SPM or RMI
+ */
+ rand_cpu_spm_rmi();
+
+ /*
+ * for each CPU we assign it randomly either spm or rmi test function
+ */
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+ if (spm_rmi_test(mpidr) == 1) {
+ if (TEST_RESULT_SUCCESS != run_on_cpu(mpidr,
+ (uintptr_t)non_secure_call_secure_multi_cpu_sync)) {
+ return TEST_RESULT_FAIL;
+ }
+ } else {
+ if (TEST_RESULT_SUCCESS != run_on_cpu(mpidr,
+ (uintptr_t)non_secure_call_realm_multi_cpu_sync)) {
+ return TEST_RESULT_FAIL;
+ }
+ }
+ }
+
+ VERBOSE("Waiting for secondary CPUs to turn off ...\n");
+ wait_for_non_lead_cpus();
+ }
+
+ VERBOSE("Done exiting.\n");
+
+ return reset_buffer_del_spm_rmi();
+}
diff --git a/tftf/tests/runtime_services/realm_payload/realm_payload_test.c b/tftf/tests/runtime_services/realm_payload/realm_payload_test.c
new file mode 100644
index 00000000..8bdc60a2
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_test.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <arch_features.h>
+#include <plat_topology.h>
+#include <power_management.h>
+#include <platform.h>
+#include <runtime_services/realm_payload/realm_payload_test.h>
+#include <test_helpers.h>
+
+static test_result_t realm_multi_cpu_payload_test(void);
+static test_result_t realm_multi_cpu_payload_del_undel(void);
+
+/* Buffer to delegate and undelegate */
+static char bufferdelegate[NUM_GRANULES * GRANULE_SIZE * PLATFORM_CORE_COUNT] __aligned(GRANULE_SIZE);
+static char bufferstate[NUM_GRANULES * PLATFORM_CORE_COUNT];
+
+/*
+ * Overall test for realm payload in three sections:
+ * 1. Single CPU version check: SMC call to realm payload to return
+ * version information
+ * 2. Multi CPU version check: SMC call to realm payload to return
+ * version information from all CPU's in system
+ * 3. Delegate and Undelegate Non-Secure granule via
+ * SMC call to realm payload
+ * 4. Multi CPU delegation where random assignment of states
+ * (realm, non-secure)is assigned to a set of granules.
+ * Each CPU is given a number of granules to delegate in
+ * parallel with the other CPU's
+ * 5. Fail testing of delegation parameters such as
+ * attempting to perform a delegation on the same granule
+ * twice and then testing a misaligned address
+ */
+
+test_result_t init_buffer_del(void)
+{
+ u_register_t retrmm;
+
+ for (int i = 0; i < (NUM_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+ if ((rand() % 2) == 0) {
+ retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+ bufferstate[i] = B_DELEGATED;
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ } else {
+ bufferstate[i] = B_UNDELEGATED;
+ }
+ }
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Single CPU version check function
+ */
+test_result_t realm_version_single_cpu(void)
+{
+ u_register_t retrmm;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ retrmm = realm_version();
+
+ tftf_testcase_printf("RMM version is: %lu.%lu\n",
+ RMI_ABI_VERSION_GET_MAJOR(retrmm),
+ RMI_ABI_VERSION_GET_MINOR(retrmm));
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Multi CPU version check function in parallel.
+ */
+test_result_t realm_version_multi_cpu(void)
+{
+ u_register_t lead_mpid, target_mpid;
+ int cpu_node;
+ long long ret;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+ for_each_cpu(cpu_node) {
+ target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+ if (lead_mpid == target_mpid) {
+ continue;
+ }
+
+ ret = tftf_cpu_on(target_mpid,
+ (uintptr_t)realm_multi_cpu_payload_test, 0);
+
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("CPU ON failed for 0x%llx\n",
+ (unsigned long long)target_mpid);
+ return TEST_RESULT_FAIL;
+ }
+
+ }
+
+ ret = realm_multi_cpu_payload_test();
+
+ for_each_cpu(cpu_node) {
+ target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+ if (lead_mpid == target_mpid) {
+ continue;
+ }
+
+ while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
+ PSCI_STATE_OFF) {
+ continue;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Delegate and Undelegate Non Secure Granule
+ */
+test_result_t realm_delegate_undelegate(void)
+{
+ u_register_t retrmm;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ retrmm = realm_granule_delegate((u_register_t)bufferdelegate);
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ retrmm = realm_granule_undelegate((u_register_t)bufferdelegate);
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Undelegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ tftf_testcase_printf("Delegate and undelegate of buffer 0x%lx succeeded\n",
+ (uintptr_t)bufferdelegate);
+
+ return TEST_RESULT_SUCCESS;
+}
+
+static test_result_t realm_multi_cpu_payload_test(void)
+{
+ u_register_t retrmm = realm_version();
+
+ tftf_testcase_printf("Multi CPU RMM version on CPU %llx is: %lu.%lu\n",
+ (long long)read_mpidr_el1() & MPID_MASK, RMI_ABI_VERSION_GET_MAJOR(retrmm),
+ RMI_ABI_VERSION_GET_MINOR(retrmm));
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Select all CPU's to randomly delegate/undelegate
+ * granule pages to stress the delegate mechanism
+ */
+test_result_t realm_delundel_multi_cpu(void)
+{
+ u_register_t lead_mpid, target_mpid;
+ int cpu_node;
+ long long ret;
+ u_register_t retrmm;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+ if (init_buffer_del() == TEST_RESULT_FAIL) {
+ return TEST_RESULT_FAIL;
+ }
+
+ for_each_cpu(cpu_node) {
+ target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+ if (lead_mpid == target_mpid) {
+ continue;
+ }
+
+ ret = tftf_cpu_on(target_mpid,
+ (uintptr_t)realm_multi_cpu_payload_del_undel, 0);
+
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("CPU ON failed for 0x%llx\n",
+ (unsigned long long)target_mpid);
+ return TEST_RESULT_FAIL;
+ }
+
+ }
+
+ for_each_cpu(cpu_node) {
+ target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+ if (lead_mpid == target_mpid) {
+ continue;
+ }
+
+ while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
+ PSCI_STATE_OFF) {
+ continue;
+ }
+ }
+
+ /*
+ * Cleanup to set all granules back to undelegated
+ */
+
+ for (int i = 0; i < (NUM_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+ if (bufferstate[i] == B_DELEGATED) {
+ retrmm = realm_granule_undelegate((u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+ bufferstate[i] = B_UNDELEGATED;
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ }
+ }
+
+ ret = TEST_RESULT_SUCCESS;
+ return ret;
+}
+
+/*
+ * Multi CPU testing of delegate and undelegate of granules
+ * The granules are first randomly initialized to either realm or non secure
+ * using the function init_buffer_del and then the function below
+ * assigns NUM_GRANULES to each CPU for delegation or undelgation
+ * depending upon the initial state
+ */
+static test_result_t realm_multi_cpu_payload_del_undel(void)
+{
+ u_register_t retrmm;
+ unsigned int cpu_node;
+
+ cpu_node = platform_get_core_pos(read_mpidr_el1() & MPID_MASK);
+
+ for (int i = 0; i < NUM_GRANULES; i++) {
+ if (bufferstate[((cpu_node * NUM_GRANULES) + i)] == B_UNDELEGATED) {
+ retrmm = realm_granule_delegate((u_register_t)
+ &bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+ bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_DELEGATED;
+ } else {
+ retrmm = realm_granule_undelegate((u_register_t)
+ &bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+ bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_UNDELEGATED;
+ }
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ }
+ return TEST_RESULT_SUCCESS;
+}
+
+/*Fail testing of delegation process. The first is an error expected
+ * for processing the same granule twice and the second is submission of
+ * a misaligned address
+ */
+
+test_result_t realm_fail_del(void)
+{
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ u_register_t retrmm;
+
+ retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[0]);
+
+ if (retrmm != 0UL) {
+ tftf_testcase_printf
+ ("Delegate operation does not pass as expected for double delegation, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[0]);
+
+ if (retrmm == 0UL) {
+ tftf_testcase_printf
+ ("Delegate operation does not fail as expected for double delegation, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ retrmm = realm_granule_undelegate((u_register_t)&bufferdelegate[1]);
+
+ if (retrmm == 0UL) {
+ tftf_testcase_printf
+ ("Delegate operation does not return fail for misaligned address, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ retrmm = realm_granule_undelegate((u_register_t)&bufferdelegate[0]);
+
+ if (retrmm != 0UL) {
+ tftf_testcase_printf
+ ("Delegate operation returns fail for cleanup, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c b/tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c
new file mode 100644
index 00000000..49bf674a
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <runtime_services/realm_payload/realm_payload_test.h>
+
+u_register_t realm_version(void)
+{
+ smc_args args = { RMI_RMM_REQ_VERSION };
+ smc_ret_values ret;
+
+ ret = tftf_smc(&args);
+ return ret.ret0;
+}
+
+u_register_t realm_granule_delegate(u_register_t add)
+{
+ smc_args args = { 0 };
+ smc_ret_values ret;
+
+ args.fid = SMC_RMM_GRANULE_DELEGATE;
+ args.arg1 = add;
+
+ ret = tftf_smc(&args);
+ return ret.ret0;
+}
+
+u_register_t realm_granule_undelegate(u_register_t add)
+{
+ smc_args args = { 0 };
+ smc_ret_values ret;
+
+ args.fid = SMC_RMM_GRANULE_UNDELEGATE;
+ args.arg1 = add;
+
+ ret = tftf_smc(&args);
+ return ret.ret0;
+}
+
+u_register_t realm_create(u_register_t rd_addr, u_register_t realm_params_addr)
+{
+ smc_args args = { 0 };
+ smc_ret_values ret;
+
+ args.fid = SMC_RMM_REALM_CREATE;
+ args.arg1 = rd_addr;
+ args.arg2 = realm_params_addr;
+
+ ret = tftf_smc(&args);
+ return ret.ret0;
+}
+
+u_register_t realm_destroy(u_register_t rd_addr)
+{
+ smc_args args = { 0 };
+ smc_ret_values ret;
+
+ args.fid = SMC_RMM_REALM_DESTROY;
+ args.arg1 = rd_addr;
+
+ ret = tftf_smc(&args);
+ return ret.ret0;
+} \ No newline at end of file
diff --git a/tftf/tests/runtime_services/secure_service/aarch32/ffa_arch_helpers.S b/tftf/tests/runtime_services/secure_service/aarch32/ffa_arch_helpers.S
new file mode 100644
index 00000000..0d5395fa
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/aarch32/ffa_arch_helpers.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .macro service_call _conduit
+ /* Push r9 to keep the stack pointer aligned to 64 bit. */
+ push {r4 - r9}
+
+ /*
+ * Save the ffa_value pointer in a callee saved register.
+ */
+ mov r8, r0
+
+ /* Load the argument values into the appropriate registers. */
+ ldm r0, {r0 - r7}
+
+ \_conduit #0
+
+ /*
+ * The return values are stored in x0-x7, put them in the ffa_value
+ * return structure.
+ */
+ stm r8, {r0 - r7}
+
+ pop {r4 - r9}
+ .endm
+
+.globl ffa_svc
+func ffa_svc
+ service_call svc
+ bx lr
+endfunc ffa_svc
+
+.globl ffa_smc
+func ffa_smc
+ service_call smc
+ bx lr
+endfunc ffa_smc
diff --git a/tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S b/tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S
new file mode 100644
index 00000000..0e35a382
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .macro service_call _conduit
+ /*
+ * Save the address of the ffa_value structure on the stack.
+ *
+ * Although x0 contains an 8-byte value, we are allocating 16 bytes
+ * on the stack to respect the 16-byte stack-alignment.
+ */
+ str x0, [sp, #-16]!
+
+ /* Load the argument values into the appropriate registers. */
+ ldp x6, x7, [x0, #48]
+ ldp x4, x5, [x0, #32]
+ ldp x2, x3, [x0, #16]
+ ldp x0, x1, [x0, #0]
+
+ \_conduit #0
+
+ /*
+ * Pop the ffa_value structure address from the stack into a
+ * caller-saved register.
+ */
+ ldr x9, [sp], #16
+
+ /*
+ * The return values are stored in x0-x7, put them in the ffa_value
+ * return structure.
+ */
+ stp x0, x1, [x9, #0]
+ stp x2, x3, [x9, #16]
+ stp x4, x5, [x9, #32]
+ stp x6, x7, [x9, #48]
+
+ .endm
+
+.globl ffa_svc
+func ffa_svc
+ service_call svc
+ ret
+endfunc ffa_svc
+
+.globl ffa_smc
+func ffa_smc
+ service_call smc
+ ret
+endfunc ffa_smc
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index 8e7b58c6..f7370566 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -1,13 +1,24 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <smccc.h>
+#include <assert.h>
#include <ffa_endpoints.h>
#include <ffa_helpers.h>
#include <ffa_svc.h>
+#include <smccc.h>
+
+struct ffa_value ffa_service_call(struct ffa_value *args)
+{
+#if IMAGE_IVY
+ ffa_svc(args);
+#else
+ ffa_smc(args);
+#endif
+ return *args;
+}
/*-----------------------------------------------------------------------------
* FFA_RUN
@@ -26,15 +37,15 @@
* -BUSY: vCPU is busy and caller must retry later
* -ABORTED: vCPU or VM ran into an unexpected error and has aborted
*/
-smc_ret_values ffa_run(uint32_t dest_id, uint32_t vcpu_id)
+struct ffa_value ffa_run(uint32_t dest_id, uint32_t vcpu_id)
{
- smc_args args = {
- FFA_MSG_RUN,
+ struct ffa_value args = {
+ FFA_RUN,
(dest_id << 16) | vcpu_id,
0, 0, 0, 0, 0, 0
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/*-----------------------------------------------------------------------------
@@ -55,12 +66,12 @@ smc_ret_values ffa_run(uint32_t dest_id, uint32_t vcpu_id)
* -BUSY: Message target is busy
* -ABORTED: Message target ran into an unexpected error and has aborted
*/
-smc_ret_values ffa_msg_send_direct_req64(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint64_t arg0,
- uint64_t arg1, uint64_t arg2,
- uint64_t arg3, uint64_t arg4)
+struct ffa_value ffa_msg_send_direct_req64(ffa_id_t source_id,
+ ffa_id_t dest_id, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MSG_SEND_DIRECT_REQ_SMC64,
.arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
.arg2 = 0,
@@ -71,15 +82,15 @@ smc_ret_values ffa_msg_send_direct_req64(ffa_vm_id_t source_id,
.arg7 = arg4,
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_msg_send_direct_req32(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint32_t arg0,
- uint32_t arg1, uint32_t arg2,
- uint32_t arg3, uint32_t arg4)
+struct ffa_value ffa_msg_send_direct_req32(ffa_id_t source_id,
+ ffa_id_t dest_id, uint32_t arg0,
+ uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t arg4)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MSG_SEND_DIRECT_REQ_SMC32,
.arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
.arg2 = 0,
@@ -90,15 +101,15 @@ smc_ret_values ffa_msg_send_direct_req32(ffa_vm_id_t source_id,
.arg7 = arg4,
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_msg_send_direct_resp64(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint64_t arg0,
- uint64_t arg1, uint64_t arg2,
- uint64_t arg3, uint64_t arg4)
+struct ffa_value ffa_msg_send_direct_resp64(ffa_id_t source_id,
+ ffa_id_t dest_id, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MSG_SEND_DIRECT_RESP_SMC64,
.arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
.arg2 = 0,
@@ -109,15 +120,15 @@ smc_ret_values ffa_msg_send_direct_resp64(ffa_vm_id_t source_id,
.arg7 = arg4,
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_msg_send_direct_resp32(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint32_t arg0,
- uint32_t arg1, uint32_t arg2,
- uint32_t arg3, uint32_t arg4)
+struct ffa_value ffa_msg_send_direct_resp32(ffa_id_t source_id,
+ ffa_id_t dest_id, uint32_t arg0,
+ uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t arg4)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MSG_SEND_DIRECT_RESP_SMC32,
.arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
.arg2 = 0,
@@ -128,7 +139,7 @@ smc_ret_values ffa_msg_send_direct_resp32(ffa_vm_id_t source_id,
.arg7 = arg4,
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
@@ -137,9 +148,9 @@ smc_ret_values ffa_msg_send_direct_resp32(ffa_vm_id_t source_id,
* composite memory region offset.
*/
static void ffa_memory_region_init_header(
- struct ffa_memory_region *memory_region, ffa_vm_id_t sender,
+ struct ffa_memory_region *memory_region, ffa_id_t sender,
ffa_memory_attributes_t attributes, ffa_memory_region_flags_t flags,
- ffa_memory_handle_t handle, uint32_t tag, ffa_vm_id_t receiver,
+ ffa_memory_handle_t handle, uint32_t tag, ffa_id_t receiver,
ffa_memory_access_permissions_t permissions)
{
memory_region->sender = sender;
@@ -168,7 +179,7 @@ static void ffa_memory_region_init_header(
*/
uint32_t ffa_memory_region_init(
struct ffa_memory_region *memory_region, size_t memory_region_max_size,
- ffa_vm_id_t sender, ffa_vm_id_t receiver,
+ ffa_id_t sender, ffa_id_t receiver,
const struct ffa_memory_region_constituent constituents[],
uint32_t constituent_count, uint32_t tag,
ffa_memory_region_flags_t flags, enum ffa_data_access data_access,
@@ -259,7 +270,7 @@ uint32_t ffa_memory_region_init(
*/
uint32_t ffa_memory_retrieve_request_init(
struct ffa_memory_region *memory_region, ffa_memory_handle_t handle,
- ffa_vm_id_t sender, ffa_vm_id_t receiver, uint32_t tag,
+ ffa_id_t sender, ffa_id_t receiver, uint32_t tag,
ffa_memory_region_flags_t flags, enum ffa_data_access data_access,
enum ffa_instruction_access instruction_access,
enum ffa_memory_type type, enum ffa_memory_cacheability cacheability,
@@ -291,105 +302,134 @@ uint32_t ffa_memory_retrieve_request_init(
memory_region->receiver_count * sizeof(struct ffa_memory_access);
}
-
/*
* FFA Version ABI helper.
* Version fields:
* -Bits[30:16]: Major version.
* -Bits[15:0]: Minor version.
*/
-smc_ret_values ffa_version(uint32_t input_version)
+struct ffa_value ffa_version(uint32_t input_version)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_VERSION,
.arg1 = input_version
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_id_get(void)
+struct ffa_value ffa_id_get(void)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_ID_GET
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_msg_wait(void)
+struct ffa_value ffa_spm_id_get(void)
{
- smc_args args = {
+ struct ffa_value args = {
+ .fid = FFA_SPM_ID_GET
+ };
+
+ return ffa_service_call(&args);
+}
+
+struct ffa_value ffa_msg_wait(void)
+{
+ struct ffa_value args = {
.fid = FFA_MSG_WAIT
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_error(int32_t error_code)
+struct ffa_value ffa_error(int32_t error_code)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_ERROR,
.arg1 = 0,
.arg2 = error_code
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Query the higher EL if the requested FF-A feature is implemented. */
-smc_ret_values ffa_features(uint32_t feature)
+struct ffa_value ffa_features(uint32_t feature)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_FEATURES,
.arg1 = feature
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Get information about VMs or SPs based on UUID */
-smc_ret_values ffa_partition_info_get(const uint32_t uuid[4])
+struct ffa_value ffa_partition_info_get(const struct ffa_uuid uuid)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_PARTITION_INFO_GET,
- .arg1 = uuid[0],
- .arg2 = uuid[1],
- .arg3 = uuid[2],
- .arg4 = uuid[3]
+ .arg1 = uuid.uuid[0],
+ .arg2 = uuid.uuid[1],
+ .arg3 = uuid.uuid[2],
+ .arg4 = uuid.uuid[3]
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Query SPMD that the rx buffer of the partition can be released */
-smc_ret_values ffa_rx_release(void)
+struct ffa_value ffa_rx_release(void)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_RX_RELEASE
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Map the RXTX buffer */
-smc_ret_values ffa_rxtx_map(uintptr_t send, uintptr_t recv, uint32_t pages)
+struct ffa_value ffa_rxtx_map(uintptr_t send, uintptr_t recv, uint32_t pages)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_RXTX_MAP_SMC64,
.arg1 = send,
.arg2 = recv,
- .arg3 = pages
+ .arg3 = pages,
+ .arg4 = FFA_PARAM_MBZ,
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ
+ };
+
+ return ffa_service_call(&args);
+}
+
+/* Unmap the RXTX buffer allocated by the given FF-A component */
+struct ffa_value ffa_rxtx_unmap(void)
+{
+ struct ffa_value args = {
+ .fid = FFA_RXTX_UNMAP,
+ .arg1 = FFA_PARAM_MBZ,
+ .arg2 = FFA_PARAM_MBZ,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ,
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Donate memory to another partition */
-smc_ret_values ffa_mem_donate(uint32_t descriptor_length,
+struct ffa_value ffa_mem_donate(uint32_t descriptor_length,
uint32_t fragment_length)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_DONATE_SMC32,
.arg1 = descriptor_length,
.arg2 = fragment_length,
@@ -397,14 +437,14 @@ smc_ret_values ffa_mem_donate(uint32_t descriptor_length,
.arg4 = FFA_PARAM_MBZ
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Lend memory to another partition */
-smc_ret_values ffa_mem_lend(uint32_t descriptor_length,
- uint32_t fragment_length)
+struct ffa_value ffa_mem_lend(uint32_t descriptor_length,
+ uint32_t fragment_length)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_LEND_SMC32,
.arg1 = descriptor_length,
.arg2 = fragment_length,
@@ -412,14 +452,14 @@ smc_ret_values ffa_mem_lend(uint32_t descriptor_length,
.arg4 = FFA_PARAM_MBZ
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Share memory with another partition */
-smc_ret_values ffa_mem_share(uint32_t descriptor_length,
- uint32_t fragment_length)
+struct ffa_value ffa_mem_share(uint32_t descriptor_length,
+ uint32_t fragment_length)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_SHARE_SMC32,
.arg1 = descriptor_length,
.arg2 = fragment_length,
@@ -427,14 +467,14 @@ smc_ret_values ffa_mem_share(uint32_t descriptor_length,
.arg4 = FFA_PARAM_MBZ
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Retrieve memory shared by another partition */
-smc_ret_values ffa_mem_retrieve_req(uint32_t descriptor_length,
- uint32_t fragment_length)
+struct ffa_value ffa_mem_retrieve_req(uint32_t descriptor_length,
+ uint32_t fragment_length)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_RETRIEVE_REQ_SMC32,
.arg1 = descriptor_length,
.arg2 = fragment_length,
@@ -445,28 +485,189 @@ smc_ret_values ffa_mem_retrieve_req(uint32_t descriptor_length,
.arg7 = FFA_PARAM_MBZ
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Relinquish access to memory region */
-smc_ret_values ffa_mem_relinquish(void)
+struct ffa_value ffa_mem_relinquish(void)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_RELINQUISH,
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Reclaim exclusive access to owned memory region */
-smc_ret_values ffa_mem_reclaim(uint64_t handle, uint32_t flags)
+struct ffa_value ffa_mem_reclaim(uint64_t handle, uint32_t flags)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_RECLAIM,
.arg1 = (uint32_t) handle,
.arg2 = (uint32_t) (handle >> 32),
.arg3 = flags
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
+}
+
+/** Create Notifications Bitmap for the given VM */
+struct ffa_value ffa_notification_bitmap_create(ffa_id_t vm_id,
+ ffa_vcpu_count_t vcpu_count)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_BITMAP_CREATE,
+ .arg1 = vm_id,
+ .arg2 = vcpu_count,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ,
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ,
+ };
+
+ return ffa_service_call(&args);
+}
+
+/** Destroy Notifications Bitmap for the given VM */
+struct ffa_value ffa_notification_bitmap_destroy(ffa_id_t vm_id)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_BITMAP_DESTROY,
+ .arg1 = vm_id,
+ .arg2 = FFA_PARAM_MBZ,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ,
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ,
+ };
+
+ return ffa_service_call(&args);
+}
+
+/** Bind VM to all the notifications in the bitmap */
+struct ffa_value ffa_notification_bind(ffa_id_t sender, ffa_id_t receiver,
+ uint32_t flags,
+ ffa_notification_bitmap_t bitmap)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_BIND,
+ .arg1 = (sender << 16) | (receiver),
+ .arg2 = flags,
+ .arg3 = (uint32_t)(bitmap & 0xFFFFFFFFU),
+ .arg4 = (uint32_t)(bitmap >> 32),
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ,
+ };
+
+ return ffa_service_call(&args);
+}
+
+/** Unbind previously bound VM from notifications in bitmap */
+struct ffa_value ffa_notification_unbind(ffa_id_t sender,
+ ffa_id_t receiver,
+ ffa_notification_bitmap_t bitmap)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_UNBIND,
+ .arg1 = (sender << 16) | (receiver),
+ .arg2 = FFA_PARAM_MBZ,
+ .arg3 = (uint32_t)(bitmap),
+ .arg4 = (uint32_t)(bitmap >> 32),
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ,
+ };
+
+ return ffa_service_call(&args);
+}
+
+struct ffa_value ffa_notification_set(ffa_id_t sender, ffa_id_t receiver,
+ uint32_t flags,
+ ffa_notification_bitmap_t bitmap)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_SET,
+ .arg1 = (sender << 16) | (receiver),
+ .arg2 = flags,
+ .arg3 = (uint32_t)(bitmap & 0xFFFFFFFFU),
+ .arg4 = (uint32_t)(bitmap >> 32),
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ
+ };
+
+ return ffa_service_call(&args);
+}
+
+struct ffa_value ffa_notification_get(ffa_id_t receiver, uint32_t vcpu_id,
+ uint32_t flags)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_GET,
+ .arg1 = (vcpu_id << 16) | (receiver),
+ .arg2 = flags,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ,
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ
+ };
+
+ return ffa_service_call(&args);
+}
+
+struct ffa_value ffa_notification_info_get(void)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_INFO_GET_SMC64,
+ .arg1 = FFA_PARAM_MBZ,
+ .arg2 = FFA_PARAM_MBZ,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ,
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ
+ };
+
+ return ffa_service_call(&args);
+}
+
+static size_t char_to_arg_helper(const char *message, size_t size,
+ u_register_t *arg)
+{
+ size_t to_write = size > sizeof(uint64_t) ? sizeof(uint64_t) : size;
+
+ for (int i = 0; i < to_write; i++) {
+ ((char *)arg)[i] = message[i];
+ }
+ return to_write;
+}
+
+struct ffa_value ffa_console_log(const char *message, size_t char_count)
+{
+ struct ffa_value args = {
+ .fid = FFA_CONSOLE_LOG_SMC64,
+ .arg1 = char_count,
+ };
+ size_t written = 0;
+
+ assert(char_count <= sizeof(uint64_t) * 6);
+
+ written += char_to_arg_helper(&message[written], char_count - written,
+ &args.arg2);
+ written += char_to_arg_helper(&message[written], char_count - written,
+ &args.arg3);
+ written += char_to_arg_helper(&message[written], char_count - written,
+ &args.arg4);
+ written += char_to_arg_helper(&message[written], char_count - written,
+ &args.arg5);
+ written += char_to_arg_helper(&message[written], char_count - written,
+ &args.arg6);
+ char_to_arg_helper(&message[written], char_count - written,
+ &args.arg7);
+
+ return ffa_service_call(&args);
}
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index 179ef1cb..ae00ff59 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -1,22 +1,29 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <cactus_test_cmds.h>
#include <debug.h>
#include <ffa_endpoints.h>
+#include <ffa_svc.h>
+#include <lib/extensions/sve.h>
#include <spm_common.h>
#include <xlat_tables_v2.h>
#define __STR(x) #x
#define STR(x) __STR(x)
-#define SIMD_TWO_VECTORS_BYTES_STR (2 * SIMD_VECTOR_LEN_BYTES)
+
+#define fill_simd_helper(num1, num2) "ldp q"#num1", q"#num2",\
+ [%0], #"STR(2 * SIMD_VECTOR_LEN_BYTES)";"
+#define read_simd_helper(num1, num2) "stp q"#num1", q"#num2",\
+ [%0], #"STR(2 * SIMD_VECTOR_LEN_BYTES)";"
/**
* Helper to log errors after FF-A calls.
*/
-bool is_ffa_call_error(smc_ret_values ret)
+bool is_ffa_call_error(struct ffa_value ret)
{
if (ffa_func_id(ret) == FFA_ERROR) {
VERBOSE("FF-A call returned error (%x): %d\n",
@@ -26,12 +33,25 @@ bool is_ffa_call_error(smc_ret_values ret)
return false;
}
+bool is_expected_ffa_error(struct ffa_value ret, int32_t error_code)
+{
+ if (ffa_func_id(ret) == FFA_ERROR &&
+ ffa_error_code(ret) == error_code) {
+ return true;
+ }
+
+ ERROR("Expected FFA_ERROR(%x), code: %d, got %x %d\n",
+ FFA_ERROR, error_code, ffa_func_id(ret), ffa_error_code(ret));
+
+ return false;
+}
+
/**
* Helper to verify return of FF-A call is an FFA_MSG_SEND_DIRECT_RESP.
* Should be used after FFA_MSG_SEND_DIRECT_REQ, or after sending a test command
* to an SP.
*/
-bool is_ffa_direct_response(smc_ret_values ret)
+bool is_ffa_direct_response(struct ffa_value ret)
{
if ((ffa_func_id(ret) == FFA_MSG_SEND_DIRECT_RESP_SMC32) ||
(ffa_func_id(ret) == FFA_MSG_SEND_DIRECT_RESP_SMC64)) {
@@ -48,7 +68,7 @@ bool is_ffa_direct_response(smc_ret_values ret)
/**
* Helper to check the return value of FF-A call is as expected.
*/
-bool is_expected_ffa_return(smc_ret_values ret, uint32_t func_id)
+bool is_expected_ffa_return(struct ffa_value ret, uint32_t func_id)
{
if (ffa_func_id(ret) == func_id) {
return true;
@@ -59,26 +79,58 @@ bool is_expected_ffa_return(smc_ret_values ret, uint32_t func_id)
return false;
}
+bool is_expected_cactus_response(struct ffa_value ret, uint32_t expected_resp,
+ uint32_t arg)
+{
+ if (!is_ffa_direct_response(ret)) {
+ return false;
+ }
+
+ if (cactus_get_response(ret) != expected_resp ||
+ (uint32_t)ret.arg4 != arg) {
+ ERROR("Expected response %x and %x; "
+ "Obtained %x and %x\n",
+ expected_resp, arg, cactus_get_response(ret),
+ (int32_t)ret.arg4);
+ return false;
+ }
+
+ return true;
+}
+
+void dump_ffa_value(struct ffa_value ret)
+{
+ NOTICE("FF-A value: %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
+ ret.fid,
+ ret.arg1,
+ ret.arg2,
+ ret.arg3,
+ ret.arg4,
+ ret.arg5,
+ ret.arg6,
+ ret.arg7);
+}
+
void fill_simd_vector_regs(const simd_vector_t v[SIMD_NUM_VECTORS])
{
#ifdef __aarch64__
__asm__ volatile(
- "ldp q0, q1, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q2, q3, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q4, q5, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q6, q7, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q8, q9, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q10, q11, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q12, q13, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q14, q15, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q16, q17, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q18, q19, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q20, q21, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q22, q23, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q24, q25, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q26, q27, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q28, q29, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q30, q31, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
+ fill_simd_helper(0, 1)
+ fill_simd_helper(2, 3)
+ fill_simd_helper(4, 5)
+ fill_simd_helper(6, 7)
+ fill_simd_helper(8, 9)
+ fill_simd_helper(10, 11)
+ fill_simd_helper(12, 13)
+ fill_simd_helper(14, 15)
+ fill_simd_helper(16, 17)
+ fill_simd_helper(18, 19)
+ fill_simd_helper(20, 21)
+ fill_simd_helper(22, 23)
+ fill_simd_helper(24, 25)
+ fill_simd_helper(26, 27)
+ fill_simd_helper(28, 29)
+ fill_simd_helper(30, 31)
"sub %0, %0, #" STR(SIMD_NUM_VECTORS * SIMD_VECTOR_LEN_BYTES) ";"
: : "r" (v));
#endif
@@ -88,29 +140,112 @@ void read_simd_vector_regs(simd_vector_t v[SIMD_NUM_VECTORS])
{
#ifdef __aarch64__
memset(v, 0, sizeof(simd_vector_t) * SIMD_NUM_VECTORS);
-
__asm__ volatile(
- "stp q0, q1, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q2, q3, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q4, q5, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q6, q7, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q8, q9, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q10, q11, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q12, q13, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q14, q15, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q16, q17, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q18, q19, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q20, q21, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q22, q23, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q24, q25, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q26, q27, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q28, q29, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q30, q31, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
+ read_simd_helper(0, 1)
+ read_simd_helper(2, 3)
+ read_simd_helper(4, 5)
+ read_simd_helper(6, 7)
+ read_simd_helper(8, 9)
+ read_simd_helper(10, 11)
+ read_simd_helper(12, 13)
+ read_simd_helper(14, 15)
+ read_simd_helper(16, 17)
+ read_simd_helper(18, 19)
+ read_simd_helper(20, 21)
+ read_simd_helper(22, 23)
+ read_simd_helper(24, 25)
+ read_simd_helper(26, 27)
+ read_simd_helper(28, 29)
+ read_simd_helper(30, 31)
"sub %0, %0, #" STR(SIMD_NUM_VECTORS * SIMD_VECTOR_LEN_BYTES) ";"
: : "r" (v));
#endif
}
+void fill_sve_vector_regs(const sve_vector_t v[SVE_NUM_VECTORS])
+{
+#ifdef __aarch64__
+ __asm__ volatile(
+ ".arch_extension sve\n"
+ fill_sve_helper(0)
+ fill_sve_helper(1)
+ fill_sve_helper(2)
+ fill_sve_helper(3)
+ fill_sve_helper(4)
+ fill_sve_helper(5)
+ fill_sve_helper(6)
+ fill_sve_helper(7)
+ fill_sve_helper(8)
+ fill_sve_helper(9)
+ fill_sve_helper(10)
+ fill_sve_helper(11)
+ fill_sve_helper(12)
+ fill_sve_helper(13)
+ fill_sve_helper(14)
+ fill_sve_helper(15)
+ fill_sve_helper(16)
+ fill_sve_helper(17)
+ fill_sve_helper(18)
+ fill_sve_helper(19)
+ fill_sve_helper(20)
+ fill_sve_helper(21)
+ fill_sve_helper(22)
+ fill_sve_helper(23)
+ fill_sve_helper(24)
+ fill_sve_helper(25)
+ fill_sve_helper(26)
+ fill_sve_helper(27)
+ fill_sve_helper(28)
+ fill_sve_helper(29)
+ fill_sve_helper(30)
+ fill_sve_helper(31)
+ ".arch_extension nosve\n"
+ : : "r" (v));
+#endif
+}
+
+void read_sve_vector_regs(sve_vector_t v[SVE_NUM_VECTORS])
+{
+#ifdef __aarch64__
+ __asm__ volatile(
+ ".arch_extension sve\n"
+ read_sve_helper(0)
+ read_sve_helper(1)
+ read_sve_helper(2)
+ read_sve_helper(3)
+ read_sve_helper(4)
+ read_sve_helper(5)
+ read_sve_helper(6)
+ read_sve_helper(7)
+ read_sve_helper(8)
+ read_sve_helper(9)
+ read_sve_helper(10)
+ read_sve_helper(11)
+ read_sve_helper(12)
+ read_sve_helper(13)
+ read_sve_helper(14)
+ read_sve_helper(15)
+ read_sve_helper(16)
+ read_sve_helper(17)
+ read_sve_helper(18)
+ read_sve_helper(19)
+ read_sve_helper(20)
+ read_sve_helper(21)
+ read_sve_helper(22)
+ read_sve_helper(23)
+ read_sve_helper(24)
+ read_sve_helper(25)
+ read_sve_helper(26)
+ read_sve_helper(27)
+ read_sve_helper(28)
+ read_sve_helper(29)
+ read_sve_helper(30)
+ read_sve_helper(31)
+ ".arch_extension nosve\n"
+ : : "r" (v));
+#endif
+}
+
/*
* check_spmc_execution_level
*
@@ -125,17 +260,17 @@ void read_simd_vector_regs(simd_vector_t v[SIMD_NUM_VECTORS])
bool check_spmc_execution_level(void)
{
unsigned int is_optee_spmc_criteria = 0U;
- smc_ret_values ret_values;
+ struct ffa_value ret_values;
/*
* Send a first OP-TEE-defined protocol message through
- * FFA direct message.
+ * FFA direct message. Expect it to implement either v1.0 or v1.1.
*/
ret_values = ffa_msg_send_direct_req32(HYP_ID, SP_ID(1),
OPTEE_FFA_GET_API_VERSION, 0,
0, 0, 0);
- if ((ret_values.ret3 == FFA_VERSION_MAJOR) &&
- (ret_values.ret4 == FFA_VERSION_MINOR)) {
+ if (ret_values.arg3 == 1 &&
+ (ret_values.arg4 == 0 || ret_values.arg4 == 1)) {
is_optee_spmc_criteria++;
}
@@ -146,8 +281,8 @@ bool check_spmc_execution_level(void)
ret_values = ffa_msg_send_direct_req32(HYP_ID, SP_ID(1),
OPTEE_FFA_GET_OS_VERSION,
0, 0, 0, 0);
- if ((ret_values.ret3 == OPTEE_FFA_GET_OS_VERSION_MAJOR) &&
- (ret_values.ret4 == OPTEE_FFA_GET_OS_VERSION_MINOR)) {
+ if ((ret_values.arg3 == OPTEE_FFA_GET_OS_VERSION_MAJOR) &&
+ (ret_values.arg4 == OPTEE_FFA_GET_OS_VERSION_MINOR)) {
is_optee_spmc_criteria++;
}
@@ -163,14 +298,13 @@ static const struct ffa_features_test ffa_feature_test_target[] = {
{"FFA_RX_RELEASE_32 check", FFA_RX_RELEASE, FFA_SUCCESS_SMC32},
{"FFA_RXTX_MAP_32 check", FFA_RXTX_MAP_SMC32, FFA_ERROR},
{"FFA_RXTX_MAP_64 check", FFA_RXTX_MAP_SMC64, FFA_SUCCESS_SMC32},
- {"FFA_RXTX_UNMAP_32 check", FFA_RXTX_UNMAP, FFA_ERROR},
+ {"FFA_RXTX_UNMAP_32 check", FFA_RXTX_UNMAP, FFA_SUCCESS_SMC32},
{"FFA_PARTITION_INFO_GET_32 check", FFA_PARTITION_INFO_GET, FFA_SUCCESS_SMC32},
{"FFA_ID_GET_32 check", FFA_ID_GET, FFA_SUCCESS_SMC32},
- {"FFA_MSG_POLL_32 check", FFA_MSG_POLL, FFA_SUCCESS_SMC32},
+ {"FFA_SPM_ID_GET_32 check", FFA_SPM_ID_GET, FFA_SUCCESS_SMC32,
+ MAKE_FFA_VERSION(1, 1)},
{"FFA_MSG_WAIT_32 check", FFA_MSG_WAIT, FFA_SUCCESS_SMC32},
- {"FFA_YIELD_32 check", FFA_MSG_YIELD, FFA_SUCCESS_SMC32},
- {"FFA_RUN_32 check", FFA_MSG_RUN, FFA_SUCCESS_SMC32},
- {"FFA_MSG_SEND_32 check", FFA_MSG_SEND, FFA_SUCCESS_SMC32},
+ {"FFA_RUN_32 check", FFA_RUN, FFA_SUCCESS_SMC32},
{"FFA_MEM_DONATE_32 check", FFA_MEM_DONATE_SMC32, FFA_SUCCESS_SMC32},
{"FFA_MEM_LEND_32 check", FFA_MEM_LEND_SMC32, FFA_SUCCESS_SMC32},
{"FFA_MEM_SHARE_32 check", FFA_MEM_SHARE_SMC32, FFA_SUCCESS_SMC32},
@@ -178,7 +312,23 @@ static const struct ffa_features_test ffa_feature_test_target[] = {
{"FFA_MEM_RETRIEVE_RESP_32 check", FFA_MEM_RETRIEVE_RESP, FFA_SUCCESS_SMC32},
{"FFA_MEM_RELINQUISH_32 check", FFA_MEM_RELINQUISH, FFA_SUCCESS_SMC32},
{"FFA_MEM_RECLAIM_32 check", FFA_MEM_RECLAIM, FFA_SUCCESS_SMC32},
- {"Check non-existent command", 0xFFFF, FFA_ERROR}
+ {"FFA_NOTIFICATION_BITMAP_CREATE_32 check",
+ FFA_NOTIFICATION_BITMAP_CREATE, FFA_SUCCESS_SMC32},
+ {"FFA_NOTIFICATION_BITMAP_DESTROY_32 check",
+ FFA_NOTIFICATION_BITMAP_DESTROY, FFA_SUCCESS_SMC32},
+ {"FFA_NOTIFICATION_BIND_32 check", FFA_NOTIFICATION_BIND,
+ FFA_SUCCESS_SMC32},
+ {"FFA_NOTIFICATION_UNBIND_32 check", FFA_NOTIFICATION_UNBIND,
+ FFA_SUCCESS_SMC32},
+ {"FFA_NOTIFICATION_SET_32 check", FFA_NOTIFICATION_SET,
+ FFA_SUCCESS_SMC32},
+ {"FFA_NOTIFICATION_INFO_GET_64 check", FFA_NOTIFICATION_INFO_GET_SMC64,
+ FFA_SUCCESS_SMC32},
+ /* Indirect messaging is only supported in Nwd */
+ {"FFA_YIELD_32 check", FFA_MSG_YIELD, FFA_ERROR},
+ {"FFA_MSG_SEND_32 check", FFA_MSG_SEND, FFA_ERROR},
+ {"FFA_MSG_POLL_32 check", FFA_MSG_POLL, FFA_ERROR},
+ {"Check non-existent command", 0xFFFF, FFA_ERROR},
};
/*
@@ -199,10 +349,10 @@ unsigned int get_ffa_feature_test_target(
bool memory_retrieve(struct mailbox_buffers *mb,
struct ffa_memory_region **retrieved, uint64_t handle,
- ffa_vm_id_t sender, ffa_vm_id_t receiver,
- uint32_t mem_func)
+ ffa_id_t sender, ffa_id_t receiver,
+ ffa_memory_region_flags_t flags)
{
- smc_ret_values ret;
+ struct ffa_value ret;
uint32_t fragment_size;
uint32_t total_size;
uint32_t descriptor_size;
@@ -212,18 +362,13 @@ bool memory_retrieve(struct mailbox_buffers *mb,
return false;
}
- /*
- * TODO: Revise shareability attribute in function call
- * below.
- * https://lists.trustedfirmware.org/pipermail/hafnium/2020-June/000023.html
- */
descriptor_size = ffa_memory_retrieve_request_init(
- mb->send, handle, sender, receiver, 0, 0,
+ mb->send, handle, sender, receiver, 0, flags,
FFA_DATA_ACCESS_RW,
FFA_INSTRUCTION_ACCESS_NX,
FFA_MEMORY_NORMAL_MEM,
FFA_MEMORY_CACHE_WRITE_BACK,
- FFA_MEMORY_OUTER_SHAREABLE);
+ FFA_MEMORY_INNER_SHAREABLE);
ret = ffa_mem_retrieve_req(descriptor_size, descriptor_size);
@@ -242,8 +387,8 @@ bool memory_retrieve(struct mailbox_buffers *mb,
* successful ffa_mem_retrieve_req, total_size must be equal to
* fragment_size.
*/
- total_size = ret.ret1;
- fragment_size = ret.ret2;
+ total_size = ret.arg1;
+ fragment_size = ret.arg2;
if (total_size != fragment_size) {
ERROR("Only expect one memory segment to be sent!\n");
@@ -269,9 +414,9 @@ bool memory_retrieve(struct mailbox_buffers *mb,
}
bool memory_relinquish(struct ffa_mem_relinquish *m, uint64_t handle,
- ffa_vm_id_t id)
+ ffa_id_t id)
{
- smc_ret_values ret;
+ struct ffa_value ret;
ffa_mem_relinquish_init(m, handle, 0, id);
ret = ffa_mem_relinquish();
@@ -288,18 +433,15 @@ bool memory_relinquish(struct ffa_mem_relinquish *m, uint64_t handle,
/**
* Helper to call memory send function whose func id is passed as a parameter.
* Returns a valid handle in case of successful operation or
- * FFA_MEMORY_HANDLE_INVALID if something goes wrong.
+ * FFA_MEMORY_HANDLE_INVALID if something goes wrong. Populates *ret with a
+ * resulting smc value to handle the error higher in the test chain.
*
* TODO: Do memory send with 'ffa_memory_region' taking multiple segments
*/
ffa_memory_handle_t memory_send(
struct ffa_memory_region *memory_region, uint32_t mem_func,
- uint32_t fragment_length, uint32_t total_length)
+ uint32_t fragment_length, uint32_t total_length, struct ffa_value *ret)
{
- smc_ret_values ret;
- ffa_vm_id_t receiver =
- memory_region->receivers[0].receiver_permissions.receiver;
-
if (fragment_length != total_length) {
ERROR("For now, fragment_length and total_length need to be"
" equal");
@@ -308,25 +450,29 @@ ffa_memory_handle_t memory_send(
switch (mem_func) {
case FFA_MEM_SHARE_SMC32:
- ret = ffa_mem_share(total_length, fragment_length);
+ *ret = ffa_mem_share(total_length, fragment_length);
break;
case FFA_MEM_LEND_SMC32:
- ret = ffa_mem_lend(total_length, fragment_length);
+ *ret = ffa_mem_lend(total_length, fragment_length);
break;
case FFA_MEM_DONATE_SMC32:
- ret = ffa_mem_donate(total_length, fragment_length);
+ *ret = ffa_mem_donate(total_length, fragment_length);
break;
default:
+ *ret = (struct ffa_value){0};
ERROR("TFTF - Invalid func id %x!\n", mem_func);
return FFA_MEMORY_HANDLE_INVALID;
}
- if (is_ffa_call_error(ret)) {
- ERROR("Failed to send message to: %x\n", receiver);
+ if (is_ffa_call_error(*ret)) {
+ VERBOSE("Failed to send memory to: %x\n",
+ memory_region->receivers[0]
+ .receiver_permissions
+ .receiver);
return FFA_MEMORY_HANDLE_INVALID;
}
- return ffa_mem_success_handle(ret);
+ return ffa_mem_success_handle(*ret);
}
/**
@@ -336,9 +482,9 @@ ffa_memory_handle_t memory_send(
*/
ffa_memory_handle_t memory_init_and_send(
struct ffa_memory_region *memory_region, size_t memory_region_max_size,
- ffa_vm_id_t sender, ffa_vm_id_t receiver,
+ ffa_id_t sender, ffa_id_t receiver,
const struct ffa_memory_region_constituent *constituents,
- uint32_t constituents_count, uint32_t mem_func)
+ uint32_t constituents_count, uint32_t mem_func, struct ffa_value *ret)
{
uint32_t remaining_constituent_count;
uint32_t total_length;
@@ -348,13 +494,21 @@ ffa_memory_handle_t memory_init_and_send(
FFA_DATA_ACCESS_NOT_SPECIFIED :
FFA_DATA_ACCESS_RW;
+ /*
+ * Initialize memory region structure for the respective memory send
+ * operation. Note that memory type shall only be specified for memory
+ * share, for memory lend and memory donate these shall remain
+ * unspecified.
+ */
remaining_constituent_count = ffa_memory_region_init(
memory_region, memory_region_max_size, sender, receiver, constituents,
constituents_count, 0, 0, data_access,
FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
- FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
- FFA_MEMORY_INNER_SHAREABLE, &total_length, &fragment_length
- );
+ mem_func == FFA_MEM_SHARE_SMC32
+ ? FFA_MEMORY_NORMAL_MEM
+ : FFA_MEMORY_NOT_SPECIFIED_MEM,
+ FFA_MEMORY_CACHE_WRITE_BACK, FFA_MEMORY_INNER_SHAREABLE,
+ &total_length, &fragment_length);
/*
* For simplicity of the test, and at least for the time being,
@@ -366,5 +520,94 @@ ffa_memory_handle_t memory_init_and_send(
}
return memory_send(memory_region, mem_func, fragment_length,
- total_length);
+ total_length, ret);
+}
+
+static bool ffa_uuid_equal(const struct ffa_uuid uuid1,
+ const struct ffa_uuid uuid2)
+{
+ return (uuid1.uuid[0] == uuid2.uuid[0]) &&
+ (uuid1.uuid[1] == uuid2.uuid[1]) &&
+ (uuid1.uuid[2] == uuid2.uuid[2]) &&
+ (uuid2.uuid[3] == uuid2.uuid[3]);
+}
+
+/**
+ * Sends a ffa_partition_info request and checks the response against the
+ * target.
+ */
+bool ffa_partition_info_helper(struct mailbox_buffers *mb,
+ const struct ffa_uuid uuid,
+ const struct ffa_partition_info *expected,
+ const uint16_t expected_size)
+{
+ bool result = true;
+ struct ffa_value ret = ffa_partition_info_get(uuid);
+
+ if (ffa_func_id(ret) == FFA_SUCCESS_SMC32) {
+ if (ffa_partition_info_count(ret) != expected_size) {
+ ERROR("Unexpected number of partitions %d\n",
+ ffa_partition_info_count(ret));
+ return false;
+ }
+ if (ffa_partition_info_desc_size(ret) !=
+ sizeof(struct ffa_partition_info)) {
+ ERROR("Unexpected partition info descriptor size %d\n",
+ ffa_partition_info_desc_size(ret));
+ return false;
+ }
+ const struct ffa_partition_info *info =
+ (const struct ffa_partition_info *)(mb->recv);
+
+ for (unsigned int i = 0U; i < expected_size; i++) {
+ /*
+ * If a UUID is specified then the UUID returned in the
+ * partition info descriptor MBZ.
+ */
+ struct ffa_uuid expected_uuid =
+ ffa_uuid_equal(uuid, NULL_UUID) ?
+ expected[i].uuid :
+ NULL_UUID;
+
+ if (info[i].id != expected[i].id) {
+ ERROR("Wrong ID. Expected %x, got %x\n",
+ expected[i].id,
+ info[i].id);
+ result = false;
+ }
+ if (info[i].exec_context != expected[i].exec_context) {
+ ERROR("Wrong context. Expected %d, got %d\n",
+ expected[i].exec_context,
+ info[i].exec_context);
+ result = false;
+ }
+ if (info[i].properties != expected[i].properties) {
+ ERROR("Wrong properties. Expected %d, got %d\n",
+ expected[i].properties,
+ info[i].properties);
+ result = false;
+ }
+
+ if (!ffa_uuid_equal(info[i].uuid, expected_uuid)) {
+ ERROR("Wrong UUID. Expected %x %x %x %x, "
+ "got %x %x %x %x\n",
+ expected_uuid.uuid[0],
+ expected_uuid.uuid[1],
+ expected_uuid.uuid[2],
+ expected_uuid.uuid[3],
+ info[i].uuid.uuid[0],
+ info[i].uuid.uuid[1],
+ info[i].uuid.uuid[2],
+ info[i].uuid.uuid[3]);
+ result = false;
+ }
+ }
+ }
+
+ ret = ffa_rx_release();
+ if (is_ffa_call_error(ret)) {
+ ERROR("Failed to release RX buffer\n");
+ result = false;
+ }
+ return result;
}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c b/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
index 0a722e49..5e52f125 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -24,14 +24,13 @@ static const struct ffa_uuid expected_sp_uuids[] = {
{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
};
-
static event_t cpu_booted[PLATFORM_CORE_COUNT];
-static test_result_t send_cactus_echo_cmd(ffa_vm_id_t sender,
- ffa_vm_id_t dest,
+static test_result_t send_cactus_echo_cmd(ffa_id_t sender,
+ ffa_id_t dest,
uint64_t value)
{
- smc_ret_values ret;
+ struct ffa_value ret;
ret = cactus_echo_send_cmd(sender, dest, value);
/*
@@ -92,12 +91,12 @@ test_result_t test_ffa_direct_messaging(void)
* otherwise.
* For the CACTUS_SUCCESS response, the test returns TEST_RESULT_SUCCESS.
*/
-static test_result_t send_cactus_req_echo_cmd(ffa_vm_id_t sender,
- ffa_vm_id_t dest,
- ffa_vm_id_t echo_dest,
+static test_result_t send_cactus_req_echo_cmd(ffa_id_t sender,
+ ffa_id_t dest,
+ ffa_id_t echo_dest,
uint64_t value)
{
- smc_ret_values ret;
+ struct ffa_value ret;
ret = cactus_req_echo_send_cmd(sender, dest, echo_dest, value);
@@ -128,13 +127,13 @@ test_result_t test_ffa_sp_to_sp_direct_messaging(void)
* The following the tests are intended to test the handling of a
* direct message request with a VM's ID as a the sender.
*/
- result = send_cactus_req_echo_cmd(HYP_ID + 1, SP_ID(2), SP_ID(3),
+ result = send_cactus_req_echo_cmd(VM_ID(1), SP_ID(2), SP_ID(3),
ECHO_VAL2);
if (result != TEST_RESULT_SUCCESS) {
return result;
}
- result = send_cactus_req_echo_cmd(HYP_ID + 2, SP_ID(3), SP_ID(1),
+ result = send_cactus_req_echo_cmd(VM_ID(2), SP_ID(3), SP_ID(1),
ECHO_VAL3);
return result;
@@ -142,7 +141,7 @@ test_result_t test_ffa_sp_to_sp_direct_messaging(void)
test_result_t test_ffa_sp_to_sp_deadlock(void)
{
- smc_ret_values ret;
+ struct ffa_value ret;
/**********************************************************************
* Check SPMC has ffa_version and expected FFA endpoints are deployed.
@@ -165,14 +164,12 @@ test_result_t test_ffa_sp_to_sp_deadlock(void)
/**
* Handler that is passed during tftf_cpu_on to individual CPU cores.
* Runs a specific core and send a direct message request.
- * Expects core_pos | SP_ID as a response.
*/
static test_result_t cpu_on_handler(void)
{
- unsigned int mpid = read_mpidr_el1() & MPID_MASK;
- unsigned int core_pos = platform_get_core_pos(mpid);
+ unsigned int core_pos = get_current_core_id();
test_result_t ret = TEST_RESULT_SUCCESS;
- smc_ret_values ffa_ret;
+ struct ffa_value ffa_ret;
/*
* Send a direct message request to SP1 (MP SP) from current physical
@@ -255,48 +252,9 @@ out:
*/
test_result_t test_ffa_secondary_core_direct_msg(void)
{
- unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
- unsigned int core_pos, cpu_node, mpidr;
- int32_t ret;
-
/**********************************************************************
* Check SPMC has ffa_version and expected FFA endpoints are deployed.
**********************************************************************/
CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
-
- for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
- tftf_init_event(&cpu_booted[i]);
- }
-
- for_each_cpu(cpu_node) {
- mpidr = tftf_get_mpidr_from_node(cpu_node);
- if (mpidr == lead_mpid) {
- continue;
- }
-
- ret = tftf_cpu_on(mpidr, (uintptr_t)cpu_on_handler, 0U);
- if (ret != 0) {
- ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
- }
- }
-
- VERBOSE("Waiting secondary CPUs to turn off ...\n");
-
- for_each_cpu(cpu_node) {
- mpidr = tftf_get_mpidr_from_node(cpu_node);
- if (mpidr == lead_mpid) {
- continue;
- }
-
- core_pos = platform_get_core_pos(mpidr);
- tftf_wait_for_event(&cpu_booted[core_pos]);
- }
-
- VERBOSE("Done exiting.\n");
-
- /**********************************************************************
- * All tests passed.
- **********************************************************************/
-
- return TEST_RESULT_SUCCESS;
+ return spm_run_multi_core_test((uintptr_t)cpu_on_handler, cpu_booted);
}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
new file mode 100644
index 00000000..61cf2ada
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <cactus_test_cmds.h>
+#include <debug.h>
+#include <ffa_endpoints.h>
+#include <ffa_svc.h>
+#include <irq.h>
+#include <platform.h>
+#include <runtime_services/realm_payload/realm_payload_test.h>
+#include <smccc.h>
+#include <spm_common.h>
+#include <test_helpers.h>
+
+#define SENDER HYP_ID
+#define RECEIVER SP_ID(1)
+
+static __aligned(PAGE_SIZE) uint64_t share_page[PAGE_SIZE / sizeof(uint64_t)];
+
+static const struct ffa_uuid expected_sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
+};
+
+/**
+ * @Test_Aim@ Check a realm region cannot be accessed from a secure partition.
+ *
+ * This test shares a TFTF allocated buffer with a secure partition through
+ * FF-A memory sharing operation. The buffer is initially marked NS in the GPT
+ * and transitioned to realm after sharing. Then, the SP is invoked to retrieve
+ * the region (map it to its S2 translation regime), and maps it to its secure
+ * S1 translation regime. It then attempts a read access which results in the
+ * PE triggering a GPF caught by a custom synchronous abort handler.
+ *
+ */
+test_result_t rl_memory_cannot_be_accessed_in_s(void)
+{
+ struct ffa_memory_region_constituent constituents[] = {
+ {
+ (void *)share_page, 1, 0
+ }
+ };
+ const uint32_t constituents_count = sizeof(constituents) /
+ sizeof(struct ffa_memory_region_constituent);
+ ffa_memory_handle_t handle;
+ struct mailbox_buffers mb;
+ struct ffa_value ret;
+ u_register_t retmm;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ handle = memory_init_and_send((struct ffa_memory_region *)mb.send,
+ PAGE_SIZE, SENDER, RECEIVER,
+ constituents, constituents_count,
+ FFA_MEM_SHARE_SMC32, &ret);
+
+ if (handle == FFA_MEMORY_HANDLE_INVALID) {
+ return TEST_RESULT_FAIL;
+ }
+
+ VERBOSE("TFTF - Handle: %llx Address: %p\n",
+ handle, constituents[0].address);
+
+ /* Delegate the shared page to Realm. */
+ retmm = realm_granule_delegate((u_register_t)&share_page);
+ if (retmm != 0UL) {
+ ERROR("Granule delegate failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Retrieve the shared page and attempt accessing it. */
+ ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_SHARE_SMC32,
+ handle, 0, true, 1);
+
+ /* Undelegate the shared page. */
+ retmm = realm_granule_undelegate((u_register_t)&share_page);
+ if (retmm != 0UL) {
+ ERROR("Granule undelegate failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ if (is_ffa_call_error(ffa_mem_reclaim(handle, 0))) {
+ ERROR("Memory reclaim failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Expect success response with value 1 hinting an exception
+ * triggered while the SP accessed the region.
+ */
+ if (!(cactus_get_response(ret) == CACTUS_SUCCESS &&
+ cactus_error_code(ret) == 1)) {
+ ERROR("Exceptions test failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_features.c b/tftf/tests/runtime_services/secure_service/test_ffa_features.c
deleted file mode 100644
index e4cd845f..00000000
--- a/tftf/tests/runtime_services/secure_service/test_ffa_features.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <spm_common.h>
-#include <test_helpers.h>
-#include <tftf_lib.h>
-
-test_result_t test_ffa_features(void)
-{
- SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
-
- /* Check if SPMC is OP-TEE at S-EL1 */
- if (check_spmc_execution_level()) {
- /* FFA_FEATURES is not yet supported in OP-TEE */
- return TEST_RESULT_SUCCESS;
- }
-
- smc_ret_values ffa_ret;
- const struct ffa_features_test *ffa_feature_test_target;
- unsigned int i, test_target_size =
- get_ffa_feature_test_target(&ffa_feature_test_target);
-
- for (i = 0U; i < test_target_size; i++) {
- ffa_ret = ffa_features(ffa_feature_test_target[i].feature);
- if (ffa_func_id(ffa_ret) != ffa_feature_test_target[i].expected_ret) {
- tftf_testcase_printf("%s returned %x, expected %x\n",
- ffa_feature_test_target[i].test_name,
- ffa_func_id(ffa_ret),
- ffa_feature_test_target[i].expected_ret);
- return TEST_RESULT_FAIL;
- }
- if ((ffa_feature_test_target[i].expected_ret == FFA_ERROR) &&
- (ffa_error_code(ffa_ret) != FFA_ERROR_NOT_SUPPORTED)) {
- tftf_testcase_printf("%s failed for the wrong reason: "
- "returned %x, expected %x\n",
- ffa_feature_test_target[i].test_name,
- ffa_error_code(ffa_ret),
- FFA_ERROR_NOT_SUPPORTED);
- return TEST_RESULT_FAIL;
- }
- }
-
- return TEST_RESULT_SUCCESS;
-}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c b/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c
index 7c70de2c..1c175137 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -64,20 +64,12 @@ static int timer_handler(void *data)
test_result_t test_ffa_ns_interrupt(void)
{
int ret;
- smc_ret_values ret_values;
+ struct ffa_value ret_values;
CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
/* Enable managed exit interrupt as FIQ in the secure side. */
- ret_values = cactus_interrupt_cmd(SENDER, RECEIVER, MANAGED_EXIT_INTERRUPT_ID,
- true, INTERRUPT_TYPE_FIQ);
-
- if (!is_ffa_direct_response(ret_values)) {
- return TEST_RESULT_FAIL;
- }
-
- if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
- ERROR("Failed to enable Managed exit interrupt\n");
+ if (!spm_set_managed_exit_int(RECEIVER, true)) {
return TEST_RESULT_FAIL;
}
@@ -134,15 +126,7 @@ test_result_t test_ffa_ns_interrupt(void)
}
/* Disable Managed exit interrupt */
- ret_values = cactus_interrupt_cmd(SENDER, RECEIVER, MANAGED_EXIT_INTERRUPT_ID,
- false, 0);
-
- if (!is_ffa_direct_response(ret_values)) {
- return TEST_RESULT_FAIL;
- }
-
- if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
- ERROR("Failed to disable Managed exit interrupt\n");
+ if (!spm_set_managed_exit_int(RECEIVER, false)) {
return TEST_RESULT_FAIL;
}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
index f126c57d..f382ff39 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,6 +25,20 @@ static const struct ffa_uuid expected_sp_uuids[] = {
/* Memory section to be used for memory share operations */
static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE];
+static bool check_written_words(uint32_t *ptr, uint32_t word, uint32_t wcount)
+{
+ VERBOSE("TFTF - Memory contents after SP use:\n");
+ for (unsigned int i = 0U; i < wcount; i++) {
+ VERBOSE(" %u: %x\n", i, ptr[i]);
+
+ /* Verify content of memory is as expected. */
+ if (ptr[i] != word) {
+ return false;
+ }
+ }
+ return true;
+}
+
/**
* Tests that it is possible to share memory with SWd from NWd.
* After calling the respective memory send API, it will expect a reply from
@@ -45,11 +59,14 @@ static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE];
*/
static test_result_t test_memory_send_sp(uint32_t mem_func)
{
- smc_ret_values ret;
+ struct ffa_value ret;
ffa_memory_handle_t handle;
uint32_t *ptr;
struct mailbox_buffers mb;
+ /* Arbitrarily write 5 words after using memory. */
+ const uint32_t nr_words_to_write = 5;
+
/***********************************************************************
* Check if SPMC has ffa_version and expected FFA endpoints are deployed.
**********************************************************************/
@@ -67,7 +84,7 @@ static test_result_t test_memory_send_sp(uint32_t mem_func)
handle = memory_init_and_send((struct ffa_memory_region *)mb.send,
MAILBOX_SIZE, SENDER, RECEIVER,
constituents, constituents_count,
- mem_func);
+ mem_func, &ret);
if (handle == FFA_MEMORY_HANDLE_INVALID) {
return TEST_RESULT_FAIL;
@@ -78,7 +95,8 @@ static test_result_t test_memory_send_sp(uint32_t mem_func)
ptr = (uint32_t *)constituents[0].address;
- ret = cactus_mem_send_cmd(SENDER, RECEIVER, mem_func, handle);
+ ret = cactus_mem_send_cmd(SENDER, RECEIVER, mem_func, handle, 0,
+ true, nr_words_to_write);
if (!is_ffa_direct_response(ret)) {
return TEST_RESULT_FAIL;
@@ -89,17 +107,11 @@ static test_result_t test_memory_send_sp(uint32_t mem_func)
return TEST_RESULT_FAIL;
}
- /*
- * Print 5 words from the memory region to validate SP wrote to the
- * memory region.
- */
- VERBOSE("TFTF - Memory contents after SP use:\n");
- for (unsigned int i = 0U; i < 5U; i++)
- VERBOSE(" %u: %x\n", i, ptr[i]);
-
- /* To make the compiler happy in case it is not a verbose build */
- if (LOG_LEVEL < LOG_LEVEL_VERBOSE)
- (void)ptr;
+ /* Check that borrower used the memory as expected for this test. */
+ if (!check_written_words(ptr, mem_func, nr_words_to_write)) {
+ ERROR("Words written to shared memory, not as expected.\n");
+ return TEST_RESULT_FAIL;
+ }
if (mem_func != FFA_MEM_DONATE_SMC32 &&
is_ffa_call_error(ffa_mem_reclaim(handle, 0))) {
@@ -130,10 +142,11 @@ test_result_t test_mem_donate_sp(void)
* Cactus SP should reply to TFTF on whether the test succeeded or not.
*/
static test_result_t test_req_mem_send_sp_to_sp(uint32_t mem_func,
- ffa_vm_id_t sender_sp,
- ffa_vm_id_t receiver_sp)
+ ffa_id_t sender_sp,
+ ffa_id_t receiver_sp,
+ bool non_secure)
{
- smc_ret_values ret;
+ struct ffa_value ret;
/***********************************************************************
* Check if SPMC's ffa_version and presence of expected FF-A endpoints.
@@ -141,33 +154,174 @@ static test_result_t test_req_mem_send_sp_to_sp(uint32_t mem_func,
CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
ret = cactus_req_mem_send_send_cmd(HYP_ID, sender_sp, mem_func,
- receiver_sp);
+ receiver_sp, non_secure);
if (!is_ffa_direct_response(ret)) {
return TEST_RESULT_FAIL;
}
if (cactus_get_response(ret) == CACTUS_ERROR) {
+ ERROR("Failed sharing memory between SPs. Error code: %d\n",
+ cactus_error_code(ret));
return TEST_RESULT_FAIL;
}
return TEST_RESULT_SUCCESS;
}
+/*
+ * Test requests a memory send operation from SP to VM.
+ * The tests expects cactus to reply CACTUS_ERROR, providing FF-A error code of
+ * the last memory send FF-A call that cactus performed.
+ */
+static test_result_t test_req_mem_send_sp_to_vm(uint32_t mem_func,
+ ffa_id_t sender_sp,
+ ffa_id_t receiver_vm)
+{
+ struct ffa_value ret;
+
+ /**********************************************************************
+ * Check if SPMC's ffa_version and presence of expected FF-A endpoints.
+ *********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+ ret = cactus_req_mem_send_send_cmd(HYP_ID, sender_sp, mem_func,
+ receiver_vm, false);
+
+ if (!is_ffa_direct_response(ret)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (cactus_get_response(ret) == CACTUS_ERROR &&
+ cactus_error_code(ret) == FFA_ERROR_DENIED) {
+ return TEST_RESULT_SUCCESS;
+ }
+
+ tftf_testcase_printf("Did not get the expected error, "
+ "mem send returned with %d\n",
+ cactus_get_response(ret));
+ return TEST_RESULT_FAIL;
+}
+
test_result_t test_req_mem_share_sp_to_sp(void)
{
return test_req_mem_send_sp_to_sp(FFA_MEM_SHARE_SMC32, SP_ID(3),
- SP_ID(2));
+ SP_ID(2), false);
+}
+
+test_result_t test_req_ns_mem_share_sp_to_sp(void)
+{
+ /*
+ * Skip the test when RME is enabled (for test setup reasons).
+ * For RME tests, the model specifies 48b physical address size
+ * at the PE, but misses allocating RAM and increasing the PA at
+ * the interconnect level.
+ */
+ if (get_armv9_2_feat_rme_support() != 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /* This test requires 48b physical address size capability. */
+ SKIP_TEST_IF_PA_SIZE_LESS_THAN(48);
+
+ return test_req_mem_send_sp_to_sp(FFA_MEM_SHARE_SMC32, SP_ID(3),
+ SP_ID(2), true);
}
test_result_t test_req_mem_lend_sp_to_sp(void)
{
return test_req_mem_send_sp_to_sp(FFA_MEM_LEND_SMC32, SP_ID(3),
- SP_ID(2));
+ SP_ID(2), false);
}
test_result_t test_req_mem_donate_sp_to_sp(void)
{
return test_req_mem_send_sp_to_sp(FFA_MEM_DONATE_SMC32, SP_ID(1),
- SP_ID(3));
+ SP_ID(3), false);
+}
+
+test_result_t test_req_mem_share_sp_to_vm(void)
+{
+ return test_req_mem_send_sp_to_vm(FFA_MEM_SHARE_SMC32, SP_ID(1),
+ HYP_ID);
+}
+
+test_result_t test_req_mem_lend_sp_to_vm(void)
+{
+ return test_req_mem_send_sp_to_vm(FFA_MEM_LEND_SMC32, SP_ID(2),
+ HYP_ID);
+}
+
+test_result_t test_mem_share_to_sp_clear_memory(void)
+{
+ struct ffa_memory_region_constituent constituents[] = {
+ {(void *)share_page, 1, 0}};
+ const uint32_t constituents_count = sizeof(constituents) /
+ sizeof(struct ffa_memory_region_constituent);
+ struct mailbox_buffers mb;
+ uint32_t remaining_constituent_count;
+ uint32_t total_length;
+ uint32_t fragment_length;
+ ffa_memory_handle_t handle;
+ struct ffa_value ret;
+ uint32_t *ptr;
+ /* Arbitrarily write 10 words after using shared memory. */
+ const uint32_t nr_words_to_write = 10U;
+
+ CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ remaining_constituent_count = ffa_memory_region_init(
+ (struct ffa_memory_region *)mb.send, MAILBOX_SIZE, SENDER,
+ RECEIVER, constituents, constituents_count, 0,
+ FFA_MEMORY_REGION_FLAG_CLEAR, FFA_DATA_ACCESS_RW,
+ FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
+ FFA_MEMORY_NOT_SPECIFIED_MEM, 0, 0,
+ &total_length, &fragment_length);
+
+ if (remaining_constituent_count != 0) {
+ ERROR("Transaction descriptor initialization failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ handle = memory_send(mb.send, FFA_MEM_LEND_SMC32, fragment_length,
+ total_length, &ret);
+
+ if (handle == FFA_MEMORY_HANDLE_INVALID) {
+ ERROR("Memory Share failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ VERBOSE("Memory has been shared!\n");
+
+ ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_LEND_SMC32, handle,
+ FFA_MEMORY_REGION_FLAG_CLEAR, true,
+ nr_words_to_write);
+
+ if (!is_ffa_direct_response(ret)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (cactus_get_response(ret) != CACTUS_SUCCESS) {
+ ERROR("Failed memory send operation!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_mem_reclaim(handle, 0);
+
+ if (is_ffa_call_error(ret)) {
+ ERROR("Memory reclaim failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ ptr = (uint32_t *)constituents[0].address;
+
+ /* Check that borrower used the memory as expected for this test. */
+ if (!check_written_words(ptr, FFA_MEM_LEND_SMC32, nr_words_to_write)) {
+ ERROR("Words written to shared memory, not as expected.\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
new file mode 100644
index 00000000..e900ae35
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
@@ -0,0 +1,1634 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <irq.h>
+#include <smccc.h>
+
+#include <arch_helpers.h>
+#include <cactus_test_cmds.h>
+#include <ffa_endpoints.h>
+#include <ffa_svc.h>
+#include <platform.h>
+#include <spm_common.h>
+#include <test_helpers.h>
+
+/**
+ * Defining variables to test the per-vCPU notifications.
+ * The conceived test follows the same logic, despite the sender receiver type
+ * of endpoint (VM or secure partition).
+ * Using global variables because these need to be accessed in the cpu on handler
+ * function 'request_notification_get_per_vcpu_on_handler'.
+ * In each specific test function, change 'per_vcpu_receiver' and
+ * 'per_vcpu_sender' have the logic work for:
+ * - NWd to SP;
+ * - SP to NWd;
+ * - SP to SP.
+ */
+static ffa_id_t per_vcpu_receiver;
+static ffa_id_t per_vcpu_sender;
+uint32_t per_vcpu_flags_get;
+static event_t per_vcpu_finished[PLATFORM_CORE_COUNT];
+
+static const struct ffa_uuid expected_sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
+};
+
+static ffa_notification_bitmap_t g_notifications = FFA_NOTIFICATION(0) |
+ FFA_NOTIFICATION(1) |
+ FFA_NOTIFICATION(30) |
+ FFA_NOTIFICATION(50) |
+ FFA_NOTIFICATION(63);
+
+/**
+ * Use FFA_FEATURES to retrieve the ID of:
+ * - Schedule Receiver Interrupt
+ * - Notification Pending Interrupt
+ * - Managed Exit Interrupt
+ * Validate the call works as expected, and they match the used int ID in the
+ * remainder of the tests.
+ */
+test_result_t test_notifications_retrieve_int_ids(void)
+{
+ struct ffa_value ret;
+
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
+ /* Check if SPMC is OP-TEE at S-EL1 */
+ if (check_spmc_execution_level()) {
+ /* FFA_FEATURES is not yet supported in OP-TEE */
+ return TEST_RESULT_SUCCESS;
+ }
+
+ ret = ffa_features(FFA_FEATURE_NPI);
+ if (is_ffa_call_error(ret) ||
+ ffa_feature_intid(ret) != NOTIFICATION_PENDING_INTERRUPT_INTID) {
+ ERROR("Failed to retrieved NPI (exp: %u, got: %u)\n",
+ NOTIFICATION_PENDING_INTERRUPT_INTID,
+ ffa_feature_intid(ret));
+
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_features(FFA_FEATURE_SRI);
+ if (is_ffa_call_error(ret) ||
+ ffa_feature_intid(ret) != FFA_SCHEDULE_RECEIVER_INTERRUPT_ID) {
+ ERROR("Failed to retrieved SRI (exp: %u, got: %u)\n",
+ FFA_SCHEDULE_RECEIVER_INTERRUPT_ID,
+ ffa_feature_intid(ret));
+
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_features(FFA_FEATURE_MEI);
+ if (is_ffa_call_error(ret) ||
+ ffa_feature_intid(ret) != MANAGED_EXIT_INTERRUPT_ID) {
+ ERROR("Failed to retrieved MEI (exp: %u, got: %u)\n",
+ MANAGED_EXIT_INTERRUPT_ID,
+ ffa_feature_intid(ret));
+
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Helper to create bitmap for NWd VMs.
+ */
+static bool notifications_bitmap_create(ffa_id_t vm_id,
+ ffa_vcpu_count_t vcpu_count)
+{
+ VERBOSE("Creating bitmap for VM %x; cpu count: %u.\n",
+ vm_id, vcpu_count);
+ struct ffa_value ret = ffa_notification_bitmap_create(vm_id,
+ vcpu_count);
+
+ return !is_ffa_call_error(ret);
+}
+
+/**
+ * Helper to destroy bitmap for NWd VMs.
+ */
+static bool notifications_bitmap_destroy(ffa_id_t vm_id)
+{
+ VERBOSE("Destroying bitmap of VM %x.\n", vm_id);
+ struct ffa_value ret = ffa_notification_bitmap_destroy(vm_id);
+
+ return !is_ffa_call_error(ret);
+}
+
+/**
+ * Test notifications bitmap create and destroy interfaces.
+ */
+test_result_t test_ffa_notifications_bitmap_create_destroy(void)
+{
+ const ffa_id_t vm_id = VM_ID(1);
+
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
+ if (check_spmc_execution_level()) {
+ VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ if (!notifications_bitmap_create(vm_id, PLATFORM_CORE_COUNT)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notifications_bitmap_destroy(vm_id)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test notifications bitmap destroy in a case the bitmap hasn't been created.
+ */
+test_result_t test_ffa_notifications_destroy_not_created(void)
+{
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
+ if (check_spmc_execution_level()) {
+ VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ struct ffa_value ret = ffa_notification_bitmap_destroy(VM_ID(1));
+
+ if (!is_expected_ffa_error(ret, FFA_ERROR_DENIED)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test attempt to create notifications bitmap for NWd VM if it had been
+ * already created.
+ */
+test_result_t test_ffa_notifications_create_after_create(void)
+{
+ struct ffa_value ret;
+ const ffa_id_t vm_id = VM_ID(2);
+
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
+ if (check_spmc_execution_level()) {
+ VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /* First successfully create a notifications bitmap */
+ if (!notifications_bitmap_create(vm_id, 1)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Attempt to do the same to the same VM. */
+ ret = ffa_notification_bitmap_create(vm_id, 1);
+
+ if (!is_expected_ffa_error(ret, FFA_ERROR_DENIED)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Destroy to not affect other tests */
+ if (!notifications_bitmap_destroy(vm_id)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Helper function to test FFA_NOTIFICATION_BIND interface.
+ * Receives all arguments to use 'cactus_notification_bind_send_cmd', and
+ * expected response for the test command.
+ *
+ * Returns:
+ * - 'true' if response was obtained and it was as expected;
+ * - 'false' if there was an error with use of FFA_MSG_SEND_DIRECT_REQ, or
+ * the obtained response was not as expected.
+ */
+static bool request_notification_bind(
+ ffa_id_t cmd_dest, ffa_id_t receiver, ffa_id_t sender,
+ ffa_notification_bitmap_t notifications, uint32_t flags,
+ uint32_t expected_resp, uint32_t error_code)
+{
+ struct ffa_value ret;
+
+ VERBOSE("TFTF requesting SP to bind notifications!\n");
+
+ ret = cactus_notification_bind_send_cmd(HYP_ID, cmd_dest, receiver,
+ sender, notifications, flags);
+
+ if (!is_expected_cactus_response(ret, expected_resp, error_code)) {
+ ERROR("Failed notifications bind. receiver: %x; sender: %x\n",
+ receiver, sender);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Helper function to test FFA_NOTIFICATION_UNBIND interface.
+ * Receives all arguments to use 'cactus_notification_unbind_send_cmd', and
+ * expected response for the test command.
+ *
+ * Returns:
+ * - 'true' if response was obtained and it was as expected;
+ * - 'false' if there was an error with use of FFA_MSG_SEND_DIRECT_REQ, or
+ * the obtained response was not as expected.
+ */
+static bool request_notification_unbind(
+ ffa_id_t cmd_dest, ffa_id_t receiver, ffa_id_t sender,
+ ffa_notification_bitmap_t notifications, uint32_t expected_resp,
+ uint32_t error_code)
+{
+ struct ffa_value ret;
+
+ VERBOSE("TFTF requesting SP to unbind notifications!\n");
+
+ ret = cactus_notification_unbind_send_cmd(HYP_ID, cmd_dest, receiver,
+ sender, notifications);
+
+ if (!is_expected_cactus_response(ret, expected_resp, error_code)) {
+ ERROR("Failed notifications unbind. receiver: %x; sender: %x\n",
+ receiver, sender);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Test calls from SPs to the bind and unbind interfaces, expecting success
+ * returns.
+ * This test issues a request via direct messaging to the SP, which executes
+ * the test and responds with the result of the call.
+ */
+test_result_t test_ffa_notifications_sp_bind_unbind(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /** First bind... */
+ if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2),
+ g_notifications, 0, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!request_notification_bind(SP_ID(1), SP_ID(1), 1,
+ g_notifications, 0, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /** ... then unbind using the same arguments. */
+ if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2),
+ g_notifications, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!request_notification_unbind(SP_ID(1), SP_ID(1), 1,
+ g_notifications, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test successful attempt of doing bind and unbind of the same set of
+ * notifications.
+ */
+test_result_t test_ffa_notifications_vm_bind_unbind(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ const ffa_id_t vm_id = VM_ID(1);
+ struct ffa_value ret;
+
+ if (!notifications_bitmap_create(vm_id, 1)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_notification_bind(SP_ID(2), vm_id, 0, g_notifications);
+
+ if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_notification_unbind(SP_ID(2), vm_id, g_notifications);
+
+ if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notifications_bitmap_destroy(vm_id)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test expected failure of using a NS FF-A ID for the sender.
+ */
+test_result_t test_ffa_notifications_vm_bind_vm(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ const ffa_id_t vm_id = VM_ID(1);
+ const ffa_id_t sender_id = VM_ID(2);
+ struct ffa_value ret;
+
+ if (!notifications_bitmap_create(vm_id, 1)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_notification_bind(sender_id, vm_id, 0, g_notifications);
+
+ if (!is_expected_ffa_error(ret, FFA_ERROR_INVALID_PARAMETER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notifications_bitmap_destroy(vm_id)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test failure of both bind and unbind in case at least one notification is
+ * already bound to another FF-A endpoint.
+ * Expect error code FFA_ERROR_DENIED.
+ */
+test_result_t test_ffa_notifications_already_bound(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /** Bind first to test */
+ if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2),
+ g_notifications, 0, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /** Attempt to bind notifications bound in above request. */
+ if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(3),
+ g_notifications, 0, CACTUS_ERROR,
+ FFA_ERROR_DENIED)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /** Attempt to unbind notifications bound in initial request. */
+ if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(3),
+ g_notifications, CACTUS_ERROR,
+ FFA_ERROR_DENIED)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /** Reset the state the SP's notifications state. */
+ if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2),
+ g_notifications, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Try to bind/unbind notifications spoofing the identity of the receiver.
+ * Commands will be sent to SP_ID(1), which will use SP_ID(3) as the receiver.
+ * Expect error code FFA_ERROR_INVALID_PARAMETER.
+ */
+test_result_t test_ffa_notifications_bind_unbind_spoofing(void)
+{
+ ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(8);
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ if (!request_notification_bind(SP_ID(1), SP_ID(3), SP_ID(2),
+ notifications, 0, CACTUS_ERROR,
+ FFA_ERROR_INVALID_PARAMETER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!request_notification_unbind(SP_ID(1), SP_ID(3), SP_ID(2),
+ notifications, CACTUS_ERROR,
+ FFA_ERROR_INVALID_PARAMETER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Call FFA_NOTIFICATION_BIND with notifications bitmap zeroed.
+ * Expecting error code FFA_ERROR_INVALID_PARAMETER.
+ */
+test_result_t test_ffa_notifications_bind_unbind_zeroed(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2),
+ 0, 0, CACTUS_ERROR,
+ FFA_ERROR_INVALID_PARAMETER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2),
+ 0, CACTUS_ERROR,
+ FFA_ERROR_INVALID_PARAMETER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Helper function to test FFA_NOTIFICATION_GET interface.
+ * Receives all arguments to use 'cactus_notification_get_send_cmd', and returns
+ * the received response. Depending on the testing scenario, this will allow
+ * to validate if the returned bitmaps are as expected.
+ *
+ * Returns:
+ * - 'true' if response was obtained.
+ * - 'false' if there was an error sending the request.
+ */
+static bool request_notification_get(
+ ffa_id_t cmd_dest, ffa_id_t receiver, uint32_t vcpu_id, uint32_t flags,
+ bool check_npi_handled, struct ffa_value *response)
+{
+ VERBOSE("TFTF requesting SP to get notifications!\n");
+
+ *response = cactus_notification_get_send_cmd(HYP_ID, cmd_dest,
+ receiver, vcpu_id,
+ flags, check_npi_handled);
+
+ return is_ffa_direct_response(*response);
+}
+
+static bool request_notification_set(
+ ffa_id_t cmd_dest, ffa_id_t receiver, ffa_id_t sender, uint32_t flags,
+ ffa_notification_bitmap_t notifications, ffa_id_t echo_dest,
+ uint32_t exp_resp, int32_t exp_error)
+{
+ struct ffa_value ret;
+
+ VERBOSE("TFTF requesting SP %x (as %x) to set notifications to %x\n",
+ cmd_dest, sender, receiver);
+
+ ret = cactus_notifications_set_send_cmd(HYP_ID, cmd_dest, receiver,
+ sender, flags, notifications,
+ echo_dest);
+
+ if (!is_expected_cactus_response(ret, exp_resp, exp_error)) {
+ ERROR("Failed notifications set. receiver: %x; sender: %x\n",
+ receiver, sender);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Helper to set notification. If sender is VM, the function will call directly
+ * FFA_NOTIFICATION_SET, if it is an SP it will request the SP to set
+ * notifications. In both cases it is expected a successful outcome.
+ */
+static bool notification_set(ffa_id_t receiver, ffa_id_t sender,
+ uint32_t flags,
+ ffa_notification_bitmap_t notifications)
+{
+ struct ffa_value ret;
+
+ /* Sender sets notifications to receiver. */
+ if (!IS_SP_ID(sender)) {
+ VERBOSE("VM %x Setting notifications %llx to receiver %x\n",
+ sender, notifications, receiver);
+ ret = ffa_notification_set(sender, receiver, flags, notifications);
+
+ if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) {
+ ERROR("Failed notifications set. receiver: %x; sender: %x\n",
+ receiver, sender);
+ return false;
+ }
+ return true;
+ }
+
+ return request_notification_set(sender, receiver, sender, flags,
+ notifications, 0, CACTUS_SUCCESS, 0);
+}
+
+/**
+ * Check that SP's response to CACTUS_NOTIFICATION_GET_CMD is as expected.
+ */
+static bool is_notifications_get_as_expected(
+ struct ffa_value *ret, uint64_t exp_from_sp, uint64_t exp_from_vm,
+ ffa_id_t receiver)
+{
+ uint64_t from_sp;
+ uint64_t from_vm;
+ bool success_ret;
+
+ /**
+ * If receiver ID is SP, this is to evaluate the response to test
+ * command 'CACTUS_NOTIFICATION_GET_CMD'.
+ */
+ if (IS_SP_ID(receiver)) {
+ success_ret = (cactus_get_response(*ret) == CACTUS_SUCCESS);
+ from_sp = cactus_notifications_get_from_sp(*ret);
+ from_vm = cactus_notifications_get_from_vm(*ret);
+ } else {
+ /**
+ * Else, this is to evaluate the return of FF-A call:
+ * ffa_notification_get.
+ */
+ success_ret = (ffa_func_id(*ret) == FFA_SUCCESS_SMC32);
+ from_sp = ffa_notifications_get_from_sp(*ret);
+ from_vm = ffa_notifications_get_from_vm(*ret);
+ }
+
+ if (success_ret != true ||
+ exp_from_sp != from_sp ||
+ exp_from_vm != from_vm) {
+ VERBOSE("Notifications not as expected:\n"
+ " from sp: %llx exp: %llx\n"
+ " from vm: %llx exp: %llx\n",
+ from_sp, exp_from_sp, from_vm, exp_from_vm);
+ return false;
+ }
+
+ return true;
+}
+
+static bool is_notifications_info_get_as_expected(
+ struct ffa_value *ret, uint16_t *ids, uint32_t *lists_sizes,
+ const uint32_t max_ids_count, uint32_t lists_count, bool more_pending)
+{
+ if (lists_count != ffa_notifications_info_get_lists_count(*ret) ||
+ more_pending != ffa_notifications_info_get_more_pending(*ret)) {
+ ERROR("Notification info get not as expected.\n"
+ " Lists counts: %u; more pending %u\n",
+ ffa_notifications_info_get_lists_count(*ret),
+ ffa_notifications_info_get_more_pending(*ret));
+ dump_ffa_value(*ret);
+ return false;
+ }
+
+ for (uint32_t i = 0; i < lists_count; i++) {
+ uint32_t cur_size =
+ ffa_notifications_info_get_list_size(*ret,
+ i + 1);
+
+ if (lists_sizes[i] != cur_size) {
+ ERROR("Expected list size[%u] %u != %u\n", i,
+ lists_sizes[i], cur_size);
+ return false;
+ }
+ }
+
+ /* Compare the IDs list */
+ if (memcmp(&ret->arg3, ids, sizeof(ids[0]) * max_ids_count) != 0) {
+ ERROR("List of IDs not as expected\n");
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Helper to bind notification and set it.
+ * If receiver is SP it will request SP to perform the bind, else invokes
+ * FFA_NOTIFICATION_BIND.
+ * If Sender is SP it will request it to perform the set, else invokes
+ * FFA_NOTIFICATION_SET.
+ */
+static bool notification_bind_and_set(ffa_id_t sender,
+ ffa_id_t receiver, ffa_notification_bitmap_t notifications, uint32_t flags)
+{
+ struct ffa_value ret;
+ uint32_t flags_bind = flags & FFA_NOTIFICATIONS_FLAG_PER_VCPU;
+
+ /* Receiver binds notifications to sender. */
+ if (!IS_SP_ID(receiver)) {
+ ret = ffa_notification_bind(sender, receiver,
+ flags_bind, notifications);
+
+ if (is_ffa_call_error(ret)) {
+ return false;
+ }
+ } else {
+ if (!request_notification_bind(receiver, receiver, sender,
+ notifications, flags_bind,
+ CACTUS_SUCCESS,
+ 0)) {
+ return false;
+ }
+ }
+
+ return notification_set(receiver, sender, flags, notifications);
+}
+
+/**
+ * Helper to request SP to get the notifications and validate the return.
+ */
+static bool notification_get_and_validate(
+ ffa_id_t receiver, ffa_notification_bitmap_t exp_from_sp,
+ ffa_notification_bitmap_t exp_from_vm, uint32_t vcpu_id,
+ uint32_t flags, bool check_npi_handled)
+{
+ struct ffa_value ret;
+
+ /* Receiver gets pending notifications. */
+ if (IS_SP_ID(receiver)) {
+ request_notification_get(receiver, receiver, vcpu_id, flags,
+ check_npi_handled, &ret);
+ } else {
+ ret = ffa_notification_get(receiver, vcpu_id, flags);
+ }
+
+ return is_notifications_get_as_expected(&ret, exp_from_sp, exp_from_vm,
+ receiver);
+}
+
+static bool notifications_info_get(
+ uint16_t *expected_ids, uint32_t expected_lists_count,
+ uint32_t *expected_lists_sizes, const uint32_t max_ids_count,
+ bool expected_more_pending)
+{
+ struct ffa_value ret;
+
+ VERBOSE("Getting pending notification's info.\n");
+
+ ret = ffa_notification_info_get();
+
+ return !is_ffa_call_error(ret) &&
+ is_notifications_info_get_as_expected(&ret, expected_ids,
+ expected_lists_sizes,
+ max_ids_count,
+ expected_lists_count,
+ expected_more_pending);
+}
+
+static volatile int schedule_receiver_interrupt_received;
+
+static int schedule_receiver_interrupt_handler(void *data)
+{
+ assert(schedule_receiver_interrupt_received == 0);
+ schedule_receiver_interrupt_received = 1;
+ return 0;
+}
+
+/**
+ * Enable the Schedule Receiver Interrupt and register the respective
+ * handler.
+ */
+static void schedule_receiver_interrupt_init(void)
+{
+ tftf_irq_register_handler(FFA_SCHEDULE_RECEIVER_INTERRUPT_ID,
+ schedule_receiver_interrupt_handler);
+
+ tftf_irq_enable(FFA_SCHEDULE_RECEIVER_INTERRUPT_ID, 0xA);
+}
+
+/**
+ * Enable the Notification Pending Interrupt for the target SP.
+ */
+static bool notification_pending_interrupt_sp_enable(ffa_id_t receiver,
+ bool enable)
+{
+ VERBOSE("Configuring NPI to receiver: %x\n", receiver);
+ struct ffa_value ret = cactus_interrupt_cmd(
+ HYP_ID, receiver, NOTIFICATION_PENDING_INTERRUPT_INTID,
+ enable, INTERRUPT_TYPE_IRQ);
+
+
+ if (!is_ffa_direct_response(ret) ||
+ cactus_get_response(ret) != CACTUS_SUCCESS) {
+ ERROR("Failed to configure NPI in SP %x core: %x\n",
+ receiver, get_current_core_id());
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Disable the Schedule Receiver Interrupt and unregister the respective
+ * handler.
+ */
+static void schedule_receiver_interrupt_deinit(void)
+{
+ tftf_irq_disable(FFA_SCHEDULE_RECEIVER_INTERRUPT_ID);
+ tftf_irq_unregister_handler(FFA_SCHEDULE_RECEIVER_INTERRUPT_ID);
+ schedule_receiver_interrupt_received = 0;
+}
+
+bool check_schedule_receiver_interrupt_handled(void)
+{
+ if (schedule_receiver_interrupt_received == 1) {
+ VERBOSE("Schedule Receiver Interrupt handled!\n");
+ schedule_receiver_interrupt_received = 0;
+ return true;
+ }
+ VERBOSE("Schedule Receiver Interrupt NOT handled!\n");
+ return false;
+}
+
+/**
+ * Base function to test notifications signaling with an SP as a receiver.
+ */
+static test_result_t base_test_global_notifications_signal_sp(
+ const ffa_id_t sender, const ffa_id_t receiver,
+ const ffa_notification_bitmap_t notifications, const uint32_t flags_get)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ if (!IS_SP_ID(receiver)) {
+ ERROR("Receiver is expected to be an SP ID!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Variables to validate calls to FFA_NOTIFICATION_INFO_GET. */
+ uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t lists_count;
+ uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ schedule_receiver_interrupt_init();
+
+ /* Enable NPI. */
+ if (!notification_pending_interrupt_sp_enable(receiver, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notification_bind_and_set(sender, receiver, notifications,
+ FFA_NOTIFICATIONS_FLAG_DELAY_SRI)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /**
+ * Simple list of IDs expected on return from FFA_NOTIFICATION_INFO_GET.
+ */
+ ids[0] = receiver;
+ lists_count = 1;
+
+ if (!notifications_info_get(ids, lists_count, lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ false)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notification_get_and_validate(
+ receiver, IS_SP_ID(sender) ? notifications : 0,
+ !IS_SP_ID(sender) ? notifications : 0, 0, flags_get, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!request_notification_unbind(receiver, receiver, sender,
+ notifications, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable NPI. */
+ if (!notification_pending_interrupt_sp_enable(receiver, false)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test to validate a VM can signal an SP.
+ */
+test_result_t test_ffa_notifications_vm_signals_sp(void)
+{
+ return base_test_global_notifications_signal_sp(
+ 1, SP_ID(1), FFA_NOTIFICATION(1) | FFA_NOTIFICATION(60),
+ FFA_NOTIFICATIONS_FLAG_BITMAP_VM);
+}
+
+/**
+ * Test to validate an SP can signal an SP.
+ */
+test_result_t test_ffa_notifications_sp_signals_sp(void)
+{
+ return base_test_global_notifications_signal_sp(
+ SP_ID(1), SP_ID(2), g_notifications,
+ FFA_NOTIFICATIONS_FLAG_BITMAP_SP);
+}
+
+/**
+ * Test to validate an SP can signal a VM.
+ */
+test_result_t test_ffa_notifications_sp_signals_vm(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ const ffa_id_t sender = SP_ID(1);
+ const ffa_id_t receiver = VM_ID(1);
+ uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_SP;
+ struct ffa_value ret;
+ test_result_t result = TEST_RESULT_SUCCESS;
+
+ /* Variables to validate calls to FFA_NOTIFICATION_INFO_GET. */
+ uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t lists_count;
+ uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+
+ /* Ask SPMC to allocate notifications bitmap. */
+ if (!notifications_bitmap_create(receiver, 1)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_init();
+
+ /* Request receiver to bind a set of notifications to the sender. */
+ if (!notification_bind_and_set(sender, receiver, g_notifications,
+ FFA_NOTIFICATIONS_FLAG_DELAY_SRI)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /*
+ * FFA_NOTIFICATION_INFO_GET return list should be simple, containing
+ * only the receiver's ID.
+ */
+ ids[0] = receiver;
+ lists_count = 1;
+
+ if (!notifications_info_get(ids, lists_count, lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ false)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Get pending notifications, and retrieve response. */
+ if (!notification_get_and_validate(receiver, g_notifications, 0, 0,
+ get_flags, false)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_notification_unbind(sender, receiver, g_notifications);
+
+ if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ if (!notifications_bitmap_destroy(receiver)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ return result;
+}
+
+/**
+ * Test to validate it is not possible to unbind a pending notification.
+ */
+test_result_t test_ffa_notifications_unbind_pending(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ const ffa_id_t receiver = SP_ID(1);
+ const ffa_id_t sender = VM_ID(1);
+ const ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(30) |
+ FFA_NOTIFICATION(35);
+ uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_VM;
+
+ schedule_receiver_interrupt_init();
+
+ /* Request receiver to bind a set of notifications to the sender. */
+ if (!notification_bind_and_set(sender, receiver, notifications, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Attempt to unbind the pending notification, but expect error return
+ * given the notification is pending.
+ */
+ if (!request_notification_unbind(receiver, receiver, sender,
+ FFA_NOTIFICATION(30),
+ CACTUS_ERROR, FFA_ERROR_DENIED)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Request receiver partition to get pending notifications from VMs.
+ * Only notification 30 is expected.
+ */
+ if (!notification_get_and_validate(receiver, 0, notifications, 0,
+ get_flags, false)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Unbind all notifications, to not interfere with other tests. */
+ if (!request_notification_unbind(receiver, receiver, sender,
+ notifications, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test the result of a call to FFA_NOTIFICATION_INFO_GET if no pending
+ * notifications.
+ */
+test_result_t test_ffa_notifications_info_get_none(void)
+{
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
+ if (check_spmc_execution_level()) {
+ VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ struct ffa_value ret;
+
+ ret = ffa_notification_info_get();
+
+ if (!is_expected_ffa_error(ret, FFA_ERROR_NO_DATA)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * CPU_ON handler for testing per-vCPU notifications to SPs (either from VMs
+ * or from SPs). It requests the SP to retrieve its pending notifications
+ * within its current Execution Context. The SP shall obtain all per-vCPU
+ * targeted to the running vCPU.
+ */
+static test_result_t request_notification_get_per_vcpu_on_handler(void)
+{
+ unsigned int core_pos = get_current_core_id();
+ test_result_t result = TEST_RESULT_FAIL;
+
+ uint64_t exp_from_vm = 0;
+ uint64_t exp_from_sp = 0;
+
+ if (IS_SP_ID(per_vcpu_sender)) {
+ exp_from_sp = FFA_NOTIFICATION(core_pos);
+ } else {
+ exp_from_vm = FFA_NOTIFICATION(core_pos);
+ }
+
+ VERBOSE("Request get per-vCPU notification to %x, core: %u.\n",
+ per_vcpu_receiver, core_pos);
+
+ /*
+ * Secure Partitions secondary ECs need one round of ffa_run to reach
+ * the message loop.
+ */
+ if (!spm_core_sp_init(per_vcpu_receiver)) {
+ goto out;
+ }
+
+ /*
+ * Request to get notifications sent to the respective vCPU.
+ * Check also if NPI was handled by the receiver. It should have been
+ * pended at notifications set, in the respective vCPU.
+ */
+ if (!notification_get_and_validate(
+ per_vcpu_receiver, exp_from_sp, exp_from_vm, core_pos,
+ per_vcpu_flags_get, true)) {
+ goto out;
+ }
+
+ result = TEST_RESULT_SUCCESS;
+
+out:
+ /* Tell the lead CPU that the calling CPU has completed the test. */
+ tftf_send_event(&per_vcpu_finished[core_pos]);
+
+ return result;
+}
+
+static test_result_t base_npi_enable_per_cpu(bool enable)
+{
+ test_result_t result = TEST_RESULT_FAIL;
+ uint32_t core_pos = get_current_core_id();
+
+ VERBOSE("Request SP %x to enable NPI in core %u\n",
+ per_vcpu_receiver, core_pos);
+
+ /*
+ * Secure Partitions secondary ECs need one round of ffa_run to reach
+ * the message loop.
+ */
+ if (!spm_core_sp_init(per_vcpu_receiver)) {
+ goto out;
+ }
+
+ if (!notification_pending_interrupt_sp_enable(per_vcpu_receiver,
+ enable)) {
+ goto out;
+ }
+
+ result = TEST_RESULT_SUCCESS;
+
+out:
+ /* Tell the lead CPU that the calling CPU has completed the test. */
+ tftf_send_event(&per_vcpu_finished[core_pos]);
+
+ return result;
+}
+
+static test_result_t npi_enable_per_vcpu_on_handler(void)
+{
+ return base_npi_enable_per_cpu(true);
+}
+
+static test_result_t npi_disable_per_vcpu_on_handler(void)
+{
+ return base_npi_enable_per_cpu(false);
+}
+/**
+ * Base function to test signaling of per-vCPU notifications.
+ * Test whole flow between two FF-A endpoints: binding, getting notification
+ * info, and getting pending notifications.
+ * Each vCPU will receive a notification whose ID is the same as the core
+ * position.
+ */
+static test_result_t base_test_per_vcpu_notifications(ffa_id_t sender,
+ ffa_id_t receiver)
+{
+ /*
+ * Manually set variables to validate what should be the return of to
+ * FFA_NOTIFICATION_INFO_GET.
+ */
+ uint16_t exp_ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+ receiver, 0, 1, 2,
+ receiver, 3, 4, 5,
+ receiver, 6, 7, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ };
+ uint32_t exp_lists_count = 3;
+ uint32_t exp_lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+ 3, 3, 2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ const bool exp_more_notif_pending = false;
+ test_result_t result = TEST_RESULT_SUCCESS;
+ uint64_t notifications_to_unbind = 0;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ per_vcpu_flags_get = IS_SP_ID(sender)
+ ? FFA_NOTIFICATIONS_FLAG_BITMAP_SP
+ : FFA_NOTIFICATIONS_FLAG_BITMAP_VM;
+
+ /* Setting global variables to be accessed by the cpu_on handler. */
+ per_vcpu_receiver = receiver;
+ per_vcpu_sender = sender;
+
+ /* Boot all cores and enable the NPI in all of them. */
+ if (spm_run_multi_core_test(
+ (uintptr_t)npi_enable_per_vcpu_on_handler,
+ per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Enable NPI in lead core. */
+ if (!notification_pending_interrupt_sp_enable(receiver, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Prepare notifications bitmap to request Cactus to bind them as
+ * per-vCPU.
+ */
+ for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+ notifications_to_unbind |= FFA_NOTIFICATION(i);
+
+ uint32_t flags = FFA_NOTIFICATIONS_FLAG_DELAY_SRI |
+ FFA_NOTIFICATIONS_FLAG_PER_VCPU |
+ FFA_NOTIFICATIONS_FLAGS_VCPU_ID((uint16_t)i);
+
+ if (!notification_bind_and_set(sender,
+ receiver,
+ FFA_NOTIFICATION(i),
+ flags)) {
+ return TEST_RESULT_FAIL;
+ }
+ }
+
+ /* Call FFA_NOTIFICATION_INFO_GET and validate return. */
+ if (!notifications_info_get(exp_ids, exp_lists_count, exp_lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ exp_more_notif_pending)) {
+ ERROR("Info Get Failed....\n");
+ result = TEST_RESULT_FAIL;
+ goto out;
+ }
+
+ /*
+ * Request SP to get notifications in core 0, as this is not iterated
+ * at the CPU ON handler.
+ * Set `check_npi_handled` to true, as the receiver is supposed to be
+ * preempted by the NPI.
+ */
+ if (!notification_get_and_validate(
+ receiver, IS_SP_ID(sender) ? FFA_NOTIFICATION(0) : 0,
+ !IS_SP_ID(sender) ? FFA_NOTIFICATION(0) : 0, 0,
+ per_vcpu_flags_get, true)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Bring up all the cores, and request the receiver to get notifications
+ * in each one of them.
+ */
+ if (spm_run_multi_core_test(
+ (uintptr_t)request_notification_get_per_vcpu_on_handler,
+ per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+ result = TEST_RESULT_FAIL;
+ }
+
+out:
+ /* As a clean-up, unbind notifications. */
+ if (!request_notification_unbind(receiver, receiver,
+ sender,
+ notifications_to_unbind,
+ CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Boot all cores and DISABLE the NPI in all of them. */
+ if (spm_run_multi_core_test(
+ (uintptr_t)npi_disable_per_vcpu_on_handler,
+ per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable the NPI in the receiver. */
+ if (!notification_pending_interrupt_sp_enable(receiver, false)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return result;
+}
+
+/**
+ * Test to validate a VM can signal a per-vCPU notification to an SP.
+ */
+test_result_t test_ffa_notifications_vm_signals_sp_per_vcpu(void)
+{
+ return base_test_per_vcpu_notifications(0, SP_ID(1));
+}
+
+/**
+ * Test to validate an SP can signal a per-vCPU notification to an SP.
+ */
+test_result_t test_ffa_notifications_sp_signals_sp_per_vcpu(void)
+{
+ return base_test_per_vcpu_notifications(SP_ID(1), SP_ID(2));
+}
+
+static test_result_t notification_get_per_vcpu_on_handler(void)
+{
+ unsigned int core_pos = get_current_core_id();
+ test_result_t result = TEST_RESULT_SUCCESS;
+
+ VERBOSE("Getting per-vCPU notifications from %x, core: %u.\n",
+ per_vcpu_receiver, core_pos);
+
+ if (!spm_core_sp_init(per_vcpu_sender)) {
+ goto out;
+ }
+
+ if (!notification_get_and_validate(per_vcpu_receiver,
+ FFA_NOTIFICATION(core_pos), 0,
+ core_pos,
+ FFA_NOTIFICATIONS_FLAG_BITMAP_SP,
+ false)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+out:
+ /* Tell the lead CPU that the calling CPU has completed the test. */
+ tftf_send_event(&per_vcpu_finished[core_pos]);
+
+ return result;
+}
+
+/**
+ * Test whole flow from binding, to getting notifications' info, and getting
+ * pending notifications, namely signaling of notifications from SP to a VM.
+ * Each vCPU will receive a notification whose ID is the same as the core
+ * position.
+ */
+test_result_t test_ffa_notifications_sp_signals_vm_per_vcpu(void)
+{
+ /* Making a VM the receiver, and an SP the sender */
+ per_vcpu_receiver = VM_ID(1);
+ per_vcpu_sender = SP_ID(2);
+
+ /**
+ * Manually set variables to validate what should be the return of to
+ * FFA_NOTIFICATION_INFO_GET.
+ */
+ uint16_t exp_ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+ per_vcpu_receiver, 0, 1, 2,
+ per_vcpu_receiver, 3, 4, 5,
+ per_vcpu_receiver, 6, 7, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ };
+ uint32_t exp_lists_count = 3;
+ uint32_t exp_lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+ 3, 3, 2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ const bool exp_more_notif_pending = false;
+ test_result_t result = TEST_RESULT_SUCCESS;
+ uint64_t notifications_to_unbind = 0;
+ struct ffa_value ret;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Create bitmap for receiver. */
+ if (!notifications_bitmap_create(per_vcpu_receiver,
+ PLATFORM_CORE_COUNT)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Bind notifications, and request Cactus SP to set them. */
+ for (uint32_t i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+ notifications_to_unbind |= FFA_NOTIFICATION(i);
+
+ uint32_t flags = FFA_NOTIFICATIONS_FLAG_DELAY_SRI |
+ FFA_NOTIFICATIONS_FLAG_PER_VCPU |
+ FFA_NOTIFICATIONS_FLAGS_VCPU_ID((uint16_t)i);
+
+ if (!notification_bind_and_set(per_vcpu_sender,
+ per_vcpu_receiver,
+ FFA_NOTIFICATION(i),
+ flags)) {
+ return TEST_RESULT_FAIL;
+ };
+ }
+
+ /* Call FFA_NOTIFICATION_INFO_GET and validate return. */
+ if (!notifications_info_get(exp_ids, exp_lists_count, exp_lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ exp_more_notif_pending)) {
+ ERROR("Info Get Failed....\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Get notifications in core 0, as it is not iterated at the CPU ON
+ * handler.
+ */
+ if (!notification_get_and_validate(per_vcpu_receiver,
+ FFA_NOTIFICATION(0), 0, 0,
+ FFA_NOTIFICATIONS_FLAG_BITMAP_SP,
+ false)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Bring up all the cores, and get notifications in each one of them. */
+ if (spm_run_multi_core_test(
+ (uintptr_t)notification_get_per_vcpu_on_handler,
+ per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+ ERROR("Failed to get per-vCPU notifications\n");
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* As a clean-up, unbind notifications. */
+ ret = ffa_notification_unbind(per_vcpu_sender, per_vcpu_receiver,
+ notifications_to_unbind);
+ if (is_ffa_call_error(ret)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ return result;
+}
+
+/**
+ * Test to validate behavior in SWd if the SRI is not delayed. If the
+ * notification setter handled a managed exit it is indicative the SRI was
+ * sent immediately.
+ */
+test_result_t test_ffa_notifications_sp_signals_sp_immediate_sri(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ const ffa_id_t sender = SP_ID(1);
+ const ffa_id_t receiver = SP_ID(2);
+ uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_SP;
+ struct ffa_value ret;
+ test_result_t result = TEST_RESULT_SUCCESS;
+
+ /** Variables to validate calls to FFA_NOTIFICATION_INFO_GET. */
+ uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t lists_count;
+ uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+
+ ids[0] = receiver;
+ lists_count = 1;
+
+ /* Enable managed exit interrupt as FIQ in the secure side. */
+ if (!spm_set_managed_exit_int(sender, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_init();
+
+ /* Request receiver to bind a set of notifications to the sender. */
+ if (!request_notification_bind(receiver, receiver, sender,
+ g_notifications, 0, CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Request sender to set notification, and expect the response is
+ * MANAGED_EXIT_INTERRUPT_ID.
+ */
+ if (!request_notification_set(sender, receiver, sender, 0,
+ g_notifications, 0,
+ MANAGED_EXIT_INTERRUPT_ID, 0)) {
+ ERROR("SRI not handled immediately!\n");
+ result = TEST_RESULT_FAIL;
+ } else {
+ VERBOSE("SP %x did a managed exit.\n", sender);
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Call FFA_NOTIFICATION_INFO_GET and validate return. */
+ if (!notifications_info_get(ids, lists_count, lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ false)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Validate notification get. */
+ if (!request_notification_get(receiver, receiver, 0, get_flags, false, &ret) ||
+ !is_notifications_get_as_expected(&ret, g_notifications, 0,
+ receiver)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Resume setter Cactus in the handling of CACTUS_NOTIFICATIONS_SET_CMD.
+ */
+ ret = ffa_msg_send_direct_req64(HYP_ID, sender, 0, 0, 0, 0, 0);
+
+ /* Expected result to CACTUS_NOTIFICATIONS_SET_CMD. */
+ if (!is_expected_cactus_response(ret, CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Unbind for clean-up. */
+ if (!request_notification_unbind(receiver, receiver, sender,
+ g_notifications, CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ /* Disable managed exit interrupt as FIQ in the secure side. */
+ if (!spm_set_managed_exit_int(sender, false)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return result;
+}
+
+/**
+ * Test to validate behavior in SWd if the SRI is delayed.
+ */
+test_result_t test_ffa_notifications_sp_signals_sp_delayed_sri(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ const ffa_id_t sender = SP_ID(3);
+ const ffa_id_t receiver = SP_ID(2);
+ const ffa_id_t echo_dest = SP_ID(1);
+ uint32_t echo_dest_cmd_count = 0;
+ uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_SP;
+ struct ffa_value ret;
+ test_result_t result = TEST_RESULT_SUCCESS;
+
+ /** Variables to validate calls to FFA_NOTIFICATION_INFO_GET. */
+ uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t lists_count;
+ uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+
+ ids[0] = receiver;
+ lists_count = 1;
+
+ /* Enable managed exit interrupt as FIQ in the secure side. */
+ if (!spm_set_managed_exit_int(sender, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_init();
+
+ /* Request receiver to bind a set of notifications to the sender. */
+ if (!request_notification_bind(receiver, receiver, sender,
+ g_notifications, 0, CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ ret = cactus_get_req_count_send_cmd(HYP_ID, echo_dest);
+
+ if (cactus_get_response(ret) == CACTUS_SUCCESS) {
+ /*
+ * Save the command count from the echo_dest, to validate it
+ * has been incremented after the request to set notifications.
+ */
+ echo_dest_cmd_count = cactus_get_req_count(ret);
+ VERBOSE("Partition %x command count %u.\n", echo_dest,
+ echo_dest_cmd_count);
+ } else {
+ VERBOSE("Failed to get cmds count from %u\n", echo_dest);
+ result = TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Request sender to set notification with Delay SRI flag, and specify
+ * echo destination.
+ */
+ if (!request_notification_set(sender, receiver, sender,
+ FFA_NOTIFICATIONS_FLAG_DELAY_SRI,
+ g_notifications, echo_dest,
+ CACTUS_SUCCESS, 0)) {
+ VERBOSE("Failed to set notifications!\n");
+ result = TEST_RESULT_FAIL;
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Get command count again from echo_dest, to validate that it has been
+ * incremented by one. This should indicate the notification setter has
+ * issued a request to echo_dest right after the notification set, thus
+ * proving the SRI hasn't been sent right after FFA_NOTIFICATION_SET.
+ */
+ ret = cactus_get_req_count_send_cmd(HYP_ID, echo_dest);
+ if (cactus_get_response(ret) == CACTUS_SUCCESS) {
+ if (cactus_get_req_count(ret) == echo_dest_cmd_count + 1) {
+ VERBOSE("SRI successfully delayed.\n");
+ } else {
+ VERBOSE("Failed to get cmds count from %u.\n",
+ echo_dest);
+ result = TEST_RESULT_FAIL;
+ }
+ } else {
+ VERBOSE("Failed to get cmds count from %x\n", echo_dest);
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Call FFA_NOTIFICATION_INFO_GET and validate return. */
+ if (!notifications_info_get(ids, lists_count, lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ false)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Validate notification get. */
+ if (!request_notification_get(receiver, receiver, 0, get_flags, false, &ret) ||
+ !is_notifications_get_as_expected(&ret, g_notifications, 0,
+ receiver)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Unbind for clean-up. */
+ if (!request_notification_unbind(receiver, receiver, sender,
+ g_notifications, CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ /* Disable managed exit interrupt as FIQ in the secure side. */
+ if (!spm_set_managed_exit_int(sender, false)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return result;
+}
+
+test_result_t notifications_set_per_vcpu_on_handler(void)
+{
+ unsigned int core_pos = get_current_core_id();
+ test_result_t result = TEST_RESULT_FAIL;
+
+ if (!spm_core_sp_init(per_vcpu_sender)) {
+ goto out;
+ }
+
+ if (!notification_set(per_vcpu_receiver, per_vcpu_sender,
+ FFA_NOTIFICATIONS_FLAG_DELAY_SRI |
+ FFA_NOTIFICATIONS_FLAG_PER_VCPU |
+ FFA_NOTIFICATIONS_FLAGS_VCPU_ID(0),
+ FFA_NOTIFICATION(core_pos))) {
+ goto out;
+ }
+
+ result = TEST_RESULT_SUCCESS;
+
+out:
+ /* Tell the lead CPU that the calling CPU has completed the test. */
+ tftf_send_event(&per_vcpu_finished[core_pos]);
+
+ return result;
+}
+
+test_result_t test_ffa_notifications_mp_sp_signals_up_sp(void)
+{
+ ffa_notification_bitmap_t to_bind = 0;
+
+ /* prepare info get variables. */
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Setting per-vCPU sender and receiver IDs. */
+ per_vcpu_sender = SP_ID(2); /* MP SP */
+ per_vcpu_receiver = SP_ID(3); /* UP SP */
+
+ schedule_receiver_interrupt_init();
+
+ notification_pending_interrupt_sp_enable(per_vcpu_receiver, true);
+
+ /* Prepare notifications bitmap to have one bit platform core. */
+ for (uint32_t i = 0; i < PLATFORM_CORE_COUNT; i++) {
+ to_bind |= FFA_NOTIFICATION(i);
+ }
+
+ /* Request receiver to bind a set of notifications to the sender. */
+ if (!request_notification_bind(per_vcpu_receiver, per_vcpu_receiver,
+ per_vcpu_sender, to_bind,
+ FFA_NOTIFICATIONS_FLAG_PER_VCPU,
+ CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Boot up system, and then request sender to signal notification from
+ * every core into into receiver's only vCPU. Delayed SRI.
+ */
+ if (!notification_set(per_vcpu_receiver, per_vcpu_sender,
+ FFA_NOTIFICATIONS_FLAG_DELAY_SRI |
+ FFA_NOTIFICATIONS_FLAG_PER_VCPU |
+ FFA_NOTIFICATIONS_FLAGS_VCPU_ID(0),
+ FFA_NOTIFICATION(0))) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (spm_run_multi_core_test(
+ (uintptr_t)notifications_set_per_vcpu_on_handler,
+ per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notification_get_and_validate(per_vcpu_receiver, to_bind, 0, 0,
+ FFA_NOTIFICATIONS_FLAG_BITMAP_SP, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Request unbind. */
+ if (!request_notification_unbind(per_vcpu_receiver, per_vcpu_receiver,
+ per_vcpu_sender, to_bind,
+ CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ notification_pending_interrupt_sp_enable(per_vcpu_receiver, false);
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_rxtx_map.c b/tftf/tests/runtime_services/secure_service/test_ffa_rxtx_map.c
deleted file mode 100644
index 1b47c5f9..00000000
--- a/tftf/tests/runtime_services/secure_service/test_ffa_rxtx_map.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <debug.h>
-
-#include <test_helpers.h>
-#include <xlat_tables_defs.h>
-
-static struct mailbox_buffers mb;
-
-static test_result_t test_ffa_rxtx_map(uint32_t expected_return)
-{
- smc_ret_values ret;
-
- /**********************************************************************
- * Verify that FFA is there and that it has the correct version.
- **********************************************************************/
- SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
-
- /**********************************************************************
- * If OP-TEE is SPMC skip this test.
- **********************************************************************/
- if (check_spmc_execution_level()) {
- VERBOSE("OP-TEE as SPMC at S-EL1. Skipping test!\n");
- return TEST_RESULT_SKIPPED;
- }
-
- /*
- * Declare RXTX buffers, assign them to the mailbox and call
- * FFA_RXTX_MAP.
- */
- CONFIGURE_AND_MAP_MAILBOX(mb, PAGE_SIZE, ret);
- if (ffa_func_id(ret) != expected_return) {
- ERROR("Failed to map RXTX buffers %x!\n", ffa_error_code(ret));
- return TEST_RESULT_FAIL;
- }
-
- return TEST_RESULT_SUCCESS;
-}
-
-/**
- * Test mapping RXTX buffers from NWd.
- * This test also sets the Mailbox for other SPM related tests that need to use
- * RXTX buffers.
- */
-test_result_t test_ffa_rxtx_map_success(void)
-{
- test_result_t ret = test_ffa_rxtx_map(FFA_SUCCESS_SMC32);
-
- if (ret == TEST_RESULT_SUCCESS) {
- INFO("Set RXTX Mailbox for remaining spm tests!\n");
- set_tftf_mailbox(&mb);
- }
- return ret;
-}
-
-/**
- * Test to verify that 2nd call to FFA_RXTX_MAP should fail.
- */
-test_result_t test_ffa_rxtx_map_fail(void)
-{
- INFO("This test expects error log.\n");
- return test_ffa_rxtx_map(FFA_ERROR);
-}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c b/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c
new file mode 100644
index 00000000..ac19c06f
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cactus_test_cmds.h>
+#include <ffa_endpoints.h>
+#include <ffa_helpers.h>
+#include <test_helpers.h>
+#include <timer.h>
+
+#define SENDER HYP_ID
+#define RECEIVER SP_ID(1)
+#define RECEIVER_2 SP_ID(2)
+#define SP_SLEEP_TIME 1000U
+#define NS_TIME_SLEEP 1500U
+#define ECHO_VAL1 U(0xa0a0a0a0)
+
+static const struct ffa_uuid expected_sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}
+ };
+
+static bool configure_trusted_wdog_interrupt(ffa_id_t source, ffa_id_t dest,
+ bool enable)
+{
+ struct ffa_value ret_values;
+
+ ret_values = cactus_interrupt_cmd(source, dest, IRQ_TWDOG_INTID,
+ enable, INTERRUPT_TYPE_IRQ);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response message while configuring"
+ " TWDOG interrupt\n");
+ return false;
+ }
+
+ if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
+ ERROR("Failed to configure Trusted Watchdog interrupt\n");
+ return false;
+ }
+ return true;
+}
+
+static bool enable_trusted_wdog_interrupt(ffa_id_t source, ffa_id_t dest)
+{
+ return configure_trusted_wdog_interrupt(source, dest, true);
+}
+
+static bool disable_trusted_wdog_interrupt(ffa_id_t source, ffa_id_t dest)
+{
+ return configure_trusted_wdog_interrupt(source, dest, false);
+}
+
+/*
+ * @Test_Aim@ Test secure interrupt handling while first Secure Partition is
+ * in RUNNING state.
+ *
+ * 1. Send a direct message request command to first Cactus SP to start the
+ * trusted watchdog timer.
+ *
+ * 2. Send a command to SP to first sleep( by executing a busy loop), then
+ * restart trusted watchdog timer and then sleep again.
+ *
+ * 3. While SP is running the first busy loop, Secure interrupt should trigger
+ * during this time.
+ *
+ * 4. The interrupt will be trapped to SPM as IRQ. SPM will inject the virtual
+ * IRQ to the first SP through vIRQ conduit and perform eret to resume
+ * execution in SP.
+ *
+ * 5. Execution traps to irq handler of Cactus SP. It will handle the secure
+ * interrupt triggered by the trusted watchdog timer.
+ *
+ * 6. Cactus SP will perform End-Of-Interrupt and resume execution in the busy
+ * loop.
+ *
+ * 7. Trusted watchdog timer will trigger once again followed by steps 4 to 6.
+ *
+ * 8. Cactus SP will send a direct response message with the elapsed time back
+ * to the normal world.
+ *
+ * 9. We make sure the time elapsed in the sleep routine by SP is not less than
+ * the requested value.
+ *
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
+ *
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
+ *
+ * 12. Test finishes successfully once the TFTF disables the trusted watchdog
+ * interrupt through a direct message request command.
+ *
+ */
+
+test_result_t test_ffa_sec_interrupt_sp_running(void)
+{
+ struct ffa_value ret_values;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Enable trusted watchdog interrupt as IRQ in the secure side. */
+ if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, 50);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for starting TWDOG timer\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Send request to first Cactus SP to sleep */
+ ret_values = cactus_sleep_trigger_wdog_cmd(SENDER, RECEIVER, SP_SLEEP_TIME, 50);
+
+ /*
+ * Secure interrupt should trigger during this time, Cactus
+ * will handle the trusted watchdog timer.
+ */
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for sleep command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ VERBOSE("Secure interrupt has preempted execution: %u\n",
+ cactus_get_response(ret_values));
+
+ /* Make sure elapsed time not less than sleep time */
+ if (cactus_get_response(ret_values) < SP_SLEEP_TIME) {
+ ERROR("Lapsed time less than requested sleep time\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable Trusted Watchdog interrupt. */
+ if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test secure interrupt handling while Secure Partition is waiting
+ * for a message.
+ *
+ * 1. Send a direct message request command to first Cactus SP to start the
+ * trusted watchdog timer.
+ *
+ * 2. Once the SP returns with a direct response message, it moves to WAITING
+ state.
+ *
+ * 3. Execute a busy loop to sleep for NS_TIME_SLEEP ms.
+ *
+ * 4. Trusted watchdog timer expires during this time which leads to secure
+ * interrupt being triggered while cpu is executing in normal world.
+ *
+ * 5. The interrupt is trapped to BL31/SPMD as FIQ and later synchronously
+ * delivered to SPM.
+ *
+ * 6. SPM injects a virtual IRQ to first Cactus Secure Partition.
+ *
+ * 7. Once the SP handles the interrupt, it returns execution back to normal
+ * world using FFA_MSG_WAIT call.
+ *
+ * 8. SPM, through the help of SPMD, resumes execution in normal world to
+ * continue the busy loop.
+ *
+ * 9. We make sure the time elapsed in the sleep routine is not less than
+ * the requested value.
+ *
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
+ *
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
+ *
+ * 12. Test finishes successfully once the TFTF disables the trusted watchdog
+ * interrupt through a direct message request command.
+ *
+ */
+test_result_t test_ffa_sec_interrupt_sp_waiting(void)
+{
+ uint64_t time1;
+ volatile uint64_t time2, time_lapsed;
+ uint64_t timer_freq = read_cntfrq_el0();
+ struct ffa_value ret_values;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Enable trusted watchdog interrupt as IRQ in the secure side. */
+ if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Send a message to SP1 through direct messaging.
+ */
+ ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, 100);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for starting TWDOG timer\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ time1 = syscounter_read();
+
+ /*
+ * Sleep for NS_TIME_SLEEP ms. This ensures secure wdog timer triggers during this
+ * time. We explicitly do not use tftf_timer_sleep();
+ */
+ waitms(NS_TIME_SLEEP);
+ time2 = syscounter_read();
+
+ /* Lapsed time should be at least equal to sleep time */
+ time_lapsed = ((time2 - time1) * 1000) / timer_freq;
+
+ if (time_lapsed < NS_TIME_SLEEP) {
+ ERROR("Time elapsed less than expected value: %llu vs %u\n",
+ time_lapsed, NS_TIME_SLEEP);
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable Trusted Watchdog interrupt. */
+ if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test secure interrupt handling while first Secure Partition is
+ * in BLOCKED state.
+ *
+ * 1. Send a direct message request command to first Cactus SP to start the
+ * trusted watchdog timer.
+ *
+ * 2. Send a direct request to first SP to forward sleep command to second SP.
+ *
+ * 3. While second SP is running the busy loop, Secure interrupt should trigger
+ * during this time.
+ *
+ * 4. The interrupt will be trapped to SPM as IRQ. SPM will inject the virtual
+ * IRQ to the first SP through vIRQ conduit and perform eret to resume
+ * execution in first SP.
+ *
+ * 5. Execution traps to irq handler of Cactus SP. It will handle the secure
+ * interrupt triggered by the trusted watchdog timer.
+ *
+ * 6. First SP performs EOI by calling interrupt deactivate ABI and invokes
+ * FFA_RUN to resume second SP in the busy loop.
+ *
+ * 7. Second SP will complete the busy sleep loop and send a direct response
+ * message with the elapsed time back to the first SP.
+ *
+ * 8. First SP checks for the elapsed time and sends a direct response with
+ * a SUCCESS value back to tftf.
+ *
+ * 9. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
+ *
+ * 10. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
+ *
+ * 11. Test finishes successfully once the TFTF disables the trusted watchdog
+ * interrupt through a direct message request command.
+ */
+test_result_t test_ffa_sec_interrupt_sp_blocked(void)
+{
+ struct ffa_value ret_values;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Enable trusted watchdog interrupt as IRQ in the secure side. */
+ if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, 100);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for starting TWDOG timer\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Send request to first Cactus SP to send request to Second Cactus
+ * SP to sleep
+ */
+ ret_values = cactus_fwd_sleep_cmd(SENDER, RECEIVER, RECEIVER_2,
+ SP_SLEEP_TIME);
+
+ /*
+ * Secure interrupt should trigger during this time, Cactus
+ * will handle the trusted watchdog timer.
+ */
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable Trusted Watchdog interrupt. */
+ if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test secure interrupt handling while first Secure Partition is
+ * in WAITING state while the second Secure Partition is running.
+ *
+ * 1. Send a direct message request command to first Cactus SP to start the
+ * trusted watchdog timer.
+ *
+ * 2. Send a direct request to second SP to sleep by executing a busy loop.
+ *
+ * 3. While second SP is running the busy loop, Secure interrupt should trigger
+ * during this time.
+ *
+ * 4. The interrupt is trapped to the SPM as a physical IRQ. The SPM injects a
+ * virtual IRQ to the first SP and resumes it while it is in waiting state.
+ *
+ * 5. Execution traps to irq handler of the first Cactus SP. It will handle the
+ * secure interrupt triggered by the trusted watchdog timer.
+ *
+ * 6. Cactus SP will perform End-Of-Interrupt by calling the interrupt
+ * deactivate HVC and invoke FFA_MSG_WAIT ABI to perform interrupt signal
+ * completion.
+ *
+ * 7. SPM then resumes the second SP which was pre-empted by secure interrupt.
+ *
+ * 8. Second SP will complete the busy sleep loop and send a direct response
+ * message with the elapsed time back to the first SP.
+ *
+ * 9. We make sure the time elapsed in the sleep routine by SP is not less than
+ * the requested value.
+ *
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
+ *
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
+ *
+ * 12. Test finishes successfully once the TFTF disables the trusted watchdog
+ * interrupt through a direct message request command.
+ */
+test_result_t test_ffa_sec_interrupt_sp1_waiting_sp2_running(void)
+{
+ struct ffa_value ret_values;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Enable trusted watchdog interrupt as IRQ in the secure side. */
+ if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, 100);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for starting TWDOG timer\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Send request to Second Cactus SP to sleep. */
+ ret_values = cactus_sleep_cmd(SENDER, RECEIVER_2, SP_SLEEP_TIME);
+
+ /*
+ * Secure interrupt should trigger during this time, Cactus
+ * will handle the trusted watchdog timer.
+ */
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for sleep command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure elapsed time not less than sleep time. */
+ if (cactus_get_response(ret_values) < SP_SLEEP_TIME) {
+ ERROR("Lapsed time less than requested sleep time\n");
+ }
+
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable Trusted Watchdog interrupt. */
+ if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_setup_and_discovery.c b/tftf/tests/runtime_services/secure_service/test_ffa_setup_and_discovery.c
new file mode 100644
index 00000000..b80f9c4f
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_setup_and_discovery.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+
+#include <ffa_endpoints.h>
+#include <ffa_helpers.h>
+#include <ffa_svc.h>
+#include <spm_common.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <xlat_tables_defs.h>
+
+static bool should_skip_version_test;
+
+static struct mailbox_buffers mb;
+
+static const struct ffa_uuid sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}, {IVY_UUID}
+ };
+
+static const struct ffa_partition_info ffa_expected_partition_info[] = {
+ /* Primary partition info */
+ {
+ .id = SP_ID(1),
+ .exec_context = PRIMARY_EXEC_CTX_COUNT,
+ .properties = FFA_PARTITION_DIRECT_REQ_RECV |
+ FFA_PARTITION_NOTIFICATION,
+ .uuid = sp_uuids[0]
+ },
+ /* Secondary partition info */
+ {
+ .id = SP_ID(2),
+ .exec_context = SECONDARY_EXEC_CTX_COUNT,
+ .properties = FFA_PARTITION_DIRECT_REQ_RECV |
+ FFA_PARTITION_NOTIFICATION,
+ .uuid = sp_uuids[1]
+ },
+ /* Tertiary partition info */
+ {
+ .id = SP_ID(3),
+ .exec_context = TERTIARY_EXEC_CTX_COUNT,
+ .properties = FFA_PARTITION_DIRECT_REQ_RECV |
+ FFA_PARTITION_NOTIFICATION,
+ .uuid = sp_uuids[2]
+ },
+ /* Ivy partition info */
+ {
+ .id = SP_ID(4),
+ .exec_context = IVY_EXEC_CTX_COUNT,
+ .properties = FFA_PARTITION_DIRECT_REQ_RECV,
+ .uuid = sp_uuids[3]
+ }
+};
+
+/*
+ * Using FFA version expected for SPM.
+ */
+#define SPM_VERSION MAKE_FFA_VERSION(FFA_VERSION_MAJOR, FFA_VERSION_MINOR)
+
+/******************************************************************************
+ * FF-A Features ABI Tests
+ ******************************************************************************/
+
+test_result_t test_ffa_features(void)
+{
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
+
+ /* Check if SPMC is OP-TEE at S-EL1 */
+ if (check_spmc_execution_level()) {
+ /* FFA_FEATURES is not yet supported in OP-TEE */
+ return TEST_RESULT_SUCCESS;
+ }
+
+ struct ffa_value ffa_ret;
+ unsigned int expected_ret;
+ const struct ffa_features_test *ffa_feature_test_target;
+ unsigned int i, test_target_size =
+ get_ffa_feature_test_target(&ffa_feature_test_target);
+ struct ffa_features_test test_target;
+
+ for (i = 0U; i < test_target_size; i++) {
+ test_target = ffa_feature_test_target[i];
+ ffa_ret = ffa_features(test_target.feature);
+ expected_ret = FFA_VERSION_COMPILED
+ >= test_target.version_added ?
+ test_target.expected_ret : FFA_ERROR;
+ if (ffa_func_id(ffa_ret) != expected_ret) {
+ tftf_testcase_printf("%s returned %x, expected %x\n",
+ test_target.test_name,
+ ffa_func_id(ffa_ret),
+ expected_ret);
+ return TEST_RESULT_FAIL;
+ }
+ if ((expected_ret == FFA_ERROR) &&
+ (ffa_error_code(ffa_ret) != FFA_ERROR_NOT_SUPPORTED)) {
+ tftf_testcase_printf("%s failed for the wrong reason: "
+ "returned %x, expected %x\n",
+ test_target.test_name,
+ ffa_error_code(ffa_ret),
+ FFA_ERROR_NOT_SUPPORTED);
+ return TEST_RESULT_FAIL;
+ }
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/******************************************************************************
+ * FF-A Version ABI Tests
+ ******************************************************************************/
+
+/*
+ * Calls FFA Version ABI, and checks if the result as expected.
+ */
+static test_result_t test_ffa_version(uint32_t input_version,
+ uint32_t expected_return)
+{
+ if (should_skip_version_test) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ struct ffa_value ret_values = ffa_version(input_version);
+
+ uint32_t spm_version = (uint32_t)(0xFFFFFFFF & ret_values.fid);
+
+ if (spm_version == expected_return) {
+ return TEST_RESULT_SUCCESS;
+ }
+
+ tftf_testcase_printf("Input Version: 0x%x\n"
+ "Return: 0x%x\nExpected: 0x%x\n",
+ input_version, spm_version, expected_return);
+
+ return TEST_RESULT_FAIL;
+}
+
+/*
+ * @Test_Aim@ Validate what happens when using same version as SPM.
+ */
+test_result_t test_ffa_version_equal(void)
+{
+ /*
+ * FFA_VERSION interface is used to check that SPM functionality is
+ * supported. On FFA_VERSION invocation from TFTF, the SPMD returns
+ * either NOT_SUPPORTED or the SPMC version value provided in the SPMC
+ * manifest. The variable "should_skip_test" is set to true when the
+ * SPMD returns NOT_SUPPORTED or a mismatched version, which means that
+ * a TFTF physical FF-A endpoint version (SPM_VERSION) does not match
+ * the SPMC's physical FF-A endpoint version. This prevents running the
+ * subsequent FF-A version tests (and break the test flow), as they're
+ * not relevant when the SPMD is not present within BL31
+ * (FFA_VERSION returns NOT_SUPPORTED).
+ */
+ test_result_t ret = test_ffa_version(SPM_VERSION, SPM_VERSION);
+
+ if (ret != TEST_RESULT_SUCCESS) {
+ should_skip_version_test = true;
+ ret = TEST_RESULT_SKIPPED;
+ }
+ return ret;
+}
+
+/*
+ * @Test_Aim@ Validate what happens when setting bit 31 in
+ * 'input_version'. As per spec, FFA version is 31 bits long.
+ * Bit 31 set is an invalid input.
+ */
+test_result_t test_ffa_version_bit31(void)
+{
+ return test_ffa_version(FFA_VERSION_BIT31_MASK | SPM_VERSION,
+ FFA_ERROR_NOT_SUPPORTED);
+}
+
+/*
+ * @Test_Aim@ Validate what happens for bigger version than SPM's.
+ */
+test_result_t test_ffa_version_bigger(void)
+{
+ return test_ffa_version(MAKE_FFA_VERSION(FFA_VERSION_MAJOR + 1, 0),
+ SPM_VERSION);
+}
+
+/*
+ * @Test_Aim@ Validate what happens for smaller version than SPM's.
+ */
+test_result_t test_ffa_version_smaller(void)
+{
+ return test_ffa_version(MAKE_FFA_VERSION(0, 9), SPM_VERSION);
+}
+
+/******************************************************************************
+ * FF-A RXTX ABI Tests
+ ******************************************************************************/
+
+static test_result_t test_ffa_rxtx_map(uint32_t expected_return)
+{
+ struct ffa_value ret;
+
+ /**********************************************************************
+ * Verify that FFA is there and that it has the correct version.
+ **********************************************************************/
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
+
+ /**********************************************************************
+ * If OP-TEE is SPMC skip this test.
+ **********************************************************************/
+ if (check_spmc_execution_level()) {
+ VERBOSE("OP-TEE as SPMC at S-EL1. Skipping test!\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /*
+ * Declare RXTX buffers, assign them to the mailbox and call
+ * FFA_RXTX_MAP.
+ */
+ CONFIGURE_AND_MAP_MAILBOX(mb, PAGE_SIZE, ret);
+ if (ffa_func_id(ret) != expected_return) {
+ ERROR("Failed to map RXTX buffers %x!\n", ffa_error_code(ret));
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test mapping RXTX buffers from NWd.
+ */
+test_result_t test_ffa_rxtx_map_success(void)
+{
+ return test_ffa_rxtx_map(FFA_SUCCESS_SMC32);
+}
+
+/**
+ * Test to verify that 2nd call to FFA_RXTX_MAP should fail.
+ */
+test_result_t test_ffa_rxtx_map_fail(void)
+{
+ VERBOSE("This test expects error log.\n");
+ return test_ffa_rxtx_map(FFA_ERROR);
+}
+
+static test_result_t test_ffa_rxtx_unmap(uint32_t expected_return)
+{
+ struct ffa_value ret;
+
+ /**********************************************************************
+ * Verify that FFA is there and that it has the correct version.
+ **********************************************************************/
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
+
+ /**********************************************************************
+ * If OP-TEE is SPMC skip this test.
+ **********************************************************************/
+ if (check_spmc_execution_level()) {
+ VERBOSE("OP-TEE as SPMC at S-EL1. Skipping test!\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ ret = ffa_rxtx_unmap();
+ if (!is_expected_ffa_return(ret, expected_return)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test unmapping RXTX buffers from NWd.
+ */
+test_result_t test_ffa_rxtx_unmap_success(void)
+{
+ return test_ffa_rxtx_unmap(FFA_SUCCESS_SMC32);
+}
+
+/**
+ * Test to verify that 2nd call to FFA_RXTX_UNMAP should fail.
+ */
+test_result_t test_ffa_rxtx_unmap_fail(void)
+{
+ VERBOSE("This test expects error log.\n");
+ return test_ffa_rxtx_unmap(FFA_ERROR);
+}
+
+/**
+ * Test mapping RXTX buffers that have been previously unmapped from NWd.
+ * This test also sets the Mailbox for other SPM related tests that need to use
+ * RXTX buffers.
+ */
+test_result_t test_ffa_rxtx_map_unmapped_success(void)
+{
+ test_result_t ret = test_ffa_rxtx_map(FFA_SUCCESS_SMC32);
+
+ if (ret == TEST_RESULT_SUCCESS) {
+ VERBOSE("Set RXTX Mailbox for remaining spm tests.\n");
+ set_tftf_mailbox(&mb);
+ }
+ return ret;
+}
+/******************************************************************************
+ * FF-A SPM_ID_GET ABI Tests
+ ******************************************************************************/
+
+test_result_t test_ffa_spm_id_get(void)
+{
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
+ struct ffa_value ffa_ret = ffa_spm_id_get();
+
+ if (is_ffa_call_error(ffa_ret)) {
+ ERROR("FFA_SPM_ID_GET call failed! Error code: 0x%x\n",
+ ffa_error_code(ffa_ret));
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Check the SPMC value given in the fvp_spmc_manifest is returned */
+ ffa_id_t spm_id = ffa_endpoint_id(ffa_ret);
+
+ if (spm_id != SPMC_ID) {
+ ERROR("Expected SPMC_ID of 0x%x\n received: 0x%x\n",
+ SPMC_ID, spm_id);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/******************************************************************************
+ * FF-A PARTITION_INFO_GET ABI Tests
+ ******************************************************************************/
+
+/**
+ * Attempt to get the SP partition information for individual partitions as well
+ * as all secure partitions.
+ */
+test_result_t test_ffa_partition_info(void)
+{
+ /***********************************************************************
+ * Check if SPMC has ffa_version and expected FFA endpoints are deployed.
+ **********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 1, sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ if (!ffa_partition_info_helper(&mb, sp_uuids[0],
+ &ffa_expected_partition_info[0], 1)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!ffa_partition_info_helper(&mb, sp_uuids[1],
+ &ffa_expected_partition_info[1], 1)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!ffa_partition_info_helper(&mb, sp_uuids[2],
+ &ffa_expected_partition_info[2], 1)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!ffa_partition_info_helper(&mb, NULL_UUID,
+ ffa_expected_partition_info,
+ ARRAY_SIZE(ffa_expected_partition_info))) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Attempt to get v1.0 partition info descriptors.
+ */
+test_result_t test_ffa_partition_info_v1_0(void)
+{
+ /**************************************************************
+ * Check if SPMC has ffa_version and expected FFA endpoints
+ * are deployed.
+ *************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 0, sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ test_result_t result = TEST_RESULT_SUCCESS;
+ struct ffa_value ret = ffa_partition_info_get(NULL_UUID);
+ uint64_t expected_size = ARRAY_SIZE(ffa_expected_partition_info);
+
+ if (ffa_func_id(ret) == FFA_SUCCESS_SMC32) {
+ if (ffa_partition_info_count(ret) != expected_size) {
+ ERROR("Unexpected number of partitions %d\n",
+ ffa_partition_info_count(ret));
+ return TEST_RESULT_FAIL;
+ }
+ if (ffa_partition_info_desc_size(ret) !=
+ sizeof(struct ffa_partition_info_v1_0)) {
+ ERROR("Unexepcted partition info descriptor size %d\n",
+ ffa_partition_info_desc_size(ret));
+ return TEST_RESULT_FAIL;
+ }
+ const struct ffa_partition_info_v1_0 *info =
+ (const struct ffa_partition_info_v1_0 *)(mb.recv);
+
+ for (unsigned int i = 0U; i < expected_size; i++) {
+ if (info[i].id != ffa_expected_partition_info[i].id) {
+ ERROR("Wrong ID. Expected %x, got %x\n",
+ ffa_expected_partition_info[i].id,
+ info[i].id);
+ result = TEST_RESULT_FAIL;
+ }
+ if (info[i].exec_context !=
+ ffa_expected_partition_info[i].exec_context) {
+ ERROR("Wrong context. Expected %d, got %d\n",
+ ffa_expected_partition_info[i].exec_context,
+ info[i].exec_context);
+ result = TEST_RESULT_FAIL;
+ }
+ if (info[i].properties !=
+ ffa_expected_partition_info[i].properties) {
+ ERROR("Wrong properties. Expected %d, got %d\n",
+ ffa_expected_partition_info[i].properties,
+ info[i].properties);
+ result = TEST_RESULT_FAIL;
+ }
+ }
+ }
+
+ ret = ffa_rx_release();
+ if (is_ffa_call_error(ret)) {
+ ERROR("Failed to release RX buffer\n");
+ result = TEST_RESULT_FAIL;
+ }
+ return result;
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_version.c b/tftf/tests/runtime_services/secure_service/test_ffa_version.c
deleted file mode 100644
index 41eca5ad..00000000
--- a/tftf/tests/runtime_services/secure_service/test_ffa_version.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <ffa_svc.h>
-#include <test_helpers.h>
-#include <tftf_lib.h>
-
-/*
- * Using FFA version expected for SPM.
- */
-#define SPM_VERSION MAKE_FFA_VERSION(FFA_VERSION_MAJOR, FFA_VERSION_MINOR)
-
-static bool should_skip_test;
-
-/*
- * Calls FFA Version ABI, and checks if the result as expected.
- */
-static test_result_t test_ffa_version(uint32_t input_version, uint32_t expected_return)
-{
- if (should_skip_test) {
- return TEST_RESULT_SKIPPED;
- }
-
- smc_ret_values ret_values = ffa_version(input_version);
-
- uint32_t spm_version = (uint32_t)(0xFFFFFFFF & ret_values.ret0);
-
- if (spm_version == expected_return) {
- return TEST_RESULT_SUCCESS;
- }
-
- tftf_testcase_printf("Input Version: 0x%x\nReturn: 0x%x\nExpected: 0x%x\n",
- input_version, spm_version, expected_return);
-
- return TEST_RESULT_FAIL;
-}
-
-/*
- * @Test_Aim@ Validate what happens when using same version as SPM.
- */
-test_result_t test_ffa_version_equal(void)
-{
- /*
- * FFA_VERSION interface is used to check that SPM functionality is supported.
- * On FFA_VERSION invocation from TFTF, the SPMD returns either NOT_SUPPORTED or
- * the SPMC version value provided in the SPMC manifest. The variable "should_skip_test"
- * is set to true when the SPMD returns NOT_SUPPORTED or a mismatched version, which
- * means that a TFTF physical FF-A endpoint version (SPM_VERSION) does not match the
- * SPMC's physical FF-A endpoint version. This prevents running the subsequent FF-A
- * version tests (and break the test flow), as they're not relevant when the SPMD is
- * not present within BL31 (FFA_VERSION returns NOT_SUPPORTED).
- */
- test_result_t ret = test_ffa_version(SPM_VERSION, SPM_VERSION);
- if (ret != TEST_RESULT_SUCCESS) {
- should_skip_test = true;
- ret = TEST_RESULT_SKIPPED;
- }
- return ret;
-}
-
-/*
- * @Test_Aim@ Validate what happens when setting bit 31 in
- * 'input_version'. As per spec, FFA version is 31 bits long.
- * Bit 31 set is an invalid input.
- */
-test_result_t test_ffa_version_bit31(void)
-{
- return test_ffa_version(FFA_VERSION_BIT31_MASK | SPM_VERSION, FFA_ERROR_NOT_SUPPORTED);
-}
-
-/*
- * @Test_Aim@ Validate what happens for bigger version than SPM's.
- */
-test_result_t test_ffa_version_bigger(void)
-{
- return test_ffa_version(MAKE_FFA_VERSION(FFA_VERSION_MAJOR + 1, 0), SPM_VERSION);
-}
-
-/*
- * @Test_Aim@ Validate what happens for smaller version than SPM's.
- */
-test_result_t test_ffa_version_smaller(void)
-{
- return test_ffa_version(MAKE_FFA_VERSION(0, 9), SPM_VERSION);
-}
diff --git a/tftf/tests/runtime_services/secure_service/test_spci_blocking_request.c b/tftf/tests/runtime_services/secure_service/test_spci_blocking_request.c
index 6d248428..d2aa20b8 100644
--- a/tftf/tests/runtime_services/secure_service/test_spci_blocking_request.c
+++ b/tftf/tests/runtime_services/secure_service/test_spci_blocking_request.c
@@ -29,8 +29,7 @@ static test_result_t test_spci_blocking_multicore_fn(void)
u_register_t rx1, rx2, rx3;
test_result_t result = TEST_RESULT_SUCCESS;
- u_register_t cpu_mpid = read_mpidr_el1() & MPID_MASK;
- unsigned int core_pos = platform_get_core_pos(cpu_mpid);
+ unsigned int core_pos = get_current_core_id();
tftf_send_event(&cpu_has_entered_test[core_pos]);
diff --git a/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c b/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
index f57fa243..2927fc2d 100644
--- a/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
+++ b/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,7 @@
#include <cactus_test_cmds.h>
#include <ffa_endpoints.h>
#include <ffa_helpers.h>
+#include <lib/extensions/sve.h>
#include <test_helpers.h>
#define SENDER HYP_ID
@@ -14,19 +15,20 @@
static const struct ffa_uuid expected_sp_uuids[] = { {PRIMARY_UUID} };
-static test_result_t simd_vector_compare(simd_vector_t a[SIMD_NUM_VECTORS],
- simd_vector_t b[SIMD_NUM_VECTORS])
+static test_result_t fp_vector_compare(uint8_t *a, uint8_t *b,
+ size_t vector_size, uint8_t vectors_num)
{
- for (unsigned int num = 0U; num < SIMD_NUM_VECTORS; num++) {
- if (memcmp(a[num], b[num], sizeof(simd_vector_t)) != 0) {
- ERROR("Vectors not equal: a:0x%llx b:0x%llx\n",
- (uint64_t)a[num][0], (uint64_t)b[num][0]);
- return TEST_RESULT_FAIL;
- }
+ if (memcmp(a, b, vector_size * vectors_num) != 0) {
+ return TEST_RESULT_FAIL;
}
return TEST_RESULT_SUCCESS;
}
+#ifdef __aarch64__
+static sve_vector_t sve_vectors_input[SVE_NUM_VECTORS] __aligned(16);
+static sve_vector_t sve_vectors_output[SVE_NUM_VECTORS] __aligned(16);
+#endif
+
/*
* Tests that SIMD vectors are preserved during the context switches between
* normal world and the secure world.
@@ -35,8 +37,6 @@ static test_result_t simd_vector_compare(simd_vector_t a[SIMD_NUM_VECTORS],
*/
test_result_t test_simd_vectors_preserved(void)
{
- SKIP_TEST_IF_AARCH32();
-
/****************