blob: 7269d42f28d40677244b95ea6beb987c19e2e065 [file] [log] [blame]
Alexander Hansen00b3cae2024-11-26 17:32:33 +01001#include "package_parser.hpp"
2
3#include <libpldm/firmware_update.h>
4#include <libpldm/utils.h>
5
6#include <phosphor-logging/lg2.hpp>
7#include <xyz/openbmc_project/Common/error.hpp>
8
9#include <memory>
10
Alexander Hansen00b3cae2024-11-26 17:32:33 +010011using namespace std;
12
13PHOSPHOR_LOG2_USING;
14
15namespace pldm
16{
17
18namespace utils
19{
20
21std::string toString(const struct variable_field& var)
22{
23 if (var.ptr == nullptr || !var.length)
24 {
25 return "";
26 }
27
28 std::string str(reinterpret_cast<const char*>(var.ptr), var.length);
29 std::replace_if(
30 str.begin(), str.end(), [](const char& c) { return !isprint(c); }, ' ');
31 return str;
32}
33
34} // namespace utils
35
36namespace fw_update
37{
38
39using InternalFailure =
40 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
41
42size_t PackageParser::parseFDIdentificationArea(
43 DeviceIDRecordCount deviceIdRecCount, const std::vector<uint8_t>& pkgHdr,
44 size_t offset)
45{
46 size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
47
48 while (deviceIdRecCount-- && (pkgHdrRemainingSize > 0))
49 {
50 pldm_firmware_device_id_record deviceIdRecHeader{};
51 variable_field applicableComponents{};
52 variable_field compImageSetVersionStr{};
53 variable_field recordDescriptors{};
54 variable_field fwDevicePkgData{};
55
56 auto rc = decode_firmware_device_id_record(
57 pkgHdr.data() + offset, pkgHdrRemainingSize,
58 componentBitmapBitLength, &deviceIdRecHeader, &applicableComponents,
59 &compImageSetVersionStr, &recordDescriptors, &fwDevicePkgData);
60 if (rc)
61 {
62 error(
63 "Failed to decode firmware device ID record, response code '{RC}'",
64 "RC", rc);
65 throw InternalFailure();
66 }
67
68 Descriptors descriptors{};
69 while (deviceIdRecHeader.descriptor_count-- &&
70 (recordDescriptors.length > 0))
71 {
72 uint16_t descriptorType = 0;
73 variable_field descriptorData{};
74
75 rc = decode_descriptor_type_length_value(
76 recordDescriptors.ptr, recordDescriptors.length,
77 &descriptorType, &descriptorData);
78 if (rc)
79 {
80 error(
81 "Failed to decode descriptor type value of type '{TYPE}' and length '{LENGTH}', response code '{RC}'",
82 "TYPE", descriptorType, "LENGTH", recordDescriptors.length,
83 "RC", rc);
84 throw InternalFailure();
85 }
86
87 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
88 {
89 descriptors.emplace(
90 descriptorType,
91 DescriptorData{descriptorData.ptr,
92 descriptorData.ptr + descriptorData.length});
93 }
94 else
95 {
96 uint8_t descTitleStrType = 0;
97 variable_field descTitleStr{};
98 variable_field vendorDefinedDescData{};
99
100 rc = decode_vendor_defined_descriptor_value(
101 descriptorData.ptr, descriptorData.length,
102 &descTitleStrType, &descTitleStr, &vendorDefinedDescData);
103 if (rc)
104 {
105 error(
106 "Failed to decode vendor-defined descriptor value of type '{TYPE}' and length '{LENGTH}', response code '{RC}'",
107 "TYPE", descriptorType, "LENGTH",
108 recordDescriptors.length, "RC", rc);
109 throw InternalFailure();
110 }
111
112 descriptors.emplace(
113 descriptorType,
114 std::make_tuple(utils::toString(descTitleStr),
115 VendorDefinedDescriptorData{
116 vendorDefinedDescData.ptr,
117 vendorDefinedDescData.ptr +
118 vendorDefinedDescData.length}));
119 }
120
121 auto nextDescriptorOffset =
122 sizeof(pldm_descriptor_tlv().descriptor_type) +
123 sizeof(pldm_descriptor_tlv().descriptor_length) +
124 descriptorData.length;
125 recordDescriptors.ptr += nextDescriptorOffset;
126 recordDescriptors.length -= nextDescriptorOffset;
127 }
128
129 DeviceUpdateOptionFlags deviceUpdateOptionFlags =
130 deviceIdRecHeader.device_update_option_flags.value;
131
132 ApplicableComponents componentsList;
133
134 for (size_t varBitfieldIdx = 0;
135 varBitfieldIdx < applicableComponents.length; varBitfieldIdx++)
136 {
137 std::bitset<8> entry{*(applicableComponents.ptr + varBitfieldIdx)};
138 for (size_t idx = 0; idx < entry.size(); idx++)
139 {
140 if (entry[idx])
141 {
142 componentsList.emplace_back(
143 idx + (varBitfieldIdx * entry.size()));
144 }
145 }
146 }
147
148 fwDeviceIDRecords.emplace_back(std::make_tuple(
149 deviceUpdateOptionFlags, componentsList,
150 utils::toString(compImageSetVersionStr), std::move(descriptors),
151 FirmwareDevicePackageData{
152 fwDevicePkgData.ptr,
153 fwDevicePkgData.ptr + fwDevicePkgData.length}));
154 offset += deviceIdRecHeader.record_length;
155 pkgHdrRemainingSize -= deviceIdRecHeader.record_length;
156 }
157
158 return offset;
159}
160
161size_t PackageParser::parseCompImageInfoArea(ComponentImageCount compImageCount,
162 const std::vector<uint8_t>& pkgHdr,
163 size_t offset)
164{
165 size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
166
167 while (compImageCount-- && (pkgHdrRemainingSize > 0))
168 {
169 pldm_component_image_information compImageInfo{};
170 variable_field compVersion{};
171
172 auto rc = decode_pldm_comp_image_info(
173 pkgHdr.data() + offset, pkgHdrRemainingSize, &compImageInfo,
174 &compVersion);
175 if (rc)
176 {
177 error(
178 "Failed to decode component image information, response code '{RC}'",
179 "RC", rc);
180 throw InternalFailure();
181 }
182
183 CompClassification compClassification =
184 compImageInfo.comp_classification;
185 CompIdentifier compIdentifier = compImageInfo.comp_identifier;
186 CompComparisonStamp compComparisonTime =
187 compImageInfo.comp_comparison_stamp;
188 CompOptions compOptions = compImageInfo.comp_options.value;
189 ReqCompActivationMethod reqCompActivationMethod =
190 compImageInfo.requested_comp_activation_method.value;
191 CompLocationOffset compLocationOffset =
192 compImageInfo.comp_location_offset;
193 CompSize compSize = compImageInfo.comp_size;
194
195 componentImageInfos.emplace_back(std::make_tuple(
196 compClassification, compIdentifier, compComparisonTime, compOptions,
197 reqCompActivationMethod, compLocationOffset, compSize,
198 utils::toString(compVersion)));
199 offset += sizeof(pldm_component_image_information) +
200 compImageInfo.comp_version_string_length;
201 pkgHdrRemainingSize -= sizeof(pldm_component_image_information) +
202 compImageInfo.comp_version_string_length;
203 }
204
205 return offset;
206}
207
208void PackageParser::validatePkgTotalSize(uintmax_t pkgSize)
209{
210 uintmax_t calcPkgSize = pkgHeaderSize;
211 for (const auto& componentImageInfo : componentImageInfos)
212 {
213 CompLocationOffset compLocOffset = std::get<static_cast<size_t>(
214 ComponentImageInfoPos::CompLocationOffsetPos)>(componentImageInfo);
215 CompSize compSize =
216 std::get<static_cast<size_t>(ComponentImageInfoPos::CompSizePos)>(
217 componentImageInfo);
218
219 if (compLocOffset != calcPkgSize)
220 {
221 auto cmpVersion = std::get<static_cast<size_t>(
222 ComponentImageInfoPos::CompVersionPos)>(componentImageInfo);
223 error(
224 "Failed to validate the component location offset '{OFFSET}' for version '{COMPONENT_VERSION}' and package size '{SIZE}'",
225 "OFFSET", compLocOffset, "COMPONENT_VERSION", cmpVersion,
226 "SIZE", calcPkgSize);
227 throw InternalFailure();
228 }
229
230 calcPkgSize += compSize;
231 }
232
233 if (calcPkgSize != pkgSize)
234 {
235 error(
236 "Failed to match package size '{PKG_SIZE}' to calculated package size '{CALCULATED_PACKAGE_SIZE}'.",
237 "PKG_SIZE", pkgSize, "CALCULATED_PACKAGE_SIZE", calcPkgSize);
238 throw InternalFailure();
239 }
240}
241
242void PackageParserV1::parse(const std::vector<uint8_t>& pkgHdr,
243 uintmax_t pkgSize)
244{
Alexander Hansen692d67e2025-06-17 11:24:39 +0200245 if (pkgHeaderSize >= pkgHdr.size())
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100246 {
247 error("Invalid package header size '{PKG_HDR_SIZE}' ", "PKG_HDR_SIZE",
248 pkgHeaderSize);
249 throw InternalFailure();
250 }
251
252 size_t offset = sizeof(pldm_package_header_information) + pkgVersion.size();
253 if (offset + sizeof(DeviceIDRecordCount) >= pkgHeaderSize)
254 {
255 error("Failed to parse package header of size '{PKG_HDR_SIZE}'",
256 "PKG_HDR_SIZE", pkgHeaderSize);
257 throw InternalFailure();
258 }
259
260 auto deviceIdRecCount = static_cast<DeviceIDRecordCount>(pkgHdr[offset]);
261 offset += sizeof(DeviceIDRecordCount);
262
263 offset = parseFDIdentificationArea(deviceIdRecCount, pkgHdr, offset);
264 if (deviceIdRecCount != fwDeviceIDRecords.size())
265 {
266 error("Failed to find DeviceIDRecordCount {DREC_CNT} entries",
267 "DREC_CNT", deviceIdRecCount);
268 throw InternalFailure();
269 }
270 if (offset + sizeof(ComponentImageCount) >= pkgHeaderSize)
271 {
272 error("Failed to parsing package header of size '{PKG_HDR_SIZE}'",
273 "PKG_HDR_SIZE", pkgHeaderSize);
274 throw InternalFailure();
275 }
276
277 auto compImageCount = static_cast<ComponentImageCount>(
278 le16toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8)));
279 offset += sizeof(ComponentImageCount);
280
281 offset = parseCompImageInfoArea(compImageCount, pkgHdr, offset);
282 if (compImageCount != componentImageInfos.size())
283 {
284 error("Failed to find ComponentImageCount '{COMP_IMG_CNT}' entries",
285 "COMP_IMG_CNT", compImageCount);
286 throw InternalFailure();
287 }
288
289 if (offset + sizeof(PackageHeaderChecksum) != pkgHeaderSize)
290 {
291 error("Failed to parse package header of size '{PKG_HDR_SIZE}'",
292 "PKG_HDR_SIZE", pkgHeaderSize);
293 throw InternalFailure();
294 }
295
Andrew Jeffery0bb36ee2025-04-05 21:48:18 +1030296 auto calcChecksum = pldm_edac_crc32(pkgHdr.data(), offset);
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100297 auto checksum = static_cast<PackageHeaderChecksum>(
298 le32toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8) |
299 (pkgHdr[offset + 2] << 16) | (pkgHdr[offset + 3] << 24)));
300 if (calcChecksum != checksum)
301 {
302 error(
303 "Failed to parse package header for calculated checksum '{CALCULATED_CHECKSUM}' and header checksum '{PACKAGE_HEADER_CHECKSUM}'",
304 "CALCULATED_CHECKSUM", calcChecksum, "PACKAGE_HEADER_CHECKSUM",
305 checksum);
306 throw InternalFailure();
307 }
308
309 validatePkgTotalSize(pkgSize);
310}
311
312std::unique_ptr<PackageParser> parsePackageHeader(std::vector<uint8_t>& pkgData)
313{
314 constexpr std::array<uint8_t, PLDM_FWUP_UUID_LENGTH> hdrIdentifierv1{
315 0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43,
316 0x98, 0x00, 0xA0, 0x2F, 0x05, 0x9A, 0xCA, 0x02};
317 constexpr uint8_t pkgHdrVersion1 = 0x01;
318
319 pldm_package_header_information pkgHeader{};
320 variable_field pkgVersion{};
321 auto rc = decode_pldm_package_header_info(pkgData.data(), pkgData.size(),
322 &pkgHeader, &pkgVersion);
323 if (rc)
324 {
325 error(
326 "Failed to decode PLDM package header information, response code '{RC}'",
327 "RC", rc);
328 return nullptr;
329 }
330
331 if (std::equal(pkgHeader.uuid, pkgHeader.uuid + PLDM_FWUP_UUID_LENGTH,
332 hdrIdentifierv1.begin(), hdrIdentifierv1.end()) &&
333 (pkgHeader.package_header_format_version == pkgHdrVersion1))
334 {
335 PackageHeaderSize pkgHdrSize = pkgHeader.package_header_size;
336 ComponentBitmapBitLength componentBitmapBitLength =
337 pkgHeader.component_bitmap_bit_length;
338 return std::make_unique<PackageParserV1>(
339 pkgHdrSize, utils::toString(pkgVersion), componentBitmapBitLength);
340 }
341
342 return nullptr;
343}
344
345} // namespace fw_update
346
347} // namespace pldm