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