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