1 /*
2 * Copyright (c) 2017 Nordic Semiconductor ASA
3 * Copyright (c) 2016-2017 Linaro Limited
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <stddef.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <zephyr/drivers/flash.h>
12 #include <zephyr/storage/flash_map.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/init.h>
15 #include <zephyr/logging/log.h>
16
17 #include <zephyr/sys/__assert.h>
18 #include <zephyr/sys/byteorder.h>
19
20 #include "bootutil/bootutil_public.h"
21 #include <zephyr/dfu/mcuboot.h>
22
23 #if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) || \
24 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT)
25 /* For RAM LOAD mode, the active image must be fetched from the bootloader */
26 #include <bootutil/boot_status.h>
27 #include <zephyr/retention/blinfo.h>
28
29 #define SLOT0_PARTITION slot0_partition
30 #define SLOT1_PARTITION slot1_partition
31 #define SLOT2_PARTITION slot2_partition
32 #define SLOT3_PARTITION slot3_partition
33 #define SLOT4_PARTITION slot4_partition
34 #define SLOT5_PARTITION slot5_partition
35 #endif
36
37 #include "mcuboot_priv.h"
38
39 LOG_MODULE_REGISTER(mcuboot_dfu, LOG_LEVEL_DBG);
40
41 /*
42 * Helpers for image headers and trailers, as defined by mcuboot.
43 */
44
45 /*
46 * Strict defines: the definitions in the following block contain
47 * values which are MCUboot implementation requirements.
48 */
49
50 /* Header: */
51 #define BOOT_HEADER_MAGIC_V1 0x96f3b83d
52 #define BOOT_HEADER_SIZE_V1 32
53
54 enum IMAGE_INDEXES {
55 IMAGE_INDEX_INVALID = -1,
56 IMAGE_INDEX_0,
57 IMAGE_INDEX_1,
58 IMAGE_INDEX_2
59 };
60
61 #if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) || \
62 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT)
63 /* For RAM LOAD mode, the active image must be fetched from the bootloader */
64 #define ACTIVE_SLOT_FLASH_AREA_ID boot_fetch_active_slot()
65 #define INVALID_SLOT_ID 255
66 #else
67 /* Get active partition. zephyr,code-partition chosen node must be defined */
68 #define ACTIVE_SLOT_FLASH_AREA_ID DT_FIXED_PARTITION_ID(DT_CHOSEN(zephyr_code_partition))
69 #endif
70
71 /*
72 * Raw (on-flash) representation of the v1 image header.
73 */
74 struct mcuboot_v1_raw_header {
75 uint32_t header_magic;
76 uint32_t image_load_address;
77 uint16_t header_size;
78 uint16_t pad;
79 uint32_t image_size;
80 uint32_t image_flags;
81 struct {
82 uint8_t major;
83 uint8_t minor;
84 uint16_t revision;
85 uint32_t build_num;
86 } version;
87 uint32_t pad2;
88 } __packed;
89
90 /*
91 * End of strict defines
92 */
93
94 #if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) || \
95 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT)
boot_fetch_active_slot(void)96 uint8_t boot_fetch_active_slot(void)
97 {
98 int rc;
99 uint8_t slot, fa_id;
100
101 rc = blinfo_lookup(BLINFO_RUNNING_SLOT, &slot, sizeof(slot));
102
103 if (rc <= 0) {
104 LOG_ERR("Failed to fetch active slot: %d", rc);
105
106 return INVALID_SLOT_ID;
107 }
108
109 LOG_DBG("Active slot: %d", slot);
110 /* Map slot number back to flash area ID */
111 switch (slot) {
112 case 0:
113 fa_id = FIXED_PARTITION_ID(SLOT0_PARTITION);
114 break;
115
116 #if FIXED_PARTITION_EXISTS(SLOT1_PARTITION)
117 case 1:
118 fa_id = FIXED_PARTITION_ID(SLOT1_PARTITION);
119 break;
120 #endif
121
122 #if FIXED_PARTITION_EXISTS(SLOT2_PARTITION)
123 case 2:
124 fa_id = FIXED_PARTITION_ID(SLOT2_PARTITION);
125 break;
126 #endif
127
128 #if FIXED_PARTITION_EXISTS(SLOT3_PARTITION)
129 case 3:
130 fa_id = FIXED_PARTITION_ID(SLOT3_PARTITION);
131 break;
132 #endif
133
134 #if FIXED_PARTITION_EXISTS(SLOT4_PARTITION)
135 case 4:
136 fa_id = FIXED_PARTITION_ID(SLOT4_PARTITION);
137 break;
138 #endif
139
140 #if FIXED_PARTITION_EXISTS(SLOT5_PARTITION)
141 case 5:
142 fa_id = FIXED_PARTITION_ID(SLOT5_PARTITION);
143 break;
144 #endif
145
146 default:
147 fa_id = INVALID_SLOT_ID;
148 break;
149 }
150
151 return fa_id;
152 }
153 #else /* CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD ||
154 * CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT
155 */
boot_fetch_active_slot(void)156 uint8_t boot_fetch_active_slot(void)
157 {
158 return ACTIVE_SLOT_FLASH_AREA_ID;
159 }
160 #endif /* CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD ||
161 * CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT
162 */
163
164 #if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_OFFSET)
boot_get_image_start_offset(uint8_t area_id)165 size_t boot_get_image_start_offset(uint8_t area_id)
166 {
167 size_t off = 0;
168 int image = IMAGE_INDEX_INVALID;
169
170 if (area_id == FIXED_PARTITION_ID(slot1_partition)) {
171 image = IMAGE_INDEX_0;
172 #if FIXED_PARTITION_EXISTS(slot3_partition)
173 } else if (area_id == FIXED_PARTITION_ID(slot3_partition)) {
174 image = IMAGE_INDEX_1;
175 #endif
176 #if FIXED_PARTITION_EXISTS(slot5_partition)
177 } else if (area_id == FIXED_PARTITION_ID(slot5_partition)) {
178 image = IMAGE_INDEX_2;
179 #endif
180 }
181
182 if (image != IMAGE_INDEX_INVALID) {
183 /* Need to check status from primary slot to get correct offset for secondary
184 * slot image header
185 */
186 const struct flash_area *fa;
187 uint32_t num_sectors = SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN;
188 struct flash_sector sector_data;
189 int rc;
190
191 rc = flash_area_open(area_id, &fa);
192 if (rc) {
193 LOG_ERR("Flash open area %u failed: %d", area_id, rc);
194 goto done;
195 }
196
197 if (mcuboot_swap_type_multi(image) != BOOT_SWAP_TYPE_REVERT) {
198 /* For swap using offset mode, the image starts in the second sector of
199 * the upgrade slot, so apply the offset when this is needed, do this by
200 * getting information on first sector only, this is expected to return an
201 * error as there are more slots, so allow the not enough memory error
202 */
203 rc = flash_area_get_sectors(area_id, &num_sectors, §or_data);
204 if ((rc != 0 && rc != -ENOMEM) ||
205 num_sectors != SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN) {
206 LOG_ERR("Failed to get sector details: %d", rc);
207 } else {
208 off = sector_data.fs_size;
209 }
210 }
211
212 flash_area_close(fa);
213 }
214
215 done:
216 LOG_DBG("Start offset for area %u: 0x%x", area_id, off);
217 return off;
218 }
219 #endif /* CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_OFFSET */
220
boot_read_v1_header(uint8_t area_id,struct mcuboot_v1_raw_header * v1_raw)221 static int boot_read_v1_header(uint8_t area_id,
222 struct mcuboot_v1_raw_header *v1_raw)
223 {
224 const struct flash_area *fa;
225 int rc;
226 size_t off = boot_get_image_start_offset(area_id);
227
228 rc = flash_area_open(area_id, &fa);
229 if (rc) {
230 return rc;
231 }
232
233 /*
234 * Read and validty-check the raw header.
235 */
236 rc = flash_area_read(fa, off, v1_raw, sizeof(*v1_raw));
237 flash_area_close(fa);
238 if (rc) {
239 return rc;
240 }
241
242 v1_raw->header_magic = sys_le32_to_cpu(v1_raw->header_magic);
243 v1_raw->header_size = sys_le16_to_cpu(v1_raw->header_size);
244
245 /*
246 * Validity checks.
247 *
248 * Larger values in header_size than BOOT_HEADER_SIZE_V1 are
249 * possible, e.g. if Zephyr was linked with
250 * CONFIG_ROM_START_OFFSET > BOOT_HEADER_SIZE_V1.
251 */
252 if ((v1_raw->header_magic != BOOT_HEADER_MAGIC_V1) ||
253 (v1_raw->header_size < BOOT_HEADER_SIZE_V1)) {
254 return -EIO;
255 }
256
257 v1_raw->image_load_address =
258 sys_le32_to_cpu(v1_raw->image_load_address);
259 v1_raw->header_size = sys_le16_to_cpu(v1_raw->header_size);
260 v1_raw->image_size = sys_le32_to_cpu(v1_raw->image_size);
261 v1_raw->image_flags = sys_le32_to_cpu(v1_raw->image_flags);
262 v1_raw->version.revision =
263 sys_le16_to_cpu(v1_raw->version.revision);
264 v1_raw->version.build_num =
265 sys_le32_to_cpu(v1_raw->version.build_num);
266
267 return 0;
268 }
269
boot_read_bank_header(uint8_t area_id,struct mcuboot_img_header * header,size_t header_size)270 int boot_read_bank_header(uint8_t area_id,
271 struct mcuboot_img_header *header,
272 size_t header_size)
273 {
274 int rc;
275 struct mcuboot_v1_raw_header v1_raw;
276 struct mcuboot_img_sem_ver *sem_ver;
277 size_t v1_min_size = (sizeof(uint32_t) +
278 sizeof(struct mcuboot_img_header_v1));
279
280 /*
281 * Only version 1 image headers are supported.
282 */
283 if (header_size < v1_min_size) {
284 return -ENOMEM;
285 }
286 rc = boot_read_v1_header(area_id, &v1_raw);
287 if (rc) {
288 return rc;
289 }
290
291 /*
292 * Copy just the fields we care about into the return parameter.
293 *
294 * - header_magic: skip (only used to check format)
295 * - image_load_address: skip (only matters for PIC code)
296 * - header_size: skip (only used to check format)
297 * - image_size: include
298 * - image_flags: skip (all unsupported or not relevant)
299 * - version: include
300 */
301 header->mcuboot_version = 1U;
302 header->h.v1.image_size = v1_raw.image_size;
303 sem_ver = &header->h.v1.sem_ver;
304 sem_ver->major = v1_raw.version.major;
305 sem_ver->minor = v1_raw.version.minor;
306 sem_ver->revision = v1_raw.version.revision;
307 sem_ver->build_num = v1_raw.version.build_num;
308 return 0;
309 }
310
mcuboot_swap_type_multi(int image_index)311 int mcuboot_swap_type_multi(int image_index)
312 {
313 return boot_swap_type_multi(image_index);
314 }
315
mcuboot_swap_type(void)316 int mcuboot_swap_type(void)
317 {
318 #ifdef FLASH_AREA_IMAGE_SECONDARY
319 return boot_swap_type();
320 #else
321 return BOOT_SWAP_TYPE_NONE;
322 #endif
323
324 }
325
boot_request_upgrade(int permanent)326 int boot_request_upgrade(int permanent)
327 {
328 #ifdef FLASH_AREA_IMAGE_SECONDARY
329 int rc;
330
331 rc = boot_set_pending(permanent);
332 if (rc) {
333 return -EFAULT;
334 }
335 #endif /* FLASH_AREA_IMAGE_SECONDARY */
336 return 0;
337 }
338
boot_request_upgrade_multi(int image_index,int permanent)339 int boot_request_upgrade_multi(int image_index, int permanent)
340 {
341 int rc;
342
343 rc = boot_set_pending_multi(image_index, permanent);
344 if (rc) {
345 return -EFAULT;
346 }
347 return 0;
348 }
349
boot_is_img_confirmed(void)350 bool boot_is_img_confirmed(void)
351 {
352 struct boot_swap_state state;
353 const struct flash_area *fa;
354 int rc;
355
356 rc = flash_area_open(ACTIVE_SLOT_FLASH_AREA_ID, &fa);
357 if (rc) {
358 return false;
359 }
360
361 rc = boot_read_swap_state(fa, &state);
362 if (rc != 0) {
363 return false;
364 }
365
366 if (state.magic == BOOT_MAGIC_UNSET) {
367 /* This is initial/preprogramed image.
368 * Such image can neither be reverted nor physically confirmed.
369 * Treat this image as confirmed which ensures consistency
370 * with `boot_write_img_confirmed...()` procedures.
371 */
372 return true;
373 }
374
375 return state.image_ok == BOOT_FLAG_SET;
376 }
377
boot_write_img_confirmed(void)378 int boot_write_img_confirmed(void)
379 {
380 const struct flash_area *fa;
381 int rc = 0;
382
383 if (flash_area_open(ACTIVE_SLOT_FLASH_AREA_ID, &fa) != 0) {
384 return -EIO;
385 }
386
387 rc = boot_set_next(fa, true, true);
388
389 flash_area_close(fa);
390
391 return rc;
392 }
393
boot_write_img_confirmed_multi(int image_index)394 int boot_write_img_confirmed_multi(int image_index)
395 {
396 int rc;
397
398 rc = boot_set_confirmed_multi(image_index);
399 if (rc) {
400 return -EIO;
401 }
402
403 return 0;
404 }
405
boot_erase_img_bank(uint8_t area_id)406 int boot_erase_img_bank(uint8_t area_id)
407 {
408 const struct flash_area *fa;
409 int rc;
410
411 rc = flash_area_open(area_id, &fa);
412 if (rc) {
413 return rc;
414 }
415
416 rc = flash_area_flatten(fa, 0, fa->fa_size);
417
418 flash_area_close(fa);
419
420 return rc;
421 }
422
boot_get_trailer_status_offset(size_t area_size)423 ssize_t boot_get_trailer_status_offset(size_t area_size)
424 {
425 return (ssize_t)area_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
426 }
427
boot_get_area_trailer_status_offset(uint8_t area_id)428 ssize_t boot_get_area_trailer_status_offset(uint8_t area_id)
429 {
430 int rc;
431 const struct flash_area *fa;
432 ssize_t offset;
433
434 rc = flash_area_open(area_id, &fa);
435 if (rc) {
436 return rc;
437 }
438
439 offset = boot_get_trailer_status_offset(fa->fa_size);
440
441 flash_area_close(fa);
442
443 if (offset < 0) {
444 return -EFAULT;
445 }
446
447 return offset;
448 }
449