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