blob: 31a9d74e48eaca777118c495ca8675080dab7589 [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 Vincze8bdfc2d2019-03-18 15:49:23 +010067 .fa_id = FLASH_AREA_IMAGE_PRIMARY,
Tamas Banf70ef8c2017-12-19 15:35:09 +000068 .fa_device_id = FLASH_DEVICE_ID,
David Vincze8bdfc2d2019-03-18 15:49:23 +010069 .fa_off = FLASH_AREA_IMAGE_PRIMARY_OFFSET,
70 .fa_size = FLASH_AREA_IMAGE_PRIMARY_SIZE,
Tamas Banf70ef8c2017-12-19 15:35:09 +000071 },
72 },
73 {
74 .magic = FLASH_MAP_ENTRY_MAGIC,
75 .area = {
David Vincze8bdfc2d2019-03-18 15:49:23 +010076 .fa_id = FLASH_AREA_IMAGE_SECONDARY,
Tamas Banf70ef8c2017-12-19 15:35:09 +000077 .fa_device_id = FLASH_DEVICE_ID,
David Vincze8bdfc2d2019-03-18 15:49:23 +010078 .fa_off = FLASH_AREA_IMAGE_SECONDARY_OFFSET,
79 .fa_size = FLASH_AREA_IMAGE_SECONDARY_SIZE,
Tamas Banf70ef8c2017-12-19 15:35:09 +000080 },
81 },
82 {
83 .magic = FLASH_MAP_ENTRY_MAGIC,
84 .area = {
85 .fa_id = FLASH_AREA_IMAGE_SCRATCH,
86 .fa_device_id = FLASH_DEVICE_ID,
87 .fa_off = FLASH_AREA_IMAGE_SCRATCH_OFFSET,
88 .fa_size = FLASH_AREA_IMAGE_SCRATCH_SIZE,
89 },
90 }
91};
92
93int flash_device_base(uint8_t fd_id, uintptr_t *ret)
94{
95 if (fd_id != FLASH_DEVICE_ID) {
96 BOOT_LOG_ERR("invalid flash ID %d; expected %d",
97 fd_id, FLASH_DEVICE_ID);
TTornblomc640e072019-06-14 14:33:51 +020098 return -1;
Tamas Banf70ef8c2017-12-19 15:35:09 +000099 }
100 *ret = FLASH_DEVICE_BASE;
101 return 0;
102}
103
104/*
105 * `open` a flash area. The `area` in this case is not the individual
106 * sectors, but describes the particular flash area in question.
107 */
108int flash_area_open(uint8_t id, const struct flash_area **area)
109{
110 int i;
111
112 BOOT_LOG_DBG("area %d", id);
113
114 for (i = 0; i < ARRAY_SIZE(part_map); i++) {
115 if (id == part_map[i].area.fa_id) {
116 break;
117 }
118 }
119 if (i == ARRAY_SIZE(part_map)) {
120 return -1;
121 }
122
123 *area = &part_map[i].area;
124 part_map[i].ref_count++;
125 return 0;
126}
127
128/*
129 * Nothing to do on close.
130 */
131void flash_area_close(const struct flash_area *area)
132{
133 struct flash_map_entry *entry;
134
135 if (!area) {
136 return;
137 }
138
139 entry = CONTAINER_OF(area, struct flash_map_entry, area);
140 if (entry->magic != FLASH_MAP_ENTRY_MAGIC) {
141 BOOT_LOG_ERR("invalid area %p (id %u)", area, area->fa_id);
142 return;
143 }
144 if (entry->ref_count == 0) {
145 BOOT_LOG_ERR("area %u use count underflow", area->fa_id);
146 return;
147 }
148 entry->ref_count--;
149}
150
Tamas Ban581034a2017-12-19 19:54:37 +0000151void flash_area_warn_on_open(void)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000152{
153 int i;
Tamas Ban581034a2017-12-19 19:54:37 +0000154 struct flash_map_entry *entry;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000155
156 for (i = 0; i < ARRAY_SIZE(part_map); i++) {
Tamas Ban581034a2017-12-19 19:54:37 +0000157 entry = &part_map[i];
Tamas Banf70ef8c2017-12-19 15:35:09 +0000158 if (entry->ref_count) {
159 BOOT_LOG_WRN("area %u has %u users",
160 entry->area.fa_id, entry->ref_count);
161 }
162 }
163}
164
David Vincze39e78552018-10-10 17:10:01 +0200165uint8_t flash_area_erased_val(const struct flash_area *area)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000166{
David Vincze39e78552018-10-10 17:10:01 +0200167 (void)area;
168
169 return FLASH_DEV_NAME.GetInfo()->erased_value;
170}
171
172int flash_area_read(const struct flash_area *area, uint32_t off, void *dst,
173 uint32_t len)
174{
175 BOOT_LOG_DBG("read area=%d, off=%#x, len=%#x", area->fa_id, off, len);
Tamas Banc3828852018-02-01 12:24:16 +0000176 return FLASH_DEV_NAME.ReadData(area->fa_off + off, dst, len);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000177}
178
David Vincze39e78552018-10-10 17:10:01 +0200179int flash_area_read_is_empty(const struct flash_area *area, uint32_t off,
180 void *dst, uint32_t len)
181{
182 uint32_t i;
183 uint8_t *u8dst;
184 int rc;
185
186 BOOT_LOG_DBG("read_is_empty area=%d, off=%#x, len=%#x",
187 area->fa_id, off, len);
188
189 rc = FLASH_DEV_NAME.ReadData(area->fa_off + off, dst, len);
190 if(rc != 0) {
191 return -1;
192 }
193
194 u8dst = (uint8_t*)dst;
195
196 for (i = 0; i < len; i++) {
197 if (u8dst[i] != flash_area_erased_val(area)) {
198 return 0;
199 }
200 }
201
202 return 1;
203}
204
Tamas Ban581034a2017-12-19 19:54:37 +0000205int flash_area_write(const struct flash_area *area, uint32_t off,
206 const void *src, uint32_t len)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000207{
Tamas Banc3828852018-02-01 12:24:16 +0000208 BOOT_LOG_DBG("write area=%d, off=%#x, len=%#x", area->fa_id, off, len);
209 return FLASH_DEV_NAME.ProgramData(area->fa_off + off, src, len);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000210}
211
212int flash_area_erase(const struct flash_area *area, uint32_t off, uint32_t len)
213{
Tamas Banc3828852018-02-01 12:24:16 +0000214 ARM_FLASH_INFO *flash_info;
215 uint32_t deleted_len = 0;
216 int32_t rc = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000217
Tamas Banc3828852018-02-01 12:24:16 +0000218 BOOT_LOG_DBG("erase area=%d, off=%#x, len=%#x", area->fa_id, off, len);
219 flash_info = FLASH_DEV_NAME.GetInfo();
220
221 if (flash_info->sector_info == NULL) {
222 /* Uniform sector layout */
223 while (deleted_len < len) {
224 rc = FLASH_DEV_NAME.EraseSector(area->fa_off + off);
225 if (rc != 0) {
226 break;
227 }
228 deleted_len += flash_info->sector_size;
229 off += flash_info->sector_size;
230 }
231 } else {
232 /* Inhomogeneous sector layout, explicitly defined
233 * Currently not supported.
234 */
235 }
236
Tamas Banf70ef8c2017-12-19 15:35:09 +0000237 return rc;
238}
239
240uint8_t flash_area_align(const struct flash_area *area)
241{
Tamas Banc3828852018-02-01 12:24:16 +0000242 ARM_FLASH_INFO *flash_info;
243
244 flash_info = FLASH_DEV_NAME.GetInfo();
245 return flash_info->program_unit;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000246}
247
248/*
David Vincze8bdfc2d2019-03-18 15:49:23 +0100249 * This depends on the mappings defined in sysflash.h, and assumes that the
250 * primary slot, the secondary slot, and the scratch area are contiguous.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000251 */
252int flash_area_id_from_image_slot(int slot)
253{
David Vincze401c7422019-06-21 20:44:05 +0200254 static const int area_id_tab[] = {FLASH_AREA_IMAGE_PRIMARY,
255 FLASH_AREA_IMAGE_SECONDARY,
256 FLASH_AREA_IMAGE_SCRATCH};
257
258 if (slot >= 0 && slot < ARRAY_SIZE(area_id_tab)) {
259 return area_id_tab[slot];
260 }
261
262 return -EINVAL; /* flash_area_open will fail on that */
263}
264
265int flash_area_id_to_image_slot(int area_id)
266{
267 switch (area_id) {
268 case FLASH_AREA_IMAGE_PRIMARY:
269 return 0;
270 case FLASH_AREA_IMAGE_SECONDARY:
271 return 1;
272 default:
273 BOOT_LOG_ERR("invalid flash area ID");
274 return -1;
275 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000276}
277
Tamas Ban581034a2017-12-19 19:54:37 +0000278static int validate_idx(int idx, uint32_t *off, uint32_t *len)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000279{
280 /*
281 * This simple layout has uniform slots, so just fill in the
282 * right one.
283 */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000284
285 switch (idx) {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100286 case FLASH_AREA_IMAGE_PRIMARY:
287 *off = FLASH_AREA_IMAGE_PRIMARY_OFFSET;
288 *len = FLASH_AREA_IMAGE_PRIMARY_SIZE;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000289 break;
David Vincze8bdfc2d2019-03-18 15:49:23 +0100290 case FLASH_AREA_IMAGE_SECONDARY:
291 *off = FLASH_AREA_IMAGE_SECONDARY_OFFSET;
292 *len = FLASH_AREA_IMAGE_SECONDARY_SIZE;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000293 break;
294 case FLASH_AREA_IMAGE_SCRATCH:
295 *off = FLASH_AREA_IMAGE_SCRATCH_OFFSET;
296 *len = FLASH_AREA_IMAGE_SCRATCH_SIZE;
297 break;
298 default:
299 BOOT_LOG_ERR("unknown flash area %d", idx);
300 return -1;
301 }
302
Tamas Ban581034a2017-12-19 19:54:37 +0000303 BOOT_LOG_DBG("area %d: offset=0x%x, length=0x%x, sector size=0x%x",
304 idx, *off, *len, FLASH_AREA_IMAGE_SECTOR_SIZE);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000305 return 0;
306}
307
Tamas Banf70ef8c2017-12-19 15:35:09 +0000308int flash_area_to_sectors(int idx, int *cnt, struct flash_area *ret)
309{
Tamas Ban581034a2017-12-19 19:54:37 +0000310 uint32_t off;
311 uint32_t len;
312 uint32_t max_cnt = *cnt;
313 uint32_t rem_len;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000314
Tamas Ban581034a2017-12-19 19:54:37 +0000315 if (validate_idx(idx, &off, &len)) {
316 return -1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000317 }
318
Tamas Ban581034a2017-12-19 19:54:37 +0000319 if (*cnt < 1) {
320 return -1;
321 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000322
Tamas Ban581034a2017-12-19 19:54:37 +0000323 rem_len = len;
324 *cnt = 0;
325 while (rem_len > 0 && *cnt < max_cnt) {
326 if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
327 BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
328 idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
329 return -1;
330 }
331
332 ret[*cnt].fa_id = idx;
333 ret[*cnt].fa_device_id = 0;
334 ret[*cnt].pad16 = 0;
335 ret[*cnt].fa_off = off + (FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt));
336 ret[*cnt].fa_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
337 *cnt = *cnt + 1;
338 rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
339 }
340
Tamas Banc3828852018-02-01 12:24:16 +0000341 if (*cnt > max_cnt) {
Tamas Ban581034a2017-12-19 19:54:37 +0000342 BOOT_LOG_ERR("flash area %d sector count overflow", idx);
343 return -1;
344 }
345
346 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000347}
348
Tamas Ban581034a2017-12-19 19:54:37 +0000349/*
350 * Lookup the sector map for a given flash area. This should fill in
351 * `ret` with all of the sectors in the area. `*cnt` will be set to
352 * the storage at `ret` and should be set to the final number of
353 * sectors in this area.
354 */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000355int flash_area_get_sectors(int idx, uint32_t *cnt, struct flash_sector *ret)
356{
Tamas Ban581034a2017-12-19 19:54:37 +0000357 uint32_t off;
358 uint32_t len;
359 uint32_t max_cnt = *cnt;
360 uint32_t rem_len;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000361
Tamas Ban581034a2017-12-19 19:54:37 +0000362 if (validate_idx(idx, &off, &len)) {
363 return -1;
364 }
365
366 if (*cnt < 1) {
367 return -1;
368 }
369
370 rem_len = len;
371 *cnt = 0;
372 while (rem_len > 0 && *cnt < max_cnt) {
373 if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
374 BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
375 idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
376 return -1;
377 }
378
379 ret[*cnt].fs_off = FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt);
380 ret[*cnt].fs_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
381 *cnt = *cnt + 1;
382 rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
383 }
384
Tamas Banc3828852018-02-01 12:24:16 +0000385 if (*cnt > max_cnt) {
Tamas Ban581034a2017-12-19 19:54:37 +0000386 BOOT_LOG_ERR("flash area %d sector count overflow", idx);
387 return -1;
388 }
389
390 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000391}