1 /*
2  * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <freertos/FreeRTOS.h>
11 #include <freertos/task.h>
12 #include <freertos/semphr.h>
13 
14 #include <unity.h>
15 #include <esp_spi_flash.h>
16 #include <esp_attr.h>
17 #include <esp_flash_encrypt.h>
18 
19 #include "../cache_utils.h"
20 
21 static QueueHandle_t result_queue;
22 
cache_test_task(void * arg)23 static IRAM_ATTR void cache_test_task(void *arg)
24 {
25     bool do_disable = (bool)arg;
26     bool result;
27     if(do_disable) {
28         spi_flash_disable_interrupts_caches_and_other_cpu();
29     }
30     result = spi_flash_cache_enabled();
31     if (do_disable) {
32         spi_flash_enable_interrupts_caches_and_other_cpu();
33     }
34 
35     TEST_ASSERT( xQueueSendToBack(result_queue, &result, 0) );
36     vTaskDelete(NULL);
37 }
38 
39 TEST_CASE("spi_flash_cache_enabled() works on both CPUs", "[spi_flash][esp_flash]")
40 {
41     result_queue = xQueueCreate(1, sizeof(bool));
42 
43     for(int cpu = 0; cpu < portNUM_PROCESSORS; cpu++) {
44         for(int disable = 0; disable <= 1; disable++) {
45             bool do_disable = disable;
46             bool result;
47             printf("Testing cpu %d disabled %d\n", cpu, do_disable);
48 
49             xTaskCreatePinnedToCore(cache_test_task, "cache_check_task",
50                                     2048, (void *)do_disable, configMAX_PRIORITIES-1, NULL, cpu);
51 
52             TEST_ASSERT( xQueueReceive(result_queue, &result, 2) );
53             TEST_ASSERT_EQUAL(!do_disable, result);
54         }
55     }
56 
57     vQueueDelete(result_queue);
58 }
59 
60 #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2)
61 
62 // This needs to sufficiently large array, otherwise it may end up in
63 // DRAM (e.g. size <= 8 bytes && ARCH == RISCV)
64 static const uint32_t s_in_rodata[8] = { 0x12345678, 0xfedcba98 };
65 
cache_access_test_func(void * arg)66 static void IRAM_ATTR cache_access_test_func(void* arg)
67 {
68     /* Assert that the array s_in_rodata is in DROM. If not, this test is
69      * invalid as disabling the cache wouldn't have any effect. */
70     TEST_ASSERT(esp_ptr_in_drom(s_in_rodata));
71 
72     spi_flash_disable_interrupts_caches_and_other_cpu();
73     volatile uint32_t* src = (volatile uint32_t*) s_in_rodata;
74     uint32_t v1 = src[0];
75     uint32_t v2 = src[1];
76     bool cache_enabled = spi_flash_cache_enabled();
77     spi_flash_enable_interrupts_caches_and_other_cpu();
78     printf("%d %x %x\n", cache_enabled, v1, v2);
79     vTaskDelete(NULL);
80 }
81 
82 #ifdef CONFIG_IDF_TARGET_ESP32C3
83 #define CACHE_ERROR_REASON "Cache error,RTC_SW_CPU_RST"
84 #elif CONFIG_IDF_TARGET_ESP32S3
85 #define CACHE_ERROR_REASON "Cache disabled,RTC_SW_CPU_RST"
86 #else
87 #define CACHE_ERROR_REASON "Cache disabled,SW_RESET"
88 #endif
89 
90 // These tests works properly if they resets the chip with the
91 // "Cache disabled but cached memory region accessed" reason and the correct CPU is logged.
92 TEST_CASE("invalid access to cache raises panic (PRO CPU)", "[spi_flash][reset="CACHE_ERROR_REASON"]")
93 {
94     xTaskCreatePinnedToCore(&cache_access_test_func, "ia", 2048, NULL, 5, NULL, 0);
95     vTaskDelay(1000/portTICK_PERIOD_MS);
96 }
97 
98 #ifndef CONFIG_FREERTOS_UNICORE
99 
100 TEST_CASE("invalid access to cache raises panic (APP CPU)", "[spi_flash][reset="CACHE_ERROR_REASON"]")
101 {
102     xTaskCreatePinnedToCore(&cache_access_test_func, "ia", 2048, NULL, 5, NULL, 1);
103     vTaskDelay(1000/portTICK_PERIOD_MS);
104 }
105 
106 #endif // !CONFIG_FREERTOS_UNICORE
107 #endif // !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2)
108