blob: 2d865a70d3c0d51577ec8fd932ec7572541a48e1 [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
36#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO
37#include "bootutil/bootutil_log.h"
38
Tamas Banc3828852018-02-01 12:24:16 +000039/* Flash device name must be specified by target */
40extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
Tamas Banf70ef8c2017-12-19 15:35:09 +000041
42/*
43 * For now, we only support one flash device.
44 *
45 * Pick a random device ID for it that's unlikely to collide with
46 * anything "real".
47 */
48#define FLASH_DEVICE_ID 100
Tamas Ban581034a2017-12-19 19:54:37 +000049#define FLASH_DEVICE_BASE FLASH_BASE_ADDRESS
Tamas Banf70ef8c2017-12-19 15:35:09 +000050
51#define FLASH_MAP_ENTRY_MAGIC 0xd00dbeef
52
53struct flash_map_entry {
54 const uint32_t magic;
55 const struct flash_area area;
56 unsigned int ref_count;
57};
58
59/*
60 * The flash area describes essentially the partition table of the
David Vincze8bdfc2d2019-03-18 15:49:23 +010061 * flash. In this case, it starts with FLASH_AREA_IMAGE_PRIMARY.
Tamas Banf70ef8c2017-12-19 15:35:09 +000062 */
63static struct flash_map_entry part_map[] = {
64 {
65 .magic = FLASH_MAP_ENTRY_MAGIC,
66 .area = {
David Vinczebb207982019-08-21 15:13:04 +020067 .fa_id = FLASH_AREA_0_ID,
Tamas Banf70ef8c2017-12-19 15:35:09 +000068 .fa_device_id = FLASH_DEVICE_ID,
David Vinczebb207982019-08-21 15:13:04 +020069 .fa_off = FLASH_AREA_0_OFFSET,
70 .fa_size = FLASH_AREA_0_SIZE,
Tamas Banf70ef8c2017-12-19 15:35:09 +000071 },
72 },
73 {
74 .magic = FLASH_MAP_ENTRY_MAGIC,
75 .area = {
David Vinczebb207982019-08-21 15:13:04 +020076 .fa_id = FLASH_AREA_2_ID,
Tamas Banf70ef8c2017-12-19 15:35:09 +000077 .fa_device_id = FLASH_DEVICE_ID,
David Vinczebb207982019-08-21 15:13:04 +020078 .fa_off = FLASH_AREA_2_OFFSET,
79 .fa_size = FLASH_AREA_2_SIZE,
80 },
81 },
82#if (MCUBOOT_IMAGE_NUMBER == 2)
83 {
84 .magic = FLASH_MAP_ENTRY_MAGIC,
85 .area = {
86 .fa_id = FLASH_AREA_1_ID,
87 .fa_device_id = FLASH_DEVICE_ID,
88 .fa_off = FLASH_AREA_1_OFFSET,
89 .fa_size = FLASH_AREA_1_SIZE,
Tamas Banf70ef8c2017-12-19 15:35:09 +000090 },
91 },
92 {
93 .magic = FLASH_MAP_ENTRY_MAGIC,
94 .area = {
David Vinczebb207982019-08-21 15:13:04 +020095 .fa_id = FLASH_AREA_3_ID,
Tamas Banf70ef8c2017-12-19 15:35:09 +000096 .fa_device_id = FLASH_DEVICE_ID,
David Vinczebb207982019-08-21 15:13:04 +020097 .fa_off = FLASH_AREA_3_OFFSET,
98 .fa_size = FLASH_AREA_3_SIZE,
99 },
100 },
101#endif
102 {
103 .magic = FLASH_MAP_ENTRY_MAGIC,
104 .area = {
105 .fa_id = FLASH_AREA_SCRATCH_ID,
106 .fa_device_id = FLASH_DEVICE_ID,
107 .fa_off = FLASH_AREA_SCRATCH_OFFSET,
108 .fa_size = FLASH_AREA_SCRATCH_SIZE,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000109 },
110 }
111};
112
113int flash_device_base(uint8_t fd_id, uintptr_t *ret)
114{
115 if (fd_id != FLASH_DEVICE_ID) {
116 BOOT_LOG_ERR("invalid flash ID %d; expected %d",
117 fd_id, FLASH_DEVICE_ID);
TTornblomc640e072019-06-14 14:33:51 +0200118 return -1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000119 }
120 *ret = FLASH_DEVICE_BASE;
121 return 0;
122}
123
124/*
125 * `open` a flash area. The `area` in this case is not the individual
126 * sectors, but describes the particular flash area in question.
127 */
128int flash_area_open(uint8_t id, const struct flash_area **area)
129{
130 int i;
131
132 BOOT_LOG_DBG("area %d", id);
133
134 for (i = 0; i < ARRAY_SIZE(part_map); i++) {
135 if (id == part_map[i].area.fa_id) {
136 break;
137 }
138 }
139 if (i == ARRAY_SIZE(part_map)) {
140 return -1;
141 }
142
143 *area = &part_map[i].area;
144 part_map[i].ref_count++;
145 return 0;
146}
147
148/*
149 * Nothing to do on close.
150 */
151void flash_area_close(const struct flash_area *area)
152{
153 struct flash_map_entry *entry;
154
155 if (!area) {
156 return;
157 }
158
159 entry = CONTAINER_OF(area, struct flash_map_entry, area);
160 if (entry->magic != FLASH_MAP_ENTRY_MAGIC) {
161 BOOT_LOG_ERR("invalid area %p (id %u)", area, area->fa_id);
162 return;
163 }
164 if (entry->ref_count == 0) {
165 BOOT_LOG_ERR("area %u use count underflow", area->fa_id);
166 return;
167 }
168 entry->ref_count--;
169}
170
Tamas Ban581034a2017-12-19 19:54:37 +0000171void flash_area_warn_on_open(void)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000172{
173 int i;
Tamas Ban581034a2017-12-19 19:54:37 +0000174 struct flash_map_entry *entry;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000175
176 for (i = 0; i < ARRAY_SIZE(part_map); i++) {
Tamas Ban581034a2017-12-19 19:54:37 +0000177 entry = &part_map[i];
Tamas Banf70ef8c2017-12-19 15:35:09 +0000178 if (entry->ref_count) {
179 BOOT_LOG_WRN("area %u has %u users",
180 entry->area.fa_id, entry->ref_count);
181 }
182 }
183}
184
David Vincze39e78552018-10-10 17:10:01 +0200185uint8_t flash_area_erased_val(const struct flash_area *area)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000186{
David Vincze39e78552018-10-10 17:10:01 +0200187 (void)area;
188
189 return FLASH_DEV_NAME.GetInfo()->erased_value;
190}
191
192int flash_area_read(const struct flash_area *area, uint32_t off, void *dst,
193 uint32_t len)
194{
195 BOOT_LOG_DBG("read area=%d, off=%#x, len=%#x", area->fa_id, off, len);
Tamas Banc3828852018-02-01 12:24:16 +0000196 return FLASH_DEV_NAME.ReadData(area->fa_off + off, dst, len);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000197}
198
David Vincze39e78552018-10-10 17:10:01 +0200199int flash_area_read_is_empty(const struct flash_area *area, uint32_t off,
200 void *dst, uint32_t len)
201{
202 uint32_t i;
203 uint8_t *u8dst;
204 int rc;
205
206 BOOT_LOG_DBG("read_is_empty area=%d, off=%#x, len=%#x",
207 area->fa_id, off, len);
208
209 rc = FLASH_DEV_NAME.ReadData(area->fa_off + off, dst, len);
210 if(rc != 0) {
211 return -1;
212 }
213
214 u8dst = (uint8_t*)dst;
215
216 for (i = 0; i < len; i++) {
217 if (u8dst[i] != flash_area_erased_val(area)) {
218 return 0;
219 }
220 }
221
222 return 1;
223}
224
Tamas Ban581034a2017-12-19 19:54:37 +0000225int flash_area_write(const struct flash_area *area, uint32_t off,
226 const void *src, uint32_t len)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000227{
Tamas Banc3828852018-02-01 12:24:16 +0000228 BOOT_LOG_DBG("write area=%d, off=%#x, len=%#x", area->fa_id, off, len);
229 return FLASH_DEV_NAME.ProgramData(area->fa_off + off, src, len);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000230}
231
232int flash_area_erase(const struct flash_area *area, uint32_t off, uint32_t len)
233{
Tamas Banc3828852018-02-01 12:24:16 +0000234 ARM_FLASH_INFO *flash_info;
235 uint32_t deleted_len = 0;
236 int32_t rc = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000237
Tamas Banc3828852018-02-01 12:24:16 +0000238 BOOT_LOG_DBG("erase area=%d, off=%#x, len=%#x", area->fa_id, off, len);
239 flash_info = FLASH_DEV_NAME.GetInfo();
240
241 if (flash_info->sector_info == NULL) {
242 /* Uniform sector layout */
243 while (deleted_len < len) {
244 rc = FLASH_DEV_NAME.EraseSector(area->fa_off + off);
245 if (rc != 0) {
246 break;
247 }
248 deleted_len += flash_info->sector_size;
249 off += flash_info->sector_size;
250 }
251 } else {
252 /* Inhomogeneous sector layout, explicitly defined
253 * Currently not supported.
254 */
255 }
256
Tamas Banf70ef8c2017-12-19 15:35:09 +0000257 return rc;
258}
259
Raef Coles204c5b42019-09-05 09:18:47 +0100260uint32_t flash_area_align(const struct flash_area *area)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000261{
Tamas Banc3828852018-02-01 12:24:16 +0000262 ARM_FLASH_INFO *flash_info;
263
264 flash_info = FLASH_DEV_NAME.GetInfo();
265 return flash_info->program_unit;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000266}
267
268/*
David Vincze8bdfc2d2019-03-18 15:49:23 +0100269 * This depends on the mappings defined in sysflash.h, and assumes that the
270 * primary slot, the secondary slot, and the scratch area are contiguous.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000271 */
272int flash_area_id_from_image_slot(int slot)
273{
David Vinczebb207982019-08-21 15:13:04 +0200274#if (MCUBOOT_IMAGE_NUMBER == 1)
275 static
276#endif
277 const int area_id_tab[] = {FLASH_AREA_IMAGE_PRIMARY,
278 FLASH_AREA_IMAGE_SECONDARY,
279 FLASH_AREA_IMAGE_SCRATCH};
David Vincze401c7422019-06-21 20:44:05 +0200280
281 if (slot >= 0 && slot < ARRAY_SIZE(area_id_tab)) {
282 return area_id_tab[slot];
283 }
284
285 return -EINVAL; /* flash_area_open will fail on that */
286}
287
288int flash_area_id_to_image_slot(int area_id)
289{
David Vinczebb207982019-08-21 15:13:04 +0200290 if (area_id == FLASH_AREA_IMAGE_PRIMARY) {
David Vincze401c7422019-06-21 20:44:05 +0200291 return 0;
David Vincze401c7422019-06-21 20:44:05 +0200292 }
David Vinczebb207982019-08-21 15:13:04 +0200293 if (area_id == FLASH_AREA_IMAGE_SECONDARY) {
294 return 1;
295 }
296
297 BOOT_LOG_ERR("invalid flash area ID");
298 return -1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000299}
300
Tamas Ban581034a2017-12-19 19:54:37 +0000301static int validate_idx(int idx, uint32_t *off, uint32_t *len)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000302{
303 /*
304 * This simple layout has uniform slots, so just fill in the
305 * right one.
306 */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000307
308 switch (idx) {
David Vinczebb207982019-08-21 15:13:04 +0200309 case FLASH_AREA_0_ID:
310 *off = FLASH_AREA_0_OFFSET;
311 *len = FLASH_AREA_0_SIZE;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000312 break;
David Vinczebb207982019-08-21 15:13:04 +0200313 case FLASH_AREA_2_ID:
314 *off = FLASH_AREA_2_OFFSET;
315 *len = FLASH_AREA_2_SIZE;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000316 break;
David Vinczebb207982019-08-21 15:13:04 +0200317#if (MCUBOOT_IMAGE_NUMBER == 2)
318 case FLASH_AREA_1_ID:
319 *off = FLASH_AREA_1_OFFSET;
320 *len = FLASH_AREA_1_SIZE;
321 break;
322 case FLASH_AREA_3_ID:
323 *off = FLASH_AREA_3_OFFSET;
324 *len = FLASH_AREA_3_SIZE;
325 break;
326#endif
327 case FLASH_AREA_SCRATCH_ID:
328 *off = FLASH_AREA_SCRATCH_OFFSET;
329 *len = FLASH_AREA_SCRATCH_SIZE;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000330 break;
331 default:
332 BOOT_LOG_ERR("unknown flash area %d", idx);
333 return -1;
334 }
335
Tamas Ban581034a2017-12-19 19:54:37 +0000336 BOOT_LOG_DBG("area %d: offset=0x%x, length=0x%x, sector size=0x%x",
337 idx, *off, *len, FLASH_AREA_IMAGE_SECTOR_SIZE);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000338 return 0;
339}
340
Tamas Banf70ef8c2017-12-19 15:35:09 +0000341int flash_area_to_sectors(int idx, int *cnt, struct flash_area *ret)
342{
Tamas Ban581034a2017-12-19 19:54:37 +0000343 uint32_t off;
344 uint32_t len;
345 uint32_t max_cnt = *cnt;
346 uint32_t rem_len;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000347
Tamas Ban581034a2017-12-19 19:54:37 +0000348 if (validate_idx(idx, &off, &len)) {
349 return -1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000350 }
351
Tamas Ban581034a2017-12-19 19:54:37 +0000352 if (*cnt < 1) {
353 return -1;
354 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000355
Tamas Ban581034a2017-12-19 19:54:37 +0000356 rem_len = len;
357 *cnt = 0;
358 while (rem_len > 0 && *cnt < max_cnt) {
359 if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
360 BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
361 idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
362 return -1;
363 }
364
365 ret[*cnt].fa_id = idx;
366 ret[*cnt].fa_device_id = 0;
367 ret[*cnt].pad16 = 0;
368 ret[*cnt].fa_off = off + (FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt));
369 ret[*cnt].fa_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
370 *cnt = *cnt + 1;
371 rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
372 }
373
Tamas Banc3828852018-02-01 12:24:16 +0000374 if (*cnt > max_cnt) {
Tamas Ban581034a2017-12-19 19:54:37 +0000375 BOOT_LOG_ERR("flash area %d sector count overflow", idx);
376 return -1;
377 }
378
379 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000380}
381
Tamas Ban581034a2017-12-19 19:54:37 +0000382/*
383 * Lookup the sector map for a given flash area. This should fill in
384 * `ret` with all of the sectors in the area. `*cnt` will be set to
385 * the storage at `ret` and should be set to the final number of
386 * sectors in this area.
387 */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000388int flash_area_get_sectors(int idx, uint32_t *cnt, struct flash_sector *ret)
389{
Tamas Ban581034a2017-12-19 19:54:37 +0000390 uint32_t off;
391 uint32_t len;
392 uint32_t max_cnt = *cnt;
393 uint32_t rem_len;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000394
Tamas Ban581034a2017-12-19 19:54:37 +0000395 if (validate_idx(idx, &off, &len)) {
396 return -1;
397 }
398
399 if (*cnt < 1) {
400 return -1;
401 }
402
403 rem_len = len;
404 *cnt = 0;
405 while (rem_len > 0 && *cnt < max_cnt) {
406 if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
407 BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
408 idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
409 return -1;
410 }
411
412 ret[*cnt].fs_off = FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt);
413 ret[*cnt].fs_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
414 *cnt = *cnt + 1;
415 rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
416 }
417
Tamas Banc3828852018-02-01 12:24:16 +0000418 if (*cnt > max_cnt) {
Tamas Ban581034a2017-12-19 19:54:37 +0000419 BOOT_LOG_ERR("flash area %d sector count overflow", idx);
420 return -1;
421 }
422
423 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000424}