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