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