blob: ddc82d60731028dcf82689d9fb85cd9b6bbb4533 [file] [log] [blame]
Tom Joseph1630f392021-06-29 04:30:03 -07001#include "package_parser.hpp"
2
Tom Joseph1630f392021-06-29 04:30:03 -07003#include "common/utils.hpp"
4
George Liuc453e162022-12-21 17:16:23 +08005#include <libpldm/firmware_update.h>
6#include <libpldm/utils.h>
7
Riya Dixit49cfb132023-03-02 04:26:53 -06008#include <phosphor-logging/lg2.hpp>
Tom Joseph1630f392021-06-29 04:30:03 -07009#include <xyz/openbmc_project/Common/error.hpp>
10
11#include <iostream>
12#include <memory>
13
Riya Dixit49cfb132023-03-02 04:26:53 -060014PHOSPHOR_LOG2_USING;
15
Tom Joseph1630f392021-06-29 04:30:03 -070016namespace pldm
17{
18
19namespace fw_update
20{
21
22using InternalFailure =
23 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
24
25size_t PackageParser::parseFDIdentificationArea(
26 DeviceIDRecordCount deviceIdRecCount, const std::vector<uint8_t>& pkgHdr,
27 size_t offset)
28{
29 size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
30
31 while (deviceIdRecCount-- && (pkgHdrRemainingSize > 0))
32 {
33 pldm_firmware_device_id_record deviceIdRecHeader{};
34 variable_field applicableComponents{};
35 variable_field compImageSetVersionStr{};
36 variable_field recordDescriptors{};
37 variable_field fwDevicePkgData{};
38
39 auto rc = decode_firmware_device_id_record(
40 pkgHdr.data() + offset, pkgHdrRemainingSize,
41 componentBitmapBitLength, &deviceIdRecHeader, &applicableComponents,
42 &compImageSetVersionStr, &recordDescriptors, &fwDevicePkgData);
43 if (rc)
44 {
Riya Dixit49cfb132023-03-02 04:26:53 -060045 error("Decoding firmware device ID record failed, RC={RC}", "RC",
46 rc);
Tom Joseph1630f392021-06-29 04:30:03 -070047 throw InternalFailure();
48 }
49
50 Descriptors descriptors{};
51 while (deviceIdRecHeader.descriptor_count-- &&
52 (recordDescriptors.length > 0))
53 {
54 uint16_t descriptorType = 0;
55 variable_field descriptorData{};
56
57 rc = decode_descriptor_type_length_value(
58 recordDescriptors.ptr, recordDescriptors.length,
59 &descriptorType, &descriptorData);
60 if (rc)
61 {
Riya Dixit49cfb132023-03-02 04:26:53 -060062 error(
63 "Decoding descriptor type, length and value failed, RC={RC}",
64 "RC", rc);
Tom Joseph1630f392021-06-29 04:30:03 -070065 throw InternalFailure();
66 }
67
68 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
69 {
70 descriptors.emplace(
71 descriptorType,
72 DescriptorData{descriptorData.ptr,
73 descriptorData.ptr + descriptorData.length});
74 }
75 else
76 {
77 uint8_t descTitleStrType = 0;
78 variable_field descTitleStr{};
79 variable_field vendorDefinedDescData{};
80
81 rc = decode_vendor_defined_descriptor_value(
82 descriptorData.ptr, descriptorData.length,
83 &descTitleStrType, &descTitleStr, &vendorDefinedDescData);
84 if (rc)
85 {
Riya Dixit49cfb132023-03-02 04:26:53 -060086 error(
87 "Decoding Vendor-defined descriptor value failed, RC={RC}",
88 "RC", rc);
Tom Joseph1630f392021-06-29 04:30:03 -070089 throw InternalFailure();
90 }
91
92 descriptors.emplace(
93 descriptorType,
94 std::make_tuple(utils::toString(descTitleStr),
95 VendorDefinedDescriptorData{
96 vendorDefinedDescData.ptr,
97 vendorDefinedDescData.ptr +
98 vendorDefinedDescData.length}));
99 }
100
101 auto nextDescriptorOffset =
102 sizeof(pldm_descriptor_tlv().descriptor_type) +
103 sizeof(pldm_descriptor_tlv().descriptor_length) +
104 descriptorData.length;
105 recordDescriptors.ptr += nextDescriptorOffset;
106 recordDescriptors.length -= nextDescriptorOffset;
107 }
108
109 DeviceUpdateOptionFlags deviceUpdateOptionFlags =
110 deviceIdRecHeader.device_update_option_flags.value;
111
112 ApplicableComponents componentsList;
113
114 for (size_t varBitfieldIdx = 0;
115 varBitfieldIdx < applicableComponents.length; varBitfieldIdx++)
116 {
117 std::bitset<8> entry{*(applicableComponents.ptr + varBitfieldIdx)};
118 for (size_t idx = 0; idx < entry.size(); idx++)
119 {
120 if (entry[idx])
121 {
122 componentsList.emplace_back(
123 idx + (varBitfieldIdx * entry.size()));
124 }
125 }
126 }
127
128 fwDeviceIDRecords.emplace_back(std::make_tuple(
129 deviceUpdateOptionFlags, componentsList,
130 utils::toString(compImageSetVersionStr), std::move(descriptors),
131 FirmwareDevicePackageData{fwDevicePkgData.ptr,
132 fwDevicePkgData.ptr +
133 fwDevicePkgData.length}));
134 offset += deviceIdRecHeader.record_length;
135 pkgHdrRemainingSize -= deviceIdRecHeader.record_length;
136 }
137
138 return offset;
139}
140
141size_t PackageParser::parseCompImageInfoArea(ComponentImageCount compImageCount,
142 const std::vector<uint8_t>& pkgHdr,
143 size_t offset)
144{
145 size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
146
147 while (compImageCount-- && (pkgHdrRemainingSize > 0))
148 {
149 pldm_component_image_information compImageInfo{};
150 variable_field compVersion{};
151
152 auto rc = decode_pldm_comp_image_info(pkgHdr.data() + offset,
153 pkgHdrRemainingSize,
154 &compImageInfo, &compVersion);
155 if (rc)
156 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600157 error("Decoding component image information failed, RC={RC}", "RC",
158 rc);
Tom Joseph1630f392021-06-29 04:30:03 -0700159 throw InternalFailure();
160 }
161
162 CompClassification compClassification =
163 compImageInfo.comp_classification;
164 CompIdentifier compIdentifier = compImageInfo.comp_identifier;
165 CompComparisonStamp compComparisonTime =
166 compImageInfo.comp_comparison_stamp;
167 CompOptions compOptions = compImageInfo.comp_options.value;
168 ReqCompActivationMethod reqCompActivationMethod =
169 compImageInfo.requested_comp_activation_method.value;
170 CompLocationOffset compLocationOffset =
171 compImageInfo.comp_location_offset;
172 CompSize compSize = compImageInfo.comp_size;
173
174 componentImageInfos.emplace_back(std::make_tuple(
175 compClassification, compIdentifier, compComparisonTime, compOptions,
176 reqCompActivationMethod, compLocationOffset, compSize,
177 utils::toString(compVersion)));
178 offset += sizeof(pldm_component_image_information) +
179 compImageInfo.comp_version_string_length;
180 pkgHdrRemainingSize -= sizeof(pldm_component_image_information) +
181 compImageInfo.comp_version_string_length;
182 }
183
184 return offset;
185}
186
187void PackageParser::validatePkgTotalSize(uintmax_t pkgSize)
188{
189 uintmax_t calcPkgSize = pkgHeaderSize;
190 for (const auto& componentImageInfo : componentImageInfos)
191 {
192 CompLocationOffset compLocOffset = std::get<static_cast<size_t>(
193 ComponentImageInfoPos::CompLocationOffsetPos)>(componentImageInfo);
194 CompSize compSize =
195 std::get<static_cast<size_t>(ComponentImageInfoPos::CompSizePos)>(
196 componentImageInfo);
197
198 if (compLocOffset != calcPkgSize)
199 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600200 auto cmpVersion = std::get<static_cast<size_t>(
201 ComponentImageInfoPos::CompVersionPos)>(componentImageInfo);
202 error(
203 "Validating the component location offset failed, COMP_VERSION={COMP_VERS}",
204 "COMP_VERS", cmpVersion);
Tom Joseph1630f392021-06-29 04:30:03 -0700205 throw InternalFailure();
206 }
207
208 calcPkgSize += compSize;
209 }
210
211 if (calcPkgSize != pkgSize)
212 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600213 error(
214 "Package size does not match calculated package size, PKG_SIZE={PKG_SIZE}, CALC_PKG_SIZE={CAL_PKG_SIZE}",
215 "PKG_SIZE", pkgSize, "CAL_PKG_SIZE", calcPkgSize);
Tom Joseph1630f392021-06-29 04:30:03 -0700216 throw InternalFailure();
217 }
218}
219
220void PackageParserV1::parse(const std::vector<uint8_t>& pkgHdr,
221 uintmax_t pkgSize)
222{
223 if (pkgHeaderSize != pkgHdr.size())
224 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600225 error("Package header size is invalid, PKG_HDR_SIZE={PKG_HDR_SIZE}",
226 "PKG_HDR_SIZE", pkgHeaderSize);
Tom Joseph1630f392021-06-29 04:30:03 -0700227 throw InternalFailure();
228 }
229
230 size_t offset = sizeof(pldm_package_header_information) + pkgVersion.size();
231 if (offset + sizeof(DeviceIDRecordCount) >= pkgHeaderSize)
232 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600233 error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
234 "PKG_HDR_SIZE", pkgHeaderSize);
Tom Joseph1630f392021-06-29 04:30:03 -0700235 throw InternalFailure();
236 }
237
238 auto deviceIdRecCount = static_cast<DeviceIDRecordCount>(pkgHdr[offset]);
239 offset += sizeof(DeviceIDRecordCount);
240
241 offset = parseFDIdentificationArea(deviceIdRecCount, pkgHdr, offset);
242 if (deviceIdRecCount != fwDeviceIDRecords.size())
243 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600244 error(
245 "DeviceIDRecordCount entries not found, DEVICE_ID_REC_COUNT={DREC_CNT}",
246 "DREC_CNT", deviceIdRecCount);
Tom Joseph1630f392021-06-29 04:30:03 -0700247 throw InternalFailure();
248 }
249 if (offset + sizeof(ComponentImageCount) >= pkgHeaderSize)
250 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600251 error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
252 "PKG_HDR_SIZE", pkgHeaderSize);
Tom Joseph1630f392021-06-29 04:30:03 -0700253 throw InternalFailure();
254 }
255
256 auto compImageCount = static_cast<ComponentImageCount>(
257 le16toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8)));
258 offset += sizeof(ComponentImageCount);
259
260 offset = parseCompImageInfoArea(compImageCount, pkgHdr, offset);
261 if (compImageCount != componentImageInfos.size())
262 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600263 error(
264 "ComponentImageCount entries not found, COMP_IMAGE_COUNT={COMP_IMG_CNT}",
265 "COMP_IMG_CNT", compImageCount);
Tom Joseph1630f392021-06-29 04:30:03 -0700266 throw InternalFailure();
267 }
268
269 if (offset + sizeof(PackageHeaderChecksum) != pkgHeaderSize)
270 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600271 error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
272 "PKG_HDR_SIZE", pkgHeaderSize);
Tom Joseph1630f392021-06-29 04:30:03 -0700273 throw InternalFailure();
274 }
275
276 auto calcChecksum = crc32(pkgHdr.data(), offset);
277 auto checksum = static_cast<PackageHeaderChecksum>(
278 le32toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8) |
279 (pkgHdr[offset + 2] << 16) | (pkgHdr[offset + 3] << 24)));
280 if (calcChecksum != checksum)
281 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600282 error(
283 "Parsing package header failed, CALC_CHECKSUM={CHK_SUM}, PKG_HDR_CHECKSUM={PKG_HDR_CHK_SUM}",
284 "CHK_SUM", calcChecksum, "PKG_HDR_CHK_SUM", checksum);
Tom Joseph1630f392021-06-29 04:30:03 -0700285 throw InternalFailure();
286 }
287
288 validatePkgTotalSize(pkgSize);
289}
290
291std::unique_ptr<PackageParser> parsePkgHeader(std::vector<uint8_t>& pkgData)
292{
293 constexpr std::array<uint8_t, PLDM_FWUP_UUID_LENGTH> hdrIdentifierv1{
294 0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43,
295 0x98, 0x00, 0xA0, 0x2F, 0x05, 0x9A, 0xCA, 0x02};
296 constexpr uint8_t pkgHdrVersion1 = 0x01;
297
298 pldm_package_header_information pkgHeader{};
299 variable_field pkgVersion{};
300 auto rc = decode_pldm_package_header_info(pkgData.data(), pkgData.size(),
301 &pkgHeader, &pkgVersion);
302 if (rc)
303 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600304 error("Decoding PLDM package header information failed, RC={RC}", "RC",
305 rc);
Tom Joseph1630f392021-06-29 04:30:03 -0700306 return nullptr;
307 }
308
309 if (std::equal(pkgHeader.uuid, pkgHeader.uuid + PLDM_FWUP_UUID_LENGTH,
310 hdrIdentifierv1.begin(), hdrIdentifierv1.end()) &&
311 (pkgHeader.package_header_format_version == pkgHdrVersion1))
312 {
313 PackageHeaderSize pkgHdrSize = pkgHeader.package_header_size;
314 ComponentBitmapBitLength componentBitmapBitLength =
315 pkgHeader.component_bitmap_bit_length;
316 return std::make_unique<PackageParserV1>(
317 pkgHdrSize, utils::toString(pkgVersion), componentBitmapBitLength);
318 }
319
320 return nullptr;
321}
322
323} // namespace fw_update
324
Patrick Williams6da4f912023-05-10 07:50:53 -0500325} // namespace pldm