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