1 /*
2  * Copyright (c) 2017-2025 Nordic Semiconductor ASA
3  * Copyright (c) 2017 Linaro Limited
4  * Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 #include <zephyr/types.h>
9 #include <assert.h>
10 #include <stddef.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <zephyr/logging/log.h>
14 #include <zephyr/dfu/mcuboot.h>
15 #include <zephyr/dfu/flash_img.h>
16 #include <zephyr/dfu/mcuboot.h>
17 #include <zephyr/storage/flash_map.h>
18 #include <zephyr/storage/stream_flash.h>
19 
20 LOG_MODULE_REGISTER(flash_img, CONFIG_IMG_MANAGER_LOG_LEVEL);
21 
22 #ifdef CONFIG_IMG_ERASE_PROGRESSIVELY
23 #include <bootutil/bootutil_public.h>
24 #endif
25 
26 #include <zephyr/devicetree.h>
27 #ifdef CONFIG_TRUSTED_EXECUTION_NONSECURE
28 	#define UPLOAD_FLASH_AREA_LABEL slot1_ns_partition
29 #else
30 #if FIXED_PARTITION_EXISTS(slot1_partition)
31 	#define UPLOAD_FLASH_AREA_LABEL slot1_partition
32 #else
33 	#define UPLOAD_FLASH_AREA_LABEL slot0_partition
34 #endif
35 #endif
36 
37 #ifdef CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD
38 /* For RAM LOAD mode, the active image must be fetched from the bootloader */
39 #define UPLOAD_FLASH_AREA_ID flash_img_get_upload_slot()
40 #else
41 /* FIXED_PARTITION_ID() values used below are auto-generated by DT */
42 #define UPLOAD_FLASH_AREA_ID FIXED_PARTITION_ID(UPLOAD_FLASH_AREA_LABEL)
43 #endif /* CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD */
44 #define UPLOAD_FLASH_AREA_CONTROLLER \
45 	DT_GPARENT(DT_NODELABEL(UPLOAD_FLASH_AREA_LABEL))
46 
47 #if DT_NODE_HAS_PROP(UPLOAD_FLASH_AREA_CONTROLLER, write_block_size)
48 #define FLASH_WRITE_BLOCK_SIZE \
49 	DT_PROP(UPLOAD_FLASH_AREA_CONTROLLER, write_block_size)
50 
51 BUILD_ASSERT((CONFIG_IMG_BLOCK_BUF_SIZE % FLASH_WRITE_BLOCK_SIZE == 0),
52 	     "CONFIG_IMG_BLOCK_BUF_SIZE is not a multiple of "
53 	     "FLASH_WRITE_BLOCK_SIZE");
54 #endif
55 
56 #define FLASH_CHECK_ERASED_BUFFER_SIZE 16
57 #define ERASED_VAL_32(x) (((x) << 24) | ((x) << 16) | ((x) << 8) | (x))
58 
scramble_mcuboot_trailer(struct flash_img_context * ctx)59 static int scramble_mcuboot_trailer(struct flash_img_context *ctx)
60 {
61 	int rc = 0;
62 
63 #ifdef CONFIG_IMG_ERASE_PROGRESSIVELY
64 	if (stream_flash_bytes_written(&ctx->stream) == 0) {
65 		off_t toff = boot_get_trailer_status_offset(ctx->flash_area->fa_size);
66 		off_t offset;
67 		size_t size;
68 		const struct flash_parameters *fparams =
69 			flash_get_parameters(flash_area_get_device(ctx->flash_area));
70 #ifdef CONFIG_STREAM_FLASH_ERASE
71 		/* for erasable devices prgressive-erase works only along with
72 		 * CONFIG_STREAM_FLASH_ERASE option.
73 		 */
74 		if (flash_params_get_erase_cap(fparams) & FLASH_ERASE_C_EXPLICIT) {
75 			/* On devices with explicit erase we are aligning to page
76 			 * layout.
77 			 */
78 			struct flash_pages_info info;
79 
80 			rc = flash_get_page_info_by_offs(flash_area_get_device(ctx->flash_area),
81 							 toff, &info);
82 			if (rc != 0) {
83 				return rc;
84 			}
85 			offset = info.start_offset;
86 			size = info.size;
87 
88 		} else
89 #endif
90 		{
91 			/* On devices with no erase, we are aligning to write block
92 			 * size.
93 			 */
94 			offset = (toff + fparams->write_block_size - 1) &
95 				 ~(fparams->write_block_size - 1);
96 			/* No alignment correction needed here, offset is corrected already
97 			 * and, size should be aligned.
98 			 */
99 			size = ctx->flash_area->fa_size - offset;
100 		}
101 
102 		rc = flash_area_flatten(ctx->flash_area, offset, size);
103 	}
104 #endif
105 
106 	return rc;
107 }
108 
109 
flash_img_buffered_write(struct flash_img_context * ctx,const uint8_t * data,size_t len,bool flush)110 int flash_img_buffered_write(struct flash_img_context *ctx, const uint8_t *data,
111 			     size_t len, bool flush)
112 {
113 	int rc;
114 
115 	/* If there is a need to erase the trailer, that should happen before any
116 	 * write is done to partition.
117 	 */
118 	rc = scramble_mcuboot_trailer(ctx);
119 	if (rc != 0) {
120 		return rc;
121 	}
122 
123 
124 	/* if CONFIG_IMG_ERASE_PROGRESSIVELY is enabled the enabled CONFIG_STREAM_FLASH_ERASE
125 	 * ensures that stream_flash erases flash progresively.
126 	 */
127 	rc = stream_flash_buffered_write(&ctx->stream, data, len, flush);
128 	if (!flush) {
129 		return rc;
130 	}
131 
132 	flash_area_close(ctx->flash_area);
133 	ctx->flash_area = NULL;
134 
135 	return rc;
136 }
137 
flash_img_bytes_written(struct flash_img_context * ctx)138 size_t flash_img_bytes_written(struct flash_img_context *ctx)
139 {
140 	return stream_flash_bytes_written(&ctx->stream);
141 }
142 
143 #if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_OFFSET)
144 /**
145  * Determines if the specified area of flash is completely unwritten.
146  *
147  * @param	fa	pointer to flash area to scan
148  *
149  * @return	0	when not empty, 1 when empty, negative errno code on error.
150  */
flash_check_erased(const struct flash_area * fa)151 static int flash_check_erased(const struct flash_area *fa)
152 {
153 	uint32_t data[FLASH_CHECK_ERASED_BUFFER_SIZE];
154 	off_t addr;
155 	off_t end;
156 	int bytes_to_read;
157 	int rc;
158 	int i;
159 	uint8_t erased_val;
160 	uint32_t erased_val_32;
161 
162 	assert(fa->fa_size % sizeof(erased_val_32) == 0);
163 
164 	erased_val = flash_area_erased_val(fa);
165 	erased_val_32 = ERASED_VAL_32(erased_val);
166 
167 	end = fa->fa_size;
168 	for (addr = 0; addr < end; addr += sizeof(data)) {
169 		if (end - addr < sizeof(data)) {
170 			bytes_to_read = end - addr;
171 		} else {
172 			bytes_to_read = sizeof(data);
173 		}
174 
175 		rc = flash_area_read(fa, addr, data, bytes_to_read);
176 
177 		if (rc < 0) {
178 			LOG_ERR("Failed to read data from flash area: %d", rc);
179 			return rc;
180 		}
181 
182 		for (i = 0; i < bytes_to_read / sizeof(erased_val_32); i++) {
183 			if (data[i] != erased_val_32) {
184 				return 0;
185 			}
186 		}
187 	}
188 
189 	return 1;
190 }
191 #endif
192 
flash_img_init_id(struct flash_img_context * ctx,uint8_t area_id)193 int flash_img_init_id(struct flash_img_context *ctx, uint8_t area_id)
194 {
195 	int rc;
196 	const struct device *flash_dev;
197 #if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_OFFSET)
198 	uint32_t sector_count = SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN;
199 	struct flash_sector sector_data;
200 #endif
201 
202 	rc = flash_area_open(area_id,
203 			       (const struct flash_area **)&(ctx->flash_area));
204 	if (rc) {
205 		return rc;
206 	}
207 
208 	flash_dev = flash_area_get_device(ctx->flash_area);
209 
210 #if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_OFFSET)
211 	/* Query size of first sector in flash for upgrade slot, so it can be erased, and begin
212 	 * upload started at the second sector
213 	 */
214 	rc = flash_area_sectors((const struct flash_area *)ctx->flash_area, &sector_count,
215 				&sector_data);
216 
217 	if (rc && rc != -ENOMEM) {
218 		flash_area_close(ctx->flash_area);
219 		ctx->flash_area = NULL;
220 		return rc;
221 	} else if (sector_count != SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN) {
222 		flash_area_close(ctx->flash_area);
223 		ctx->flash_area = NULL;
224 		return -ENOENT;
225 	}
226 
227 	if (!flash_check_erased((const struct flash_area *)ctx->flash_area)) {
228 		/* Flash is not empty, therefore flatten/erase the area to prevent issues when
229 		 * the firmware update process begins
230 		 */
231 		rc = flash_area_flatten((const struct flash_area *)ctx->flash_area, 0,
232 					sector_data.fs_size);
233 
234 		if (rc) {
235 			flash_area_close(ctx->flash_area);
236 			ctx->flash_area = NULL;
237 			return rc;
238 		}
239 	}
240 
241 	return stream_flash_init(&ctx->stream, flash_dev, ctx->buf, CONFIG_IMG_BLOCK_BUF_SIZE,
242 				 (ctx->flash_area->fa_off + sector_data.fs_size),
243 				 (ctx->flash_area->fa_size - sector_data.fs_size), NULL);
244 #else
245 	return stream_flash_init(&ctx->stream, flash_dev, ctx->buf,
246 			CONFIG_IMG_BLOCK_BUF_SIZE, ctx->flash_area->fa_off,
247 			ctx->flash_area->fa_size, NULL);
248 #endif
249 }
250 
251 #ifdef CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD
flash_img_get_upload_slot(void)252 uint8_t flash_img_get_upload_slot(void)
253 {
254 	uint8_t slot;
255 
256 	slot = boot_fetch_active_slot();
257 
258 	if (slot == FIXED_PARTITION_ID(slot0_partition)) {
259 		return FIXED_PARTITION_ID(slot1_partition);
260 	}
261 	return FIXED_PARTITION_ID(slot0_partition);
262 }
263 #else  /* CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD */
flash_img_get_upload_slot(void)264 uint8_t flash_img_get_upload_slot(void)
265 {
266 	return UPLOAD_FLASH_AREA_ID;
267 }
268 #endif /* CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD */
269 
flash_img_init(struct flash_img_context * ctx)270 int flash_img_init(struct flash_img_context *ctx)
271 {
272 	return flash_img_init_id(ctx, UPLOAD_FLASH_AREA_ID);
273 }
274 
275 #if defined(CONFIG_IMG_ENABLE_IMAGE_CHECK)
flash_img_check(struct flash_img_context * ctx,const struct flash_img_check * fic,uint8_t area_id)276 int flash_img_check(struct flash_img_context *ctx,
277 		    const struct flash_img_check *fic,
278 		    uint8_t area_id)
279 {
280 	struct flash_area_check fac;
281 	int rc;
282 
283 	if (!ctx || !fic) {
284 		return -EINVAL;
285 	}
286 
287 	rc = flash_area_open(area_id,
288 			     (const struct flash_area **)&(ctx->flash_area));
289 	if (rc) {
290 		return rc;
291 	}
292 
293 	fac.match = fic->match;
294 	fac.clen = fic->clen;
295 	fac.off = boot_get_image_start_offset(area_id);
296 	fac.rbuf = ctx->buf;
297 	fac.rblen = sizeof(ctx->buf);
298 
299 	rc = flash_area_check_int_sha256(ctx->flash_area, &fac);
300 
301 	flash_area_close(ctx->flash_area);
302 	ctx->flash_area = NULL;
303 
304 	return rc;
305 }
306 #endif
307