blob: a28817aac651c8574b5080c8d1749e1e8a9bfc51 [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
30#define FLASH_DEVICE_INTERNAL_FLASH 0
31#define FLASH_AREAS 3
32
33/** Application defined secondary block device */
34mbed::BlockDevice* mcuboot_secondary_bd = get_secondary_bd();
35
36/** Internal application block device */
37static FlashIAPBlockDevice mcuboot_primary_bd(MCUBOOT_PRIMARY_SLOT_START_ADDR, MCUBOOT_SLOT_SIZE);
38
39#ifndef MCUBOOT_OVERWRITE_ONLY
40/** Scratch space is at the end of internal flash, after the main application */
41static FlashIAPBlockDevice mcuboot_scratch_bd(MCUBOOT_SCRATCH_START_ADDR, MCUBOOT_SCRATCH_SIZE);
42#endif
43
44static mbed::BlockDevice* flash_map_bd[FLASH_AREAS] = {
45 (mbed::BlockDevice*) &mcuboot_primary_bd, /** Primary (loadable) image area */
46 mcuboot_secondary_bd, /** Secondary (update candidate) image area */
47#ifndef MCUBOOT_OVERWRITE_ONLY
48 (mbed::BlockDevice*) &mcuboot_scratch_bd /** Scratch space for swapping images */
49#else
50 nullptr
51#endif
52};
53
54static struct flash_area flash_areas[FLASH_AREAS];
55
56int flash_area_open(uint8_t id, const struct flash_area** fapp) {
57
58 *fapp = &flash_areas[id];
59 struct flash_area* fap = (struct flash_area*)*fapp;
60
61 // The offset of the slot is from the beginning of the flash device.
62 switch (id) {
63 case PRIMARY_ID:
64 fap->fa_off = MCUBOOT_PRIMARY_SLOT_START_ADDR;
65 break;
66 case SECONDARY_ID:
67 // The offset of the secondary slot is not currently used.
68 fap->fa_off = 0;
69 break;
70#ifndef MCUBOOT_OVERWRITE_ONLY
71 case SCRATCH_ID:
72 fap->fa_off = MCUBOOT_SCRATCH_START_ADDR;
73 break;
74#endif
75 default:
76 MCUBOOT_LOG_ERR("flash_area_open, unknown id %d", id);
77 return -1;
78 }
79
80 fap->fa_id = id;
81 fap->fa_device_id = 0; // not relevant
82
83 mbed::BlockDevice* bd = flash_map_bd[id];
84 fap->fa_size = (uint32_t) bd->size();
85 return bd->init();
86}
87
88void flash_area_close(const struct flash_area* fap) {
89 mbed::BlockDevice* bd = flash_map_bd[fap->fa_id];
90 bd->deinit();
91}
92
93/*
94 * Read/write/erase. Offset is relative from beginning of flash area.
95 */
96int flash_area_read(const struct flash_area* fap, uint32_t off, void* dst, uint32_t len) {
97 mbed::BlockDevice* bd = flash_map_bd[fap->fa_id];
98
99 // Note: The address must be aligned to bd->get_read_size(). If MCUBOOT_READ_GRANULARITY
100 // is defined, the length does not need to be aligned.
101#ifdef MCUBOOT_READ_GRANULARITY
102 uint32_t read_size = bd->get_read_size();
103 if (read_size == 0) {
104 MCUBOOT_LOG_ERR("Invalid read size: must be non-zero");
105 return -1;
106 }
107 if (MCUBOOT_READ_GRANULARITY < read_size) {
108 MCUBOOT_LOG_ERR("Please increase MCUBOOT_READ_GRANULARITY (currently %u) to be at least %u",
109 MCUBOOT_READ_GRANULARITY, read_size);
110 return -1;
111 }
112
113 uint32_t remainder = len % read_size;
114 len -= remainder;
115 if (len != 0) {
116#endif
117 if (!bd->is_valid_read(off, len)) {
118 MCUBOOT_LOG_ERR("Invalid read: fa_id %d offset 0x%x len 0x%x", fap->fa_id, off, len);
119 return -1;
120 }
121 else {
122 int ret = bd->read(dst, off, len);
123 if (ret != 0) {
124 MCUBOOT_LOG_ERR("Read failed: fa_id %d offset 0x%x len 0x%x", fap->fa_id, off, len);
125 return ret;
126 }
127 }
128#ifdef MCUBOOT_READ_GRANULARITY
129 }
130
131 if (remainder) {
132 if (!bd->is_valid_read(off + len, read_size)) {
133 MCUBOOT_LOG_ERR("Invalid read: fa_id %d offset 0x%x len 0x%x", fap->fa_id, off + len, read_size);
134 return -1;
135 }
136 else {
137 uint8_t buffer[MCUBOOT_READ_GRANULARITY];
138 int ret = bd->read(buffer, off + len, read_size);
139 if (ret != 0) {
140 MCUBOOT_LOG_ERR("Read failed: %d", ret);
141 return ret;
142 }
143 memcpy((uint8_t *)dst + len, buffer, remainder);
144 }
145 }
146#endif
147
148 return 0;
149}
150
151int flash_area_write(const struct flash_area* fap, uint32_t off, const void* src, uint32_t len) {
152 mbed::BlockDevice* bd = flash_map_bd[fap->fa_id];
153 return bd->program(src, off, len);
154}
155
156int flash_area_erase(const struct flash_area* fap, uint32_t off, uint32_t len) {
157 mbed::BlockDevice* bd = flash_map_bd[fap->fa_id];
158 return bd->erase(off, len);
159}
160
161uint8_t flash_area_align(const struct flash_area* fap) {
162 mbed::BlockDevice* bd = flash_map_bd[fap->fa_id];
163 return bd->get_program_size();
164}
165
166uint8_t flash_area_erased_val(const struct flash_area* fap) {
167 mbed::BlockDevice* bd = flash_map_bd[fap->fa_id];
168 return bd->get_erase_value();
169}
170
171int flash_area_get_sectors(int fa_id, uint32_t* count, struct flash_sector* sectors) {
172 mbed::BlockDevice* bd = flash_map_bd[fa_id];
173
174 // Loop through sectors and collect information on them
175 bd_addr_t offset = 0;
176 *count = 0;
177 while (*count < MCUBOOT_MAX_IMG_SECTORS && bd->is_valid_read(offset, bd->get_read_size())) {
178
179 sectors[*count].fs_off = offset;
180 bd_size_t erase_size = bd->get_erase_size(offset);
181 sectors[*count].fs_size = erase_size;
182
183 offset += erase_size;
184 *count += 1;
185 }
186
187 return 0;
188}
189
190int flash_area_id_from_image_slot(int slot) {
191 return slot;
192}
193
194int flash_area_id_to_image_slot(int area_id) {
195 return area_id;
196}
197
198/**
199 * Multi images support not implemented yet
200 */
201int flash_area_id_from_multi_image_slot(int image_index, int slot)
202{
203 assert(image_index == 0);
204 return slot;
205}
206
207int flash_area_id_to_multi_image_slot(int image_index, int area_id)
208{
209 assert(image_index == 0);
210 return area_id;
211}