1 /*
2 * Copyright (c) 2018-2021 mcumgr authors
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/init.h>
9 #include <zephyr/drivers/flash.h>
10 #include <zephyr/storage/flash_map.h>
11 #include <zephyr/dfu/mcuboot.h>
12 #include <zephyr/dfu/flash_img.h>
13 #include <zephyr/logging/log.h>
14 #include <bootutil/bootutil_public.h>
15 #include <assert.h>
16
17 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
18 #include <zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h>
19
20 #include <mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h>
21
22 #if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO)
23 #include <zephyr/retention/retention.h>
24 #include <zephyr/retention/blinfo.h>
25 #endif
26
27 LOG_MODULE_DECLARE(mcumgr_img_grp, CONFIG_MCUMGR_GRP_IMG_LOG_LEVEL);
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
36 /* SLOT0_PARTITION and SLOT1_PARTITION are not checked because
37 * there is not conditional code that depends on them. If they do
38 * not exist compilation will fail, but in case if some of other
39 * partitions do not exist, code will compile and will not work
40 * properly.
41 */
42 #if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER >= 2
43 BUILD_ASSERT(FIXED_PARTITION_EXISTS(SLOT2_PARTITION) &&
44 FIXED_PARTITION_EXISTS(SLOT3_PARTITION),
45 "Missing partitions?");
46 #endif
47
48 #if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER == 3
49 BUILD_ASSERT(FIXED_PARTITION_EXISTS(SLOT4_PARTITION) &&
50 FIXED_PARTITION_EXISTS(SLOT5_PARTITION),
51 "Missing partitions?");
52 #endif
53
54 /**
55 * Determines if the specified area of flash is completely unwritten.
56 *
57 * @param fa pointer to flash area to scan
58 *
59 * @return 0 when not empty, 1 when empty, negative errno code on error.
60 */
img_mgmt_flash_check_empty_inner(const struct flash_area * fa)61 static int img_mgmt_flash_check_empty_inner(const struct flash_area *fa)
62 {
63 uint32_t data[16];
64 off_t addr;
65 off_t end;
66 int bytes_to_read;
67 int rc;
68 int i;
69 uint8_t erased_val;
70 uint32_t erased_val_32;
71
72 assert(fa->fa_size % 4 == 0);
73
74 erased_val = flash_area_erased_val(fa);
75 erased_val_32 = ERASED_VAL_32(erased_val);
76
77 end = fa->fa_size;
78 for (addr = 0; addr < end; addr += sizeof(data)) {
79 if (end - addr < sizeof(data)) {
80 bytes_to_read = end - addr;
81 } else {
82 bytes_to_read = sizeof(data);
83 }
84
85 rc = flash_area_read(fa, addr, data, bytes_to_read);
86 if (rc < 0) {
87 LOG_ERR("Failed to read data from flash area: %d", rc);
88 return IMG_MGMT_ERR_FLASH_READ_FAILED;
89 }
90
91 for (i = 0; i < bytes_to_read / 4; i++) {
92 if (data[i] != erased_val_32) {
93 return 0;
94 }
95 }
96 }
97
98 return 1;
99 }
100
101 #ifndef CONFIG_IMG_ERASE_PROGRESSIVELY
102 /* Check if area is empty
103 *
104 * @param fa_id ID of flash area to scan.
105 *
106 * @return 0 when not empty, 1 when empty, negative errno code on error.
107 */
img_mgmt_flash_check_empty(uint8_t fa_id)108 static int img_mgmt_flash_check_empty(uint8_t fa_id)
109 {
110 const struct flash_area *fa;
111 int rc;
112
113 rc = flash_area_open(fa_id, &fa);
114 if (rc == 0) {
115 rc = img_mgmt_flash_check_empty_inner(fa);
116
117 flash_area_close(fa);
118 } else {
119 LOG_ERR("Failed to open flash area ID %u: %d", fa_id, rc);
120 rc = IMG_MGMT_ERR_FLASH_OPEN_FAILED;
121 }
122
123 return rc;
124 }
125 #endif
126
127 /**
128 * Get flash_area ID for a image number; actually the slots are images
129 * for Zephyr, as slot 0 of image 0 is image_0, slot 0 of image 1 is
130 * image_2 and so on. The function treats slot numbers as absolute
131 * slot number starting at 0.
132 */
133 int
img_mgmt_flash_area_id(int slot)134 img_mgmt_flash_area_id(int slot)
135 {
136 uint8_t fa_id;
137
138 switch (slot) {
139 case 0:
140 fa_id = FIXED_PARTITION_ID(SLOT0_PARTITION);
141 break;
142
143 case 1:
144 fa_id = FIXED_PARTITION_ID(SLOT1_PARTITION);
145 break;
146
147 #if FIXED_PARTITION_EXISTS(SLOT2_PARTITION)
148 case 2:
149 fa_id = FIXED_PARTITION_ID(SLOT2_PARTITION);
150 break;
151 #endif
152
153 #if FIXED_PARTITION_EXISTS(SLOT3_PARTITION)
154 case 3:
155 fa_id = FIXED_PARTITION_ID(SLOT3_PARTITION);
156 break;
157 #endif
158
159 #if FIXED_PARTITION_EXISTS(SLOT4_PARTITION)
160 case 4:
161 fa_id = FIXED_PARTITION_ID(SLOT4_PARTITION);
162 break;
163 #endif
164
165 #if FIXED_PARTITION_EXISTS(SLOT5_PARTITION)
166 case 5:
167 fa_id = FIXED_PARTITION_ID(SLOT5_PARTITION);
168 break;
169 #endif
170
171 default:
172 fa_id = -1;
173 break;
174 }
175
176 return fa_id;
177 }
178
179 #if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER == 1
180 /**
181 * In normal operation this function will select between first two slot
182 * (in reality it just checks whether second slot can be used), ignoring the
183 * slot parameter.
184 * When CONFIG_MCUMGR_GRP_IMG_DIRECT_UPLOAD is defined it will check if given
185 * slot is available, and allowed, for DFU; providing 0 as a parameter means
186 * find any unused and non-active available (auto-select); any other positive
187 * value is direct (slot + 1) to be used; if checks are positive, then area
188 * ID is returned, -1 is returned otherwise.
189 * Note that auto-selection is performed only between the two first slots.
190 */
img_mgmt_get_unused_slot_area_id(int slot)191 static int img_mgmt_get_unused_slot_area_id(int slot)
192 {
193 #if defined(CONFIG_MCUMGR_GRP_IMG_DIRECT_UPLOAD)
194 slot--;
195 if (slot < -1) {
196 return -1;
197 } else if (slot == -1) {
198 #endif
199 /*
200 * Auto select slot; note that this is performed only between two first
201 * slots, at this point, which will require fix when Direct-XIP, which
202 * may support more slots, gets support within Zephyr.
203 */
204 for (slot = 0; slot < 2; slot++) {
205 if (img_mgmt_slot_in_use(slot) == 0) {
206 int area_id = img_mgmt_flash_area_id(slot);
207
208 if (area_id >= 0) {
209 return area_id;
210 }
211 }
212 }
213 return -1;
214 #if defined(CONFIG_MCUMGR_GRP_IMG_DIRECT_UPLOAD)
215 }
216 /*
217 * Direct selection; the first two slots are checked for being available
218 * and unused; the all other slots are just checked for availability.
219 */
220 if (slot < 2) {
221 slot = img_mgmt_slot_in_use(slot) == 0 ? slot : -1;
222 }
223
224 /* Return area ID for the slot or -1 */
225 return slot != -1 ? img_mgmt_flash_area_id(slot) : -1;
226 #endif
227 }
228 #elif CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER >= 2
img_mgmt_get_unused_slot_area_id(unsigned int image)229 static int img_mgmt_get_unused_slot_area_id(unsigned int image)
230 {
231 int area_id = -1;
232 int slot = 0;
233
234 slot = img_mgmt_get_opposite_slot(img_mgmt_active_slot(image));
235
236 if (!img_mgmt_slot_in_use(slot)) {
237 area_id = img_mgmt_flash_area_id(slot);
238 }
239
240 return area_id;
241 }
242 #else
243 #error "Unsupported number of images"
244 #endif
245
img_mgmt_vercmp(const struct image_version * a,const struct image_version * b)246 int img_mgmt_vercmp(const struct image_version *a, const struct image_version *b)
247 {
248 if (a->iv_major < b->iv_major) {
249 return -1;
250 } else if (a->iv_major > b->iv_major) {
251 return 1;
252 }
253
254 if (a->iv_minor < b->iv_minor) {
255 return -1;
256 } else if (a->iv_minor > b->iv_minor) {
257 return 1;
258 }
259
260 if (a->iv_revision < b->iv_revision) {
261 return -1;
262 } else if (a->iv_revision > b->iv_revision) {
263 return 1;
264 }
265
266 #if defined(CONFIG_MCUMGR_GRP_IMG_VERSION_CMP_USE_BUILD_NUMBER)
267 if (a->iv_build_num < b->iv_build_num) {
268 return -1;
269 } else if (a->iv_build_num > b->iv_build_num) {
270 return 1;
271 }
272 #endif
273
274 return 0;
275 }
276
img_mgmt_erase_slot(int slot)277 int img_mgmt_erase_slot(int slot)
278 {
279 const struct flash_area *fa;
280 int rc;
281 int area_id = img_mgmt_flash_area_id(slot);
282
283 if (area_id < 0) {
284 return IMG_MGMT_ERR_INVALID_SLOT;
285 }
286
287 rc = flash_area_open(area_id, &fa);
288
289 if (rc < 0) {
290 LOG_ERR("Failed to open flash area ID %u: %d", area_id, rc);
291 return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
292 }
293
294 rc = img_mgmt_flash_check_empty_inner(fa);
295
296 if (rc == 0) {
297 rc = flash_area_flatten(fa, 0, fa->fa_size);
298
299 if (rc != 0) {
300 LOG_ERR("Failed to erase flash area: %d", rc);
301 rc = IMG_MGMT_ERR_FLASH_ERASE_FAILED;
302 }
303 } else if (rc == 1) {
304 /* A return value of 1 indicates that the slot is already erased, thus
305 * return a success code to the client
306 */
307 rc = 0;
308 }
309
310 flash_area_close(fa);
311
312 return rc;
313 }
314
img_mgmt_write_pending(int slot,bool permanent)315 int img_mgmt_write_pending(int slot, bool permanent)
316 {
317 int rc;
318
319 if (slot != 1 && !(CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER == 2 && slot == 3)) {
320 return IMG_MGMT_ERR_INVALID_SLOT;
321 }
322
323 rc = boot_request_upgrade_multi(img_mgmt_slot_to_image(slot), permanent);
324 if (rc != 0) {
325 LOG_ERR("Failed to write pending flag for slot %d: %d", slot, rc);
326 return IMG_MGMT_ERR_FLASH_WRITE_FAILED;
327 }
328
329 return IMG_MGMT_ERR_OK;
330 }
331
img_mgmt_write_confirmed(void)332 int img_mgmt_write_confirmed(void)
333 {
334 int rc;
335
336 rc = boot_write_img_confirmed();
337 if (rc != 0) {
338 LOG_ERR("Failed to write confirmed flag: %d", rc);
339 return IMG_MGMT_ERR_FLASH_WRITE_FAILED;
340 }
341
342 return IMG_MGMT_ERR_OK;
343 }
344
img_mgmt_read(int slot,unsigned int offset,void * dst,unsigned int num_bytes)345 int img_mgmt_read(int slot, unsigned int offset, void *dst, unsigned int num_bytes)
346 {
347 const struct flash_area *fa;
348 int rc;
349 int area_id = img_mgmt_flash_area_id(slot);
350
351 if (area_id < 0) {
352 return IMG_MGMT_ERR_INVALID_SLOT;
353 }
354
355 rc = flash_area_open(area_id, &fa);
356 if (rc != 0) {
357 LOG_ERR("Failed to open flash area ID %u: %d", area_id, rc);
358 return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
359 }
360
361 rc = flash_area_read(fa, offset, dst, num_bytes);
362 flash_area_close(fa);
363
364 if (rc != 0) {
365 LOG_ERR("Failed to read data from flash: %d", rc);
366 return IMG_MGMT_ERR_FLASH_READ_FAILED;
367 }
368
369 return 0;
370 }
371
372 #if defined(CONFIG_MCUMGR_GRP_IMG_USE_HEAP_FOR_FLASH_IMG_CONTEXT)
img_mgmt_write_image_data(unsigned int offset,const void * data,unsigned int num_bytes,bool last)373 int img_mgmt_write_image_data(unsigned int offset, const void *data, unsigned int num_bytes,
374 bool last)
375 {
376 /* Even if K_HEAP_MEM_POOL_SIZE will be able to match size of the structure,
377 * keep in mind that when application will put the heap under pressure, obtaining
378 * of a flash image context may not be possible, so plan bigger heap size or
379 * make sure to limit application pressure on heap when DFU is expected.
380 */
381 BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= (sizeof(struct flash_img_context)),
382 "Not enough heap mem for flash_img_context.");
383
384 int rc = IMG_MGMT_ERR_OK;
385 static struct flash_img_context *ctx;
386
387 if (offset != 0 && ctx == NULL) {
388 return IMG_MGMT_ERR_FLASH_CONTEXT_NOT_SET;
389 }
390
391 if (offset == 0) {
392 if (ctx != NULL) {
393 return IMG_MGMT_ERR_FLASH_CONTEXT_ALREADY_SET;
394 }
395 ctx = k_malloc(sizeof(struct flash_img_context));
396
397 if (ctx == NULL) {
398 return IMG_MGMT_ERR_NO_FREE_MEMORY;
399 }
400
401 if (flash_img_init_id(ctx, g_img_mgmt_state.area_id) != 0) {
402 rc = IMG_MGMT_ERR_FLASH_OPEN_FAILED;
403 goto out;
404 }
405 }
406
407 if (flash_img_buffered_write(ctx, data, num_bytes, last) != 0) {
408 rc = IMG_MGMT_ERR_FLASH_WRITE_FAILED;
409 goto out;
410 }
411
412 out:
413 if (last || rc != MGMT_ERR_EOK) {
414 k_free(ctx);
415 ctx = NULL;
416 }
417
418 return rc;
419 }
420 #else
img_mgmt_write_image_data(unsigned int offset,const void * data,unsigned int num_bytes,bool last)421 int img_mgmt_write_image_data(unsigned int offset, const void *data, unsigned int num_bytes,
422 bool last)
423 {
424 static struct flash_img_context ctx;
425
426 if (offset == 0) {
427 if (flash_img_init_id(&ctx, g_img_mgmt_state.area_id) != 0) {
428 return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
429 }
430 }
431
432 if (flash_img_buffered_write(&ctx, data, num_bytes, last) != 0) {
433 return IMG_MGMT_ERR_FLASH_WRITE_FAILED;
434 }
435
436 return IMG_MGMT_ERR_OK;
437 }
438 #endif
439
img_mgmt_erase_image_data(unsigned int off,unsigned int num_bytes)440 int img_mgmt_erase_image_data(unsigned int off, unsigned int num_bytes)
441 {
442 const struct flash_area *fa;
443 int rc;
444
445 if (off != 0) {
446 rc = IMG_MGMT_ERR_INVALID_OFFSET;
447 goto end;
448 }
449
450 rc = flash_area_open(g_img_mgmt_state.area_id, &fa);
451 if (rc != 0) {
452 LOG_ERR("Can't bind to the flash area (err %d)", rc);
453 rc = IMG_MGMT_ERR_FLASH_OPEN_FAILED;
454 goto end;
455 }
456
457 /* align requested erase size to the erase-block-size */
458 const struct device *dev = flash_area_get_device(fa);
459
460 if (dev == NULL) {
461 rc = IMG_MGMT_ERR_FLASH_AREA_DEVICE_NULL;
462 goto end_fa;
463 }
464 struct flash_pages_info page;
465 off_t page_offset = fa->fa_off + num_bytes - 1;
466
467 rc = flash_get_page_info_by_offs(dev, page_offset, &page);
468 if (rc != 0) {
469 LOG_ERR("bad offset (0x%lx)", (long)page_offset);
470 rc = IMG_MGMT_ERR_INVALID_PAGE_OFFSET;
471 goto end_fa;
472 }
473
474 size_t erase_size = page.start_offset + page.size - fa->fa_off;
475
476 rc = flash_area_flatten(fa, 0, erase_size);
477
478 if (rc != 0) {
479 LOG_ERR("image slot erase of 0x%zx bytes failed (err %d)", erase_size,
480 rc);
481 rc = IMG_MGMT_ERR_FLASH_ERASE_FAILED;
482 goto end_fa;
483 }
484
485 LOG_INF("Erased 0x%zx bytes of image slot", erase_size);
486
487 #ifdef CONFIG_MCUBOOT_IMG_MANAGER
488 /* Right now MCUmgr supports only mcuboot images.
489 * Above compilation swich might help to recognize mcuboot related
490 * code when supports for anothe bootloader will be introduced.
491 */
492
493 /* erase the image trailer area if it was not erased */
494 off = boot_get_trailer_status_offset(fa->fa_size);
495 if (off >= erase_size) {
496 rc = flash_get_page_info_by_offs(dev, fa->fa_off + off, &page);
497
498 off = page.start_offset - fa->fa_off;
499 erase_size = fa->fa_size - off;
500
501 rc = flash_area_flatten(fa, off, erase_size);
502 if (rc != 0) {
503 LOG_ERR("image slot trailer erase of 0x%zx bytes failed (err %d)",
504 erase_size, rc);
505 rc = IMG_MGMT_ERR_FLASH_ERASE_FAILED;
506 goto end_fa;
507 }
508
509 LOG_INF("Erased 0x%zx bytes of image slot trailer", erase_size);
510 }
511 #endif
512 rc = IMG_MGMT_ERR_OK;
513
514 end_fa:
515 flash_area_close(fa);
516 end:
517 return rc;
518 }
519
img_mgmt_swap_type(int slot)520 int img_mgmt_swap_type(int slot)
521 {
522 int image = img_mgmt_slot_to_image(slot);
523
524 switch (mcuboot_swap_type_multi(image)) {
525 case BOOT_SWAP_TYPE_NONE:
526 return IMG_MGMT_SWAP_TYPE_NONE;
527 case BOOT_SWAP_TYPE_TEST:
528 return IMG_MGMT_SWAP_TYPE_TEST;
529 case BOOT_SWAP_TYPE_PERM:
530 return IMG_MGMT_SWAP_TYPE_PERM;
531 case BOOT_SWAP_TYPE_REVERT:
532 return IMG_MGMT_SWAP_TYPE_REVERT;
533 default:
534 return IMG_MGMT_SWAP_TYPE_UNKNOWN;
535 }
536 }
537
538 /**
539 * Verifies an upload request and indicates the actions that should be taken
540 * during processing of the request. This is a "read only" function in the
541 * sense that it doesn't write anything to flash and doesn't modify any global
542 * variables.
543 *
544 * @param req The upload request to inspect.
545 * @param action On success, gets populated with information about how to process
546 * the request.
547 *
548 * @return 0 if processing should occur; A MGMT_ERR code if an error response should be sent
549 * instead.
550 */
img_mgmt_upload_inspect(const struct img_mgmt_upload_req * req,struct img_mgmt_upload_action * action)551 int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req,
552 struct img_mgmt_upload_action *action)
553 {
554 const struct image_header *hdr;
555 struct image_version cur_ver;
556 int rc;
557
558 memset(action, 0, sizeof(*action));
559
560 if (req->off == SIZE_MAX) {
561 /* Request did not include an `off` field. */
562 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_hdr_malformed);
563 return IMG_MGMT_ERR_INVALID_OFFSET;
564 }
565
566 if (req->off == 0) {
567 /* First upload chunk. */
568 const struct flash_area *fa;
569 #if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD) && \
570 (defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) || \
571 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) || \
572 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) || \
573 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \
574 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)) && \
575 CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0
576 const struct flash_area *fa_current;
577 int current_img_area;
578 #elif defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO)
579 int max_image_size;
580 #endif
581
582 if (req->img_data.len < sizeof(struct image_header)) {
583 /* Image header is the first thing in the image */
584 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_hdr_malformed);
585 return IMG_MGMT_ERR_INVALID_IMAGE_HEADER;
586 }
587
588 if (req->size == SIZE_MAX) {
589 /* Request did not include a `len` field. */
590 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_hdr_malformed);
591 return IMG_MGMT_ERR_INVALID_LENGTH;
592 }
593
594 action->size = req->size;
595
596 hdr = (struct image_header *)req->img_data.value;
597 if (hdr->ih_magic != IMAGE_MAGIC) {
598 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_magic_mismatch);
599 return IMG_MGMT_ERR_INVALID_IMAGE_HEADER_MAGIC;
600 }
601
602 if (req->data_sha.len > IMG_MGMT_DATA_SHA_LEN) {
603 return IMG_MGMT_ERR_INVALID_HASH;
604 }
605
606 /*
607 * If request includes proper data hash we can check whether there is
608 * upload in progress (interrupted due to e.g. link disconnection) with
609 * the same data hash so we can just resume it by simply including
610 * current upload offset in response.
611 */
612 if ((req->data_sha.len > 0) && (g_img_mgmt_state.area_id != -1)) {
613 if ((g_img_mgmt_state.data_sha_len == req->data_sha.len) &&
614 !memcmp(g_img_mgmt_state.data_sha, req->data_sha.value,
615 req->data_sha.len)) {
616 return IMG_MGMT_ERR_OK;
617 }
618 }
619
620 action->area_id = img_mgmt_get_unused_slot_area_id(req->image);
621 if (action->area_id < 0) {
622 /* No slot where to upload! */
623 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_no_slot);
624 return IMG_MGMT_ERR_NO_FREE_SLOT;
625 }
626
627 rc = flash_area_open(action->area_id, &fa);
628 if (rc) {
629 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
630 img_mgmt_err_str_flash_open_failed);
631 LOG_ERR("Failed to open flash area ID %u: %d", action->area_id, rc);
632 return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
633 }
634
635 /* Check that the area is of sufficient size to store the new image */
636 if (req->size > fa->fa_size) {
637 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
638 img_mgmt_err_str_image_too_large);
639 flash_area_close(fa);
640 LOG_ERR("Upload too large for slot: %u > %u", req->size, fa->fa_size);
641 return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE;
642 }
643
644 #if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD) && \
645 (defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) || \
646 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) || \
647 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) || \
648 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \
649 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)) && \
650 CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0
651 /* Check if slot1 is larger than slot0 by the update size, if so then the size
652 * check can be skipped because the devicetree partitions are okay
653 */
654 current_img_area = img_mgmt_flash_area_id(req->image);
655
656 if (current_img_area < 0) {
657 /* Current slot cannot be determined */
658 LOG_ERR("Failed to determine active slot for image %d: %d", req->image,
659 current_img_area);
660 return IMG_MGMT_ERR_ACTIVE_SLOT_NOT_KNOWN;
661 }
662
663 rc = flash_area_open(current_img_area, &fa_current);
664 if (rc) {
665 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
666 img_mgmt_err_str_flash_open_failed);
667 LOG_ERR("Failed to open flash area ID %u: %d", current_img_area, rc);
668 flash_area_close(fa);
669 return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
670 }
671
672 flash_area_close(fa_current);
673
674 LOG_DBG("Primary size: %d, secondary size: %d, overhead: %d, max update size: %d",
675 fa_current->fa_size, fa->fa_size, CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE,
676 (fa->fa_size + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE));
677
678 if (fa_current->fa_size >= (fa->fa_size + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE)) {
679 /* Upgrade slot is of sufficient size, nothing to check */
680 LOG_INF("Upgrade slots already sized appropriately, "
681 "CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD is not needed");
682 goto skip_size_check;
683 }
684
685 if (req->size > (fa->fa_size - CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE)) {
686 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
687 img_mgmt_err_str_image_too_large);
688 flash_area_close(fa);
689 LOG_ERR("Upload too large for slot (with end offset): %u > %u", req->size,
690 (fa->fa_size - CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE));
691 return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE;
692 }
693
694 skip_size_check:
695 #elif defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO)
696 rc = blinfo_lookup(BLINFO_MAX_APPLICATION_SIZE, (char *)&max_image_size,
697 sizeof(max_image_size));
698
699 if (rc == sizeof(max_image_size) && max_image_size > 0 &&
700 req->size > max_image_size) {
701 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
702 img_mgmt_err_str_image_too_large);
703 flash_area_close(fa);
704 LOG_ERR("Upload too large for slot (with max image size): %u > %u",
705 req->size, max_image_size);
706 return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE;
707 }
708 #endif
709
710 #if defined(CONFIG_MCUMGR_GRP_IMG_REJECT_DIRECT_XIP_MISMATCHED_SLOT)
711 if (hdr->ih_flags & IMAGE_F_ROM_FIXED) {
712 if (fa->fa_off != hdr->ih_load_addr) {
713 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
714 img_mgmt_err_str_image_bad_flash_addr);
715 flash_area_close(fa);
716 return IMG_MGMT_ERR_INVALID_FLASH_ADDRESS;
717 }
718 }
719 #endif
720
721 flash_area_close(fa);
722
723 if (req->upgrade) {
724 /* User specified upgrade-only. Make sure new image version is
725 * greater than that of the currently running image.
726 */
727 rc = img_mgmt_my_version(&cur_ver);
728 if (rc != 0) {
729 return IMG_MGMT_ERR_VERSION_GET_FAILED;
730 }
731
732 if (img_mgmt_vercmp(&cur_ver, &hdr->ih_ver) >= 0) {
733 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
734 img_mgmt_err_str_downgrade);
735 return IMG_MGMT_ERR_CURRENT_VERSION_IS_NEWER;
736 }
737 }
738
739 #ifndef CONFIG_IMG_ERASE_PROGRESSIVELY
740 rc = img_mgmt_flash_check_empty(action->area_id);
741 if (rc < 0) {
742 return rc;
743 }
744
745 action->erase = (rc == 0);
746 #endif
747 } else {
748 /* Continuation of upload. */
749 action->area_id = g_img_mgmt_state.area_id;
750 action->size = g_img_mgmt_state.size;
751
752 if (req->off != g_img_mgmt_state.off) {
753 /*
754 * Invalid offset. Drop the data, and respond with the offset we're
755 * expecting data for.
756 */
757 return IMG_MGMT_ERR_OK;
758 }
759
760 if ((req->off + req->img_data.len) > action->size) {
761 /* Data overrun, the amount of data written would be more than the size
762 * of the image that the client originally sent
763 */
764 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_data_overrun);
765 return IMG_MGMT_ERR_INVALID_IMAGE_DATA_OVERRUN;
766 }
767 }
768
769 action->write_bytes = req->img_data.len;
770 action->proceed = true;
771 IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, NULL);
772
773 return IMG_MGMT_ERR_OK;
774 }
775
img_mgmt_erased_val(int slot,uint8_t * erased_val)776 int img_mgmt_erased_val(int slot, uint8_t *erased_val)
777 {
778 const struct flash_area *fa;
779 int rc;
780 int area_id = img_mgmt_flash_area_id(slot);
781
782 if (area_id < 0) {
783 return IMG_MGMT_ERR_INVALID_SLOT;
784 }
785
786 rc = flash_area_open(area_id, &fa);
787 if (rc != 0) {
788 LOG_ERR("Failed to open flash area ID %u: %d", area_id, rc);
789 return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
790 }
791
792 *erased_val = flash_area_erased_val(fa);
793 flash_area_close(fa);
794
795 return 0;
796 }
797