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, &sector_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