1 /*
2 * Copyright (c) 2023 Google Inc
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <sys/types.h>
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/flash/stm32_flash_api_extensions.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/logging/log.h>
12
13 #ifdef CONFIG_USERSPACE
14 #include <zephyr/syscall.h>
15 #include <zephyr/internal/syscall_handler.h>
16 #endif
17
18 #include <soc.h>
19 #include "flash_stm32.h"
20
21 LOG_MODULE_REGISTER(flash_stm32_ex_op, CONFIG_FLASH_LOG_LEVEL);
22
23 #if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
flash_stm32_ex_op_sector_wp(const struct device * dev,const uintptr_t in,void * out)24 int flash_stm32_ex_op_sector_wp(const struct device *dev, const uintptr_t in,
25 void *out)
26 {
27 const struct flash_stm32_ex_op_sector_wp_in *request =
28 (const struct flash_stm32_ex_op_sector_wp_in *)in;
29 struct flash_stm32_ex_op_sector_wp_out *result =
30 (struct flash_stm32_ex_op_sector_wp_out *)out;
31 uint64_t change_mask;
32 int rc = 0, rc2 = 0;
33 #ifdef CONFIG_USERSPACE
34 bool syscall_trap = z_syscall_trap();
35 #endif
36
37 if (request != NULL) {
38 #ifdef CONFIG_USERSPACE
39 struct flash_stm32_ex_op_sector_wp_in in_copy;
40
41 if (syscall_trap) {
42 K_OOPS(k_usermode_from_copy(&in_copy, request,
43 sizeof(in_copy)));
44 request = &in_copy;
45 }
46 #endif
47 change_mask = request->enable_mask;
48
49 if (!IS_ENABLED(
50 CONFIG_FLASH_STM32_WRITE_PROTECT_DISABLE_PREVENTION)) {
51 change_mask |= request->disable_mask;
52 }
53
54 rc = flash_stm32_option_bytes_lock(dev, false);
55 if (rc == 0) {
56 rc = flash_stm32_update_wp_sectors(
57 dev, change_mask, request->enable_mask);
58 }
59
60 rc2 = flash_stm32_option_bytes_lock(dev, true);
61 if (!rc) {
62 rc = rc2;
63 }
64 }
65
66 if (result != NULL) {
67 #ifdef CONFIG_USERSPACE
68 struct flash_stm32_ex_op_sector_wp_out out_copy;
69
70 if (syscall_trap) {
71 result = &out_copy;
72 }
73 #endif
74 rc2 = flash_stm32_get_wp_sectors(dev, &result->protected_mask);
75 if (!rc) {
76 rc = rc2;
77 }
78
79 #ifdef CONFIG_USERSPACE
80 if (syscall_trap) {
81 K_OOPS(k_usermode_to_copy(out, result, sizeof(out_copy)));
82 }
83 #endif
84 }
85
86 return rc;
87 }
88 #endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */
89
90 #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
flash_stm32_ex_op_update_rdp(const struct device * dev,bool enable,bool permanent)91 int flash_stm32_ex_op_update_rdp(const struct device *dev, bool enable,
92 bool permanent)
93 {
94 uint8_t current_level, target_level;
95
96 current_level = flash_stm32_get_rdp_level(dev);
97 target_level = current_level;
98
99 /*
100 * 0xAA = RDP level 0 (no protection)
101 * 0xCC = RDP level 2 (permanent protection)
102 * others = RDP level 1 (protection active)
103 */
104 switch (current_level) {
105 case FLASH_STM32_RDP2:
106 if (!enable || !permanent) {
107 LOG_DBG("RDP level 2 is permanent and can't be changed!");
108 return -ENOTSUP;
109 }
110 break;
111 case FLASH_STM32_RDP0:
112 if (enable) {
113 target_level = FLASH_STM32_RDP1;
114 if (permanent) {
115 #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW)
116 target_level = FLASH_STM32_RDP2;
117 #else
118 LOG_DBG("Permanent readout protection (RDP "
119 "level 0 -> 2) not allowed");
120 return -ENOTSUP;
121 #endif
122 }
123 }
124 break;
125 default: /* FLASH_STM32_RDP1 */
126 if (enable && permanent) {
127 #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW)
128 target_level = FLASH_STM32_RDP2;
129 #else
130 LOG_DBG("Permanent readout protection (RDP "
131 "level 1 -> 2) not allowed");
132 return -ENOTSUP;
133 #endif
134 }
135 if (!enable) {
136 #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW)
137 target_level = FLASH_STM32_RDP0;
138 #else
139 LOG_DBG("Disabling readout protection (RDP "
140 "level 1 -> 0) not allowed");
141 return -EACCES;
142 #endif
143 }
144 }
145
146 /* Update RDP level if needed */
147 if (current_level != target_level) {
148 LOG_INF("RDP changed from 0x%02x to 0x%02x", current_level,
149 target_level);
150
151 flash_stm32_set_rdp_level(dev, target_level);
152 }
153 return 0;
154 }
155
flash_stm32_ex_op_rdp(const struct device * dev,const uintptr_t in,void * out)156 int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in,
157 void *out)
158 {
159 const struct flash_stm32_ex_op_rdp *request =
160 (const struct flash_stm32_ex_op_rdp *)in;
161 struct flash_stm32_ex_op_rdp *result =
162 (struct flash_stm32_ex_op_rdp *)out;
163 uint8_t current_level;
164
165 #ifdef CONFIG_USERSPACE
166 struct flash_stm32_ex_op_rdp copy;
167 bool syscall_trap = z_syscall_trap();
168 #endif
169 int rc = 0, rc2 = 0;
170
171 if (request != NULL) {
172 #ifdef CONFIG_USERSPACE
173 if (syscall_trap) {
174 K_OOPS(k_usermode_from_copy(©, request, sizeof(copy)));
175 request = ©
176 }
177 #endif
178 rc = flash_stm32_option_bytes_lock(dev, false);
179 if (rc == 0) {
180 rc = flash_stm32_ex_op_update_rdp(dev, request->enable,
181 request->permanent);
182 }
183
184 rc2 = flash_stm32_option_bytes_lock(dev, true);
185 if (!rc) {
186 rc = rc2;
187 }
188 }
189
190 if (result != NULL) {
191 #ifdef CONFIG_USERSPACE
192 if (syscall_trap) {
193 result = ©
194 }
195 #endif
196
197 current_level = flash_stm32_get_rdp_level(dev);
198
199 /*
200 * 0xAA = RDP level 0 (no protection)
201 * 0xCC = RDP level 2 (permanent protection)
202 * others = RDP level 1 (protection active)
203 */
204 switch (current_level) {
205 case FLASH_STM32_RDP2:
206 result->enable = true;
207 result->permanent = true;
208 break;
209 case FLASH_STM32_RDP0:
210 result->enable = false;
211 result->permanent = false;
212 break;
213 default: /* FLASH_STM32_RDP1 */
214 result->enable = true;
215 result->permanent = false;
216 }
217
218 #ifdef CONFIG_USERSPACE
219 if (syscall_trap) {
220 K_OOPS(k_usermode_to_copy(out, result, sizeof(copy)));
221 }
222 #endif
223 }
224
225 return rc;
226 }
227 #endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */
228
flash_stm32_ex_op(const struct device * dev,uint16_t code,const uintptr_t in,void * out)229 int flash_stm32_ex_op(const struct device *dev, uint16_t code,
230 const uintptr_t in, void *out)
231 {
232 int rv = -ENOTSUP;
233
234 flash_stm32_sem_take(dev);
235
236 switch (code) {
237 #if defined(CONFIG_FLASH_STM32_WRITE_PROTECT)
238 case FLASH_STM32_EX_OP_SECTOR_WP:
239 rv = flash_stm32_ex_op_sector_wp(dev, in, out);
240 break;
241 #endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */
242 #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION)
243 case FLASH_STM32_EX_OP_RDP:
244 rv = flash_stm32_ex_op_rdp(dev, in, out);
245 break;
246 #endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */
247 #if defined(CONFIG_FLASH_STM32_BLOCK_REGISTERS)
248 case FLASH_STM32_EX_OP_BLOCK_OPTION_REG:
249 rv = flash_stm32_option_bytes_disable(dev);
250 break;
251 case FLASH_STM32_EX_OP_BLOCK_CONTROL_REG:
252 rv = flash_stm32_control_register_disable(dev);
253 break;
254 #endif /* CONFIG_FLASH_STM32_BLOCK_REGISTERS */
255 #if defined(CONFIG_FLASH_STM32_OPTION_BYTES) && ( \
256 defined(CONFIG_DT_HAS_ST_STM32F4_FLASH_CONTROLLER_ENABLED) || \
257 defined(CONFIG_DT_HAS_ST_STM32F7_FLASH_CONTROLLER_ENABLED) || \
258 defined(CONFIG_DT_HAS_ST_STM32G4_FLASH_CONTROLLER_ENABLED) || \
259 defined(CONFIG_DT_HAS_ST_STM32L4_FLASH_CONTROLLER_ENABLED))
260 case FLASH_STM32_EX_OP_OPTB_READ:
261 if (out == NULL) {
262 rv = -EINVAL;
263 break;
264 }
265
266 *(uint32_t *)out = flash_stm32_option_bytes_read(dev);
267 rv = 0;
268
269 break;
270 case FLASH_STM32_EX_OP_OPTB_WRITE:
271 int rv2;
272
273 rv = flash_stm32_option_bytes_lock(dev, false);
274 if (rv > 0) {
275 break;
276 }
277
278 rv2 = flash_stm32_option_bytes_write(dev, UINT32_MAX, (uint32_t)in);
279 /* returned later, we always re-lock */
280
281 rv = flash_stm32_option_bytes_lock(dev, true);
282 if (rv > 0) {
283 break;
284 }
285
286 rv = rv2;
287
288 break;
289 #endif
290 }
291
292 flash_stm32_sem_give(dev);
293
294 return rv;
295 }
296