1 /*
2  * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <CppUTest/TestHarness.h>
8 #include <cstdlib>
9 #include <cstring>
10 
11 #include "common/uuid/uuid.h"
12 #include "media/disk/guid.h"
13 #include "media/volume/block_volume/block_volume.h"
14 #include "media/volume/index/volume_index.h"
15 #include "media/volume/volume.h"
16 #include "service/block_storage/config/ref/ref_partition_configurator.h"
17 #include "service/block_storage/factory/ref_ram_gpt/block_store_factory.h"
18 #include "service/fwu/agent/fw_directory.h"
19 #include "service/fwu/fw_store/banked/volume_id.h"
20 #include "service/fwu/installer/copy/copy_installer.h"
21 #include "service/fwu/installer/installer_index.h"
22 #include "service/fwu/installer/raw/raw_installer.h"
23 
TEST_GROUP(FwuCopyInstallerTests)24 TEST_GROUP(FwuCopyInstallerTests)
25 {
26 	void setup()
27 	{
28 		int result;
29 		struct uuid_octets partition_guid;
30 
31 		m_image = NULL;
32 
33 		installer_index_init();
34 		volume_index_init();
35 
36 		/* Use the reference disk configuration and use partition 1 & 2 as
37 		 * storage for A and B firmware banks.
38 		 */
39 		m_block_store = ref_ram_gpt_block_store_factory_create();
40 
41 		/* Construct fw volume A */
42 		uuid_guid_octets_from_canonical(&partition_guid, REF_PARTITION_1_GUID);
43 
44 		result = block_volume_init(&m_block_volume_a, m_block_store, &partition_guid,
45 					   &m_fw_volume_a);
46 
47 		LONGS_EQUAL(0, result);
48 		CHECK_TRUE(m_fw_volume_a);
49 
50 		/* Construct fw volume B */
51 		uuid_guid_octets_from_canonical(&partition_guid, REF_PARTITION_2_GUID);
52 
53 		result = block_volume_init(&m_block_volume_b, m_block_store, &partition_guid,
54 					   &m_fw_volume_b);
55 
56 		LONGS_EQUAL(0, result);
57 		CHECK_TRUE(m_fw_volume_b);
58 
59 		/* Prepare an image_info structure to describe the image to
60 		 * install into one of volumes.
61 		 */
62 		uuid_guid_octets_from_canonical(&m_image_info.img_type_uuid,
63 						"1c22ca2c-9732-49e6-ba3b-eed40e27fda3");
64 
65 		m_image_info.max_size =
66 			(REF_PARTITION_1_ENDING_LBA - REF_PARTITION_1_STARTING_LBA + 1) *
67 			REF_PARTITION_BLOCK_SIZE;
68 		m_image_info.lowest_accepted_version = 1;
69 		m_image_info.active_version = 1;
70 		m_image_info.permissions = 0;
71 		m_image_info.image_index = 0;
72 		m_image_info.location_id = FW_STORE_LOCATION_ID;
73 		m_image_info.install_type = INSTALL_TYPE_WHOLE_VOLUME;
74 
75 		/* Mimic a platform configuration where storage volumes are assigned
76 		 * location and usage IDs. These usage IDs correspond to an A/B banked
77 		 * firmware store.
78 		 */
79 		volume_index_add(banked_volume_id(FW_STORE_LOCATION_ID, BANKED_USAGE_ID_FW_BANK_A),
80 				 m_fw_volume_a);
81 		volume_index_add(banked_volume_id(FW_STORE_LOCATION_ID, BANKED_USAGE_ID_FW_BANK_B),
82 				 m_fw_volume_b);
83 
84 		/* A platform configuration will also determine which installers are
85 		 * assigned to which locations. For these tests, there is a raw_installer
86 		 * to install the initial image and a copy_installer to install a copy
87 		 * into the other bank.
88 		 */
89 		raw_installer_init(&m_raw_installer, &m_image_info.img_type_uuid,
90 				   FW_STORE_LOCATION_ID);
91 		installer_index_register(&m_raw_installer.base_installer);
92 
93 		copy_installer_init(&m_copy_installer, &m_image_info.img_type_uuid,
94 				    FW_STORE_LOCATION_ID);
95 		installer_index_register(&m_copy_installer.base_installer);
96 	}
97 
98 	void teardown()
99 	{
100 		delete[] m_image;
101 
102 		raw_installer_deinit(&m_raw_installer);
103 		copy_installer_deinit(&m_copy_installer);
104 
105 		installer_index_clear();
106 		volume_index_clear();
107 
108 		block_volume_deinit(&m_block_volume_a);
109 		block_volume_deinit(&m_block_volume_b);
110 		ref_ram_gpt_block_store_factory_destroy(m_block_store);
111 	}
112 
113 	void create_image(size_t len)
114 	{
115 		m_image = new uint8_t[len];
116 		m_image_len = len;
117 
118 		for (size_t i = 0; i < len; i++)
119 			m_image[i] = (uint8_t)rand();
120 	}
121 
122 	void install_initial_image(size_t len)
123 	{
124 		create_image(len);
125 
126 		/* Expect to find a suitable installer for the given image_info */
127 		struct installer *installer =
128 			installer_index_find(m_image_info.install_type, m_image_info.location_id);
129 		CHECK_TRUE(installer);
130 		UNSIGNED_LONGS_EQUAL(FW_STORE_LOCATION_ID, installer->location_id);
131 
132 		/* Begin installation transaction - installing into volume A */
133 		int status = installer_begin(
134 			installer,
135 			banked_volume_id(FW_STORE_LOCATION_ID,
136 					 BANKED_USAGE_ID_FW_BANK_B), /* Current volume */
137 			banked_volume_id(FW_STORE_LOCATION_ID,
138 					 BANKED_USAGE_ID_FW_BANK_A)); /* Update volume */
139 		LONGS_EQUAL(0, status);
140 
141 		status = installer_open(installer, &m_image_info);
142 		LONGS_EQUAL(0, status);
143 
144 		status = installer_write(installer, m_image, m_image_len);
145 		LONGS_EQUAL(0, status);
146 
147 		status = installer_commit(installer);
148 		LONGS_EQUAL(0, status);
149 
150 		status = installer_finalize(installer);
151 		LONGS_EQUAL(0, status);
152 
153 		check_update_installed(m_fw_volume_a);
154 	}
155 
156 	void check_update_installed(struct volume * volume)
157 	{
158 		int status = 0;
159 		size_t total_read = 0;
160 
161 		status = volume_open(volume);
162 		LONGS_EQUAL(0, status);
163 
164 		while (total_read < m_image_len) {
165 			uint8_t read_buf[1000];
166 			size_t len_read = 0;
167 			size_t bytes_remaining = m_image_len - total_read;
168 			size_t req_len = (bytes_remaining > sizeof(read_buf)) ? sizeof(read_buf) :
169 										bytes_remaining;
170 
171 			memset(read_buf, 0, sizeof(read_buf));
172 
173 			status = volume_read(volume, (uintptr_t)read_buf, req_len, &len_read);
174 			LONGS_EQUAL(0, status);
175 			UNSIGNED_LONGS_EQUAL(req_len, len_read);
176 
177 			MEMCMP_EQUAL(&m_image[total_read], read_buf, len_read);
178 
179 			total_read += len_read;
180 		}
181 
182 		status = volume_close(volume);
183 		LONGS_EQUAL(0, status);
184 	}
185 
186 	static const unsigned int FW_STORE_LOCATION_ID = 0x100;
187 
188 	struct block_store *m_block_store;
189 	struct block_volume m_block_volume_a;
190 	struct block_volume m_block_volume_b;
191 	struct volume *m_fw_volume_a;
192 	struct volume *m_fw_volume_b;
193 	struct raw_installer m_raw_installer;
194 	struct copy_installer m_copy_installer;
195 	struct image_info m_image_info;
196 	uint8_t *m_image;
197 	size_t m_image_len;
198 };
199 
TEST(FwuCopyInstallerTests,installAndCopy)200 TEST(FwuCopyInstallerTests, installAndCopy)
201 {
202 	/* Install an arbitrary size image into bank A */
203 	install_initial_image(13011);
204 
205 	/* Expect to find a suitable copy installer */
206 	struct installer *installer =
207 		installer_index_find(INSTALL_TYPE_WHOLE_VOLUME_COPY, FW_STORE_LOCATION_ID);
208 	CHECK_TRUE(installer);
209 	UNSIGNED_LONGS_EQUAL(FW_STORE_LOCATION_ID, installer->location_id);
210 
211 	/* Begin installation transaction - installing into volume B */
212 	int status =
213 		installer_begin(installer,
214 				banked_volume_id(FW_STORE_LOCATION_ID,
215 						 BANKED_USAGE_ID_FW_BANK_A), /* Current volume */
216 				banked_volume_id(FW_STORE_LOCATION_ID,
217 						 BANKED_USAGE_ID_FW_BANK_B)); /* Update volume */
218 	LONGS_EQUAL(0, status);
219 
220 	/* Finalize the installation -  the copy should happen here */
221 	status = installer_finalize(installer);
222 	LONGS_EQUAL(0, status);
223 
224 	/* Expect volume B to contain a copy of what's in volume A */
225 	check_update_installed(m_fw_volume_b);
226 }
227