1 #include "inttypes.h"
2 #include "unity.h"
3 #include "esp_attr.h"
4 #include "esp_log.h"
5 #include "soc/soc.h"
6 #include "esp_system.h"
7 #if CONFIG_IDF_TARGET_ESP32
8 #include "spiram.h"
9 #endif
10 
11 static __NOINIT_ATTR uint32_t s_noinit;
12 static RTC_NOINIT_ATTR uint32_t s_rtc_noinit;
13 static RTC_DATA_ATTR uint32_t s_rtc_data;
14 static RTC_RODATA_ATTR uint32_t s_rtc_rodata;
15 static RTC_FAST_ATTR uint32_t s_rtc_force_fast;
16 static RTC_SLOW_ATTR uint32_t s_rtc_force_slow;
17 #if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
18 static EXT_RAM_NOINIT_ATTR uint32_t s_noinit_ext;
19 #endif
20 
21 extern int _rtc_noinit_start;
22 extern int _rtc_noinit_end;
23 extern int _rtc_data_start;
24 extern int _rtc_data_end;
25 extern int _noinit_start;
26 extern int _noinit_end;
27 extern int _rtc_force_fast_start;
28 extern int _rtc_force_fast_end;
29 extern int _rtc_force_slow_start;
30 extern int _rtc_force_slow_end;
31 extern int _ext_ram_noinit_start;
32 extern int _ext_ram_noinit_end;
33 extern int _ext_ram_bss_start;
34 extern int _ext_ram_bss_end;
35 
36 
data_in_segment(void * ptr,int * seg_start,int * seg_end)37 static bool data_in_segment(void *ptr, int *seg_start, int *seg_end)
38 {
39     return ((intptr_t)ptr < (intptr_t)seg_end) && \
40            ((intptr_t)ptr >= (intptr_t)seg_start);
41 }
42 
43 TEST_CASE("Attributes place variables into correct sections", "[ld]")
44 {
45     TEST_ASSERT(data_in_segment(&s_noinit, &_noinit_start, &_noinit_end));
46     TEST_ASSERT(data_in_segment(&s_rtc_noinit, &_rtc_noinit_start, &_rtc_noinit_end));
47     TEST_ASSERT(data_in_segment(&s_rtc_data, &_rtc_data_start, &_rtc_data_end));
48     TEST_ASSERT(data_in_segment(&s_rtc_rodata, &_rtc_data_start, &_rtc_data_end));
49     TEST_ASSERT(data_in_segment(&s_rtc_force_fast, &_rtc_force_fast_start, &_rtc_force_fast_end));
50     TEST_ASSERT(data_in_segment(&s_rtc_force_slow, &_rtc_force_slow_start, &_rtc_force_slow_end));
51 
52 #if CONFIG_ESP32_RTCDATA_IN_FAST_MEM   || \
53     CONFIG_ESP32S2_RTCDATA_IN_FAST_MEM || \
54     CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM || \
55     CONFIG_ESP32C3_RTCDATA_IN_FAST_MEM
56     TEST_ASSERT(data_in_segment(&s_rtc_data, (int*) SOC_RTC_DRAM_LOW, (int*) SOC_RTC_DRAM_HIGH));
57     TEST_ASSERT(data_in_segment(&s_rtc_rodata, (int*) SOC_RTC_DRAM_LOW, (int*) SOC_RTC_DRAM_HIGH));
58     TEST_ASSERT(data_in_segment(&s_rtc_noinit, (int*) SOC_RTC_DRAM_LOW, (int*) SOC_RTC_DRAM_HIGH));
59 #else
60     TEST_ASSERT(data_in_segment(&s_rtc_data, (int*) SOC_RTC_DATA_LOW, (int*) SOC_RTC_DATA_HIGH));
61     TEST_ASSERT(data_in_segment(&s_rtc_rodata, (int*) SOC_RTC_DATA_LOW, (int*) SOC_RTC_DATA_HIGH));
62     TEST_ASSERT(data_in_segment(&s_rtc_noinit, (int*) SOC_RTC_DATA_LOW, (int*) SOC_RTC_DATA_HIGH));
63 #endif
64 
65     TEST_ASSERT(data_in_segment(&s_rtc_force_fast, (int*) SOC_RTC_DRAM_LOW, (int*) SOC_RTC_DRAM_HIGH));
66     TEST_ASSERT(data_in_segment(&s_rtc_force_slow, (int*) SOC_RTC_DATA_LOW, (int*) SOC_RTC_DATA_HIGH));
67 
68 #if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
69     TEST_ASSERT(data_in_segment(&s_noinit_ext, &_ext_ram_noinit_start, &_ext_ram_noinit_end));
70 #endif
71 }
72 
73 
74 #if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
75 
76 #define TEST_BUFFER_SIZE (16*1024/4)
77 static EXT_RAM_NOINIT_ATTR uint32_t s_noinit_buffer[TEST_BUFFER_SIZE];
78 
write_spiram_and_reset(void)79 static void write_spiram_and_reset(void)
80 {
81     // Fill the noinit buffer
82     printf("Filling buffer\n");
83     for (uint32_t i = 0; i < TEST_BUFFER_SIZE; i++) {
84         s_noinit_buffer[i] = i ^ 0x55555555U;
85     }
86     printf("Flushing cache\n");
87     // Flush the cache out to SPIRAM before resetting.
88     esp_spiram_writeback_cache();
89 
90     printf("Restarting\n");
91     // Reset to test that noinit memory is left intact.
92     esp_restart();
93 }
94 
check_spiram_contents(void)95 static void check_spiram_contents(void)
96 {
97     // Confirm that the memory contents are still what we expect
98     uint32_t error_count = 0;
99     for (uint32_t i = 0; i < TEST_BUFFER_SIZE; i++) {
100         if (s_noinit_buffer[i] != (i ^ 0x55555555U)) {
101             error_count++;
102         }
103     }
104     printf("Found %" PRIu32 " memory errors\n", error_count);
105     TEST_ASSERT(error_count == 0);
106 }
107 
108 TEST_CASE_MULTIPLE_STAGES("Spiram test noinit memory", "[spiram]", write_spiram_and_reset, check_spiram_contents);
109 
110 #endif // CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
111 
112 
113 #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
114 #define TEST_BSS_NUM    256
115 static EXT_RAM_ATTR uint32_t s_bss_buffer[TEST_BSS_NUM];
116 
117 TEST_CASE("Test variables placed in external .bss segment", "[ld]")
118 {
119     for (int i = 0; i < TEST_BSS_NUM; i++) {
120         TEST_ASSERT(data_in_segment(&s_bss_buffer[i], &_ext_ram_bss_start, &_ext_ram_bss_end));
121         TEST_ASSERT_EQUAL(0, s_bss_buffer[i]);
122     }
123 }
124 #endif  //#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
125