1 /*
2 * Copyright (c) 2023 Google Inc
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/drivers/flash.h>
10 #include <zephyr/drivers/flash/stm32_flash_api_extensions.h>
11 #include <zephyr/devicetree.h>
12 #include <zephyr/storage/flash_map.h>
13
14 #define TEST_AREA storage_partition
15 #define TEST_AREA_OFFSET FIXED_PARTITION_OFFSET(TEST_AREA)
16 #define TEST_AREA_SIZE FIXED_PARTITION_SIZE(TEST_AREA)
17 #define TEST_AREA_MAX (TEST_AREA_OFFSET + TEST_AREA_SIZE)
18 #define TEST_AREA_DEVICE FIXED_PARTITION_DEVICE(TEST_AREA)
19 #define TEST_AREA_DEVICE_REG DT_REG_ADDR(DT_MTD_FROM_FIXED_PARTITION(DT_NODELABEL(TEST_AREA)))
20
21 #define EXPECTED_SIZE 512
22
23 static const struct device *const flash_dev = TEST_AREA_DEVICE;
24
25 #if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
26 static const struct flash_parameters *flash_params;
27 static uint64_t sector_mask;
28 static uint8_t __aligned(4) expected[EXPECTED_SIZE];
29
sector_mask_from_offset(const struct device * dev,off_t offset,size_t size,uint64_t * mask)30 static int sector_mask_from_offset(const struct device *dev, off_t offset,
31 size_t size, uint64_t *mask)
32 {
33 struct flash_pages_info start_page, end_page;
34
35 if (flash_get_page_info_by_offs(dev, offset, &start_page) ||
36 flash_get_page_info_by_offs(dev, offset + size - 1, &end_page)) {
37 return -EINVAL;
38 }
39
40 *mask = ((1UL << (end_page.index + 1)) - 1) &
41 ~((1UL << start_page.index) - 1);
42
43 return 0;
44 }
45 #endif
46
flash_stm32_setup(void)47 static void *flash_stm32_setup(void)
48 {
49 #if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
50 struct flash_stm32_ex_op_sector_wp_out wp_status;
51 struct flash_stm32_ex_op_sector_wp_in wp_request;
52 uint8_t buf[EXPECTED_SIZE];
53 bool is_buf_clear = true;
54 int rc;
55 #endif
56
57 /* Check if tested region fits in flash. */
58 zassert_true((TEST_AREA_OFFSET + EXPECTED_SIZE) < TEST_AREA_MAX,
59 "Test area exceeds flash size");
60
61 zassert_true(device_is_ready(flash_dev));
62
63 #if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
64 flash_params = flash_get_parameters(flash_dev);
65
66 rc = sector_mask_from_offset(flash_dev, TEST_AREA_OFFSET, EXPECTED_SIZE,
67 §or_mask);
68 zassert_equal(rc, 0, "Cannot get sector mask");
69
70 TC_PRINT("Sector mask for offset 0x%x size 0x%x is 0x%llx\n",
71 TEST_AREA_OFFSET, EXPECTED_SIZE, sector_mask);
72
73 /* Check if region is not write protected. */
74 rc = flash_ex_op(flash_dev, FLASH_STM32_EX_OP_SECTOR_WP,
75 (uintptr_t)NULL, &wp_status);
76 zassert_equal(rc, 0, "Cannot get write protect status");
77
78 TC_PRINT("Protected sectors: 0x%llx\n", wp_status.protected_mask);
79
80 /* Remove protection if needed. */
81 if (wp_status.protected_mask & sector_mask) {
82 TC_PRINT("Removing write protection\n");
83 wp_request.disable_mask = sector_mask;
84 wp_request.enable_mask = 0;
85
86 rc = flash_ex_op(flash_dev, FLASH_STM32_EX_OP_SECTOR_WP,
87 (uintptr_t)&wp_request, NULL);
88 zassert_equal(rc, 0, "Cannot remove write protection");
89 }
90
91 /* Check if test region is not empty. */
92 rc = flash_read(flash_dev, TEST_AREA_OFFSET, buf, EXPECTED_SIZE);
93 zassert_equal(rc, 0, "Cannot read flash");
94
95 /* Check if flash is cleared. */
96 for (off_t i = 0; i < EXPECTED_SIZE; i++) {
97 if (buf[i] != flash_params->erase_value) {
98 is_buf_clear = false;
99 break;
100 }
101 }
102
103 if (!is_buf_clear) {
104 TC_PRINT("Test area is not empty. Clear it before continuing.\n");
105 rc = flash_erase(flash_dev, TEST_AREA_OFFSET, EXPECTED_SIZE);
106 zassert_equal(rc, 0, "Flash memory not properly erased");
107 }
108
109 /* Fill test buffer with some pattern. */
110 for (int i = 0; i < EXPECTED_SIZE; i++) {
111 expected[i] = i;
112 }
113 #endif
114
115 return NULL;
116 }
117
118 #if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
ZTEST(flash_stm32,test_stm32_write_protection)119 ZTEST(flash_stm32, test_stm32_write_protection)
120 {
121 struct flash_stm32_ex_op_sector_wp_in wp_request;
122 uint8_t buf[EXPECTED_SIZE];
123 int rc;
124
125 TC_PRINT("Enabling write protection...");
126 wp_request.disable_mask = 0;
127 wp_request.enable_mask = sector_mask;
128
129 rc = flash_ex_op(flash_dev, FLASH_STM32_EX_OP_SECTOR_WP,
130 (uintptr_t)&wp_request, NULL);
131 zassert_equal(rc, 0, "Cannot enable write protection");
132 TC_PRINT("Done\n");
133
134 rc = flash_write(flash_dev, TEST_AREA_OFFSET, expected, EXPECTED_SIZE);
135 zassert_not_equal(rc, 0, "Write suceeded");
136 TC_PRINT("Write failed as expected, error %d\n", rc);
137
138 rc = flash_read(flash_dev, TEST_AREA_OFFSET, buf, EXPECTED_SIZE);
139 zassert_equal(rc, 0, "Cannot read flash");
140
141 for (off_t i = 0; i < EXPECTED_SIZE; i++) {
142 zassert_true(buf[i] == flash_params->erase_value,
143 "Buffer is not empty after write with protected "
144 "sectors");
145 }
146
147 TC_PRINT("Disabling write protection...");
148 wp_request.disable_mask = sector_mask;
149 wp_request.enable_mask = 0;
150
151 rc = flash_ex_op(flash_dev, FLASH_STM32_EX_OP_SECTOR_WP,
152 (uintptr_t)&wp_request, NULL);
153 zassert_equal(rc, 0, "Cannot disable write protection");
154 TC_PRINT("Done\n");
155
156 rc = flash_write(flash_dev, TEST_AREA_OFFSET, expected, EXPECTED_SIZE);
157 zassert_equal(rc, 0, "Write failed");
158 TC_PRINT("Write suceeded\n");
159
160 rc = flash_read(flash_dev, TEST_AREA_OFFSET, buf, EXPECTED_SIZE);
161 zassert_equal(rc, 0, "Cannot read flash");
162
163 zassert_equal(memcmp(buf, expected, EXPECTED_SIZE), 0,
164 "Read data doesn't match expected data");
165 }
166 #endif
167
168 #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
ZTEST(flash_stm32,test_stm32_readout_protection_disabled)169 ZTEST(flash_stm32, test_stm32_readout_protection_disabled)
170 {
171 struct flash_stm32_ex_op_rdp rdp_status;
172 int rc;
173
174 rc = flash_ex_op(flash_dev, FLASH_STM32_EX_OP_RDP, (uintptr_t)NULL,
175 &rdp_status);
176 zassert_equal(rc, 0, "Failed to get RDP status");
177 zassert_false(rdp_status.enable, "RDP is enabled");
178 zassert_false(rdp_status.permanent, "RDP is enabled permanently");
179
180 TC_PRINT("RDP is disabled\n");
181 }
182 #endif
183
184 #ifdef CONFIG_FLASH_STM32_BLOCK_REGISTERS
185
186 #if defined(CONFIG_FLASH_STM32_WRITE_PROTECT) || defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
187 #error Block Register tests unable to run other tests, because of locked registers.
188 #endif
189
190 int flash_stm32_option_bytes_lock(const struct device *dev, bool enable);
191
flash_opt_locked(void)192 static bool flash_opt_locked(void)
193 {
194 FLASH_TypeDef *regs = (FLASH_TypeDef *)TEST_AREA_DEVICE_REG;
195
196 return regs->OPTCR & FLASH_OPTCR_OPTLOCK;
197 }
198
flash_cr_unlock(void)199 static void flash_cr_unlock(void)
200 {
201 FLASH_TypeDef *regs = (FLASH_TypeDef *)TEST_AREA_DEVICE_REG;
202
203 regs->KEYR = FLASH_KEY1;
204 regs->KEYR = FLASH_KEY2;
205 }
206
flash_cr_locked(void)207 static bool flash_cr_locked(void)
208 {
209 FLASH_TypeDef *regs = (FLASH_TypeDef *)TEST_AREA_DEVICE_REG;
210
211 return regs->CR & FLASH_CR_LOCK;
212 }
213
ZTEST(flash_stm32,test_stm32_block_registers)214 ZTEST(flash_stm32, test_stm32_block_registers)
215 {
216 /* Test OPT lock. */
217 TC_PRINT("Unlocking OPT\n");
218 flash_stm32_option_bytes_lock(flash_dev, false);
219 zassert_false(flash_opt_locked(), "Unable to unlock OPT");
220
221 TC_PRINT("Blocking OPT\n");
222 flash_ex_op(flash_dev, FLASH_STM32_EX_OP_BLOCK_OPTION_REG, (uintptr_t)NULL, NULL);
223
224 zassert_true(flash_opt_locked(), "Blocking OPT didn't lock OPT");
225 TC_PRINT("Try to unlock blocked OPT\n");
226 __set_FAULTMASK(1);
227 flash_stm32_option_bytes_lock(flash_dev, false);
228 /* Clear Bus Fault pending bit */
229 SCB->SHCSR &= ~SCB_SHCSR_BUSFAULTPENDED_Msk;
230 __set_FAULTMASK(0);
231 zassert_true(flash_opt_locked(), "OPT unlocked after being blocked");
232
233 /* Test CR lock. */
234 zassert_true(flash_cr_locked(), "CR should be locked by default");
235 TC_PRINT("Unlocking CR\n");
236 flash_cr_unlock();
237 zassert_false(flash_cr_locked(), "Unable to unlock CR");
238 TC_PRINT("Blocking CR\n");
239 flash_ex_op(flash_dev, FLASH_STM32_EX_OP_BLOCK_CONTROL_REG, (uintptr_t)NULL, NULL);
240 zassert_true(flash_cr_locked(), "Blocking CR didn't lock CR");
241 __set_FAULTMASK(1);
242 TC_PRINT("Try to unlock blocked CR\n");
243 flash_cr_unlock();
244 /* Clear Bus Fault pending bit */
245 SCB->SHCSR &= ~SCB_SHCSR_BUSFAULTPENDED_Msk;
246 __set_FAULTMASK(0);
247 zassert_true(flash_cr_locked(), "CR unlocked after being blocked");
248 }
249 #endif
250
251 ZTEST_SUITE(flash_stm32, NULL, flash_stm32_setup, NULL, NULL, NULL);
252