1 /*
2 * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include <stdbool.h>
9 #include "target.h"
10 #include "flash_map/flash_map.h"
11 #include "flash_map_backend/flash_map_backend.h"
12 #include "bootutil_priv.h"
13 #include "bootutil/bootutil_log.h"
14 #include "bootutil/fault_injection_hardening.h"
15 #include "Driver_Flash.h"
16 #ifdef PLATFORM_HAS_BOOT_DMA
17 #include "boot_dma.h"
18 #endif /* PLATFORM_HAS_BOOT_DMA */
19
20 #define FLASH_PROGRAM_UNIT TFM_HAL_FLASH_PROGRAM_UNIT
21
22 /**
23 * Return the greatest value not greater than `value` that is aligned to
24 * `alignment`.
25 */
26 #define FLOOR_ALIGN(value, alignment) ((value) & ~((alignment) - 1))
27
28 /**
29 * Return the least value not less than `value` that is aligned to `alignment`.
30 */
31 #define CEILING_ALIGN(value, alignment) \
32 (((value) + ((alignment) - 1)) & ~((alignment) - 1))
33
34 extern const struct flash_area flash_map[];
35 extern const int flash_map_entry_num;
36
37 extern const ARM_DRIVER_FLASH *flash_driver[];
38 extern const int flash_driver_entry_num;
39
40 /* Valid entries for data item width */
41 static const uint32_t data_width_byte[] = {
42 sizeof(uint8_t),
43 sizeof(uint16_t),
44 sizeof(uint32_t),
45 };
46
47 /*
48 * Check the target address in the flash_area_xxx operation.
49 */
is_range_valid(const struct flash_area * area,uint32_t off,uint32_t len)50 static bool is_range_valid(const struct flash_area *area,
51 uint32_t off,
52 uint32_t len)
53 {
54 uint32_t size;
55
56 if (!area) {
57 return false;
58 }
59
60 if (!boot_u32_safe_add(&size, off, len)) {
61 return false;
62 }
63
64 if (area->fa_size < size) {
65 return false;
66 }
67
68 return true;
69 }
flash_area_driver_init(void)70 int flash_area_driver_init(void)
71 {
72 int i;
73
74 for (i = 0; i < flash_driver_entry_num; i++) {
75 if (flash_driver[i]->Initialize(NULL) != ARM_DRIVER_OK)
76 return -1;
77 }
78
79 return 0;
80 }
81 /*
82 * `open` a flash area. The `area` in this case is not the individual
83 * sectors, but describes the particular flash area in question.
84 */
flash_area_open(uint8_t id,const struct flash_area ** area)85 int flash_area_open(uint8_t id, const struct flash_area **area)
86 {
87 int i;
88
89 BOOT_LOG_DBG("area %d", id);
90
91 for (i = 0; i < flash_map_entry_num; i++) {
92 if (id == flash_map[i].fa_id) {
93 break;
94 }
95 }
96 if (i == flash_map_entry_num) {
97 return -1;
98 }
99
100 *area = &flash_map[i];
101 return 0;
102 }
103
flash_area_close(const struct flash_area * area)104 void flash_area_close(const struct flash_area *area)
105 {
106 /* Nothing to do. */
107 }
108
109 /*
110 * Read/write/erase. Offset is relative from beginning of flash area.
111 * `off` and `len` can be any alignment.
112 * Return 0 on success, other value on failure.
113 */
flash_area_read(const struct flash_area * area,uint32_t off,void * dst,uint32_t len)114 int flash_area_read(const struct flash_area *area, uint32_t off, void *dst,
115 uint32_t len)
116 {
117 volatile uint32_t remaining_len;
118 uint32_t read_length;
119 uint32_t aligned_off;
120 uint32_t item_number;
121 #ifdef PLATFORM_HAS_BOOT_DMA
122 uint32_t dma_src_addr;
123 #endif /* PLATFORM_HAS_BOOT_DMA */
124
125 /* The maximum value of data_width is 4 bytes. */
126 uint8_t temp_buffer[sizeof(uint32_t)];
127 uint8_t data_width, i = 0, j;
128 int ret = 0;
129
130 ARM_FLASH_CAPABILITIES DriverCapabilities;
131
132 BOOT_LOG_DBG("read area=%d, off=%#x, len=%#x", area->fa_id, off, len);
133
134 if (!is_range_valid(area, off, len)) {
135 return -1;
136 }
137
138 remaining_len = len;
139
140 /* CMSIS ARM_FLASH_ReadData API requires the `addr` data type size aligned.
141 * Data type size is specified by the data_width in ARM_FLASH_CAPABILITIES.
142 */
143 DriverCapabilities = DRV_FLASH_AREA(area)->GetCapabilities();
144 data_width = data_width_byte[DriverCapabilities.data_width];
145 aligned_off = FLOOR_ALIGN(off, data_width);
146
147 #ifdef PLATFORM_HAS_BOOT_DMA
148 if (len >= BOOT_DMA_MIN_SIZE_REQ) {
149 dma_src_addr = FLASH_BASE_ADDRESS + area->fa_off + off;
150 BOOT_LOG_DBG("dma memcpy call:src_addr=%#x, dest_addr=%#x, len=%#x",
151 dma_src_addr, dst, len);
152
153 ret = boot_dma_memcpy(dma_src_addr, (uint32_t)dst, len, 0);
154 if (ret == 0) {
155 /* DMA transfer copy success */
156 return 0;
157 }
158 }
159 #endif /* PLATFORM_HAS_BOOT_DMA */
160
161 /* Either DMA is not supported or DMA transfer copy failure or
162 * memory transaction size is less than required.
163 * Continue to use default flash driver.
164 */
165
166 /* Read the first data_width long data if `off` is not aligned. */
167 if (aligned_off != off) {
168 ret = DRV_FLASH_AREA(area)->ReadData(area->fa_off + aligned_off,
169 temp_buffer,
170 1);
171 if (ret < 0) {
172 return ret;
173 }
174
175 /* Record how many target data have been read. */
176 read_length = ((off - aligned_off + len) >= data_width) ?
177 (data_width - (off - aligned_off)) : len;
178
179 /* Copy the read data from off. */
180 for (i = 0; i < read_length; i++) {
181 ((uint8_t *)dst)[i] = temp_buffer[i + off - aligned_off];
182 }
183 remaining_len -= read_length;
184 }
185
186 if (remaining_len == 0) {
187 return 0;
188 }
189
190 /* The `cnt` parameter in CMSIS ARM_FLASH_ReadData indicates number of data
191 * items to read. The size of a data item is equal to the data_width value.
192 *
193 * When using the FIH library with at least the medium profile the below
194 * division operation is repeated and the results are checked for consistency
195 * (remaining_len is declared volatile to avoid compiler optimization).
196 * This helps to prevent a FI assisted overflow of the 'dst' buffer.
197 */
198 FIH_SET(item_number, (remaining_len / data_width));
199
200 if (item_number) {
201 /* There is at least one data item (of size data_width) to read. */
202 ret = DRV_FLASH_AREA(area)->ReadData(area->fa_off + off + i,
203 (uint8_t *)dst + i,
204 item_number);
205 if (ret < 0) {
206 return ret;
207 }
208 remaining_len -= item_number * data_width;
209
210 if (remaining_len == 0) {
211 return 0;
212 }
213 }
214
215 /* The number of remaining bytes is less than data_width (of the driver) */
216 ret = DRV_FLASH_AREA(area)->ReadData(
217 area->fa_off + off + i + (item_number * data_width),
218 temp_buffer,
219 1);
220
221 /* CMSIS ARM_FLASH_ReadData can return the number of data items read or
222 * Status Error Codes which are negative for failures.
223 */
224 if (ret < 0) {
225 return ret;
226 }
227
228 for (j = 0; j < remaining_len; j++) {
229 ((uint8_t *)dst)[i + (item_number * data_width) + j] = temp_buffer[j];
230 }
231
232 return 0;
233 }
234
235 /* Writes `len` bytes of flash memory at `off` from the buffer at `src`.
236 * `off` and `len` can be any alignment.
237 */
flash_area_write(const struct flash_area * area,uint32_t off,const void * src,uint32_t len)238 int flash_area_write(const struct flash_area *area, uint32_t off,
239 const void *src, uint32_t len)
240 {
241 uint8_t add_padding[FLASH_PROGRAM_UNIT];
242 #if (FLASH_PROGRAM_UNIT == 1)
243 uint8_t len_padding[FLASH_PROGRAM_UNIT]; /* zero sized arrayas are illegal C */
244 #else
245 uint8_t len_padding[FLASH_PROGRAM_UNIT - 1];
246 #endif
247 ARM_FLASH_CAPABILITIES DriverCapabilities;
248 uint8_t data_width;
249 /* The PROGRAM_UNIT aligned value of `off` */
250 uint32_t aligned_off;
251
252 /* The total write length. */
253 uint32_t aligned_len;
254 uint32_t i, k;
255
256 /* The index in src[] that has been programmed. */
257 uint32_t src_written_idx = 0;
258 uint32_t add_padding_size, len_padding_size;
259 uint32_t write_size;
260 uint32_t last_unit_start_off;
261 /*
262 * aligned_off off last_unit_start_off
263 * | | |
264 * | add_padding_size | | | len_padding_size |
265 * |+++++++++++++++++++**|******************|***@@@@@@@@@@@@@@@@@@@@|
266 * | | | |
267 * ---->--|---- PROGRAM UNIT ---|-- PROGRAM UNIT --|---- PROGRAM UNIT -----|
268 * | | | |
269 * |+++++++++++++++++++**|******************|***@@@@@@@@@@@@@@@@@@@@|
270 * |<-------- len --------->|
271 */
272
273 BOOT_LOG_DBG("write area=%d, off=%#x, len=%#x", area->fa_id, off, len);
274
275 /* Align the target address. The area->fa_off should already be aligned. */
276 aligned_off = FLOOR_ALIGN(off, FLASH_PROGRAM_UNIT);
277 add_padding_size = off - aligned_off;
278 if (!is_range_valid(area, off, len)) {
279 return -1;
280 }
281
282 DriverCapabilities = DRV_FLASH_AREA(area)->GetCapabilities();
283 data_width = data_width_byte[DriverCapabilities.data_width];
284
285 if (FLASH_PROGRAM_UNIT) {
286 /* Read the bytes from aligned_off to off. */
287 if (flash_area_read(area, aligned_off, add_padding, add_padding_size)) {
288 return -1;
289 }
290 }
291
292 /* Align the write size */
293 aligned_len = CEILING_ALIGN(len + add_padding_size, FLASH_PROGRAM_UNIT);
294 len_padding_size = aligned_len - len - add_padding_size;
295 if (!is_range_valid(area, aligned_off, aligned_len)) {
296 return -1;
297 }
298
299 /* Read the bytes from (off + len) to (off + aligned_len). */
300 if (flash_area_read(area, off + len, len_padding,
301 len_padding_size)) {
302 return -1;
303 }
304
305 /* Program the first FLASH_PROGRAM_UNIT. */
306 if (add_padding_size) {
307 /* Fill the first program unit bytes with data from src. */
308 for (i = add_padding_size, src_written_idx = 0;
309 (i < FLASH_PROGRAM_UNIT) && (src_written_idx < len);
310 i++, src_written_idx++) {
311 add_padding[i] = ((uint8_t *)src)[src_written_idx];
312 }
313 if (src_written_idx == len) {
314 /* aligned_len equals to FLASH_PROGRAM_UNIT in this case.
315 * Fill the len_padding_size datas into add_padding.
316 */
317 for (k = 0; (i < FLASH_PROGRAM_UNIT) && (k < len_padding_size);
318 i++, k++) {
319 add_padding[i] = len_padding[k];
320 }
321 if (k != len_padding_size) {
322 return -1;
323 }
324 }
325
326 /* Check the first program unit bytes are all filled. */
327 if (i != FLASH_PROGRAM_UNIT) {
328 return -1;
329 }
330 if (DRV_FLASH_AREA(area)->ProgramData(area->fa_off + aligned_off,
331 add_padding,
332 FLASH_PROGRAM_UNIT / data_width) < 0) {
333 return -1;
334 }
335 }
336
337 /* 'src_written_idx' indicates the number of the src data which has already
338 * been programed into flash. 'src_written_idx' equals to 'len' means that
339 * all the data in src has been programmed and aligned_len equals to
340 * FLASH_PROGRAM_UNIT. This case has been handled above.
341 * 'src_written_idx' less than 'len' means that not all the data in src has
342 * been programmed.
343 */
344 if (src_written_idx < len) {
345 /* Program from the first aligned bytes(src_written_idx) to the last
346 * aligned bytes in src.
347 */
348 write_size = FLOOR_ALIGN(len - src_written_idx, FLASH_PROGRAM_UNIT);
349 if (write_size > 0) {
350 if (DRV_FLASH_AREA(area)->ProgramData(
351 area->fa_off + off + src_written_idx,
352 src,
353 write_size / data_width) < 0) {
354 return -1;
355 }
356 src_written_idx += write_size;
357 }
358 last_unit_start_off = src_written_idx;
359
360 /* Program the last program unit data into flash. */
361 if (len_padding_size) {
362 /* Copy the last unaligned bytes in src to add_padding. */
363 for (i = 0; (i < FLASH_PROGRAM_UNIT) && (src_written_idx < len);
364 i++, src_written_idx++) {
365 add_padding[i] = ((uint8_t *)src)[src_written_idx];
366 }
367
368 if (src_written_idx != len) {
369 return -1;
370 }
371 /* Copy the len_padding_size bytes in len_padding to add_padding. */
372 for (k = 0; (i < FLASH_PROGRAM_UNIT) && (k < len_padding_size);
373 i++, k++) {
374 add_padding[i] = len_padding[k];
375 }
376 write_size = add_padding_size + last_unit_start_off +
377 FLASH_PROGRAM_UNIT;
378 if ((i != FLASH_PROGRAM_UNIT) || (k != len_padding_size) ||
379 (aligned_len != write_size)) {
380 return -1;
381 }
382 if (DRV_FLASH_AREA(area)->ProgramData(
383 area->fa_off + off + last_unit_start_off,
384 add_padding,
385 FLASH_PROGRAM_UNIT / data_width) < 0) {
386 return -1;
387 }
388 }
389 }
390
391 return 0;
392 }
393
flash_area_erase(const struct flash_area * area,uint32_t off,uint32_t len)394 int flash_area_erase(const struct flash_area *area, uint32_t off, uint32_t len)
395 {
396 ARM_FLASH_INFO *flash_info;
397 uint32_t deleted_len = 0;
398 int32_t rc = 0;
399
400 BOOT_LOG_DBG("erase area=%d, off=%#x, len=%#x", area->fa_id, off, len);
401
402 if (!is_range_valid(area, off, len)) {
403 return -1;
404 }
405
406 flash_info = DRV_FLASH_AREA(area)->GetInfo();
407
408 if (flash_info->sector_info == NULL) {
409 /* Uniform sector layout */
410 while (deleted_len < len) {
411 rc = DRV_FLASH_AREA(area)->EraseSector(area->fa_off + off);
412 if (rc != 0) {
413 break;
414 }
415 deleted_len += flash_info->sector_size;
416 off += flash_info->sector_size;
417 }
418 } else {
419 /* Inhomogeneous sector layout, explicitly defined
420 * Currently not supported.
421 */
422 }
423
424 return rc;
425 }
426
flash_area_align(const struct flash_area * area)427 uint32_t flash_area_align(const struct flash_area *area)
428 {
429 ARM_FLASH_INFO *flash_info;
430
431 flash_info = DRV_FLASH_AREA(area)->GetInfo();
432 return flash_info->program_unit;
433 }
434