diff --git a/README.md b/README.md index 9b8a6d9..5ee9be8 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ These tests are split between a UEFI application and a Linux driver that togethe and SBBR specifications. These tests are further described in detail. ## Release details - - Code Quality: REL v1.3 + - Code Quality: REL v1.4 - The SBSA tests are written for version 3.0 of the SBSA specification. - The SBBR tests are written for version 1.0 of the SBBR specification. - The compliance suite is not a substitute for design verification. diff --git a/acs_sync.sh b/acs_sync.sh index 232470d..87c84bf 100755 --- a/acs_sync.sh +++ b/acs_sync.sh @@ -34,7 +34,7 @@ LUVOS_DIR="luv" DOWNLOAD_LUVOS=1 REMOVE_LUVOS=1 LUVOS_GIT_CLONE="git clone https://github.com/01org/luv-yocto.git" -LUVOS_GIT_CHECKOUT="git checkout -b v2.2-rc1 v2.2-rc1" +LUVOS_GIT_CHECKOUT="git checkout -b v2.2 v2.2" LUVOS_PATCH_FILE="../patches/luvos.patch" LUVOS_GIT_APPLY="git apply $LUVOS_PATCH_FILE" diff --git a/patches/luvos.patch b/patches/luvos.patch index 775d188..92e71e7 100644 --- a/patches/luvos.patch +++ b/patches/luvos.patch @@ -1,32 +1,33 @@ -From f7db258a3f73dc4d3f9fe02a53dadf3086b08cf3 Mon Sep 17 00:00:00 2001 +From 47d6be79584a123bf7adcf544432cb5335064c52 Mon Sep 17 00:00:00 2001 From: Sakar Arora -Date: Fri, 2 Feb 2018 23:56:46 +0530 +Date: Tue, 6 Feb 2018 14:19:21 +0530 Subject: [PATCH] luvos --- - build_luvos.sh | 88 ++++++++++ - meta-luv/classes/luv-efi.bbclass | 71 +++++++- + build_luvos.sh | 88 +++++++ + meta-luv/classes/luv-efi.bbclass | 71 +++++- meta-luv/conf/distro/luv.conf | 2 +- meta-luv/recipes-bsp/sbbr/sbbr/README.md | 2 + - meta-luv/recipes-bsp/sbbr/sbbr/sbbr-sct.patch | 136 ++++++++++++++++ - meta-luv/recipes-bsp/sbbr/sbbr_v1.0.bb | 101 ++++++++++++ - meta-luv/recipes-bsp/sbsa/files/compile.sh | 28 ++++ - meta-luv/recipes-bsp/sbsa/sbsa.bb | 107 ++++++++++++ + meta-luv/recipes-bsp/sbbr/sbbr/sbbr-sct.patch | 277 +++++++++++++++++++++ + meta-luv/recipes-bsp/sbbr/sbbr_v1.0.bb | 101 ++++++++ + meta-luv/recipes-bsp/sbsa/files/compile.sh | 28 +++ + meta-luv/recipes-bsp/sbsa/sbsa.bb | 107 ++++++++ meta-luv/recipes-core/efivarfs/efivarfs-test.bb | 1 - meta-luv/recipes-core/fwts/fwts/sbbr-fwts.patch | 17 ++ - meta-luv/recipes-core/fwts/fwts_git.bb | 8 +- - .../images/core-image-efi-initramfs.bb | 1 + - meta-luv/recipes-core/images/luv-live-image.bb | 10 +- - meta-luv/recipes-core/images/luv-netboot-image.bb | 8 +- + meta-luv/recipes-core/fwts/fwts_git.bb | 4 +- + .../images/core-image-efi-initramfs.bb | 2 +- + meta-luv/recipes-core/images/luv-image.inc | 3 +- + meta-luv/recipes-core/images/luv-live-image.bb | 8 +- + meta-luv/recipes-core/images/luv-netboot-image.bb | 5 +- .../kernel_efi_warnings/kernel-efi-warnings_0.1.bb | 2 - meta-luv/recipes-core/luv-test/luv-test.bb | 6 + - .../luv-test/luv-test/luv-collect-results | 181 +++++++++++++++++++++ + .../luv-test/luv-test/luv-collect-results | 181 ++++++++++++++ .../recipes-core/luv-test/luv-test/luv-sbsa-test | 18 ++ .../luv-test/luv-test/luv-test-manager | 5 + - .../linux/linux-yocto-efi-test_4.13.bb | 3 +- + .../linux/linux-yocto-efi-test_4.14.bb | 3 +- meta/conf/bitbake.conf | 2 +- - sbsa_setup.sh | 43 +++++ - 22 files changed, 823 insertions(+), 17 deletions(-) + sbsa_setup.sh | 41 +++ + 23 files changed, 959 insertions(+), 15 deletions(-) create mode 100755 build_luvos.sh create mode 100644 meta-luv/recipes-bsp/sbbr/sbbr/README.md create mode 100644 meta-luv/recipes-bsp/sbbr/sbbr/sbbr-sct.patch @@ -133,7 +134,7 @@ index 0000000..bc6b659 +fi +exit diff --git a/meta-luv/classes/luv-efi.bbclass b/meta-luv/classes/luv-efi.bbclass -index 0caa5a8..4cdf56e 100644 +index 8c1b892..66c653e 100644 --- a/meta-luv/classes/luv-efi.bbclass +++ b/meta-luv/classes/luv-efi.bbclass @@ -16,6 +16,13 @@ def get_bits_depends(d): @@ -147,10 +148,10 @@ index 0caa5a8..4cdf56e 100644 + return "sbbr:do_deploy" +_SBBRDEPENDS = "${@get_sbbr_depends(d)}" + - # The x86 build is depends on grub-efi and AArch64 build depends on grub_git - def get_grub_depends(d): - import re -@@ -65,7 +72,13 @@ efi_populate() { + do_bootimg[depends] += "${MLPREFIX}grub-efi:do_deploy \ + sbsigntool-native:do_populate_sysroot" + +@@ -55,7 +62,13 @@ efi_populate() { # Install grub2 in EFI directory if [ "${TARGET_ARCH}" = "aarch64" ]; then install -m 0644 ${DEPLOY_DIR_IMAGE}/${GRUB_EFI_LOADER_IMAGE} ${DEST}${EFIDIR}/${DEST_EFI_LOADER_IMAGE} @@ -165,7 +166,7 @@ index 0caa5a8..4cdf56e 100644 # TODO: need conditional signing; e.g., if (DISTRO_FEATURES contains secure_boot) # shim bootloader does not seem to work with i386. Thus we don't use it for 32-bit -@@ -102,6 +115,52 @@ efi_populate() { +@@ -92,6 +105,52 @@ efi_populate() { install -m 0644 ${LUV_CFG} ${DEST} } @@ -218,7 +219,7 @@ index 0caa5a8..4cdf56e 100644 BITS_EFI_LOADER_IMAGE = "${DEST_EFI_LOADER_IMAGE}" efi_populate_bits() { DEST=$1 -@@ -182,6 +241,11 @@ python build_efi_cfg() { +@@ -172,6 +231,11 @@ python build_efi_cfg() { cfgfile.write('default=bits\n') cfgfile.write('fallback=0\n') @@ -230,7 +231,7 @@ index 0caa5a8..4cdf56e 100644 cfgfile.write('menuentry \'luv\' {\n') cfgfile.write('linux /vmlinuz ') -@@ -208,6 +272,11 @@ python build_efi_cfg() { +@@ -199,6 +263,11 @@ python build_efi_cfg() { cfgfile.write('chainloader /EFI/BOOT/bits/%s\n' % loader) cfgfile.write('}\n') @@ -243,14 +244,14 @@ index 0caa5a8..4cdf56e 100644 } diff --git a/meta-luv/conf/distro/luv.conf b/meta-luv/conf/distro/luv.conf -index d846d00..50ff3dc 100644 +index fb0a833..55ddcfe 100644 --- a/meta-luv/conf/distro/luv.conf +++ b/meta-luv/conf/distro/luv.conf @@ -17,4 +17,4 @@ VIRTUAL-RUNTIME_init_manager = "systemd" VIRTUAL-RUNTIME_initscripts = "" DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit" --INITRAMFS_MAXSIZE = "200000" +-INITRAMFS_MAXSIZE = "235000" +INITRAMFS_MAXSIZE = "400000" diff --git a/meta-luv/recipes-bsp/sbbr/sbbr/README.md b/meta-luv/recipes-bsp/sbbr/sbbr/README.md new file mode 100644 @@ -262,10 +263,139 @@ index 0000000..06f0264 +======== diff --git a/meta-luv/recipes-bsp/sbbr/sbbr/sbbr-sct.patch b/meta-luv/recipes-bsp/sbbr/sbbr/sbbr-sct.patch new file mode 100644 -index 0000000..8954968 +index 0000000..3c2fb4b --- /dev/null +++ b/meta-luv/recipes-bsp/sbbr/sbbr/sbbr-sct.patch -@@ -0,0 +1,136 @@ +@@ -0,0 +1,277 @@ ++diff --git a/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/ImageBBTest.inf b/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/ImageBBTest.inf ++index 10d9e8c..9deb345 100644 ++--- a/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/ImageBBTest.inf +++++ b/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/ImageBBTest.inf ++@@ -84,4 +84,5 @@ ++ ++ [Protocols] ++ gEfiTestProfileLibraryGuid +++ gEfiTestRecoveryLibraryGuid ++ gBlackBoxEfiHIIPackageListProtocolGuid ++diff --git a/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/ImageBBTestConformance.c b/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/ImageBBTestConformance.c ++index 4c63a08..6bd92ec 100644 ++--- a/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/ImageBBTestConformance.c +++++ b/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/ImageBBTestConformance.c ++@@ -809,6 +809,7 @@ BBTestExitBootServicesConsistencyTest ( ++ ) ++ { ++ EFI_STANDARD_TEST_LIBRARY_PROTOCOL *StandardLib; +++ EFI_TEST_RECOVERY_LIBRARY_PROTOCOL *RecoveryLib; ++ EFI_STATUS Status; ++ EFI_TEST_ASSERTION AssertionType; ++ UINTN MapKey; ++@@ -817,6 +818,7 @@ BBTestExitBootServicesConsistencyTest ( ++ UINTN DataSize; ++ UINT8 Data[MAX_BUFFER_SIZE]; ++ EFI_STATUS ReturnStatus; +++ UINTN RecoveryData[2], RecoveryDataSize; ++ ++ // ++ // Init ++@@ -834,6 +836,16 @@ BBTestExitBootServicesConsistencyTest ( ++ return Status; ++ } ++ +++ RecoveryLib = NULL; +++ +++ Status = gtBS->HandleProtocol ( +++ SupportHandle, +++ &gEfiTestRecoveryLibraryGuid, +++ (VOID **) &RecoveryLib); +++ if (EFI_ERROR(Status)) { +++ return Status; +++ } +++ ++ Status = ImageTestCheckForCleanEnvironment (&Numbers); ++ if (EFI_ERROR(Status)) { ++ StandardLib->RecordAssertion ( ++@@ -849,18 +861,12 @@ BBTestExitBootServicesConsistencyTest ( ++ ); ++ return Status; ++ } +++ +++ RecoveryDataSize = sizeof(RecoveryData); +++ Status = RecoveryLib->ReadResetRecord(RecoveryLib, &RecoveryDataSize, RecoveryData); ++ ++- DataSize = MAX_BUFFER_SIZE; ++- Status = gtRT->GetVariable ( ++- L"ExitBootServicesTestVariable", // VariableName ++- &gTestVendor1Guid, // VendorGuid ++- NULL, // Attributes ++- &DataSize, // DataSize ++- &ReturnStatus // Data ++- ); ++- ++- if (Status == EFI_SUCCESS) { ++- goto CheckResult; +++ if (!EFI_ERROR(Status) && RecoveryData[0] == 1) { +++ goto CheckResult; ++ } ++ ++ // ++@@ -899,19 +905,10 @@ BBTestExitBootServicesConsistencyTest ( ++ mImageHandle, ++ MapKey ++ ); ++- if (ReturnStatus == EFI_INVALID_PARAMETER) { ++- AssertionType = EFI_TEST_ASSERTION_PASSED; ++- } else { ++- AssertionType = EFI_TEST_ASSERTION_FAILED; ++- } ++- ++- Status = gtRT->SetVariable ( ++- L"ExitBootServicesTestVariable", // VariableName ++- &gTestVendor1Guid, // VendorGuid ++- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, // Attributes ++- sizeof(EFI_STATUS), // DataSize ++- &ReturnStatus // Data ++- ); +++ +++ RecoveryData[0] = 1; +++ RecoveryData[1] = ReturnStatus; +++ RecoveryLib->WriteResetRecord (RecoveryLib, sizeof(RecoveryData), RecoveryData); ++ ++ //reset system ++ gtRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); ++@@ -919,7 +916,7 @@ BBTestExitBootServicesConsistencyTest ( ++ // get var to get the status ++ CheckResult: ++ ++- if (ReturnStatus == EFI_INVALID_PARAMETER) { +++ if (RecoveryData[1] == EFI_INVALID_PARAMETER) { ++ AssertionType = EFI_TEST_ASSERTION_PASSED; ++ } else { ++ AssertionType = EFI_TEST_ASSERTION_FAILED; ++@@ -933,18 +930,10 @@ CheckResult: ++ L"%a:%d: the Status is - %r, expected status is %r", ++ __FILE__, ++ (UINTN)__LINE__, ++- ReturnStatus, +++ RecoveryData[1], ++ EFI_INVALID_PARAMETER ++ ); ++ ++- Status = gtRT->SetVariable ( ++- L"ExitBootServicesTestVariable", // VariableName ++- &gTestVendor1Guid, // VendorGuid ++- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, // Attributes ++- 0, // DataSize ++- Data // Data ++- ); ++- ++ Status = ImageTestCheckForCleanEnvironment (&Numbers); ++ if (EFI_ERROR(Status)) { ++ StandardLib->RecordAssertion ( ++@@ -961,4 +950,3 @@ CheckResult: ++ } ++ return EFI_SUCCESS; ++ } ++- +diff --git a/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/ImageBBTestFunction.c b/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/ImageBBTestFunction.c +index d0af10d..632c8df 100644 +--- a/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/ImageBBTestFunction.c @@ -282,6 +412,18 @@ index 0000000..8954968 + #endif + return EFI_SUCCESS; + } ++diff --git a/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/Misc.h b/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/Misc.h ++index da3277b..5457565 100644 ++--- a/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/Misc.h +++++ b/SctPkg/TestCase/UEFI/EFI/BootServices/ImageServices/BlackBoxTest/Misc.h ++@@ -60,6 +60,7 @@ Abstract: ++ ++ #include "ImageBBTest.h" ++ #include "ProtocolDefinition.h" +++#include EFI_TEST_PROTOCOL_DEFINITION(TestRecoveryLibrary) ++ ++ typedef struct { ++ VOID *Registration; +diff --git a/SctPkg/TestCase/UEFI/EFI/BootServices/SbbrBootServices/BlackBoxTest/SbbrBootServicesBBTestFunction.c b/SctPkg/TestCase/UEFI/EFI/BootServices/SbbrBootServices/BlackBoxTest/SbbrBootServicesBBTestFunction.c +index c88d60b..6fbd11a 100644 +--- a/SctPkg/TestCase/UEFI/EFI/BootServices/SbbrBootServices/BlackBoxTest/SbbrBootServicesBBTestFunction.c @@ -657,10 +799,10 @@ index 0000000..6cb2871 + +addtask deploy before do_build after do_install diff --git a/meta-luv/recipes-core/efivarfs/efivarfs-test.bb b/meta-luv/recipes-core/efivarfs/efivarfs-test.bb -index 07760b2..c3eec9a 100644 +index 0853e52..190d683 100644 --- a/meta-luv/recipes-core/efivarfs/efivarfs-test.bb +++ b/meta-luv/recipes-core/efivarfs/efivarfs-test.bb -@@ -72,4 +72,3 @@ do_install() { +@@ -71,4 +71,3 @@ do_install() { } LUV_TEST_LOG_PARSER="luv-parser-efivarfs" @@ -689,18 +831,11 @@ index 0000000..69e92fe + } + diff --git a/meta-luv/recipes-core/fwts/fwts_git.bb b/meta-luv/recipes-core/fwts/fwts_git.bb -index 122f9b9..9baa534 100644 +index 62d2430..0d2d751 100644 --- a/meta-luv/recipes-core/fwts/fwts_git.bb +++ b/meta-luv/recipes-core/fwts/fwts_git.bb -@@ -4,11 +4,12 @@ HOMEPAGE = "https://wiki.ubuntu.com/Kernel/Reference/fwts" - LICENSE = "GPLv2+" - LIC_FILES_CHKSUM = "file://src/main.c;beginline=1;endline=16;md5=31da590f3e9f3bd34dcdb9e4db568519" - --PV = "V17.09.00+git${SRCPV}" -+PV = "V17.12.00+git${SRCPV}" - --SRCREV = "7cc5c0823ec56859b0c8d91607befd8a151ec7f1" -+SRCREV = "df2784c6fbff02288c736f85354b22f46dc193f4" +@@ -9,6 +9,7 @@ PV = "V17.12.00+git${SRCPV}" + SRCREV = "df2784c6fbff02288c736f85354b22f46dc193f4" SRC_URI = "git://kernel.ubuntu.com/hwe/fwts.git \ file://luv-parser-fwts \ + file://sbbr-fwts.patch \ @@ -718,22 +853,31 @@ index 122f9b9..9baa534 100644 FILES_${PN} += "${libdir}/fwts/lib*${SOLIBS}" FILES_${PN} += "/lib/modules/${KERNEL_VERSION}/extra/efi_runtime.ko" diff --git a/meta-luv/recipes-core/images/core-image-efi-initramfs.bb b/meta-luv/recipes-core/images/core-image-efi-initramfs.bb -index d733b61..b7736ff 100644 +index 9529534..8a62075 100644 --- a/meta-luv/recipes-core/images/core-image-efi-initramfs.bb +++ b/meta-luv/recipes-core/images/core-image-efi-initramfs.bb -@@ -9,6 +9,7 @@ IMAGE_INSTALL = "\ +@@ -8,7 +8,7 @@ IMAGE_INSTALL = "\ util-linux-mount util-linux-umount kmod sed tar net-tools \ shadow util-linux procps efivarfs-test pstore-test \ - plymouth plymouth-set-default-theme kernel-efi-warnings linux-firmware kexec \ -+ sbsa-acs-drv sbsa-acs-app \ + plymouth plymouth-set-default-theme kernel-efi-warnings linux-firmware-luv kexec \ +- acpixtract iasl \ ++ acpixtract iasl sbsa-acs-drv sbsa-acs-app \ " X86_ADDITIONS = "chipsec python-codecs python-subprocess vmcore-dmesg bits \ -diff --git a/meta-luv/recipes-core/images/luv-live-image.bb b/meta-luv/recipes-core/images/luv-live-image.bb -index 142d71c..9ed38ab 100644 ---- a/meta-luv/recipes-core/images/luv-live-image.bb -+++ b/meta-luv/recipes-core/images/luv-live-image.bb -@@ -28,7 +28,7 @@ COMMON_CMDLINE_x86 += "splash nomodeset crash_kexec_post_notifiers" +diff --git a/meta-luv/recipes-core/images/luv-image.inc b/meta-luv/recipes-core/images/luv-image.inc +index b851709..55275e6 100644 +--- a/meta-luv/recipes-core/images/luv-image.inc ++++ b/meta-luv/recipes-core/images/luv-image.inc +@@ -3,6 +3,7 @@ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda + + DEPENDS_append_x86 = " grub-efi bits" + DEPENDS_append_x86-64 = " grub-efi bits" ++DEPENDS_${PN} = "bits sbbr" + + HDDDIR = "${S}/hddimg" + +@@ -24,7 +25,7 @@ COMMON_CMDLINE_x86 += "splash nomodeset crash_kexec_post_notifiers" # Unlike the += operand, _append's do not insert a space between the current value # and the appended string. Thus, we add them. @@ -742,16 +886,20 @@ index 142d71c..9ed38ab 100644 CMDLINE_append_x86 = "${COMMON_CMDLINE_x86}" CMDLINE_append_x86-64 = "${COMMON_CMDLINE_x86}" -@@ -44,7 +44,7 @@ python() { +diff --git a/meta-luv/recipes-core/images/luv-live-image.bb b/meta-luv/recipes-core/images/luv-live-image.bb +index b7a0f66..1cefc5d 100644 +--- a/meta-luv/recipes-core/images/luv-live-image.bb ++++ b/meta-luv/recipes-core/images/luv-live-image.bb +@@ -9,7 +9,7 @@ MACHINE_FEATURES += "efi" - SPLASH_IMAGE = "blue-luv.jpg" + CMDLINE = "${CMDLINE_BASE}" -GRUB_TIMEOUT = "2" +GRUB_TIMEOUT = "1" inherit image-live -@@ -68,8 +68,8 @@ build_img() { +@@ -31,8 +31,8 @@ build_img() { BYTES_PER_SECTOR=512 MiB=$(expr 1024 \* 1024) VFAT_RESULTS=${DEPLOY_DIR_IMAGE}/${PN}-results.hddimg @@ -762,7 +910,7 @@ index 142d71c..9ed38ab 100644 VFAT_RESULTS_SPACE=$(expr $VFAT_RESULTS_SPACE_MiB \* $MiB) VFAT_RESULTS_BLOCKS=$(expr $VFAT_RESULTS_SPACE / 1024) # TODO: do we need to dynamically generate the UUID? -@@ -88,6 +88,8 @@ build_img() { +@@ -51,6 +51,8 @@ build_img() { mkdosfs -C ${VFAT_RESULTS} -S ${BYTES_PER_SECTOR} -i ${VFAT_RESULTS_UUID} \ -n ${VFAT_RESULTS_LABEL} $VFAT_RESULTS_BLOCKS @@ -772,27 +920,10 @@ index 142d71c..9ed38ab 100644 # Now that we are calculating sizes in MiB make sure that the value diff --git a/meta-luv/recipes-core/images/luv-netboot-image.bb b/meta-luv/recipes-core/images/luv-netboot-image.bb -index facb24a..e8602a1 100644 +index d6eca7b..77dde4f 100644 --- a/meta-luv/recipes-core/images/luv-netboot-image.bb +++ b/meta-luv/recipes-core/images/luv-netboot-image.bb -@@ -3,6 +3,7 @@ LIC_FILES_CHKSUM = "file://${COREBASE}/LICENSE;md5=4d92cd373abda3937c2bc47fbc49d - - DEPENDS_append_x86 = " bits" - DEPENDS_append_x86-64 = " bits" -+DEPENDS_${PN} = "bits sbbr" - - INITRD_IMAGE_LIVE = "core-image-efi-initramfs" - IMGDEPLOYDIR = "${DEPLOY_DIR_IMAGE}" -@@ -29,7 +30,7 @@ COMMON_CMDLINE_x86 += "splash nomodeset crash_kexec_post_notifiers" - - # Unlike the += operand, _append's do not insert a space between the current value - # and the appended string. Thus, we add them. --CMDLINE_append_aarch64 = " acpi=on" -+CMDLINE_append_aarch64 = " acpi=on crashkernel=256M earlycon uefi_debug luv.netboot" - CMDLINE_append_x86 = "${COMMON_CMDLINE_x86}" - CMDLINE_append_x86-64 = "${COMMON_CMDLINE_x86}" - -@@ -68,7 +69,8 @@ do_mkimage[depends] += "dosfstools-native:do_populate_sysroot \ +@@ -25,7 +25,8 @@ do_mkimage[depends] += "dosfstools-native:do_populate_sysroot \ mtools-native:do_populate_sysroot \ cdrtools-native:do_populate_sysroot \ virtual/kernel:do_deploy \ @@ -802,9 +933,9 @@ index facb24a..e8602a1 100644 do_bootimg[noexec] = "1" -@@ -78,6 +80,8 @@ do_populate_image() { - efi_populate_bits ${HDDDIR} - else +@@ -33,6 +34,8 @@ do_populate_image() { + install -d ${HDDDIR}${EFIDIR} + if [ "${TARGET_ARCH}" = "aarch64" ]; then echo "${DEST_EFI_LOADER_IMAGE}" > ${HDDDIR}${EFIDIR}/startup.nsh + efi_populate_sbbr ${HDDDIR} + efi_populate_sbsa ${HDDDIR} @@ -822,19 +953,19 @@ index a0fde3c..85eec50 100644 -LUV_TEST="kernel-efi-warnings" -LUV_TEST_ARGS="" diff --git a/meta-luv/recipes-core/luv-test/luv-test.bb b/meta-luv/recipes-core/luv-test/luv-test.bb -index 36421dd..6f2f1d2 100644 +index 164a616..0ca0fc1 100644 --- a/meta-luv/recipes-core/luv-test/luv-test.bb +++ b/meta-luv/recipes-core/luv-test/luv-test.bb -@@ -33,6 +33,8 @@ SRC_URI += "file://luv-test-manager file://luv-test-parser \ - file://luv-crash-handler.service \ - file://luv-netconsole.service \ - file://luv-dmesg-acpi-tables-dump \ +@@ -36,6 +36,8 @@ SRC_URI += "file://luv-test-manager file://luv-test-parser \ + file://luv-reboot-poweroff.service \ + file://luv-reboot-poweroff \ + file://luv-message \ + file://luv-collect-results \ + file://luv-sbsa-test \ " - RDEPENDS_${PN}-netconsole+= "kernel-modules curl iputils iproute2 bash init-ifupdown dhcp-client" -@@ -68,6 +70,10 @@ do_install_append() { + RDEPENDS_${PN}+= "kernel-modules curl iputils iproute2 bash init-ifupdown dhcp-client gzip" +@@ -84,6 +86,10 @@ do_install_append() { install -m 0644 ${WORKDIR}/luv-scripts ${D}${datadir}/luv/html install -m 0644 ${WORKDIR}/luv-css-styles ${D}${datadir}/luv/html @@ -847,7 +978,7 @@ index 36421dd..6f2f1d2 100644 install -m 0644 ${WORKDIR}/luv-test-manager.service ${D}${systemd_unitdir}/system diff --git a/meta-luv/recipes-core/luv-test/luv-test/luv-collect-results b/meta-luv/recipes-core/luv-test/luv-test/luv-collect-results new file mode 100644 -index 0000000..6f4601a +index 0000000..9afbc12 --- /dev/null +++ b/meta-luv/recipes-core/luv-test/luv-test/luv-collect-results @@ -0,0 +1,181 @@ @@ -893,7 +1024,7 @@ index 0000000..6f4601a + try: + fwtsRaw = open(fwtsRawPath, "r") + except IOError: -+ print "FWTS raw results file \"%s\" could not be opened, skipping." % fwtsRawPath ++ print ("FWTS raw results file \"%s\" could not be opened, skipping." % fwtsRawPath) + return -1 + + # Printing .MD file header for FWTS results. @@ -917,7 +1048,7 @@ index 0000000..6f4601a + # Finding SCT test results. + sbbrDir = os.path.join(d, "SCT", "Log") + if os.path.isdir(sbbrDir) == False: -+ print "SBBR SCT results directory \"%s\" not found. Skipping." % sbbrDir ++ print ("SBBR SCT results directory \"%s\" not found. Skipping." % sbbrDir) + return -1 + + # Printing .MD file header for SCT results. @@ -960,7 +1091,7 @@ index 0000000..6f4601a +def log_sbsa(d): + sbsaDir = os.path.join(d, "sbsa_results") + if os.path.isdir(sbsaDir) == False: -+ print "SBSA results results directory \"%s\" not found. Skipping." % sbsaDir ++ print ("SBSA results results directory \"%s\" not found. Skipping." % sbsaDir) + return -1 + + uefi = "not found"; @@ -968,39 +1099,39 @@ index 0000000..6f4601a + for entry in os.listdir(sbsaDir): + if(entry == "uefi"): + sbsaUefiLogs = os.path.join(sbsaDir, "uefi", "SbsaResults.log") -+ try: -+ f = open(sbsaUefiLogs, "r") -+ except IOError: -+ print "SBSA UEFI results file \"%s\" could not be opened, skipping." % sbsaUefiLogs ++ try: ++ f = open(sbsaUefiLogs, "r") ++ except IOError: ++ print ("SBSA UEFI results file \"%s\" could not be opened, skipping." % sbsaUefiLogs) + continue + logs = f.read() + outFile.write("\n\nSBSA UEFI Test Results\n\n") + outFile.write(logs) -+ uefi = "collected" -+ if(entry=="linux"): -+ sbsaLinuxLogs = os.path.join(sbsaDir, "linux", "SbsaResults.log") -+ try: -+ f = open(sbsaLinuxLogs, "r") -+ except IOError: -+ print "SBSA Linux results file \"%s\" could not be opened, skipping." % sbsaLinuxLogs -+ continue ++ uefi = "collected" ++ if(entry == "linux"): ++ sbsaLinuxLogs = os.path.join(sbsaDir, "linux", "SbsaResults.log") ++ try: ++ f = open(sbsaLinuxLogs, "r") ++ except IOError: ++ print ("SBSA Linux results file \"%s\" could not be opened, skipping." % sbsaLinuxLogs) ++ continue + logs = f.read() + outFile.write("\n\nSBSA Linux Test Results\n\n") + outFile.write(logs) -+ linux = "collected" -+ print "SBSA Results for linux %s\n" % linux -+ print "SBSA Results for UEFI %s\n" % uefi ++ linux = "collected" ++ print ("SBSA Results for linux %s\n" % linux) ++ print ("SBSA Results for UEFI %s\n" % uefi) + +# Script entry point. + +# This script needs to be run on a stripped out yocto distribution so we can't use argparse. +if "-h" in sys.argv or "--help" in sys.argv: -+ print "Usage:" -+ print " python %s [-h] LUV_RESULTS OUTPUT_FILE" % sys.argv[0] -+ print "Options:" -+ print " -h, --help Display this help and exit." -+ print " LUV_RESULTS Path to luv-results directory/drive." -+ print " OUTPUT_FILE File for script output, must have .md file extension." ++ print ("Usage:") ++ print (" python %s [-h] LUV_RESULTS OUTPUT_FILE" % sys.argv[0]) ++ print ("Options:") ++ print (" -h, --help Display this help and exit.") ++ print (" LUV_RESULTS Path to luv-results directory/drive.") ++ print (" OUTPUT_FILE File for script output, must have .md file extension.") + exit() + +arg_directory = sys.argv[1] @@ -1009,32 +1140,32 @@ index 0000000..6f4601a +# Validating parameter and opening output file. +filename, fileext = os.path.splitext(arg_output) +if fileext != ".md" and fileext != ".MD": -+ print "Output file must have .md file extension. Exiting." ++ print ("Output file must have .md file extension. Exiting.") + exit() +try: + outFile = open(arg_output, "w") +except IOError: -+ print "Could not open \"%s\" for writing. Exiting." % arg_output ++ print ("Could not open \"%s\" for writing. Exiting." % arg_output) + exit() + +# Scanning FWTS. -+print "Gathering FWTS test results..." ++print ("Gathering FWTS test results...") +log_fwts(arg_directory) + +# Scanning SBBR. -+print "Gathering UEFI SBBR SCT test results..." ++print ("Gathering UEFI SBBR SCT test results...") +log_sbbr(arg_directory) + +# Scanning SBSA. -+print "Gathering SBSA test results..." ++print ("Gathering SBSA test results...") +log_sbsa(arg_directory) + +outFile.close() + -+print "Done, test results can be found in \"%s\"" % arg_output ++print ("Done, test results can be found in \"%s\"" % arg_output) diff --git a/meta-luv/recipes-core/luv-test/luv-test/luv-sbsa-test b/meta-luv/recipes-core/luv-test/luv-test/luv-sbsa-test new file mode 100644 -index 0000000..a9b6863 +index 0000000..a359ddb --- /dev/null +++ b/meta-luv/recipes-core/luv-test/luv-test/luv-sbsa-test @@ -0,0 +1,18 @@ @@ -1053,29 +1184,29 @@ index 0000000..a9b6863 +# See the License for the specific language governing permissions and +# limitations under the License. + -+insmod /lib/modules/4.13.0-yocto-standard/extra/sbsa_acs.ko ++insmod /lib/modules/4.14.0-efitest/extra/sbsa_acs.ko +mkdir -p $1/sbsa_results/linux +sbsa > $1/sbsa_results/linux/SbsaResults.log diff --git a/meta-luv/recipes-core/luv-test/luv-test/luv-test-manager b/meta-luv/recipes-core/luv-test/luv-test/luv-test-manager -index 6f3a120..fcb02df 100644 +index f1e2176..cbf6a31 100644 --- a/meta-luv/recipes-core/luv-test/luv-test/luv-test-manager +++ b/meta-luv/recipes-core/luv-test/luv-test/luv-test-manager -@@ -295,6 +295,11 @@ cat ${LUV_SAVE_RESULTS_DIR}/luv.results | awk '/\[\+/ { units += 1 } - cat /tmp/testsuites | html_inline ${LUV_HTML_REPORT} | tee -a /dev/kmsg /tmp/luv.results \ +@@ -289,6 +289,11 @@ cat ${LUV_SAVE_RESULTS_DIR}/luv.results | awk '/\[\+/ { units += 1 } + cat /tmp/testsuites | html_inline ${LUV_HTML_REPORT} | tee -a /tmp/luv.results \ ${LUV_SAVE_RESULTS_DIR}/luv.results +# test SBSA compliance on luv +sh /etc/luv-sbsa-test ${LUV_STORAGE} +# collecting test results -+python /etc/luv-collect-results ${LUV_STORAGE} ${LUV_STORAGE}/results.md ++python3 /etc/luv-collect-results ${LUV_STORAGE} ${LUV_STORAGE}/results.md + result=$(cat /tmp/testsuites) - plymouth_write "$result" + luv_msg_write "$result" sleep 2 -diff --git a/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.13.bb b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.13.bb -index a60e59a..450954f 100644 ---- a/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.13.bb -+++ b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.13.bb +diff --git a/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.14.bb b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.14.bb +index f02dfa5..b4b590e 100644 +--- a/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.14.bb ++++ b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.14.bb @@ -59,7 +59,7 @@ KERNEL_FEATURES_remove= " features/debug/printk.scc" # Override SRC_URI in a bbappend file to point at a different source @@ -1085,19 +1216,19 @@ index a60e59a..450954f 100644 # These patches are under discussion on ML SRC_URI += "file://0001-serial-SPCR-check-bit-width-for-the-16550-UART.patch \ -@@ -79,6 +79,7 @@ SRC_URI += "file://0001-PCI-Vulcan-AHCI-PCI-bar-fix-for-Broadcom-Vulcan-earl.pat - file://0008-x86-efi-Introduce-EFI_WARN_ON_ILLEGAL_ACCESSES.patch \ +@@ -80,6 +80,7 @@ SRC_URI += "file://0001-PCI-Vulcan-AHCI-PCI-bar-fix-for-Broadcom-Vulcan-earl.pat file://0001-selftests-change-reboot-flag-location.patch \ file://0001-pstore-test-remove-log-directory.patch \ -+ file://0001-SBSA-ACS-linux-v4.13.patch \ + file://0001-x86-mttr-Update-only-valid-variable-range-MTRRs.patch \ ++ file://0001-Enterprise-acs-linux-v4.13.patch \ " COMMON_CFG_x86 = " file://qemux86/modules.cfg \ diff --git a/meta/conf/bitbake.conf b/meta/conf/bitbake.conf -index 2dac3a1..7833e05 100644 +index 9696273..11d8888 100644 --- a/meta/conf/bitbake.conf +++ b/meta/conf/bitbake.conf -@@ -754,7 +754,7 @@ INITRAMFS_FSTYPES ?= "cpio.gz" +@@ -763,7 +763,7 @@ INITRAMFS_FSTYPES ?= "cpio.gz" # The maximum size in Kbytes for the generated initramfs image size. # Usually, it should be less than 1/2 of ram size, or you may fail to # boot it. @@ -1108,7 +1239,7 @@ index 2dac3a1..7833e05 100644 MACHINE_TASK_PROVIDER ?= "${DEFAULT_TASK_PROVIDER}" diff --git a/sbsa_setup.sh b/sbsa_setup.sh new file mode 100755 -index 0000000..d2daa63 +index 0000000..505cdc1 --- /dev/null +++ b/sbsa_setup.sh @@ -0,0 +1,43 @@ @@ -1140,7 +1271,7 @@ index 0000000..d2daa63 +git checkout -b v18.02_REL1.3 v18.02_REL1.3 +rm -rf $LUVDIR/meta-luv/recipes-core/sbsa-acs-drv +mv -f sbsa-acs-drv $LUVDIR/meta-luv/recipes-core/ -+mv -f kernel/src/0001-SBSA-ACS-linux-v4.13.patch $LUVDIR/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/ ++mv -f kernel/src/0001-Enterprise-acs-linux-v4.13.patch $LUVDIR/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/ + +cd $TMPDIR +git clone https://github.com/ARM-software/sbsa-acs.git diff --git a/sdei/README.md b/sdei/README.md new file mode 100644 index 0000000..b3241a7 --- /dev/null +++ b/sdei/README.md @@ -0,0 +1,180 @@ + +# Software Delegated Exception Interface - Architecture Compliance Suite + +## Software Delegated Exception Interface +**Software Delegated Exception Interface** (SDEI) Platform Design Document provides a mechanism for registering and servicing system events from system firmware. + +For more information, download the [SDEI Platform Design Document](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0054a/index.html). + +## Release details + - Code Quality: Beta v0.6 + - Code Completed: 48 out of 52. + - The tests are written for version 1.0 of the SDEI Platform Design Document. + +## SDEI compliance source + +The SDEI ACS tests compliance as a client to SDEI dispatcher running in EL3 as part of ARM-TF. The client application runs in EL2 (UEFI application) and EL1 (Linux kernel module/userspace application). + +## Downloading SDEI ACS + +SDEI ACS is a sub-directory in arm-enterprise-acs repository. + +$ git clone https://github.com/ARM-software/arm-enterprise-acs.git
+$ cd arm-enterprise-acs/sdei + +## Building SDEI ACS +### UEFI application +#### Prerequisites + +Before starting the ACS build, ensure that the following requirements are met. + +- Any mainstream Linux based OS distribution. +- git clone EDK2 tree. +- Install GCC 6.3 or later toolchain for Linux from [here](https://releases.linaro.org/components/toolchain/binaries). +- Install the build prerequisite packages to build EDK2. The details of the packages are beyond the scope of this document. + +#### Build Steps +
    +$ cd /path/to/arm-enterprise-acs/sdei
    +$ ./scripts/build_uefi.sh +
+ +#### Build Output + +The following output file is created in /path/to/arm-enterprise-acs/sdei/workspace/output/: + +- Sdei.efi + +### Linux kernel module and user space application +#### Build Steps +
    +$ cd /path/to/arm-enterprise-acs/sdei
    +$ ./scripts/build_linux.sh +
+ +#### Build Output +The following output files are created in in /path/to/arm-enterprise-acs/sdei/workspace/output/: + +- sdei_acs.ko +- sdei +- Image + + +## Test suite execution in UEFI + +### Post-Silicon + +On a system where a USB port is available and functional, perform the following steps: + +1. Copy 'Sdei.efi' to a USB Flash drive. +2. Plug in the USB Flash drive to one of the functional USB ports on the system. +3. Boot the system to UEFI shell. +4. To determine the file system number of the plugged in USB drive, execute 'map -r' command. +5. Type 'fsx' where 'x' is replaced by the number determined in step 4. +6. To start the compliance tests, run the executable Sdei.efi with the appropriate arguments. + +### Emulation environment with secondary storage + +On an emulation environment with secondary storage, perform the following steps: + +1. Create an image file which contains the 'Sdei.efi' file. For Example:
+$ mkfs.vfat -C -n HD0 hda.img 31457280
+$ sudo mount hda.img /mnt/sdei
+$ cd /path/to/arm-enterprise-acs/sdei/workspace/output/
+$ sudo cp Sdei.efi /mnt/sdei/
+$ sudo umount /mnt/sdei +2. Load the image file to the secondary storage using a backdoor. The steps followed to load the image file are Emulation environment specific and beyond the scope of this document. +3. Boot the system to UEFI shell. +4. To determine the file system number of the secondary storage, execute 'map -r' command. +5. Type 'fsx' where 'x' is replaced by the number determined in step 4. +6. To start the compliance tests, run the executable Sdei.efi with the appropriate arguments. + +### Emulation environment without secondary storage + +On an Emulation platform where secondary storage is not available, perform the following steps: + +1. Add the path to 'Sdei.efi' file in the UEFI FD file. +2. Build UEFI image including the UEFI Shell. +3. Boot the system to UEFI shell. +4. Run the executable 'Sdei.efi' to start the compliance tests. + +## Test suite execution in Linux + +### Post-Silicon + +On a system where a USB port is available and functional, perform the following steps: + +1. Copy kernel module sdei_acs.ko, user space application sdei and kernel binary Image to a USB flash drive. +2. Boot kernel binary Image using platform specific kernel arguments. +3. On linux shell, mount the USB flash drive. For example:
#mount /dev/sdb /mnt +4. Insert sdei kernel module and run sdei application.
#cd /mnt
#insmod sdei_acs.ko
#./sdei + +### Emulation environment with secondary storage + +On an emulation environment with secondary storage, perform the following steps: + +1. Create an image file which contains the 'Sdei.efi' file. For Example:
+$ mkfs.vfat -C -n HD0 hda.img 31457280
+$ sudo mount hda.img /mnt/sdei
+$ cd /path/to/arm-enterprise-acs/sdei/workspace/output/
+$ sudo cp sdei_acs.ko sdei Image /mnt/sdei
+$ sudo umount /mnt/sdei +2. Load the image file to the secondary storage using a backdoor. The steps followed to load the image file are Emulation environment specific and beyond the scope of this document. +3. Boot kernel binary Image using platform specific kernel arguments. +4. On linux shell, mount the secondary storage. For example:
#mount /dev/vda /mnt +5. Insert sdei kernel module and run sdei application.
#cd /mnt
#insmod sdei_acs.ko
#./sdei + +## Application arguments + +Command line arguments are similar for uefi and linux applications, with some exceptions. + +### UEFI + +Shell> Sdei.efi [-v <verbosity>] [-skip <test_id>] [-f <filename>] + + +### Linux +\# sdei [-v <verbosity>] [-skip <test_id>] + + +#### -v +Choose the verbosity level. + +- 1 - ERROR +- 2 - WARN and ERROR +- 3 - TEST and above +- 4 - DEBUG and above +- 5 - INFO and above +- 6 - KERNEL dump kernel prints during tests (Only for linux application) + +#### -skip +Overrides the suite to skip the execution of a particular +test. For example, -skip 10 skips test 10. + +#### -f (Only for UEFI application) +Save the test output into a file in secondary storage. For example -f sdei.log creates a file sdei.log with test output. + + +### UEFI example + +Shell> Sdei.efi -v 5 -skip 15,20,30 -f sdei_uefi.log + +Runs SDEI ACS with verbosity INFO, skips test 15, 20 and 30 and saves the test results in sdei_uefi.log. + +### Linux example + +\# sdei -v 1 -skip 10,20 + +Runs SDEI ACS with verbosity ERROR, skips test 10 and 20. + +## Interrupt numbers used in SDEI testing + +SPI interrupts: 230, 231 +PPI interrupts: 18 +SGI interrupts: 5 + +##SDEI compliance - Known Issues + +- Test #30 fails in linux. This is under debug. +- Test #45, #47 and #48 are run only in UEFI Shell application and is skipped when run in Linux. +- Running the SDEI ACS once is sufficient for compliance. There are stability issues when the ACS application is run multiple times without rebooting the system. diff --git a/sdei/docs/Arm_SDEI_Architecture_Compliance_Test_Scenario.pdf b/sdei/docs/Arm_SDEI_Architecture_Compliance_Test_Scenario.pdf new file mode 100755 index 0000000..1cca877 Binary files /dev/null and b/sdei/docs/Arm_SDEI_Architecture_Compliance_Test_Scenario.pdf differ diff --git a/sdei/docs/Arm_SDEI_Architecture_Compliance_Validation_Methodology.pdf b/sdei/docs/Arm_SDEI_Architecture_Compliance_Validation_Methodology.pdf new file mode 100755 index 0000000..d96e8ac Binary files /dev/null and b/sdei/docs/Arm_SDEI_Architecture_Compliance_Validation_Methodology.pdf differ diff --git a/sdei/linux_app/Makefile b/sdei/linux_app/Makefile new file mode 100644 index 0000000..1da0eec --- /dev/null +++ b/sdei/linux_app/Makefile @@ -0,0 +1,46 @@ +## @file + # Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + # SPDX-License-Identifier : Apache-2.0 + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. +## + + +program_NAME := sdei +program_C_SRCS := $(wildcard *.c) +program_CXX_SRCS := $(wildcard *.cpp) +program_C_OBJS := ${program_C_SRCS:.c=.o} +program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o} +program_OBJS := $(program_C_OBJS) $(program_CXX_OBJS) +program_INCLUDE_DIRS := ../val/include +program_LIBRARY_DIRS := +program_LIBRARIES := +CC := $(CROSS_COMPILE)gcc + +CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) -DTARGET_LINUX -g +LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) +LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) + +.PHONY: all clean distclean + +all: $(program_NAME) + +$(program_NAME): $(program_OBJS) + $(CROSS_COMPILE)gcc -static $(program_OBJS) -o $(program_NAME) + +clean: + @- $(RM) $(program_NAME) + @- $(RM) $(program_OBJS) + +distclean: clean + diff --git a/sdei/linux_app/include/sdei_app_main.h b/sdei/linux_app/include/sdei_app_main.h new file mode 100644 index 0000000..c7e5662 --- /dev/null +++ b/sdei/linux_app/include/sdei_app_main.h @@ -0,0 +1,57 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#ifndef __SDEI_APP_MAIN_H__ +#define __SDEI_APP_MAIN_H__ + +#define SDEI_APP_VERSION_MAJOR 1 +#define SDEI_APP_VERSION_MINOR 0 + +#define SDEI_NUM_TESTS 50 + +#define SDEI_PASS 0 +#define SDEI_SKIP 1 +#define SDEI_FAIL 2 +#define SDEI_ERROR 3 + +typedef unsigned long test_flags; + +typedef struct sdei_log_control { + int32_t print_level; + void *log_file_handle; +} sdei_log_control; + +typedef struct sdei_test_control { + /* which tests to run? */ + test_flags flags[2]; + unsigned int tests_skipped; + unsigned int tests_passed; + unsigned int tests_failed; + unsigned int tests_aborted; +} sdei_test_control; + +typedef struct sdei_control { + sdei_log_control log_control; + sdei_test_control tst_control; +} sdei_control_t; + +typedef struct __SDEI_MSG__ { + char string[100]; + unsigned long data; +} sdei_msg_parms_t; + +#endif diff --git a/sdei/linux_app/include/sdei_test_intf.h b/sdei/linux_app/include/sdei_test_intf.h new file mode 100644 index 0000000..0a88c7f --- /dev/null +++ b/sdei/linux_app/include/sdei_test_intf.h @@ -0,0 +1,37 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + + +#ifndef __SDEI_TEST_INTF_H__ +#define __SDEI_TEST_INTF_H__ + +#include "sdei_app_main.h" + +#define ACS_LOG_KERNEL 0x6 +#define SDEI_TEST_COMPLETE 0xFFFFFFFF +#define SDEI_TEST_CLEANUP 0xAAAAAAAA + +/* Function Prototypes */ +void testlib_enable_test(sdei_control_t *control, int test_id); +void testlib_disable_test(sdei_control_t *control, int test_id); +int init_test_env(sdei_control_t *control); +int testlib_execute_tests(sdei_control_t *control); +void testlib_cleanup(void); + +void testlib_run_specific(sdei_control_t *control, int test_id, int count); +void read_msg_from_proc_sdei(void); +#endif diff --git a/sdei/linux_app/sdei_app_main.c b/sdei/linux_app/sdei_app_main.c new file mode 100644 index 0000000..50e9417 --- /dev/null +++ b/sdei/linux_app/sdei_app_main.c @@ -0,0 +1,126 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include +#include +#include +#include +#include +#include + +#include "include/sdei_app_main.h" +#include "include/sdei_test_intf.h" + +sdei_control_t control; + +void print_help(){ + printf ("\nUsage: sdei [-v ] | [--skip ] | [--run ]\n" + "Options:\n" + "-v Verbosity of the Prints\n" + " 5 shows all prints, 1 shows Errors, 6 for Linux kernel printks\n" + "--skip Test(s) to be skipped\n" + "--run Test(s) to be run\n" + " Refer to section 4 of SDEI_ACS_User_Guide\n" + " To skip a module, use Model_ID as mentioned in user guide\n" + " To skip a particular test within a module, use the exact testcase number\n" + ); +} + +int parse_cmdline(int argc, char **argv) +{ + int c = 0; + int test_id = 0, count = 0; + char *endptr, *pt; + struct option long_opt[] = + { + {"skip", required_argument, NULL, 'n'}, + {"run", required_argument, NULL, 'r'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + /* Process Command Line arguments */ + while ((c = getopt_long(argc, argv, "hv:n:r:", long_opt, NULL)) != -1) + { + switch (c) + { + case 'v': + control.log_control.print_level = strtol(optarg, &endptr, 10); + if (control.log_control.print_level > 6) { + printf("Verbosity level is invalid\n"); + print_help(); + return 1; + } + break; + case 'h': + print_help(); + return 1; + break; + case 'n':/*SKIP tests */ + pt = strtok(optarg, ","); + while (pt != NULL) { + test_id = atoi(pt); + testlib_disable_test(&control, (test_id-1)); + pt = strtok(NULL, ","); + } + break; + /* To run specific test */ + case 'r': + pt = strtok(optarg, ","); + while (pt != NULL) { + test_id = atoi(pt); + count++; + testlib_run_specific(&control, (test_id-1), count); + pt = strtok(NULL, ","); + } + break; + default: + printf("unknown commandline option\n"); + print_help(); + return 1; + } + } + return 0; +} + +int +main (int argc, char **argv) +{ + int status; + + status = init_test_env(&control); + if (status) { + printf ("Cannot initialize test environment. Exiting.... \n"); + return 0; + } + + status = parse_cmdline(argc, argv); + if (status) + return 1; + + printf ("\n ************ SDEI Architecture Compliance Suite ********* \n"); + printf (" Version %d.%d \n", + SDEI_APP_VERSION_MAJOR, SDEI_APP_VERSION_MINOR); + + printf ("\n Starting tests for Print level is %2d)\n\n", control.log_control.print_level); + testlib_execute_tests(&control); + + printf("\n *** SDEI tests complete *** \n\n"); + testlib_cleanup(); + + return 0; +} diff --git a/sdei/linux_app/sdei_test_intf.c b/sdei/linux_app/sdei_test_intf.c new file mode 100644 index 0000000..d8af39a --- /dev/null +++ b/sdei/linux_app/sdei_test_intf.c @@ -0,0 +1,145 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + + +#include +#include +#include + +#include +#include "include/sdei_test_intf.h" + +static inline void enable_test(sdei_test_control *control, int i) { + control->flags[i/64] |= ((unsigned long)(1ULL << (i % 64))); +} + +static inline void disable_test(sdei_test_control *control, int i) { + control->flags[i/64] &= ~((unsigned long)(1ULL << (i % 64))); +} + +void testlib_run_specific(sdei_control_t *control, int test_id, int count) +{ + if (count == 1) { + control->tst_control.flags[0] = 0ULL; + control->tst_control.flags[1] = 0ULL; + } + + if (test_id <= SDEI_NUM_TESTS) + enable_test(&control->tst_control, test_id); +} + +void testlib_enable_test(sdei_control_t *control, int test_id) { + + if (test_id < SDEI_NUM_TESTS) + enable_test(&control->tst_control, test_id); +} + +void testlib_disable_test(sdei_control_t *control, int test_id) { + + if (test_id < SDEI_NUM_TESTS) + disable_test(&control->tst_control, test_id); +} + +int init_test_env(sdei_control_t *control) +{ + FILE *fd = NULL; + + fd = fopen("/proc/sdei", "rw+"); + if (fd == NULL) { + printf("Unable to open /proc/sdei\n"); + return SDEI_FAIL; + } + + // Initialize global counters + control->tst_control.tests_passed = 0; + control->tst_control.tests_failed = 0; + control->tst_control.tests_skipped = 0; + control->tst_control.tests_aborted = 0; + control->tst_control.flags[0] = ~(0ULL); + control->tst_control.flags[1] = ~(0ULL); + control->log_control.log_file_handle = NULL; + control->log_control.print_level = 3; + + fclose(fd); + return 0; +} + +void testlib_cleanup(void) +{ + FILE *fd = NULL; + unsigned int flag = SDEI_TEST_CLEANUP; + + fd = fopen("/proc/sdei_msg", "w"); + if (fd == NULL) { + printf("Unable to open /proc/sdei_msg\n"); + return; + } + + fwrite(&flag, 1, sizeof(flag), fd); + fclose(fd); +} + +void read_msg_from_proc_sdei(void) +{ + FILE *fd = NULL; + char buf_msg[sizeof(sdei_msg_parms_t)]; + sdei_msg_parms_t msg_params; + + fd = fopen("/proc/sdei_msg", "r"); + if (fd == NULL) { + printf("Unable to open /proc/sdei_msg\n"); + return; + } + + fseek(fd, 0, SEEK_SET); + /* Print Until buffer is empty */ + while (fread(buf_msg,sizeof(buf_msg),1,fd)) { + printf("%s", buf_msg); + } + fclose(fd); +} + +int testlib_execute_tests(sdei_control_t *control) +{ + FILE *fd = NULL; + unsigned int test_status = 0; + + fd = fopen("/proc/sdei", "rw+"); + if (fd == NULL) { + printf("Unable to open /proc/sdei\n"); + return SDEI_FAIL; + } + + /* Few tests targeted only for UEFI environment. + * So skipping those tests in Linux + */ + testlib_disable_test(control, 44); + testlib_disable_test(control, 46); + testlib_disable_test(control, 47); + + fwrite(control, 1, sizeof(struct sdei_control), fd); + + if (control->log_control.print_level != ACS_LOG_KERNEL) { + while (test_status != SDEI_TEST_COMPLETE) { + fread(&test_status, sizeof(test_status), 1, fd); + read_msg_from_proc_sdei(); + } + } + + fclose(fd); + return 0; +} diff --git a/sdei/platform/pal_uefi/SdeiPalLib.inf b/sdei/platform/pal_uefi/SdeiPalLib.inf new file mode 100644 index 0000000..4f22cc8 --- /dev/null +++ b/sdei/platform/pal_uefi/SdeiPalLib.inf @@ -0,0 +1,71 @@ +## @file +# Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. +# SPDX-License-Identifier : Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SdeiPalLib + FILE_GUID = 7f2093fb-2e69-46eb-af52-ba1df42f6195 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = SdeiPalLib|UEFI_APPLICATION UEFI_DRIVER + +[Sources.common] + ../../val/include/pal_interface.h + include/pal_uefi.h + include/pal_sdei_interface.h + src/pal_misc.c + src/pal_wd_timer.c + src/pal_pe.c + src/pal_gic.c + src/pal_acpi.c + src/pal_sdei_interface.c + src/AArch64/ArmSmc.S + src/AArch64/Cache.S + src/AArch64/ModuleEntryPoint.S + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + EdkCompatibilityPkg/EdkCompatibilityPkg.dec + + +[LibraryClasses] + IoLib + BaseLib + UefiLib + ShellLib + DebugLib + BaseMemoryLib + ShellCEntryLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + +[Protocols] + gEfiAcpiTableProtocolGuid ## CONSUMES + gHardwareInterruptProtocolGuid ## CONSUMES + gEfiCpuArchProtocolGuid ## CONSUMES + gEfiPciIoProtocolGuid ## CONSUMES + +[Guids] + gEfiAcpi20TableGuid + gEfiAcpiTableGuid + +[BuildOptions] + GCC:*_*_*_ASM_FLAGS = -march=armv8.2-a diff --git a/sdei/platform/pal_uefi/include/pal_sdei_interface.h b/sdei/platform/pal_uefi/include/pal_sdei_interface.h new file mode 100644 index 0000000..6593ce5 --- /dev/null +++ b/sdei/platform/pal_uefi/include/pal_sdei_interface.h @@ -0,0 +1,39 @@ +/* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Copyright (C) 2018 Arm Limited + * SPDX-License-Identifier : Apache-2.0 + * + */ + +#ifndef __PAL_SDEI_INTERFACE_H +#define __PAL_SDEI_INTERFACE_H + +/* SDEI return values */ +#define SDEI_SUCCESS 0 +#define SDEI_NOT_SUPPORTED -1 +#define SDEI_INVALID_PARAMETERS -2 +#define SDEI_DENIED -3 +#define SDEI_PENDING -5 +#define SDEI_OUT_OF_RESOURCE -10 + +#define FADT_PSCI_USE_HVC (1<<1) /* 01: HVC must be used instead of SMC as the PSCI conduit */ + +enum sdei_conduit_types { + CONDUIT_INVALID = 0, + CONDUIT_SMC, + CONDUIT_HVC, +}; + +#endif /* __PAL_SDEI_INTERFACE_H */ diff --git a/sdei/platform/pal_uefi/include/pal_uefi.h b/sdei/platform/pal_uefi/include/pal_uefi.h new file mode 100644 index 0000000..d1c87ef --- /dev/null +++ b/sdei/platform/pal_uefi/include/pal_uefi.h @@ -0,0 +1,55 @@ +/* + * SDEI ACS Platform module. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Copyright (C) 2018 Arm Limited + * SPDX-License-Identifier : Apache-2.0 + * + * + */ + +#ifndef __PAL_UEFI_H__ +#define __PAL_UEFI_H__ + +#include "pal_interface.h" + +extern sdei_log_control g_log_control; + +typedef struct { + UINT64 Arg0; + UINT64 Arg1; + UINT64 Arg2; + UINT64 Arg3; + UINT64 Arg4; + UINT64 Arg5; + UINT64 Arg6; + UINT64 Arg7; +} ARM_SMC_ARGS; + + +#define ARM_SMC_ID_PSCI_CPU_ON_AARCH64 0xc4000003 +#define ARM_SMC_ID_PSCI_CPU_OFF 0x84000002 +#define ARM_SMC_ID_PSCI_CPU_SUSPEND_AARCH64 0xc4000001 +#define ARM_SMC_ID_PSCI_FEATURES 0x8400000A +#define BASE_FVP_UART_BASE 0x1c090000 + +VOID +DataCacheCleanInvalidateVA(UINT64 Address); +VOID +DataCacheInvalidateVA(UINT64 Address); + +VOID +pal_print(UINT32 verbosity, CHAR8 *str, ...); + +#endif /* __PAL_UEFI_H__ */ diff --git a/sdei/platform/pal_uefi/src/AArch64/ArmSmc.S b/sdei/platform/pal_uefi/src/AArch64/ArmSmc.S new file mode 100644 index 0000000..625f0ec --- /dev/null +++ b/sdei/platform/pal_uefi/src/AArch64/ArmSmc.S @@ -0,0 +1,67 @@ +// +// Copyright (c) 2018, Arm Limited. All rights reserved. +// SPDX-License-Identifier : Apache-2.0 +// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// + +GCC_ASM_EXPORT(ArmCallSmc) +GCC_ASM_EXPORT(PsciCpuSuspend) + +ASM_PFX(ArmCallSmc): + // Push x0 on the stack - The stack must always be quad-word aligned + str x0, [sp, #-16]! + + // Load the SMC arguments 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] + + smc #0 + + // Pop the ARM_SMC_ARGS structure address from the stack into x9 + ldr x9, [sp], #16 + + // Store the SMC returned values into the ARM_SMC_ARGS structure. + // A SMC call can return up to 4 values - we do not need to store back x4-x7. + stp x2, x3, [x9, #16] + stp x0, x1, [x9, #0] + + mov x0, x9 + + ret + +ASM_PFX(PsciCpuSuspend): + // Push x0 on the stack - The stack must always be quad-word aligned + str x0, [sp, #-16]! + + // Load the SMC arguments 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] + + adr x3, 1f + + smc #0 + +1: + // Pop the ARM_HVC_SMC_ARGS structure address from the stack into x9 + ldr x9, [sp], #16 + + // Store the SMC returned values into the ARM_HVC_SMC_ARGS structure. + // A SMC call can return up to 4 values - we do not need to store back x4-x7. + stp x2, x3, [x9, #16] + stp x0, x1, [x9, #0] + + mov x0, x9 + + ret diff --git a/sdei/platform/pal_uefi/src/AArch64/Cache.S b/sdei/platform/pal_uefi/src/AArch64/Cache.S new file mode 100644 index 0000000..419c876 --- /dev/null +++ b/sdei/platform/pal_uefi/src/AArch64/Cache.S @@ -0,0 +1,42 @@ +#/** @file +# Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. +# SPDX-License-Identifier : Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#**/ + +.text +.align 3 + +GCC_ASM_EXPORT(DataCacheCleanInvalidateVA) +GCC_ASM_EXPORT(DataCacheInvalidateVA) +GCC_ASM_EXPORT(DataCacheCleanVA) + +ASM_PFX(DataCacheCleanInvalidateVA): + dc civac, x0 + dsb sy + isb + ret + +ASM_PFX(DataCacheCleanVA): + dc cvac, x0 + dsb ish + isb + ret + +ASM_PFX(DataCacheInvalidateVA): + dc ivac, x0 + dsb ish + isb + ret diff --git a/sdei/platform/pal_uefi/src/AArch64/ModuleEntryPoint.S b/sdei/platform/pal_uefi/src/AArch64/ModuleEntryPoint.S new file mode 100644 index 0000000..5d1c028 --- /dev/null +++ b/sdei/platform/pal_uefi/src/AArch64/ModuleEntryPoint.S @@ -0,0 +1,89 @@ +#/** @file +# Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. +# SPDX-License-Identifier : Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#**/ + +.text +.align 3 + +GCC_ASM_IMPORT(ArmReadMpidr) +GCC_ASM_IMPORT(PalGetSecondaryStackBase) +GCC_ASM_IMPORT(PalGetMaxMpidr) +GCC_ASM_IMPORT(GetStackSize) +GCC_ASM_EXPORT(ModuleEntryPoint) + +StartupAddr: .8byte ASM_PFX(CEntryPoint) + +ASM_PFX(ModuleEntryPoint): + // Get ID of this CPU in Multicore system + bl ASM_PFX(ArmReadMpidr) + // Keep a copy of the MpId register value + mov x10, x0 + + // With this function: CorePos = (Aff3 x maxAff2 x maxAff1 x maxAff0) + + // (Aff2 x maxAff1 x maxAff0) + (Aff1 x maxAff0) + Aff0 + and x1, x0, 0xFF + and x2, x0, 0xFF00 + lsr x2, x2, 8 + and x3, x0, 0xFF0000 + lsr x3, x3, 16 + and x4, x0, 0xFF00000000 + lsr x4, x4, 32 + + bl ASM_PFX(PalGetMaxMpidr) + and x5, x0, 0xFF + add x5, x5, 1 + and x6, x0, 0xFF00 + lsr x6, x6, 8 + add x6, x6, 1 + and x7, x0, 0xFF0000 + lsr x7, x7, 16 + add x7, x7, 1 + and x8, x0, 0xFF00000000 + lsr x8, x8, 32 + add x8, x8, 1 // x8 has maxAff3, which is reserved for future use + + madd x0, x2, x5, x1 + mul x5, x5, x6 + madd x0, x3, x5, x0 + mul x5, x5, x7 + madd x0, x4, x5, x0 + mov x1, x0 //PE Index + bl ASM_PFX(GetStackSize) + mul x1, x1, x0 + sub x1, x1, x0 //Save the stack top + mov x2, x0 + +_GetStackBase: + mov x0, 0 + //ldr x4, GetStackMem + //blr x4 + //ASM_PFX(pal_allocate_stack) + bl ASM_PFX(PalGetSecondaryStackBase) + add x0, x0, x1 + str xzr, [x0] + add x1, x0, x2 + mov sp, x1 +_PrepareArguments: + mov x1, 0 + mov x2, 0 + mov x3, 0 + ldr x4, StartupAddr + + blr x4 + +_NeverReturn: + b _NeverReturn diff --git a/sdei/platform/pal_uefi/src/pal_acpi.c b/sdei/platform/pal_uefi/src/pal_acpi.c new file mode 100644 index 0000000..677ac5c --- /dev/null +++ b/sdei/platform/pal_uefi/src/pal_acpi.c @@ -0,0 +1,225 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#include +#include +#include +#include +#include +#include + +#include "Foundation/Efi/Guid/Acpi/Acpi.h" +#include +#include "Include/IndustryStandard/Acpi61.h" + +#include "pal_uefi.h" + +#define EFI_ACPI_6_2_SOFTWARE_DELEGATION_EXCEPTION_INTERFACE_SIGNATURE ((('S') | ('D' << 8)) | ((('E') | ('I' << 8)) << 16)) +/** + @brief Use UEFI System Table to look up Acpi20TableGuid and returns the Xsdt Address + + @param None + + @return Returns 64-bit XSDT address + */ +UINT64 +pal_get_xsdt_ptr() +{ + EFI_ACPI_6_1_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp; + UINT32 Index; + + for (Index = 0, Rsdp = NULL; Index < gST->NumberOfTableEntries; Index++) { + if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpiTableGuid) || + CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid) + ) { + // A match was found. + Rsdp = (EFI_ACPI_6_1_ROOT_SYSTEM_DESCRIPTION_POINTER *) gST->ConfigurationTable[Index].VendorTable; + break; + } + } + if (Rsdp == NULL) { + return 0; + } else { + return((UINT64) (EFI_ACPI_6_1_ROOT_SYSTEM_DESCRIPTION_POINTER *) Rsdp->XsdtAddress); + } + +} + +/** + @brief Iterate through the tables pointed by XSDT and return FADT Table address + + @param None + + @return 64-bit FADT address +**/ +UINT64 +pal_get_fadt_ptr() +{ + EFI_ACPI_DESCRIPTION_HEADER *Xsdt; + UINT64 *Entry64; + UINT32 Entry64Num; + UINT32 Idx; + + Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) pal_get_xsdt_ptr(); + if (Xsdt == NULL) { + pal_print(ACS_LOG_ERR, "\n XSDT not found"); + return 0; + } + + Entry64 = (UINT64 *)(Xsdt + 1); + Entry64Num = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 3; + for (Idx = 0; Idx < Entry64Num; Idx++) { + if (*(UINT32 *)(UINTN)(Entry64[Idx]) == EFI_ACPI_6_1_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) { + return(UINT64)(Entry64[Idx]); + } + } + + return 0; + +} + +/** + @brief Iterate through the tables pointed by XSDT and return SDEI Table address + + @param None + + @return 64-bit SDEI address +**/ +UINT64 +pal_get_sdei_ptr() +{ + EFI_ACPI_DESCRIPTION_HEADER *Xsdt; + UINT64 *Entry64; + UINT32 Entry64Num; + UINT32 Idx; + + Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) pal_get_xsdt_ptr(); + if (Xsdt == NULL) { + pal_print(ACS_LOG_ERR, "\n XSDT not found"); + return 0; + } + + Entry64 = (UINT64 *)(Xsdt + 1); + Entry64Num = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 3; + for (Idx = 0; Idx < Entry64Num; Idx++) { + if (*(UINT32 *)(UINTN)(Entry64[Idx]) == EFI_ACPI_6_2_SOFTWARE_DELEGATION_EXCEPTION_INTERFACE_SIGNATURE) {//TODO ADD SDEI SPECIFIC SIGNATURE + return(UINT64)(Entry64[Idx]); + } + } + + return 0; + +} + +/** + @brief Iterate through the tables pointed by XSDT and return MADT address + + @param None + + @return 64-bit MADT address +**/ +UINT64 +pal_get_madt_ptr() +{ + + EFI_ACPI_DESCRIPTION_HEADER *Xsdt; + UINT64 *Entry64; + UINT32 Entry64Num; + UINT32 Idx; + + Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) pal_get_xsdt_ptr(); + if (Xsdt == NULL) { + pal_print(ACS_LOG_ERR, "\n XSDT not found"); + return 0; + } + + Entry64 = (UINT64 *)(Xsdt + 1); + Entry64Num = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 3; + for (Idx = 0; Idx < Entry64Num; Idx++) { + if (*(UINT32 *)(UINTN)(Entry64[Idx]) == EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE) { + return(UINT64)(Entry64[Idx]); + } + } + + return 0; + +} + +/** + @brief Iterate through the tables pointed by XSDT and return HEST address + + @param None + + @return 64-bit HEST address +**/ +UINT64 +pal_get_hest_ptr() +{ + + EFI_ACPI_DESCRIPTION_HEADER *Xsdt; + UINT64 *Entry64; + UINT32 Entry64Num; + UINT32 Idx; + + Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) pal_get_xsdt_ptr(); + if (Xsdt == NULL) { + pal_print(ACS_LOG_ERR, "\n XSDT not found"); + return 0; + } + + Entry64 = (UINT64 *)(Xsdt + 1); + Entry64Num = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 3; + for (Idx = 0; Idx < Entry64Num; Idx++) { + if (*(UINT32 *)(UINTN)(Entry64[Idx]) == EFI_ACPI_6_1_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE) { + return(UINT64)(Entry64[Idx]); + } + } + return 0; +} + +/** + @brief Iterate through the tables pointed by XSDT and return GTDT address + + @param None + + @return 64-bit GTDT address +**/ +UINT64 +pal_get_gtdt_ptr() +{ + + EFI_ACPI_DESCRIPTION_HEADER *Xsdt; + UINT64 *Entry64; + UINT32 Entry64Num; + UINT32 Idx; + + Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) pal_get_xsdt_ptr(); + if (Xsdt == NULL) { + pal_print(ACS_LOG_ERR, "\n XSDT not found"); + return 0; + } + + Entry64 = (UINT64 *)(Xsdt + 1); + Entry64Num = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 3; + for (Idx = 0; Idx < Entry64Num; Idx++) { + if (*(UINT32 *)(UINTN)(Entry64[Idx]) == EFI_ACPI_6_1_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE) { + return(UINT64)(Entry64[Idx]); + } + } + + return 0; + +} diff --git a/sdei/platform/pal_uefi/src/pal_gic.c b/sdei/platform/pal_uefi/src/pal_gic.c new file mode 100644 index 0000000..396bc20 --- /dev/null +++ b/sdei/platform/pal_uefi/src/pal_gic.c @@ -0,0 +1,171 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include +#include +#include + +#include "Include/IndustryStandard/Acpi61.h" +#include +#include + +#include "pal_uefi.h" + +static EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *gMadtHdr; + +EFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL; + + +UINT64 +pal_get_madt_ptr(); + +/** + @brief Populate information about the GIC sub-system at the input address. + In a UEFI-ACPI framework, this information is part of the MADT table. + + @param GicTable Address of the memory region where this information is to be filled in + + @return None +**/ +VOID +pal_gic_create_info_table(gic_info_table_t *GicTable) +{ + EFI_ACPI_6_1_GIC_STRUCTURE *Entry = NULL; + gic_info_entry_t *GicEntry = NULL; + UINT32 Length= 0; + UINT32 TableLength; + + if (GicTable == NULL) { + pal_print(ACS_LOG_ERR, "\n Input GIC Table Pointer is NULL. Cannot create GIC INFO"); + return; + } + + GicEntry = GicTable->gic_info; + GicTable->header.gic_version = 0; + GicTable->header.num_gicrd = 0; + GicTable->header.num_gicd = 0; + GicTable->header.num_its = 0; + + gMadtHdr = (EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *) pal_get_madt_ptr(); + + if (gMadtHdr != NULL) { + TableLength = gMadtHdr->Header.Length; + pal_print(ACS_LOG_INFO, "\n MADT is at %x and length is %x", gMadtHdr, TableLength); + } else { + pal_print(ACS_LOG_ERR, "\n MADT not found"); + return; + } + + Entry = (EFI_ACPI_6_1_GIC_STRUCTURE *) (gMadtHdr + 1); + Length = sizeof (EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER); + + + do { + + if (Entry->Type == EFI_ACPI_6_1_GIC) { + if (Entry->PhysicalBaseAddress != 0) { + GicEntry->type = ENTRY_TYPE_CPUIF; + GicEntry->base = Entry->PhysicalBaseAddress; + pal_print(ACS_LOG_INFO, "\n GIC CPUIF base %x", GicEntry->base); + GicEntry++; + } + } + + if (Entry->Type == EFI_ACPI_6_1_GICR) { + GicEntry->type = ENTRY_TYPE_GICRD; + GicEntry->base = ((EFI_ACPI_6_1_GICR_STRUCTURE *)Entry)->DiscoveryRangeBaseAddress; + pal_print(ACS_LOG_INFO, "\n GIC RD base %x", GicEntry->base); + GicTable->header.num_gicrd++; + GicEntry++; + } + + if (Entry->Type == EFI_ACPI_6_1_GICD) { + GicEntry->type = ENTRY_TYPE_GICD; + GicEntry->base = ((EFI_ACPI_6_1_GIC_DISTRIBUTOR_STRUCTURE *)Entry)->PhysicalBaseAddress; + GicTable->header.gic_version = ((EFI_ACPI_6_1_GIC_DISTRIBUTOR_STRUCTURE *)Entry)->GicVersion; + GicTable->header.num_gicd++; + GicEntry++; + } + + if (Entry->Type == EFI_ACPI_6_1_GIC_ITS) { + GicEntry->type = ENTRY_TYPE_GICITS; + GicEntry->base = ((EFI_ACPI_6_1_GIC_ITS_STRUCTURE *)Entry)->PhysicalBaseAddress; + pal_print(ACS_LOG_INFO, "\n GIC ITS base %x", GicEntry->base); + GicTable->header.num_its++; + GicEntry++; + } + Length += Entry->Length; + Entry = (EFI_ACPI_6_1_GIC_STRUCTURE *) ((UINT8 *)Entry + (Entry->Length)); + + + } while (Length < TableLength); + + GicEntry->type = 0xFF; //Indicate end of data + +} + +/** + @brief Enable the interrupt in the GIC Distributor and GIC CPU Interface and hook + the interrupt service routine for the IRQ to the UEFI Framework + + @param int_id Interrupt ID which needs to be enabled and service routine installed for + @param isr Function pointer of the Interrupt service routine + + @return Status of the operation +**/ +UINT32 +pal_gic_install_isr(UINT32 int_id, VOID *isr) +{ + + EFI_STATUS Status; + + // Find the interrupt controller protocol. + Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt); + if (EFI_ERROR(Status)) { + return 0xFFFFFFFF; + } + + //First disable the interrupt to enable a clean handoff to our Interrupt handler. + gInterrupt->DisableInterruptSource(gInterrupt, int_id); + + //Register our handler + Status = gInterrupt->RegisterInterruptSource (gInterrupt, int_id, isr); + if (EFI_ERROR(Status)) { + Status = gInterrupt->RegisterInterruptSource (gInterrupt, int_id, NULL); //Deregister existing handler + Status = gInterrupt->RegisterInterruptSource (gInterrupt, int_id, isr); //register our Handler. + //Even if this fails. there is nothing we can do in UEFI mode + } + + return 0; +} + +VOID +pal_gic_end_of_interrupt(UINT32 int_id) +{ + // Find the interrupt controller protocol. + gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt); + + //EndOfInterrupt. + gInterrupt->EndOfInterrupt(gInterrupt, int_id); +} + +UINT32 +pal_gic_free_interrupt(UINT32 int_id) +{ + return 0; +} diff --git a/sdei/platform/pal_uefi/src/pal_misc.c b/sdei/platform/pal_uefi/src/pal_misc.c new file mode 100644 index 0000000..a7152ba --- /dev/null +++ b/sdei/platform/pal_uefi/src/pal_misc.c @@ -0,0 +1,142 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#include +#include +#include +#include +#include + +#include "pal_uefi.h" + +/** + @brief Sends a formatted string to the output console + + @param string An ASCII string + @param data data for the formatted output + + @return None +**/ +VOID +pal_print(UINT32 verbosity, CHAR8 *str, ...) { + if (verbosity <= g_log_control.print_level) { + + CHAR8 Buffer[2048]; + UINTN BufferSize = 1; + if (str) { + VA_LIST marker; + VA_START(marker, str); + BufferSize = AsciiVSPrint(Buffer, 2048, str, marker); + VA_END(marker); + } + + AsciiPrint(Buffer); + + if (g_log_control.log_file_handle) { + + EFI_STATUS Status = 0; + Status = ShellWriteFile(g_log_control.log_file_handle, &BufferSize, (VOID*)Buffer); + if (EFI_ERROR(Status)) + AsciiPrint("Error in writing to log file\n"); + } + } +} + +/** + @brief Provides a single point of abstraction to read from all + Memory Mapped IO address + + @param addr 64-bit address + + @return 32-bit data read from the input address +**/ +UINT32 +pal_mmio_read(UINT64 addr) +{ + UINT32 data; + + if (addr & 0x3) { + addr = addr & ~(0x3); //make sure addr is aligned to 4 bytes + } + data = (*(volatile UINT32 *)addr); + return data; +} + +/** + @brief Provides a single point of abstraction to write to all + Memory Mapped IO address + + @param addr 64-bit address + @param data 32-bit data to write to address + + @return None +**/ +VOID +pal_mmio_write(UINT64 addr, UINT32 data) +{ + *(volatile UINT32 *)addr = data; +} + +UINT64 *pal_pa_to_va(UINT64 addr) +{ + return 0; +} + +VOID pal_va_write(UINT64 *addr, UINT32 offset, UINT32 data) +{ + +} + +VOID pal_va_free(UINT64 *addr) +{ + +} + +VOID +pal_print_raw(CHAR8 *string, UINT64 data) +{ + UINT8 j, buffer[16]; + INT8 i=0; + /* TODO : Fix THis */ + UINT64 addr = BASE_FVP_UART_BASE; + for (;*string!='\0';++string) { + if (*string == '%') { + ++string; + if (*string == 'd') { + while (data != 0) { + j = data%10; + data = data/10; + buffer[i]= j + 48 ; + i = i+1; + } + } else if (*string == 'x' || *string == 'X') { + while (data != 0) { + j = data & 0xf; + data = data >> 4; + buffer[i]= j + ((j > 9) ? 55 : 48) ; + i = i+1; + } + } + if (i>0) { + while (i>=0) + *(volatile UINT8 *)addr = buffer[--i]; + } else + *(volatile UINT8 *)addr = 48; + + } else + *(volatile UINT8 *)addr = *string; + } +} diff --git a/sdei/platform/pal_uefi/src/pal_pe.c b/sdei/platform/pal_uefi/src/pal_pe.c new file mode 100644 index 0000000..c95d555 --- /dev/null +++ b/sdei/platform/pal_uefi/src/pal_pe.c @@ -0,0 +1,368 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#include +#include +#include +#include + +#include "Include/IndustryStandard/Acpi61.h" +#include +#include + +#include "pal_uefi.h" + +static EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *gMadtHdr; +UINT8 *gSecondaryPeStack; +UINT64 gMpidrMax; +pe_shared_mem_t *g_pe_shared_mem; +pe_info_table_t *gPeTable; + +#define SIZE_STACK_SECONDARY_PE 0x200 //512 bytes per core +#define UPDATE_AFF_MAX(src,dest,mask) ((dest & mask) > (src & mask) ? (dest & mask) : (src & mask)) +#define PeStackTop(i) ((UINT64)gSecondaryPeStack + (i-1) * SIZE_STACK_SECONDARY_PE) +#define PSCI_STATE_POWER_DOWN (1 << 16) + +UINT64 +pal_get_madt_ptr(); +VOID +ArmCallSmc ( + IN OUT ARM_SMC_ARGS *Args + ); + +VOID +PsciCpuSuspend ( + IN OUT ARM_SMC_ARGS *Args + ); + +UINT64 +ArmReadMpidr ( + VOID + ); + +VOID +ModuleEntryPoint(); + +UINT64 +GetStackSize() +{ + return SIZE_STACK_SECONDARY_PE; +} + +/** + @brief Return the base address of the region allocated for Stack use for the Secondary + PEs. + @param None + @return base address of the Stack +**/ +UINT64 +PalGetSecondaryStackBase() +{ + return (UINT64)gSecondaryPeStack; +} + +/** + @brief Returns the Max of each 8-bit Affinity fields in MPIDR. + @param None + @return Max MPIDR +**/ +UINT64 +PalGetMaxMpidr() +{ + return gMpidrMax; +} + +VOID +PeSetData(UINT64 *Addr, UINT64 Payload, UINT64 Arg) +{ + *Addr = Payload; + *(Addr + 1) = Arg; + DataCacheCleanInvalidateVA((UINT64)Addr); +} + +VOID PeGetData(UINT64 *Addr, UINT64 *ResAddr, UINT64 *Arg) +{ + *ResAddr = *Addr; + *Arg = *(Addr + 1); +} + +STATIC VOID +PowerOnPe(UINT64 Mpidr) { + ARM_SMC_ARGS ArmSmcArgs; + ArmSmcArgs.Arg0 = ARM_SMC_ID_PSCI_CPU_ON_AARCH64; + ArmSmcArgs.Arg1 = Mpidr; + ArmSmcArgs.Arg2 = (UINT64)ModuleEntryPoint; + ArmCallSmc(&ArmSmcArgs); +} + +STATIC VOID +PowerOffPe() { + ARM_SMC_ARGS ArmSmcArgs; + ArmSmcArgs.Arg0 = ARM_SMC_ID_PSCI_CPU_OFF; + ArmSmcArgs.Arg1 = PSCI_STATE_POWER_DOWN; + ArmCallSmc(&ArmSmcArgs); +} + +STATIC UINT32 +PsciPowerStateIdExtended(VOID) +{ + ARM_SMC_ARGS ArmSmcArgs; + ArmSmcArgs.Arg0 = ARM_SMC_ID_PSCI_FEATURES; + ArmSmcArgs.Arg1 = ARM_SMC_ID_PSCI_CPU_SUSPEND_AARCH64; + ArmCallSmc(&ArmSmcArgs); + return (ArmSmcArgs.Arg0 >> 1) & 0x1; +} + +VOID +pal_pe_suspend(UINT32 PowerDown) +{ + UINT32 PowerState = 0; + if (PowerDown) { + if (PsciPowerStateIdExtended()) + PowerState = (1 << 30); + else + PowerState = (1 << 16); + } + ARM_SMC_ARGS ArmSmcArgs; + ArmSmcArgs.Arg0 = ARM_SMC_ID_PSCI_CPU_SUSPEND_AARCH64; + ArmSmcArgs.Arg1 = PowerState; + ArmSmcArgs.Arg2 = 0; + ArmSmcArgs.Arg3 = 0; + PsciCpuSuspend(&ArmSmcArgs); +} + +VOID +pal_pe_poweroff(UINT32 Index) { + PeSetData((UINT64*)PeStackTop(Index), (UINT64)PowerOffPe, 0); +} + +VOID +pal_pe_poweron(UINT64 Mpidr) { + PowerOnPe(Mpidr); +} + +INT32 +pal_invoke_psci_fn(UINT64 Arg0, UINT64 Arg1, UINT64 Arg2, UINT64 Arg3) +{ + ARM_SMC_ARGS ArmSmcArgs; + ArmSmcArgs.Arg0 = Arg0; + ArmSmcArgs.Arg1 = Arg1; + ArmSmcArgs.Arg2 = Arg2; + ArmSmcArgs.Arg3 = Arg3; + ArmCallSmc(&ArmSmcArgs); + return ArmSmcArgs.Arg0; +} + + +VOID +CEntryPoint(UINT64 Addr) { + UINT64 ResAddr = 0, Arg = 0; + while (1) { + while (!ResAddr) { + DataCacheInvalidateVA(Addr); + DataCacheInvalidateVA(Addr+8); + ResAddr = *(UINT64*)Addr; + Arg = *((UINT64*)Addr + 1); + } + ((VOID (*)(VOID*))ResAddr)((VOID*)Arg); + *(UINT64*)Addr = 0; + ResAddr = 0; + } +} + + +/** + @brief Allocate memory region for secondary PE stack use. SIZE of stack for each PE + is a #define + + @param Number of PEs + + @return None +**/ +VOID +PalAllocateSecondaryStack(UINT64 mpidr) +{ + EFI_STATUS Status; + UINT32 NumPe, Aff0, Aff1, Aff2, Aff3; + + Aff0 = ((mpidr & 0x00000000ff) >> 0); + Aff1 = ((mpidr & 0x000000ff00) >> 8); + Aff2 = ((mpidr & 0x0000ff0000) >> 16); + Aff3 = ((mpidr & 0xff00000000) >> 32); + + NumPe = ((Aff3+1) * (Aff2+1) * (Aff1+1) * (Aff0+1)); + + if (gSecondaryPeStack == NULL) { + Status = gBS->AllocatePool ( EfiBootServicesData, + (NumPe * SIZE_STACK_SECONDARY_PE), + (VOID **) &gSecondaryPeStack); + if (EFI_ERROR(Status)) { + pal_print(ACS_LOG_ERR, "\n FATAL-Allocation for Seconday stack failed %x", Status); + } + DataCacheCleanInvalidateVA((UINT64)&gSecondaryPeStack); + } +} + +/** + @brief This API fills in the PE_INFO Table with information about the PEs in the + system. This is achieved by parsing the ACPI - MADT table. + + @param PeTable - Address where the PE information needs to be filled. + + @return None +**/ +VOID +pal_pe_create_info_table(pe_info_table_t *PeTable) +{ + EFI_ACPI_6_1_GIC_STRUCTURE *Entry = NULL; + pe_info_entry_t *Ptr = NULL; + UINT32 TableLength = 0; + UINT32 Length = 0, Index; + UINT64 MpidrAff0Max = 0, MpidrAff1Max = 0, MpidrAff2Max = 0, MpidrAff3Max = 0; + + + if (PeTable == NULL) { + pal_print(ACS_LOG_ERR, "\n Input PE Table Pointer is NULL. Cannot create PE INFO"); + return; + } + + gMadtHdr = (EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *) pal_get_madt_ptr(); + gPeTable = PeTable; + + if (gMadtHdr != NULL) { + TableLength = gMadtHdr->Header.Length; + pal_print(ACS_LOG_INFO, "\n MADT is at %x and length is %x", gMadtHdr, TableLength); + } else { + pal_print(ACS_LOG_ERR, "\n MADT not found"); + return; + } + + PeTable->header.num_of_pe = 0; + + Entry = (EFI_ACPI_6_1_GIC_STRUCTURE *) (gMadtHdr + 1); + Length = sizeof (EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER); + Ptr = PeTable->pe_info; + + do { + + if (Entry->Type == EFI_ACPI_6_1_GIC) { + //Fill in the cpu num and the mpidr in pe info table + Ptr->mpidr = Entry->MPIDR; + Ptr->pe_num = PeTable->header.num_of_pe; + Ptr->pmu_gsiv = Entry->PerformanceInterruptGsiv; + pal_print(ACS_LOG_DEBUG, "\n MPIDR %x PE num %x", Ptr->mpidr, Ptr->pe_num); + DataCacheCleanInvalidateVA((UINT64)Ptr); + Ptr++; + PeTable->header.num_of_pe++; + + MpidrAff0Max = UPDATE_AFF_MAX(MpidrAff0Max, Entry->MPIDR, 0x000000ff); + MpidrAff1Max = UPDATE_AFF_MAX(MpidrAff1Max, Entry->MPIDR, 0x0000ff00); + MpidrAff2Max = UPDATE_AFF_MAX(MpidrAff2Max, Entry->MPIDR, 0x00ff0000); + MpidrAff3Max = UPDATE_AFF_MAX(MpidrAff3Max, Entry->MPIDR, 0xff00000000); + } + + Length += Entry->Length; + Entry = (EFI_ACPI_6_1_GIC_STRUCTURE *) ((UINT8 *)Entry + (Entry->Length)); + + }while (Length < TableLength); + + gMpidrMax = MpidrAff0Max | MpidrAff1Max | MpidrAff2Max | MpidrAff3Max; + PalAllocateSecondaryStack(gMpidrMax); + DataCacheCleanInvalidateVA((UINT64)&gMpidrMax); + DataCacheCleanInvalidateVA((UINT64)PeTable); + + Ptr = PeTable->pe_info; + Ptr++; + for (Index = 1; Index < PeTable->header.num_of_pe; Index++) { + PowerOnPe(Ptr->mpidr); + Ptr++; + } + +} + +int pal_pe_execute_on_all(int num_pe, VOID *payload, UINT64 arg) { + int i; + UINT64 *Addr, MyMpidr = ArmReadMpidr() & (~(0xffULL << 24)); + pe_info_entry_t *Ptr = gPeTable->pe_info; + + ((VOID(*)(VOID*))payload)((VOID*)arg); + for (i = 0; i < num_pe; i++, Ptr++) { + if (MyMpidr == Ptr->mpidr) + continue; + Addr = (UINT64*)PeStackTop(i); + *(Addr+1) = arg; + *Addr = (UINT64)payload; + DataCacheCleanInvalidateVA((UINT64)(Addr + 1)); + DataCacheCleanInvalidateVA((UINT64)Addr); + while (1) { + DataCacheInvalidateVA((UINT64)Addr); + if (*Addr == 0) + break; + } + } + return 0; +} + +void pal_pe_clean_up() { + for (int i = 1; i < gPeTable->header.num_of_pe; i++) { + PeSetData((UINT64*)PeStackTop(i), (UINT64)PowerOffPe, 0); + } +} + +/** +@brief Allocate memory which is to be used to share data across PEs + +@param num_pe - Number of PEs in the system +@param sizeofentry - Size of memory region allocated to each PE + +@return None +**/ +acs_status_t +pal_pe_alloc_shared_mem(UINT32 num_pe, UINT32 sizeofentry) +{ + EFI_STATUS Status; + g_pe_shared_mem = NULL; + + Status = gBS->AllocatePool ( EfiBootServicesData, + (num_pe * sizeofentry), + (VOID **) &g_pe_shared_mem ); + + pal_print(ACS_LOG_INFO, "\n Shared memory is %llx", g_pe_shared_mem); + + if (EFI_ERROR(Status)) { + pal_print(ACS_LOG_ERR, "\n Allocate Pool shared memory failed %x", Status); + } + DataCacheCleanInvalidateVA((UINT64)&g_pe_shared_mem); + return ACS_SUCCESS; +} + +void +pal_pe_free_shared_mem() +{ + gBS->FreePool((VOID*)g_pe_shared_mem); +} + +void +pal_pe_data_cache_invalidate(UINT64 Addr) +{ + DataCacheInvalidateVA(Addr); +} + +void +pal_pe_data_cache_clean_invalidate(UINT64 Addr) +{ + DataCacheCleanInvalidateVA(Addr); +} diff --git a/sdei/platform/pal_uefi/src/pal_sdei_interface.c b/sdei/platform/pal_uefi/src/pal_sdei_interface.c new file mode 100644 index 0000000..4e950a1 --- /dev/null +++ b/sdei/platform/pal_uefi/src/pal_sdei_interface.c @@ -0,0 +1,251 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include +#include +#include +#include +#include + +#include "Foundation/Efi/Guid/Acpi/Acpi.h" +#include +#include "Include/IndustryStandard/Acpi61.h" + +#include "pal_uefi.h" +#include "pal_sdei_interface.h" + +#define GHES_VERSION_2 10 +#define GHES_NOTIFY_TYPE_SDEI 0xb + +/* + * The call to use to reach the firmware. + */ +void (*sdei_firmware_call)(ARM_SMC_ARGS *args); +typedef struct { + UINT32 a; //TODO to remove once supported +} EFI_ACPI_6_2_SOFTWARE_DELEGATION_EXCEPTION_INTERFACE; +static EFI_ACPI_6_2_SOFTWARE_DELEGATION_EXCEPTION_INTERFACE *gSdeiHdr; //TODO ADD SDEI SPECIFIC SIGNATURE + +UINT64 +pal_get_sdei_ptr(); + +UINT64 +pal_get_fadt_ptr(); + +UINT64 +pal_get_hest_ptr(); + +void +ArmCallSmc ( + IN OUT ARM_SMC_ARGS *Args + ); + +void +ArmCallHvc ( + IN OUT ARM_SMC_ARGS *Args + ); + +int pal_pe_get_mpidr_cpu_id(int cpu, UINT64 *fw_cpu) +{ + int err = SDEI_STATUS_INVALID; + //TODO + + return err; +} + +int pal_pe_get_cpu_id_mpidr(UINT64 fw_cpu, int *cpu) +{ + int err = SDEI_STATUS_INVALID; + //TODO + + return err; +} + +int pal_sdei_to_uefi_errno(unsigned long sdei_err) +{ + switch (sdei_err) { + case SDEI_NOT_SUPPORTED: + return SDEI_STATUS_NOT_SUPPORTED; + case SDEI_INVALID_PARAMETERS: + return SDEI_STATUS_INVALID; + case SDEI_DENIED: + return SDEI_STATUS_DENIED; + case SDEI_PENDING: + return SDEI_STATUS_PENDING; + case SDEI_OUT_OF_RESOURCE: + return SDEI_STATUS_OUT_OF_RESOURCE; + } + + /* Not an error value ... */ + return sdei_err; +} + +/* + * If x0 is any of these values, then the call failed, use sdei_to_uefi_errno() + * to translate. + */ +static int sdei_is_err(UINT64 res) +{ + switch (res) { + case SDEI_NOT_SUPPORTED: + case SDEI_INVALID_PARAMETERS: + case SDEI_DENIED: + case SDEI_PENDING: + case SDEI_OUT_OF_RESOURCE: + return TRUE; + } + + return FALSE; +} + +int pal_invoke_sdei_fn(unsigned long function_id, unsigned long arg0, + unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, + UINT64 *result) +{ + int err = 0; + UINT64 res; + ARM_SMC_ARGS args; + args.Arg0 = function_id; + args.Arg1 = arg0; + args.Arg2 = arg1; + args.Arg3 = arg2; + args.Arg4 = arg3; + args.Arg5 = arg4; + + ArmCallSmc(&args); + res = args.Arg0; + + if (sdei_is_err(res)) + err = pal_sdei_to_uefi_errno(res); + + if (result) + *result = res; + + return err; +} + +void pal_execute_eachpe(void *func, void *info, int wait){ + + //TODO; +} + +void *pal_intf_alloc(int size){ + return 0; +} + +void pal_intf_free(void *handle) { + +} + +unsigned int pal_smp_pe_id(void) { + + //TODO; + return 0; +} + +void pal_intf_lock(void) { + +} + +void pal_intf_unlock(void) { + +} + +/** + @brief Make the SMC call using AARCH64 Assembly code + SMC calls can take up to 7 arguments and return up to 4 return values. + Therefore, the 4 first fields in the ARM_SMC_ARGS structure are used + for both input and output values. + + @param Argumets to pass to the EL3 firmware + + @return None +**/ +VOID +pal_call_smc(ARM_SMC_ARGS *ArmSmcArgs) +{ + ArmCallSmc (ArmSmcArgs); +} + +void pal_interface_broken(void) +{ + sdei_firmware_call = NULL; +} + +int pal_conduit_get(void) +{ + sdei_firmware_call = &pal_call_smc; + return CONDUIT_SMC; +} + +int pal_acpi_present(void) +{ + gSdeiHdr = (EFI_ACPI_6_2_SOFTWARE_DELEGATION_EXCEPTION_INTERFACE *) pal_get_sdei_ptr(); //TODO ADD SDEI SPECIFIC SIGNATURE + + if (gSdeiHdr == NULL) { + pal_print(ACS_LOG_ERR, "\n SDEI entry not found in ACPI table"); + return FALSE; + } + + return TRUE; +} + +/* + * Read ACPI Hardware Error Source table and intialize the event info + * table with event numbers read from Generic Hardware Error Source + * structures in the table. + */ +int pal_sdei_create_event_info_table(event_info_table_t *EventTable) +{ + EFI_ACPI_6_1_HARDWARE_ERROR_SOURCE_TABLE_HEADER *Hest = NULL; + EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE *Ghes; + event_info_t *event; + int i; + + EventTable->num_events = 0; + EventTable->hest_found = 0; + EventTable->num_ghes_notify = 0; + Hest = (EFI_ACPI_6_1_HARDWARE_ERROR_SOURCE_TABLE_HEADER *) pal_get_hest_ptr(); + if (Hest == NULL) + return -1; + + //EventTable->num_events = Hest->ErrorSourceCount; + EventTable->hest_found = 1; + event = (event_info_t*) EventTable->info; + + Ghes = (EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE*)(Hest + 1); + for (i = 0; i < Hest->ErrorSourceCount; i++) { + if (Ghes->NotificationStructure.Type == GHES_NOTIFY_TYPE_SDEI) { + event->number = Ghes->NotificationStructure.Vector; + pal_print(ACS_LOG_DEBUG, "\n Found SDEI error event %d", event->number); + EventTable->num_ghes_notify++; + if (event->number) + EventTable->num_events++; + event++; + } + if (Ghes->Type == GHES_VERSION_2) + Ghes = (EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE*) + (UINT8*)Ghes + sizeof(EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE); + else + Ghes++; + + } + return 0; +} + diff --git a/sdei/platform/pal_uefi/src/pal_wd_timer.c b/sdei/platform/pal_uefi/src/pal_wd_timer.c new file mode 100644 index 0000000..279d8c0 --- /dev/null +++ b/sdei/platform/pal_uefi/src/pal_wd_timer.c @@ -0,0 +1,292 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include +#include +#include + +#include +#include "Include/IndustryStandard/Acpi61.h" + +#include "include/pal_uefi.h" + +#define INVALID_INDEX 0xFFFFFFFF + +typedef enum { + TIMER_INFO_IS_PLATFORM_TIMER_SECURE, + TIMER_INFO_SYS_INTID, + TIMER_INFO_SYS_CNT_BASE_N +} sys_timer_info_t; + +timer_info_table_t *g_sys_timertable; + +static EFI_ACPI_6_1_GENERIC_TIMER_DESCRIPTION_TABLE *gGtdtHdr; + +UINT64 +pal_get_gtdt_ptr(); + +/** + @brief This API fills in the TIMER_INFO_TABLE with information about local and system + timers in the system. This is achieved by parsing the ACPI - GTDT table. + + @param TimerTable - Address where the Timer information needs to be filled. + + @return None +**/ +VOID +pal_timer_create_info_table(timer_info_table_t *TimerTable) +{ + EFI_ACPI_6_1_GTDT_GT_BLOCK_STRUCTURE *Entry = NULL; + EFI_ACPI_6_1_GTDT_GT_BLOCK_TIMER_STRUCTURE *GtBlockTimer = NULL; + timer_info_gtblock_t *GtEntry = NULL; + UINT32 Length= 0; + UINT32 i; + UINT32 num_of_entries; + + if (TimerTable == NULL) { + pal_print(ACS_LOG_ERR, "\n Input Timer Table Pointer is NULL."); + return; + } + + GtEntry = TimerTable->gt_info; + TimerTable->header.num_platform_timer = 0; + + gGtdtHdr = (EFI_ACPI_6_1_GENERIC_TIMER_DESCRIPTION_TABLE *) pal_get_gtdt_ptr(); + + if (gGtdtHdr == NULL) { + pal_print(ACS_LOG_ERR, "\n GTDT not found"); + return; + } + pal_print(ACS_LOG_INFO, "\n GTDT is at %x and length is %x", + gGtdtHdr, gGtdtHdr->Header.Length); + + /* Fill in our internal table */ + TimerTable->header.s_el1_timer_flag = gGtdtHdr->SecurePL1TimerFlags; + TimerTable->header.ns_el1_timer_flag = gGtdtHdr->NonSecurePL1TimerFlags; + TimerTable->header.el2_timer_flag = gGtdtHdr->NonSecurePL2TimerFlags; + TimerTable->header.s_el1_timer_gsiv = gGtdtHdr->SecurePL1TimerGSIV; + TimerTable->header.ns_el1_timer_gsiv = gGtdtHdr->NonSecurePL1TimerGSIV; + TimerTable->header.el2_timer_gsiv = gGtdtHdr->NonSecurePL2TimerGSIV; + TimerTable->header.virtual_timer_flag = gGtdtHdr->VirtualTimerFlags; + TimerTable->header.virtual_timer_gsiv = gGtdtHdr->VirtualTimerGSIV; + + Length = gGtdtHdr->PlatformTimerOffset; + Entry = (EFI_ACPI_6_1_GTDT_GT_BLOCK_STRUCTURE *) ((UINT8 *)gGtdtHdr + Length); + Length = sizeof (EFI_ACPI_6_1_GENERIC_TIMER_DESCRIPTION_TABLE); + num_of_entries = gGtdtHdr->PlatformTimerCount; + + while (num_of_entries) { + + if (Entry->Type == EFI_ACPI_6_1_GTDT_GT_BLOCK) { + pal_print(ACS_LOG_INFO, "\n Found block entry"); + GtEntry->type = TIMER_TYPE_SYS_TIMER; + GtEntry->block_cntl_base = Entry->CntCtlBase; + GtEntry->timer_count = Entry->GTBlockTimerCount; + pal_print(ACS_LOG_DEBUG, "\n CNTCTLBase = %x", GtEntry->block_cntl_base); + GtBlockTimer = (EFI_ACPI_6_1_GTDT_GT_BLOCK_TIMER_STRUCTURE *)(((UINT8 *)Entry) + + Entry->GTBlockTimerOffset); + for (i = 0; i < GtEntry->timer_count; i++) { + pal_print(ACS_LOG_INFO, "\n Found timer entry"); + GtEntry->GtCntBase[i] = GtBlockTimer->CntBaseX; + GtEntry->GtCntEl0Base[i] = GtBlockTimer->CntEL0BaseX; + GtEntry->gsiv[i] = GtBlockTimer->GTxPhysicalTimerGSIV; + GtEntry->virt_gsiv[i] = GtBlockTimer->GTxVirtualTimerGSIV; + GtEntry->flags[i] = GtBlockTimer->GTxPhysicalTimerFlags | + (GtBlockTimer->GTxVirtualTimerFlags << 8) | + (GtBlockTimer->GTxCommonFlags << 16); + DataCacheCleanInvalidateVA((UINT64)GtEntry); + pal_print(ACS_LOG_DEBUG, "\n CNTBaseN = %x for sys counter = %d", + GtEntry->GtCntBase[i], i); + GtBlockTimer++; + TimerTable->header.num_platform_timer++; + } + GtEntry++; + } + Entry = (EFI_ACPI_6_1_GTDT_GT_BLOCK_STRUCTURE *) ((UINT8 *)Entry + (Entry->Length)); + num_of_entries--; + } + DataCacheCleanInvalidateVA((UINT64)TimerTable); + g_sys_timertable = TimerTable; +} + +/** + @brief This API fills in the wd_info_table_t with information about Watchdogs + in the system. This is achieved by parsing the ACPI - GTDT table. + + @param WdTable - Address where the Timer information needs to be filled. + + @return None +**/ + +UINT32 +pal_wd_create_info_table(wd_info_table_t *WdTable) +{ + + EFI_ACPI_6_1_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE *Entry = NULL; + wd_info_entry_t *WdEntry = NULL; + UINT32 Length= 0; + UINT32 num_of_entries; + + if (WdTable == NULL) { + pal_print(ACS_LOG_ERR, "\n Input Watchdog Table Pointer is NULL."); + return 1; + } + + WdEntry = WdTable->wd_info; + WdTable->header.num_wd = 0; + gGtdtHdr = (EFI_ACPI_6_1_GENERIC_TIMER_DESCRIPTION_TABLE *) pal_get_gtdt_ptr(); + + if (gGtdtHdr == NULL) { + pal_print(ACS_LOG_ERR, "\n GTDT not found"); + return 1; + } + + Length = gGtdtHdr->PlatformTimerOffset; + Entry = (EFI_ACPI_6_1_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE *) ((UINT8 *)gGtdtHdr + + Length); + Length = sizeof (EFI_ACPI_6_1_GENERIC_TIMER_DESCRIPTION_TABLE); + num_of_entries = gGtdtHdr->PlatformTimerCount; + + while (num_of_entries) + { + + if (Entry->Type == EFI_ACPI_6_1_GTDT_GT_BLOCK) { + //Skip. this info is added in the timer info function + } + + if (Entry->Type == EFI_ACPI_6_1_GTDT_SBSA_GENERIC_WATCHDOG) { + WdEntry->wd_refresh_base = Entry->RefreshFramePhysicalAddress; + WdEntry->wd_ctrl_base = Entry->WatchdogControlFramePhysicalAddress; + WdEntry->wd_gsiv = Entry->WatchdogTimerGSIV; + WdEntry->wd_flags = Entry->WatchdogTimerFlags; + DataCacheCleanInvalidateVA((UINT64)WdEntry); + WdTable->header.num_wd++; + pal_print(ACS_LOG_INFO, "\n Watchdog base = 0x%x INTID = 0x%x", + WdEntry->wd_ctrl_base, WdEntry->wd_gsiv); + WdEntry++; + } + Entry = (EFI_ACPI_6_1_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE *)((UINT8 *)Entry + (Entry->Length)); + num_of_entries--; + + } + DataCacheCleanInvalidateVA((UINT64)WdTable); + + return 0; +} + +VOID pal_wd_set_ws0(UINT64 *vaddr, UINT64 base, UINT32 index, UINT32 timeout) +{ + if (timeout == 0) { + pal_mmio_write((base + WD_REG_BASE), WD_DISABLE); //val_wd_disable(index); + return; + } + + pal_mmio_write((base + WD_REG_CTRL), timeout); + pal_mmio_write((base + WD_REG_BASE), WD_ENABLE); //val_wd_enable(index); +} + +VOID pal_platform_timer_get_entry_index(UINT32 index, UINT32 *block, UINT32 *block_index) +{ + if (index > g_sys_timertable->header.num_platform_timer){ + *block = INVALID_INDEX; + return; + } + *block = 0; + *block_index = index; + while (index > g_sys_timertable->gt_info[*block].timer_count) { + index = index - g_sys_timertable->gt_info[*block].timer_count; + *block_index = index; + *block = *block + 1; + } +} + +UINT64 pal_timer_get_info(UINT32 type, UINT32 index) +{ + UINT32 block_num, block_index; + + if (!g_sys_timertable) + return INVALID_INDEX; + + switch (type) { + case TIMER_INFO_IS_PLATFORM_TIMER_SECURE: + pal_platform_timer_get_entry_index (index, &block_num, &block_index); + if (block_num != INVALID_INDEX) + return ((g_sys_timertable->gt_info[block_num].flags[block_index] >> 16) & 1); + break; + case TIMER_INFO_SYS_INTID: + pal_platform_timer_get_entry_index (index, &block_num, &block_index); + if (block_num != INVALID_INDEX) + return g_sys_timertable->gt_info[block_num].gsiv[block_index]; + break; + case TIMER_INFO_SYS_CNT_BASE_N: + pal_platform_timer_get_entry_index (index, &block_num, &block_index); + if (block_num != INVALID_INDEX) + return g_sys_timertable->gt_info[block_num].GtCntBase[block_index]; + break; + default: + break; + } + + return INVALID_INDEX; +} + +acs_status_t pal_configure_second_interrupt(UINT32 *index, UINT64 *int_id) +{ + UINT64 timer_num = g_sys_timertable->header.num_platform_timer; + UINT32 ns_timer= 0; + + if (!timer_num) { + pal_print(ACS_LOG_ERR, "\n No System timers are defined"); + return ACS_ERROR; + } + + while (timer_num && !ns_timer) { + /* array index starts from 0, so subtract 1 from count */ + timer_num--; + /* Skip secure timer */ + if (pal_timer_get_info(TIMER_INFO_IS_PLATFORM_TIMER_SECURE, timer_num)) + continue; + + ns_timer++; + + *int_id = pal_timer_get_info(TIMER_INFO_SYS_INTID, timer_num); + *index = timer_num; + } + + if (!ns_timer) { + pal_print(ACS_LOG_ERR, "\n No non-secure systimer implemented"); + return ACS_ERROR; + } + + return ACS_SUCCESS; +} + +VOID pal_generate_second_interrupt(UINT32 index, UINT32 timeout) +{ + UINT64 cnt_base_n; + cnt_base_n = pal_timer_get_info(TIMER_INFO_SYS_CNT_BASE_N, index); + pal_mmio_write(cnt_base_n + 0x28, timeout); + pal_mmio_write(cnt_base_n + 0x2C, 1); +} + +VOID pal_disable_second_interrupt(UINT32 index) +{ + UINT64 cnt_base_n; + cnt_base_n = pal_timer_get_info(TIMER_INFO_SYS_CNT_BASE_N, index); + pal_mmio_write(cnt_base_n + 0x2C, 0); +} diff --git a/sdei/scripts/acsbuild.sh b/sdei/scripts/acsbuild.sh new file mode 100755 index 0000000..6b3bc25 --- /dev/null +++ b/sdei/scripts/acsbuild.sh @@ -0,0 +1,9 @@ + +if [ -v $GCC49_AARCH64_PREFIX ] +then + echo "GCC49_AARCH64_PREFIX is not set" + echo "set using export GCC49_AARCH64_PREFIX=/bin/aarch64-linux-gnu-" + return 0 +fi + +build -a AARCH64 -t GCC49 -p ShellPkg/ShellPkg.dsc -m AppPkg/Applications/sdei-acs/uefi_app/SdeiAcs.inf diff --git a/sdei/scripts/build_linux.sh b/sdei/scripts/build_linux.sh new file mode 100755 index 0000000..4941f36 --- /dev/null +++ b/sdei/scripts/build_linux.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +W=${PWD}/workspace +S=${PWD} + +if [ ! -d workspace ] +then + mkdir workspace +fi +cd ${W} +if [ ! -d gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu ] +then + rm -f gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu.tar.xz + wget https://releases.linaro.org/components/toolchain/binaries/6.3-2017.05/aarch64-linux-gnu/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu.tar.xz + xz -d gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu.tar.xz + tar -xf gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu.tar +fi +if [ ! -d output ] +then + mkdir output +fi + +echo "Building SDEI ACS for Linux" +if [ ! -d linux-acs ] +then + git clone git://linux-arm.org/linux-acs.git +fi +if [ ! -d linux ] +then + git clone https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux + cd linux + git checkout -b v4.13 v4.13 + git apply ${W}/linux-acs/kernel/src/0001-Enterprise-acs-linux-v4.13.patch + cd ${W} +fi +cd linux +export ARCH=arm64 +export CROSS_COMPILE=${W}/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- +make defconfig +make -j16 +cp arch/arm64/boot/Image ../output +cd ${W}/linux-acs/sdei-acs-drv/files +./setup.sh ${S} +export KERNEL_SRC=${W}/linux +cd platform/pal_linux +make +cd ../../val +make +cd ../ +make +cp sdei_acs.ko ${W}/output + +cd ${S}/linux_app/ +make +cp sdei ${W}/output +cd ${S} diff --git a/sdei/scripts/build_uefi.sh b/sdei/scripts/build_uefi.sh new file mode 100755 index 0000000..618f597 --- /dev/null +++ b/sdei/scripts/build_uefi.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +W=${PWD}/workspace +S=${PWD} + +if [ ! -d workspace ] +then + mkdir workspace +fi +cd ${W} +if [ ! -d gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu ] +then + rm -f gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu.tar.xz + wget https://releases.linaro.org/components/toolchain/binaries/6.3-2017.05/aarch64-linux-gnu/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu.tar.xz + xz -d gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu.tar.xz + tar -xf gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu.tar +fi + +if [ ! -d output ] +then + mkdir output +fi + +echo "Building SDEI ACS for UEFI" +if [ ! -d edk2 ] +then + git clone https://github.com/tianocore/edk2.git +fi +cd ${W}/edk2 +make -C BaseTools + +if ! grep -q SdeiPalLib "ShellPkg/ShellPkg.dsc" +then + sed -i '/LibraryClasses.common/ a \ \ SdeiPalLib|AppPkg/Applications/sdei-acs/platform/pal_uefi/SdeiPalLib.inf' ShellPkg/ShellPkg.dsc +fi +if ! grep -q SdeiValLib "ShellPkg/ShellPkg.dsc" +then + sed -i '/LibraryClasses.common/ a \ \ SdeiValLib|AppPkg/Applications/sdei-acs/val/SdeiValLib.inf' ShellPkg/ShellPkg.dsc +fi +if ! grep -q SdeiAcs "ShellPkg/ShellPkg.dsc" +then + sed -i '/Components/ a \ \ AppPkg/Applications/sdei-acs/uefi_app/SdeiAcs.inf' ShellPkg/ShellPkg.dsc +fi + +rm -f AppPkg/Applications/sdei-acs +ln -s ${S} AppPkg/Applications/sdei-acs +export GCC49_AARCH64_PREFIX=${W}/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- +source edksetup.sh +./AppPkg/Applications/sdei-acs/scripts/acsbuild.sh +cp Build/Shell/DEBUG_GCC49/AARCH64/Sdei.efi ../output diff --git a/sdei/test_pool/test_001.c b/sdei/test_pool/test_001.c new file mode 100644 index 0000000..3444473 --- /dev/null +++ b/sdei/test_pool/test_001.c @@ -0,0 +1,51 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include + +#define TEST_DESC "Verify that system has EL2, or EL3, or both " + +/* This function reads ID_AA64PFR0_EL1 system register on each PE and verify the + * EL3 or EL2 implementation + */ +static void payload(void* data) +{ + uint64_t cfg; + int el3 = 0, el2 = 0; + acs_status_t status = val_pe_reg_read(ID_AA64PFR0_EL1, &cfg); + if (status == ACS_SUCCESS) { + if (cfg & (0xf << 12)) + el3 = 1; + if (cfg & (0xf << 8)) + el2 = 1; + } else { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_ABORT); + return; + } + if (el3 || el2) + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + else + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); +} + +static void test_entry(void) +{ + val_pe_execute_on_all((void*)payload, 0); +} + +SDEI_SET_TEST_DEPS(test_001_deps, TEST_NONE_ID); +SDEI_PUBLISH_TEST(test_001, TEST_001_ID, TEST_DESC, test_001_deps, test_entry, TRUE); diff --git a/sdei/test_pool/test_002.c b/sdei/test_pool/test_002.c new file mode 100644 index 0000000..09401f7 --- /dev/null +++ b/sdei/test_pool/test_002.c @@ -0,0 +1,49 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include + +#define TEST_DESC "Verify that system has GICv3 " + +/* This function verifies the GICv3 support implementation */ +static void payload(void) +{ + uint32_t gic_version; + acs_status_t status = val_gic_get_version(&gic_version); + + if (status == ACS_SUCCESS) { + if (gic_version == GIC_INFO_VERSION) { + val_print(ACS_LOG_INFO, "\n GICv3 implemented"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + } else { + val_print(ACS_LOG_INFO, "\n GICv3 not implemented"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + } + } else { + val_print(ACS_LOG_ERR, "\n val_gic_get_version failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_ABORT); + } + return; +} + +static void test_entry(void) +{ + payload(); +} + +SDEI_SET_TEST_DEPS(test_002_deps, TEST_NONE_ID); +SDEI_PUBLISH_TEST(test_002, TEST_002_ID, TEST_DESC, test_002_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_003.c b/sdei/test_pool/test_003.c new file mode 100644 index 0000000..16b5a6c --- /dev/null +++ b/sdei/test_pool/test_003.c @@ -0,0 +1,95 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI event register test " +#define SDEI_UNKNOWN_EVENT 0x10000 +#define REGISTERED 0x1 + +/* This function verifies the shared and private events register to Dispatcher. + * it also checks event register error checks. + */ +static uint32_t payload(void *data) +{ + uint64_t type = (uint64_t)data; + uint32_t event_num, status = SDEI_TEST_PASS; + int32_t err; + uint64_t event_status; + + event_num = val_event_get(type, SDEI_EVENT_PRIORITY_ANY); + if (!event_num) { + status = SDEI_TEST_SKIP; + goto return_status; + } + + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + status = SDEI_TEST_FAIL; + goto return_status; + } + + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err != SDEI_STATUS_DENIED) { + status = SDEI_TEST_FAIL; + goto event_unregister; + } + + err = val_sdei_event_status(event_num, &event_status); + if (err) { + status = SDEI_TEST_ERROR; + goto event_unregister; + } + + if (!(event_status & REGISTERED)) { + status = SDEI_TEST_FAIL; + goto event_unregister; + } + +event_unregister: + err = val_sdei_event_unregister(event_num); + if (err) { + status = SDEI_TEST_ERROR; + goto return_status; + } + +return_status: + val_test_pe_set_status(val_pe_get_index(), status); + return status; +} + +static void test_entry(void) +{ + uint32_t ret; + + ret = payload((void*)SDEI_EVENT_TYPE_SHARED); + + if (ret & SDEI_TEST_FAIL) + return; + + ret = val_sdei_event_register(SDEI_UNKNOWN_EVENT, (uint64_t)asm_event_handler, NULL, 0, 0); + if (ret != SDEI_STATUS_INVALID) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + val_pe_execute_on_all(payload, SDEI_EVENT_TYPE_PRIVATE); +} + +SDEI_SET_TEST_DEPS(test_003_deps, TEST_NONE_ID); +SDEI_PUBLISH_TEST(test_003, TEST_003_ID, TEST_DESC, test_003_deps, test_entry, TRUE); diff --git a/sdei/test_pool/test_004.c b/sdei/test_pool/test_004.c new file mode 100644 index 0000000..063b763 --- /dev/null +++ b/sdei/test_pool/test_004.c @@ -0,0 +1,121 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI interrupt bind test (SPI,PPI, SGI) " + +/* This function verifies the shared and private interrupt binding to event. + * it also checks sdei interrupt bind error checks. + */ +static void payload(void) +{ + uint32_t event_num, new_event_num; + int32_t err; + + /* Interrupt bind test for SPI */ + err = val_gic_disable_interrupt(SPI_INTR_NUM); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %d disable failed", SPI_INTR_NUM); + return; + } + err = val_sdei_interrupt_bind(SPI_INTR_NUM, &event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI interrupt number %d bind failed with err %d", + SPI_INTR_NUM, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + err = val_sdei_interrupt_bind(SPI_INTR_NUM, &new_event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI interrupt number %d bind failed with err %d", + SPI_INTR_NUM, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + if (event_num != new_event_num) { + val_print(ACS_LOG_ERR, "\n SPI interrupt number %d re-bind test" + "failed with err %d\n", SPI_INTR_NUM, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + } + err = val_sdei_interrupt_release(event_num); + if (err) { + val_print(ACS_LOG_WARN, "\n Event number %d intrrupt release failed with err %d", + event_num, err); + } + + /* Interrupt bind test for PPI */ + err = val_gic_disable_interrupt(PPI_INTR_NUM); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %d disable failed", PPI_INTR_NUM); + return; + } + err = val_sdei_interrupt_bind(PPI_INTR_NUM, &event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n PPI interrupt number %d bind failed with err %d", + PPI_INTR_NUM, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + err = val_sdei_interrupt_bind(PPI_INTR_NUM, &new_event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n PPI interrupt number %d bind failed with err %d", + PPI_INTR_NUM, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + if (event_num != new_event_num) { + val_print(ACS_LOG_ERR, "\n PPI interrupt number %d re-bind test" + "failed with err %d", PPI_INTR_NUM, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + } + err = val_sdei_interrupt_release(event_num); + if (err) { + val_print(ACS_LOG_WARN, "\n Event number %d intrrupt release failed with err %d", + event_num, err); + } + + /* Interrupt bind test for SGI */ + err = val_gic_disable_interrupt(SGI_INTR_NUM); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %d disable failed", SGI_INTR_NUM); + return; + } + err = val_sdei_interrupt_bind(SGI_INTR_NUM, &event_num); + if (err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n SGI interrupt number %d bind failed", SGI_INTR_NUM); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); +} + +static void test_entry(void) +{ + payload(); +} + +SDEI_SET_TEST_DEPS(test_004_deps, TEST_NONE_ID); +SDEI_PUBLISH_TEST(test_004, TEST_004_ID, TEST_DESC, test_004_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_005.c b/sdei/test_pool/test_005.c new file mode 100644 index 0000000..0ec80a6 --- /dev/null +++ b/sdei/test_pool/test_005.c @@ -0,0 +1,98 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI event enable test " +#define SDEI_UNKNOWN_EVENT 0x10000 +#define EVENT_ENABLED 0x2 + +/* This function verifies the shared and private events enable functionality. + * it also checks event enable error checks. + */ +static uint32_t payload(void *data) +{ + uint64_t type = (uint64_t)data; + uint32_t event_num, status = SDEI_TEST_PASS; + int32_t err; + uint64_t event_status; + + event_num = val_event_get(type, SDEI_EVENT_PRIORITY_ANY); + if (!event_num) { + status = SDEI_TEST_SKIP; + goto return_status; + } + /*Try to to enable unregistered event */ + err = val_sdei_event_enable(event_num); + if (err != SDEI_STATUS_DENIED) { + status = SDEI_TEST_FAIL; + goto return_status; + } + + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + status = SDEI_TEST_FAIL; + goto return_status; + } + + err = val_sdei_event_enable(event_num); + if (err) { + status = SDEI_TEST_FAIL; + goto event_unregister; + } + + err = val_sdei_event_status(event_num, &event_status); + if (err) { + status = SDEI_TEST_ERROR; + goto event_unregister; + } + + if (!(event_status & EVENT_ENABLED)) { + status = SDEI_TEST_FAIL; + goto event_unregister; + } + +event_unregister: + err = val_sdei_event_unregister(event_num); + if (err) + status = SDEI_TEST_ERROR; +return_status: + val_test_pe_set_status(val_pe_get_index(), status); + return status; +} + +static void test_entry(void) +{ + uint32_t ret; + + ret = payload((void*)SDEI_EVENT_TYPE_SHARED); + if (ret & SDEI_TEST_FAIL) + return; + + /* Invalid event number enable testcase */ + ret = val_sdei_event_enable(SDEI_UNKNOWN_EVENT); + if (ret != SDEI_STATUS_INVALID) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + val_pe_execute_on_all(payload, SDEI_EVENT_TYPE_PRIVATE); +} + +SDEI_SET_TEST_DEPS(test_005_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_005, TEST_005_ID, TEST_DESC, test_005_deps, test_entry, TRUE); diff --git a/sdei/test_pool/test_006.c b/sdei/test_pool/test_006.c new file mode 100644 index 0000000..29368de --- /dev/null +++ b/sdei/test_pool/test_006.c @@ -0,0 +1,101 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI event disable test " + +#define SDEI_UNKNOWN_EVENT 0x10000 +#define ENABLED 0x2 + +/* This function verifies the shared and private events disable functionality. + * it also checks event disable error checks. + */ +static uint32_t payload(void *data) +{ + uint64_t type = (uint64_t)data; + uint32_t event_num, status = SDEI_TEST_PASS; + int32_t err; + uint64_t event_status; + + event_num = val_event_get(type, SDEI_EVENT_PRIORITY_ANY); + if (!event_num) { + status = SDEI_TEST_SKIP; + goto return_status; + } + + /*Try to to disable unregistered event */ + err = val_sdei_event_disable(event_num); + if (err != SDEI_STATUS_DENIED) { + status = SDEI_TEST_FAIL; + goto return_status; + } + + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + status = SDEI_TEST_FAIL; + goto return_status; + } + + err = val_sdei_event_disable(event_num); + if (err) { + status = SDEI_TEST_FAIL; + goto event_unregister; + } + + err = val_sdei_event_status(event_num, &event_status); + if (err) { + status = SDEI_TEST_ERROR; + goto event_unregister; + } + + if (event_status & ENABLED) { + status = SDEI_TEST_FAIL; + goto event_unregister; + } + +event_unregister: + err = val_sdei_event_unregister(event_num); + if (err) + status = SDEI_TEST_ERROR; + +return_status: + val_test_pe_set_status(val_pe_get_index(), status); + return status; +} + +static void test_entry(void) +{ + uint32_t ret; + + ret = payload((void*)SDEI_EVENT_TYPE_SHARED); + if (ret & SDEI_TEST_FAIL) + return; + + /* Invalid event number enable testcase */ + ret = val_sdei_event_enable(SDEI_UNKNOWN_EVENT); + if (ret != SDEI_STATUS_INVALID) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + val_pe_execute_on_all(payload, SDEI_EVENT_TYPE_PRIVATE); +} + +SDEI_SET_TEST_DEPS(test_006_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_006, TEST_006_ID, TEST_DESC, test_006_deps, test_entry, TRUE); diff --git a/sdei/test_pool/test_007.c b/sdei/test_pool/test_007.c new file mode 100644 index 0000000..2df7cfe --- /dev/null +++ b/sdei/test_pool/test_007.c @@ -0,0 +1,96 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI event un-register test " + +#define SDEI_UNKNOWN_EVENT 0x10000 +#define REGISTERED 0x1 + +/* This function verifies the shared and private events un-register. + * it also checks event un-register error checks. + */ +static uint32_t payload(void *data) +{ + uint64_t type = (uint64_t)data; + uint32_t event_num; + int32_t err, status = SDEI_TEST_PASS; + uint64_t event_status; + + event_num = val_event_get(type, SDEI_EVENT_PRIORITY_ANY); + if (!event_num) { + status = SDEI_TEST_SKIP; + goto return_status; + } + + err = val_sdei_event_unregister(event_num); + if (err != SDEI_STATUS_DENIED) { + status = SDEI_TEST_FAIL; + goto return_status; + } + + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + status = SDEI_TEST_FAIL; + goto return_status; + } + + err = val_sdei_event_unregister(event_num); + if (err) { + status = SDEI_TEST_FAIL; + goto return_status; + } + + err = val_sdei_event_status(event_num, &event_status); + if (err) { + status = SDEI_TEST_ERROR; + goto return_status; + } + + if ((event_status & REGISTERED)) { + status = SDEI_TEST_FAIL; + goto return_status; + } + +return_status: + val_test_pe_set_status(val_pe_get_index(), status); + return status; +} + +static void test_entry(void) +{ + uint32_t ret; + + ret = payload((void*)SDEI_EVENT_TYPE_SHARED); + + if (ret & SDEI_TEST_FAIL) + return; + + ret = val_sdei_event_unregister(SDEI_UNKNOWN_EVENT); + if (ret != SDEI_STATUS_INVALID) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + val_pe_execute_on_all(payload, SDEI_EVENT_TYPE_PRIVATE); +} + + +SDEI_SET_TEST_DEPS(test_007_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_007, TEST_007_ID, TEST_DESC, test_007_deps, test_entry, TRUE); diff --git a/sdei/test_pool/test_008.c b/sdei/test_pool/test_008.c new file mode 100644 index 0000000..6c467fe --- /dev/null +++ b/sdei/test_pool/test_008.c @@ -0,0 +1,34 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include + +#define TEST_DESC "Verify client execute in AArch64 State " + +static void payload(void) +{ + val_print(ACS_LOG_ERR, "\n Not implemented "); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_SKIP); +} + +static void test_entry(void) +{ + payload(); +} + +SDEI_SET_TEST_DEPS(test_008_deps, TEST_NONE_ID); +SDEI_PUBLISH_TEST(test_008, TEST_008_ID, TEST_DESC, test_008_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_009.c b/sdei/test_pool/test_009.c new file mode 100644 index 0000000..ad46022 --- /dev/null +++ b/sdei/test_pool/test_009.c @@ -0,0 +1,170 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI_EVENT_ROUTING_SET call " +#define SDEI_UNKNOWN_EVENT 0x10000 +#define INVALID_AFFINITY 0xFFFFFFFF + +static void test_entry(void) +{ + int32_t err, evt_routing_err; + int32_t cpu_id = 2; + uint32_t event_num; + + event_num = val_event_get(SDEI_EVENT_TYPE_SHARED, SDEI_EVENT_PRIORITY_ANY); + + /* Routing Mode - RM_ANY testcase */ + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + evt_routing_err = val_sdei_event_routing_set(event_num, FALSE, 0); + if (evt_routing_err) { + val_print(ACS_LOG_ERR, "\n SDEI event routing set failed with err %x", + evt_routing_err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + err = val_sdei_event_unregister(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed with err %x", + event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + + event_num = val_event_get(SDEI_EVENT_TYPE_SHARED, SDEI_EVENT_PRIORITY_ANY); + evt_routing_err = val_sdei_event_routing_set(event_num, FALSE, 0); + if (evt_routing_err != SDEI_STATUS_DENIED) { + val_print(ACS_LOG_ERR, "\n SDEI event routing set failed with err %x", + evt_routing_err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* Routing Mode - RM_PE testcase */ + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + else { + evt_routing_err = val_sdei_event_routing_set(event_num, TRUE, cpu_id); + if (evt_routing_err) { + val_print(ACS_LOG_ERR, "\n SDEI event routing set failed with err %x", + evt_routing_err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + err = val_sdei_event_unregister(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed with err %x", + event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + + /* INVALID Parameters if Invalid Affinity */ + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + evt_routing_err = val_sdei_event_routing_set(event_num, TRUE, INVALID_AFFINITY); + if (evt_routing_err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n SDEI event routing set failed with err %x", + evt_routing_err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + err = val_sdei_event_unregister(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed with err %x", + event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + + /* INVALID Parameters if Invalid Event Number */ + event_num = SDEI_UNKNOWN_EVENT; + evt_routing_err = val_sdei_event_routing_set(event_num, FALSE, 0); + + if (evt_routing_err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n SDEI event routing set failed with err %x", + evt_routing_err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* INVALID Parameters if Not Shared Event */ + event_num = val_event_get(SDEI_EVENT_TYPE_PRIVATE, SDEI_EVENT_PRIORITY_ANY); + if (event_num) { + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + evt_routing_err = val_sdei_event_routing_set(event_num, FALSE, 0); + if (evt_routing_err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n SDEI event routing set failed with err %x", + evt_routing_err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + err = val_sdei_event_unregister(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed with err %x", + event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + } else + val_print(ACS_LOG_TEST, "\n SDEI private event not found"); + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + return; + +event_unregister: + err = val_sdei_event_unregister(event_num); + if (err) { + val_print(ACS_LOG_WARN, "\n SDEI event %d unregister failed with err %x", + event_num, err); + } +} + +SDEI_SET_TEST_DEPS(test_009_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_009, TEST_009_ID, TEST_DESC, test_009_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_010.c b/sdei/test_pool/test_010.c new file mode 100644 index 0000000..1880307 --- /dev/null +++ b/sdei/test_pool/test_010.c @@ -0,0 +1,85 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI interrupt release test for SPI,PPI " + +static void test_entry(void) +{ + uint32_t event_num; + int32_t err; + + /* Interrupt release test for SPI */ + err = val_gic_disable_interrupt(SPI_INTR_NUM); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %d disable failed", SPI_INTR_NUM); + return; + } + err = val_sdei_interrupt_bind(SPI_INTR_NUM, &event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI interrupt number %d bind failed with err %d", + SPI_INTR_NUM, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + err = val_sdei_interrupt_release(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI event number %d release failed with err %d", + event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + + /* Interrupt relase test for PPI */ + err = val_gic_disable_interrupt(PPI_INTR_NUM); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %d disable failed", PPI_INTR_NUM); + return; + } + err = val_sdei_interrupt_bind(PPI_INTR_NUM, &event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n PPI interrupt number %d bind failed with err %d", + PPI_INTR_NUM, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + err = val_sdei_interrupt_release(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n PPI event number %d release failed with err %d", + event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + + /* Interrupt Release test for unbounded event */ + err = val_sdei_interrupt_release(event_num); + if (err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n Interrupt release failed for unbounded event %d" + "with err %d", event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); +} + +SDEI_SET_TEST_DEPS(test_010_deps, TEST_001_ID); +SDEI_PUBLISH_TEST(test_010, TEST_010_ID, TEST_DESC, test_010_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_011.c b/sdei/test_pool/test_011.c new file mode 100644 index 0000000..3198757 --- /dev/null +++ b/sdei/test_pool/test_011.c @@ -0,0 +1,111 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI event status test " + +#define SDEI_UNKNOWN_EVENT 0x10000 + +static void event_handler(void) +{ + return; +} + +static void test_entry(void) +{ + int32_t err; + uint64_t result; + uint32_t event_num; + + event_num = val_event_get(SDEI_EVENT_TYPE_SHARED, SDEI_EVENT_PRIORITY_ANY); + + /* Verify the event status in event un-registered state */ + err = val_sdei_event_status(event_num, &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + if (result == 0) { + val_print(ACS_LOG_INFO, "\n SDEI event %d unregistered, disabled," + " event handler not running", event_num); + } + else { + val_print(ACS_LOG_ERR, "\n SDEI event status test failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* Verify the event status in event register and enable state */ + err = val_sdei_event_register(event_num, (uint64_t)event_handler, NULL, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + else { + err = val_sdei_event_enable(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + err = val_sdei_event_status(event_num, &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + if (!(result & (EVENT_STATUS_REGISTER_BIT | EVENT_STATUS_ENABLE_BIT))) { + val_print(ACS_LOG_ERR, "\n SDEI event status test failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + err = val_sdei_event_unregister(event_num); + if (err) { + val_print(ACS_LOG_WARN, "\n SDEI event %d unregister failed with err %x", + event_num, err); + } + } + + /* Verify the event status for unknown event */ + event_num = SDEI_UNKNOWN_EVENT; + err = val_sdei_event_status(event_num, &result); + if (err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n SDEI event status test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + return; + +event_unregister: + err = val_sdei_event_unregister(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + event_num, err); + } +} + +SDEI_SET_TEST_DEPS(test_011_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_011, TEST_011_ID, TEST_DESC, test_011_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_012.c b/sdei/test_pool/test_012.c new file mode 100644 index 0000000..38e30f3 --- /dev/null +++ b/sdei/test_pool/test_012.c @@ -0,0 +1,282 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI event get info test " + +#define SDEI_UNKNOWN_EVENT 0x10000 + +static void payload(void) +{ + int32_t err, cpu_id =2; + uint64_t result; + struct sdei_event event; + + /* Verifying Event Get info for Private event */ + event.event_num = val_event_get(SDEI_EVENT_TYPE_PRIVATE, SDEI_EVENT_PRIORITY_ANY); + if (event.event_num) { + event.is_bound_irq = FALSE; + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_TYPE, + &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + else if (result == SDEI_EVENT_TYPE_PRIVATE) { + val_print(ACS_LOG_INFO, "\n SDEI event %d type is private", event.event_num); + } + else { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* Testing software signal feature using Event Get info*/ + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_SIGNALED, + &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + else if (result) { + val_print(ACS_LOG_INFO, "\n SDEI event %d cannot be software signalled", + event.event_num); + } + else { + val_print(ACS_LOG_INFO, "\n SDEI event %d can be software signalled", + event.event_num); + } + + /* Testing event priority feature using Event Get info*/ + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_PRIORITY, + &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + else if (result) { + val_print(ACS_LOG_INFO, "\n SDEI event %d is critical event", event.event_num); + } + else { + val_print(ACS_LOG_INFO, "\n SDEI event %d is normal event", event.event_num); + } + + /* Testing event routing feature using Event Get info*/ + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_ROUTING_MODE, + &result); + if (err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* Testing event routing affinity feature using Event Get info*/ + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_ROUTING_AFF, + &result); + if (err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } else + val_print(ACS_LOG_TEST, "\n SDEI private event not found"); + + /* Verifying Event Get info for Shared event */ + event.event_num = val_event_get(SDEI_EVENT_TYPE_SHARED, SDEI_EVENT_PRIORITY_ANY); + event.is_bound_irq = FALSE; + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + err = val_sdei_event_routing_set(event.event_num, TRUE, cpu_id); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event routing set failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Testing event type feature using Event Get info*/ + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_TYPE, + &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + else if (result == SDEI_EVENT_TYPE_SHARED) { + val_print(ACS_LOG_INFO, "\n SDEI event %d type is shared", event.event_num); + } + else { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* Testing event routing mode feature using Event Get info*/ + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_ROUTING_MODE, + &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + else if (result == SDEI_EVENT_REGISTER_RM_PE) { + val_print(ACS_LOG_INFO, "\n SDEI event %d routing mode is RM_PE", event.event_num); + } + else { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Testing event routing affinity feature using Event Get info*/ + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_ROUTING_AFF, + &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + else { + val_print(ACS_LOG_INFO, "\n SDEI event %d affinity is %llx", + event.event_num ,result); + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_WARN, "\n SDEI event %d unregister failed with err %x", + event.event_num, err); + } + } + + event.event_num = val_event_get(SDEI_EVENT_TYPE_SHARED, SDEI_EVENT_PRIORITY_ANY); + /* Testing DENIED error code for Event Get info*/ + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_ROUTING_MODE, + &result); + if (err != SDEI_STATUS_DENIED) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_ROUTING_AFF, + &result); + if (err != SDEI_STATUS_DENIED) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + event.event_num = 0; + event.is_bound_irq = FALSE; + /* Testing software signal feature using Event Get info for event number zero(0) */ + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_SIGNALED, + &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + else if (result == 0) { + val_print(ACS_LOG_INFO, "\n SDEI event %d can be software signalled", + event.event_num); + } + else { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + err = val_gic_disable_interrupt(SPI_INTR_NUM); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %d disable failed", SPI_INTR_NUM); + return; + } + err = val_sdei_interrupt_bind(SPI_INTR_NUM, &event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI interrupt number %d bind failed with err %d", + SPI_INTR_NUM, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + event.is_bound_irq = TRUE; + /* Testing EV_PRIORITY for binded interrupt using Get info */ + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_PRIORITY, + &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_interrupt_release; + } + else if (result == 0) { + val_print(ACS_LOG_INFO, "\n SDEI event %d is normal priority event", + event.event_num); + err = val_sdei_interrupt_release(event.event_num); + if (err) { + val_print(ACS_LOG_WARN, "\n Event number %d intrrupt release failed with err %d", + event.event_num, err); + } + } + else { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_interrupt_release; + } + + /* Verifying SDEI GET INFO for invalid event number */ + event.event_num = SDEI_UNKNOWN_EVENT; + err = val_sdei_event_get_info(event.event_num, SDEI_EVENT_INFO_EV_ROUTING_AFF, + &result); + if (err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n SDEI event get info failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + return; + +event_unregister: + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed with err %x", + event.event_num, err); + } +event_interrupt_release: + if (event.is_bound_irq) { + err = val_sdei_interrupt_release(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d intrrupt release failed with err %d", + event.event_num, err); + } + } +} + +static void test_entry(void) +{ + payload(); +} + +SDEI_SET_TEST_DEPS(test_012_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_012, TEST_012_ID, TEST_DESC, test_012_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_013.c b/sdei/test_pool/test_013.c new file mode 100644 index 0000000..03339e2 --- /dev/null +++ b/sdei/test_pool/test_013.c @@ -0,0 +1,77 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI private reset test " + +#define REGISTERED 0x1 + +/* Verifying Privet reset on each PE */ +static uint32_t payload(void *data) +{ + uint32_t event_num, status = SDEI_TEST_PASS; + int32_t err; + uint64_t event_status = 0; + + event_num = val_event_get(SDEI_EVENT_TYPE_PRIVATE, SDEI_EVENT_PRIORITY_ANY); + if (!event_num) { + status = SDEI_TEST_SKIP; + goto set_status; + } + + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + status = SDEI_TEST_SKIP; + goto set_status; + } + + err = val_sdei_private_reset(NULL); + if (err) { + status = SDEI_TEST_FAIL; + goto event_unregister; + } + + err = val_sdei_event_status(event_num, &event_status); + if (err) { + status = SDEI_TEST_ERROR; + goto event_unregister; + } + + if (event_status & REGISTERED) { + status = SDEI_TEST_FAIL; + goto event_unregister; + } else + goto set_status; + +event_unregister: + err = val_sdei_event_unregister(event_num); + if (err) + status = SDEI_TEST_ERROR; +set_status: + val_test_pe_set_status(val_pe_get_index(), status); + return status; +} + +static void test_entry(void) +{ + val_pe_execute_on_all(payload, 0); +} + +SDEI_SET_TEST_DEPS(test_013_deps, TEST_NONE_ID); +SDEI_PUBLISH_TEST(test_013, TEST_013_ID, TEST_DESC, test_013_deps, test_entry, TRUE); diff --git a/sdei/test_pool/test_014.c b/sdei/test_pool/test_014.c new file mode 100644 index 0000000..e70627d --- /dev/null +++ b/sdei/test_pool/test_014.c @@ -0,0 +1,68 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI SHARED RESET test " + +static void test_entry(void) +{ + int32_t err; + uint64_t result; + struct sdei_event event; + + event.event_num = val_event_get(SDEI_EVENT_TYPE_SHARED, SDEI_EVENT_PRIORITY_ANY); + event.is_bound_irq = FALSE; + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + err = val_sdei_shared_reset(); + if (err) { + val_print(ACS_LOG_ERR, "\n Failed SDEI shared reset: %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + err = val_sdei_event_status(event.event_num, &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + if (result & EVENT_STATUS_REGISTER_BIT) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + return; + +event_unregister: + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_WARN, "\n SDEI event %d unregister fail with err %x", + event.event_num, err); + } +} + +SDEI_SET_TEST_DEPS(test_014_deps, TEST_001_ID); +SDEI_PUBLISH_TEST(test_014, TEST_014_ID, TEST_DESC, test_014_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_015.c b/sdei/test_pool/test_015.c new file mode 100644 index 0000000..04a9db5 --- /dev/null +++ b/sdei/test_pool/test_015.c @@ -0,0 +1,61 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI_PE_MASK Call " + +#define ALREADY_MASKED 0 +#define MASKED 1 + +/* Verifying PE_MASK call on each PE */ +static void payload(void *data) +{ + int32_t err; + uint32_t status = SDEI_TEST_PASS; + uint64_t result = 0; + + err = val_sdei_unmask(); + if (err) { + status = SDEI_TEST_SKIP; + goto set_status; + } + + err = val_sdei_mask(&result); + if (err || (result != MASKED)) { + status = SDEI_TEST_FAIL; + goto set_status; + } + + err = val_sdei_mask(&result); + if (err || (result != ALREADY_MASKED)) { + status = SDEI_TEST_FAIL; + goto set_status; + } + +set_status: + val_test_pe_set_status(val_pe_get_index(), status); +} + +static void test_entry(void) +{ + val_pe_execute_on_all(payload, 0); +} + +SDEI_SET_TEST_DEPS(test_015_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_015, TEST_015_ID, TEST_DESC, test_015_deps, test_entry, TRUE); diff --git a/sdei/test_pool/test_016.c b/sdei/test_pool/test_016.c new file mode 100644 index 0000000..ade6c2e --- /dev/null +++ b/sdei/test_pool/test_016.c @@ -0,0 +1,42 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI_PE_UNMASK Call " + +static void payload(void *data) +{ + int32_t err; + + err = val_sdei_unmask(); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); +} + +static void test_entry(void) +{ + val_pe_execute_on_all(payload, 0); +} + +SDEI_SET_TEST_DEPS(test_016_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_016, TEST_016_ID, TEST_DESC, test_016_deps, test_entry, TRUE); diff --git a/sdei/test_pool/test_017.c b/sdei/test_pool/test_017.c new file mode 100644 index 0000000..4c52455 --- /dev/null +++ b/sdei/test_pool/test_017.c @@ -0,0 +1,65 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI_FEATURES Call " +#define VALID_FEATURE 0 +#define INVALID_FEATURE 0x10 + +static void payload(void) +{ + uint64_t num_slots, shared_slots, private_slots; + int32_t err; + + /* Check SDEI_FEATURES valid call */ + err = val_sdei_features(VALID_FEATURE, &num_slots); + + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI_FEATURES failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + private_slots = __EXTRACT_BITS(num_slots, 0, 16); + shared_slots = __EXTRACT_BITS(num_slots, 16, 16); + + if (__EXTRACT_BITS(num_slots, 32, 32) || (private_slots < 2) || (shared_slots < 2)) { + val_print(ACS_LOG_ERR, "\n SDEI_FEATURES expected value mismatch"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + + /* Check Invalid Parameters call */ + err = val_sdei_features(INVALID_FEATURE, &num_slots); + if (err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n SDEI_FEATURES failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); +} + +static void test_entry(void) +{ + payload(); +} + +SDEI_SET_TEST_DEPS(test_017_deps, TEST_NONE_ID); +SDEI_PUBLISH_TEST(test_017, TEST_017_ID, TEST_DESC, test_017_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_018.c b/sdei/test_pool/test_018.c new file mode 100644 index 0000000..86194fe --- /dev/null +++ b/sdei/test_pool/test_018.c @@ -0,0 +1,62 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI_VERSION Call " + +static void test_entry(void) +{ + uint64_t version, major_rev, minor_rev; + int32_t err; + + err = val_sdei_get_version(&version); + + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI_VERSION failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + major_rev = __EXTRACT_BITS(version, 48, 15); + minor_rev = __EXTRACT_BITS(version, 32, 16); + val_print(ACS_LOG_INFO, "\n SDEI minor revision = %llx", major_rev); + val_print(ACS_LOG_INFO, "\n SDEI major revision = %llx", minor_rev); + + if (major_rev != 1) { + val_print(ACS_LOG_ERR, "\n SDEI_VERSION major revision value mismatch" + " expected = %d: found = %llx", 1, major_rev); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + if (minor_rev != 0) { + val_print(ACS_LOG_ERR, "\n SDEI_VERSION minor revision value mismatch" + "expected = %d: found = %llx", 0, minor_rev); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + if (__EXTRACT_BITS(version, 63, 1)) { /* Bit[63] should be 0 */ + val_print(ACS_LOG_ERR, "\n SDEI_VERSION expected value mismatch"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); +} + +SDEI_SET_TEST_DEPS(test_018_deps, TEST_NONE_ID); +SDEI_PUBLISH_TEST(test_018, TEST_018_ID, TEST_DESC, test_018_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_019.c b/sdei/test_pool/test_019.c new file mode 100644 index 0000000..e9ef898 --- /dev/null +++ b/sdei/test_pool/test_019.c @@ -0,0 +1,44 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify ERROR CODE-NOT_SUPPORTED " + +static void test_entry(void) +{ + int32_t err; + uint64_t version; + + err = val_sdei_get_version(&version); + if (!err) { + val_print(ACS_LOG_WARN, "\n SDEI dispatcher present, skipping test "); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_SKIP); + return; + } + + if (err == SDEI_STATUS_NOT_SUPPORTED) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + return; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); +} + +SDEI_SET_TEST_DEPS(test_019_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_019, TEST_019_ID, TEST_DESC, test_019_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_020.c b/sdei/test_pool/test_020.c new file mode 100644 index 0000000..6dff38a --- /dev/null +++ b/sdei/test_pool/test_020.c @@ -0,0 +1,44 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify ERROR CODE-INVALID_PARAMETERS " +#define SDEI_UNKNOWN_EVENT 0x10000 + +static void test_entry(void) { + + struct sdei_event event; + int32_t err; + + /* INVALID_PARAMETERS Testcase */ + event.event_num = SDEI_UNKNOWN_EVENT; + event.is_bound_irq = FALSE; + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n Invalid parameters check failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + return; +} + +SDEI_SET_TEST_DEPS(test_020_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_020, TEST_020_ID, TEST_DESC, test_020_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_021.c b/sdei/test_pool/test_021.c new file mode 100644 index 0000000..a95a8b2 --- /dev/null +++ b/sdei/test_pool/test_021.c @@ -0,0 +1,66 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify ERROR CODE-DENIED " + +static void test_entry(void) { + + struct sdei_event event; + int32_t err; + + event.event_num = val_event_get(SDEI_EVENT_TYPE_SHARED, SDEI_EVENT_PRIORITY_ANY); + event.is_bound_irq = FALSE; + + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } else { + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err != SDEI_STATUS_DENIED) { + val_print(ACS_LOG_ERR, "\n ERROR CODE-DENIED check failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_WARN, "\n SDEI event %d unregister failed with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + return; + +event_unregister: + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed with err %x", + event.event_num, err); + } +} + +SDEI_SET_TEST_DEPS(test_021_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_021, TEST_021_ID, TEST_DESC, test_021_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_022.c b/sdei/test_pool/test_022.c new file mode 100644 index 0000000..4c7ee75 --- /dev/null +++ b/sdei/test_pool/test_022.c @@ -0,0 +1,166 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify ERROR-CODE PENDING " + +static int32_t g_wd_num; +static uint64_t g_int_id = 0; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static struct sdei_event g_event; + +static void event_handler(void) +{ + int32_t err; + + val_print(ACS_LOG_DEBUG, "\n Received WD0 event"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + /* Verifying Error-code pending */ + err = val_sdei_event_unregister(g_event.event_num); + if (err != SDEI_STATUS_PENDING) { + val_print(ACS_LOG_ERR, "\n ERROR CODE-PENDING check failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + } else { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + } + + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + uint64_t res = 0; + int32_t err; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + g_event.is_bound_irq = TRUE; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + g_int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", g_int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(g_int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", g_int_id); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + /* Binding Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(g_int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + g_int_id, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + + err = val_sdei_event_register(g_event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + g_event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto interrupt_release; + } + + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Generating Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (g_handler_flag && timeout--); + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(g_event.event_num, &res); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + g_event.event_num, err); + if (!(res & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if ((res & EVENT_STATUS_REGISTER_BIT)) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_ERROR); + goto event_unregister; + } + else { + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %d", + g_event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_ERROR); + } + goto unmap_va; + } + +event_unregister: + err = val_sdei_event_unregister(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + g_event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + g_event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); +} + +SDEI_SET_TEST_DEPS(test_022_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_022, TEST_022_ID, TEST_DESC, test_022_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_023.c b/sdei/test_pool/test_023.c new file mode 100644 index 0000000..12e4635 --- /dev/null +++ b/sdei/test_pool/test_023.c @@ -0,0 +1,83 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify ERROR CODE-OUT_OF_RESOURCE " +#define VALID_FEATURE 0 + +static void test_entry(void) +{ + int32_t err; + uint64_t num_slots; + uint32_t i, shared_slots, intr_num = SPI_INTR_NUM; + uint32_t event_num[100]; + + err = val_sdei_features(VALID_FEATURE, &num_slots); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI_FEATURES failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + shared_slots = __EXTRACT_BITS(num_slots, 16, 16); + + /* Bind the interrupts for available shared slots */ + for (i=0; i < shared_slots; i++) { + err = val_gic_disable_interrupt(intr_num+i); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %d disable failed\n", intr_num+i); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + err = val_sdei_interrupt_bind(intr_num+i, event_num+i); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt number %d bind failed with err %d", + intr_num+i, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + } + + /* Bind event when no bind slots are available */ + err = val_gic_disable_interrupt(intr_num+i); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %d disable failed", intr_num+i); + return; + } + err = val_sdei_interrupt_bind(intr_num+i, event_num+i); + if (err != SDEI_STATUS_OUT_OF_RESOURCE) { + val_print(ACS_LOG_ERR, "\n ERROR CODE-OUT_OF_RESOURCE check failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + } else { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + } + + /* Release all the bind interrupts */ + for (i=0; i +#include + +#define TEST_DESC "Verify SDEI_EVENT_COMPLETE Call " + +static int32_t g_wd_num; +static uint64_t g_int_id = 0; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; + +static void event_handler_shared(void) +{ + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + struct sdei_event event; + int32_t err; + uint64_t result; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + event.is_bound_irq = TRUE; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + g_int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", g_int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(g_int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", g_int_id); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(g_int_id, &event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + g_int_id, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler_shared, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto interrupt_release; + } + + err = val_sdei_event_enable(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Generating Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + /* Handler Running False Check */ + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event.event_num, &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + if (!(result & EVENT_STATUS_RUNNING_BIT)) + break; + }while (timeout--); + + if (result & EVENT_STATUS_RUNNING_BIT) { + val_print(ACS_LOG_ERR, "\n SDEI_EVENT_COMPLETE test failed, handler running"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + +event_unregister: + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); +} + +SDEI_SET_TEST_DEPS(test_024_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_024, TEST_024_ID, TEST_DESC, test_024_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_025.c b/sdei/test_pool/test_025.c new file mode 100644 index 0000000..eca38f4 --- /dev/null +++ b/sdei/test_pool/test_025.c @@ -0,0 +1,182 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI_EVENT_CONTEXT and X0,X1,X2 args " +#define INVALID_PARAM_ID 0x100 + +static int32_t g_wd_num; +static uint64_t g_int_id = 0; +static uint64_t g_x0_arg = 0; +static uint64_t g_x1_arg = 0; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; + +static void event_handler(uint64_t x0, uint64_t x1, uint64_t x2) +{ + int32_t err; + uint32_t query; + uint64_t *result = NULL; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + + /* Query on X0 value using event context api */ + query = 0; + err = val_sdei_event_context(query, result); + + /* Verifying x0 and x1 args after trigger the event */ + if (x0 != g_x0_arg) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + g_handler_flag = 0; + return; + } + if (x1 != g_x1_arg) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + g_handler_flag = 0; + return; + } + + /* Invalid parameter check */ + query = INVALID_PARAM_ID; + err = val_sdei_event_context(query, result); + if (err != SDEI_STATUS_INVALID) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + g_handler_flag = 0; + return; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t result = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + struct sdei_event event; + int32_t err; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + event.is_bound_irq = TRUE; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + g_int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", g_int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(g_int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", g_int_id); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(g_int_id, &event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI interrupt number %lld bind failed with err %d", + g_int_id, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + + g_x0_arg = event.event_num; + g_x1_arg = (uint64_t)event_handler; + val_pe_data_cache_clean_invalidate((uint64_t)&g_x0_arg); + val_pe_data_cache_clean_invalidate((uint64_t)&g_x1_arg); + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto interrupt_release; + } + + err = val_sdei_event_enable(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Generate Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + +event_unregister: + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event.event_num, &result); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + event.event_num, err); + if (!(result & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); +} + +SDEI_SET_TEST_DEPS(test_025_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_025, TEST_025_ID, TEST_DESC, test_025_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_026.c b/sdei/test_pool/test_026.c new file mode 100644 index 0000000..dd71dd6 --- /dev/null +++ b/sdei/test_pool/test_026.c @@ -0,0 +1,100 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify GHES fw discovery, events and notify " + +static void test_entry(void) +{ + uint32_t type; + uint64_t result = 0; + int32_t err; + int32_t num_events; + int32_t i; + event_info_t *event_info; + struct sdei_event event; + + /* GHES firmware discovery in ACPI */ + type = HEST_FOUND; + err = val_event_get_hest_info(type, &result); + if (result && !err) { + val_print(ACS_LOG_INFO, "\n Generic hardware error source found in ACPI"); + } else { + val_print(ACS_LOG_ERR, "\n Generic hardware error source not found "); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* GHES Notify structres check */ + type = NUM_GHES; + err = val_event_get_hest_info(type, &result); + if (result && !err) { + val_print(ACS_LOG_INFO, "\n Generic hardware error source notify structures found"); + } else { + val_print(ACS_LOG_ERR, "\n Generic hardware error source notify structures" + " not found"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* GHES SDEI Events check */ + type = NUM_EVENTS; + err = val_event_get_hest_info(type, &result); + if (result && !err) { + val_print(ACS_LOG_INFO, "\n Generic hardware error source SDEI events found: %lld", + result); + } else { + val_print(ACS_LOG_ERR, "\n Generic hardware error source SDEI events not found"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + type = HEST_NOTIFY; + num_events = result; + err = val_event_get_hest_info(type, &result); + if (!result && !err) { + val_print(ACS_LOG_ERR, "\n HEST SDEI events info not found"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + event_info = (event_info_t *)result; + event.is_bound_irq = FALSE; + for (i=0; i < num_events; i++) + { + event.event_num = event_info->number; + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_WARN, "\n SDEI event %d unregister failed with err %x", + event.event_num, err); + } + event_info++; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); +} + +SDEI_SET_TEST_DEPS(test_026_deps, TEST_NONE_ID); +SDEI_PUBLISH_TEST(test_026, TEST_026_ID, TEST_DESC, test_026_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_027.c b/sdei/test_pool/test_027.c new file mode 100644 index 0000000..bde678d --- /dev/null +++ b/sdei/test_pool/test_027.c @@ -0,0 +1,156 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI_EVENT_CONTEXT denied test " + +static int32_t g_wd_num; +static uint64_t g_int_id = 0; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; + +static void event_handler(void) +{ + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + uint64_t res = 0; + struct sdei_event event; + uint32_t query; + uint64_t *result = NULL; + int32_t err; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + event.is_bound_irq = TRUE; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + g_int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", g_int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(g_int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", g_int_id); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(g_int_id, &event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI interrupt number %lld bind failed with err %d", + g_int_id, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto interrupt_release; + } + + err = val_sdei_event_enable(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Generate Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (g_handler_flag && timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + /* Event Context Denied check */ + query = 2; + err = val_sdei_event_context(query, result); + if (err != SDEI_STATUS_DENIED) { + val_print(ACS_LOG_ERR, "\n val_api_event_context failed with err %x", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + +event_unregister: + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event.event_num, &res); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + event.event_num, err); + if (!(res & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); +} + +SDEI_SET_TEST_DEPS(test_027_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_027, TEST_027_ID, TEST_DESC, test_027_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_028.c b/sdei/test_pool/test_028.c new file mode 100644 index 0000000..2c7221a --- /dev/null +++ b/sdei/test_pool/test_028.c @@ -0,0 +1,155 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI_EVENT_COMPLETE_RESUME Call " + +static int32_t g_wd_num; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; + +/* Event handler resume function */ +static void event_handler_resume(void) +{ + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 100, timeout; + uint64_t wd_ctrl_base; + uint64_t g_int_id = 0; + struct sdei_event event; + int32_t err; + uint64_t result; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + event.is_bound_irq = TRUE; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + g_int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", g_int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(g_int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", g_int_id); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(g_int_id, &event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + g_int_id, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + + err = val_sdei_event_register(event.event_num, (uint64_t)asm_handler_resume, + (void *)event_handler_resume, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto interrupt_release; + } + + err = val_sdei_event_enable(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Generate Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + /* Handler Running False Check */ + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event.event_num, &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + if (!(result & EVENT_STATUS_RUNNING_BIT)) + break; + }while (timeout--); + + if (result & EVENT_STATUS_RUNNING_BIT) { + val_print(ACS_LOG_ERR, "\n SDEI_EVENT_COMPLETE test failed, handler running"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + +event_unregister: + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); +} + +SDEI_SET_TEST_DEPS(test_028_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_028, TEST_028_ID, TEST_DESC, test_028_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_029.c b/sdei/test_pool/test_029.c new file mode 100644 index 0000000..07f1a0d --- /dev/null +++ b/sdei/test_pool/test_029.c @@ -0,0 +1,194 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify clients intr cannot pre-empt handler " +#define RUNNING_BIT 0x4 + +static int32_t g_wd_num; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static volatile int32_t g_handler_counter = 0; +static volatile uint64_t g_status = SDEI_TEST_PASS; + +static int client_isr_handler(void) +{ + /* If interrupt is preempted event handler, assign status to TEST_FAIL */ + if (g_handler_flag) + g_status = SDEI_TEST_FAIL; + + g_handler_counter++; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_counter); + return 0; +} + +/* Generate Interrupt in Event handler to check the preemption */ +static void event_handler(void) +{ + uint32_t timeout = TIMEOUT_MEDIUM; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + /* Generate the SPI interrupt */ + val_gic_generate_interrupt(SPI_INTR_NUM1); + while (timeout--); + g_handler_flag = 0; + g_handler_counter++; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_counter); +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t int_id = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + uint64_t res = 0; + struct sdei_event event; + int32_t err; + + g_handler_flag = 1; + g_handler_counter = 0; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + event.is_bound_irq = TRUE; + event.type = SDEI_EVENT_TYPE_SHARED; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI interrupt number %lld bind failed with err %d", + int_id, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, SDEI_EVENT_REGISTER_RM_PE, + val_pe_get_mpid_index(0)); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto interrupt_release; + } + + err = val_sdei_event_enable(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Register SPI Interrupt line */ + err = val_gic_install_isr(SPI_INTR_NUM1, client_isr_handler); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt register %x failed with err %d", + SPI_INTR_NUM1, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Route SPI interrupt to PE zero */ + val_gic_route_interrupt_to_pe(SPI_INTR_NUM1, val_pe_get_mpid_index(0)); + + /* Generate Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (g_handler_flag && timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + val_pe_data_cache_invalidate((uint64_t)&g_handler_counter); + if (g_handler_flag == 0 && (g_handler_counter == 2)) + break; + } + if (g_handler_flag || (g_handler_counter != 2)) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto free_interrupt; + } + + if (g_status & SDEI_TEST_FAIL) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto free_interrupt; + } + + } while (0); + + if (!ns_wdg) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + +free_interrupt: + val_gic_end_of_interrupt(SPI_INTR_NUM1); + val_gic_free_interrupt(SPI_INTR_NUM1); +event_unregister: + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event.event_num, &res); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + event.event_num, err); + if (!(res & RUNNING_BIT)) + break; + } while (timeout--); + + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed with err %x", + event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); +} + +SDEI_SET_TEST_DEPS(test_029_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_029, TEST_029_ID, TEST_DESC, test_029_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_030.c b/sdei/test_pool/test_030.c new file mode 100644 index 0000000..37bfaa0 --- /dev/null +++ b/sdei/test_pool/test_030.c @@ -0,0 +1,191 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify events are higher priority than intr " +#define RUNNING_BIT 0x4 + +static int32_t g_wd_num; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static volatile int32_t g_handler_counter = 0; +static volatile uint64_t g_status = SDEI_TEST_FAIL; + +/* Generate Event in interrupt handler to check the preemption */ +static int client_isr_handler(void) +{ + uint64_t timer_expire_ticks = 1, timeout; + + timeout = TIMEOUT_MEDIUM; + /* Generate Watchdog event */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + while (timeout--); + g_handler_flag = 0; + g_handler_counter++; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_counter); + + return 0; +} + +static void event_handler(void) +{ + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + /* If event is preempted interrupt handler, assign status to TEST_PASS */ + if (g_handler_flag) + g_status = SDEI_TEST_PASS; + g_handler_counter++; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t int_id = 0; + uint64_t timeout; + uint64_t wd_ctrl_base; + uint64_t res = 0; + struct sdei_event event; + int32_t err; + + g_handler_flag = 1; + g_handler_counter = 0; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + event.is_bound_irq = TRUE; + event.type = SDEI_EVENT_TYPE_SHARED; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI interrupt number %lld bind failed with err %d", + int_id, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, SDEI_EVENT_REGISTER_RM_PE, + val_pe_get_mpid_index(0)); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto interrupt_release; + } + + err = val_sdei_event_enable(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + /* Register SPI Interrupt line */ + err = val_gic_install_isr(SPI_INTR_NUM1, client_isr_handler); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt register %x failed with err %d", + SPI_INTR_NUM1, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Route SPI interrupt to PE zero */ + val_gic_route_interrupt_to_pe(SPI_INTR_NUM1, val_pe_get_mpid_index(0)); + /* Generate SPI interrupt */ + val_gic_generate_interrupt(SPI_INTR_NUM1); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + val_pe_data_cache_invalidate((uint64_t)&g_handler_counter); + if ((g_handler_flag == 0) && (g_handler_counter == 2)) + break; + } + if (g_handler_flag || (g_handler_counter != 2)) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto free_interrupt; + } + + if (g_status & SDEI_TEST_FAIL) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto free_interrupt; + } + + } while (0); + + if (!ns_wdg) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + +free_interrupt: + val_gic_end_of_interrupt(SPI_INTR_NUM1); + val_gic_free_interrupt(SPI_INTR_NUM1); +event_unregister: + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event.event_num, &res); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x\n", + event.event_num, err); + if (!(res & RUNNING_BIT)) + break; + } while (timeout--); + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed with err %x", + event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); +} + +SDEI_SET_TEST_DEPS(test_030_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_030, TEST_030_ID, TEST_DESC, test_030_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_031.c b/sdei/test_pool/test_031.c new file mode 100644 index 0000000..4e8e793 --- /dev/null +++ b/sdei/test_pool/test_031.c @@ -0,0 +1,220 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify check always availability- VERSION " + +static int32_t g_wd_num; +static uint64_t g_test_status= SDEI_TEST_PASS; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static struct sdei_event g_event; + +/* Check the SDEI_VERSION API in below states + * 1. Handler-Unregistered State + * 2. Handler-registered State + * 3. Handler-Enabled State + * 4. Handler-Enabled & Running State + * 5. Handler-Unregister Pending State + */ +static void event_handler(void) +{ + uint64_t result; + int32_t err; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + + /* Check 4 - Handler-Enabled & Running State */ + err = val_sdei_get_version(&result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Enabled & Running check failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + } + + err = val_sdei_event_unregister(g_event.event_num); + if (err != SDEI_STATUS_PENDING) { + val_print(ACS_LOG_ERR, "\n Unregister-Pending check failed"); + g_test_status = SDEI_TEST_FAIL; + } + + /* Check 5 - Handler-Unregister Pending State */ + err = val_sdei_get_version(&result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Enabled & Running check failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + } + + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + int32_t err; + uint64_t result; + uint64_t int_id = 0; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + g_event.is_bound_irq = TRUE; + + do { + /*Array index starts from 0, so subtract 1 from count*/ + g_wd_num--; + + /* Skip secure Watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event.event_num); + + /* Check 1 - Handler-Unregistered State */ + err = val_sdei_get_version(&result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Unregistered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + + err = val_sdei_event_register(g_event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + g_event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + /* Check 2 - Handler-Registered State */ + err = val_sdei_get_version(&result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Registered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Check 3 - Handler-Enabled State */ + err = val_sdei_get_version(&result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Enabled state check failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Generate Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(g_event.event_num, &result); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + g_event.event_num, err); + if (!(result & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if ((result & EVENT_STATUS_REGISTER_BIT)) { + g_test_status = SDEI_TEST_ERROR; + goto event_unregister; + } + else { + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event num %d release failed : err %d", + g_event.event_num, err); + g_test_status = SDEI_TEST_ERROR; + } + goto unmap_va; + } + +event_unregister: + err = val_sdei_event_unregister(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed : err %x", + g_event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + g_event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); + val_test_pe_set_status(val_pe_get_index(), + ((g_test_status == SDEI_TEST_PASS) ? SDEI_TEST_PASS : SDEI_TEST_FAIL) + ); +} + +SDEI_SET_TEST_DEPS(test_031_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_031, TEST_031_ID, TEST_DESC, test_031_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_032.c b/sdei/test_pool/test_032.c new file mode 100644 index 0000000..d43a24a --- /dev/null +++ b/sdei/test_pool/test_032.c @@ -0,0 +1,252 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify check always availability-Event Status " + +static int32_t g_wd_num; +static uint64_t g_test_status= SDEI_TEST_PASS; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static struct sdei_event g_event; + +/* Check the SDEI_EVENT_STATUS API in below states + * 1. Handler-Unregistered State + * 2. Handler-registered State + * 3. Handler-Enabled State + * 4. Handler-Enabled & Running State + * 5. Handler-Unregister Pending State + */ +static void event_handler(void) +{ + uint64_t result; + int32_t err; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + + /* Check 4 - Handler-Enabled & Running State */ + err = val_sdei_event_status(g_event.event_num, &result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Enabled & Running check failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + } else { + if (!(result & EVENT_STATUS_RUNNING_BIT)) { + val_print(ACS_LOG_ERR, "\n SDEI_EVENT_STATUS running bit mismatch," + "found value = %llx", (result & EVENT_STATUS_RUNNING_BIT)); + g_test_status = SDEI_TEST_FAIL; + } + } + + err = val_sdei_event_unregister(g_event.event_num); + if (err != SDEI_STATUS_PENDING) { + val_print(ACS_LOG_ERR, "\n Unregister-Pending check failed"); + g_test_status = SDEI_TEST_FAIL; + } + + /* Check 5 - Handler-Unregister Pending State */ + err = val_sdei_event_status(g_event.event_num, &result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Enabled & Running check failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + } else { + if (!(result & EVENT_STATUS_RUNNING_BIT)) { + val_print(ACS_LOG_ERR, "\n SDEI_EVENT_STATUS running bit mismatch," + "found value = %llx", (result & EVENT_STATUS_RUNNING_BIT)); + g_test_status = SDEI_TEST_FAIL; + } + } + + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + int32_t err; + uint64_t result; + uint64_t int_id = 0; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + g_event.is_bound_irq = TRUE; + + do { + /*Array index starts from 0, so subtract 1 from count*/ + g_wd_num--; + + /* Skip secure Watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event.event_num); + + /* Check 1 - Handler-Unregistered State */ + err = val_sdei_event_status(g_event.event_num, &result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Unregistered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } else { + if (result & EVENT_STATUS_REGISTER_BIT) { + val_print(ACS_LOG_ERR, "\n SDEI_EVENT_STATUS register bit mismatch," + "found = %llx", (result & EVENT_STATUS_REGISTER_BIT)); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + } + + err = val_sdei_event_register(g_event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI evt %d register fail with err %x", + g_event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + /* Check 2 - Handler-Registered State */ + err = val_sdei_event_status(g_event.event_num, &result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Registered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } else { + if (!(result & EVENT_STATUS_REGISTER_BIT)) { + val_print(ACS_LOG_ERR, "\n SDEI_EVENT_STATUS register bit mismatch," + "found = %llx", (result & EVENT_STATUS_REGISTER_BIT)); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } + + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + /* Check 3 - Handler-Enabled State */ + err = val_sdei_event_status(g_event.event_num, &result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Enabled state check failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } else { + if (!(result & EVENT_STATUS_ENABLE_BIT)) { + val_print(ACS_LOG_ERR, "\n SDEI_EVENT_STATUS enable bit mismatch," + "found value = %llx\n", (result & EVENT_STATUS_ENABLE_BIT)); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } + + /* Generate Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(g_event.event_num, &result); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + g_event.event_num, err); + if (!(result & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if ((result & EVENT_STATUS_REGISTER_BIT)) { + g_test_status = SDEI_TEST_ERROR; + goto event_unregister; + } + else { + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event num %d release failed :err %d", + g_event.event_num, err); + g_test_status = SDEI_TEST_ERROR; + } + goto unmap_va; + } + +event_unregister: + err = val_sdei_event_unregister(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed :err %x", + g_event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + g_event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); + val_test_pe_set_status(val_pe_get_index(), + ((g_test_status == SDEI_TEST_PASS) ? SDEI_TEST_PASS : SDEI_TEST_FAIL) + ); +} + +SDEI_SET_TEST_DEPS(test_032_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_032, TEST_032_ID, TEST_DESC, test_032_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_033.c b/sdei/test_pool/test_033.c new file mode 100644 index 0000000..8090a79 --- /dev/null +++ b/sdei/test_pool/test_033.c @@ -0,0 +1,102 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify SDEI_EVENT_SIGNAL test " + +#define SDEI_UNKNOWN_EVENT 0x10000 + +static volatile int32_t g_handler_flag = 1; + +static void event_handler(void) +{ + g_handler_flag = 0; +} + +/* Registering event 0 on each PE and verifying sdei event signal to each PE */ +static void payload(void *ignore) +{ + uint64_t timeout; + uint64_t res = 0; + int32_t err; + void *entry_point; + struct sdei_event event; + + g_handler_flag = 1; + timeout = TIMEOUT_MEDIUM; + entry_point = &asm_event_handler; + event.is_bound_irq = FALSE; + event.event_num = 0; + + err = val_sdei_event_register(event.event_num, (uint64_t)entry_point, + (void *)event_handler, 0, 0); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + err = val_sdei_event_enable(event.event_num); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + err = val_sdei_event_signal(event.event_num, val_pe_get_mpid_index(val_pe_get_index())); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event signal failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + while (g_handler_flag && timeout--); + if (g_handler_flag) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event.event_num, &res); + if (!(res & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + +event_unregister: + err = val_sdei_event_unregister(event.event_num); +} + +static void test_entry(void) { + uint32_t event_num; + int32_t err; + + /* verifying sdei_event_signal for unknown event */ + event_num = SDEI_UNKNOWN_EVENT; + err = val_sdei_event_signal(event_num, val_pe_get_mpid_index(0)); + if (err != SDEI_STATUS_INVALID) { + val_print(ACS_LOG_ERR, "\n SDEI event signal failed with err %d", err); + val_test_set_status(val_pe_get_num(), SDEI_TEST_FAIL); + return; + } + + val_pe_execute_on_all((void*)payload, 0); +} + +SDEI_SET_TEST_DEPS(test_033_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_033, TEST_033_ID, TEST_DESC, test_033_deps, test_entry, TRUE); diff --git a/sdei/test_pool/test_034.c b/sdei/test_pool/test_034.c new file mode 100644 index 0000000..20df10c --- /dev/null +++ b/sdei/test_pool/test_034.c @@ -0,0 +1,225 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify always availability- SDEI_FEATURES " + +#define VALID_FEATURE 0 + +static int32_t g_wd_num; +static uint64_t g_test_status= SDEI_TEST_PASS; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static struct sdei_event g_event; + +/* Check the SDEI_FEATURES API in below states + * 1. Handler-Unregistered State + * 2. Handler-registered State + * 3. Handler-Enabled State + * 4. Handler-Enabled & Running State + * 5. Handler-Unregister Pending State + */ +static void event_handler(void) +{ + uint64_t num_slots; + int32_t err; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + + /* Check 4 - Handler-Enabled & Running State */ + err = val_sdei_features(VALID_FEATURE, &num_slots); + if (err) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + + err = val_sdei_event_unregister(g_event.event_num); + if (err != SDEI_STATUS_PENDING) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + + /* Check 5 - Handler-Unregister Pending State */ + err = val_sdei_features(VALID_FEATURE, &num_slots); + if (err) { + g_test_status = SDEI_TEST_FAIL; + } + + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + int32_t err; + uint64_t num_slots; + uint64_t result; + uint64_t int_id = 0; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + g_event.is_bound_irq = TRUE; + + do { + /*Array index starts from 0, so subtract 1 from count*/ + g_wd_num--; + + /* Skip secure Watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", + int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI Intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event.event_num); + + /* Check 1 - Handler-Unregistered State */ + err = val_sdei_features(VALID_FEATURE, &num_slots); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Unregistered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + + err = val_sdei_event_register(g_event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + g_event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + /* Check 2 - Handler-Registered State */ + err = val_sdei_features(VALID_FEATURE, &num_slots); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Registered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Check 3 - Handler-Enabled State */ + err = val_sdei_features(VALID_FEATURE, &num_slots); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Enabled state check failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Generate Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(g_event.event_num, &result); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + g_event.event_num, err); + if (!(result & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if ((result & EVENT_STATUS_REGISTER_BIT)) { + g_test_status = SDEI_TEST_ERROR; + goto event_unregister; + } + else { + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event num %d release failed : err %d", + g_event.event_num, err); + g_test_status = SDEI_TEST_ERROR; + } + goto unmap_va; + } + +event_unregister: + err = val_sdei_event_unregister(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed : err %x", + g_event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + g_event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); + val_test_pe_set_status(val_pe_get_index(), + ((g_test_status == SDEI_TEST_PASS) ? SDEI_TEST_PASS : SDEI_TEST_FAIL) + ); +} + +SDEI_SET_TEST_DEPS(test_034_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_034, TEST_034_ID, TEST_DESC, test_034_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_035.c b/sdei/test_pool/test_035.c new file mode 100644 index 0000000..77741c7 --- /dev/null +++ b/sdei/test_pool/test_035.c @@ -0,0 +1,268 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify always availability- SDEI_SHARED_RESET " + +static int32_t g_wd_num; +static uint64_t g_test_status= SDEI_TEST_PASS; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static struct sdei_event g_event; + +/* Check the SDEI_SHARED_RESET API in below states + * 1. Handler-Unregistered State + * 2. Handler-registered State + * 3. Handler-Enabled State + * 4. Handler-Enabled & Running State + * 5. Handler-Unregister Pending State + */ +static void event_handler(void) +{ + int32_t err; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + + /* Check 4 - Handler-Enabled & Running State */ + err = val_sdei_shared_reset(); + if (err != SDEI_STATUS_DENIED) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + + err = val_sdei_event_unregister(g_event.event_num); + if (err != SDEI_STATUS_PENDING) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + + /* Check 5 - Handler-Unregister Pending State */ + err = val_sdei_shared_reset(); + if (err != SDEI_STATUS_DENIED) { + g_test_status = SDEI_TEST_FAIL; + } + + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + int32_t err; + uint64_t result; + uint64_t int_id = 0; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + g_event.is_bound_irq = TRUE; + + do { + /*Array index starts from 0, so subtract 1 from count*/ + g_wd_num--; + + /* Skip secure Watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + /* Check 1 - Handler-Unregistered State */ + err = val_sdei_shared_reset(); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Unregistered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event.event_num); + + err = val_sdei_event_register(g_event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + g_event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + /* Check 2 - Handler-Registered State */ + err = val_sdei_shared_reset(); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Registered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + err = val_sdei_interrupt_bind(int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event.event_num); + + err = val_sdei_event_register(g_event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + g_event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Check 3 - Handler-Enabled State */ + err = val_sdei_shared_reset(); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Enabled state check failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + err = val_sdei_interrupt_bind(int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event.event_num); + + err = val_sdei_event_register(g_event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + g_event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Generate Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(g_event.event_num, &result); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + g_event.event_num, err); + if (!(result & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if ((result & EVENT_STATUS_REGISTER_BIT)) { + g_test_status = SDEI_TEST_ERROR; + goto event_unregister; + } else { + goto unmap_va; + } + +event_unregister: + err = val_sdei_event_unregister(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed : err %x", + g_event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + g_event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); + val_test_pe_set_status(val_pe_get_index(), + ((g_test_status == SDEI_TEST_PASS) ? SDEI_TEST_PASS : SDEI_TEST_FAIL) + ); +} + +SDEI_SET_TEST_DEPS(test_035_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_035, TEST_035_ID, TEST_DESC, test_035_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_036.c b/sdei/test_pool/test_036.c new file mode 100644 index 0000000..214911b --- /dev/null +++ b/sdei/test_pool/test_036.c @@ -0,0 +1,260 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify always availability- PE_MASK " + +static int32_t g_wd_num; +static uint64_t g_test_status= SDEI_TEST_PASS; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static struct sdei_event g_event; + +/* Check the SDEI_PE_MASK API in below states + * 1. Handler-Unregistered State + * 2. Handler-registered State + * 3. Handler-Enabled State + * 4. Handler-Enabled & Running State + * 5. Handler-Unregister Pending State + */ +static void event_handler(void) +{ + uint64_t result; + int32_t err; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + + /* Check 4 - Handler-Enabled & Running State */ + err = val_sdei_mask(&result); + if (err) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); + return; + } + + err = val_sdei_unmask(); + if (err) { + g_test_status = SDEI_TEST_FAIL; + return; + } + + err = val_sdei_event_unregister(g_event.event_num); + if (err != SDEI_STATUS_PENDING) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); + return; + } + + /* Check 5 - Handler-Unregister Pending State */ + err = val_sdei_mask(&result); + if (err) { + g_test_status = SDEI_TEST_FAIL; + } + + err = val_sdei_unmask(); + if (err) { + g_test_status = SDEI_TEST_FAIL; + return; + } + + g_handler_flag = 0; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); +} + +static void test_entry(void) +{ + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + int32_t err; + uint64_t result; + uint64_t int_id = 0; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + g_event.is_bound_irq = TRUE; + + do { + /*Array index starts from 0, so subtract 1 from count*/ + g_wd_num--; + + /* Skip secure Watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", + int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event.event_num); + + /* Check 1 - Handler-Unregistered State */ + err = val_sdei_mask(&result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Unregistered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + err = val_sdei_unmask(); + if (err) { + val_print(ACS_LOG_ERR, "\n Unmask failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + err = val_sdei_event_register(g_event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI evt %d register fail with err %x", + g_event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + /* Check 2 - Handler-Registered State */ + err = val_sdei_mask(&result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Registered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + err = val_sdei_unmask(); + if (err) { + val_print(ACS_LOG_ERR, "\n Unmask failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Check 3 - Handler-Enabled State */ + err = val_sdei_mask(&result); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Enabled state check failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + err = val_sdei_unmask(); + if (err) { + val_print(ACS_LOG_ERR, "\n Unmask failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + + /* Generate Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(g_event.event_num, &result); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + g_event.event_num, err); + if (!(result & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if ((result & EVENT_STATUS_REGISTER_BIT)) { + g_test_status = SDEI_TEST_ERROR; + goto event_unregister; + } + else { + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Evt num %d release failed : err %d", + g_event.event_num, err); + g_test_status = SDEI_TEST_ERROR; + } + goto unmap_va; + } + +event_unregister: + err = val_sdei_event_unregister(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI evt %d unregister failed : err %x", + g_event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + g_event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); + val_test_pe_set_status(val_pe_get_index(), + ((g_test_status == SDEI_TEST_PASS) ? SDEI_TEST_PASS : SDEI_TEST_FAIL) + ); +} + +SDEI_SET_TEST_DEPS(test_036_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_036, TEST_036_ID, TEST_DESC, test_036_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_037.c b/sdei/test_pool/test_037.c new file mode 100644 index 0000000..4a4daed --- /dev/null +++ b/sdei/test_pool/test_037.c @@ -0,0 +1,228 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify always availability- PE_UNMASK " + +static int32_t g_wd_num; +static uint64_t g_test_status= SDEI_TEST_PASS; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static struct sdei_event g_event; + +/* Check the SDEI_PE_UNMASK API in below states + * 1. Handler-Unregistered State + * 2. Handler-registered State + * 3. Handler-Enabled State + * 4. Handler-Enabled & Running State + * 5. Handler-Unregister Pending State + */ +static void event_handler(void) +{ + int32_t err; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + + /* Check 4 - Handler-Enabled & Running State */ + err = val_sdei_unmask(); + if (err) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); + return; + } + + err = val_sdei_event_unregister(g_event.event_num); + if (err != SDEI_STATUS_PENDING) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); + return; + } + + /* Check 5 - Handler-Unregister Pending State */ + err = val_sdei_unmask(); + if (err) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); + return; + } + + g_handler_flag = 0; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); +} + +static void test_entry(void) +{ + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + int32_t err; + uint64_t result; + uint64_t int_id = 0; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + g_event.is_bound_irq = TRUE; + + do { + /*Array index starts from 0, so subtract 1 from count*/ + g_wd_num--; + + /* Skip secure Watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event.event_num); + + /* Check 1 - Handler-Unregistered State */ + err = val_sdei_unmask(); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Unregistered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + err = val_sdei_event_register(g_event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI evt %d register fail with err %x", + g_event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + /* Check 2 - Handler-Registered State */ + err = val_sdei_unmask(); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Registered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Check 3 - Handler-Enabled State */ + err = val_sdei_unmask(); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Enabled state check failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Generate Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(g_event.event_num, &result); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + g_event.event_num, err); + if (!(result & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if ((result & EVENT_STATUS_REGISTER_BIT)) { + g_test_status = SDEI_TEST_ERROR; + goto event_unregister; + } + else { + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Evt num %d release failed : err %d", + g_event.event_num, err); + g_test_status = SDEI_TEST_ERROR; + } + goto unmap_va; + } + +event_unregister: + err = val_sdei_event_unregister(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI evt %d unregister failed : err %x", + g_event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + g_event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); + val_test_pe_set_status(val_pe_get_index(), + ((g_test_status == SDEI_TEST_PASS) ? SDEI_TEST_PASS : SDEI_TEST_FAIL) + ); +} + +SDEI_SET_TEST_DEPS(test_037_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_037, TEST_037_ID, TEST_DESC, test_037_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_038.c b/sdei/test_pool/test_038.c new file mode 100644 index 0000000..58877a6 --- /dev/null +++ b/sdei/test_pool/test_038.c @@ -0,0 +1,221 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify always availability- INTERRUPT_BIND " + +#define VALID_FEATURE 0 + +static int32_t g_wd_num; +static uint64_t g_test_status= SDEI_TEST_PASS; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static struct sdei_event g_event; +static uint32_t g_event_num; + +/* Check the SDEI_INTERRUPT_BIND API in below states + * 1. Handler-Unregistered State + * 2. Handler-registered State + * 3. Handler-Enabled State + * 4. Handler-Enabled & Running State + * 5. Handler-Unregister Pending State + */ +static void event_handler(void) +{ + int32_t err; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + + /* Check 4 - Handler-Enabled & Running State */ + err = val_sdei_interrupt_bind(SPI_INTR_NUM1, &g_event_num); + if (err) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + + err = val_sdei_event_unregister(g_event.event_num); + if (err != SDEI_STATUS_PENDING) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + + /* Check 5 - Handler-Unregister Pending State */ + err = val_sdei_interrupt_bind(SPI_INTR_NUM1, &g_event_num); + if (err) { + g_test_status = SDEI_TEST_FAIL; + } + + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + int32_t err; + uint64_t result; + uint64_t int_id = 0; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + g_event.is_bound_irq = TRUE; + + do { + /*Array index starts from 0, so subtract 1 from count*/ + g_wd_num--; + + /* Skip secure Watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + /* Check 1 - Handler-Unregistered State */ + err = val_sdei_interrupt_bind(int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event.event_num); + + err = val_sdei_event_register(g_event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + g_event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + /* Check 2 - Handler-Registered State */ + err = val_gic_disable_interrupt(SPI_INTR_NUM1); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %d disable failed\n", SPI_INTR_NUM1); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + err = val_sdei_interrupt_bind(SPI_INTR_NUM1, &g_event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %d bind failed with err %d", + SPI_INTR_NUM1, err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event_num); + + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Check 3 - Handler-Enabled State */ + err = val_sdei_interrupt_bind(SPI_INTR_NUM1, &g_event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %d bind failed with err %d", + SPI_INTR_NUM1, err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event_num); + + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(g_event.event_num, &result); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + g_event.event_num, err); + if (!(result & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if ((result & EVENT_STATUS_REGISTER_BIT)) { + g_test_status = SDEI_TEST_ERROR; + goto event_unregister; + } else { + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event num %d release failed : err %d", + g_event.event_num, err); + g_test_status = SDEI_TEST_ERROR; + } + goto unmap_va; + } + +event_unregister: + err = val_sdei_event_unregister(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed : err %x", + g_event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(g_event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event num %d release failed : err %d", + g_event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); + val_test_pe_set_status(val_pe_get_index(), + ((g_test_status == SDEI_TEST_PASS) ? SDEI_TEST_PASS : SDEI_TEST_FAIL) + ); +} + +SDEI_SET_TEST_DEPS(test_038_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_038, TEST_038_ID, TEST_DESC, test_038_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_039.c b/sdei/test_pool/test_039.c new file mode 100644 index 0000000..7991815 --- /dev/null +++ b/sdei/test_pool/test_039.c @@ -0,0 +1,224 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify always availability- SDEI_PRIVATE_RESET " + +#define PPI_NUM 31 + +static volatile int32_t g_handler_flag = 1; +static uint64_t g_test_status= SDEI_TEST_PASS; +static struct sdei_event g_event; + +/* Check the SDEI_PRIVATE_RESET API in below states + * 1. Handler-Unregistered State + * 2. Handler-registered State + * 3. Handler-Enabled State + * 4. Handler-Enabled & Running State + * 5. Handler-Unregister Pending State + */ +static void event_handler(void) +{ + uint32_t err; + uint32_t res = 0; + uint64_t current_el; + + err = val_pe_reg_read(CurrentEL, ¤t_el); + current_el = __EXTRACT_BITS(current_el, 2, 2); + + if (current_el == 1) + val_timer_set_phy_el1(0); + else if (current_el == 2) + val_timer_set_phy_el2(0); + + /* Check 4 - Handler-Enabled & Running State */ + err = val_sdei_private_reset(&res); + if (err != SDEI_STATUS_DENIED) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + + err = val_sdei_event_unregister(g_event.event_num); + if (err != SDEI_STATUS_PENDING) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + + /* Check 5 - Handler-Unregister Pending State */ + err = val_sdei_private_reset(&res); + if (err != SDEI_STATUS_DENIED) { + g_test_status = SDEI_TEST_FAIL; + } + + g_handler_flag = 0; +} + +static void payload(void *ignore) +{ + uint64_t timer_expire_ticks = 1; + uint64_t timeout; + uint64_t res = 0; + uint32_t err; + uint64_t current_el; + void *entry_point; + + g_handler_flag = 1; + g_test_status = SDEI_TEST_PASS; + timeout = WD_TIME_OUT; + entry_point = &asm_event_handler; + + /* Check 1 - Handler-Unregistered State */ + err = val_sdei_private_reset(&res); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + err = val_sdei_event_register(g_event.event_num, (uint64_t)entry_point, + (void *)event_handler, 0, 0); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* Check 2 - Handler-Registered State */ + err = val_sdei_private_reset(&res); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + err = val_sdei_event_register(g_event.event_num, (uint64_t)entry_point, + (void *)event_handler, 0, 0); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Check 3 - Handler-Enabled State */ + err = val_sdei_private_reset(&res); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + err = val_sdei_event_register(g_event.event_num, (uint64_t)entry_point, + (void *)event_handler, 0, 0); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + err = val_pe_reg_read(CurrentEL, ¤t_el); + current_el = __EXTRACT_BITS(current_el, 2, 2); + /* Generate the timer interrupt based on EL state */ + if (current_el == 1) + val_timer_set_phy_el1(timer_expire_ticks); + else if (current_el == 2) + val_timer_set_phy_el2(timer_expire_ticks); + + while (g_handler_flag && timeout--); + if (g_handler_flag) { + if (current_el == 1) + val_timer_set_phy_el1(0); + else if (current_el == 2) + val_timer_set_phy_el2(0); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + val_test_pe_set_status(val_pe_get_index(), + ((g_test_status == SDEI_TEST_PASS) ? SDEI_TEST_PASS : SDEI_TEST_FAIL)); + + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(g_event.event_num, &res); + if (!(res & EVENT_STATUS_RUNNING_BIT) && !(res & EVENT_STATUS_REGISTER_BIT)) + return; + } while (timeout--); + +event_unregister: + err = val_sdei_event_unregister(g_event.event_num); +} + +static void test_entry(void) { + int32_t err; + uint64_t g_int_id = 0; + uint64_t current_el; + + g_handler_flag = 1; + g_event.is_bound_irq = TRUE; + + /* Read current EL state */ + err = val_pe_reg_read(CurrentEL, ¤t_el); + current_el = __EXTRACT_BITS(current_el, 2, 2); + + /* Read the timer interrupt based on EL state */ + if (current_el == 1) + g_int_id = val_timer_get_info(TIMER_INFO_PHY_EL1_INTID, 0); + else if (current_el == 2) + g_int_id = val_timer_get_info(TIMER_INFO_PHY_EL2_INTID, 0); + + if (g_int_id > PPI_NUM) { + val_print(ACS_LOG_ERR, "\n Incorrect PPI value %lld", g_int_id); + return; + } + val_print(ACS_LOG_DEBUG, "\n timer interrupt id: %lld", g_int_id); + + err = val_gic_disable_interrupt(g_int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", g_int_id); + val_test_set_status(val_pe_get_num(), SDEI_TEST_FAIL); + return; + } + /* Bind the timer interrupt to event */ + err = val_sdei_interrupt_bind(g_int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + g_int_id, err); + val_test_set_status(val_pe_get_num(), SDEI_TEST_FAIL); + return; + } + + val_pe_data_cache_clean_invalidate((uint64_t)&g_event.event_num); + + val_pe_execute_on_all((void*)payload, 0); + + /* Release the timer interrupt */ + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event num %d release failed : err %d", + g_event.event_num, err); + } +} + +SDEI_SET_TEST_DEPS(test_039_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_039, TEST_039_ID, TEST_DESC, test_039_deps, test_entry, TRUE); diff --git a/sdei/test_pool/test_040.c b/sdei/test_pool/test_040.c new file mode 100644 index 0000000..718e75d --- /dev/null +++ b/sdei/test_pool/test_040.c @@ -0,0 +1,278 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify same priority events run in sequence " + +static int32_t g_wd_num; +static uint32_t g_index = 0; +static uint64_t *g_wd_va_addr = NULL; +static volatile uint64_t g_test_status= SDEI_TEST_PASS; +static volatile int32_t g_event_counter = 0; + +static void wd_event_handler(void) +{ + val_wd_set_ws0(g_wd_va_addr, g_wd_num, 0); + g_event_counter++; + val_pe_data_cache_clean_invalidate((uint64_t)&g_event_counter); +} + +static void second_event_handler(void) +{ + val_disable_second_interrupt(g_index); + g_event_counter++; + val_pe_data_cache_clean_invalidate((uint64_t)&g_event_counter); +} + +static uint64_t wd_event_register(struct sdei_event *wd_event) +{ + uint32_t ns_wdg = 0; + uint64_t wd_ctrl_base; + uint64_t int_id = 0; + void *entry_point; + int32_t err; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + entry_point = &asm_event_handler; + wd_event->is_bound_irq = TRUE; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + + /* Read the Watchdog interrupt from info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read the Watchdog base address from info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_va_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + + err = val_sdei_event_register(wd_event->event_num, (uint64_t)entry_point, + (void *)wd_event_handler, SDEI_EVENT_REGISTER_RM_PE, + val_pe_get_mpid_index(0)); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + wd_event->event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + err = val_sdei_event_enable(wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return g_test_status; + } + + return g_test_status; + +event_unregister: + err = val_sdei_event_unregister(wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + wd_event->event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + wd_event->event_num, err); + } +unmap_va: + val_va_free(g_wd_va_addr); + return g_test_status; +} + +static uint64_t second_event_register(struct sdei_event *second_event) +{ + uint64_t int_id; + uint32_t err; + void *entry_point; + + entry_point = &asm_event_handler; + second_event->is_bound_irq = TRUE; + + /* To generate second event, here Platform timer interrupt is used in this routine */ + err = val_configure_second_interrupt(&g_index, &int_id); + val_pe_data_cache_clean_invalidate((uint64_t)&g_index); + if (err) { + val_print(ACS_LOG_ERR, "\n Second interrupt enable failed"); + return SDEI_TEST_FAIL; + } + val_print(ACS_LOG_DEBUG, "\n Found second source intid %llx", int_id); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + return SDEI_TEST_FAIL; + } + /* Bind second interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &second_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + return SDEI_TEST_FAIL; + } + + err = val_sdei_event_register(second_event->event_num, (uint64_t)entry_point, + (void *)second_event_handler, SDEI_EVENT_REGISTER_RM_PE, + val_pe_get_mpid_index(0)); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + second_event->event_num, err); + goto interrupt_release; + } + + err = val_sdei_event_enable(second_event->event_num); + if (!err) { + return g_test_status; + } + + val_print(ACS_LOG_ERR, "\n SDEI event enable test failed with err %d", err); + err = val_sdei_event_unregister(second_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + second_event->event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(second_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + second_event->event_num, err); + } + return SDEI_TEST_FAIL; +} + +static void test_entry(void) { + uint64_t timer_expire_ticks = 100, timeout; + uint32_t err; + uint64_t result1, result2; + struct sdei_event wd_event; + struct sdei_event second_event; + + g_event_counter = 0; + timeout = WD_TIME_OUT; + + /* Register and Enable the Watchdog event */ + g_test_status = wd_event_register(&wd_event); + if (g_test_status & SDEI_TEST_FAIL) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* Register and Enable the second event, here Platform timer used as a second event */ + g_test_status = second_event_register(&second_event); + if (g_test_status & SDEI_TEST_FAIL) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister1; + } + + /* Generate Watchdog event */ + val_wd_set_ws0(g_wd_va_addr, g_wd_num, timer_expire_ticks); + /* Generate Second event */ + val_generate_second_interrupt(g_index, timer_expire_ticks); + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_event_counter); + if (g_event_counter == 2) + break; + } + if (g_event_counter != 2) { + val_print(ACS_LOG_ERR, "\n Event trigger failed"); + val_wd_set_ws0(g_wd_va_addr, g_wd_num, 0); + val_disable_second_interrupt(g_index); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister2; + } + + /*Handler Running False Check */ + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(wd_event.event_num, &result1); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister2; + } + err = val_sdei_event_status(second_event.event_num, &result2); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister2; + } + + if (!(result1 & EVENT_STATUS_RUNNING_BIT) && !(result2 & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + +event_unregister2: + err = val_sdei_event_unregister(second_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + second_event.event_num, err); + } + err = val_sdei_interrupt_release(second_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + second_event.event_num, err); + } +event_unregister1: + err = val_sdei_event_unregister(wd_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + wd_event.event_num, err); + } + err = val_sdei_interrupt_release(wd_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + wd_event.event_num, err); + } + val_va_free(g_wd_va_addr); +} + +SDEI_SET_TEST_DEPS(test_040_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_040, TEST_040_ID, TEST_DESC, test_040_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_041.c b/sdei/test_pool/test_041.c new file mode 100644 index 0000000..cc4cfb8 --- /dev/null +++ b/sdei/test_pool/test_041.c @@ -0,0 +1,298 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify same class events cannot preempt " + +static int32_t g_wd_num; +static uint32_t g_index = 0; +static uint64_t *g_wd_va_addr = NULL; +static volatile uint64_t g_test_status= SDEI_TEST_PASS; +static volatile int32_t g_handler_flag = 0; +static volatile int32_t g_event_counter = 0; + +/* Generating Second Event in Watchdog event handler to check the preemption */ +static void wd_event_handler(void) +{ + uint64_t timeout = TIMEOUT_MEDIUM; + uint32_t timer_expire_ticks = 10; + + val_wd_set_ws0(g_wd_va_addr, g_wd_num, 0); + /* Generate Second event */ + val_generate_second_interrupt(g_index, timer_expire_ticks); + while (timeout--); + g_handler_flag = 0; + g_event_counter++; + val_pe_data_cache_clean_invalidate((uint64_t)&g_event_counter); + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); +} + +static void second_event_handler(void) +{ + val_disable_second_interrupt(g_index); + /* If Second event is preempted WD event handler, assign status to TEST_FAIL */ + if (g_handler_flag) + g_test_status = SDEI_TEST_FAIL; + g_event_counter++; + val_pe_data_cache_clean_invalidate((uint64_t)&g_event_counter); +} + +static uint64_t wd_event_register(struct sdei_event *wd_event) +{ + uint32_t ns_wdg = 0; + uint64_t wd_ctrl_base; + uint64_t int_id = 0; + void *entry_point; + int32_t err; + + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + entry_point = &asm_event_handler; + wd_event->is_bound_irq = TRUE; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + + /* Read the Watchdog interrupt from info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read the Watchdog base address from info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_va_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + + err = val_sdei_event_register(wd_event->event_num, (uint64_t)entry_point, + (void *)wd_event_handler, SDEI_EVENT_REGISTER_RM_PE, + val_pe_get_mpid_index(0)); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + wd_event->event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + err = val_sdei_event_enable(wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return g_test_status; + } + + return g_test_status; + +event_unregister: + err = val_sdei_event_unregister(wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + wd_event->event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + wd_event->event_num, err); + } +unmap_va: + val_va_free(g_wd_va_addr); + return g_test_status; +} + +static uint64_t second_event_register(struct sdei_event *second_event) +{ + uint64_t int_id; + uint32_t err; + void *entry_point; + + entry_point = &asm_event_handler; + second_event->is_bound_irq = TRUE; + + /* To generate second event, here Platform timer interrupt is used in this routine */ + err = val_configure_second_interrupt(&g_index, &int_id); + val_pe_data_cache_clean_invalidate((uint64_t)&g_index); + if (err) { + val_print(ACS_LOG_ERR, "\n Second interrupt enable failed"); + return SDEI_TEST_FAIL; + } + val_print(ACS_LOG_DEBUG, "\n Found second source intid %llx", int_id); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + return SDEI_TEST_FAIL; + } + /* Bind second source interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &second_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + return SDEI_TEST_FAIL; + } + + err = val_sdei_event_register(second_event->event_num, (uint64_t)entry_point, + (void *)second_event_handler, SDEI_EVENT_REGISTER_RM_PE, + val_pe_get_mpid_index(0)); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + second_event->event_num, err); + goto interrupt_release; + } + + err = val_sdei_event_enable(second_event->event_num); + if (!err) { + return g_test_status; + } + + val_print(ACS_LOG_ERR, "\n SDEI event enable test failed with err %d", err); + err = val_sdei_event_unregister(second_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + second_event->event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(second_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + second_event->event_num, err); + } + return SDEI_TEST_FAIL; +} + +static void test_entry(void) { + uint64_t timer_expire_ticks = 100, timeout; + uint32_t err; + uint64_t result1, result2; + struct sdei_event wd_event; + struct sdei_event second_event; + + g_handler_flag = 0; + g_event_counter = 0; + timeout = WD_TIME_OUT; + + /* Register and Enable the Watchdog event */ + g_test_status = wd_event_register(&wd_event); + if (g_test_status & SDEI_TEST_FAIL) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* Register and Enable the second event, here Platform timer used as a second event */ + g_test_status = second_event_register(&second_event); + if (g_test_status & SDEI_TEST_FAIL) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister1; + } + + /* Generate Watchdog event */ + val_wd_set_ws0(g_wd_va_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + val_pe_data_cache_invalidate((uint64_t)&g_event_counter); + if ((g_handler_flag == 0) && (g_event_counter == 2)) + break; + } + if (g_handler_flag || (g_event_counter != 2)) { + val_print(ACS_LOG_ERR, "\n Event trigger failed"); + val_wd_set_ws0(g_wd_va_addr, g_wd_num, 0); + val_disable_second_interrupt(g_index); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister2; + } + + /*Handler Running False Check */ + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(wd_event.event_num, &result1); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister2; + } + err = val_sdei_event_status(second_event.event_num, &result2); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister2; + } + + if (!(result1 & EVENT_STATUS_RUNNING_BIT) && !(result2 & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if (g_test_status & SDEI_TEST_FAIL) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister2; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + +event_unregister2: + err = val_sdei_event_unregister(second_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + second_event.event_num, err); + } + err = val_sdei_interrupt_release(second_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + second_event.event_num, err); + } +event_unregister1: + err = val_sdei_event_unregister(wd_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + wd_event.event_num, err); + } + err = val_sdei_interrupt_release(wd_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + wd_event.event_num, err); + } + val_va_free(g_wd_va_addr); +} + +SDEI_SET_TEST_DEPS(test_041_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_041, TEST_041_ID, TEST_DESC, test_041_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_042.c b/sdei/test_pool/test_042.c new file mode 100644 index 0000000..b9b0846 --- /dev/null +++ b/sdei/test_pool/test_042.c @@ -0,0 +1,383 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify always availability- SDEI_EVENT_SIGNAL " + +static int32_t g_wd_num; +static uint64_t g_test_status= SDEI_TEST_PASS; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static struct sdei_event g_event; +static uint32_t g_main_pe; + +static uint32_t get_secondary_pe_index(void) +{ + uint32_t my_index = val_pe_get_index(); + uint32_t num_pe = val_pe_get_num(), i; + + for (i = 0; i < num_pe; i++) { + if (my_index != i) + return i; + } + return -1; +} + +static void event_signal_handler(void) +{ + g_handler_flag = 0; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); +} + +/* Check the SDEI_EVENT_SIGNAL in below states + * 1. Handler-Unregistered State + * 2. Handler-registered State + * 3. Handler-Enabled State + * 4. Handler-Enabled & Running State + * 5. Handler-Unregister Pending State + */ +static void event_handler(void) +{ + int32_t err; + uint32_t event_num = 0; + uint64_t res = 0; + uint64_t timeout; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + + timeout = TIMEOUT_MEDIUM; + /* Check 4 - Handler-Enabled & Running State */ + err = val_sdei_event_signal(event_num, val_pe_get_mpid_index(g_main_pe)); + if (err) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + while (timeout--) { + if (!g_handler_flag) + break; + } + /* Check the event signal handler invoke */ + if (g_handler_flag) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event_num, &res); + if (err) + break; + if (!(res & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + err = val_sdei_event_unregister(g_event.event_num); + if (err != SDEI_STATUS_PENDING) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + + timeout = TIMEOUT_MEDIUM; + /* Check 5 - Handler-Unregister Pending State */ + err = val_sdei_event_signal(event_num, val_pe_get_mpid_index(val_pe_get_index())); + if (err) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + while (timeout--) { + if (!g_handler_flag) + break; + } + /* Check the event signal handler invoke */ + if (g_handler_flag) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event_num, &res); + if (err) + break; + if (!(res & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + g_handler_flag = 0; +} + +static void event_signal_register(void *ignore) +{ + int32_t err; + void *entry_point; + uint32_t event_num; + + entry_point = &asm_event_handler; + event_num = 0; + /* Register the event zero */ + err = val_sdei_event_register(event_num, (uint64_t)entry_point, + (void *)event_signal_handler, 0, 0); + if (err) { + g_test_status = SDEI_TEST_FAIL; + return; + } + + err = val_sdei_event_enable(event_num); + if (!err) + return; + + g_test_status = SDEI_TEST_FAIL; + val_sdei_event_unregister(event_num); +} + +static void event_signal_unregister(void *ignore) +{ + uint32_t err; + uint32_t event_num = 0; + + err = val_sdei_event_unregister(event_num); + if (err) { + g_test_status = SDEI_TEST_FAIL; + } +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + void *entry_point; + int32_t err; + uint32_t event_num = 0; + uint64_t res = 0; + uint64_t int_id = 0; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + entry_point = &asm_event_handler; + g_event.is_bound_irq = TRUE; + g_event.type = SDEI_EVENT_TYPE_SHARED; + + val_pe_execute_on_all((void*)event_signal_register, 0); + if (g_test_status & SDEI_TEST_FAIL) { + val_print(ACS_LOG_ERR, "\n SDEI event signal register failed"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + do { + /*Array index starts from 0, so subtract 1 from count*/ + g_wd_num--; + + /* Skip secure Watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = TIMEOUT_MEDIUM; + + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + err = val_sdei_interrupt_bind(int_id, &g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + val_pe_data_cache_clean_invalidate((uint64_t)&g_event.event_num); + /* Check 1 - Handler-Unregistered State */ + err = val_sdei_event_signal(event_num, val_pe_get_mpid_index(val_pe_get_index())); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Unregistered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + while (timeout--) { + if (!g_handler_flag) + break; + } + if (g_handler_flag) { + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event_num, &res); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + event_num, err); + if (!(res & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + g_handler_flag = 1; + timeout = TIMEOUT_MEDIUM; + err = val_sdei_event_register(g_event.event_num, (uint64_t)entry_point, + (void *)event_handler, SDEI_EVENT_REGISTER_RM_PE, + val_pe_get_mpid_index(get_secondary_pe_index())); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI evt %d register fail with err %x", + g_event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + /* Check 2 - Handler-Registered State */ + err = val_sdei_event_signal(event_num, val_pe_get_mpid_index(val_pe_get_index())); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Registered state check failed with err %d", + err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + while (timeout--) { + if (!g_handler_flag) + break; + } + if (g_handler_flag) { + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event_num, &res); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + event_num, err); + if (!(res & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + g_handler_flag = 1; + timeout = TIMEOUT_MEDIUM; + err = val_sdei_event_enable(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Check 3 - Handler-Enabled State */ + err = val_sdei_event_signal(event_num, val_pe_get_mpid_index(val_pe_get_index())); + if (err) { + val_print(ACS_LOG_ERR, "\n Handler-Enabled state check failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (!g_handler_flag) + break; + } + if (g_handler_flag) { + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event_num, &res); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + event_num, err); + if (!(res & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + g_handler_flag = 1; + g_main_pe = val_pe_get_index(); + val_pe_data_cache_clean_invalidate((uint64_t)&g_main_pe); + timeout = WD_TIME_OUT; + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + while (timeout--) { + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(g_event.event_num, &res); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + g_event.event_num, err); + if (!(res & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if ((res & EVENT_STATUS_REGISTER_BIT)) { + g_test_status = SDEI_TEST_ERROR; + goto event_unregister; + } + else { + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event num %d release failed : err %d", + g_event.event_num, err); + g_test_status = SDEI_TEST_ERROR; + } + goto unmap_va; + } + +event_unregister: + err = val_sdei_event_unregister(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister failed : err %x", + g_event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(g_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + g_event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); + val_pe_execute_on_all((void*)event_signal_unregister, 0); + val_test_pe_set_status(val_pe_get_index(), + ((g_test_status == SDEI_TEST_PASS) ? SDEI_TEST_PASS : SDEI_TEST_FAIL) + ); +} + +SDEI_SET_TEST_DEPS(test_042_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_042, TEST_042_ID, TEST_DESC, test_042_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_043.c b/sdei/test_pool/test_043.c new file mode 100644 index 0000000..5d215f8 --- /dev/null +++ b/sdei/test_pool/test_043.c @@ -0,0 +1,309 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify only 1 instance of shared event handled " + +static int32_t g_wd_num; +static uint32_t g_index = 0; +static uint64_t *g_wd_va_addr = NULL; +static volatile uint64_t g_test_status = SDEI_TEST_PASS; +static volatile int32_t g_event_counter = 0; +static volatile int32_t g_handler_flag = 1; + +static void wd_event_handler(void) +{ + uint64_t timeout = TIMEOUT_MEDIUM; + + val_wd_set_ws0(g_wd_va_addr, g_wd_num, 0); + g_event_counter++; + if (g_handler_flag) { + while (timeout--) { + if (g_event_counter == 2) { + g_test_status = SDEI_TEST_FAIL; + break; + } + } + } + g_handler_flag = 0; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); + val_pe_data_cache_clean_invalidate((uint64_t)&g_event_counter); +} + +static void second_event_handler(void) +{ + uint64_t timeout = TIMEOUT_MEDIUM; + + val_disable_second_interrupt(g_index); + g_event_counter++; + if (g_handler_flag) { + while (timeout--) { + if (g_event_counter == 2) { + g_test_status = SDEI_TEST_FAIL; + break; + } + } + } + g_handler_flag = 0; + val_pe_data_cache_clean_invalidate((uint64_t)&g_handler_flag); + val_pe_data_cache_clean_invalidate((uint64_t)&g_event_counter); +} + +static uint64_t wd_event_register(struct sdei_event *wd_event) +{ + uint32_t ns_wdg = 0; + uint64_t wd_ctrl_base; + uint64_t int_id = 0; + void *entry_point; + int32_t err; + + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + entry_point = &asm_event_handler; + wd_event->is_bound_irq = TRUE; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + + /* Read the Watchdog interrupt from info table */ + int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", int_id); + /* Read the Watchdog base address from info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_va_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + + err = val_sdei_event_register(wd_event->event_num, (uint64_t)entry_point, + (void *)wd_event_handler, SDEI_EVENT_REGISTER_RM_PE, + val_pe_get_mpid_index(0)); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + wd_event->event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + err = val_sdei_event_enable(wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return g_test_status; + } + + return g_test_status; + +event_unregister: + err = val_sdei_event_unregister(wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + wd_event->event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(wd_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + wd_event->event_num, err); + } +unmap_va: + val_va_free(g_wd_va_addr); + return g_test_status; +} + +static uint64_t second_event_register(struct sdei_event *second_event) +{ + uint64_t int_id; + uint32_t err; + void *entry_point; + + entry_point = &asm_event_handler; + second_event->is_bound_irq = TRUE; + + /* To generate second event, here Platform timer interrupt is used in this routine */ + err = val_configure_second_interrupt(&g_index, &int_id); + val_pe_data_cache_clean_invalidate((uint64_t)&g_index); + if (err) { + val_print(ACS_LOG_ERR, "\n Second interrupt enable failed"); + return SDEI_TEST_FAIL; + } + val_print(ACS_LOG_DEBUG, "\n Found second source intid %llx", int_id); + + err = val_gic_disable_interrupt(int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", int_id); + return SDEI_TEST_FAIL; + } + /* Bind second source interrupt to event */ + err = val_sdei_interrupt_bind(int_id, &second_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + int_id, err); + return SDEI_TEST_FAIL; + } + + err = val_sdei_event_register(second_event->event_num, (uint64_t)entry_point, + (void *)second_event_handler, SDEI_EVENT_REGISTER_RM_PE, + val_pe_get_mpid_index(0)); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + second_event->event_num, err); + goto interrupt_release; + } + + err = val_sdei_event_enable(second_event->event_num); + if (!err) { + return g_test_status; + } + + val_print(ACS_LOG_ERR, "\n SDEI event enable test failed with err %d", err); + err = val_sdei_event_unregister(second_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + second_event->event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(second_event->event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + second_event->event_num, err); + } + return SDEI_TEST_FAIL; +} + +static void test_entry(void) { + uint64_t timer_expire_ticks = 100, timeout; + uint32_t err; + uint64_t result1, result2; + struct sdei_event wd_event; + struct sdei_event second_event; + + g_event_counter = 0; + g_handler_flag = 1; + timeout = WD_TIME_OUT; + + /* Register and Enable the Watchdog event */ + g_test_status = wd_event_register(&wd_event); + if (g_test_status & SDEI_TEST_FAIL) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* Register and Enable the second event, here Platform timer used as a second event */ + g_test_status = second_event_register(&second_event); + if (g_test_status & SDEI_TEST_FAIL) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister1; + } + + /* Generate Watchdog event */ + val_wd_set_ws0(g_wd_va_addr, g_wd_num, timer_expire_ticks); + /* Generate second event */ + val_generate_second_interrupt(g_index, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_event_counter); + if (g_event_counter == 2) + break; + } + if (g_event_counter != 2) { + val_print(ACS_LOG_ERR, "\n Event trigger failed"); + val_wd_set_ws0(g_wd_va_addr, g_wd_num, 0); + val_disable_second_interrupt(g_index); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister2; + } + + /* Handler Running False Check */ + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(wd_event.event_num, &result1); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister2; + } + err = val_sdei_event_status(second_event.event_num, &result2); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister2; + } + + if (!(result1 & EVENT_STATUS_RUNNING_BIT) && !(result2 & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if (g_test_status & SDEI_TEST_FAIL) + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + else + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + +event_unregister2: + err = val_sdei_event_unregister(second_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + second_event.event_num, err); + } + err = val_sdei_interrupt_release(second_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + second_event.event_num, err); + } +event_unregister1: + err = val_sdei_event_unregister(wd_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + wd_event.event_num, err); + } + err = val_sdei_interrupt_release(wd_event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + wd_event.event_num, err); + } + val_va_free(g_wd_va_addr); +} + +SDEI_SET_TEST_DEPS(test_043_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_043, TEST_043_ID, TEST_DESC, test_043_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_044.c b/sdei/test_pool/test_044.c new file mode 100644 index 0000000..22a8ddd --- /dev/null +++ b/sdei/test_pool/test_044.c @@ -0,0 +1,176 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify PSCI VERSION, FEATURES, AFFINITY_INFO " + +static int32_t g_wd_num; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static volatile int32_t g_test_status = SDEI_TEST_PASS; + +static void event_handler(void) +{ + uint32_t ver = 0; + uint32_t err; + uint64_t target_aff, lowest_aff_level; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + + target_aff = 0; + lowest_aff_level = 0; + err = val_psci_version(&ver); + if (err) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + + err = val_psci_affinity_info(target_aff, lowest_aff_level); + if (err) { + g_test_status = SDEI_TEST_FAIL; + g_handler_flag = 0; + return; + } + + err = val_psci_features(PSCI_FN_PSCI_CPU_SUSPEND); + if (err) { + g_test_status = SDEI_TEST_FAIL; + } + + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + uint64_t res = 0; + uint64_t wd_int_id = 0; + struct sdei_event event; + int32_t err; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + event.is_bound_irq = TRUE; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + wd_int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", wd_int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(wd_int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", wd_int_id); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + /* Binding Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(wd_int_id, &event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI interrupt number %lld bind failed with err %d", + wd_int_id, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto interrupt_release; + } + + err = val_sdei_event_enable(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Generating Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (g_handler_flag && timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + if (g_test_status & SDEI_TEST_FAIL) + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + else + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + +event_unregister: + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event.event_num, &res); + if (err) + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + event.event_num, err); + if (!(res & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); +} + +SDEI_SET_TEST_DEPS(test_044_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_044, TEST_044_ID, TEST_DESC, test_044_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_045.c b/sdei/test_pool/test_045.c new file mode 100644 index 0000000..3e79b63 --- /dev/null +++ b/sdei/test_pool/test_045.c @@ -0,0 +1,134 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify Suspend, check wakeup mask and status " + +#define REGISTERED 0x1 +#define ALREADY_MASKED 0 +#define WD_TIMEOUT 0x1000 +#define SUSPEND_POWERDOWN 1 + +static uint32_t g_wd_index; + +static void isr(void) +{ + uint32_t wd_int_id; + val_wd_set_ws0(0, g_wd_index, 0); + wd_int_id = val_wd_get_info(g_wd_index, WD_INFO_GSIV); + val_print(ACS_LOG_INFO, "\n Watchdog interrupt %d recieved", wd_int_id); + val_gic_end_of_interrupt(wd_int_id); +} + +static void test_entry(void) +{ + uint32_t wd_int_id, event_num, wd_num; + uint64_t result, event_status; + int err; + + g_wd_index = -1; + wd_num = val_wd_get_info(0, WD_INFO_COUNT); + + /* Get the first non-secure watchdog timer index */ + while (wd_num--) { + if (!val_wd_get_info(wd_num, WD_INFO_ISSECURE)) { + g_wd_index = wd_num; + break; + } + } + + if (g_wd_index == -1) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_SKIP); + return; + } + + /* Get a shared event */ + event_num = val_event_get(SDEI_EVENT_TYPE_SHARED, SDEI_EVENT_PRIORITY_ANY); + if (!event_num) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* Register the shared event*/ + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, NULL, 0, 0); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + /* Unmask SDEI on this PE*/ + err = val_sdei_unmask(); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Get the watchdog interrupt id */ + wd_int_id = val_wd_get_info(g_wd_index, WD_INFO_GSIV); + + /* Install interrupt handler for the watchdog interrupt */ + err = val_gic_install_isr(wd_int_id, isr); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt register %x failed with err %d\n", + wd_int_id, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Enable the watchdog with a small timeout value */ + val_wd_set_ws0(0, g_wd_index, WD_TIMEOUT); + + /* Put the PE to suspend with powerdown state */ + val_pe_suspend(SUSPEND_POWERDOWN); + + /* After wake up, check the event status */ + err = val_sdei_event_status(event_num, &event_status); + if (err) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto free_interrupt; + } + + /* The event status should be REGISTERED */ + if (!(event_status & REGISTERED)) { + val_print(ACS_LOG_ERR, "\n Event status changed after waking up 0x%x", event_status); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto free_interrupt; + } + + /* Check the PE SDEI mask status. PE should be already masked. */ + err = val_sdei_mask(&result); + if (err || (result != ALREADY_MASKED)) { + val_print(ACS_LOG_ERR, "\n PE unmasked after waking up 0x%x", result); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto free_interrupt; + } + + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); +free_interrupt: + val_gic_free_interrupt(wd_int_id); +event_unregister: + err = val_sdei_event_unregister(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + event_num, err); + } +} + +SDEI_SET_TEST_DEPS(test_045_deps, TEST_NONE_ID); +SDEI_PUBLISH_TEST(test_045, TEST_045_ID, TEST_DESC, test_045_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_046.c b/sdei/test_pool/test_046.c new file mode 100644 index 0000000..71a52f4 --- /dev/null +++ b/sdei/test_pool/test_046.c @@ -0,0 +1,173 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify mask status of the PE after handler " + +#define PE_MASKED 1 + +static int32_t g_wd_num; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static volatile int32_t g_test_status = SDEI_TEST_PASS; + +static void event_handler(void) +{ + uint32_t err; + uint64_t result = 0; + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + + err = val_sdei_mask(&result); + if (err || (result != PE_MASKED)) { + g_test_status = SDEI_TEST_FAIL; + } + g_handler_flag = 0; +} + +static void unmask_cpu(void *ignored) +{ + val_sdei_unmask(); +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 1, timeout; + uint64_t wd_ctrl_base; + uint64_t res = 0; + uint64_t wd_int_id = 0; + struct sdei_event event; + int32_t err; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + event.is_bound_irq = TRUE; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + wd_int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", wd_int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(wd_int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", wd_int_id); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(wd_int_id, &event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI interrupt number %lld bind failed with err %d", + wd_int_id, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto unmap_va; + } + + err = val_sdei_event_register(event.event_num, (uint64_t)asm_event_handler, + (void *)event_handler, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register failed with err %x", + event.event_num, err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto interrupt_release; + } + + err = val_sdei_event_enable(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable test failed with err %d", err); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + /* Generate Watchdog event */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (g_handler_flag && timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event.event_num, &res); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d status failed err %x", + event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + break; + } + if (!(res & EVENT_STATUS_RUNNING_BIT)) + break; + } while (timeout--); + + if (res & EVENT_STATUS_RUNNING_BIT) + g_test_status = SDEI_TEST_FAIL; + + if (g_test_status & SDEI_TEST_FAIL) + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + else + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + + val_pe_execute_on_all(unmask_cpu, 0); + +event_unregister: + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); +} + +SDEI_SET_TEST_DEPS(test_046_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_046, TEST_046_ID, TEST_DESC, test_046_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_047.c b/sdei/test_pool/test_047.c new file mode 100644 index 0000000..ffa6d93 --- /dev/null +++ b/sdei/test_pool/test_047.c @@ -0,0 +1,73 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify after PE reset, events will be masked " + +#define ALREADY_MASKED 0 + +static volatile uint32_t g_test_status = SDEI_TEST_PASS; +static uint32_t g_reset_pe_index; + +uint32_t get_reset_pe_index(void) +{ + uint32_t my_index = val_pe_get_index(); + uint32_t num_pe = val_pe_get_num(), i; + for (i = 0; i < num_pe; i++) { + if (my_index != i) + return i; + } + return -1; +} + +static void payload(void *ignore) +{ + uint64_t result = 0; + int32_t err; + + if (val_pe_get_index() == g_reset_pe_index) { + err = val_sdei_mask(&result); + if (err || (result != ALREADY_MASKED)) { + g_test_status = SDEI_TEST_FAIL; + } + } +} + +static void test_entry(void) +{ + + g_reset_pe_index = get_reset_pe_index(); + val_pe_data_cache_clean_invalidate((uint64_t)&g_reset_pe_index); + + /* Reset PE */ + val_pe_poweroff(g_reset_pe_index); + val_pe_poweron(g_reset_pe_index); + + val_pe_execute_on_all(payload, 0); + + if (g_test_status & SDEI_TEST_FAIL) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + } else { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + } + +} + +SDEI_SET_TEST_DEPS(test_047_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_047, TEST_047_ID, TEST_DESC, test_047_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_048.c b/sdei/test_pool/test_048.c new file mode 100644 index 0000000..1632dc0 --- /dev/null +++ b/sdei/test_pool/test_048.c @@ -0,0 +1,131 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "If PE off, no event should not bring it online " + +#define WD_TIMEOUT 0x1 +#define TIMEOUT 0x1000 + +static int g_handler_called; +static uint32_t g_wd_index; + +static void event_handler(void) { + val_wd_set_ws0(0, g_wd_index, 0); + g_handler_called = 1; +} +uint32_t get_secondary_pe_index(void) +{ + uint32_t my_index = val_pe_get_index(); + uint32_t num_pe = val_pe_get_num(), i; + for (i = 0; i < num_pe; i++) { + if (my_index != i) + return i; + } + return -1; +} + +static void test_entry(void) +{ + uint32_t wd_int_id, event_num, wd_num, timeout; + uint64_t secondary_mpidr; + uint32_t secondary_index; + int err; + + g_wd_index = -1; + wd_num = val_wd_get_info(0, WD_INFO_COUNT); + + /* Get the first non-secure watchdog timer index */ + while (wd_num--) { + if (!val_wd_get_info(wd_num, WD_INFO_ISSECURE)) { + g_wd_index = wd_num; + break; + } + } + + if (g_wd_index == -1) { + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_SKIP); + return; + } + + val_pe_data_cache_clean_invalidate((uint64_t)&g_wd_index); + + /* Read Watchdog interrupt from Watchdog info table */ + wd_int_id = val_wd_get_info(g_wd_index, WD_INFO_GSIV); + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(wd_int_id, &event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt (%d) bind failed", wd_int_id); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + return; + } + + secondary_index = get_secondary_pe_index(); + secondary_mpidr = val_pe_get_mpid_index(secondary_index); + + err = val_sdei_event_register(event_num, (uint64_t)asm_event_handler, (void*)event_handler, + SDEI_EVENT_REGISTER_RM_PE, secondary_mpidr); + if (err) { + val_print(ACS_LOG_ERR, "\n Event (%d) register failed", event_num); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto interrupt_release; + } + + err = val_sdei_event_enable(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event (%d) enable failed", event_num); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + goto event_unregister; + } + + val_pe_poweroff(secondary_index); + + val_wd_set_ws0(0, g_wd_index, WD_TIMEOUT); + + timeout = TIMEOUT; + + while (!timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_called); + if (g_handler_called) + break; + } + + val_wd_set_ws0(0, g_wd_index, 0); + + if (g_handler_called) { + val_print(ACS_LOG_ERR, "\n Event turned on powered off core"); + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_FAIL); + } else + val_test_pe_set_status(val_pe_get_index(), SDEI_TEST_PASS); + +event_unregister: + err = val_sdei_event_unregister(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event (%d) unregister failed", event_num); + } + +interrupt_release: + err = val_sdei_interrupt_release(event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt (%d) release failed", wd_int_id); + } +} + +SDEI_SET_TEST_DEPS(test_048_deps, TEST_NONE_ID); +SDEI_PUBLISH_TEST(test_048, TEST_048_ID, TEST_DESC, test_048_deps, test_entry, FALSE); diff --git a/sdei/test_pool/test_049.c b/sdei/test_pool/test_049.c new file mode 100644 index 0000000..6307642 --- /dev/null +++ b/sdei/test_pool/test_049.c @@ -0,0 +1,193 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include + +#define TEST_DESC "Verify event resume context test " +#define EXPECTED_DAIF 0xF +#define EXPECTED_SPsel 0x1 + +static int32_t g_wd_num; +static uint64_t *g_wd_addr = NULL; +static volatile int32_t g_handler_flag = 1; +static uint64_t g_test_status= SDEI_TEST_PASS; +uint64_t g_interrupted_pc = 0; +uint64_t g_interrupted_pstate = 0; + +/* Event handler resume function */ +static void event_handler_resume(void) +{ + uint32_t err; + uint64_t value; + + /* Check PSTATE is set to DAIF=0b1111, El = Elc, nRW=0, SP=1*/ + err = val_pe_reg_read(DAIF, &value); + if (err || (value != EXPECTED_DAIF)) { + g_test_status = SDEI_TEST_FAIL; + } + err = val_pe_reg_read(SPsel, &value); + if (err || (value != EXPECTED_SPsel)) { + g_test_status = SDEI_TEST_FAIL; + } + err = val_pe_reg_read(CurrentEL, &value); + value = __EXTRACT_BITS(value, 2, 2); + if (err || (value != CLIENT_EL)) { + g_test_status = SDEI_TEST_FAIL; + } + + /* Check ELR_ELc is Set to Interrupted PC */ + err = val_pe_reg_read(ELR_EL, &value); + if (err || (value != g_interrupted_pc)) { + g_test_status = SDEI_TEST_FAIL; + } + + /* Check SPSR_ELc is Set to Interrupted PSTATE */ + err = val_pe_reg_read(SPSR_EL, &value); + if (err || (value != g_interrupted_pstate)) { + g_test_status = SDEI_TEST_FAIL; + } + + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_handler_flag = 0; +} + +static void test_entry(void) { + uint32_t ns_wdg = 0; + uint64_t timer_expire_ticks = 100, timeout; + uint64_t wd_ctrl_base; + uint64_t g_int_id = 0; + struct sdei_event event; + int32_t err; + uint64_t result; + + g_handler_flag = 1; + g_wd_num = val_wd_get_info(0, WD_INFO_COUNT); + event.is_bound_irq = TRUE; + + do { + /* array index starts from 0, so subtract 1 from count */ + g_wd_num--; + + /* Skip Secure watchdog */ + if (val_wd_get_info(g_wd_num, WD_INFO_ISSECURE)) + continue; + + ns_wdg++; + timeout = WD_TIME_OUT; + + /* Read Watchdog interrupt from Watchdog info table */ + g_int_id = val_wd_get_info(g_wd_num, WD_INFO_GSIV); + val_print(ACS_LOG_DEBUG, "\n WS0 interrupt id: %lld", g_int_id); + /* Read Watchdog base address from Watchdog info table */ + wd_ctrl_base = val_wd_get_info(g_wd_num, WD_INFO_CTRL_BASE); + g_wd_addr = val_pa_to_va(wd_ctrl_base); + + err = val_gic_disable_interrupt(g_int_id); + if (err) { + val_print(ACS_LOG_ERR, "\n Interrupt %lld disable failed", g_int_id); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + /* Bind Watchdog interrupt to event */ + err = val_sdei_interrupt_bind(g_int_id, &event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI intr number %lld bind failed with err %d", + g_int_id, err); + g_test_status = SDEI_TEST_FAIL; + goto unmap_va; + } + + err = val_sdei_event_register(event.event_num, (uint64_t)asm_handler_resume_context, + (void *)event_handler_resume, 0, 0); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d register fail with err %x", + event.event_num, err); + g_test_status = SDEI_TEST_FAIL; + goto interrupt_release; + } + + err = val_sdei_event_enable(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event enable failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + + /* Generate Watchdog interrupt */ + val_wd_set_ws0(g_wd_addr, g_wd_num, timer_expire_ticks); + + while (timeout--) { + val_pe_data_cache_invalidate((uint64_t)&g_handler_flag); + if (g_handler_flag == 0) + break; + } + if (g_handler_flag) { + val_print(ACS_LOG_ERR, "\n Watchdog interrupt trigger failed"); + val_wd_set_ws0(g_wd_addr, g_wd_num, 0); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + } while (0); + + if (!ns_wdg) { + g_test_status = SDEI_TEST_FAIL; + val_print(ACS_LOG_ERR, "\n No non-secure Watchdogs reported"); + return; + } + + /* Handler Running False Check */ + timeout = TIMEOUT_MEDIUM; + do { + err = val_sdei_event_status(event.event_num, &result); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event status failed with err %d", err); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + if (!(result & EVENT_STATUS_RUNNING_BIT)) + break; + }while (timeout--); + + if (result & EVENT_STATUS_RUNNING_BIT) { + val_print(ACS_LOG_ERR, "\n SDEI_EVENT_COMPLETE test failed, Handler Running"); + g_test_status = SDEI_TEST_FAIL; + goto event_unregister; + } + g_test_status = SDEI_TEST_PASS; + +event_unregister: + err = val_sdei_event_unregister(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SDEI event %d unregister fail with err %x", + event.event_num, err); + } +interrupt_release: + err = val_sdei_interrupt_release(event.event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n Event number %d release failed with err %x", + event.event_num, err); + } +unmap_va: + val_va_free(g_wd_addr); + val_test_pe_set_status(val_pe_get_index(), + ((g_test_status == SDEI_TEST_PASS) ? SDEI_TEST_PASS : SDEI_TEST_FAIL) + ); +} + +SDEI_SET_TEST_DEPS(test_049_deps, TEST_001_ID, TEST_002_ID); +SDEI_PUBLISH_TEST(test_049, TEST_049_ID, TEST_DESC, test_049_deps, test_entry, FALSE); diff --git a/sdei/uefi_app/SdeiAcs.h b/sdei/uefi_app/SdeiAcs.h new file mode 100644 index 0000000..7b48672 --- /dev/null +++ b/sdei/uefi_app/SdeiAcs.h @@ -0,0 +1,24 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#ifndef __SDEI_AVS_LEVEL_H__ +#define __SDEI_AVS_LEVEL_H__ + + #define SDEI_ACS_MAJOR_VER 0 + #define SDEI_ACS_MINOR_VER 1 + +#endif diff --git a/sdei/uefi_app/SdeiAcs.inf b/sdei/uefi_app/SdeiAcs.inf new file mode 100644 index 0000000..4978958 --- /dev/null +++ b/sdei/uefi_app/SdeiAcs.inf @@ -0,0 +1,114 @@ +## @file +# Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. +# SPDX-License-Identifier : Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = Sdei + FILE_GUID = a912f198-7f0e-4803-b908-b757b806ec83 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 0.1 + ENTRY_POINT = ShellCEntryLib + +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources.AARCH64] + ../val/include/val_interface.h + SdeiAcsMain.c + ../test_pool/test_001.c + ../test_pool/test_002.c + ../test_pool/test_003.c + ../test_pool/test_004.c + ../test_pool/test_005.c + ../test_pool/test_006.c + ../test_pool/test_007.c + ../test_pool/test_008.c + ../test_pool/test_009.c + ../test_pool/test_010.c + ../test_pool/test_011.c + ../test_pool/test_012.c + ../test_pool/test_013.c + ../test_pool/test_014.c + ../test_pool/test_015.c + ../test_pool/test_016.c + ../test_pool/test_017.c + ../test_pool/test_018.c + ../test_pool/test_019.c + ../test_pool/test_020.c + ../test_pool/test_021.c + ../test_pool/test_022.c + ../test_pool/test_023.c + ../test_pool/test_024.c + ../test_pool/test_025.c + ../test_pool/test_026.c + ../test_pool/test_027.c + ../test_pool/test_028.c + ../test_pool/test_029.c + ../test_pool/test_030.c + ../test_pool/test_031.c + ../test_pool/test_032.c + ../test_pool/test_033.c + ../test_pool/test_034.c + ../test_pool/test_035.c + ../test_pool/test_036.c + ../test_pool/test_037.c + ../test_pool/test_038.c + ../test_pool/test_039.c + ../test_pool/test_040.c + ../test_pool/test_041.c + ../test_pool/test_042.c + ../test_pool/test_043.c + ../test_pool/test_044.c + ../test_pool/test_045.c + ../test_pool/test_046.c + ../test_pool/test_047.c + ../test_pool/test_048.c + ../test_pool/test_049.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ShellPkg/ShellPkg.dec + EdkCompatibilityPkg/EdkCompatibilityPkg.dec + +[LibraryClasses] + SdeiValLib + SdeiPalLib + UefiLib + ShellLib + DebugLib + BaseMemoryLib + ShellCEntryLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + +[Protocols] + gEfiAcpiTableProtocolGuid ## CONSUMES + gHardwareInterruptProtocolGuid ## CONSUMES + gEfiCpuArchProtocolGuid ## CONSUMES + gEfiPciIoProtocolGuid ## CONSUMES + gEfiLoadedImageProtocolGuid ## CONSUMES + +[Guids] + gEfiAcpi20TableGuid + gEfiAcpiTableGuid + +[BuildOptions] + GCC:*_*_*_ASM_FLAGS = -march=armv8.1-a diff --git a/sdei/uefi_app/SdeiAcsMain.c b/sdei/uefi_app/SdeiAcsMain.c new file mode 100644 index 0000000..0f6f1cc --- /dev/null +++ b/sdei/uefi_app/SdeiAcsMain.c @@ -0,0 +1,324 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "SdeiAcs.h" + +sdei_log_control g_log_control; + +VOID +HelpMsg ( + VOID + ) +{ + Print (L"\nUsage: Sdei.efi [-v ] | [-l ] | [-f ] | [-s] | [-skip ]\n" + "Options:\n" + "-v Verbosity of the Prints\n" + " 1 shows all prints, 5 shows Errors\n" + "-f Name of the log file to record the test results in\n" + "-skip Test(s) to be skipped\n" + " Refer to section 4 of SDEI_ACS_User_Guide\n" + " To skip a particular test use the testcase number\n" + "-run Test(s) to run\n" + ); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-v" , TypeValue}, // -v # Verbosity of the Prints. 1 shows all prints, 5 shows Errors + {L"-f" , TypeValue}, // -f # Name of the log file to record the test results in. + {L"-skip" , TypeValue}, // -skip # test(s) to skip execution + {L"-run" , TypeValue}, // -run # test(s) to execute + {L"-help" , TypeFlag}, // -help # help : info about commands + {L"-h" , TypeFlag}, // -h # help : info about commands + {NULL , TypeMax} + }; + +EFI_STATUS +createPeInfoTable ( +) +{ + + EFI_STATUS Status; + UINT64 *PeInfoTable; + + Status = gBS->AllocatePool ( EfiBootServicesData, + PE_INFO_TABLE_SZ, + (VOID **) &PeInfoTable ); + + if (EFI_ERROR(Status)) + { + Print(L"Allocate Pool failed %x \n", Status); + return Status; + } + + Status = val_pe_create_info_table(PeInfoTable); + + return Status; + +} + +EFI_STATUS +createGicInfoTable ( +) +{ + EFI_STATUS Status; + UINT64 *GicInfoTable; + + Status = gBS->AllocatePool (EfiBootServicesData, + GIC_INFO_TABLE_SZ, + (VOID **) &GicInfoTable); + + if (EFI_ERROR(Status)) + { + Print(L"Allocate Pool failed %x \n", Status); + return Status; + } + + Status = val_gic_create_info_table(GicInfoTable); + + return Status; + +} + +EFI_STATUS +createEventInfoTable ( +) +{ + EFI_STATUS Status; + UINT64 *EventInfoTable; + + Status = gBS->AllocatePool (EfiBootServicesData, + EVENT_INFO_TABLE_SZ, + (VOID **) &EventInfoTable); + + if (EFI_ERROR(Status)) + { + Print(L"Allocate Pool failed %x \n", Status); + return Status; + } + + Status = val_sdei_create_event_info_table(EventInfoTable); + + return Status; + +} + +EFI_STATUS +createWatchdogInfoTable( +) +{ + UINT64 *WdInfoTable; + EFI_STATUS Status; + + Status = gBS->AllocatePool (EfiBootServicesData, + WD_INFO_TABLE_SZ, + (VOID **) &WdInfoTable); + + if (EFI_ERROR(Status)) + { + Print(L"Allocate Pool failed %x \n", Status); + return Status; + } + Status = val_wd_create_info_table(WdInfoTable); + + return Status; + +} + +EFI_STATUS +createTimerInfoTable( +) +{ + UINT64 *TimerInfoTable; + EFI_STATUS Status; + + Status = gBS->AllocatePool (EfiBootServicesData, + TIMER_INFO_TABLE_SZ, + (VOID **) &TimerInfoTable); + + if (EFI_ERROR(Status)) + { + Print(L"Allocate Pool failed %x \n", Status); + return Status; + } + val_timer_create_info_table(TimerInfoTable); + + return Status; +} + +/*** + SDEI Compliance Suite Entry Point. + + Call the Entry points of individual modules. + + @retval 0 The application exited normally. + @retval Other An error occurred. +***/ +INTN +EFIAPI +ShellAppMain ( + IN UINTN Argc, + IN CHAR16 **Argv + ) +{ + + LIST_ENTRY *ParamPackage; + CONST CHAR16 *CmdLineArg; + CHAR16 *ProbParam; + UINT32 Status; + UINT32 i, test_id; + sdei_test_control control; + + val_test_init(&control); + + // + // Process Command Line arguments + // + Status = ShellInitialize(); + Status = ShellCommandLineParse (ParamList, &ParamPackage, &ProbParam, TRUE); + if (Status) { + Print(L"Shell command line parse error %x\n", Status); + Print(L"Unrecognized option %s passed\n", ProbParam); + HelpMsg(); + return SHELL_INVALID_PARAMETER; + } + + for (i = 1; i 5) { + g_log_control.print_level = ACS_LOG_TEST; + } + } + + + // Options with Values + CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-f"); + g_log_control.log_file_handle = NULL; + if (CmdLineArg != NULL) { + Status = ShellOpenFileByName(CmdLineArg, &g_log_control.log_file_handle, + EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE, 0x0); + if (EFI_ERROR(Status)) { + Print(L"Failed to open log file %s\n", CmdLineArg); + } + } + + // Options with Values + if ((ShellCommandLineGetFlag (ParamPackage, L"-help")) || + (ShellCommandLineGetFlag (ParamPackage, L"-h"))){ + HelpMsg(); + return 0; + } + Status = createPeInfoTable(); + if (Status) + return Status; + + Status = createGicInfoTable(); + if (Status) + return Status; + + Status = createEventInfoTable(); + if (Status) + return Status; + + Status = createWatchdogInfoTable(); + if (Status) + return Status; + + Status = createTimerInfoTable(); + if (Status) + return Status; + + Status = val_sdei_initialization(); + if (Status) { + val_print(ACS_LOG_ERR, "SDEI initialization failed\n"); + return Status; + } + + val_shared_mem_alloc(); + + // + // Initialize global counters + // + control.tests_passed = 0; + control.tests_failed = 0; + control.tests_skipped = 0; + control.tests_aborted = 0; + + Print(L"\n\n SDEI Architecture Compliance Suite \n"); + Print(L" Version %d.%d \n", SDEI_ACS_MAJOR_VER, SDEI_ACS_MINOR_VER); + val_test_execute(&control); + Print(L"Tests passed : %d\n", control.tests_passed); + Print(L"Tests failed : %d\n", control.tests_failed); + Print(L"Tests skipped : %d\n", control.tests_skipped); + Print(L"Tests aborted : %d\n", control.tests_aborted); + + val_shared_mem_free(); + + if (g_log_control.log_file_handle) { + ShellCloseFile(g_log_control.log_file_handle); + } + + Print(L"\n *** SDEI tests complete. Reset the system. *** \n\n"); + + return(0); +} diff --git a/sdei/val/Makefile b/sdei/val/Makefile new file mode 100644 index 0000000..d60a045 --- /dev/null +++ b/sdei/val/Makefile @@ -0,0 +1,106 @@ +## @file + # Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + # SPDX-License-Identifier : Apache-2.0 + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. +## + +export CROSS_COMPILE ?= aarch64-linux-gnu- +export ARCH ?= arm64 + +#since we have copied the files locally +ACS_DIR ?= ../ + +VAL_SRC = $(ACS_DIR)/val/src +TEST_POOL = $(ACS_DIR)/test_pool + +obj-m += sdei_acs_val.o +sdei_acs_val-objs += $(VAL_SRC)/val_pe.o \ + $(VAL_SRC)/val_sdei_interface.o \ + $(VAL_SRC)/val_misc.o \ + $(VAL_SRC)/val_gic.o \ + $(VAL_SRC)/val_timer.o \ + $(VAL_SRC)/val_timer_support.o \ + $(VAL_SRC)/val_wd_timer.o \ + $(VAL_SRC)/val_test_infra.o \ + $(VAL_SRC)/val_psci.o \ + $(VAL_SRC)/AArch64/PeRegSysSupport.o \ + $(VAL_SRC)/AArch64/ArchTimerSupport.o \ + $(VAL_SRC)/AArch64/event_handler.o \ + $(TEST_POOL)/test_001.o \ + $(TEST_POOL)/test_002.o \ + $(TEST_POOL)/test_003.o \ + $(TEST_POOL)/test_004.o \ + $(TEST_POOL)/test_005.o \ + $(TEST_POOL)/test_006.o \ + $(TEST_POOL)/test_007.o \ + $(TEST_POOL)/test_008.o \ + $(TEST_POOL)/test_009.o \ + $(TEST_POOL)/test_010.o \ + $(TEST_POOL)/test_011.o \ + $(TEST_POOL)/test_012.o \ + $(TEST_POOL)/test_013.o \ + $(TEST_POOL)/test_014.o \ + $(TEST_POOL)/test_015.o \ + $(TEST_POOL)/test_016.o \ + $(TEST_POOL)/test_017.o \ + $(TEST_POOL)/test_018.o \ + $(TEST_POOL)/test_019.o \ + $(TEST_POOL)/test_020.o \ + $(TEST_POOL)/test_021.o \ + $(TEST_POOL)/test_022.o \ + $(TEST_POOL)/test_023.o \ + $(TEST_POOL)/test_024.o \ + $(TEST_POOL)/test_025.o \ + $(TEST_POOL)/test_026.o \ + $(TEST_POOL)/test_027.o \ + $(TEST_POOL)/test_028.o \ + $(TEST_POOL)/test_029.o \ + $(TEST_POOL)/test_030.o \ + $(TEST_POOL)/test_031.o \ + $(TEST_POOL)/test_032.o \ + $(TEST_POOL)/test_033.o \ + $(TEST_POOL)/test_034.o \ + $(TEST_POOL)/test_035.o \ + $(TEST_POOL)/test_036.o \ + $(TEST_POOL)/test_037.o \ + $(TEST_POOL)/test_038.o \ + $(TEST_POOL)/test_039.o \ + $(TEST_POOL)/test_040.o \ + $(TEST_POOL)/test_041.o \ + $(TEST_POOL)/test_042.o \ + $(TEST_POOL)/test_043.o \ + $(TEST_POOL)/test_044.o \ + $(TEST_POOL)/test_045.o \ + $(TEST_POOL)/test_046.o \ + $(TEST_POOL)/test_047.o \ + $(TEST_POOL)/test_048.o \ + $(TEST_POOL)/test_049.o + +ccflags-y=-I$(PWD)/$(ACS_DIR)/val/include -I$(PWD)/$(ACS_DIR)/platform/pal_linux/include -I$(PWD)/$(ACS_DIR)/ -DTARGET_LINUX -Wall -Werror + +all: +ifeq ($(KERNEL_SRC),) + echo " KERNEL_SRC variable should be set to kernel path " + exit 1 +else + echo "Kernel source is set to $(KERNEL_SRC)" +endif + + make -C $(KERNEL_SRC) M=$(PWD) modules + +modules_install: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules_install + +clean: + make -C $(KERNEL_SRC) M=$(PWD) clean diff --git a/sdei/val/SdeiValLib.inf b/sdei/val/SdeiValLib.inf new file mode 100644 index 0000000..56d8bfe --- /dev/null +++ b/sdei/val/SdeiValLib.inf @@ -0,0 +1,50 @@ +## @file +# Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. +# SPDX-License-Identifier : Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SdeiValLib + FILE_GUID = cdd4fb8f-06c5-4a28-8cb8-7f5b664e278c + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = SdeiValLib|UEFI_APPLICATION UEFI_DRIVER + +[Sources.common] + ../ + include/val_interface.h + include/val_sdei_interface.h + include/pal_interface.h + include/val_pe.h + include/val_timer.h + src/val_misc.c + src/val_wd_timer.c + src/val_sdei_interface.c + src/val_pe.c + src/val_gic.c + src/val_timer.c + src/val_timer_support.c + src/val_test_infra.c + src/val_psci.c + src/AArch64/PeRegSysSupport.S + src/AArch64/event_handler.S + src/AArch64/ArchTimerSupport.S + +[Packages] + MdePkg/MdePkg.dec + +[BuildOptions] + GCC:*_*_*_ASM_FLAGS = -march=armv8.2-a diff --git a/sdei/val/include/pal_interface.h b/sdei/val/include/pal_interface.h new file mode 100644 index 0000000..ab76b5a --- /dev/null +++ b/sdei/val/include/pal_interface.h @@ -0,0 +1,278 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#ifndef __PAL_INTERFACE_H +#define __PAL_INTERFACE_H + +#ifdef TARGET_LINUX + #include + typedef uint64_t addr_t; +#else + typedef CHAR8 char8_t; + typedef CHAR16 char16_t; + typedef UINT8 uint8_t; + typedef UINT16 uint16_t; + typedef UINT32 uint32_t; + typedef UINT32 size_t; + typedef UINT64 uint64_t; + typedef INT8 int8_t; + typedef INT16 int16_t; + typedef INT32 int32_t; + typedef INT64 int64_t; + typedef BOOLEAN bool; + typedef UINT64 addr_t; +#endif + +enum sdei_status { + SDEI_STATUS_SUCCESS = 0, + SDEI_STATUS_NOT_SUPPORTED = 0x80000000, + SDEI_STATUS_INVALID, + SDEI_STATUS_DENIED, + SDEI_STATUS_PENDING, + SDEI_STATUS_OUT_OF_RESOURCE, +}; + +#define SDEI_EVENT_TYPE_PRIVATE 0 +#define SDEI_EVENT_TYPE_SHARED 1 +#define SDEI_EVENT_TYPE_ANY 2 +#define SDEI_EVENT_PRIORITY_NORMAL 0 +#define SDEI_EVENT_PRIORITY_CRITICAL 1 +#define SDEI_EVENT_PRIORITY_ANY 2 +#define SDEI_EVENT_UNBOUND 0x10000 + +#define WD_REG_CTRL 0x8 +#define WD_REG_BASE 0x0 + +#define WD_ENABLE 0x1 +#define WD_DISABLE 0x0 + +typedef struct { + uint32_t number; +} event_info_t; + +typedef struct { + uint32_t num_events; + int32_t hest_found; + uint32_t num_ghes_notify; + event_info_t info[]; +} event_info_table_t; + +int pal_invoke_sdei_fn(unsigned long function_id, unsigned long arg0, + unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, + uint64_t *result); + +int pal_sdei_create_event_info_table(event_info_table_t *event_table); +void *pal_intf_alloc(int size); +void pal_intf_free(void *handle); +unsigned int pal_smp_pe_id(void); +void pal_intf_lock(void); +void pal_intf_unlock(void); +void pal_interface_broken(void); +int pal_conduit_get(void); +int pal_acpi_present(void); +void pal_print_raw(char *string, uint64_t data); + +void pal_print(uint32_t verbosity, char *str, ...); + +typedef struct sdei_log_control { + int print_level; + void *log_file_handle; +} sdei_log_control; + +typedef struct { + uint64_t data0; + uint64_t data1; + uint32_t status; +} pe_shared_mem_t; + +/* PE Test related Definitions */ + +/** + * @brief number of PEs discovered +**/ +typedef struct { + uint32_t num_of_pe; +} pe_info_hdr_t; + +/** + * @brief structure instance for PE entry +**/ +typedef struct { + uint32_t pe_num; ///< PE Index + uint32_t attr; ///< PE attributes + uint64_t mpidr; ///< PE MPIDR + uint32_t pmu_gsiv; ///< PMU Interrupt ID +} pe_info_entry_t; + +typedef struct { + pe_info_hdr_t header; + pe_info_entry_t pe_info[]; +} pe_info_table_t; + +typedef enum { + ACS_LOG_ERR = 1, + ACS_LOG_WARN, + ACS_LOG_TEST, + ACS_LOG_DEBUG, + ACS_LOG_INFO, + ACS_LOG_KERNEL +} acs_log_level_t; + +typedef enum { + ACS_SUCCESS, + ACS_ERROR +} acs_status_t; + +void pal_pe_create_info_table(pe_info_table_t *pe_info_table_t); +int pal_pe_execute_on_all(int num_pe, void *payload, uint64_t arg); +void pal_pe_suspend(uint32_t power_state); +void pal_pe_poweroff(uint32_t pe_index); +void pal_pe_poweron(uint64_t pe_mpidr); +acs_status_t pal_pe_alloc_shared_mem(uint32_t num_pe, size_t size); +void pal_pe_free_shared_mem(void); +void pal_pe_clean_up(void); +acs_status_t pal_pe_read_shared_mem(uint32_t index, pe_shared_mem_t *dst); +acs_status_t pal_pe_write_shared_mem(uint32_t index, pe_shared_mem_t *src); +void pal_pe_data_cache_invalidate(uint64_t); +void pal_pe_data_cache_clean_invalidate(uint64_t); + +/** + * @brief GIC Info header - Summary of GIC subsytem +**/ +typedef struct { + uint32_t gic_version; + uint32_t num_gicd; + uint32_t num_gicrd; + uint32_t num_its; +} gic_info_hdr_t; + +typedef enum { + ENTRY_TYPE_CPUIF = 0x1000, + ENTRY_TYPE_GICD, + ENTRY_TYPE_GICRD, + ENTRY_TYPE_GICITS +} gic_info_type_t; + +/** + * @brief structure instance for GIC entry +**/ +typedef struct { + uint32_t type; + uint64_t base; +} gic_info_entry_t; + +/** + * @brief GIC Information Table +**/ +typedef struct { + gic_info_hdr_t header; + gic_info_entry_t gic_info[]; ///< Array of Information blocks - instantiated for each GIC type +} gic_info_table_t; + +void pal_gic_create_info_table(gic_info_table_t *gic_info_table); +uint32_t pal_gic_install_isr(uint32_t int_id, void *isr); +void pal_gic_end_of_interrupt(uint32_t int_id); +uint32_t pal_gic_free_interrupt(uint32_t int_id); + +/** + * @brief Watchdog Info header - Summary of Watchdog subsytem +**/ +typedef struct { + uint32_t num_wd; ///< number of Watchdogs present in the system +} wd_info_hdr_t; + +/** + * @brief structure instance for Watchdog entry +**/ +typedef struct { + uint64_t wd_ctrl_base; ///< Watchdog Control Register Frame + uint64_t wd_refresh_base; ///< Watchdog Refresh Register Frame + uint32_t wd_gsiv; ///< Watchdog Interrupt ID + uint32_t wd_flags; +} wd_info_entry_t; + +/** + * @brief WD Information Table +**/ +typedef struct { + wd_info_hdr_t header; + wd_info_entry_t wd_info[]; +} wd_info_table_t; + +uint32_t pal_wd_create_info_table(wd_info_table_t *wd_info_table); + +/* Timer tests related definitions */ + +/** + * @brief Timer Info header - Summary of Timer subsytem +**/ +typedef struct { + uint32_t s_el1_timer_flag; + uint32_t ns_el1_timer_flag; + uint32_t el2_timer_flag; + uint32_t el2_virt_timer_flag; + uint32_t s_el1_timer_gsiv; + uint32_t ns_el1_timer_gsiv; + uint32_t el2_timer_gsiv; + uint32_t virtual_timer_flag; + uint32_t virtual_timer_gsiv; + uint32_t el2_virt_timer_gsiv; + uint32_t num_platform_timer; + uint32_t num_watchdog; + uint32_t sys_timer_status; +} timer_info_hdr_t; + +#define TIMER_TYPE_SYS_TIMER 0x2001 + +/** + * @brief structure instance for TIMER entry +**/ +typedef struct { + uint32_t type; + uint32_t timer_count; + uint64_t block_cntl_base; + uint8_t frame_num[8]; + uint64_t GtCntBase[8]; + uint64_t GtCntEl0Base[8]; + uint32_t gsiv[8]; + uint32_t virt_gsiv[8]; + uint32_t flags[8]; +} timer_info_gtblock_t; + +typedef struct { + timer_info_hdr_t header; + timer_info_gtblock_t gt_info[]; +} timer_info_table_t; + +void pal_timer_create_info_table(timer_info_table_t *timer_info_table); + +void pal_wd_set_ws0(uint64_t *vaddr, uint64_t base, uint32_t index, uint32_t timeout); +acs_status_t pal_configure_second_interrupt(uint32_t *index, uint64_t *int_id); +void pal_generate_second_interrupt(uint32_t index, uint32_t timeout); +void pal_disable_second_interrupt(uint32_t index); + +uint32_t pal_mmio_read(uint64_t addr); +void pal_mmio_write(uint64_t addr, uint32_t data); +uint64_t *pal_pa_to_va(uint64_t addr); +void pal_va_write(uint64_t *addr, uint32_t offset, uint32_t data); +void pal_va_free(uint64_t *addr); +void pal_free_mem(uint64_t *ptr); + +int32_t pal_invoke_psci_fn(uint64_t function_id, uint64_t arg0, + uint64_t arg1, uint64_t arg2); +#endif diff --git a/sdei/val/include/val_interface.h b/sdei/val/include/val_interface.h new file mode 100644 index 0000000..b336a76 --- /dev/null +++ b/sdei/val/include/val_interface.h @@ -0,0 +1,225 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#ifndef __VAL_INTERFACE_H +#define __VAL_INTERFACE_H + +#include "pal_interface.h" +#include "val_test_infra.h" +#ifdef TARGET_LINUX + #include "pal_linux.h" + #define TRUE 1 + #define FALSE 0 + #define CLIENT_EL 0x1 +#else + #define CLIENT_EL 0x2 +#endif + +#include "val_pe.h" +#define val_print(verbosity, fmt, ...) pal_print(verbosity, fmt, ##__VA_ARGS__) +#define val_print_raw(string, data) pal_print_raw(string, data) +#define GIC_INFO_VERSION 3 +#define EVENT_STATUS_REGISTER_BIT (1 << 0) +#define EVENT_STATUS_ENABLE_BIT (1 << 1) +#define EVENT_STATUS_RUNNING_BIT (1 << 2) +#define __EXTRACT_BITS(data, start, length) ((data >> start) & ((1ul << length)-1)) + +#define PE_MPIDR_LEVEL_BITS 8 +#define PE_MPIDR_LEVEL_MASK ((1 << PE_MPIDR_LEVEL_BITS) - 1) +#define PE_MPIDR_AFFINITY_LEVEL(mpidr, level) \ + ((mpidr >> (PE_MPIDR_LEVEL_BITS * level)) & PE_MPIDR_LEVEL_MASK) +#define INVALID_INDEX 0xFFFFFFFF + +/* Below interrupt numbers used in SDEI testing */ +#define SPI_INTR_NUM 230 +#define SPI_INTR_NUM1 231 +#define PPI_INTR_NUM 18 +#define SGI_INTR_NUM 5 + +extern pe_shared_mem_t *g_pe_shared_mem; + +typedef enum { + MPIDR_EL1 = 1, + ID_AA64PFR0_EL1, + CurrentEL, + DAIF, + SPsel, + ELR_EL, + SPSR_EL, +} pe_reg_id_t; + +int32_t val_sdei_initialization(void); + +acs_status_t +val_sdei_create_event_info_table(uint64_t *event_info_table); +void val_event_free_info_table(void); + +uint32_t +val_pe_get_index(void); + +uint32_t +val_pe_get_num(void); + +acs_status_t +val_pe_execute_on_all(void *payload, uint64_t arg); + +acs_status_t +val_pe_create_info_table(void *); + +void +val_pe_data_cache_clean_invalidate(uint64_t addr); + +void +val_pe_data_cache_invalidate(uint64_t addr); + +void +val_pe_suspend(uint32_t power_state); + +void val_pe_free_info_table(void); +void +val_pe_poweroff(uint32_t pe_index); + +void +val_pe_poweron(uint32_t pe_index); + +acs_status_t +val_shared_mem_alloc(void); + +acs_status_t +val_shared_mem_read(uint32_t index, pe_shared_mem_t *dst); + +acs_status_t +val_shared_mem_write(uint32_t index, pe_shared_mem_t *src); + +void +val_shared_mem_free(void); + +acs_status_t +val_gic_create_info_table(uint64_t *gic_info_table); + +acs_status_t +val_pe_reg_read(pe_reg_id_t reg_id, uint64_t *val); + +void +val_gic_free_info_table(void); + +acs_status_t +val_get_gicd_base(uint64_t *gicd_base); + +acs_status_t +val_gic_get_version(uint32_t *version); + +acs_status_t val_gic_install_isr(uint32_t int_id, void *isr); + +acs_status_t val_gic_end_of_interrupt(uint32_t int_id); + +acs_status_t val_gic_route_interrupt_to_pe(uint32_t int_id, uint64_t mpidr); + +acs_status_t val_gic_get_interrupt_state(uint32_t int_id, uint32_t *status); + +acs_status_t val_gic_clear_interrupt(uint32_t int_id); + +acs_status_t val_gic_disable_interrupt(uint32_t int_id); +acs_status_t val_gic_generate_interrupt(uint32_t int_id); +acs_status_t val_gic_free_interrupt(uint32_t int_id); +uint64_t val_gic_mpidr_to_affinity(uint64_t mpidr); + +/* Watchdog VAL APIs */ +typedef enum { + WD_INFO_COUNT = 1, + WD_INFO_CTRL_BASE, + WD_INFO_REFRESH_BASE, + WD_INFO_GSIV, + WD_INFO_ISSECURE +} WD_INFO_TYPE; + +#define WD_TIME_OUT 0x10000000 +#define TIMEOUT_MEDIUM 0x100000 +int32_t val_wd_create_info_table(uint64_t *wd_info_table); +uint64_t val_wd_get_info(uint32_t index, uint32_t info_type); +void val_wd_enable(uint32_t index); +void val_wd_disable(uint32_t index); +void val_wd_set_ws0(uint64_t *vaddr, uint32_t index, uint32_t timeout); +void val_watchdog_free_info_table(void); + +acs_status_t +val_gic_cpuif_init(void); + +uint32_t +val_mmio_read(uint64_t addr); + +void +val_mmio_write(uint64_t addr, uint32_t data); + +uint64_t *val_pa_to_va(uint64_t addr); +void val_va_write(uint64_t *addr, uint32_t offset, uint32_t data); +void val_va_free(uint64_t *addr); +void val_intf_lock(void); +void val_intf_unlock(void); + +void asm_event_handler(void); +void asm_handler_resume(void); +void asm_handler_resume_context(void); + +/*TIMER VAL APIs */ +typedef enum { + TIMER_INFO_CNTFREQ = 1, + TIMER_INFO_PHY_EL1_INTID, + TIMER_INFO_PHY_EL1_FLAGS, + TIMER_INFO_VIR_EL1_INTID, + TIMER_INFO_VIR_EL1_FLAGS, + TIMER_INFO_PHY_EL2_INTID, + TIMER_INFO_PHY_EL2_FLAGS, + TIMER_INFO_VIR_EL2_INTID, + TIMER_INFO_VIR_EL2_FLAGS, + TIMER_INFO_NUM_PLATFORM_TIMERS, + TIMER_INFO_IS_PLATFORM_TIMER_SECURE, + TIMER_INFO_SYS_CNTL_BASE, + TIMER_INFO_SYS_CNT_BASE_N, + TIMER_INFO_SYS_INTID, + TIMER_INFO_SYS_TIMER_STATUS +} timer_info_t; + +#define SDEI_TIMER_FLAG_ALWAYS_ON 0x4 + +void val_timer_create_info_table(uint64_t *timer_info_table); +void val_timer_free_info_table(void); +uint32_t val_timer_execute_tests(uint32_t level, uint32_t num_pe); +uint64_t val_timer_get_info(timer_info_t info_type, uint64_t instance); +void val_timer_set_phy_el1(uint64_t timeout); +void val_timer_set_vir_el1(uint64_t timeout); +void val_timer_set_phy_el2(uint64_t timeout); +void val_timer_set_vir_el2(uint64_t timeout); +void val_timer_set_system_timer(addr_t cnt_base_n, uint32_t timeout); +void val_timer_disable_system_timer(addr_t cnt_base_n); +void val_timer_free_info_table(void); +uint32_t val_timer_skip_if_cntbase_access_not_allowed(uint64_t index); +void val_platform_timer_get_entry_index(uint64_t instance, uint32_t *block, uint32_t *index); +acs_status_t val_configure_second_interrupt(uint32_t *index, uint64_t *int_id); +void val_generate_second_interrupt(uint32_t index, uint32_t timeout); +void val_disable_second_interrupt(uint32_t index); + +/* PSCI VAL APIs */ +#define PSCI_FN_PSCI_VERSION 0x84000000 +#define PSCI_FN_AFFINITY_INFO 0xC4000004 +#define PSCI_FN_PSCI_FEATURES 0x8400000A +#define PSCI_FN_PSCI_CPU_SUSPEND 0xC400000E + +uint32_t val_psci_version(uint32_t *version); +uint32_t val_psci_affinity_info(uint64_t target_aff, uint64_t lowest_aff_level); +uint32_t val_psci_features(uint32_t fun_id); +#endif diff --git a/sdei/val/include/val_pe.h b/sdei/val/include/val_pe.h new file mode 100644 index 0000000..4455532 --- /dev/null +++ b/sdei/val/include/val_pe.h @@ -0,0 +1,15 @@ +uint64_t ArmReadMpidr(void); +uint64_t ArmReadIdPfr0(void); +uint64_t AA64ReadCurrentEL(void); +uint64_t ArmReadDaif(void); +uint64_t ArmReadSPselPState(void); +uint64_t ArmReadElrEl2(void); +uint64_t ArmReadSpsrEl2(void); +uint64_t ArmReadElrEl1(void); +uint64_t ArmReadSpsrEl1(void); + +acs_status_t val_is_el3_enabled(void); +acs_status_t val_is_el2_enabled(void); +uint64_t val_pe_get_mpid(void); +uint64_t val_pe_get_mpid_index(uint32_t index); +uint32_t val_pe_get_index_mpid(uint64_t mpid); diff --git a/sdei/val/include/val_sdei_interface.h b/sdei/val/include/val_sdei_interface.h new file mode 100644 index 0000000..4a76f01 --- /dev/null +++ b/sdei/val/include/val_sdei_interface.h @@ -0,0 +1,83 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#ifndef __VAL_SDEI_INTERFACE_H +#define __VAL_SDEI_INTERFACE_H + +#include "val_specification.h" + +/* kvm needs to know if hvcs are for SDEI or PSCI */ +#define IS_SDEI_CALL(x) ((x & SDEI_1_0_MASK) == SDEI_1_0_FN_BASE) + +/* Values for sdei_exit_mode */ +#define SDEI_EXIT_HVC 0 +#define SDEI_EXIT_SMC 1 + +#define HEST_FOUND 1 +#define NUM_GHES 2 +#define NUM_EVENTS 3 +#define HEST_NOTIFY 4 + +struct sdei_event { + uint32_t event_num; + uint64_t type; + uint64_t priority; + bool is_bound_irq; +}; + +/* Arch code should override this to set the entry point from firmware... */ +#ifndef sdei_arch_get_entry_point +#define sdei_arch_get_entry_point(conduit) (0) +#endif + +typedef int (sdei_event_callback)(uint32_t event, void *arg); + +int val_sdei_initialization(void); + +uint32_t val_sdei_event_register(uint32_t event_num, uint64_t entry_point, + void *arg, uint64_t flags, uint64_t affinity); +int32_t val_sdei_event_enable(uint32_t event_num); +uint32_t val_sdei_event_disable(uint32_t event_num); +uint32_t val_event_get(uint32_t type, uint32_t priority); +uint32_t val_sdei_event_signal(uint32_t event_num, uint64_t affinity); +uint32_t val_acpi_present(void); +int32_t val_sdei_event_unregister(uint32_t event_num); + +uint32_t val_sdei_event_routing_set(uint32_t event_num, bool directed, int to_cpu); +uint32_t val_sdei_event_routing_get(uint32_t event_num, bool *directed, int *to_cpu); + +int32_t val_sdei_interrupt_bind(uint32_t irq_num, uint32_t *event_num); +int32_t val_sdei_interrupt_release(uint32_t event_num); +int32_t val_sdei_features(uint32_t feature, uint64_t *num_slots); +int32_t val_sdei_get_version(uint64_t *version); + +int32_t val_sdei_event_status(uint32_t event_num, uint64_t *result); +int32_t val_sdei_event_get_info(uint32_t event, uint32_t info, uint64_t *result); +int32_t val_sdei_private_reset(void *ignored); +int32_t val_sdei_shared_reset(void); + +/* For use by arch code when CPU hotplug notifiers are not appropriate. */ +int32_t val_sdei_mask(uint64_t *result); +int32_t val_sdei_unmask(void); + +/* arch code may use this to retrieve the extra registers. */ +int32_t val_sdei_event_context(uint32_t query, uint64_t *result); +int32_t val_sdei_event_complete(uint32_t status_code); +int32_t val_sdei_event_complete_and_resume(uint64_t return_address); + +uint32_t val_event_get_hest_info(uint32_t type, uint64_t *result); +#endif /* __VAL_SDEI_INTERFACE_H */ diff --git a/sdei/val/include/val_specification.h b/sdei/val/include/val_specification.h new file mode 100644 index 0000000..df58f10 --- /dev/null +++ b/sdei/val/include/val_specification.h @@ -0,0 +1,75 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef __VAL_SPECIFICATION_H +#define __VAL_SPECIFICATION_H + +#define SDEI_1_0_FN_BASE 0xC4000020 +#define SDEI_1_0_MASK 0xFFFFFFE0 +#define SDEI_1_0_FN(n) (SDEI_1_0_FN_BASE + (n)) + +#define SDEI_1_0_FN_SDEI_VERSION SDEI_1_0_FN(0x00) +#define SDEI_1_0_FN_SDEI_EVENT_REGISTER SDEI_1_0_FN(0x01) +#define SDEI_1_0_FN_SDEI_EVENT_ENABLE SDEI_1_0_FN(0x02) +#define SDEI_1_0_FN_SDEI_EVENT_DISABLE SDEI_1_0_FN(0x03) +#define SDEI_1_0_FN_SDEI_EVENT_CONTEXT SDEI_1_0_FN(0x04) +#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE SDEI_1_0_FN(0x05) +#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME SDEI_1_0_FN(0x06) +#define SDEI_1_0_FN_SDEI_EVENT_UNREGISTER SDEI_1_0_FN(0x07) +#define SDEI_1_0_FN_SDEI_EVENT_STATUS SDEI_1_0_FN(0x08) +#define SDEI_1_0_FN_SDEI_EVENT_GET_INFO SDEI_1_0_FN(0x09) +#define SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET SDEI_1_0_FN(0x0A) +#define SDEI_1_0_FN_SDEI_PE_MASK SDEI_1_0_FN(0x0B) +#define SDEI_1_0_FN_SDEI_PE_UNMASK SDEI_1_0_FN(0x0C) +#define SDEI_1_0_FN_SDEI_INTERRUPT_BIND SDEI_1_0_FN(0x0D) +#define SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE SDEI_1_0_FN(0x0E) +#define SDEI_1_0_FN_SDEI_EVENT_SIGNAL SDEI_1_0_FN(0x0F) +#define SDEI_1_0_FN_SDEI_FEATURES SDEI_1_0_FN(0x10) +#define SDEI_1_0_FN_SDEI_PRIVATE_RESET SDEI_1_0_FN(0x11) +#define SDEI_1_0_FN_SDEI_SHARED_RESET SDEI_1_0_FN(0x12) + +#define SDEI_VERSION_MAJOR_SHIFT 48 +#define SDEI_VERSION_MAJOR_MASK 0x7fff +#define SDEI_VERSION_MINOR_SHIFT 32 +#define SDEI_VERSION_MINOR_MASK 0xffff +#define SDEI_VERSION_VENDOR_SHIFT 0 +#define SDEI_VERSION_VENDOR_MASK 0xffffffff + +#define SDEI_VERSION_MAJOR(x) (x>>SDEI_VERSION_MAJOR_SHIFT & SDEI_VERSION_MAJOR_MASK) +#define SDEI_VERSION_MINOR(x) (x>>SDEI_VERSION_MINOR_SHIFT & SDEI_VERSION_MINOR_MASK) +#define SDEI_VERSION_VENDOR(x) (x>>SDEI_VERSION_VENDOR_SHIFT & SDEI_VERSION_VENDOR_MASK) + +/* EVENT_REGISTER flags */ +#define SDEI_EVENT_REGISTER_RM_ANY 0 +#define SDEI_EVENT_REGISTER_RM_PE 1 + +/* EVENT_STATUS return value bits */ +#define SDEI_EVENT_STATUS_RUNNING 2 +#define SDEI_EVENT_STATUS_ENABLED 1 +#define SDEI_EVENT_STATUS_REGISTERED 0 + +/* EVENT_COMPLETE status values */ +#define SDEI_EV_HANDLED 0 +#define SDEI_EV_FAILED 1 + +/* GET_INFO values */ +#define SDEI_EVENT_INFO_EV_TYPE 0 +#define SDEI_EVENT_INFO_EV_SIGNALED 1 +#define SDEI_EVENT_INFO_EV_PRIORITY 2 +#define SDEI_EVENT_INFO_EV_ROUTING_MODE 3 +#define SDEI_EVENT_INFO_EV_ROUTING_AFF 4 + +#endif /* __VAL_SPECIFICATION_H */ diff --git a/sdei/val/include/val_test_infra.h b/sdei/val/include/val_test_infra.h new file mode 100644 index 0000000..42b7137 --- /dev/null +++ b/sdei/val/include/val_test_infra.h @@ -0,0 +1,219 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#define SDEI_TEST_PASS 0x0 +#define SDEI_TEST_PENDING 0x2 +#define SDEI_TEST_TIMEOUT 0x4 +#define SDEI_TEST_FAIL 0x1 +#define SDEI_TEST_ERROR 0x3 +#define SDEI_TEST_ABORT 0x5 +#define SDEI_TEST_SKIP 0x7 + +#define SDEI_NUM_TESTS 49 + +#define PE_INFO_TABLE_SZ 8192 +#define GIC_INFO_TABLE_SZ 8192 +#define EVENT_INFO_TABLE_SZ 64 +#define WD_INFO_TABLE_SZ 512 +#define TIMER_INFO_TABLE_SZ 1024 + +#define TEST_NONE_ID 0 +#define SDEI_PUBLISH_TEST(test, id, desc, deps, entry, all_pe) \ + sdei_test_desc test = {id, desc, deps, SDEI_TEST_PENDING, entry, all_pe} +#define SDEI_DECLARE_TEST(test) extern sdei_test_desc test +#define SDEI_SET_TEST_DEPS(deps, ...) static sdei_test_deps deps[] = {__VA_ARGS__, TEST_NONE_ID} + +#define TEST_TIMEOUT 0x10000 + +typedef void (*sdei_test_fn)(void); +typedef uint32_t sdei_test_deps; + +typedef struct sdei_test_desc { + uint32_t id; + char description[124]; + sdei_test_deps *deps; + uint32_t status; + sdei_test_fn test_fn; + int32_t all_pe; +} sdei_test_desc; + +typedef uint64_t test_flags; + +typedef struct sdei_test_control { + test_flags flags[2]; //which tests to run? + uint32_t tests_skipped; + uint32_t tests_passed; + uint32_t tests_failed; + uint32_t tests_aborted; +} sdei_test_control; + +void val_test_init(sdei_test_control *); +void val_test_execute(sdei_test_control *); +void val_test_disable(sdei_test_control *, int); +void val_test_run_specific(sdei_test_control *, int, int); + +void val_test_pe_set_status(uint32_t index, uint32_t status); +void val_test_set_status(uint32_t num_pe, uint32_t status); +uint32_t val_test_pe_get_status(uint32_t index); +uint32_t val_test_get_status(uint32_t num_pe, uint64_t timeout); + +#define TEST_001_ID 1 +SDEI_DECLARE_TEST(test_001); + +#define TEST_002_ID 2 +SDEI_DECLARE_TEST(test_002); + +#define TEST_003_ID 3 +SDEI_DECLARE_TEST(test_003); + +#define TEST_004_ID 4 +SDEI_DECLARE_TEST(test_004); + +#define TEST_005_ID 5 +SDEI_DECLARE_TEST(test_005); + +#define TEST_006_ID 6 +SDEI_DECLARE_TEST(test_006); + +#define TEST_007_ID 7 +SDEI_DECLARE_TEST(test_007); + +#define TEST_008_ID 8 +SDEI_DECLARE_TEST(test_008); + +#define TEST_009_ID 9 +SDEI_DECLARE_TEST(test_009); + +#define TEST_010_ID 10 +SDEI_DECLARE_TEST(test_010); + +#define TEST_011_ID 11 +SDEI_DECLARE_TEST(test_011); + +#define TEST_012_ID 12 +SDEI_DECLARE_TEST(test_012); + +#define TEST_013_ID 13 +SDEI_DECLARE_TEST(test_013); + +#define TEST_014_ID 14 +SDEI_DECLARE_TEST(test_014); + +#define TEST_015_ID 15 +SDEI_DECLARE_TEST(test_015); + +#define TEST_016_ID 16 +SDEI_DECLARE_TEST(test_016); + +#define TEST_017_ID 17 +SDEI_DECLARE_TEST(test_017); + +#define TEST_018_ID 18 +SDEI_DECLARE_TEST(test_018); + +#define TEST_019_ID 19 +SDEI_DECLARE_TEST(test_019); + +#define TEST_020_ID 20 +SDEI_DECLARE_TEST(test_020); + +#define TEST_021_ID 21 +SDEI_DECLARE_TEST(test_021); + +#define TEST_022_ID 22 +SDEI_DECLARE_TEST(test_022); + +#define TEST_023_ID 23 +SDEI_DECLARE_TEST(test_023); + +#define TEST_024_ID 24 +SDEI_DECLARE_TEST(test_024); + +#define TEST_025_ID 25 +SDEI_DECLARE_TEST(test_025); + +#define TEST_026_ID 26 +SDEI_DECLARE_TEST(test_026); + +#define TEST_027_ID 27 +SDEI_DECLARE_TEST(test_027); + +#define TEST_028_ID 28 +SDEI_DECLARE_TEST(test_028); + +#define TEST_029_ID 29 +SDEI_DECLARE_TEST(test_029); + +#define TEST_030_ID 30 +SDEI_DECLARE_TEST(test_030); + +#define TEST_031_ID 31 +SDEI_DECLARE_TEST(test_031); + +#define TEST_032_ID 32 +SDEI_DECLARE_TEST(test_032); + +#define TEST_033_ID 33 +SDEI_DECLARE_TEST(test_033); + +#define TEST_034_ID 34 +SDEI_DECLARE_TEST(test_034); + +#define TEST_035_ID 35 +SDEI_DECLARE_TEST(test_035); + +#define TEST_036_ID 36 +SDEI_DECLARE_TEST(test_036); + +#define TEST_037_ID 37 +SDEI_DECLARE_TEST(test_037); + +#define TEST_038_ID 38 +SDEI_DECLARE_TEST(test_038); + +#define TEST_039_ID 39 +SDEI_DECLARE_TEST(test_039); + +#define TEST_040_ID 40 +SDEI_DECLARE_TEST(test_040); + +#define TEST_041_ID 41 +SDEI_DECLARE_TEST(test_041); + +#define TEST_042_ID 42 +SDEI_DECLARE_TEST(test_042); + +#define TEST_043_ID 43 +SDEI_DECLARE_TEST(test_043); + +#define TEST_044_ID 44 +SDEI_DECLARE_TEST(test_044); + +#define TEST_045_ID 45 +SDEI_DECLARE_TEST(test_045); + +#define TEST_046_ID 46 +SDEI_DECLARE_TEST(test_046); + +#define TEST_047_ID 47 +SDEI_DECLARE_TEST(test_047); + +#define TEST_048_ID 48 +SDEI_DECLARE_TEST(test_048); + +#define TEST_049_ID 49 +SDEI_DECLARE_TEST(test_049); diff --git a/sdei/val/include/val_timer.h b/sdei/val/include/val_timer.h new file mode 100644 index 0000000..c129cff --- /dev/null +++ b/sdei/val/include/val_timer.h @@ -0,0 +1,86 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#ifndef __VAL_TIMER_H +#define __VAL_TIMER_H + +#define ARM_ARCH_TIMER_ENABLE (1 << 0) +#define ARM_ARCH_TIMER_IMASK (1 << 1) +#define ARM_ARCH_TIMER_ISTATUS (1 << 2) + +typedef enum { + CntFrq = 0, + CntPct, + CntkCtl, + CntpTval, + CntpCtl, + CntvTval, + CntvCtl, + CntvCt, + CntpCval, + CntvCval, + CntvOff, + CnthCtl, + CnthpTval, + CnthpCtl, + CnthpCval, + CnthvTval, + CnthvCtl, + CnthvCval, + RegMaximum +} ARM_ARCH_TIMER_REGS; + + +uint64_t ArmArchTimerReadReg (ARM_ARCH_TIMER_REGS Reg); +void ArmArchTimerWriteReg (ARM_ARCH_TIMER_REGS Reg, uint64_t *data_buf); + +uint64_t ArmReadCntFrq (void); +void ArmWriteCntFrq (uint64_t FreqInHz); +uint64_t ArmReadCntPct (void); + +uint64_t ArmReadCntkCtl (void); +void ArmWriteCntkCtl (uint64_t Val); +uint64_t ArmReadCntpTval (void); +void ArmWriteCntpTval (uint64_t Val); + +uint64_t ArmReadCntpCtl (void); +void ArmWriteCntpCtl (uint64_t Val); +uint64_t ArmReadCntvTval (void); +void ArmWriteCntvTval (uint64_t Val); + +uint64_t ArmReadCntvCtl (void); +void ArmWriteCntvCtl (uint64_t Val); +uint64_t ArmReadCntvCt (void); +uint64_t ArmReadCntpCval (void); +void ArmWriteCntpCval (uint64_t Val); + +uint64_t ArmReadCntvCval (void); +void ArmWriteCntvCval (uint64_t Val); +uint64_t ArmReadCntvOff (void); +void ArmWriteCntvOff (uint64_t Val); + +uint64_t ArmReadCnthpCtl (void); +void ArmWriteCnthpCtl (uint64_t Val); +uint64_t ArmReadCnthpTval (void); +void ArmWriteCnthpTval (uint64_t Val); + +uint64_t ArmReadCnthvCtl (void); +void ArmWriteCnthvCtl (uint64_t Val); +uint64_t ArmReadCnthvTval (void); +void ArmWriteCnthvTval (uint64_t Val); + +#endif // __VAL_TIMER_H diff --git a/sdei/val/src/AArch64/ArchTimerSupport.S b/sdei/val/src/AArch64/ArchTimerSupport.S new file mode 100644 index 0000000..75edb06 --- /dev/null +++ b/sdei/val/src/AArch64/ArchTimerSupport.S @@ -0,0 +1,210 @@ +#/** @file +# Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. +# SPDX-License-Identifier : Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#**/ + +// +// Private worker functions for ASM_PFX() +// +#define _CONCATENATE(a, b) __CONCATENATE(a, b) +#define __CONCATENATE(a, b) a ## b + +#define __USER_LABEL_PREFIX__ +// +// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix +// on symbols in assembly language. +// +#define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name) + +#define GCC_ASM_EXPORT(func__) \ + .global _CONCATENATE (__USER_LABEL_PREFIX__, func__) ;\ + .type ASM_PFX(func__), %function + +.text +.align 2 + +GCC_ASM_EXPORT(ArmReadCntFrq) +GCC_ASM_EXPORT(ArmReadCntPct) +GCC_ASM_EXPORT(ArmReadCntkCtl) +GCC_ASM_EXPORT(ArmWriteCntkCtl) +GCC_ASM_EXPORT(ArmReadCntpTval) +GCC_ASM_EXPORT(ArmWriteCntpTval) +GCC_ASM_EXPORT(ArmReadCntpCtl) +GCC_ASM_EXPORT(ArmWriteCntpCtl) +GCC_ASM_EXPORT(ArmReadCntvTval) +GCC_ASM_EXPORT(ArmWriteCntvTval) +GCC_ASM_EXPORT(ArmReadCntvCtl) +GCC_ASM_EXPORT(ArmWriteCntvCtl) +GCC_ASM_EXPORT(ArmReadCntvCt) +GCC_ASM_EXPORT(ArmReadCntpCval) +GCC_ASM_EXPORT(ArmWriteCntpCval) +GCC_ASM_EXPORT(ArmReadCntvCval) +GCC_ASM_EXPORT(ArmWriteCntvCval) +GCC_ASM_EXPORT(ArmReadCntvOff) +GCC_ASM_EXPORT(ArmWriteCntvOff) +GCC_ASM_EXPORT(ArmReadCnthpCtl) +GCC_ASM_EXPORT(ArmWriteCnthpCtl) +GCC_ASM_EXPORT(ArmReadCnthpTval) +GCC_ASM_EXPORT(ArmWriteCnthpTval) +//GCC_ASM_EXPORT(ArmReadCnthvCtl) +//GCC_ASM_EXPORT(ArmWriteCnthvCtl) +//GCC_ASM_EXPORT(ArmReadCnthvTval) +//GCC_ASM_EXPORT(ArmWriteCnthvTval) + +ASM_PFX(ArmReadCntFrq): + mrs x0, cntfrq_el0 // Read CNTFRQ + ret + + +ASM_PFX(ArmReadCntPct): + mrs x0, cntpct_el0 // Read CNTPCT (Physical counter register) + ret + + +ASM_PFX(ArmReadCntkCtl): + mrs x0, cntkctl_el1 // Read CNTK_CTL (Timer PL1 Control Register) + ret + + +ASM_PFX(ArmWriteCntkCtl): + msr cntkctl_el1, x0 // Write to CNTK_CTL (Timer PL1 Control Register) + isb + ret + + +ASM_PFX(ArmReadCntpTval): + mrs x0, cntp_tval_el0 // Read CNTP_TVAL (PL1 physical timer value register) + ret + + +ASM_PFX(ArmWriteCntpTval): + msr cntp_tval_el0, x0 // Write to CNTP_TVAL (PL1 physical timer value register) + isb + ret + + +ASM_PFX(ArmReadCntpCtl): + mrs x0, cntp_ctl_el0 // Read CNTP_CTL (PL1 Physical Timer Control Register) + ret + + +ASM_PFX(ArmWriteCntpCtl): + msr cntp_ctl_el0, x0 // Write to CNTP_CTL (PL1 Physical Timer Control Register) + isb + ret + + +ASM_PFX(ArmReadCntvTval): + mrs x0, cntv_tval_el0 // Read CNTV_TVAL (Virtual Timer Value register) + ret + + +ASM_PFX(ArmWriteCntvTval): + msr cntv_tval_el0, x0 // Write to CNTV_TVAL (Virtual Timer Value register) + isb + ret + + +ASM_PFX(ArmReadCntvCtl): + mrs x0, cntv_ctl_el0 // Read CNTV_CTL (Virtual Timer Control Register) + ret + + +ASM_PFX(ArmWriteCntvCtl): + msr cntv_ctl_el0, x0 // Write to CNTV_CTL (Virtual Timer Control Register) + isb + ret + + +ASM_PFX(ArmReadCntvCt): + mrs x0, cntvct_el0 // Read CNTVCT (Virtual Count Register) + ret + + +ASM_PFX(ArmReadCntpCval): + mrs x0, cntp_cval_el0 // Read CNTP_CTVAL (Physical Timer Compare Value Register) + ret + + +ASM_PFX(ArmWriteCntpCval): + msr cntp_cval_el0, x0 // Write to CNTP_CTVAL (Physical Timer Compare Value Register) + isb + ret + + +ASM_PFX(ArmReadCntvCval): + mrs x0, cntv_cval_el0 // Read CNTV_CTVAL (Virtual Timer Compare Value Register) + ret + + +ASM_PFX(ArmWriteCntvCval): + msr cntv_cval_el0, x0 // write to CNTV_CTVAL (Virtual Timer Compare Value Register) + isb + ret + + +ASM_PFX(ArmReadCntvOff): + mrs x0, cntvoff_el2 // Read CNTVOFF (virtual Offset register) + ret + + +ASM_PFX(ArmWriteCntvOff): + msr cntvoff_el2, x0 // Write to CNTVOFF (Virtual Offset register) + isb + ret + +ASM_PFX(ArmReadCnthpCtl): + mrs x0, cnthp_ctl_el2 + ret + + +ASM_PFX(ArmWriteCnthpCtl): + msr cnthp_ctl_el2, x0 + isb + ret + +ASM_PFX(ArmReadCnthpTval): + mrs x0, cnthp_tval_el2 + ret + + +ASM_PFX(ArmWriteCnthpTval): + msr cnthp_tval_el2, x0 + isb + ret + +//ASM_PFX(ArmReadCnthvCtl): +// mrs x0, cnthv_ctl_el2 +// ret +// +// +//ASM_PFX(ArmWriteCnthvCtl): +// msr cnthv_ctl_el2, x0 +// isb +// ret +// +//ASM_PFX(ArmReadCnthvTval): +// mrs x0, cnthv_tval_el2 +// ret +// +// +//ASM_PFX(ArmWriteCnthvTval): +// msr cnthv_tval_el2, x0 +// isb +// ret +// +// +//ASM_FUNCTION_REMOVE_IF_UNREFERENCED diff --git a/sdei/val/src/AArch64/PeRegSysSupport.S b/sdei/val/src/AArch64/PeRegSysSupport.S new file mode 100644 index 0000000..e2f6ec1 --- /dev/null +++ b/sdei/val/src/AArch64/PeRegSysSupport.S @@ -0,0 +1,416 @@ +#/** @file +# Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. +# SPDX-License-Identifier : Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#**/ + +// +// Private worker functions for ASM_PFX() +// +#define _CONCATENATE(a, b) __CONCATENATE(a, b) +#define __CONCATENATE(a, b) a ## b + +#define __USER_LABEL_PREFIX__ +// +// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix +// on symbols in assembly language. +// +#define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name) + +#define GCC_ASM_EXPORT(func__) \ + .global _CONCATENATE (__USER_LABEL_PREFIX__, func__) ;\ + .type ASM_PFX(func__), %function + + +.text +.align 3 + + +GCC_ASM_EXPORT (ArmReadMpidr) +GCC_ASM_EXPORT (ArmReadIdPfr0) +GCC_ASM_EXPORT (ArmReadIdPfr1) +GCC_ASM_EXPORT (AA64ReadMmfr0) +GCC_ASM_EXPORT (AA64ReadMmfr1) +//GCC_ASM_EXPORT (AA64ReadMmfr2) +GCC_ASM_EXPORT (AA64ReadCtr) +GCC_ASM_EXPORT (ArmReadMmfr0) +GCC_ASM_EXPORT (AA64ReadIsar0) +GCC_ASM_EXPORT (AA64ReadIsar1) +GCC_ASM_EXPORT (AA64ReadSctlr3) +GCC_ASM_EXPORT (AA64ReadSctlr2) +GCC_ASM_EXPORT (AA64ReadPmcr) +GCC_ASM_EXPORT (AA64ReadIdDfr0) +GCC_ASM_EXPORT (AA64ReadIdDfr1) +GCC_ASM_EXPORT (ArmReadHcr) +GCC_ASM_EXPORT (AA64ReadCurrentEL) +//GCC_ASM_EXPORT (AA64ReadIdMdrar) +GCC_ASM_EXPORT (AA64ReadMdcr2) +GCC_ASM_EXPORT (AA64WriteMdcr2) +GCC_ASM_EXPORT (AA64ReadVbar2) +GCC_ASM_EXPORT (AA64WriteVbar2) +GCC_ASM_EXPORT (AA64WritePmcr) +GCC_ASM_EXPORT (AA64WritePmovsset) +GCC_ASM_EXPORT (AA64WritePmintenset) +GCC_ASM_EXPORT (AA64WritePmovsclr) +GCC_ASM_EXPORT (AA64WritePmintenclr) +GCC_ASM_EXPORT (AA64ReadCcsidr) +GCC_ASM_EXPORT (AA64ReadClidr) +GCC_ASM_EXPORT (ArmReadDfr0) +GCC_ASM_EXPORT (ArmReadIsar0) +GCC_ASM_EXPORT (ArmReadIsar1) +GCC_ASM_EXPORT (ArmReadIsar2) +GCC_ASM_EXPORT (ArmReadIsar3) +GCC_ASM_EXPORT (ArmReadIsar4) +GCC_ASM_EXPORT (ArmReadIsar5) +GCC_ASM_EXPORT (ArmReadMmfr0) +GCC_ASM_EXPORT (ArmReadMmfr1) +GCC_ASM_EXPORT (ArmReadMmfr2) +GCC_ASM_EXPORT (ArmReadMmfr3) +GCC_ASM_EXPORT (ArmReadMmfr4) +GCC_ASM_EXPORT (ArmReadPfr0) +GCC_ASM_EXPORT (ArmReadPfr1) +GCC_ASM_EXPORT (ArmReadMidr) +GCC_ASM_EXPORT (ArmReadMvfr0) +GCC_ASM_EXPORT (ArmReadMvfr1) +GCC_ASM_EXPORT (ArmReadMvfr2) +GCC_ASM_EXPORT (AA64ReadPmceid0) +GCC_ASM_EXPORT (AA64ReadPmceid1) +GCC_ASM_EXPORT (AA64ReadVmpidr) +GCC_ASM_EXPORT (AA64ReadVpidr) +GCC_ASM_EXPORT (AA64ReadPmbidr) +GCC_ASM_EXPORT (AA64ReadPmsidr) +GCC_ASM_EXPORT (AA64ReadLorid) +GCC_ASM_EXPORT (AA64ReadErridr) +GCC_ASM_EXPORT (AA64ReadErr0fr) +GCC_ASM_EXPORT (AA64ReadErr1fr) +GCC_ASM_EXPORT (AA64ReadErr2fr) +GCC_ASM_EXPORT (AA64ReadErr3fr) +GCC_ASM_EXPORT (AA64WritePmsirr) +GCC_ASM_EXPORT (AA64WritePmscr2) +GCC_ASM_EXPORT (AA64WritePmsfcr) +GCC_ASM_EXPORT (AA64WritePmbptr) +GCC_ASM_EXPORT (AA64WritePmblimitr) +GCC_ASM_EXPORT (AA64ReadEsr2) +GCC_ASM_EXPORT (AA64ReadSp) +GCC_ASM_EXPORT (AA64WriteSp) +GCC_ASM_EXPORT (AA64ReadFar2) +GCC_ASM_EXPORT (ArmReadDaif) +GCC_ASM_EXPORT (ArmReadSPselPState) +GCC_ASM_EXPORT (ArmReadElrEl2) +GCC_ASM_EXPORT (ArmReadSpsrEl2) +GCC_ASM_EXPORT (ArmReadElrEl1) +GCC_ASM_EXPORT (ArmReadSpsrEl1) + +ASM_PFX(ArmReadMpidr): + mrs x0, mpidr_el1 // read EL1 MPIDR + ret + +ASM_PFX(ArmReadIdPfr0): + mrs x0, id_aa64pfr0_el1 // Read ID_AA64PFR0 Register + ret + +ASM_PFX(ArmReadIdPfr1): + mrs x0, id_aa64pfr1_el1 // Read ID_AA64PFR0 Register + ret + +ASM_PFX(AA64ReadMmfr0): + mrs x0, id_aa64mmfr0_el1 + ret + +ASM_PFX(AA64ReadMmfr1): + mrs x0, id_aa64mmfr1_el1 + ret + +//ASM_PFX(AA64ReadMmfr2): +// mrs x0, id_aa64mmfr2_el1 +// ret + +ASM_PFX(AA64ReadCtr): + mrs x0, ctr_el0 + ret + +ASM_PFX(AA64ReadIsar0): + mrs x0, id_aa64isar0_el1 + ret + +ASM_PFX(AA64ReadIsar1): + mrs x0, id_aa64isar1_el1 + ret + +ASM_PFX(AA64ReadSctlr3): + mrs x0, sctlr_el3 + ret + +ASM_PFX(AA64ReadSctlr2): + mrs x0, sctlr_el2 + ret + +ASM_PFX(AA64ReadPmcr): + mrs x0, pmcr_el0 + ret + +ASM_PFX(AA64ReadIdDfr0): + mrs x0, id_aa64dfr0_el1 + ret + +ASM_PFX(AA64ReadIdDfr1): + mrs x0, id_aa64dfr1_el1 + ret + +// UINTN ArmReadHcr(VOID) +ASM_PFX(ArmReadHcr): + mrs x0, hcr_el2 + ret + +ASM_PFX(AA64ReadCurrentEL): + mrs x0, CurrentEL + ret + +ASM_PFX(AA64ReadMdcr2): + mrs x0, mdcr_el2 + ret + +ASM_PFX(AA64WriteMdcr2): + msr mdcr_el2, x0 + isb + ret + +ASM_PFX(AA64ReadVbar2): + mrs x0, vbar_el2 + ret + +ASM_PFX(AA64WriteVbar2): + msr vbar_el2, x0 + isb + ret + +ASM_PFX(AA64WritePmcr): + msr pmcr_el0, x0 + isb + ret + +ASM_PFX(AA64WritePmovsset): + msr pmovsset_el0, x0 + isb + ret + +ASM_PFX(AA64WritePmovsclr): + msr pmovsclr_el0, x0 + isb + ret + +ASM_PFX(AA64WritePmintenset): + msr pmintenset_el1, x0 + isb + ret + +ASM_PFX(AA64WritePmintenclr): + msr pmintenclr_el1, x0 + isb + ret + +ASM_PFX(AA64ReadCcsidr): + mrs x0, ccsidr_el1 + ret + +ASM_PFX(AA64ReadClidr): + mrs x0, clidr_el1 + ret + +ASM_PFX(ArmReadDfr0): + mrs x0, id_dfr0_el1 + ret + +ASM_PFX(ArmReadIsar0): + mrs x0, id_isar0_el1 + ret + +ASM_PFX(ArmReadIsar1): + mrs x0, id_isar1_el1 + ret + +ASM_PFX(ArmReadIsar2): + mrs x0, id_isar2_el1 + ret + +ASM_PFX(ArmReadIsar3): + mrs x0, id_isar3_el1 + ret + +ASM_PFX(ArmReadIsar4): + mrs x0, id_isar4_el1 + ret + +ASM_PFX(ArmReadIsar5): + mrs x0, id_isar5_el1 + ret + +ASM_PFX(ArmReadMmfr0): + mrs x0, id_mmfr0_el1 + ret + +ASM_PFX(ArmReadMmfr1): + mrs x0, id_mmfr1_el1 + ret + +ASM_PFX(ArmReadMmfr2): + mrs x0, id_mmfr2_el1 + ret + +ASM_PFX(ArmReadMmfr3): + mrs x0, id_mmfr3_el1 + ret + +ASM_PFX(ArmReadMmfr4): + //mrs x0, id_mmfr4_el1 + ret + +ASM_PFX(ArmReadPfr0): + mrs x0, id_pfr0_el1 + ret + +ASM_PFX(ArmReadPfr1): + mrs x0, id_pfr1_el1 + ret + +ASM_PFX(ArmReadMidr): + mrs x0, midr_el1 + ret + +ASM_PFX(ArmReadMvfr0): + mrs x0, mvfr0_el1 + ret + +ASM_PFX(ArmReadMvfr1): + mrs x0, mvfr1_el1 + ret + +ASM_PFX(ArmReadMvfr2): + mrs x0, mvfr2_el1 + ret + +ASM_PFX(AA64ReadPmceid0): + mrs x0, pmceid0_el0 + ret + +ASM_PFX(AA64ReadPmceid1): + mrs x0, pmceid1_el0 + ret + +ASM_PFX(AA64ReadVmpidr): + mrs x0, vmpidr_el2 + ret + +ASM_PFX(AA64ReadVpidr): + mrs x0, vpidr_el2 + ret + +ASM_PFX(AA64ReadPmbidr): + //mrs x0, pmbidr_el1 + ret + +ASM_PFX(AA64ReadPmsidr): + //mrs x0, pmsidr_el1 + ret + +ASM_PFX(AA64ReadLorid): + //mrs x0, lorid_el1 + ret + +ASM_PFX(AA64ReadErridr): + //mrs x0, erridr_el1 + ret + +ASM_PFX(AA64ReadErr0fr): + // mrs x0, err0fr_el1 + ret + +ASM_PFX(AA64ReadErr1fr): + //mrs x0, err1fr_el1 + ret + +ASM_PFX(AA64ReadErr2fr): + //mrs x0, err2fr_el1 + ret + +ASM_PFX(AA64ReadErr3fr): + //mrs x0, err3fr_el1 + ret + +ASM_PFX(AA64WritePmsirr): + //mrs pmsirr_el1,x0 + isb + ret + +ASM_PFX(AA64WritePmscr2): + //mrs pmscr_el2,x0 + isb + ret + +ASM_PFX(AA64WritePmsfcr): + //mrs pmsfcr_el1,x0 + isb + ret + +ASM_PFX(AA64WritePmbptr): + //mrs pmbptr_el1,x0 + isb + ret + +ASM_PFX(AA64WritePmblimitr): + //mrs pmblimitr_el1,x0 + isb + ret + +ASM_PFX(AA64ReadEsr2): + mrs x0, esr_el2 + ret + +ASM_PFX(AA64ReadSp): + mov x0, sp + ret + +ASM_PFX(AA64WriteSp): + mov sp, x0 + ret + +ASM_PFX(AA64ReadFar2): + mrs x0, far_el2 + ret + +ASM_PFX(ArmReadDaif): + mrs x0, daif + ret + +ASM_PFX(ArmReadSPselPState): + mrs x0, SPsel + ret + +ASM_PFX(ArmReadElrEl2): + mrs x0, elr_el2 + ret + +ASM_PFX(ArmReadSpsrEl2): + mrs x0, spsr_el2 + ret + +ASM_PFX(ArmReadElrEl1): + mrs x0, elr_el1 + ret + +ASM_PFX(ArmReadSpsrEl1): + mrs x0, spsr_el1 + ret + diff --git a/sdei/val/src/AArch64/event_handler.S b/sdei/val/src/AArch64/event_handler.S new file mode 100644 index 0000000..1db7ad8 --- /dev/null +++ b/sdei/val/src/AArch64/event_handler.S @@ -0,0 +1,79 @@ +#/** @file +# Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. +# SPDX-License-Identifier : Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#**/ + +// +// Private worker functions for ASM_PFX() +// +#define _CONCATENATE(a, b) __CONCATENATE(a, b) +#define __CONCATENATE(a, b) a ## b + +#define __USER_LABEL_PREFIX__ +// +// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix +// on symbols in assembly language. +// +#define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name) + +#define GCC_ASM_EXPORT(func__) \ + .global _CONCATENATE (__USER_LABEL_PREFIX__, func__) ;\ + .type ASM_PFX(func__), %function + +#define SDEI_EVENT_COMPLETE 0xc4000025 +#define SDEI_EVENT_COMPLETE_RESUME 0xc4000026 + +.text +.align 3 + +.extern g_interrupted_pc +.extern g_interrupted_pstate + +GCC_ASM_EXPORT (asm_event_handler) +GCC_ASM_EXPORT (asm_handler_resume) +GCC_ASM_EXPORT (asm_handler_resume_context) + +ASM_PFX(asm_event_handler): + stp x29, x30, [sp, #-128]! + mov x29, sp + + blr x1 + + ldp x29, x30, [sp], #128 + ldr x0, =SDEI_EVENT_COMPLETE + mov x1, #0 + smc #0 + +ASM_PFX(asm_handler_resume): + stp x29, x30, [sp, #-32]! + mov x29, sp + + ldp x29, x30, [sp], #32 + ldr x0, =SDEI_EVENT_COMPLETE_RESUME + smc #0 + +ASM_PFX(asm_handler_resume_context): + stp x29, x30, [sp, #-32]! + mov x29, sp + + ldr x0, =g_interrupted_pc + str x2, [x0] + ldr x0, =g_interrupted_pstate + str x3, [x0] + + ldp x29, x30, [sp], #32 + ldr x0, =SDEI_EVENT_COMPLETE_RESUME + smc #0 diff --git a/sdei/val/src/val_gic.c b/sdei/val/src/val_gic.c new file mode 100644 index 0000000..f1f3ba3 --- /dev/null +++ b/sdei/val/src/val_gic.c @@ -0,0 +1,417 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include "val_interface.h" + +#define GICD_CLRSPI_NSR 0x048 +#define GICD_CLRLPIR 0x048 +#define GICD_ISENABLER 0x100 +#define GICD_ICENABLER 0x180 +#define GICD_ISPENDR 0x200 +#define GICD_ISACTIVER0 0x300 +#define GICD_ICPENDR0 0x280 +#define GICD_ICACTIVER0 0x380 +#define GICD_IROUTER 0x6000 + +#define SZ_64KB 0x10000 + +typedef struct gic_intr_info { + uint32_t mask; + uint64_t base; +} gic_intr_t; + +gic_info_table_t *g_gic_info_table; +static uint64_t g_gicd_base; + +acs_status_t set_gicd_base(void) +{ + gic_info_entry_t *gic_entry; + + gic_entry = g_gic_info_table->gic_info; + + while (gic_entry->type != 0xFF) { + if (gic_entry->type == ENTRY_TYPE_GICD) { + g_gicd_base = gic_entry->base; + return ACS_SUCCESS; + } + gic_entry++; + } + return ACS_ERROR; +} + +/** + * @brief This API will call PAL layer to fill in the GIC information + * into the g_gic_info_table pointer. + * 1. Caller - Application layer. + * 2. Prerequisite - Memory allocated and passed as argument. + * @param gic_info_table pre-allocated memory pointer for gic_info + * @return Error if Input param is NULL + */ +acs_status_t val_gic_create_info_table(uint64_t *gic_info_table) +{ + if (gic_info_table == NULL) { + val_print(ACS_LOG_ERR, "\n Input for Create Info table cannot be NULL"); + return ACS_ERROR; + } + + g_gic_info_table = (gic_info_table_t *)gic_info_table; + + pal_gic_create_info_table(g_gic_info_table); + + val_print(ACS_LOG_TEST, "\n GIC_INFO: Number of GICD : %4d", + g_gic_info_table->header.num_gicd); + val_print(ACS_LOG_TEST, "\n GIC_INFO: Number of ITS : %4d", + g_gic_info_table->header.num_its); + + if (g_gic_info_table->header.num_gicd == 0) { + val_print(ACS_LOG_ERR, "\n ** CRITICAL ERROR: GIC Distributor count is 0 **"); + return ACS_ERROR; + } + + if (set_gicd_base()) + return ACS_ERROR; + + return ACS_SUCCESS; +} + +/** + * @brief This API returns the base address of the GIC Distributor. + * The assumption is we have only 1 GIC Distributor. IS this true? + * 1. Caller - VAL + * 2. Prerequisite - val_gic_create_info_table + * @param None + * @return Address of GIC Distributor + */ +acs_status_t val_get_gicd_base(uint64_t *gicd_base) +{ + *gicd_base = g_gicd_base; + return ACS_SUCCESS; +} + +/** + * @brief This function is a single point of entry to retrieve + * all GIC related information. + * 1. Caller - Test Suite + * 2. Prerequisite - val_gic_create_info_table + * @return status + */ +acs_status_t val_gic_get_version(uint32_t *version) +{ + if (!version) + return ACS_ERROR; + + if (g_gic_info_table->header.gic_version != 0) { + val_print(ACS_LOG_INFO, "\n Gic version from ACPI table = %d", + g_gic_info_table->header.gic_version); + *version = g_gic_info_table->header.gic_version; + return ACS_SUCCESS; + } + + *version = ((val_mmio_read(g_gicd_base + 0xFE8) >> 4) & 0xF); + + return ACS_SUCCESS; +} + +/** + * @brief This function is installs the ISR pointed by the function pointer + * the input Interrupt ID. + * 1. Caller - Test Suite + * 2. Prerequisite - val_gic_create_info_table + * @param int_id Interrupt ID to install the ISR + * @param isr Function pointer of the ISR + * @return status + */ +acs_status_t val_gic_install_isr(uint32_t int_id, void *isr) +{ + uint32_t reg_offset = int_id / 32; + uint32_t reg_shift = int_id % 32; + uint32_t ret = 0; + + if ((int_id > 1019) || (int_id == 0)) { + val_print(ACS_LOG_ERR, "\n Invalid Interrupt ID number %d", int_id); + return ACS_ERROR; + } + + ret = pal_gic_install_isr(int_id, isr); + if (ret) + return ACS_ERROR; + + if (int_id > 31) { + /**** UEFI GIC code is not enabling interrupt in the Distributor ***/ + /**** So, do this here as a fail-safe. Remove if PAL guarantees this ***/ + val_mmio_write(g_gicd_base + GICD_ISENABLER + (4 * reg_offset), 1 << reg_shift); + } + + return ACS_SUCCESS; +} + +/** + * @brief This function free the registered interrupt line + * + * @param int_id Interrupt line to free + * + * @return status + */ +acs_status_t val_gic_free_interrupt(uint32_t int_id) +{ + int32_t ret = 0; + + ret = pal_gic_free_interrupt(int_id); + if (ret) + return ACS_ERROR; + + return ACS_SUCCESS; +} + +/** + * @brief This function generates the interrupt for given + * input interrupt id. + * + * @param int_id Interrupt ID. + * + * @return status + */ +acs_status_t val_gic_generate_interrupt(uint32_t int_id) +{ + uint64_t base = 0; + uint32_t index = 0; + uint32_t num_pe = val_pe_get_num(); + gic_info_entry_t *gic_entry; + gic_intr_t gic_intr; + + gic_intr.mask = 1 << (int_id % 32); + + if ((int_id > 0) && (int_id < 32)) { + gic_entry = g_gic_info_table->gic_info; + while (gic_entry->type != 0xFF) { + if (gic_entry->type == ENTRY_TYPE_GICRD) { + base = gic_entry->base; + break; + } + gic_entry++; + } + gic_intr.base = (base + GICD_ISPENDR + (int_id/32) * 4); + for (index = 0; index < num_pe; index++) { + base = gic_intr.base + index * 2 * SZ_64KB; + val_mmio_write(base, gic_intr.mask); + } + } else if ((int_id > 31) && (int_id < 1020)) { + gic_intr.base = (g_gicd_base + GICD_ISPENDR + (int_id/32) * 4); + val_mmio_write(gic_intr.base, gic_intr.mask); + } else { + val_print(ACS_LOG_ERR, "\n Invalid Interrupt ID number %d", int_id); + return ACS_ERROR; + } + + return ACS_SUCCESS; +} + +void gic_disable_interrupt(gic_intr_t *gic_intr) +{ + uint64_t base; + uint32_t index = 0; + uint32_t num_pe = val_pe_get_num(); + + for (index = 0; index < num_pe; index++) { + base = gic_intr->base + index * 2 * SZ_64KB; + val_mmio_write(base, gic_intr->mask); + } +} + +/** + * @brief This function disables the interrupt in GIC for given + * interrupt id. + * + * @param int_id Interrupt ID. + * + * @return status + */ +acs_status_t val_gic_disable_interrupt(uint32_t int_id) +{ + uint64_t base = 0; + gic_info_entry_t *gic_entry; + gic_intr_t gic_intr; + + gic_intr.mask = 1 << (int_id % 32); + + if ((int_id > 0) && (int_id < 32)) { + gic_entry = g_gic_info_table->gic_info; + while (gic_entry->type != 0xFF) { + if (gic_entry->type == ENTRY_TYPE_GICRD) { + base = gic_entry->base; + break; + } + gic_entry++; + } + gic_intr.base = (base + GICD_ICENABLER + (int_id/32) * 4); + gic_disable_interrupt(&gic_intr); + } else if ((int_id > 31) && (int_id < 1020)) { + gic_intr.base = (g_gicd_base + GICD_ICENABLER + (int_id/32) * 4); + val_mmio_write(gic_intr.base, gic_intr.mask); + } else { + val_print(ACS_LOG_ERR, "\n Invalid Interrupt ID number %d", int_id); + return ACS_ERROR; + } + + return ACS_SUCCESS; +} + +/** + * @brief This function writes to end of interrupt register for relevant + * interrupt group. + * 1. Caller - Test Suite + * 2. Prerequisite - val_gic_create_info_table + * @param int_id Interrupt ID for which to disable the interrupt + * @return status + */ +acs_status_t val_gic_end_of_interrupt(uint32_t int_id) +{ + uint64_t base = 0; + uint32_t index = 0; + uint32_t num_pe = val_pe_get_num(); + gic_info_entry_t *gic_entry; + gic_intr_t gic_intr; + + if ((int_id > 0) && (int_id < 32)) { + gic_entry = g_gic_info_table->gic_info; + while (gic_entry->type != 0xFF) { + if (gic_entry->type == ENTRY_TYPE_GICRD) { + base = gic_entry->base; + break; + } + gic_entry++; + } + gic_intr.base = (base + GICD_CLRLPIR); + for (index = 0; index < num_pe; index++) { + base = gic_intr.base + index * 2 * SZ_64KB; + val_mmio_write(base, int_id); + } + } + else if ((int_id > 31) && (int_id < 1020)) { + val_mmio_write((g_gicd_base + GICD_CLRSPI_NSR), int_id); + } + else { + val_print(ACS_LOG_ERR, "\n Invalid Interrupt ID number %d", int_id); + return ACS_ERROR; + } + + pal_gic_end_of_interrupt(int_id); + + return ACS_SUCCESS; +} + +/** + * @brief This function routes interrupt to specific PE. + * 1. Caller - Test Suite + * 2. Prerequisite - val_gic_create_info_table + * @param int_id Interrupt ID to be routed + * @param mpidr MPIDR_EL1 reg value of the PE to which the interrupt should be routed + * @return status + */ +acs_status_t val_gic_route_interrupt_to_pe(uint32_t int_id, uint64_t mpidr) +{ + uint64_t aff = 0; + + aff = val_gic_mpidr_to_affinity(mpidr); + if (int_id > 31) { + val_mmio_write(g_gicd_base + GICD_IROUTER + (8 * int_id), (uint32_t)aff); + val_mmio_write(g_gicd_base + GICD_IROUTER + (8 * int_id) + 0x4, (uint32_t)(aff >> 32)); + return ACS_SUCCESS; + } else { + val_print(ACS_LOG_ERR, "\n Only SPIs can be routed, INTID = %d cannot be routed", + int_id); + return ACS_ERROR; + } +} + +/** + * @brief This function will return '1' if an interrupt is either pending or active. + * 1. Caller - Test Suite + * 2. Prerequisite - val_gic_create_info_table + * @param int_id Interrupt ID + * @return pending/active status + */ +acs_status_t val_gic_get_interrupt_state(uint32_t int_id, uint32_t *status) +{ + uint32_t reg_offset = int_id / 32; + uint32_t reg_shift = int_id % 32; + uint32_t mask = (1 << reg_shift); + uint32_t active, pending; + + if (!status) + return ACS_ERROR; + + pending = val_mmio_read(g_gicd_base + GICD_ISPENDR + (4 * reg_offset)); + active = val_mmio_read(g_gicd_base + GICD_ISACTIVER0 + (4 * reg_offset)); + + val_print(ACS_LOG_DEBUG, "\n pending: %x active: %x", pending, active); + *status = ((mask & active) || (mask & pending)); + return ACS_SUCCESS; +} + +/** + * @brief This function will clear an interrupt that is pending or active. + * 1. Caller - Test Suite + * 2. Prerequisite - val_gic_create_info_table + * @param int_id Interrupt ID + * @return none + */ +acs_status_t val_gic_clear_interrupt(uint32_t int_id) +{ + uint32_t reg_offset = int_id / 32; + uint32_t reg_shift = int_id % 32; + + if ((int_id > 31) && (int_id < 1020)) { + val_mmio_write(g_gicd_base + GICD_ICPENDR0 + (4 * reg_offset), (1 << reg_shift)); + val_mmio_write(g_gicd_base + GICD_ICACTIVER0 + (4 * reg_offset), (1 << reg_shift)); + } + else { + val_print(ACS_LOG_ERR, "\n Invalid Interrupt ID number %d", int_id); + return ACS_ERROR; + } + + return ACS_SUCCESS; +} + +/** + * @brief This function converts mpidr to affinity as per GIC + * + * @param mpidr PE mpidr value + * + * @return affinity of the given PE mpidr + */ +uint64_t val_gic_mpidr_to_affinity(uint64_t mpidr) +{ + uint64_t aff; + + aff = ((uint64_t)PE_MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 | + PE_MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 | + PE_MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 | + PE_MPIDR_AFFINITY_LEVEL(mpidr, 0)); + + return aff; +} + +/** + * @brief This function frees the allocated memory for GIC info table + * + * @return none + */ +void val_gic_free_info_table(void) +{ + pal_free_mem((uint64_t *)g_gic_info_table); +} diff --git a/sdei/val/src/val_misc.c b/sdei/val/src/val_misc.c new file mode 100644 index 0000000..78264f2 --- /dev/null +++ b/sdei/val/src/val_misc.c @@ -0,0 +1,98 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include "val_interface.h" +#include "pal_interface.h" + +/** + * @brief This API calls PAL layer to read from a Memory address + * and return 32-bit data. + * 1. Caller - Test Suite + * 2. Prerequisite - None. + * + * @param addr 64-bit address + * + * @return 32-bits of data + */ +uint32_t +val_mmio_read(uint64_t addr) +{ + return pal_mmio_read(addr); + +} + +/** + * @brief This function will call PAL layer to write 32-bit data to + * a Memory address. + * 1. Caller - Test Suite + * 2. Prerequisite - None. + * + * @param addr 64-bit address + * @param data 32-bit data + * + * @return None + */ +void +val_mmio_write(uint64_t addr, uint32_t data) +{ + + pal_mmio_write(addr, data); +} + +/** + * @brief This function call PAL layer and converts physical address to + * virtual address. + * @param addr 64-bit address + * + * @return Virtual address + */ +uint64_t *val_pa_to_va(uint64_t addr) +{ + uint64_t *va; + va = pal_pa_to_va(addr); + + return va; +} + +/** + * @brief This function call PAL layer and write 32-bit data to + * memory address. + * @param addr 64-bit address + * @param offset offset + * @param data 32-bit data + * + * @return None + */ +void val_va_write(uint64_t *addr, uint32_t offset, uint32_t data) +{ + pal_va_write(addr, offset, data); +} + +void val_va_free(uint64_t *addr) +{ + pal_va_free(addr); +} + +void val_intf_lock(void) +{ + pal_intf_lock(); +} + +void val_intf_unlock(void) +{ + pal_intf_unlock(); +} diff --git a/sdei/val/src/val_pe.c b/sdei/val/src/val_pe.c new file mode 100644 index 0000000..7f8ed5f --- /dev/null +++ b/sdei/val/src/val_pe.c @@ -0,0 +1,370 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include "val_interface.h" + +/** + * @brief Pointer to the memory location of the PE Information table + */ +pe_info_table_t *g_pe_info_table; + +/** + * @brief This API will clean and invalidate the given address in Cache + * + * @param addr 64-bit address + * + * @return none + */ +void val_pe_data_cache_clean_invalidate(uint64_t addr) +{ + pal_pe_data_cache_clean_invalidate(addr); +} + +/** + * @brief This API will invalidate the given address in Cache + * + * @param addr 64-bit address + * + * @return none + */ +void val_pe_data_cache_invalidate(uint64_t addr) +{ + pal_pe_data_cache_invalidate(addr); +} + +/** + * @brief This API provides a 'C' interface to call System register reads + * 1. Caller - Test Suite + * 2. Prerequisite - None + * @param reg_id - the system register index for which data is returned + * @return the value read from the system register. + */ +acs_status_t val_pe_reg_read(pe_reg_id_t reg_id, uint64_t *val) +{ + if (!val) + return ACS_ERROR; + switch(reg_id) { + case MPIDR_EL1: + *val = ArmReadMpidr(); + break; + case ID_AA64PFR0_EL1: + *val = ArmReadIdPfr0(); + break; + case CurrentEL: + *val = AA64ReadCurrentEL(); + break; + case DAIF: + *val = __EXTRACT_BITS(ArmReadDaif(), 6, 4); + break; + case SPsel: + *val = ArmReadSPselPState(); + break; + case ELR_EL: + *val = ((CLIENT_EL == 0x2) ? ArmReadElrEl2() : ArmReadElrEl1()); + break; + case SPSR_EL: + *val = ((CLIENT_EL == 0x2) ? ArmReadSpsrEl2() : ArmReadSpsrEl1()); + break; + default: + return ACS_ERROR; + } + return ACS_SUCCESS; +} + +/** + * @brief This API provides a 'C' interface to call System register writes + * 1. Caller - Test Suite + * 2. Prerequisite - None + * @param reg_id - the system register index for which data is written + * @param write_data - the 64-bit data to write to the system register + * @return None + */ +acs_status_t val_pe_reg_write(pe_reg_id_t reg_id, uint64_t write_data) +{ + return ACS_SUCCESS; +} + +/** + * @brief This API indicates the presence of exception level 3 + * 1. Caller - Test Suite + * 2. Prerequisite - None + * @param None + * @return 1 if EL3 is present, 0 if EL3 is not implemented + */ +acs_status_t val_is_el3_enabled() +{ + uint64_t data; + + val_pe_reg_read(ID_AA64PFR0_EL1, &data); + + return ((data >> 12) & 0xF); +} + +/** + * @brief This API indicates the presence of exception level 2 + * 1. Caller - Test Suite + * 2. Prerequisite - None + * @param None + * @return 1 if EL2 is present, 0 if EL2 is not implemented + */ +acs_status_t val_is_el2_enabled() +{ + uint64_t data; + + val_pe_reg_read(ID_AA64PFR0_EL1, &data); + + return ((data >> 8) & 0xF); +} + +/** + * @brief This API will call PAL layer to fill in the PE information + * into the g_pe_info_table pointer. + * 1. Caller - Application layer. + * 2. Prerequisite - Memory allocated and passed as argument. + * @param pe_info_table pre-allocated memory pointer for pe_info + * @return Error if Input param is NULL or num_pe is 0. + */ +acs_status_t val_pe_create_info_table(void *pe_info_table) +{ + if (pe_info_table == NULL) { + val_print(ACS_LOG_ERR, "\n Input memory for PE Info table cannot be NULL"); + return ACS_ERROR; + } + + g_pe_info_table = (pe_info_table_t *)pe_info_table; + pal_pe_create_info_table(g_pe_info_table); + val_print(ACS_LOG_TEST, "\n PE_INFO: Number of PE detected : %4d", + val_pe_get_num()); + + if (val_pe_get_num() == 0) { + val_print(ACS_LOG_ERR, "\n *** CRITICAL ERROR: Num PE is 0x0 ***"); + return ACS_ERROR; + } + return ACS_SUCCESS; +} + +/** + * @brief This API will allocates memory that is shared by all PEs + * + * @param none + * + * @return status + */ +acs_status_t val_shared_mem_alloc() +{ + return pal_pe_alloc_shared_mem(val_pe_get_num(), sizeof(pe_shared_mem_t)); +} + +/** + * @brief This API will writes data to shared memory at the index provided as + * argument + * + * @param index PE index + * + * @return status + */ +acs_status_t val_shared_mem_write(uint32_t index, pe_shared_mem_t *src) +{ + pe_shared_mem_t *dst = g_pe_shared_mem + index; + dst->status = src->status; + dst->data0 = src->data0; + dst->data1 = src->data1; + val_pe_data_cache_clean_invalidate((uint64_t)&dst->status); + val_pe_data_cache_clean_invalidate((uint64_t)&dst->data0); + val_pe_data_cache_clean_invalidate((uint64_t)&dst->data1); + return ACS_SUCCESS; +} + +/** + * @brief This API will reads data from shared memory at the index provided as + * argument + * + * @param index PE index + * + * @return status + */ +acs_status_t val_shared_mem_read(uint32_t index, pe_shared_mem_t *dst) +{ + pe_shared_mem_t *src = g_pe_shared_mem + index; + val_pe_data_cache_invalidate((uint64_t)&src->status); + val_pe_data_cache_invalidate((uint64_t)&src->data0); + val_pe_data_cache_invalidate((uint64_t)&src->data1); + dst->status = src->status; + dst->data0 = src->data0; + dst->data1 = src->data1; + return ACS_SUCCESS; +} + +/** + * @brief This API frees the allocated shared memory + * @param none + * @return none + */ +void val_shared_mem_free() +{ + pal_pe_free_shared_mem(); + pal_pe_clean_up(); +} + +/** + * @brief This API returns the number of PE from the g_pe_info_table. + * 1. Caller - Application layer, test Suite. + * 2. Prerequisite - val_pe_create_info_table. + * @param None + * @return the number of pe discovered + */ +uint32_t val_pe_get_num() +{ + if (g_pe_info_table == NULL) + return 0; + + return g_pe_info_table->header.num_of_pe; +} + +/** + * @brief This API reads MPIDR system regiser and return the affx bits + * 1. Caller - Test Suite, VAL + * 2. Prerequisite - None + * @param None + * @return 32-bit affinity value + */ +uint64_t val_pe_get_mpid() +{ + uint64_t data; + + val_pe_reg_read(MPIDR_EL1, &data); + /* return the affx bits */ + data = (((data >> 32) & 0xFF) << 24) | (data & 0xFFFFFF); + + return data; +} + +/** + * @brief This API returns the MPIDR value for the PE indicated by index + * 1. Caller - Test Suite, VAL + * 2. Prerequisite - val_create_peinfo_table + * @param index - the index of the PE whose mpidr value is required. + * @return MPIDR value + */ +uint64_t val_pe_get_mpid_index(uint32_t index) +{ + pe_info_entry_t *entry; + + if (index > g_pe_info_table->header.num_of_pe) + return INVALID_INDEX; + + entry = g_pe_info_table->pe_info; + + return entry[index].mpidr; +} + +/** + * @brief This API returns the index of the PE whose MPIDR matches with the input MPIDR + * 1. Caller - Test Suite, VAL + * 2. Prerequisite - val_create_peinfo_table + * @param mpid - the mpidr value of pE whose index is returned. + * @return Index of PE + */ +uint32_t val_pe_get_index_mpid(uint64_t mpid) +{ + pe_info_entry_t *entry; + uint32_t i = g_pe_info_table->header.num_of_pe; + + entry = g_pe_info_table->pe_info; + while (i > 0) { + if (entry->mpidr == mpid) { + return entry->pe_num; + } + entry++; + i--; + } + + return INVALID_INDEX; +} + +/** + * @brief This API returns the index of the current PE + * + * @param none + * + * @return none + */ +uint32_t val_pe_get_index() +{ + uint64_t mpid = val_pe_get_mpid(); + return val_pe_get_index_mpid(mpid); +} + +/** + * @brief This API executes code addressed by given function pointer on each PE + * in the system. + * @param payload function pointer + * @param arg arguments to the fuction + * + * @return status + */ +acs_status_t val_pe_execute_on_all(void *payload, uint64_t arg) +{ + acs_status_t status; + int num_pe = val_pe_get_num(); + status = pal_pe_execute_on_all(num_pe, payload, arg); + return status; +} + +/** + * @brief This API suspends the current PE using PSCI call + * @param none + * + * @return none + */ +void val_pe_suspend(uint32_t power_down) { + pal_pe_suspend(power_down); +} + +/** + * @brief This API will power off the given PE index using PSCI call + * @param pe_index Index of the PE + * + * @return none + */ +void val_pe_poweroff(uint32_t pe_index) +{ + pal_pe_poweroff(pe_index); +} + +/** + * @brief This API will power on the given PE index using PSCI call + * @param pe_index Index of the PE + * + * @return none + */ +void val_pe_poweron(uint32_t pe_index) +{ + uint64_t pe_mpidr = val_pe_get_mpid_index(pe_index); + pal_pe_poweron(pe_mpidr); +} + +/** + * @brief This function frees the allocated memory for PE info table + * @param none + * + * @return none + */ +void val_pe_free_info_table(void) +{ + pal_free_mem((uint64_t *)g_pe_info_table); +} diff --git a/sdei/val/src/val_psci.c b/sdei/val/src/val_psci.c new file mode 100644 index 0000000..f32687d --- /dev/null +++ b/sdei/val/src/val_psci.c @@ -0,0 +1,68 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include "val_interface.h" + +/** + * @brief This function returns version of the PSCI + * @param none + * @return status + */ +uint32_t val_psci_version(uint32_t *version) +{ + *version = pal_invoke_psci_fn(PSCI_FN_PSCI_VERSION, 0, 0, 0); + return 0; +} + +/** + * @brief This function returns ON/OFF/ON_Pending states of given affinity value + * + * @param target_aff Targeted PE affinity value. + * @param lowest_aff_level Denotes the lowest affinity level field that is valid in + * the target affinity value. + * + * @return status + */ +uint32_t val_psci_affinity_info(uint64_t target_aff, uint64_t lowest_aff_level) +{ + int32_t err = -1; + + err = pal_invoke_psci_fn(PSCI_FN_AFFINITY_INFO, target_aff, lowest_aff_level, 0); + if (err < 0) + return 1; + else + return 0; +} + +/** + * @brief This function allows discovering whether a specific PSCI function is + * implemented + * + * @param fun_id Function ID for a PSCI function + * + * @return status + */ +uint32_t val_psci_features(uint32_t fun_id) +{ + int32_t err = -1; + + err = pal_invoke_psci_fn(PSCI_FN_PSCI_FEATURES, fun_id, 0, 0); + if (err < 0) + return 1; + else + return 0; +} diff --git a/sdei/val/src/val_sdei_interface.c b/sdei/val/src/val_sdei_interface.c new file mode 100644 index 0000000..38cc217 --- /dev/null +++ b/sdei/val/src/val_sdei_interface.c @@ -0,0 +1,519 @@ +/** @file + * Software Delegated Exception Interface (SDEI) API + * + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include "val_interface.h" +#include "val_sdei_interface.h" +#include "pal_interface.h" + +event_info_table_t *g_event_info_table; + +uint32_t val_acpi_present() { + + if (!pal_acpi_present()) { + return -1; + } + + return 0; +} + +/** + * @brief This function reads value stored in given register (x0 - x17), based on param_id. + * + * @param query Register value between 0 to 17 + * + * @return status + */ +int32_t val_sdei_event_context(uint32_t query, uint64_t *result) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_CONTEXT, query, 0, 0, 0, 0, + result); +} + +/** + * @brief This function retrieves information about given event based on info parameter. + * + * @param event Event number + * @param info Information requested + * + * @return status + */ +int32_t val_sdei_event_get_info(uint32_t event, uint32_t info, uint64_t *result) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_GET_INFO, event, info, 0, + 0, 0, result); +} + +/** + * @brief This function marks the event complete, with completion status. + * It is called from event handler. + * Execution resumes in the context interrupted by the event. + * + * @return status + */ +int32_t val_sdei_event_complete(uint32_t status_code) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_COMPLETE, status_code, 0, 0, + 0, 0, NULL); +} + +/** + * @brief This function marks the event complete. Execution resumes from resume_addr. + * + * @param return_address Address in clent to resume the excution from + * + * @return status + */ +int32_t val_sdei_event_complete_and_resume(uint64_t return_address) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME, return_address, 0, 0, + 0, 0, NULL); +} + +/** + * @brief This function queries SDEI features implemented by the dispatcher. + * + * @param feature This argument specifies the feature that is queried. + * + * @return none + */ +int32_t val_sdei_features(uint32_t feature, uint64_t *num_slots) +{ + int32_t err; + uint64_t result; + + err = pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_FEATURES, feature, 0, 0, 0, + 0, &result); + *num_slots = result; + + return err; +} + +static int32_t val_event_create(struct sdei_event *event) +{ + int32_t err = 0; + + err = val_sdei_event_get_info(event->event_num, SDEI_EVENT_INFO_EV_PRIORITY, + &event->priority); + if (err) { + return err; + } + + err = val_sdei_event_get_info(event->event_num, SDEI_EVENT_INFO_EV_TYPE, + &event->type); + if (err) { + return err; + } + + return err; +} + +/** + * @brief This function returns event number based on the given type + * + * @param type This argument specifies whether event is shared or private + * + * @return On success it returns the event number + */ +uint32_t val_event_get(uint32_t type, uint32_t priority) +{ + struct sdei_event event; + int err, i; + uint32_t event_num = 0; + event_info_t *event_info = &g_event_info_table->info[0]; + + if (type == SDEI_EVENT_TYPE_PRIVATE) { + err = val_sdei_interrupt_bind(PPI_INTR_NUM, &event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n PPI Interrupt bind failed with err %d", err); + } + return event_num; + } + else if (type == SDEI_EVENT_TYPE_SHARED) { + err = val_sdei_interrupt_bind(SPI_INTR_NUM, &event_num); + if (err) { + val_print(ACS_LOG_ERR, "\n SPI Interrupt bind failed with err %d", err); + } + return event_num; + } + + for (i = 0; i < g_event_info_table->num_events; i++) { + event.event_num = event_info->number; + if (priority == SDEI_EVENT_PRIORITY_ANY && type == SDEI_EVENT_TYPE_ANY) + return event.event_num; + err = val_event_create(&event); + if (err) + return 0; + + if ((priority == event.priority && type == event.type) || + (priority == SDEI_EVENT_PRIORITY_ANY && type == event.type) || + (priority == event.priority && type == SDEI_EVENT_TYPE_ANY)) + return event.event_num; + } + return 0; +} + +/** + * @brief This function returns the version of SDEI dispatcher. + * + * @return status + */ +int32_t val_sdei_get_version(uint64_t *version) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_VERSION, 0, 0, 0, 0, 0, version); +} + +/** + * @brief This function masks the PE from receiving any event. + * + * @return status + */ +int32_t val_sdei_mask(uint64_t *result) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_MASK, 0, 0, 0, 0, 0, result); +} + +/** + * @brief This function unmasks the PE to receive events. + * @param None + * + * @return status + */ +int32_t val_sdei_unmask(void) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_UNMASK, 0, 0, 0, 0, 0, NULL); +} + +/** + * @brief This function resets SDEI private data. + * + * @return status + */ +int32_t val_sdei_private_reset(void *ignored) +{ + int32_t err = 0; + + err = pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_PRIVATE_RESET, 0, 0, 0, 0, 0, + NULL); + return err; +} + +/** + * @brief This function resets shared SDEI data. + * @param None + * + * @return status + */ +int32_t val_sdei_shared_reset(void) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_SHARED_RESET, 0, 0, 0, 0, 0, + NULL); +} + +/** + * @brief This function retrieves status of the event, as one or more of running, + * enabled or registered. + * @param event_num Event number + * + * @return status + */ +int32_t val_sdei_event_status(uint32_t event_num, uint64_t *result) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_STATUS, event_num, 0, 0, 0, + 0, result); +} + +/** + * @brief This function enables a given event so that registered handler is + * called when event occurs. + * @param event_num Event number + * + * @return status + */ +int32_t val_sdei_event_enable(uint32_t event_num) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_ENABLE, event_num, 0, 0, 0, + 0, NULL); +} + +/** + * @brief This function disables a given event. + * @param event_num Event number + * + * @return status + */ +uint32_t val_sdei_event_disable(uint32_t event_num) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_DISABLE, event_num, 0, 0, + 0, 0, NULL); +} + +/** + * @brief This function binds the given interrupt to given event. + * @param irq_num Interrupt number + * + * @return status + */ +int32_t val_sdei_interrupt_bind(uint32_t irq_num, uint32_t *event_num) +{ + int32_t err; + uint64_t result; + + err = pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_INTERRUPT_BIND, irq_num, 0, 0, 0, + 0, &result); + *event_num = result; + + return err; +} + +/** + * @brief This function releases the interrupt bound to given input. + * @param event_num Event number + * + * @return status + */ +int32_t val_sdei_interrupt_release(uint32_t event_num) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE, event_num, 0, + 0, 0, 0, NULL); +} + +/** + * @brief This function unregisters the given event with the dispatcher. + * @param event_num Event number + * + * @return status + */ +int32_t val_sdei_event_unregister(uint32_t event_num) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_UNREGISTER, event_num, 0, + 0, 0, 0, NULL); +} + +/** + * @brief This function signals software event to given target PE. + * @param event_num Event number + * @param affinity Target PE affinity + * + * @return status + */ +uint32_t val_sdei_event_signal(uint32_t event_num, uint64_t affinity) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_SIGNAL, event_num, affinity, + 0, 0, 0, NULL); +} + +/** + * @brief This function registers a given event with the dispatcher. + * @param event_num Event number + * @param entry_point Entry point address at ELc for the event handler + * @param arg User defined argument passed to entry point routine. + * @param flags Routing mode flags + * @param affinity Target PE affinity + * + * @return status + */ +uint32_t val_sdei_event_register(uint32_t event_num, uint64_t entry_point, + void *arg, uint64_t flags, uint64_t affinity) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_REGISTER, event_num, + (uint64_t)entry_point, (uint64_t)arg, + flags, affinity, NULL); +} + +static uint32_t sdei_event_routing_set(uint32_t event_num, uint64_t routing_mode, + uint64_t affinity) +{ + return pal_invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET, event_num, + routing_mode, affinity, 0, 0, NULL); +} + +/** + * @brief This function changes the routing information of given event. + * @param event_num Event number + * @param directed routing mode RM_ANY or RM_PE + * @param cpu_id Target PE index + * + * @return status + */ +uint32_t val_sdei_event_routing_set(uint32_t event_num, bool directed, int32_t cpu_id) +{ + uint32_t err; + uint64_t affinity; + uint32_t routing_mode; + + if (directed) { + routing_mode = SDEI_EVENT_REGISTER_RM_PE; + affinity = val_pe_get_mpid_index(cpu_id); + if (affinity == INVALID_INDEX) { + val_print(ACS_LOG_DEBUG, "\n Failed to determine affinity for CPU %u", cpu_id); + } + } else { + routing_mode = SDEI_EVENT_REGISTER_RM_ANY; + affinity = 0; + } + err = sdei_event_routing_set(event_num, routing_mode, + affinity); + if (err) + val_print(ACS_LOG_DEBUG, "\n Failed to set routing mode"); + + return err; +} + +/** + * @brief This function retrieves routing information about given event + * @param event_num Event number + * + * @return status + */ +uint32_t val_sdei_event_routing_get(uint32_t event_num, bool *directed, int32_t *cpu_id) +{ + uint32_t err; + uint64_t info; + + err = val_sdei_event_get_info(event_num, + SDEI_EVENT_INFO_EV_ROUTING_MODE, + &info); + if (err) { + val_print(ACS_LOG_DEBUG, "\n Failed to query routing mode"); + return err; + } + *directed = (info == SDEI_EVENT_REGISTER_RM_PE); + + err = val_sdei_event_get_info(event_num, SDEI_EVENT_INFO_EV_ROUTING_AFF, + &info); + if (err) { + val_print(ACS_LOG_DEBUG, "\n Failed to query routing affinity"); + return err; + } + *cpu_id = val_pe_get_index_mpid(info); + /* Don't print a warning if the affinity is bogus for RM_ANY */ + if (*cpu_id == INVALID_INDEX) + val_print(ACS_LOG_ERR, "\n Failed to convert firmware description for affinity %llx", + info); + + return err; +} + +/** + * @brief This function creates a table of information on various SDEI events in the system. + * @param table pre-allocated memory pointer for event_info + * + * @return status + */ +acs_status_t val_sdei_create_event_info_table(uint64_t *table) +{ + int status; + if (table == NULL) + return ACS_ERROR; + g_event_info_table = (event_info_table_t*)table; + + status = pal_sdei_create_event_info_table(g_event_info_table); + if (!status) { + val_print(ACS_LOG_TEST, "\n EVT_INFO: Number of hardware error events : %4d", + g_event_info_table->num_events); + } + else { + val_print(ACS_LOG_ERR, "\n EVT_INFO: No hardware error event found"); + } + + val_pe_data_cache_clean_invalidate((uint64_t)&g_event_info_table); + return ACS_SUCCESS; +} + +uint32_t val_event_get_hest_info(uint32_t type, uint64_t *result) +{ + switch (type) + { + case HEST_FOUND: + *result = g_event_info_table->hest_found; + break; + + case NUM_GHES: + *result = g_event_info_table->num_ghes_notify; + break; + + case NUM_EVENTS: + *result = g_event_info_table->num_events; + break; + + case HEST_NOTIFY: + *result = (uint64_t)&g_event_info_table->info; + break; + + default: + *result = 0; + val_print(ACS_LOG_ERR, "\n HEST type is not valid"); + return 1; + } + return 0; +} + +/** + * @brief This function initialises the SDEI, unmask and resets the all PEs + * @param None + * @return status + */ +int32_t val_sdei_initialization(void) +{ + uint32_t err; + uint64_t ver = 0; + uint32_t conduit; + + if (!pal_acpi_present()) { + val_print(ACS_LOG_WARN, "\n SDEI entry not found in ACPI table"); + } + + conduit = pal_conduit_get(); + if (!conduit) + return -1; + + err = val_sdei_get_version(&ver); + if (err == SDEI_STATUS_NOT_SUPPORTED) + val_print(ACS_LOG_ERR, "\n advertised but not implemented in platform firmware"); + if (err) { + val_print(ACS_LOG_ERR, "\n Failed to get SDEI version: %d", err); + return err; + } + + val_print(ACS_LOG_TEST, "\n SDEIv%d.%d (0x%x) detected in firmware.", + (uint32_t)SDEI_VERSION_MAJOR(ver), (uint32_t)SDEI_VERSION_MINOR(ver), + (uint32_t)SDEI_VERSION_VENDOR(ver)); + + if (SDEI_VERSION_MAJOR(ver) != 1) { + val_print(ACS_LOG_WARN, "\n Conflicting SDEI version detected."); + return SDEI_STATUS_INVALID; + } + + val_pe_execute_on_all(val_sdei_unmask, 0); + val_pe_execute_on_all(val_sdei_private_reset, 0); + val_sdei_shared_reset(); + + return 0; +} + +/** + * @brief This function frees table of information on various SDEI events in the system. + * @param None + * + * @return none + */ +void val_event_free_info_table(void) +{ + pal_free_mem((uint64_t *)g_event_info_table); +} diff --git a/sdei/val/src/val_test_infra.c b/sdei/val/src/val_test_infra.c new file mode 100644 index 0000000..c3f5b32 --- /dev/null +++ b/sdei/val/src/val_test_infra.c @@ -0,0 +1,294 @@ +/** @file + * + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interface.h" + +extern sdei_log_control g_log_control; +sdei_test_desc sdei_test[SDEI_NUM_TESTS]; + +static int is_test_passed(int test_id) { + int i; + for (i = 0; i < SDEI_NUM_TESTS && sdei_test[i].id != test_id; i++); + if (i < SDEI_NUM_TESTS) + return sdei_test[i].status == SDEI_TEST_PASS; + return 0; +} + +static int deps_resolved(sdei_test_deps *deps) { + int i; + for (i = 0; deps[i]!=0 && is_test_passed(deps[i]); i++); + return (deps[i] == 0); +} + +static inline int run_test(sdei_test_control *control, int i) { + if (control->flags[i/64] & (1ULL << (i % 64))) + return deps_resolved(sdei_test[i].deps); + return 0; +} + +static inline void enable_test(sdei_test_control *control, int i) { + control->flags[i/64] |= ((unsigned long)(1ULL << (i % 64))); +} + +static inline void disable_test(sdei_test_control *control, int i) { + control->flags[i/64] &= ~((unsigned long)(1ULL << (i % 64))); +} + +void val_test_run_specific(sdei_test_control *control, int test_id, int init) { + int i; + if (init) { + control->flags[0] = 0ULL; + control->flags[1] = 0ULL; + } + for (i = 0; i < SDEI_NUM_TESTS && sdei_test[i].id != test_id; i++); + if (i < SDEI_NUM_TESTS) + enable_test(control, i); +} + +static void init_test(sdei_test_control *control, sdei_test_desc *test) { + val_test_set_status(val_pe_get_num(), SDEI_TEST_PENDING); + /* Always print test id and test description */ + val_print(ACS_LOG_ERR, "\n%d. ", test->id); +#ifdef TARGET_LINUX + val_print(ACS_LOG_ERR, "%s", test->description); +#else + val_print(ACS_LOG_ERR, test->description); +#endif +} + +static void log_test_result(sdei_test_control *control, int result) { + + /* Always print test results */ + if (result == SDEI_TEST_PASS) { + control->tests_passed += 1; + val_print(ACS_LOG_ERR, " : PASS\n"); + } + else if (result == SDEI_TEST_SKIP) { + control->tests_skipped += 1; + val_print(ACS_LOG_ERR, " : SKIP\n"); + } + else if (result == SDEI_TEST_FAIL) { + control->tests_failed += 1; + val_print(ACS_LOG_ERR, " : FAIL\n"); + } + else if (result == SDEI_TEST_ABORT) { + control->tests_aborted += 1; + val_print(ACS_LOG_ERR, " : ABORT\n"); + } + else if (result == SDEI_TEST_TIMEOUT) { + val_print(ACS_LOG_ERR, " : TIMEOUT\n"); + } + else if (result == SDEI_TEST_PENDING) { + val_print(ACS_LOG_ERR, " : PENDING\n"); + } + else if (result == SDEI_TEST_ERROR) { + val_print(ACS_LOG_ERR, " : ERROR\n"); + } +} + +/** + * @brief This function initializes the test infrastructure. + * + * @return none + */ +void val_test_init(sdei_test_control *control) { + sdei_test[0] = test_001; + sdei_test[1] = test_002; + sdei_test[2] = test_003; + sdei_test[3] = test_004; + sdei_test[4] = test_005; + sdei_test[5] = test_006; + sdei_test[6] = test_007; + sdei_test[7] = test_008; + sdei_test[8] = test_009; + sdei_test[9] = test_010; + sdei_test[10] = test_011; + sdei_test[11] = test_012; + sdei_test[12] = test_013; + sdei_test[13] = test_014; + sdei_test[14] = test_015; + sdei_test[15] = test_016; + sdei_test[16] = test_017; + sdei_test[17] = test_018; + sdei_test[18] = test_019; + sdei_test[19] = test_020; + sdei_test[20] = test_021; + sdei_test[21] = test_022; + sdei_test[22] = test_023; + sdei_test[23] = test_024; + sdei_test[24] = test_025; + sdei_test[25] = test_026; + sdei_test[26] = test_027; + sdei_test[27] = test_028; + sdei_test[28] = test_029; + sdei_test[29] = test_030; + sdei_test[30] = test_031; + sdei_test[31] = test_032; + sdei_test[32] = test_033; + sdei_test[33] = test_034; + sdei_test[34] = test_035; + sdei_test[35] = test_036; + sdei_test[36] = test_037; + sdei_test[37] = test_038; + sdei_test[38] = test_039; + sdei_test[39] = test_040; + sdei_test[40] = test_041; + sdei_test[41] = test_042; + sdei_test[42] = test_043; + sdei_test[43] = test_044; + sdei_test[44] = test_045; + sdei_test[45] = test_046; + sdei_test[46] = test_047; + sdei_test[47] = test_048; + sdei_test[48] = test_049; + control->flags[0] = ~(0ULL); + control->flags[1] = ~(0ULL); +} + +/** + * @brief This function enables a test for a given test id. + * @param test_id Test ID number + * + * @return none + */ +void val_test_enable(sdei_test_control *control, int test_id) { + int i; + for (i = 0; i < SDEI_NUM_TESTS && sdei_test[i].id != test_id; i++); + if (i < SDEI_NUM_TESTS) + enable_test(control, i); +} + +/** + * @brief This function disables a test for a given test id. + * @param test_id Test ID number + * + * @return none + */ +void val_test_disable(sdei_test_control *control, int test_id) { + int i; + for (i = 0; i < SDEI_NUM_TESTS && sdei_test[i].id != test_id; i++); + if (i < SDEI_NUM_TESTS) + disable_test(control, i); +} + +/** + * @brief This function executes all test cases and log the results + * + * @return none + */ +void val_test_execute(sdei_test_control *control) { + int i; + uint32_t num_pe; + + for (i = 0; i < SDEI_NUM_TESTS; i++) { + init_test(control, &sdei_test[i]); + if (sdei_test[i].all_pe) + num_pe = val_pe_get_num(); + else + num_pe = 1; + if (run_test(control, i)) { + sdei_test[i].test_fn(); + sdei_test[i].status = val_test_get_status(num_pe, TEST_TIMEOUT); + } + else + sdei_test[i].status = SDEI_TEST_SKIP; + log_test_result(control, sdei_test[i].status); + } +} + +/** + * @brief This function sets test status for a given PE. + * @param index PE index + * @param status test status + * + * @return none + */ +void val_test_pe_set_status(uint32_t index, uint32_t status) +{ + pe_shared_mem_t mem; + mem.status = status; + val_shared_mem_write(index, &mem); +} + +/** + * @brief This function sets test status for a given number of PEs. + * @param num_pe number of PEs + * @param status test status + * + * @return none + */ +void val_test_set_status(uint32_t num_pe, uint32_t status) +{ + uint32_t i; + for (i = 0; i < num_pe; i++) { + val_test_pe_set_status(i, status); + } +} + +/** + * @brief This function gets test status for a given PE. + * @param index PE index + * + * @return status for given PE + */ +uint32_t val_test_pe_get_status(uint32_t index) +{ + pe_shared_mem_t mem; + val_shared_mem_read(index, &mem); + return mem.status; +} + +/** + * @brief This function Gets test status for a given number of PEs. + * It keeps polling for a change of status from pending to a known termination status. + * @param num_pe number of PEs + * @param timeout Polling timeout value + * + * @return status + */ +uint32_t val_test_get_status(uint32_t num_pe, uint64_t timeout) +{ + uint32_t status, i; + + if (num_pe == 1) { + /* On Linux, the payload can be scheduled on any PE by the Kernel. + Hence check for status on all PEs */ + num_pe = val_pe_get_num(); + while (timeout--) { + status = SDEI_TEST_PASS; + for (i=0; i < num_pe; i++) { + status = val_test_pe_get_status(i); + if (status != SDEI_TEST_PENDING) + return status; + } + } + } + else { + while (timeout--) { + status = SDEI_TEST_PASS; + for (i = 0; i < num_pe; i++) { + status = status | val_test_pe_get_status(i); + if (status & SDEI_TEST_FAIL) + return status; + } + if (status == SDEI_TEST_PASS) + return status; + } + } + return SDEI_TEST_TIMEOUT; +} diff --git a/sdei/val/src/val_timer.c b/sdei/val/src/val_timer.c new file mode 100644 index 0000000..38bbf85 --- /dev/null +++ b/sdei/val/src/val_timer.c @@ -0,0 +1,326 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include "val_interface.h" +#include "pal_interface.h" +#include "val_timer.h" + +timer_info_table_t *g_timer_info_table; + +/** + * @brief This API is the single entry point to return all Timer related information + * 1. Caller - Test Suite + * 2. Prerequisite - val_timer_create_info_table + * @param info_type - Type of the information to be returned + * + * @return 64-bit data pertaining to the requested input type + */ + +uint64_t val_timer_get_info(timer_info_t info_type, uint64_t instance) +{ + + uint32_t block_num, block_index; + if (g_timer_info_table == NULL) + return 0; + + switch (info_type) { + case TIMER_INFO_CNTFREQ: + return ArmArchTimerReadReg(CntFrq); + case TIMER_INFO_PHY_EL1_INTID: + return g_timer_info_table->header.ns_el1_timer_gsiv; + case TIMER_INFO_VIR_EL1_INTID: + return g_timer_info_table->header.virtual_timer_gsiv; + case TIMER_INFO_PHY_EL2_INTID: + return g_timer_info_table->header.el2_timer_gsiv; + case TIMER_INFO_VIR_EL2_INTID: + return g_timer_info_table->header.el2_virt_timer_gsiv; + case TIMER_INFO_NUM_PLATFORM_TIMERS: + return g_timer_info_table->header.num_platform_timer; + case TIMER_INFO_IS_PLATFORM_TIMER_SECURE: + val_platform_timer_get_entry_index (instance, &block_num, &block_index); + if (block_num != 0xFFFF) + return ((g_timer_info_table->gt_info[block_num].flags[block_index] >> 16) & 1); + break; + case TIMER_INFO_SYS_CNTL_BASE: + val_platform_timer_get_entry_index (instance, &block_num, &block_index); + if (block_num != 0xFFFF) + return g_timer_info_table->gt_info[block_num].block_cntl_base; + break; + case TIMER_INFO_SYS_CNT_BASE_N: + val_platform_timer_get_entry_index (instance, &block_num, &block_index); + if (block_num != 0xFFFF) + return g_timer_info_table->gt_info[block_num].GtCntBase[block_index]; + break; + case TIMER_INFO_SYS_INTID: + val_platform_timer_get_entry_index (instance, &block_num, &block_index); + if (block_num != 0xFFFF) + return g_timer_info_table->gt_info[block_num].gsiv[block_index]; + break; + case TIMER_INFO_PHY_EL1_FLAGS: + return g_timer_info_table->header.ns_el1_timer_flag; + case TIMER_INFO_VIR_EL1_FLAGS: + return g_timer_info_table->header.virtual_timer_flag; + case TIMER_INFO_PHY_EL2_FLAGS: + return g_timer_info_table->header.el2_timer_flag; + case TIMER_INFO_SYS_TIMER_STATUS: + return g_timer_info_table->header.sys_timer_status; + default: + return 0; + } + return INVALID_INDEX; +} + +void val_platform_timer_get_entry_index(uint64_t instance, uint32_t *block, uint32_t *index) +{ + if (instance > g_timer_info_table->header.num_platform_timer){ + *block = 0xFFFF; + return; + } + + *block = 0; + *index = instance; + while (instance > g_timer_info_table->gt_info[*block].timer_count){ + instance = instance - g_timer_info_table->gt_info[*block].timer_count; + *index = instance; + *block = *block + 1; + } +} +/** + * @brief This API enables the Architecture timer whose register is given as the input parameter. + * 1. Caller - VAL + * 2. Prerequisite - None + * @param reg - system register of the ELx Arch timer. + * + * @return None + */ +void ArmGenericTimerEnableTimer (ARM_ARCH_TIMER_REGS reg) +{ + uint64_t timer_ctrl_reg; + + timer_ctrl_reg = ArmArchTimerReadReg (reg); + timer_ctrl_reg |= ARM_ARCH_TIMER_ENABLE; + ArmArchTimerWriteReg (reg, &timer_ctrl_reg); +} + +/** + * @brief This API disables the Architecture timer whose register is given as the input parameter. + * 1. Caller - VAL + * 2. Prerequisite - None + * @param reg - system register of the ELx Arch timer. + * + * @return None + */ +void ArmGenericTimerDisableTimer (ARM_ARCH_TIMER_REGS reg) +{ + uint64_t timer_ctrl_reg; + + timer_ctrl_reg = ArmArchTimerReadReg (reg); + timer_ctrl_reg &= ~ARM_ARCH_TIMER_ENABLE; + ArmArchTimerWriteReg (reg, &timer_ctrl_reg); +} + +/** + * @brief This API programs the el1 phy timer with the input timeout value. + * 1. Caller - Test Suite + * 2. Prerequisite - None + * @param timeout - clock ticks after which an interrupt is generated. + * + * @return None + */ +void val_timer_set_phy_el1(uint64_t timeout) +{ + + if (timeout != 0) { + ArmGenericTimerDisableTimer(CntpCtl); + ArmArchTimerWriteReg(CntpTval, &timeout); + ArmGenericTimerEnableTimer(CntpCtl); + } else { + ArmGenericTimerDisableTimer(CntpCtl); + } +} + +/** + * @brief This API programs the el1 Virtual timer with the input timeout value. + * 1. Caller - Test Suite + * 2. Prerequisite - None + * @param timeout - clock ticks after which an interrupt is generated. + * + * @return None + */ +void val_timer_set_vir_el1(uint64_t timeout) +{ + if (timeout != 0) { + ArmGenericTimerDisableTimer(CntvCtl); + ArmArchTimerWriteReg(CntvTval, &timeout); + ArmGenericTimerEnableTimer(CntvCtl); + } else { + ArmGenericTimerDisableTimer(CntvCtl); + } +} + +/** + * @brief This API programs the el2 phy timer with the input timeout value. + * 1. Caller - Test Suite + * 2. Prerequisite - None + * @param timeout - clock ticks after which an interrupt is generated. + * + * @return None + */ +void val_timer_set_phy_el2(uint64_t timeout) +{ + + if (timeout != 0) { + ArmGenericTimerDisableTimer(CnthpCtl); + ArmArchTimerWriteReg(CnthpTval, &timeout); + ArmGenericTimerEnableTimer(CnthpCtl); + } else { + ArmGenericTimerDisableTimer(CnthpCtl); + } +} + +/** + * @brief This API programs the el2 Virt timer with the input timeout value. + * 1. Caller - Test Suite + * 2. Prerequisite - None + * @param timeout - clock ticks after which an interrupt is generated. + * + * @return None + */ +void val_timer_set_vir_el2(uint64_t timeout) +{ + + if (timeout != 0) { + ArmGenericTimerDisableTimer(CnthvCtl); + ArmArchTimerWriteReg(CnthvTval, &timeout); + ArmGenericTimerEnableTimer(CnthvCtl); + } else { + ArmGenericTimerDisableTimer(CnthvCtl); + } +} + +/** + * @brief This API will call PAL layer to fill in the Timer information + * into the g_timer_info_table pointer. + * 1. Caller - Application layer. + * 2. Prerequisite - Memory allocated and passed as argument. + * @param timer_info_table pre-allocated memory pointer for timer_info + * @return Error if Input param is NULL + */ +void val_timer_create_info_table(uint64_t *timer_info_table) +{ + + if (timer_info_table == NULL) { + val_print(ACS_LOG_ERR, "\n Input for Create Info table cannot be NULL"); + return; + } + + g_timer_info_table = (timer_info_table_t *)timer_info_table; + + pal_timer_create_info_table(g_timer_info_table); + + /* UEFI or other EL1 software may have enabled the el1 physical timer. + Disable the timer to prevent interrupts at un-expected times */ + + val_timer_set_phy_el1(0); + + val_print(ACS_LOG_TEST, "\n TIMER_INFO: Number of system timers : %4d", + g_timer_info_table->header.num_platform_timer); + val_pe_data_cache_clean_invalidate((uint64_t)&g_timer_info_table); + +} + +/** + * @brief This API will program and start the counter + * @param cnt_base_n Timer base address + * @param timeout timeout value for timer + * @return None + */ +void val_timer_set_system_timer(addr_t cnt_base_n, uint32_t timeout) +{ + /* Start the System timer */ + val_mmio_write(cnt_base_n + 0x28, timeout); + + /* enable System timer */ + val_mmio_write(cnt_base_n + 0x2C, 1); + +} + +acs_status_t val_configure_second_interrupt(uint32_t *index, uint64_t *int_id) +{ + return pal_configure_second_interrupt(index, int_id); +} + +void val_generate_second_interrupt(uint32_t index, uint32_t timeout) +{ + pal_generate_second_interrupt(index, timeout); +} + +void val_disable_second_interrupt(uint32_t index) +{ + pal_disable_second_interrupt(index); +} + +/** + * @brief This API will stop the counter + * @param cnt_base_n Timer base address + * @return None + */ +void val_timer_disable_system_timer(addr_t cnt_base_n) +{ + /* stop System timer */ + val_mmio_write(cnt_base_n + 0x2C, 0); +} + +/** + * @brief This API will read CNTACR (from CNTCTLBase) to determine whether + * access permission from NS state is permitted + * @param index Timer index + * @return status + */ +uint32_t val_timer_skip_if_cntbase_access_not_allowed(uint64_t index) +{ + uint64_t cnt_ctl_base; + uint32_t data; + + cnt_ctl_base = val_timer_get_info(TIMER_INFO_SYS_CNTL_BASE, index); + if (cnt_ctl_base) { + data = val_mmio_read(cnt_ctl_base + 0x40); + if ((data & 0x1) == 0x1) + return 0; + else { + data |= 0x1; + val_mmio_write(cnt_ctl_base + 0x40, data); + data = val_mmio_read(cnt_ctl_base + 0x40); + if ((data & 0x1) == 1) + return 0; + else + return SDEI_TEST_SKIP; + } + } + else + return SDEI_TEST_SKIP; +} + +/** + * @brief This function frees the allocated memory for timer info table + * @param None + * @return none + */ +void val_timer_free_info_table(void) +{ + pal_free_mem((uint64_t *)g_timer_info_table); +} diff --git a/sdei/val/src/val_timer_support.c b/sdei/val/src/val_timer_support.c new file mode 100644 index 0000000..ca119f1 --- /dev/null +++ b/sdei/val/src/val_timer_support.c @@ -0,0 +1,155 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include "val_interface.h" +#include "pal_interface.h" +#include "val_timer.h" + +/** + * @brief This function reads from the timer registers for given input register address. + * + * @return On success it returns data for given register address. + */ +uint64_t ArmArchTimerReadReg (ARM_ARCH_TIMER_REGS Reg) +{ + switch (Reg) { + + case CntFrq: + return ArmReadCntFrq(); + + case CntPct: + return ArmReadCntPct(); + + case CntkCtl: + return ArmReadCntkCtl(); + + case CntpTval: + return ArmReadCntpTval(); + + case CntpCtl: + return ArmReadCntpCtl(); + + case CntvTval: + return ArmReadCntvTval(); + + case CntvCtl: + return ArmReadCntvCtl(); + + case CntvCt: + return ArmReadCntvCt(); + + case CntpCval: + return ArmReadCntpCval(); + + case CntvCval: + return ArmReadCntvCval(); + + case CntvOff: + return ArmReadCntvOff(); + case CnthpCtl: + return ArmReadCnthpCtl(); + case CnthpTval: + return ArmReadCnthpTval(); +// case CnthvCtl: +// return ArmReadCnthvCtl(); +// case CnthvTval: +// return ArmReadCnthvTval(); + + case CnthCtl: + case CnthpCval: + pal_print (ACS_LOG_ERR, "\n The register is related to Hypervisor Mode." + "Can't perform requested operation"); + break; + + default: + pal_print (ACS_LOG_ERR, "\n Unknown ARM Generic Timer register %x", Reg); + } + + return INVALID_INDEX; +} + +/** + * @brief This function writes data to the timer registers for given input register address. + * + * @return none + */ +void ArmArchTimerWriteReg (ARM_ARCH_TIMER_REGS Reg, uint64_t *data_buf) +{ + switch(Reg) { + + case CntPct: + pal_print(ACS_LOG_ERR, "\n Can't write to Read Only Register: CNTPCT"); + break; + + case CntkCtl: + ArmWriteCntkCtl(*data_buf); + break; + + case CntpTval: + ArmWriteCntpTval(*data_buf); + break; + + case CntpCtl: + ArmWriteCntpCtl(*data_buf); + break; + + case CntvTval: + ArmWriteCntvTval(*data_buf); + break; + + case CntvCtl: + ArmWriteCntvCtl(*data_buf); + break; + + case CntvCt: + pal_print(ACS_LOG_ERR, "\n Can't write to Read Only Register: CNTVCT"); + break; + + case CntpCval: + ArmWriteCntpCval(*data_buf); + break; + + case CntvCval: + ArmWriteCntvCval(*data_buf); + break; + + case CntvOff: + ArmWriteCntvOff(*data_buf); + break; + + case CnthpTval: + ArmWriteCnthpTval(*data_buf); + break; + case CnthpCtl: + ArmWriteCnthpCtl(*data_buf); + break; +// case CnthvTval: +// ArmWriteCnthvTval(*data_buf); +// break; +// case CnthvCtl: +// ArmWriteCnthvCtl(*data_buf); +// break; + case CnthCtl: + case CnthpCval: + pal_print(ACS_LOG_ERR, "\n The register is related to Hypervisor Mode." + "Can't perform requested operation"); + break; + + default: + pal_print(ACS_LOG_ERR, "\n Unknown ARM Generic Timer register %x", Reg); + } +} diff --git a/sdei/val/src/val_wd_timer.c b/sdei/val/src/val_wd_timer.c new file mode 100644 index 0000000..d3bb075 --- /dev/null +++ b/sdei/val/src/val_wd_timer.c @@ -0,0 +1,118 @@ +/** @file + * Copyright (c) 2018, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include "val_interface.h" +#include "pal_interface.h" + +wd_info_table_t *g_wd_info_table; + +/** + * @brief This API is a single point of entry to retrieve + * information stored in the WD Info table + * 1. Caller - Test Suite + * 2. Prerequisite - val_wd_create_info_table + * @param type the type of information being requested + * @return 64-bit data + */ +uint64_t val_wd_get_info(uint32_t index, WD_INFO_TYPE info_type) +{ + + if (g_wd_info_table == NULL) + return 0; + + switch (info_type) { + case WD_INFO_COUNT: + return g_wd_info_table->header.num_wd; + case WD_INFO_CTRL_BASE: + return g_wd_info_table->wd_info[index].wd_ctrl_base; + case WD_INFO_REFRESH_BASE: + return g_wd_info_table->wd_info[index].wd_refresh_base; + case WD_INFO_GSIV: + return g_wd_info_table->wd_info[index].wd_gsiv; + case WD_INFO_ISSECURE: + return ((g_wd_info_table->wd_info[index].wd_flags >> 2) & 1); + default: + return 0; + } +} + +/** + * @brief This API creates the watchdog info table. + * + * @param wd_info_table pre-allocated memory pointer for wd_info + * + * @return status + */ +int val_wd_create_info_table(uint64_t *wd_info_table) +{ + int32_t ret = 0; + + if (wd_info_table == NULL) { + val_print(ACS_LOG_ERR, "\n Input for Create Info table cannot be NULL"); + return 1; + } + + g_wd_info_table = (wd_info_table_t *)wd_info_table; + ret = pal_wd_create_info_table(g_wd_info_table); + + val_print(ACS_LOG_INFO, "\n WATCHDOG_INFO: Number of Watchdogs : %lld", + val_wd_get_info(0, WD_INFO_COUNT)); + val_pe_data_cache_clean_invalidate((uint64_t)&g_wd_info_table); + + return ret; +} + +/** + * @brief This API Enables watchdog by writing to Control Base register + * @param index identifies the watchdog instance to enable + * @return None + */ +void val_wd_enable(uint32_t index) +{ + val_mmio_write(g_wd_info_table->wd_info[index].wd_ctrl_base, 1); +} + +/** + * @brief This API disables watchdog by writing to Control Base register + * @param index identifies the watchdog instance to enable + * @return None + */ +void val_wd_disable(uint32_t index) +{ + val_mmio_write(g_wd_info_table->wd_info[index].wd_ctrl_base, 0); +} + +/** + * @brief This API arms the watchdog by writing to Control Base register + * @param index identifies the watchdog instance to program + * @param timeout ticks to generation of ws0 interrupt + * @return None + */ +void val_wd_set_ws0(uint64_t *vaddr, uint32_t index, uint32_t timeout) +{ + pal_wd_set_ws0(vaddr, g_wd_info_table->wd_info[index].wd_ctrl_base, index, timeout); +} + +/** + * @brief This function frees the allocated memory for Watchdog info table + * @param None + * @return none + */ +void val_watchdog_free_info_table(void) +{ + pal_free_mem((uint64_t *)g_wd_info_table); +}