blob: 955ac42b661048b9e868afc9b227809bc9015772 [file] [log] [blame]
George Becksteind82afbf2020-10-29 17:32:11 -04001/*
2 * Copyright (c) 2020 Embedded Planet
3 * Copyright (c) 2020 ARM Limited
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * 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, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
17 */
18
19#include <assert.h>
20#include <cstring>
21#include "flash_map_backend/flash_map_backend.h"
22#include "flash_map_backend/secondary_bd.h"
23#include "sysflash/sysflash.h"
24
25#include "blockdevice/BlockDevice.h"
26#include "FlashIAP/FlashIAPBlockDevice.h"
27
28#include "mcuboot_config/mcuboot_logging.h"
29
George Beckstein28779652020-12-15 13:54:51 -050030#include "bootutil_priv.h"
31
George Becksteind82afbf2020-10-29 17:32:11 -040032#define FLASH_DEVICE_INTERNAL_FLASH 0
33#define FLASH_AREAS 3
34
35/** Application defined secondary block device */
36mbed::BlockDevice* mcuboot_secondary_bd = get_secondary_bd();
37
38/** Internal application block device */
39static FlashIAPBlockDevice mcuboot_primary_bd(MCUBOOT_PRIMARY_SLOT_START_ADDR, MCUBOOT_SLOT_SIZE);
40
George Beckstein28779652020-12-15 13:54:51 -050041#if MCUBOOT_SWAP_USING_SCRATCH
George Becksteind82afbf2020-10-29 17:32:11 -040042/** Scratch space is at the end of internal flash, after the main application */
43static FlashIAPBlockDevice mcuboot_scratch_bd(MCUBOOT_SCRATCH_START_ADDR, MCUBOOT_SCRATCH_SIZE);
44#endif
45
46static mbed::BlockDevice* flash_map_bd[FLASH_AREAS] = {
47 (mbed::BlockDevice*) &mcuboot_primary_bd, /** Primary (loadable) image area */
48 mcuboot_secondary_bd, /** Secondary (update candidate) image area */
George Beckstein28779652020-12-15 13:54:51 -050049#if MCUBOOT_SWAP_USING_SCRATCH
George Becksteind82afbf2020-10-29 17:32:11 -040050 (mbed::BlockDevice*) &mcuboot_scratch_bd /** Scratch space for swapping images */
51#else
52 nullptr
53#endif
54};
55
56static struct flash_area flash_areas[FLASH_AREAS];
57
George Becksteind1233e12020-12-02 01:57:30 -050058static unsigned int open_count[FLASH_AREAS] = {0};
59
George Becksteind82afbf2020-10-29 17:32:11 -040060int flash_area_open(uint8_t id, const struct flash_area** fapp) {
61
62 *fapp = &flash_areas[id];
63 struct flash_area* fap = (struct flash_area*)*fapp;
64
65 // The offset of the slot is from the beginning of the flash device.
66 switch (id) {
67 case PRIMARY_ID:
68 fap->fa_off = MCUBOOT_PRIMARY_SLOT_START_ADDR;
69 break;
70 case SECONDARY_ID:
George Beckstein28779652020-12-15 13:54:51 -050071#if MCUBOOT_DIRECT_XIP
72 fap->fa_off = MBED_CONF_MCUBOOT_XIP_SECONDARY_SLOT_ADDRESS;
73#else
George Becksteind82afbf2020-10-29 17:32:11 -040074 fap->fa_off = 0;
George Beckstein28779652020-12-15 13:54:51 -050075#endif
George Becksteind82afbf2020-10-29 17:32:11 -040076 break;
George Beckstein28779652020-12-15 13:54:51 -050077#if MCUBOOT_SWAP_USING_SCRATCH
George Becksteind82afbf2020-10-29 17:32:11 -040078 case SCRATCH_ID:
79 fap->fa_off = MCUBOOT_SCRATCH_START_ADDR;
80 break;
81#endif
82 default:
83 MCUBOOT_LOG_ERR("flash_area_open, unknown id %d", id);
84 return -1;
85 }
86
George Becksteind1233e12020-12-02 01:57:30 -050087 open_count[id]++;
88 MCUBOOT_LOG_DBG("flash area %d open count: %d (+)", id, open_count[id]);
89
George Becksteind82afbf2020-10-29 17:32:11 -040090 fap->fa_id = id;
91 fap->fa_device_id = 0; // not relevant
92
93 mbed::BlockDevice* bd = flash_map_bd[id];
George Becksteind1233e12020-12-02 01:57:30 -050094
95 /* Only initialize if this isn't a nested call to open the flash area */
96 if (open_count[id] == 1) {
97 MCUBOOT_LOG_DBG("initializing flash area %d...", id);
Artur Tyneckia3cf3f82022-02-08 12:04:52 +010098 int ret = bd->init();
99 if (ret)
100 {
101 MCUBOOT_LOG_ERR("initializing flash area failed %d", ret);
102 return ret;
103 }
George Becksteind1233e12020-12-02 01:57:30 -0500104 } else {
105 return 0;
106 }
Artur Tyneckia3cf3f82022-02-08 12:04:52 +0100107
108 fap->fa_size = (uint32_t) bd->size();
109 return 0;
George Becksteind82afbf2020-10-29 17:32:11 -0400110}
111
112void flash_area_close(const struct flash_area* fap) {
George Becksteind1233e12020-12-02 01:57:30 -0500113 uint8_t id = fap->fa_id;
114 /* No need to close an unopened flash area, avoid an overflow of the counter */
115 if (!open_count[id]) {
116 return;
117 }
118
119 open_count[id]--;
120 MCUBOOT_LOG_DBG("flash area %d open count: %d (-)", id, open_count[id]);
121 if (!open_count[id]) {
122 /* mcuboot is not currently consistent in opening/closing flash areas only once at a time
123 * so only deinitialize the BlockDevice if all callers have closed the flash area. */
124 MCUBOOT_LOG_DBG("deinitializing flash area block device %d...", id);
125 mbed::BlockDevice* bd = flash_map_bd[id];
126 bd->deinit();
127 }
George Becksteind82afbf2020-10-29 17:32:11 -0400128}
129
130/*
131 * Read/write/erase. Offset is relative from beginning of flash area.
132 */
133int flash_area_read(const struct flash_area* fap, uint32_t off, void* dst, uint32_t len) {
134 mbed::BlockDevice* bd = flash_map_bd[fap->fa_id];
135
George Becksteind1233e12020-12-02 01:57:30 -0500136 /* Note: The address must be aligned to bd->get_read_size(). If MCUBOOT_READ_GRANULARITY
137 is defined, the length does not need to be aligned. */
George Becksteind82afbf2020-10-29 17:32:11 -0400138#ifdef MCUBOOT_READ_GRANULARITY
139 uint32_t read_size = bd->get_read_size();
140 if (read_size == 0) {
141 MCUBOOT_LOG_ERR("Invalid read size: must be non-zero");
142 return -1;
143 }
144 if (MCUBOOT_READ_GRANULARITY < read_size) {
145 MCUBOOT_LOG_ERR("Please increase MCUBOOT_READ_GRANULARITY (currently %u) to be at least %u",
146 MCUBOOT_READ_GRANULARITY, read_size);
147 return -1;
148 }
149
150 uint32_t remainder = len % read_size;
151 len -= remainder;
152 if (len != 0) {
153#endif
154 if (!bd->is_valid_read(off, len)) {
George Beckstein28779652020-12-15 13:54:51 -0500155 MCUBOOT_LOG_ERR("Invalid read: fa_id %d offset 0x%x len 0x%x", fap->fa_id,
156 (unsigned int) off, (unsigned int) len);
George Becksteind82afbf2020-10-29 17:32:11 -0400157 return -1;
158 }
159 else {
160 int ret = bd->read(dst, off, len);
161 if (ret != 0) {
George Beckstein28779652020-12-15 13:54:51 -0500162 MCUBOOT_LOG_ERR("Read failed: fa_id %d offset 0x%x len 0x%x", fap->fa_id,
163 (unsigned int) off, (unsigned int) len);
George Becksteind82afbf2020-10-29 17:32:11 -0400164 return ret;
165 }
166 }
167#ifdef MCUBOOT_READ_GRANULARITY
168 }
169
170 if (remainder) {
171 if (!bd->is_valid_read(off + len, read_size)) {
George Beckstein28779652020-12-15 13:54:51 -0500172 MCUBOOT_LOG_ERR("Invalid read: fa_id %d offset 0x%x len 0x%x", fap->fa_id,
173 (unsigned int) (off + len), (unsigned int) read_size);
George Becksteind82afbf2020-10-29 17:32:11 -0400174 return -1;
175 }
176 else {
177 uint8_t buffer[MCUBOOT_READ_GRANULARITY];
178 int ret = bd->read(buffer, off + len, read_size);
179 if (ret != 0) {
180 MCUBOOT_LOG_ERR("Read failed: %d", ret);
181 return ret;
182 }
183 memcpy((uint8_t *)dst + len, buffer, remainder);
184 }
185 }
186#endif
187
188 return 0;
189}
190
191int flash_area_write(const struct flash_area* fap, uint32_t off, const void* src, uint32_t len) {
192 mbed::BlockDevice* bd = flash_map_bd[fap->fa_id];
193 return bd->program(src, off, len);
194}
195
196int flash_area_erase(const struct flash_area* fap, uint32_t off, uint32_t len) {
197 mbed::BlockDevice* bd = flash_map_bd[fap->fa_id];
198 return bd->erase(off, len);
199}
200
Gustavo Henrique Nihei4aa286d2021-11-24 14:54:56 -0300201uint32_t flash_area_align(const struct flash_area* fap) {
George Becksteind82afbf2020-10-29 17:32:11 -0400202 mbed::BlockDevice* bd = flash_map_bd[fap->fa_id];
203 return bd->get_program_size();
204}
205
206uint8_t flash_area_erased_val(const struct flash_area* fap) {
207 mbed::BlockDevice* bd = flash_map_bd[fap->fa_id];
208 return bd->get_erase_value();
209}
210
211int flash_area_get_sectors(int fa_id, uint32_t* count, struct flash_sector* sectors) {
212 mbed::BlockDevice* bd = flash_map_bd[fa_id];
213
George Becksteind1233e12020-12-02 01:57:30 -0500214 /* Loop through sectors and collect information on them */
George Becksteind82afbf2020-10-29 17:32:11 -0400215 bd_addr_t offset = 0;
216 *count = 0;
217 while (*count < MCUBOOT_MAX_IMG_SECTORS && bd->is_valid_read(offset, bd->get_read_size())) {
218
219 sectors[*count].fs_off = offset;
220 bd_size_t erase_size = bd->get_erase_size(offset);
221 sectors[*count].fs_size = erase_size;
222
223 offset += erase_size;
224 *count += 1;
225 }
226
227 return 0;
228}
229
230int flash_area_id_from_image_slot(int slot) {
231 return slot;
232}
233
George Becksteind82afbf2020-10-29 17:32:11 -0400234/**
235 * Multi images support not implemented yet
236 */
237int flash_area_id_from_multi_image_slot(int image_index, int slot)
238{
239 assert(image_index == 0);
240 return slot;
241}
242
243int flash_area_id_to_multi_image_slot(int image_index, int area_id)
244{
245 assert(image_index == 0);
246 return area_id;
247}