| // SPDX-License-Identifier: BSD-2-Clause |
| /* |
| * Copyright (c) 2016, Linaro Limited |
| */ |
| #include <crypto/crypto.h> |
| #include <keep.h> |
| #include <kernel/interrupt.h> |
| #include <kernel/misc.h> |
| #include <kernel/pseudo_ta.h> |
| #include <kernel/tee_time.h> |
| #include <kernel/thread.h> |
| #include <platform_config.h> |
| #include <string.h> |
| #include <trace.h> |
| |
| #define TA_NAME "interrupt_tests.ta" |
| |
| #define INTERRUPT_TESTS_UUID \ |
| { 0x48d58475, 0x3d5e, 0x4202, \ |
| { 0xa7, 0x75, 0x97, 0x85, 0xd2, 0x0f, 0x78, 0xae } } |
| |
| #define CMD_INTERRUPT_TESTS 0 |
| |
| #define SGI_NUM 16 |
| #define PPI_NUM 32 |
| |
| #ifndef TEST_SGI_ID |
| #define TEST_SGI_ID 11 |
| #endif |
| #ifndef TEST_PPI_ID |
| #define TEST_PPI_ID 29 |
| #endif |
| #ifndef TEST_SPI_ID |
| #define TEST_SPI_ID 61 |
| #endif |
| #ifndef TEST_TIMES |
| #define TEST_TIMES 3 |
| #endif |
| |
| /* |
| * Trusted Application Entry Points |
| */ |
| |
| static size_t test_sgi_value[CFG_TEE_CORE_NB_CORE]; |
| static size_t test_spi_value[CFG_TEE_CORE_NB_CORE]; |
| static size_t test_ppi_value[CFG_TEE_CORE_NB_CORE]; |
| static size_t expect_sgi_value[CFG_TEE_CORE_NB_CORE]; |
| static size_t expect_spi_value[CFG_TEE_CORE_NB_CORE]; |
| static size_t expect_ppi_value[CFG_TEE_CORE_NB_CORE]; |
| |
| static enum itr_return __maybe_unused ihandler_ok(struct itr_handler *handler) |
| { |
| size_t core_num = get_core_pos(); |
| |
| assert(core_num < CFG_TEE_CORE_NB_CORE); |
| |
| if (handler->it < SGI_NUM) |
| test_sgi_value[core_num]++; |
| else if (handler->it < PPI_NUM) |
| test_ppi_value[core_num]++; |
| else |
| test_spi_value[core_num]++; |
| |
| return ITRR_HANDLED; |
| } |
| KEEP_PAGER(ihandler_ok); |
| |
| struct itr_handler sgi_handler = { |
| .it = TEST_SGI_ID, |
| .handler = ihandler_ok, |
| }; |
| |
| struct itr_handler spi_handler = { |
| .it = TEST_SPI_ID, |
| .handler = ihandler_ok, |
| }; |
| |
| struct itr_handler ppi_handler = { |
| .it = TEST_PPI_ID, |
| .handler = ihandler_ok, |
| }; |
| |
| static TEE_Result test_sgi(void) |
| { |
| TEE_Result res; |
| uint8_t i; |
| uint8_t j; |
| uint8_t num; |
| uint8_t cpu_mask; |
| |
| itr_add(&sgi_handler); |
| itr_enable(TEST_SGI_ID); |
| |
| for (i = 0; i < CFG_TEE_CORE_NB_CORE; i++) |
| expect_sgi_value[i]++; |
| itr_raise_sgi(TEST_SGI_ID, |
| (uint8_t)(SHIFT_U32(1, CFG_TEE_CORE_NB_CORE) - 1)); |
| tee_time_wait(200); |
| if (memcmp(test_sgi_value, expect_sgi_value, sizeof(test_sgi_value))) |
| return TEE_ERROR_GENERIC; |
| |
| for (i = 0; i < TEST_TIMES; i++) { |
| res = crypto_rng_read(&num, 1); |
| if (res != TEE_SUCCESS) |
| return TEE_ERROR_GENERIC; |
| num = num % CFG_TEE_CORE_NB_CORE; |
| cpu_mask = 0x0; |
| for (j = 0; j < num; j++) { |
| expect_sgi_value[j]++; |
| cpu_mask |= (0x1 << j); |
| } |
| itr_raise_sgi(TEST_SGI_ID, cpu_mask); |
| tee_time_wait(200); |
| if (memcmp(test_sgi_value, expect_sgi_value, |
| sizeof(test_sgi_value))) |
| return TEE_ERROR_GENERIC; |
| } |
| |
| return TEE_SUCCESS; |
| } |
| |
| static TEE_Result test_spi(void) |
| { |
| TEE_Result res; |
| uint8_t i; |
| uint8_t num; |
| |
| itr_add(&spi_handler); |
| itr_enable(TEST_SPI_ID); |
| |
| for (i = 0; i < TEST_TIMES; i++) { |
| res = crypto_rng_read(&num, 1); |
| if (res != TEE_SUCCESS) |
| return TEE_ERROR_GENERIC; |
| num = num % CFG_TEE_CORE_NB_CORE; |
| expect_spi_value[num]++; |
| itr_set_affinity(TEST_SPI_ID, 0x1 << num); |
| itr_raise_pi(TEST_SPI_ID); |
| tee_time_wait(200); |
| if (memcmp(test_spi_value, expect_spi_value, |
| sizeof(test_spi_value))) |
| return TEE_ERROR_GENERIC; |
| } |
| |
| return TEE_SUCCESS; |
| } |
| |
| static TEE_Result test_ppi(void) |
| { |
| uint32_t exceptions; |
| |
| itr_add(&ppi_handler); |
| itr_enable(TEST_PPI_ID); |
| |
| exceptions = thread_mask_exceptions(THREAD_EXCP_FOREIGN_INTR); |
| expect_ppi_value[get_core_pos()]++; |
| itr_raise_pi(TEST_PPI_ID); |
| thread_unmask_exceptions(exceptions); |
| tee_time_wait(200); |
| if (memcmp(test_ppi_value, expect_ppi_value, sizeof(test_ppi_value))) |
| return TEE_ERROR_GENERIC; |
| |
| return TEE_SUCCESS; |
| } |
| |
| static TEE_Result interrupt_tests(uint32_t nParamTypes __unused, |
| TEE_Param pParams[TEE_NUM_PARAMS]__unused) |
| { |
| TEE_Result res; |
| |
| res = test_sgi(); |
| if (res != TEE_SUCCESS) |
| return res; |
| |
| res = test_spi(); |
| if (res != TEE_SUCCESS) |
| return res; |
| |
| res = test_ppi(); |
| if (res != TEE_SUCCESS) |
| return res; |
| |
| return TEE_SUCCESS; |
| } |
| |
| static TEE_Result invoke_command(void *psess __unused, |
| uint32_t cmd, uint32_t ptypes, |
| TEE_Param params[4]) |
| { |
| TEE_Result res; |
| uint8_t i; |
| |
| switch (cmd) { |
| case CMD_INTERRUPT_TESTS: |
| res = interrupt_tests(ptypes, params); |
| DMSG("test value: sgi spi ppi"); |
| for (i = 0; i < CFG_TEE_CORE_NB_CORE; i++) |
| DMSG("------------[%zu] [%zu] [%zu]", |
| test_sgi_value[i], test_spi_value[i], |
| test_ppi_value[i]); |
| DMSG("expc value: sgi spi ppi"); |
| for (i = 0; i < CFG_TEE_CORE_NB_CORE; i++) |
| DMSG("------------[%zu] [%zu] [%zu]", |
| expect_sgi_value[i], expect_spi_value[i], |
| expect_ppi_value[i]); |
| return res; |
| default: |
| break; |
| } |
| return TEE_ERROR_BAD_PARAMETERS; |
| } |
| |
| pseudo_ta_register(.uuid = INTERRUPT_TESTS_UUID, .name = TA_NAME, |
| .flags = PTA_DEFAULT_FLAGS, |
| .invoke_command_entry_point = invoke_command); |