blob: dbaf94a98b63b65253dd32dea1967e1d76d35775 [file] [log] [blame]
Tamas Banf70ef8c2017-12-19 15:35:09 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
David Vincze39e78552018-10-10 17:10:01 +020020/*
21 * Original code taken from mcuboot project at:
22 * https://github.com/JuulLabs-OSS/mcuboot
David Vincze401c7422019-06-21 20:44:05 +020023 * Git SHA of the original version: 3c469bc698a9767859ed73cd0201c44161204d5c
David Vincze39e78552018-10-10 17:10:01 +020024 * Modifications are Copyright (c) 2018-2019 Arm Limited.
25 */
26
Tamas Ban581034a2017-12-19 19:54:37 +000027#include <errno.h>
28#include <stdbool.h>
Tamas Banf70ef8c2017-12-19 15:35:09 +000029
30#include "target.h"
Tamas Banc3828852018-02-01 12:24:16 +000031#include "bl2_util.h"
32#include "Driver_Flash.h"
Tamas Banf70ef8c2017-12-19 15:35:09 +000033
34#include <flash_map/flash_map.h>
Tamas Banf70ef8c2017-12-19 15:35:09 +000035#include "bootutil/bootutil_log.h"
36
Tamas Banc3828852018-02-01 12:24:16 +000037/* Flash device name must be specified by target */
38extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
Tamas Banf70ef8c2017-12-19 15:35:09 +000039
40/*
41 * For now, we only support one flash device.
42 *
43 * Pick a random device ID for it that's unlikely to collide with
44 * anything "real".
45 */
46#define FLASH_DEVICE_ID 100
Tamas Ban581034a2017-12-19 19:54:37 +000047#define FLASH_DEVICE_BASE FLASH_BASE_ADDRESS
Tamas Banf70ef8c2017-12-19 15:35:09 +000048
49#define FLASH_MAP_ENTRY_MAGIC 0xd00dbeef
50
51struct flash_map_entry {
52 const uint32_t magic;
53 const struct flash_area area;
54 unsigned int ref_count;
55};
56
57/*
58 * The flash area describes essentially the partition table of the
David Vincze8bdfc2d2019-03-18 15:49:23 +010059 * flash. In this case, it starts with FLASH_AREA_IMAGE_PRIMARY.
Tamas Banf70ef8c2017-12-19 15:35:09 +000060 */
61static struct flash_map_entry part_map[] = {
62 {
63 .magic = FLASH_MAP_ENTRY_MAGIC,
64 .area = {
David Vinczebb207982019-08-21 15:13:04 +020065 .fa_id = FLASH_AREA_0_ID,
Tamas Banf70ef8c2017-12-19 15:35:09 +000066 .fa_device_id = FLASH_DEVICE_ID,
David Vinczebb207982019-08-21 15:13:04 +020067 .fa_off = FLASH_AREA_0_OFFSET,
68 .fa_size = FLASH_AREA_0_SIZE,
Tamas Banf70ef8c2017-12-19 15:35:09 +000069 },
70 },
71 {
72 .magic = FLASH_MAP_ENTRY_MAGIC,
73 .area = {
David Vinczebb207982019-08-21 15:13:04 +020074 .fa_id = FLASH_AREA_2_ID,
Tamas Banf70ef8c2017-12-19 15:35:09 +000075 .fa_device_id = FLASH_DEVICE_ID,
David Vinczebb207982019-08-21 15:13:04 +020076 .fa_off = FLASH_AREA_2_OFFSET,
77 .fa_size = FLASH_AREA_2_SIZE,
78 },
79 },
80#if (MCUBOOT_IMAGE_NUMBER == 2)
81 {
82 .magic = FLASH_MAP_ENTRY_MAGIC,
83 .area = {
84 .fa_id = FLASH_AREA_1_ID,
85 .fa_device_id = FLASH_DEVICE_ID,
86 .fa_off = FLASH_AREA_1_OFFSET,
87 .fa_size = FLASH_AREA_1_SIZE,
Tamas Banf70ef8c2017-12-19 15:35:09 +000088 },
89 },
90 {
91 .magic = FLASH_MAP_ENTRY_MAGIC,
92 .area = {
David Vinczebb207982019-08-21 15:13:04 +020093 .fa_id = FLASH_AREA_3_ID,
Tamas Banf70ef8c2017-12-19 15:35:09 +000094 .fa_device_id = FLASH_DEVICE_ID,
David Vinczebb207982019-08-21 15:13:04 +020095 .fa_off = FLASH_AREA_3_OFFSET,
96 .fa_size = FLASH_AREA_3_SIZE,
97 },
98 },
99#endif
100 {
101 .magic = FLASH_MAP_ENTRY_MAGIC,
102 .area = {
103 .fa_id = FLASH_AREA_SCRATCH_ID,
104 .fa_device_id = FLASH_DEVICE_ID,
105 .fa_off = FLASH_AREA_SCRATCH_OFFSET,
106 .fa_size = FLASH_AREA_SCRATCH_SIZE,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000107 },
108 }
109};
110
111int flash_device_base(uint8_t fd_id, uintptr_t *ret)
112{
113 if (fd_id != FLASH_DEVICE_ID) {
114 BOOT_LOG_ERR("invalid flash ID %d; expected %d",
115 fd_id, FLASH_DEVICE_ID);
TTornblomc640e072019-06-14 14:33:51 +0200116 return -1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000117 }
118 *ret = FLASH_DEVICE_BASE;
119 return 0;
120}
121
122/*
123 * `open` a flash area. The `area` in this case is not the individual
124 * sectors, but describes the particular flash area in question.
125 */
126int flash_area_open(uint8_t id, const struct flash_area **area)
127{
128 int i;
129
130 BOOT_LOG_DBG("area %d", id);
131
132 for (i = 0; i < ARRAY_SIZE(part_map); i++) {
133 if (id == part_map[i].area.fa_id) {
134 break;
135 }
136 }
137 if (i == ARRAY_SIZE(part_map)) {
138 return -1;
139 }
140
141 *area = &part_map[i].area;
142 part_map[i].ref_count++;
143 return 0;
144}
145
146/*
147 * Nothing to do on close.
148 */
149void flash_area_close(const struct flash_area *area)
150{
151 struct flash_map_entry *entry;
152
153 if (!area) {
154 return;
155 }
156
157 entry = CONTAINER_OF(area, struct flash_map_entry, area);
158 if (entry->magic != FLASH_MAP_ENTRY_MAGIC) {
159 BOOT_LOG_ERR("invalid area %p (id %u)", area, area->fa_id);
160 return;
161 }
162 if (entry->ref_count == 0) {
163 BOOT_LOG_ERR("area %u use count underflow", area->fa_id);
164 return;
165 }
166 entry->ref_count--;
167}
168
Tamas Ban581034a2017-12-19 19:54:37 +0000169void flash_area_warn_on_open(void)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000170{
171 int i;
Tamas Ban581034a2017-12-19 19:54:37 +0000172 struct flash_map_entry *entry;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000173
174 for (i = 0; i < ARRAY_SIZE(part_map); i++) {
Tamas Ban581034a2017-12-19 19:54:37 +0000175 entry = &part_map[i];
Tamas Banf70ef8c2017-12-19 15:35:09 +0000176 if (entry->ref_count) {
177 BOOT_LOG_WRN("area %u has %u users",
178 entry->area.fa_id, entry->ref_count);
179 }
180 }
181}
182
David Vincze39e78552018-10-10 17:10:01 +0200183uint8_t flash_area_erased_val(const struct flash_area *area)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000184{
David Vincze39e78552018-10-10 17:10:01 +0200185 (void)area;
186
187 return FLASH_DEV_NAME.GetInfo()->erased_value;
188}
189
190int flash_area_read(const struct flash_area *area, uint32_t off, void *dst,
191 uint32_t len)
192{
193 BOOT_LOG_DBG("read area=%d, off=%#x, len=%#x", area->fa_id, off, len);
Tamas Banc3828852018-02-01 12:24:16 +0000194 return FLASH_DEV_NAME.ReadData(area->fa_off + off, dst, len);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000195}
196
David Vincze39e78552018-10-10 17:10:01 +0200197int flash_area_read_is_empty(const struct flash_area *area, uint32_t off,
198 void *dst, uint32_t len)
199{
200 uint32_t i;
201 uint8_t *u8dst;
202 int rc;
203
204 BOOT_LOG_DBG("read_is_empty area=%d, off=%#x, len=%#x",
205 area->fa_id, off, len);
206
207 rc = FLASH_DEV_NAME.ReadData(area->fa_off + off, dst, len);
208 if(rc != 0) {
209 return -1;
210 }
211
212 u8dst = (uint8_t*)dst;
213
214 for (i = 0; i < len; i++) {
215 if (u8dst[i] != flash_area_erased_val(area)) {
216 return 0;
217 }
218 }
219
220 return 1;
221}
222
Tamas Ban581034a2017-12-19 19:54:37 +0000223int flash_area_write(const struct flash_area *area, uint32_t off,
224 const void *src, uint32_t len)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000225{
Tamas Banc3828852018-02-01 12:24:16 +0000226 BOOT_LOG_DBG("write area=%d, off=%#x, len=%#x", area->fa_id, off, len);
227 return FLASH_DEV_NAME.ProgramData(area->fa_off + off, src, len);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000228}
229
230int flash_area_erase(const struct flash_area *area, uint32_t off, uint32_t len)
231{
Tamas Banc3828852018-02-01 12:24:16 +0000232 ARM_FLASH_INFO *flash_info;
233 uint32_t deleted_len = 0;
234 int32_t rc = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000235
Tamas Banc3828852018-02-01 12:24:16 +0000236 BOOT_LOG_DBG("erase area=%d, off=%#x, len=%#x", area->fa_id, off, len);
237 flash_info = FLASH_DEV_NAME.GetInfo();
238
239 if (flash_info->sector_info == NULL) {
240 /* Uniform sector layout */
241 while (deleted_len < len) {
242 rc = FLASH_DEV_NAME.EraseSector(area->fa_off + off);
243 if (rc != 0) {
244 break;
245 }
246 deleted_len += flash_info->sector_size;
247 off += flash_info->sector_size;
248 }
249 } else {
250 /* Inhomogeneous sector layout, explicitly defined
251 * Currently not supported.
252 */
253 }
254
Tamas Banf70ef8c2017-12-19 15:35:09 +0000255 return rc;
256}
257
Raef Coles204c5b42019-09-05 09:18:47 +0100258uint32_t flash_area_align(const struct flash_area *area)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000259{
Tamas Banc3828852018-02-01 12:24:16 +0000260 ARM_FLASH_INFO *flash_info;
261
262 flash_info = FLASH_DEV_NAME.GetInfo();
263 return flash_info->program_unit;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000264}
265
266/*
David Vincze8bdfc2d2019-03-18 15:49:23 +0100267 * This depends on the mappings defined in sysflash.h, and assumes that the
268 * primary slot, the secondary slot, and the scratch area are contiguous.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000269 */
270int flash_area_id_from_image_slot(int slot)
271{
David Vinczebb207982019-08-21 15:13:04 +0200272#if (MCUBOOT_IMAGE_NUMBER == 1)
273 static
274#endif
275 const int area_id_tab[] = {FLASH_AREA_IMAGE_PRIMARY,
276 FLASH_AREA_IMAGE_SECONDARY,
277 FLASH_AREA_IMAGE_SCRATCH};
David Vincze401c7422019-06-21 20:44:05 +0200278
279 if (slot >= 0 && slot < ARRAY_SIZE(area_id_tab)) {
280 return area_id_tab[slot];
281 }
282
283 return -EINVAL; /* flash_area_open will fail on that */
284}
285
286int flash_area_id_to_image_slot(int area_id)
287{
David Vinczebb207982019-08-21 15:13:04 +0200288 if (area_id == FLASH_AREA_IMAGE_PRIMARY) {
David Vincze401c7422019-06-21 20:44:05 +0200289 return 0;
David Vincze401c7422019-06-21 20:44:05 +0200290 }
David Vinczebb207982019-08-21 15:13:04 +0200291 if (area_id == FLASH_AREA_IMAGE_SECONDARY) {
292 return 1;
293 }
294
295 BOOT_LOG_ERR("invalid flash area ID");
296 return -1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000297}
298
Tamas Ban581034a2017-12-19 19:54:37 +0000299static int validate_idx(int idx, uint32_t *off, uint32_t *len)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000300{
301 /*
302 * This simple layout has uniform slots, so just fill in the
303 * right one.
304 */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000305
306 switch (idx) {
David Vinczebb207982019-08-21 15:13:04 +0200307 case FLASH_AREA_0_ID:
308 *off = FLASH_AREA_0_OFFSET;
309 *len = FLASH_AREA_0_SIZE;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000310 break;
David Vinczebb207982019-08-21 15:13:04 +0200311 case FLASH_AREA_2_ID:
312 *off = FLASH_AREA_2_OFFSET;
313 *len = FLASH_AREA_2_SIZE;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000314 break;
David Vinczebb207982019-08-21 15:13:04 +0200315#if (MCUBOOT_IMAGE_NUMBER == 2)
316 case FLASH_AREA_1_ID:
317 *off = FLASH_AREA_1_OFFSET;
318 *len = FLASH_AREA_1_SIZE;
319 break;
320 case FLASH_AREA_3_ID:
321 *off = FLASH_AREA_3_OFFSET;
322 *len = FLASH_AREA_3_SIZE;
323 break;
324#endif
325 case FLASH_AREA_SCRATCH_ID:
326 *off = FLASH_AREA_SCRATCH_OFFSET;
327 *len = FLASH_AREA_SCRATCH_SIZE;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000328 break;
329 default:
330 BOOT_LOG_ERR("unknown flash area %d", idx);
331 return -1;
332 }
333
Tamas Ban581034a2017-12-19 19:54:37 +0000334 BOOT_LOG_DBG("area %d: offset=0x%x, length=0x%x, sector size=0x%x",
335 idx, *off, *len, FLASH_AREA_IMAGE_SECTOR_SIZE);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000336 return 0;
337}
338
Tamas Banf70ef8c2017-12-19 15:35:09 +0000339int flash_area_to_sectors(int idx, int *cnt, struct flash_area *ret)
340{
Tamas Ban581034a2017-12-19 19:54:37 +0000341 uint32_t off;
342 uint32_t len;
343 uint32_t max_cnt = *cnt;
344 uint32_t rem_len;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000345
Tamas Ban581034a2017-12-19 19:54:37 +0000346 if (validate_idx(idx, &off, &len)) {
347 return -1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000348 }
349
Tamas Ban581034a2017-12-19 19:54:37 +0000350 if (*cnt < 1) {
351 return -1;
352 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000353
Tamas Ban581034a2017-12-19 19:54:37 +0000354 rem_len = len;
355 *cnt = 0;
356 while (rem_len > 0 && *cnt < max_cnt) {
357 if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
358 BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
359 idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
360 return -1;
361 }
362
363 ret[*cnt].fa_id = idx;
364 ret[*cnt].fa_device_id = 0;
365 ret[*cnt].pad16 = 0;
366 ret[*cnt].fa_off = off + (FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt));
367 ret[*cnt].fa_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
368 *cnt = *cnt + 1;
369 rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
370 }
371
Tamas Banc3828852018-02-01 12:24:16 +0000372 if (*cnt > max_cnt) {
Tamas Ban581034a2017-12-19 19:54:37 +0000373 BOOT_LOG_ERR("flash area %d sector count overflow", idx);
374 return -1;
375 }
376
377 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000378}
379
Tamas Ban581034a2017-12-19 19:54:37 +0000380/*
381 * Lookup the sector map for a given flash area. This should fill in
382 * `ret` with all of the sectors in the area. `*cnt` will be set to
383 * the storage at `ret` and should be set to the final number of
384 * sectors in this area.
385 */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000386int flash_area_get_sectors(int idx, uint32_t *cnt, struct flash_sector *ret)
387{
Tamas Ban581034a2017-12-19 19:54:37 +0000388 uint32_t off;
389 uint32_t len;
390 uint32_t max_cnt = *cnt;
391 uint32_t rem_len;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000392
Tamas Ban581034a2017-12-19 19:54:37 +0000393 if (validate_idx(idx, &off, &len)) {
394 return -1;
395 }
396
397 if (*cnt < 1) {
398 return -1;
399 }
400
401 rem_len = len;
402 *cnt = 0;
403 while (rem_len > 0 && *cnt < max_cnt) {
404 if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
405 BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
406 idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
407 return -1;
408 }
409
410 ret[*cnt].fs_off = FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt);
411 ret[*cnt].fs_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
412 *cnt = *cnt + 1;
413 rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
414 }
415
Tamas Banc3828852018-02-01 12:24:16 +0000416 if (*cnt > max_cnt) {
Tamas Ban581034a2017-12-19 19:54:37 +0000417 BOOT_LOG_ERR("flash area %d sector count overflow", idx);
418 return -1;
419 }
420
421 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000422}