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