blob: 0fb8b1a86151eb78655853a9938f57fff8293651 [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
Tamas Ban581034a2017-12-19 19:54:37 +000020#include <errno.h>
21#include <stdbool.h>
Tamas Banf70ef8c2017-12-19 15:35:09 +000022
23#include "target.h"
Tamas Ban581034a2017-12-19 19:54:37 +000024#include <flash.h>
Tamas Banf70ef8c2017-12-19 15:35:09 +000025
26#include <flash_map/flash_map.h>
27#include <hal/hal_flash.h>
Tamas Banf70ef8c2017-12-19 15:35:09 +000028
29#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO
30#include "bootutil/bootutil_log.h"
31
32extern struct device *boot_flash_device;
33
34/*
35 * For now, we only support one flash device.
36 *
37 * Pick a random device ID for it that's unlikely to collide with
38 * anything "real".
39 */
40#define FLASH_DEVICE_ID 100
Tamas Ban581034a2017-12-19 19:54:37 +000041#define FLASH_DEVICE_BASE FLASH_BASE_ADDRESS
Tamas Banf70ef8c2017-12-19 15:35:09 +000042
43#define FLASH_MAP_ENTRY_MAGIC 0xd00dbeef
44
45struct flash_map_entry {
46 const uint32_t magic;
47 const struct flash_area area;
48 unsigned int ref_count;
49};
50
51/*
52 * The flash area describes essentially the partition table of the
53 * flash. In this case, it starts with FLASH_AREA_IMAGE_0.
54 */
55static struct flash_map_entry part_map[] = {
56 {
57 .magic = FLASH_MAP_ENTRY_MAGIC,
58 .area = {
59 .fa_id = FLASH_AREA_IMAGE_0,
60 .fa_device_id = FLASH_DEVICE_ID,
61 .fa_off = FLASH_AREA_IMAGE_0_OFFSET,
62 .fa_size = FLASH_AREA_IMAGE_0_SIZE,
63 },
64 },
65 {
66 .magic = FLASH_MAP_ENTRY_MAGIC,
67 .area = {
68 .fa_id = FLASH_AREA_IMAGE_1,
69 .fa_device_id = FLASH_DEVICE_ID,
70 .fa_off = FLASH_AREA_IMAGE_1_OFFSET,
71 .fa_size = FLASH_AREA_IMAGE_1_SIZE,
72 },
73 },
74 {
75 .magic = FLASH_MAP_ENTRY_MAGIC,
76 .area = {
77 .fa_id = FLASH_AREA_IMAGE_SCRATCH,
78 .fa_device_id = FLASH_DEVICE_ID,
79 .fa_off = FLASH_AREA_IMAGE_SCRATCH_OFFSET,
80 .fa_size = FLASH_AREA_IMAGE_SCRATCH_SIZE,
81 },
82 }
83};
84
85int flash_device_base(uint8_t fd_id, uintptr_t *ret)
86{
87 if (fd_id != FLASH_DEVICE_ID) {
88 BOOT_LOG_ERR("invalid flash ID %d; expected %d",
89 fd_id, FLASH_DEVICE_ID);
90 return -EINVAL;
91 }
92 *ret = FLASH_DEVICE_BASE;
93 return 0;
94}
95
96/*
97 * `open` a flash area. The `area` in this case is not the individual
98 * sectors, but describes the particular flash area in question.
99 */
100int flash_area_open(uint8_t id, const struct flash_area **area)
101{
102 int i;
103
104 BOOT_LOG_DBG("area %d", id);
105
106 for (i = 0; i < ARRAY_SIZE(part_map); i++) {
107 if (id == part_map[i].area.fa_id) {
108 break;
109 }
110 }
111 if (i == ARRAY_SIZE(part_map)) {
112 return -1;
113 }
114
115 *area = &part_map[i].area;
116 part_map[i].ref_count++;
117 return 0;
118}
119
120/*
121 * Nothing to do on close.
122 */
123void flash_area_close(const struct flash_area *area)
124{
125 struct flash_map_entry *entry;
126
127 if (!area) {
128 return;
129 }
130
131 entry = CONTAINER_OF(area, struct flash_map_entry, area);
132 if (entry->magic != FLASH_MAP_ENTRY_MAGIC) {
133 BOOT_LOG_ERR("invalid area %p (id %u)", area, area->fa_id);
134 return;
135 }
136 if (entry->ref_count == 0) {
137 BOOT_LOG_ERR("area %u use count underflow", area->fa_id);
138 return;
139 }
140 entry->ref_count--;
141}
142
Tamas Ban581034a2017-12-19 19:54:37 +0000143void flash_area_warn_on_open(void)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000144{
145 int i;
Tamas Ban581034a2017-12-19 19:54:37 +0000146 struct flash_map_entry *entry;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000147
148 for (i = 0; i < ARRAY_SIZE(part_map); i++) {
Tamas Ban581034a2017-12-19 19:54:37 +0000149 entry = &part_map[i];
Tamas Banf70ef8c2017-12-19 15:35:09 +0000150 if (entry->ref_count) {
151 BOOT_LOG_WRN("area %u has %u users",
152 entry->area.fa_id, entry->ref_count);
153 }
154 }
155}
156
157int flash_area_read(const struct flash_area *area, uint32_t off, void *dst,
158 uint32_t len)
159{
160 BOOT_LOG_DBG("area=%d, off=%x, len=%x", area->fa_id, off, len);
161 return flash_read(boot_flash_device, area->fa_off + off, dst, len);
162}
163
Tamas Ban581034a2017-12-19 19:54:37 +0000164int flash_area_write(const struct flash_area *area, uint32_t off,
165 const void *src, uint32_t len)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000166{
167 int rc = 0;
168
169 BOOT_LOG_DBG("area=%d, off=%x, len=%x", area->fa_id, off, len);
170 flash_write_protection_set(boot_flash_device, false);
171 rc = flash_write(boot_flash_device, area->fa_off + off, src, len);
172 flash_write_protection_set(boot_flash_device, true);
173 return rc;
174}
175
176int flash_area_erase(const struct flash_area *area, uint32_t off, uint32_t len)
177{
178 int rc;
179
180 BOOT_LOG_DBG("area=%d, off=%x, len=%x", area->fa_id, off, len);
181 flash_write_protection_set(boot_flash_device, false);
182 rc = flash_erase(boot_flash_device, area->fa_off + off, len);
183 flash_write_protection_set(boot_flash_device, true);
184 return rc;
185}
186
187uint8_t flash_area_align(const struct flash_area *area)
188{
189 return hal_flash_align(area->fa_id);
190}
191
192/*
193 * This depends on the mappings defined in sysflash.h, and assumes
194 * that slot 0, slot 1, and the scratch area area contiguous.
195 */
196int flash_area_id_from_image_slot(int slot)
197{
198 return slot + FLASH_AREA_IMAGE_0;
199}
200
Tamas Ban581034a2017-12-19 19:54:37 +0000201static int validate_idx(int idx, uint32_t *off, uint32_t *len)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000202{
203 /*
204 * This simple layout has uniform slots, so just fill in the
205 * right one.
206 */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000207
208 switch (idx) {
209 case FLASH_AREA_IMAGE_0:
210 *off = FLASH_AREA_IMAGE_0_OFFSET;
211 *len = FLASH_AREA_IMAGE_0_SIZE;
212 break;
213 case FLASH_AREA_IMAGE_1:
214 *off = FLASH_AREA_IMAGE_1_OFFSET;
215 *len = FLASH_AREA_IMAGE_1_SIZE;
216 break;
217 case FLASH_AREA_IMAGE_SCRATCH:
218 *off = FLASH_AREA_IMAGE_SCRATCH_OFFSET;
219 *len = FLASH_AREA_IMAGE_SCRATCH_SIZE;
220 break;
221 default:
222 BOOT_LOG_ERR("unknown flash area %d", idx);
223 return -1;
224 }
225
Tamas Ban581034a2017-12-19 19:54:37 +0000226 BOOT_LOG_DBG("area %d: offset=0x%x, length=0x%x, sector size=0x%x",
227 idx, *off, *len, FLASH_AREA_IMAGE_SECTOR_SIZE);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000228 return 0;
229}
230
Tamas Banf70ef8c2017-12-19 15:35:09 +0000231int flash_area_to_sectors(int idx, int *cnt, struct flash_area *ret)
232{
Tamas Ban581034a2017-12-19 19:54:37 +0000233 uint32_t off;
234 uint32_t len;
235 uint32_t max_cnt = *cnt;
236 uint32_t rem_len;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000237
Tamas Ban581034a2017-12-19 19:54:37 +0000238 if (validate_idx(idx, &off, &len)) {
239 return -1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000240 }
241
Tamas Ban581034a2017-12-19 19:54:37 +0000242 if (*cnt < 1) {
243 return -1;
244 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000245
Tamas Ban581034a2017-12-19 19:54:37 +0000246 rem_len = len;
247 *cnt = 0;
248 while (rem_len > 0 && *cnt < max_cnt) {
249 if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
250 BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
251 idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
252 return -1;
253 }
254
255 ret[*cnt].fa_id = idx;
256 ret[*cnt].fa_device_id = 0;
257 ret[*cnt].pad16 = 0;
258 ret[*cnt].fa_off = off + (FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt));
259 ret[*cnt].fa_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
260 *cnt = *cnt + 1;
261 rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
262 }
263
264 if (*cnt >= max_cnt) {
265 BOOT_LOG_ERR("flash area %d sector count overflow", idx);
266 return -1;
267 }
268
269 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000270}
271
Tamas Ban581034a2017-12-19 19:54:37 +0000272/*
273 * Lookup the sector map for a given flash area. This should fill in
274 * `ret` with all of the sectors in the area. `*cnt` will be set to
275 * the storage at `ret` and should be set to the final number of
276 * sectors in this area.
277 */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000278int flash_area_get_sectors(int idx, uint32_t *cnt, struct flash_sector *ret)
279{
Tamas Ban581034a2017-12-19 19:54:37 +0000280 uint32_t off;
281 uint32_t len;
282 uint32_t max_cnt = *cnt;
283 uint32_t rem_len;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000284
Tamas Ban581034a2017-12-19 19:54:37 +0000285 if (validate_idx(idx, &off, &len)) {
286 return -1;
287 }
288
289 if (*cnt < 1) {
290 return -1;
291 }
292
293 rem_len = len;
294 *cnt = 0;
295 while (rem_len > 0 && *cnt < max_cnt) {
296 if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
297 BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
298 idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
299 return -1;
300 }
301
302 ret[*cnt].fs_off = FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt);
303 ret[*cnt].fs_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
304 *cnt = *cnt + 1;
305 rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
306 }
307
308 if (*cnt >= max_cnt) {
309 BOOT_LOG_ERR("flash area %d sector count overflow", idx);
310 return -1;
311 }
312
313 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000314}