/* * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include "sdkconfig.h" #include "esp_attr.h" #include "hal/memprot_types.h" #include "soc/memprot_defs.h" #include "soc/sensitive_reg.h" #include "esp_private/esp_memprot_internal.h" #include "esp_memprot.h" #include "esp_rom_sys.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" /** * ESP32S3 MEMORY PROTECTION MODULE TEST * ===================================== * * In order to safely test all the memprot features, this test application uses memprot default settings * plus proprietary testing buffers: * - s_iram_test_buffer (.iram_end_test, 1kB) - all IRAM/DRAM low region operations, test-only section * - s_dram_test_buffer (.dram0.data, 1kB) - all IRAM/DRAM high region operations, standard section * - s_rtc_text_test_buffer (.rtc_text_end_test, 1kB) - all RTCFAST low region operations, test-only section * - s_rtc_data_test_buffer (.rtc.data, 1kB) - all RTCFAST high region operations, standard section * Testing addresses are set to the middle of the testing buffers: * - test_ptr_low = (s_iram_test_buffer | s_rtc_text_test_buffer) + 0x200 * - test_ptr_high = (s_dram_test_buffer | s_rtc_data_test_buffer) + 0x200 * Each operation is tested at both low & high region addresses. * Each test result checked against expected status of PMS violation interrupt status and * against expected value stored in the memory tested (where applicable) * * Testing scheme is depicted below: * * DRam0/DMA IRam0 * ----------------------------------------------- * | IRam0_PMS_0 = IRam0_PMS_1 = IRam0_PMS_2 | * | DRam0_PMS_0 | * | | * | | * | - - - - - - - s_iram_test_buffer - - - - - -| IRam0_line1_Split_addr * DRam0_DMA_line0_Split_addr | -- test_ptr_low -- | = * = =============================================== IRam0_line0_Split_addr * DRam0_DMA_line1_Split_addr | | = * | - - - - - - - s_dram_test_buffer - - - - - --| IRam0_DRam0_Split_addr (main I/D) * | -- test_ptr_high -- | * | - - - - - - - - - - - - - - - - - - - - - - | * | | * | DRam0_PMS_1 = DRam0_PMS_2 = DRam0_PMS_3 | * | IRam0_PMS_3 | * | | * | ... | * | | * =============================================== SOC_RTC_IRAM_LOW (0x50000000) * | -- test_ptr_low -- | * | - - - - - - s_rtc_text_test_buffer - - - - -| RtcFast_Split_addr (_rtc_text_end) * | -- .rtc.dummy -- | (UNUSED - PADDING) * 8 kB | - - - - - - - - - - - - - - - - - - - - - - | [_rtc_dummy_end = _rtc_force_fast_start] * | -- .rtc.force_fast -- | (NOT USED IN THIS TEST) * | - - - - - - s_rtc_data_test_buffer - - - - -| [_rtc_force_fast_end = _rtc_data_start] * | -- test_ptr_high -- | * | - - - - - - - - - - - - - - - - - - - - - - | * =============================================== SOC_RTC_IRAM_HIGH (0x50001FFF) * | | * ----------------------------------------------- */ /* !!!IMPORTANT!!! * a0 needs to be saved/restored manually (not clobbered) to avoid return address corruption * caused by ASM block handling */ #define CODE_EXEC(code_buf, param, res) \ asm volatile ( \ "mov a3, a0\n\t" \ "movi a2," #param "\n\t" \ "callx0 %1\n\t" \ "mov %0,a2\n\t" \ "mov a0, a3\n\t" \ : "=r"(res) \ : "r"(code_buf) \ : "a2", "a3" ); /* Binary code for the following asm: * .type _testfunc,@function .global _testfunc .align 4 _testfunc: slli a2, a2, 1 ret.n */ /* disabled unless IDF-5519 gets merged */ //static uint8_t s_fnc_buff[] = {0xf0, 0x22, 0x11, 0x0d, 0xf0, 0x00, 0x00, 0x00}; typedef int (*fnc_ptr)(int); //testing buffers #define SRAM_TEST_BUFFER_SIZE 0x400 #define SRAM_TEST_OFFSET 0x200 static uint8_t __attribute__((section(".iram_end_test"))) s_iram_test_buffer[SRAM_TEST_BUFFER_SIZE] = {0}; static uint8_t __attribute__((section(".rtc_text_end_test"))) s_rtc_text_test_buffer[SRAM_TEST_BUFFER_SIZE] = {0}; static uint8_t RTC_DATA_ATTR s_rtc_data_test_buffer[SRAM_TEST_BUFFER_SIZE] = {0}; static uint8_t s_dram_test_buffer[SRAM_TEST_BUFFER_SIZE] = {0}; //auxiliary defines #define LOW_REGION true #define HIGH_REGION false #define READ_ENA true #define READ_DIS false #define WRITE_ENA true #define WRITE_DIS false #define EXEC_ENA true #define EXEC_DIS false volatile bool g_override_illegal_instruction; static void *test_mprot_addr_low(esp_mprot_mem_t mem_type) { switch (mem_type) { case MEMPROT_TYPE_IRAM0_SRAM: return (void *)((uint32_t)s_iram_test_buffer + SRAM_TEST_OFFSET); case MEMPROT_TYPE_DRAM0_SRAM: return (void *)MAP_IRAM_TO_DRAM((uint32_t)s_iram_test_buffer + SRAM_TEST_OFFSET); case MEMPROT_TYPE_IRAM0_RTCFAST: return (void *)((uint32_t)s_rtc_text_test_buffer + SRAM_TEST_OFFSET); default: abort(); } } static void *test_mprot_addr_high(esp_mprot_mem_t mem_type) { switch (mem_type) { case MEMPROT_TYPE_IRAM0_SRAM: return (void *)MAP_DRAM_TO_IRAM((uint32_t)s_dram_test_buffer + SRAM_TEST_OFFSET); case MEMPROT_TYPE_DRAM0_SRAM: return (void *)((uint32_t)s_dram_test_buffer + SRAM_TEST_OFFSET); case MEMPROT_TYPE_IRAM0_RTCFAST: return (void *)((uint32_t)s_rtc_data_test_buffer + SRAM_TEST_OFFSET); default: abort(); } } static void __attribute__((unused)) test_mprot_dump_status_register(esp_mprot_mem_t mem_type, const int core) { esp_rom_printf("FAULT ["); esp_rom_printf("core 0 dram0: 0x%08X, core 1 dram0: 0x%08X, ", REG_READ(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG), REG_READ(SENSITIVE_CORE_1_DRAM0_PMS_MONITOR_2_REG)); esp_rom_printf("core 0 iram0: 0x%08X, core 1 iram0: 0x%08X, ", REG_READ(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG), REG_READ(SENSITIVE_CORE_1_IRAM0_PMS_MONITOR_2_REG)); void *addr; esp_err_t err = esp_mprot_get_violate_addr(mem_type, &addr, core); if (err == ESP_OK) { esp_rom_printf("fault addr: 0x%08X,", (uint32_t)addr); } else { esp_rom_printf("fault addr: N/A (%s),", esp_err_to_name(err)); } esp_mprot_pms_world_t world; err = esp_mprot_get_violate_world(mem_type, &world, core); if (err == ESP_OK) { esp_rom_printf(" world: %s,", esp_mprot_pms_world_to_str(world)); } else { esp_rom_printf(" world: N/A (%s),", esp_err_to_name(err)); } uint32_t oper; err = esp_mprot_get_violate_operation(mem_type, &oper, core); if (err == ESP_OK) { esp_rom_printf(" operation: %s", esp_mprot_oper_type_to_str(oper)); } else { esp_rom_printf(" operation: N/A (%s)", esp_err_to_name(err)); } // DRAM/DMA fault: check byte-enables if (mem_type == MEMPROT_TYPE_DRAM0_SRAM) { uint32_t byteen; err = esp_mprot_get_violate_byte_enables(mem_type, &byteen, core); if (err == ESP_OK) { esp_rom_printf(", byte en: 0x%08X", byteen); } else { esp_rom_printf(", byte en: N/A (%s)", esp_err_to_name(err)); } } esp_rom_printf( "]\n" ); } static void test_mprot_check_test_result(esp_mprot_mem_t mem_type, bool expected_status) { esp_memp_intr_source_t memp_intr; esp_err_t err = esp_mprot_get_active_intr(&memp_intr); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_get_active_intr() failed (%s) - test_mprot_check_test_result\n", esp_err_to_name(err)); return; } bool intr_on = memp_intr.mem_type == mem_type && memp_intr.core > -1; bool test_result = expected_status ? !intr_on : intr_on; if (test_result) { esp_rom_printf("OK\n"); } else { test_mprot_dump_status_register(mem_type, memp_intr.core); } } static void test_mprot_get_permissions(bool low, esp_mprot_mem_t mem_type, bool *read, bool *write, bool *exec, const int core) { esp_mprot_pms_area_t area; switch (mem_type) { case MEMPROT_TYPE_IRAM0_SRAM: area = low ? MEMPROT_PMS_AREA_IRAM0_2 : MEMPROT_PMS_AREA_IRAM0_3; break; case MEMPROT_TYPE_DRAM0_SRAM: area = low ? MEMPROT_PMS_AREA_DRAM0_0 : MEMPROT_PMS_AREA_DRAM0_1; break; case MEMPROT_TYPE_IRAM0_RTCFAST: area = low ? MEMPROT_PMS_AREA_IRAM0_RTCFAST_LO : MEMPROT_PMS_AREA_IRAM0_RTCFAST_HI; break; default: abort(); } uint32_t flags; esp_err_t err = esp_mprot_get_pms_area(area, &flags, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_get_pms_area() failed (%s) - test_mprot_get_permissions\n", esp_err_to_name(err)); return; } if (read) { *read = flags & MEMPROT_OP_READ; } if (write) { *write = flags & MEMPROT_OP_WRITE; } if (exec) { *exec = flags & MEMPROT_OP_EXEC; } } static void test_mprot_set_permissions(bool low, esp_mprot_mem_t mem_type, bool read, bool write, bool *exec, const int core) { esp_err_t err; uint32_t flags = 0; if (read) { flags |= MEMPROT_OP_READ; } if (write) { flags |= MEMPROT_OP_WRITE; } if (exec && *exec) { flags |= MEMPROT_OP_EXEC; } switch (mem_type) { case MEMPROT_TYPE_IRAM0_SRAM: { if (low) { if ((err = esp_mprot_set_pms_area(MEMPROT_PMS_AREA_IRAM0_0, flags, core)) != ESP_OK) { break; } if ((err = esp_mprot_set_pms_area(MEMPROT_PMS_AREA_IRAM0_1, flags, core)) != ESP_OK) { break; } if ((err = esp_mprot_set_pms_area(MEMPROT_PMS_AREA_IRAM0_2, flags, core)) != ESP_OK) { break; } } else { if ((err = esp_mprot_set_pms_area(MEMPROT_PMS_AREA_IRAM0_3, flags, core)) != ESP_OK) { break; } } } break; case MEMPROT_TYPE_DRAM0_SRAM: { if (low) { if ((err = esp_mprot_set_pms_area(MEMPROT_PMS_AREA_DRAM0_0, flags, core)) != ESP_OK) { break; } } else { if ((err = esp_mprot_set_pms_area(MEMPROT_PMS_AREA_DRAM0_1, flags, core)) != ESP_OK) { break; } if ((err = esp_mprot_set_pms_area(MEMPROT_PMS_AREA_DRAM0_2, flags, core)) != ESP_OK) { break; } if ((err = esp_mprot_set_pms_area(MEMPROT_PMS_AREA_DRAM0_3, flags, core)) != ESP_OK) { break; } } } break; case MEMPROT_TYPE_IRAM0_RTCFAST: { if (low) { if ((err = esp_mprot_set_pms_area(MEMPROT_PMS_AREA_IRAM0_RTCFAST_LO, flags, core)) != ESP_OK) { break; } } else { if ((err = esp_mprot_set_pms_area(MEMPROT_PMS_AREA_IRAM0_RTCFAST_HI, flags, core)) != ESP_OK) { break; } } } break; default: abort(); } if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_set_pms_area() failed (%s) - test_mprot_set_permissions\n", esp_err_to_name(err)); } } static void test_mprot_read(esp_mprot_mem_t mem_type, const int core) { esp_err_t err = esp_mprot_monitor_clear_intr(mem_type, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_monitor_clear_intr() failed on core %d (%s) - test_mprot_read\n", core, esp_err_to_name(err)); return; } //get current permission settings bool write_perm_low, write_perm_high, read_perm_low, read_perm_high, exec_perm_low, exec_perm_high; bool is_exec_mem = mem_type & MEMPROT_TYPE_IRAM0_ANY; test_mprot_get_permissions(true, mem_type, &read_perm_low, &write_perm_low, is_exec_mem ? &exec_perm_low : NULL, core); test_mprot_get_permissions(false, mem_type, &read_perm_high, &write_perm_high, is_exec_mem ? &exec_perm_high : NULL, core); //get testing pointers for low & high regions uint32_t *ptr_low = test_mprot_addr_low(mem_type); uint32_t *ptr_high = test_mprot_addr_high(mem_type); const uint32_t test_val = 100; //temporarily allow WRITE for setting the test values err = esp_mprot_set_monitor_en(mem_type, false, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_set_monitor_en() failed (%s) - test_mprot_read\n", esp_err_to_name(err)); return; } test_mprot_set_permissions(LOW_REGION, mem_type, read_perm_low, WRITE_ENA, is_exec_mem ? &exec_perm_low : NULL, core); test_mprot_set_permissions(HIGH_REGION, mem_type, read_perm_high, WRITE_ENA, is_exec_mem ? &exec_perm_high : NULL, core); //store testing values to appropriate memory *ptr_low = test_val; *ptr_high = test_val + 1; //restore current PMS settings test_mprot_set_permissions(LOW_REGION, mem_type, read_perm_low, write_perm_low, is_exec_mem ? &exec_perm_low : NULL, core); test_mprot_set_permissions(HIGH_REGION, mem_type, read_perm_high, write_perm_high, is_exec_mem ? &exec_perm_high : NULL, core); //reenable monitoring err = esp_mprot_set_monitor_en(mem_type, true, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_set_monitor_en() failed (%s) - test_mprot_read\n", esp_err_to_name(err)); return; } //perform READ test in low region esp_rom_printf("%s (core %d) read low: ", esp_mprot_mem_type_to_str(mem_type), core); err = esp_mprot_monitor_clear_intr(mem_type, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_monitor_clear_intr() failed (%s) - test_mprot_read\n", esp_err_to_name(err)); return; } volatile uint32_t val = *ptr_low; if (read_perm_low && val != test_val) { esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val ); test_mprot_dump_status_register(mem_type, core); } else { test_mprot_check_test_result(mem_type, read_perm_low); } //perform READ in high region esp_rom_printf("%s (core %d) read high: ", esp_mprot_mem_type_to_str(mem_type), core); err = esp_mprot_monitor_clear_intr(mem_type, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_monitor_clear_intr() failed on core %d (%s) - test_mprot_read\n", core, esp_err_to_name(err)); return; } val = *ptr_high; if (read_perm_high && val != (test_val + 1)) { esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val); test_mprot_dump_status_register(mem_type, core); } else { test_mprot_check_test_result(mem_type, read_perm_high); } esp_mprot_monitor_clear_intr(mem_type, core); //test_mprot_dump_status_register(mem_type, core); } static void test_mprot_write(esp_mprot_mem_t mem_type, const int core) { esp_err_t err = esp_mprot_monitor_clear_intr(mem_type, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_monitor_clear_intr() failed on core %d (%s) - test_mprot_write\n", core, esp_err_to_name(err)); return; } //get current READ & WRITE permission settings bool write_perm_low, write_perm_high, read_perm_low, read_perm_high, exec_perm_low, exec_perm_high; bool is_exec_mem = mem_type & MEMPROT_TYPE_IRAM0_ANY; test_mprot_get_permissions(LOW_REGION, mem_type, &read_perm_low, &write_perm_low, is_exec_mem ? &exec_perm_low : NULL, core); test_mprot_get_permissions(HIGH_REGION, mem_type, &read_perm_high, &write_perm_high, is_exec_mem ? &exec_perm_high : NULL, core); //ensure READ enabled err = esp_mprot_set_monitor_en(mem_type, false, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_set_monitor_en() failed (%s) - test_mprot_write\n", esp_err_to_name(err)); return; } test_mprot_set_permissions(LOW_REGION, mem_type, READ_ENA, write_perm_low, is_exec_mem ? &exec_perm_low : NULL, core); test_mprot_set_permissions(HIGH_REGION, mem_type, READ_ENA, write_perm_high, is_exec_mem ? &exec_perm_high : NULL, core); err = esp_mprot_set_monitor_en(mem_type, true, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_set_monitor_en() failed (%s) - test_mprot_write\n", esp_err_to_name(err)); return; } volatile uint32_t *ptr_low = test_mprot_addr_low(mem_type); volatile uint32_t *ptr_high = test_mprot_addr_high(mem_type); const uint32_t test_val = 10; //perform WRITE in low region esp_rom_printf("%s (core %d) write low: ", esp_mprot_mem_type_to_str(mem_type), core); err = esp_mprot_monitor_clear_intr(mem_type, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_monitor_clear_intr() failed on core %d (%s) - test_mprot_write\n", core, esp_err_to_name(err)); return; } volatile uint32_t val = 0; *ptr_low = test_val; val = *ptr_low; if (write_perm_low && val != test_val) { esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val); test_mprot_dump_status_register(mem_type, core); } else { test_mprot_check_test_result(mem_type, write_perm_low); } //perform WRITE in high region esp_rom_printf("%s (core %d) write high: ", esp_mprot_mem_type_to_str(mem_type), core); err = esp_mprot_monitor_clear_intr(mem_type, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_monitor_clear_intr() failed on core %d (%s) - test_mprot_write\n", core, esp_err_to_name(err)); return; } val = 0; *ptr_high = test_val + 1; val = *ptr_high; if (val != (test_val + 1) && write_perm_high) { esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val); test_mprot_dump_status_register(mem_type, core); } else { test_mprot_check_test_result(mem_type, write_perm_high); } //restore original permissions err = esp_mprot_set_monitor_en(mem_type, false, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_set_monitor_en() failed (%s) - test_mprot_write\n", esp_err_to_name(err)); return; } test_mprot_set_permissions(LOW_REGION, mem_type, read_perm_low, write_perm_low, is_exec_mem ? &exec_perm_low : NULL, core); test_mprot_set_permissions(HIGH_REGION, mem_type, read_perm_high, write_perm_high, is_exec_mem ? &exec_perm_high : NULL, core); err = esp_mprot_set_monitor_en(mem_type, true, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_set_monitor_en() failed (%s) - test_mprot_write\n", esp_err_to_name(err)); return; } esp_mprot_monitor_clear_intr(mem_type, core); } #if 0 /* disabled unless IDF-5519 gets merged */ static void test_mprot_exec(esp_mprot_mem_t mem_type, const int core) { if (!(mem_type & MEMPROT_TYPE_IRAM0_ANY)) { esp_rom_printf("Error: EXEC test available only for IRAM access.\n" ); return; } esp_err_t err = esp_mprot_monitor_clear_intr(mem_type, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_monitor_clear_intr() failed on core %d (%s) - test_mprot_exec\n", core, esp_err_to_name(err)); return; } err = esp_mprot_set_monitor_en(mem_type, false, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_set_monitor_en() failed (%s) - test_mprot_exec\n", esp_err_to_name(err)); return; } //get require mem_type permissions bool write_perm_low, write_perm_high, read_perm_low, read_perm_high, exec_perm_low, exec_perm_high; test_mprot_get_permissions(LOW_REGION, mem_type, &read_perm_low, &write_perm_low, &exec_perm_low, core); test_mprot_get_permissions(HIGH_REGION, mem_type, &read_perm_high, &write_perm_high, &exec_perm_high, core); void *fnc_ptr_low = NULL; void *fnc_ptr_high = NULL; if (mem_type == MEMPROT_TYPE_IRAM0_SRAM) { //temporarily enable WRITE for DBUS test_mprot_set_permissions(LOW_REGION, MEMPROT_TYPE_DRAM0_SRAM, READ_ENA, WRITE_ENA, NULL, core); //get testing pointers for low & high regions using DBUS FOR CODE INJECTION! fnc_ptr_low = test_mprot_addr_low(MEMPROT_TYPE_DRAM0_SRAM); fnc_ptr_high = test_mprot_addr_high(MEMPROT_TYPE_DRAM0_SRAM); //inject the code to both low & high segments memcpy(fnc_ptr_low, (const void *) s_fnc_buff, sizeof(s_fnc_buff)); memcpy(fnc_ptr_high, (const void *) s_fnc_buff, sizeof(s_fnc_buff)); fnc_ptr_low = (void *) MAP_DRAM_TO_IRAM(fnc_ptr_low); fnc_ptr_high = (void *) MAP_DRAM_TO_IRAM(fnc_ptr_high); //reenable DBUS protection test_mprot_set_permissions(LOW_REGION, MEMPROT_TYPE_DRAM0_SRAM, READ_ENA, WRITE_DIS, NULL, core); } else if (mem_type == MEMPROT_TYPE_IRAM0_RTCFAST) { //enable WRITE for low region test_mprot_set_permissions(LOW_REGION, MEMPROT_TYPE_IRAM0_RTCFAST, read_perm_low, WRITE_ENA, &exec_perm_low, core); fnc_ptr_low = test_mprot_addr_low(MEMPROT_TYPE_IRAM0_RTCFAST); fnc_ptr_high = test_mprot_addr_high(MEMPROT_TYPE_IRAM0_RTCFAST); //inject the code to both low & high segments memcpy(fnc_ptr_low, (const void *) s_fnc_buff, sizeof(s_fnc_buff)); memcpy(fnc_ptr_high, (const void *) s_fnc_buff, sizeof(s_fnc_buff)); //reenable original protection test_mprot_set_permissions(LOW_REGION, MEMPROT_TYPE_IRAM0_RTCFAST, read_perm_low, write_perm_low, &exec_perm_low, core); } else { assert(0); } uint32_t res = 0; //LOW REGION: clear the intr flag & try to execute the code injected esp_rom_printf("%s (core %d) exec low: ", esp_mprot_mem_type_to_str(mem_type), core); err = esp_mprot_monitor_clear_intr(mem_type, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_monitor_clear_intr() failed (%s) - test_mprot_exec\n", esp_err_to_name(err)); return; } err = esp_mprot_set_monitor_en(mem_type, true, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_set_monitor_en() failed (%s) - test_mprot_exec\n", esp_err_to_name(err)); return; } fnc_ptr fnc = (fnc_ptr)fnc_ptr_low; g_override_illegal_instruction = true; CODE_EXEC(fnc, 5, res) g_override_illegal_instruction = false; //check results bool fnc_call_ok = res == 10; if (fnc_call_ok) { test_mprot_check_test_result(mem_type, exec_perm_low); } else { if (!exec_perm_low) { test_mprot_check_test_result(mem_type, false); } else { esp_rom_printf(" FAULT [injected code not executed]\n"); } } //HIGH REGION: clear the intr-on flag & try to execute the code injected esp_rom_printf("%s (core %d) exec high: ", esp_mprot_mem_type_to_str(mem_type), core); err = esp_mprot_monitor_clear_intr(mem_type, core); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_monitor_clear_intr() failed (%s) - test_mprot_exec\n", esp_err_to_name(err)); return; } fnc = (fnc_ptr)fnc_ptr_high; g_override_illegal_instruction = true; CODE_EXEC(fnc, 6, res) g_override_illegal_instruction = false; fnc_call_ok = res == 12; if (fnc_call_ok) { test_mprot_check_test_result(mem_type, exec_perm_high); } else { if (!exec_perm_high) { test_mprot_check_test_result(mem_type, false); } else { esp_rom_printf(" FAULT [injected code not executed]\n"); } } esp_mprot_monitor_clear_intr(mem_type, core); } #endif // testing per-CPU tasks esp_memp_config_t memp_cfg = { .invoke_panic_handler = false, .lock_feature = false, .split_addr = NULL, .mem_type_mask = MEMPROT_TYPE_ALL, #if configNUM_CORES > 1 .target_cpu_count = 2, .target_cpu = {PRO_CPU_NUM, APP_CPU_NUM} #else .target_cpu_count = 1, .target_cpu = {PRO_CPU_NUM} #endif }; typedef struct { int core; SemaphoreHandle_t sem; } test_ctx_t; static void task_on_CPU(void *arg) { test_ctx_t *ctx = (test_ctx_t *)arg; if (memp_cfg.mem_type_mask & MEMPROT_TYPE_IRAM0_SRAM) { test_mprot_read(MEMPROT_TYPE_IRAM0_SRAM, ctx->core); test_mprot_write(MEMPROT_TYPE_IRAM0_SRAM, ctx->core); /* disabled unless IDF-5519 gets merged */ //test_mprot_exec(MEMPROT_TYPE_IRAM0_SRAM, ctx->core); } if (memp_cfg.mem_type_mask & MEMPROT_TYPE_DRAM0_SRAM) { test_mprot_read(MEMPROT_TYPE_DRAM0_SRAM, ctx->core); test_mprot_write(MEMPROT_TYPE_DRAM0_SRAM, ctx->core); } if (memp_cfg.mem_type_mask & MEMPROT_TYPE_IRAM0_RTCFAST) { test_mprot_read(MEMPROT_TYPE_IRAM0_RTCFAST, ctx->core); test_mprot_write(MEMPROT_TYPE_IRAM0_RTCFAST, ctx->core); /* disabled unless IDF-5519 gets merged */ //test_mprot_exec(MEMPROT_TYPE_IRAM0_RTCFAST, ctx->core); } xSemaphoreGive(ctx->sem); vTaskDelete(NULL); } /* ******************************************************************************************** * main test runner */ void app_main(void) { esp_err_t err = esp_mprot_set_prot(&memp_cfg); if (err != ESP_OK) { esp_rom_printf("Error: esp_mprot_set_prot() failed (%s) - app_main\n", esp_err_to_name(err)); return; } //test each core separate test_ctx_t ctx = { .sem = xSemaphoreCreateBinary(), .core = PRO_CPU_NUM }; xTaskCreatePinnedToCore(task_on_CPU, "task_PRO_CPU", 4096, &ctx, 3, NULL, PRO_CPU_NUM); xSemaphoreTake(ctx.sem, portMAX_DELAY); //multicore setup if (configNUM_CORES > 1) { ctx.core = APP_CPU_NUM; xTaskCreatePinnedToCore(task_on_CPU, "task_APP_CPU", 4096, &ctx, 3, NULL, APP_CPU_NUM); xSemaphoreTake(ctx.sem, portMAX_DELAY); } }