1 /*
2  * Copyright (c) 2017 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/storage/flash_map.h>
9 #include <bootutil/bootutil_public.h>
10 #include <zephyr/dfu/mcuboot.h>
11 #include <zephyr/drivers/flash.h>
12 
13 #define BOOT_MAGIC_VAL_W0 0xf395c277
14 #define BOOT_MAGIC_VAL_W1 0x7fefd260
15 #define BOOT_MAGIC_VAL_W2 0x0f505235
16 #define BOOT_MAGIC_VAL_W3 0x8079b62c
17 #define BOOT_MAGIC_VALUES {BOOT_MAGIC_VAL_W0, BOOT_MAGIC_VAL_W1,\
18 			   BOOT_MAGIC_VAL_W2, BOOT_MAGIC_VAL_W3 }
19 
erase_image_status_page(const struct flash_area * fa)20 static void erase_image_status_page(const struct flash_area *fa)
21 {
22 	int ret;
23 	struct flash_pages_info page;
24 	const struct device *sf_dev;
25 
26 	sf_dev = flash_area_get_device(fa);
27 
28 	/* Erase flash page to which image status belongs. */
29 	ret = flash_get_page_info_by_offs(sf_dev, fa->fa_off + fa->fa_size - 1,
30 					  &page);
31 	zassert_true(ret == 0, "can't get the trailer's flash page info.");
32 
33 	ret = flash_erase(sf_dev, page.start_offset, page.size);
34 	zassert_true(ret == 0, "can't erase the trailer flash page.");
35 }
36 
_test_request_upgrade_n(uint8_t fa_id,int img_index,int confirmed)37 static void _test_request_upgrade_n(uint8_t fa_id, int img_index, int confirmed)
38 {
39 	const struct flash_area *fa;
40 	const uint32_t expectation[6] = {
41 		0xffffffff,
42 		0xffffffff,
43 		BOOT_MAGIC_VAL_W0,
44 		BOOT_MAGIC_VAL_W1,
45 		BOOT_MAGIC_VAL_W2,
46 		BOOT_MAGIC_VAL_W3
47 	};
48 	uint32_t readout[ARRAY_SIZE(expectation)];
49 	int ret;
50 
51 	ret = flash_area_open(fa_id, &fa);
52 	zassert_true(ret == 0, "can't open the images's flash area.");
53 
54 	erase_image_status_page(fa);
55 
56 	ret = (confirmed) ? BOOT_UPGRADE_PERMANENT : BOOT_UPGRADE_TEST;
57 	zassert_true(boot_request_upgrade_multi(img_index, ret) == 0,
58 		     "Can' request the upgrade of the %d. image.", img_index);
59 
60 	ret = flash_area_read(fa, fa->fa_size - sizeof(expectation),
61 			      &readout, sizeof(readout));
62 	zassert_true(ret == 0, "Read from flash");
63 
64 	if (confirmed) {
65 		zassert_true(memcmp(&expectation[2], &readout[2],
66 				    sizeof(expectation) -
67 				    2 * sizeof(expectation[0])) == 0,
68 				    "unexpected trailer value");
69 
70 		zassert_equal(1, readout[0] & 0xff, "confirmation error");
71 	} else {
72 		zassert_true(memcmp(expectation, readout,
73 		sizeof(expectation)) == 0, "unexpected trailer value");
74 	}
75 }
76 
ZTEST(mcuboot_multi,test_request_upgrade_multi)77 ZTEST(mcuboot_multi, test_request_upgrade_multi)
78 {
79 	_test_request_upgrade_n(FIXED_PARTITION_ID(slot1_partition), 0, 0);
80 	_test_request_upgrade_n(FIXED_PARTITION_ID(slot3_partition), 1, 1);
81 }
82 
_test_write_confirm_n(uint8_t fa_id,int img_index)83 static void _test_write_confirm_n(uint8_t fa_id, int img_index)
84 {
85 	const uint32_t img_magic[4] = BOOT_MAGIC_VALUES;
86 	uint32_t readout[ARRAY_SIZE(img_magic)];
87 	uint8_t flag[BOOT_MAX_ALIGN];
88 	const struct flash_area *fa;
89 	int ret;
90 
91 	flag[0] = 0x01;
92 	memset(&flag[1], 0xff, sizeof(flag) - 1);
93 
94 	ret = flash_area_open(fa_id, &fa);
95 	zassert_true(ret == 0, "can't open the images's flash area.");
96 
97 	erase_image_status_page(fa);
98 
99 	ret = flash_area_read(fa, fa->fa_size - sizeof(img_magic),
100 			      &readout, sizeof(img_magic));
101 	zassert_true(ret == 0, "Read from flash");
102 
103 	if (memcmp(img_magic, readout, sizeof(img_magic)) != 0) {
104 		ret = flash_area_write(fa, fa->fa_size - 16,
105 				       img_magic, 16);
106 		zassert_true(ret == 0, "Write to flash");
107 	}
108 
109 	/* set copy-done flag */
110 	ret = flash_area_write(fa, fa->fa_size - 32, &flag, sizeof(flag));
111 	zassert_true(ret == 0, "Write to flash");
112 
113 	ret = boot_write_img_confirmed_multi(img_index);
114 	zassert(ret == 0, "pass", "fail (%d)", ret);
115 
116 	ret = flash_area_read(fa, fa->fa_size - 24, readout,
117 			      sizeof(readout[0]));
118 	zassert_true(ret == 0, "Read from flash");
119 
120 	zassert_equal(1, readout[0] & 0xff, "confirmation error");
121 }
122 
ZTEST(mcuboot_multi,test_write_confirm_multi)123 ZTEST(mcuboot_multi, test_write_confirm_multi)
124 {
125 	_test_write_confirm_n(FIXED_PARTITION_ID(slot0_partition), 0);
126 	_test_write_confirm_n(FIXED_PARTITION_ID(slot2_partition), 1);
127 }
128 
129 ZTEST_SUITE(mcuboot_multi, NULL, NULL, NULL, NULL, NULL);
130