diff --git a/apps/uefi/Bsa.inf b/apps/uefi/Bsa.inf index e3144fd0..55d5e315 100644 --- a/apps/uefi/Bsa.inf +++ b/apps/uefi/Bsa.inf @@ -296,6 +296,7 @@ ../../test_pool/ras/ras014.c ../../test_pool/ras/ras016.c ../../test_pool/ras/ras017.c + ../../test_pool/ras/ras018.c ../../test_pool/ete/ete001.c ../../test_pool/ete/ete002.c ../../test_pool/ete/ete003.c diff --git a/apps/uefi/Sbsa.inf b/apps/uefi/Sbsa.inf index faaabb29..c6eb68fb 100644 --- a/apps/uefi/Sbsa.inf +++ b/apps/uefi/Sbsa.inf @@ -300,6 +300,7 @@ ../../test_pool/ras/ras014.c ../../test_pool/ras/ras016.c ../../test_pool/ras/ras017.c + ../../test_pool/ras/ras018.c ../../test_pool/ete/ete001.c ../../test_pool/ete/ete002.c ../../test_pool/ete/ete003.c diff --git a/apps/uefi/SbsaNist.inf b/apps/uefi/SbsaNist.inf index 8cdc9855..b1111f92 100644 --- a/apps/uefi/SbsaNist.inf +++ b/apps/uefi/SbsaNist.inf @@ -191,6 +191,7 @@ ../../test_pool/ras/ras014.c ../../test_pool/ras/ras016.c ../../test_pool/ras/ras017.c + ../../test_pool/ras/ras018.c ../../test_pool/ete/ete001.c ../../test_pool/ete/ete002.c ../../test_pool/ete/ete003.c diff --git a/apps/uefi/Vbsa.inf b/apps/uefi/Vbsa.inf index 38eb5134..87199860 100644 --- a/apps/uefi/Vbsa.inf +++ b/apps/uefi/Vbsa.inf @@ -299,6 +299,7 @@ ../../test_pool/ras/ras014.c ../../test_pool/ras/ras016.c ../../test_pool/ras/ras017.c + ../../test_pool/ras/ras018.c ../../test_pool/ete/ete001.c ../../test_pool/ete/ete002.c ../../test_pool/ete/ete003.c diff --git a/apps/uefi/pc_bsa.inf b/apps/uefi/pc_bsa.inf index 5dfb921e..0e68e541 100644 --- a/apps/uefi/pc_bsa.inf +++ b/apps/uefi/pc_bsa.inf @@ -299,6 +299,7 @@ ../../test_pool/ras/ras014.c ../../test_pool/ras/ras016.c ../../test_pool/ras/ras017.c + ../../test_pool/ras/ras018.c ../../test_pool/ete/ete001.c ../../test_pool/ete/ete002.c ../../test_pool/ete/ete003.c diff --git a/apps/uefi/xbsa_acpi.inf b/apps/uefi/xbsa_acpi.inf index 421bdb81..6d187db7 100644 --- a/apps/uefi/xbsa_acpi.inf +++ b/apps/uefi/xbsa_acpi.inf @@ -297,6 +297,7 @@ ../../test_pool/ras/ras014.c ../../test_pool/ras/ras016.c ../../test_pool/ras/ras017.c + ../../test_pool/ras/ras018.c ../../test_pool/ete/ete001.c ../../test_pool/ete/ete002.c ../../test_pool/ete/ete003.c diff --git a/test_pool/ras/ras009.c b/test_pool/ras/ras009.c index fe96840f..64a74157 100644 --- a/test_pool/ras/ras009.c +++ b/test_pool/ras/ras009.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2023-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2023-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -54,6 +54,7 @@ payload() uint64_t node_type; uint64_t err_inj_addr; uint64_t prox_base_addr; + uint64_t anerr = 0; uint32_t status; uint32_t fail_cnt = 0, test_skip = 0; @@ -65,6 +66,22 @@ payload() RAS_ERR_IN_t err_in_params; RAS_ERR_OUT_t err_out_params; + /* Read ID_AA64MMFR3_EL1.ANERR[47:44] == 0b0010 or 0b0011 indicate FEAT_ANERR support */ + anerr = VAL_EXTRACT_BITS(val_pe_reg_read(ID_AA64MMFR3_EL1), 44, 47); + + val_print(ACS_PRINT_INFO, "\n ID_AA64MMFR3_EL1.ANERR field = 0x%llx", anerr); + + if (anerr == FEAT_ANERR_VAL2 || anerr == FEAT_ANERR_VAL3) { + val_print(ACS_PRINT_INFO, "\n FEAT_ANERR implemented.", 0); + val_set_status(index, RESULT_PASS(TEST_NUM, 01)); + return; + } + + val_print(ACS_PRINT_INFO, + "\n FEAT_ANERR not implemented." + " Proceeding to synchronous Data Abort test.\n", + 0); + /* get number of nodes with RAS functionality */ status = val_ras_get_info(RAS_INFO_NUM_NODES, 0, &num_node); if (status || (num_node == 0)) { @@ -188,7 +205,7 @@ payload() return; } - val_set_status(index, RESULT_PASS(TEST_NUM, 01)); + val_set_status(index, RESULT_PASS(TEST_NUM, 02)); } uint32_t diff --git a/test_pool/ras/ras018.c b/test_pool/ras/ras018.c new file mode 100644 index 00000000..5f6c6b93 --- /dev/null +++ b/test_pool/ras/ras018.c @@ -0,0 +1,219 @@ +/** @file + * Copyright (c) 2026, 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/include/acs_val.h" +#include "val/include/acs_common.h" +#include "val/include/acs_pe.h" +#include "val/include/val_interface.h" +#include "val/include/acs_memory.h" +#include "val/include/acs_mpam.h" +#include "val/include/acs_ras.h" + +#define TEST_NUM (ACS_RAS_TEST_NUM_BASE + 18) +#define TEST_RULE "KBRZG" +#define TEST_DESC "Data abort on containable device err " + +static uint32_t esr_pending = 1; +static void *branch_to_test; + +static +void +esr(uint64_t interrupt_type, void *context) +{ + esr_pending = 0; + + /* Update the ELR to return to test specified address */ + val_pe_update_elr(context, (uint64_t)branch_to_test); + + val_print(ACS_PRINT_ERR, "\n Received exception of type: 0x%llx", interrupt_type); +} + +static +void +payload() +{ + uint64_t num_node; + uint64_t intf_type; + uint64_t dev_addr; + uint64_t attr = 0; + uint32_t read_data; + + uint32_t status; + uint32_t fail_cnt = 0; + uint32_t test_skip = 0; + uint32_t node_index; + uint32_t usable_node_cnt = 0; + uint64_t aderr = 0; + uint64_t num_err; + + uint32_t index = val_pe_get_index_mpid(val_pe_get_mpid()); + + RAS_ERR_IN_t err_in_params; + RAS_ERR_OUT_t err_out_params; + + /* Read ID_AA64MMFR3_EL1.ADERR[59:56] == 0b0010 or 0b0011 indicate FEAT_ADERR support */ + aderr = VAL_EXTRACT_BITS(val_pe_reg_read(ID_AA64MMFR3_EL1), 56, 59); + + val_print(ACS_PRINT_INFO, "\n ID_AA64MMFR3_EL1.ADERR field = 0x%llx", aderr); + + if (aderr == FEAT_ADERR_VAL2 || aderr == FEAT_ADERR_VAL3) { + val_print(ACS_PRINT_INFO, "\n FEAT_ADERR implemented.", 0); + val_set_status(index, RESULT_PASS(TEST_NUM, 01)); + return; + } + + val_print(ACS_PRINT_INFO, + "\n FEAT_ADERR not implemented. " + "Proceeding to synchronous Data Abort test.", + 0); + + /* get number of nodes with RAS functionality */ + status = val_ras_get_info(RAS_INFO_NUM_NODES, 0, &num_node); + if (status || (num_node == 0)) { + val_print(ACS_PRINT_ERR, + "\n RAS nodes not found. " + "Firmware interface is missing. Please conduct a paper-based analysis.", + 0); + val_set_status(index, RESULT_WARN(TEST_NUM, 01)); + return; + } + + for (node_index = 0; node_index < num_node; node_index++) { + + esr_pending = 1; + + /* MMIO-only filter */ + status = val_ras_get_info(RAS_INFO_INTF_TYPE, node_index, &intf_type); + status |= val_ras_get_info(RAS_INFO_NUM_ERR_REC, node_index, &num_err); + + if (status || (intf_type != RAS_INTERFACE_MMIO) || (num_err == 0)) { + val_print(ACS_PRINT_DEBUG, "\n intf_type: 0x%llx", intf_type); + val_print(ACS_PRINT_DEBUG, "\n num_err: 0x%llx", num_err); + continue; + } + + usable_node_cnt++; + + dev_addr = val_memory_get_addr(MEM_TYPE_DEVICE, 0, &attr); + + if (!dev_addr) { + val_print(ACS_PRINT_ERR, + "\n Failed to obtain Device memory address.\n", 0); + val_set_status(index, RESULT_FAIL(TEST_NUM, 01)); + return; + } + + val_print(ACS_PRINT_INFO, + "\n Using Device memory address: 0x%llx\n", dev_addr); + + /* Install sync and async handlers to handle exceptions.*/ + status = val_pe_install_esr(EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS, esr); + status |= val_pe_install_esr(EXCEPT_AARCH64_SERROR, esr); + if (status) { + val_print(ACS_PRINT_ERR, "\n Failed in installing the exception handler", 0); + val_set_status(index, RESULT_FAIL(TEST_NUM, 02)); + return; + } + branch_to_test = &&exception_return; + + /* Inject error with following parameters */ + err_in_params.rec_index = 0; /* not applicable for scenario*/ + err_in_params.node_index = node_index; + err_in_params.ras_error_type = ERR_CONTAINABLE; /* containable error */ + err_in_params.error_pa = dev_addr; /* address of the location where error + needs to be injected */ + err_in_params.is_pfg_check = 0; /* not a pseudo fault check */ + + /* Setup error in an implementation defined way */ + status = val_ras_setup_error(err_in_params, &err_out_params); + if (status) { + val_print(ACS_PRINT_ERR, "\n val_ras_setup_error failed, node %d", node_index); + fail_cnt++; + break; + } + + /* Inject error in an implementation defined way. + Inject error at an address, which will cause system to + record the error on reading with address syndrome in one of + the error records present for the current RAS node */ + status = val_ras_inject_error(err_in_params, &err_out_params); + if (status) { + val_print(ACS_PRINT_ERR, "\n val_ras_inject_error failed, node %d", node_index); + fail_cnt++; + break; + } + + /* wait loop to allow system to inject the error */ + val_ras_wait_timeout(10); + + /* Perform a read to error-injected address, which will cause + * system to record the error with address syndrome in one of + * the error records present for the current RAS node */ + read_data = val_mmio_read(dev_addr); + val_print(ACS_PRINT_DEBUG, "\n Error injected address: 0x%llx", dev_addr); + val_print(ACS_PRINT_DEBUG, "\n Data read: 0x%lx", read_data); + + exception_return: + val_print(ACS_PRINT_INFO, "\n value esr_pending, %d", esr_pending); + /* Check that a synchronous Data Abort was received */ + if (esr_pending) { + val_print(ACS_PRINT_DEBUG, "\n Data abort Check Fail, for node %d", node_index); + fail_cnt++; + continue; + } + } + + if (usable_node_cnt == 0) { + val_print(ACS_PRINT_INFO, + "\n No usable MMIO RAS nodes -- skipping test.\n", 0); + val_set_status(index, RESULT_SKIP(TEST_NUM, 01)); + return; + } + + if (fail_cnt) { + val_set_status(index, RESULT_FAIL(TEST_NUM, 03)); + return; + } + else if (test_skip) { + val_set_status(index, RESULT_SKIP(TEST_NUM, 02)); + return; + } + + val_set_status(index, RESULT_PASS(TEST_NUM, 02)); +} + +uint32_t +ras018_entry(uint32_t num_pe) +{ + + uint32_t status = ACS_STATUS_FAIL; + + num_pe = 1; /* This test is run on single processor */ + + val_log_context((char8_t *)__FILE__, (char8_t *)__func__, __LINE__); + status = val_initialize_test(TEST_NUM, TEST_DESC, num_pe); + + if (status != ACS_STATUS_SKIP) + val_run_test_payload(TEST_NUM, num_pe, payload, 0); + + /* get the result from all PE and check for failure */ + status = val_check_for_error(TEST_NUM, num_pe, TEST_RULE); + + val_report_status(0, ACS_END(TEST_NUM), TEST_RULE); + + return status; +} diff --git a/tools/cmake/infra/sbsa_test.txt b/tools/cmake/infra/sbsa_test.txt index 0470cb3b..a4e0532d 100644 --- a/tools/cmake/infra/sbsa_test.txt +++ b/tools/cmake/infra/sbsa_test.txt @@ -157,6 +157,7 @@ ras013.c ras014.c ras016.c ras017.c +ras018.c ete001.c ete002.c ete003.c diff --git a/val/include/acs_pe.h b/val/include/acs_pe.h index 9417d4fe..599f90a2 100644 --- a/val/include/acs_pe.h +++ b/val/include/acs_pe.h @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2020,2022-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2020,2022-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -104,6 +104,7 @@ typedef enum { ID_AA64MMFR0_EL1, ID_AA64MMFR1_EL1, ID_AA64MMFR2_EL1, + ID_AA64MMFR3_EL1, ID_AA64DFR0_EL1, ID_AA64DFR1_EL1, CTR_EL0, @@ -201,6 +202,7 @@ uint64_t ArmReadIdPfr1(void); uint64_t AA64ReadMmfr0(void); uint64_t AA64ReadMmfr1(void); uint64_t AA64ReadMmfr2(void); +uint64_t AA64ReadMmfr3(void); uint64_t AA64ReadCtr(void); uint64_t AA64ReadIsar0(void); uint64_t AA64ReadIsar1(void); diff --git a/val/include/acs_ras.h b/val/include/acs_ras.h index dfcd786a..423410df 100644 --- a/val/include/acs_ras.h +++ b/val/include/acs_ras.h @@ -64,6 +64,11 @@ #define RAS_VERSION_2 0x3 +#define FEAT_ANERR_VAL2 0x2 +#define FEAT_ANERR_VAL3 0x3 +#define FEAT_ADERR_VAL2 0x2 +#define FEAT_ADERR_VAL3 0x3 + #define ACS_ALL_1_64BIT 0xFFFFFFFFFFFFFFFF typedef enum { @@ -124,6 +129,7 @@ uint32_t ras014_entry(uint32_t num_pe); uint32_t ras015_entry(uint32_t num_pe); uint32_t ras016_entry(uint32_t num_pe); uint32_t ras017_entry(uint32_t num_pe); +uint32_t ras018_entry(uint32_t num_pe); uint64_t AA64ReadErrIdr1(void); uint64_t AA64ReadErrAddr1(void); diff --git a/val/include/rule_based_execution_enum.h b/val/include/rule_based_execution_enum.h index 717096b2..38607b87 100644 --- a/val/include/rule_based_execution_enum.h +++ b/val/include/rule_based_execution_enum.h @@ -668,6 +668,7 @@ typedef enum { RAS013_ENTRY, RAS016_ENTRY, RAS017_ENTRY, + RAS018_ENTRY, I001_ENTRY, I007_ENTRY, I002_ENTRY, diff --git a/val/src/AArch64/PeRegSysSupport.S b/val/src/AArch64/PeRegSysSupport.S index f3d7095a..15964e41 100644 --- a/val/src/AArch64/PeRegSysSupport.S +++ b/val/src/AArch64/PeRegSysSupport.S @@ -1,5 +1,5 @@ #/** @file -# Copyright (c) 2016-2020,2021,2024-2025, Arm Limited or its affiliates. All rights reserved. +# Copyright (c) 2016-2020,2021,2024-2026, Arm Limited or its affiliates. All rights reserved. # SPDX-License-Identifier : Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -44,6 +44,7 @@ GCC_ASM_EXPORT (ArmReadIdPfr1) GCC_ASM_EXPORT (AA64ReadMmfr0) GCC_ASM_EXPORT (AA64ReadMmfr1) GCC_ASM_EXPORT (AA64ReadMmfr2) +GCC_ASM_EXPORT (AA64ReadMmfr3) GCC_ASM_EXPORT (AA64ReadCtr) GCC_ASM_EXPORT (ArmReadMmfr0) GCC_ASM_EXPORT (AA64ReadIsar0) @@ -178,6 +179,10 @@ ASM_PFX(AA64ReadMmfr2): mrs x0, id_aa64mmfr2_el1 ret +ASM_PFX(AA64ReadMmfr3): + mrs x0, id_aa64mmfr3_el1 + ret + ASM_PFX(AA64ReadCtr): mrs x0, ctr_el0 ret @@ -729,4 +734,4 @@ ASM_PFX(AA64ReadTrbPtrEl1): ASM_PFX(AA64IssueISB): isb - ret \ No newline at end of file + ret diff --git a/val/src/acs_pe.c b/val/src/acs_pe.c index 0874a705..27b60d0c 100644 --- a/val/src/acs_pe.c +++ b/val/src/acs_pe.c @@ -1,5 +1,5 @@ /** @file - * Copyright (c) 2016-2025, Arm Limited or its affiliates. All rights reserved. + * Copyright (c) 2016-2026, Arm Limited or its affiliates. All rights reserved. * SPDX-License-Identifier : Apache-2.0 * Licensed under the Apache License, Version 2.0 (the "License"); @@ -64,6 +64,8 @@ val_pe_reg_read(uint32_t reg_id) return AA64ReadMmfr1(); case ID_AA64MMFR2_EL1: return AA64ReadMmfr2(); + case ID_AA64MMFR3_EL1: + return AA64ReadMmfr3(); case CTR_EL0: return AA64ReadCtr(); case ID_AA64ISAR0_EL1: diff --git a/val/src/rule_metadata.c b/val/src/rule_metadata.c index 278d5db1..f31156c6 100644 --- a/val/src/rule_metadata.c +++ b/val/src/rule_metadata.c @@ -1092,6 +1092,14 @@ rule_test_map_t rule_test_map[RULE_ID_SENTINEL] = { .flag = BASE_RULE, .test_num = ACS_RAS_TEST_NUM_BASE + 17, }, + [KBRZG] = { + .test_entry_id = RAS018_ENTRY, + .module_id = RAS, + .rule_desc = "Data abort on containable Device err", + .platform_bitmask = PLATFORM_BAREMETAL | PLATFORM_UEFI, + .flag = BASE_RULE, + .test_num = ACS_RAS_TEST_NUM_BASE + 18, + }, /* SMMU */ [B_SMMU_01] = { .test_entry_id = I001_ENTRY, @@ -2948,6 +2956,7 @@ test_entry_fn_t test_entry_func_table[TEST_ENTRY_SENTINEL] = { [RAS015_ENTRY] = ras015_entry, [RAS016_ENTRY] = ras016_entry, [RAS017_ENTRY] = ras017_entry, + [RAS018_ENTRY] = ras018_entry, [SYS_RAS_2_ENTRY] = sys_ras_2_entry, [TPM001_ENTRY] = tpm001_entry, [TPM002_ENTRY] = tpm002_entry, @@ -3202,6 +3211,7 @@ test_entry_fn_t test_entry_func_table[TEST_ENTRY_SENTINEL] = { [RAS008_ENTRY] = ras008_entry, [RAS014_ENTRY] = ras014_entry, [RAS005_ENTRY] = ras005_entry, + [RAS018_ENTRY] = ras018_entry, [E027_ENTRY] = e027_entry, [E026_ENTRY] = e026_entry, [E032_ENTRY] = e032_entry,