diff --git a/apps/uefi/Bsa.inf b/apps/uefi/Bsa.inf index d79e29c0..955a7ad5 100644 --- a/apps/uefi/Bsa.inf +++ b/apps/uefi/Bsa.inf @@ -85,6 +85,7 @@ ../../test_pool/timer/t005.c ../../test_pool/timer/t006.c ../../test_pool/timer/t008.c + ../../test_pool/timer/t009.c ../../test_pool/watchdog/w001.c ../../test_pool/watchdog/w002.c ../../test_pool/peripherals/d001.c diff --git a/apps/uefi/Sbsa.inf b/apps/uefi/Sbsa.inf index d6acec0a..d8be7a8a 100644 --- a/apps/uefi/Sbsa.inf +++ b/apps/uefi/Sbsa.inf @@ -88,6 +88,7 @@ ../../test_pool/timer/t005.c ../../test_pool/timer/t006.c ../../test_pool/timer/t008.c + ../../test_pool/timer/t009.c ../../test_pool/watchdog/w001.c ../../test_pool/watchdog/w002.c ../../test_pool/peripherals/d001.c diff --git a/apps/uefi/Vbsa.inf b/apps/uefi/Vbsa.inf index 4b152964..509b1d5a 100644 --- a/apps/uefi/Vbsa.inf +++ b/apps/uefi/Vbsa.inf @@ -87,6 +87,7 @@ ../../test_pool/timer/t005.c ../../test_pool/timer/t006.c ../../test_pool/timer/t008.c + ../../test_pool/timer/t009.c ../../test_pool/watchdog/w001.c ../../test_pool/watchdog/w002.c ../../test_pool/peripherals/d001.c diff --git a/apps/uefi/pc_bsa.inf b/apps/uefi/pc_bsa.inf index 4b48389d..d003f3b4 100644 --- a/apps/uefi/pc_bsa.inf +++ b/apps/uefi/pc_bsa.inf @@ -88,6 +88,7 @@ ../../test_pool/timer/t005.c ../../test_pool/timer/t006.c ../../test_pool/timer/t008.c + ../../test_pool/timer/t009.c ../../test_pool/watchdog/w001.c ../../test_pool/watchdog/w002.c ../../test_pool/peripherals/d001.c diff --git a/apps/uefi/xbsa_acpi.inf b/apps/uefi/xbsa_acpi.inf index a339354d..33b6363f 100644 --- a/apps/uefi/xbsa_acpi.inf +++ b/apps/uefi/xbsa_acpi.inf @@ -195,6 +195,7 @@ ../../test_pool/gic/g016.c ../../test_pool/timer/t006.c ../../test_pool/timer/t008.c + ../../test_pool/timer/t009.c ../../test_pool/watchdog/w003.c ../../test_pool/smmu/i008.c ../../test_pool/smmu/i009.c diff --git a/docs/bsa/arm_bsa_testcase_checklist.md b/docs/bsa/arm_bsa_testcase_checklist.md index 1d0fd854..1f641898 100644 --- a/docs/bsa/arm_bsa_testcase_checklist.md +++ b/docs/bsa/arm_bsa_testcase_checklist.md @@ -663,11 +663,11 @@ The checklist provides information about: L1 B_TIME_05 B_TIME_05 - Not Covered - - - - + 501,502,503,504,505 + Check sys cnt visible to PE timers + Yes + Yes + No @@ -718,11 +718,11 @@ The checklist provides information about: L1 B_TIME_10 B_TIME_10 - Not Covered - - - - + 410 + Check Non-secure timer frame access + Yes + Yes + No diff --git a/test_pool/timer/t009.c b/test_pool/timer/t009.c new file mode 100644 index 00000000..2decb853 --- /dev/null +++ b/test_pool/timer/t009.c @@ -0,0 +1,165 @@ +/** @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 "acs_val.h" +#include "val_interface.h" +#include "acs_pe.h" +#include "acs_timer.h" + +#define TEST_NUM (ACS_TIMER_TEST_NUM_BASE + 10) +#define TEST_RULE "B_TIME_10" +#define TEST_DESC "Check Non-secure timer frame access " + +#define ACCESS_CNTTIDR 1 +#define ACCESS_CNTPCT 2 + +static void *branch_to_test; +static uint64_t fault_timer_index; +static uint32_t fault_access_type; + +static +void +esr(uint64_t interrupt_type, void *context) +{ + uint32_t index = val_pe_get_index_mpid(val_pe_get_mpid()); + + val_pe_update_elr(context, (uint64_t)branch_to_test); + + val_print(ERROR, "\n Received exception type %d", interrupt_type); + if (fault_access_type == ACCESS_CNTTIDR) + val_print(ERROR, " during CNTCTLBase.CNTTIDR read for timer %llx", fault_timer_index); + else if (fault_access_type == ACCESS_CNTPCT) + val_print(ERROR, " during CNTBaseN.CNTPCT read for timer %llx", fault_timer_index); + val_set_status(index, RESULT_FAIL(1)); +} + +static +void +payload() +{ + uint32_t index = val_pe_get_index_mpid(val_pe_get_mpid()); + uint32_t status; + uint32_t ns_timer = 0; + uint32_t readable_timer = 0; + uint32_t cnttidr; + uint64_t cnt_ctl_base; + uint64_t cnt_base_n; + uint64_t cntpct; + uint64_t timer_num = val_timer_get_info(TIMER_INFO_NUM_PLATFORM_TIMERS, 0); + + branch_to_test = &&exception_taken; + status = val_pe_install_esr(EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS, esr); + status |= val_pe_install_esr(EXCEPT_AARCH64_SERROR, esr); + if (status) { + val_print(ERROR, "\n Failed to install exception handlers"); + val_set_status(index, RESULT_FAIL(2)); + return; + } + + if (!timer_num) { + val_print(DEBUG, "\n No System timers are defined"); + val_set_status(index, RESULT_SKIP(1)); + return; + } + + while (timer_num) { + --timer_num; + + /* Skip secure timers */ + if (val_timer_get_info(TIMER_INFO_IS_PLATFORM_TIMER_SECURE, timer_num)) + continue; + + ns_timer++; + cnt_ctl_base = val_timer_get_info(TIMER_INFO_SYS_CNTL_BASE, timer_num); + cnt_base_n = val_timer_get_info(TIMER_INFO_SYS_CNT_BASE_N, timer_num); + + /* + * Firmware should expose non-zero base addresses for usable Non-secure + * timer frames. Keep scanning other frames so one bad descriptor does not + * hide a later usable frame. + */ + if (cnt_ctl_base == 0) + val_print(WARN, "\n CNTCTL BASE is zero for timer %llx", timer_num); + + if (cnt_base_n == 0) + val_print(WARN, "\n CNT_BASE_N is zero for timer %llx", timer_num); + + if ((cnt_ctl_base == 0) || (cnt_base_n == 0)) + continue; + + /* + * The payload checks Non-secure memory access of CNTCTLBase and CNTBaseN, + * not register behavior. Do read probes only: no writes, no read-only/RW + * validation, and no CNTACR permission interpretation. + */ + fault_timer_index = timer_num; + fault_access_type = ACCESS_CNTTIDR; + cnttidr = val_mmio_read(cnt_ctl_base + CNTTIDR); + val_print(DEBUG, "\n CNTTIDR Read value = 0x%x", cnttidr); + + /* + * CNTPCT may legally read as RAZ/WI if CNTACR.RPCT is clear. That is + * acceptable here because CNTACR/CNTNSAR policy is Secure-state owned; + * this test only requires that the Non-secure read access itself does + * not fault. + */ + fault_access_type = ACCESS_CNTPCT; + cntpct = val_mmio_read64(cnt_base_n + CNTPCT_LOWER); + val_print(DEBUG, "\n CNTPCT Read value = 0x%llx", cntpct); + + readable_timer++; + } + + /* Report fail if OS visible platform timers exists, but non of them are non-secure access */ + if (!ns_timer) { + val_print(ERROR, "\n No non-secure systimer implemented"); + val_set_status(index, RESULT_FAIL(3)); + return; + } + + if (!readable_timer) { + val_print(ERROR, "\n No usable non-secure systimer frame found"); + val_set_status(index, RESULT_FAIL(4)); + return; + } + + val_set_status(index, RESULT_PASS); + +exception_taken: + return; +} + +uint32_t +t009_entry(uint32_t num_pe) +{ + uint32_t status = ACS_STATUS_FAIL; + + num_pe = 1; + + 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), NULL); + + return status; +} diff --git a/tools/cmake/infra/bsa_test.txt b/tools/cmake/infra/bsa_test.txt index f65fbd7f..6fca881b 100644 --- a/tools/cmake/infra/bsa_test.txt +++ b/tools/cmake/infra/bsa_test.txt @@ -49,6 +49,7 @@ t002.c t003.c t004.c t005.c +t009.c w001.c w002.c d001.c diff --git a/tools/cmake/infra/pc_bsa_test.txt b/tools/cmake/infra/pc_bsa_test.txt index 527afa0b..def7d689 100644 --- a/tools/cmake/infra/pc_bsa_test.txt +++ b/tools/cmake/infra/pc_bsa_test.txt @@ -100,6 +100,7 @@ t002.c t003.c t004.c t005.c +t009.c tpm001.c tpm002.c e001.c diff --git a/val/include/acs_timer.h b/val/include/acs_timer.h index d4f41076..e0d05daf 100644 --- a/val/include/acs_timer.h +++ b/val/include/acs_timer.h @@ -49,4 +49,5 @@ uint32_t t004_entry(uint32_t num_pe); uint32_t t005_entry(uint32_t num_pe); uint32_t t006_entry(uint32_t num_pe); uint32_t t008_entry(uint32_t num_pe); +uint32_t t009_entry(uint32_t num_pe); #endif // __ACS_TIMER_H__ diff --git a/val/include/rule_based_execution_enum.h b/val/include/rule_based_execution_enum.h index 0a94d1eb..a2a614c7 100644 --- a/val/include/rule_based_execution_enum.h +++ b/val/include/rule_based_execution_enum.h @@ -765,6 +765,7 @@ typedef enum { T005_ENTRY, T006_ENTRY, T008_ENTRY, + T009_ENTRY, W001_ENTRY, W002_ENTRY, W003_ENTRY, diff --git a/val/src/rule_metadata.c b/val/src/rule_metadata.c index 4c1b7aef..04dbc52f 100644 --- a/val/src/rule_metadata.c +++ b/val/src/rule_metadata.c @@ -1404,6 +1404,13 @@ rule_test_map_t rule_test_map[RULE_ID_SENTINEL] = { .flag = BASE_RULE, .test_num = ACS_TIMER_TEST_NUM_BASE + 1, }, + [B_TIME_05] = { + .test_entry_id = B_WAK_03_07_ENTRY, + .module_id = TIMER, + .rule_desc = "Check sys cnt visible to PE timers", + .platform_bitmask = PLATFORM_BAREMETAL | PLATFORM_UEFI, + .flag = BASE_RULE, + }, [B_TIME_06] = { .test_entry_id = T002_ENTRY, .module_id = TIMER, @@ -1436,6 +1443,14 @@ rule_test_map_t rule_test_map[RULE_ID_SENTINEL] = { .flag = BASE_RULE, .test_num = ACS_TIMER_TEST_NUM_BASE + 5, }, + [B_TIME_10] = { + .test_entry_id = T009_ENTRY, + .module_id = TIMER, + .rule_desc = "Check Non-secure timer frame access", + .platform_bitmask = PLATFORM_BAREMETAL | PLATFORM_UEFI, + .flag = BASE_RULE, + .test_num = ACS_TIMER_TEST_NUM_BASE + 10, + }, [S_L5TI_01] = { .test_entry_id = T006_ENTRY, .module_id = TIMER, @@ -3125,12 +3140,6 @@ rule_test_map_t rule_test_map[RULE_ID_SENTINEL] = { [B_TIME_04] = { .module_id = TIMER, }, - [B_TIME_05] = { - .module_id = TIMER, - }, - [B_TIME_10] = { - .module_id = TIMER, - }, [S_L8TI_01] = { .module_id = TIMER, }, @@ -3803,6 +3812,7 @@ test_entry_fn_t test_entry_func_table[TEST_ENTRY_SENTINEL] = { [T004_ENTRY] = t004_entry, [T005_ENTRY] = t005_entry, [T008_ENTRY] = t008_entry, + [T009_ENTRY] = t009_entry, [U001_ENTRY] = u001_entry, // used in wrapper. [U002_ENTRY] = u002_entry, // used in wrapper. [U003_ENTRY] = u003_entry, // used in wrapper. @@ -3917,6 +3927,7 @@ test_entry_fn_t test_entry_func_table[TEST_ENTRY_SENTINEL] = { [T003_ENTRY] = t003_entry, [T004_ENTRY] = t004_entry, [T005_ENTRY] = t005_entry, + [T009_ENTRY] = t009_entry, [W001_ENTRY] = w001_entry, [W002_ENTRY] = w002_entry, [D001_ENTRY] = d001_entry, @@ -4290,6 +4301,7 @@ test_entry_fn_t test_entry_func_table[TEST_ENTRY_SENTINEL] = { [T004_ENTRY] = t004_entry, [T001_ENTRY] = t001_entry, [T002_ENTRY] = t002_entry, + [T009_ENTRY] = t009_entry, [E039_ENTRY] = e039_entry, // used in wrapper. [E035_ENTRY] = e035_entry, [E013_ENTRY] = e013_entry,