blob: 8454770f00a1a9bd6c21d825baa3a085eb5b3817 [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
Tom Joseph1630f392021-06-29 04:30:03 -070011#include <memory>
12
Riya Dixit49cfb132023-03-02 04:26:53 -060013PHOSPHOR_LOG2_USING;
14
Tom Joseph1630f392021-06-29 04:30:03 -070015namespace pldm
16{
17
18namespace fw_update
19{
20
21using InternalFailure =
22 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23
24size_t PackageParser::parseFDIdentificationArea(
25 DeviceIDRecordCount deviceIdRecCount, const std::vector<uint8_t>& pkgHdr,
26 size_t offset)
27{
28 size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
29
30 while (deviceIdRecCount-- && (pkgHdrRemainingSize > 0))
31 {
32 pldm_firmware_device_id_record deviceIdRecHeader{};
33 variable_field applicableComponents{};
34 variable_field compImageSetVersionStr{};
35 variable_field recordDescriptors{};
36 variable_field fwDevicePkgData{};
37
38 auto rc = decode_firmware_device_id_record(
39 pkgHdr.data() + offset, pkgHdrRemainingSize,
40 componentBitmapBitLength, &deviceIdRecHeader, &applicableComponents,
41 &compImageSetVersionStr, &recordDescriptors, &fwDevicePkgData);
42 if (rc)
43 {
Riya Dixit49cfb132023-03-02 04:26:53 -060044 error("Decoding firmware device ID record failed, RC={RC}", "RC",
45 rc);
Tom Joseph1630f392021-06-29 04:30:03 -070046 throw InternalFailure();
47 }
48
49 Descriptors descriptors{};
50 while (deviceIdRecHeader.descriptor_count-- &&
51 (recordDescriptors.length > 0))
52 {
53 uint16_t descriptorType = 0;
54 variable_field descriptorData{};
55
56 rc = decode_descriptor_type_length_value(
57 recordDescriptors.ptr, recordDescriptors.length,
58 &descriptorType, &descriptorData);
59 if (rc)
60 {
Riya Dixit49cfb132023-03-02 04:26:53 -060061 error(
62 "Decoding descriptor type, length and value failed, RC={RC}",
63 "RC", rc);
Tom Joseph1630f392021-06-29 04:30:03 -070064 throw InternalFailure();
65 }
66
67 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
68 {
69 descriptors.emplace(
70 descriptorType,
71 DescriptorData{descriptorData.ptr,
72 descriptorData.ptr + descriptorData.length});
73 }
74 else
75 {
76 uint8_t descTitleStrType = 0;
77 variable_field descTitleStr{};
78 variable_field vendorDefinedDescData{};
79
80 rc = decode_vendor_defined_descriptor_value(
81 descriptorData.ptr, descriptorData.length,
82 &descTitleStrType, &descTitleStr, &vendorDefinedDescData);
83 if (rc)
84 {
Riya Dixit49cfb132023-03-02 04:26:53 -060085 error(
86 "Decoding Vendor-defined descriptor value failed, RC={RC}",
87 "RC", rc);
Tom Joseph1630f392021-06-29 04:30:03 -070088 throw InternalFailure();
89 }
90
91 descriptors.emplace(
92 descriptorType,
93 std::make_tuple(utils::toString(descTitleStr),
94 VendorDefinedDescriptorData{
95 vendorDefinedDescData.ptr,
96 vendorDefinedDescData.ptr +
97 vendorDefinedDescData.length}));
98 }
99
100 auto nextDescriptorOffset =
101 sizeof(pldm_descriptor_tlv().descriptor_type) +
102 sizeof(pldm_descriptor_tlv().descriptor_length) +
103 descriptorData.length;
104 recordDescriptors.ptr += nextDescriptorOffset;
105 recordDescriptors.length -= nextDescriptorOffset;
106 }
107
108 DeviceUpdateOptionFlags deviceUpdateOptionFlags =
109 deviceIdRecHeader.device_update_option_flags.value;
110
111 ApplicableComponents componentsList;
112
113 for (size_t varBitfieldIdx = 0;
114 varBitfieldIdx < applicableComponents.length; varBitfieldIdx++)
115 {
116 std::bitset<8> entry{*(applicableComponents.ptr + varBitfieldIdx)};
117 for (size_t idx = 0; idx < entry.size(); idx++)
118 {
119 if (entry[idx])
120 {
121 componentsList.emplace_back(
122 idx + (varBitfieldIdx * entry.size()));
123 }
124 }
125 }
126
127 fwDeviceIDRecords.emplace_back(std::make_tuple(
128 deviceUpdateOptionFlags, componentsList,
129 utils::toString(compImageSetVersionStr), std::move(descriptors),
130 FirmwareDevicePackageData{fwDevicePkgData.ptr,
131 fwDevicePkgData.ptr +
132 fwDevicePkgData.length}));
133 offset += deviceIdRecHeader.record_length;
134 pkgHdrRemainingSize -= deviceIdRecHeader.record_length;
135 }
136
137 return offset;
138}
139
140size_t PackageParser::parseCompImageInfoArea(ComponentImageCount compImageCount,
141 const std::vector<uint8_t>& pkgHdr,
142 size_t offset)
143{
144 size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
145
146 while (compImageCount-- && (pkgHdrRemainingSize > 0))
147 {
148 pldm_component_image_information compImageInfo{};
149 variable_field compVersion{};
150
151 auto rc = decode_pldm_comp_image_info(pkgHdr.data() + offset,
152 pkgHdrRemainingSize,
153 &compImageInfo, &compVersion);
154 if (rc)
155 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600156 error("Decoding component image information failed, RC={RC}", "RC",
157 rc);
Tom Joseph1630f392021-06-29 04:30:03 -0700158 throw InternalFailure();
159 }
160
161 CompClassification compClassification =
162 compImageInfo.comp_classification;
163 CompIdentifier compIdentifier = compImageInfo.comp_identifier;
164 CompComparisonStamp compComparisonTime =
165 compImageInfo.comp_comparison_stamp;
166 CompOptions compOptions = compImageInfo.comp_options.value;
167 ReqCompActivationMethod reqCompActivationMethod =
168 compImageInfo.requested_comp_activation_method.value;
169 CompLocationOffset compLocationOffset =
170 compImageInfo.comp_location_offset;
171 CompSize compSize = compImageInfo.comp_size;
172
173 componentImageInfos.emplace_back(std::make_tuple(
174 compClassification, compIdentifier, compComparisonTime, compOptions,
175 reqCompActivationMethod, compLocationOffset, compSize,
176 utils::toString(compVersion)));
177 offset += sizeof(pldm_component_image_information) +
178 compImageInfo.comp_version_string_length;
179 pkgHdrRemainingSize -= sizeof(pldm_component_image_information) +
180 compImageInfo.comp_version_string_length;
181 }
182
183 return offset;
184}
185
186void PackageParser::validatePkgTotalSize(uintmax_t pkgSize)
187{
188 uintmax_t calcPkgSize = pkgHeaderSize;
189 for (const auto& componentImageInfo : componentImageInfos)
190 {
191 CompLocationOffset compLocOffset = std::get<static_cast<size_t>(
192 ComponentImageInfoPos::CompLocationOffsetPos)>(componentImageInfo);
193 CompSize compSize =
194 std::get<static_cast<size_t>(ComponentImageInfoPos::CompSizePos)>(
195 componentImageInfo);
196
197 if (compLocOffset != calcPkgSize)
198 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600199 auto cmpVersion = std::get<static_cast<size_t>(
200 ComponentImageInfoPos::CompVersionPos)>(componentImageInfo);
201 error(
202 "Validating the component location offset failed, COMP_VERSION={COMP_VERS}",
203 "COMP_VERS", cmpVersion);
Tom Joseph1630f392021-06-29 04:30:03 -0700204 throw InternalFailure();
205 }
206
207 calcPkgSize += compSize;
208 }
209
210 if (calcPkgSize != pkgSize)
211 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600212 error(
213 "Package size does not match calculated package size, PKG_SIZE={PKG_SIZE}, CALC_PKG_SIZE={CAL_PKG_SIZE}",
214 "PKG_SIZE", pkgSize, "CAL_PKG_SIZE", calcPkgSize);
Tom Joseph1630f392021-06-29 04:30:03 -0700215 throw InternalFailure();
216 }
217}
218
219void PackageParserV1::parse(const std::vector<uint8_t>& pkgHdr,
220 uintmax_t pkgSize)
221{
222 if (pkgHeaderSize != pkgHdr.size())
223 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600224 error("Package header size is invalid, PKG_HDR_SIZE={PKG_HDR_SIZE}",
225 "PKG_HDR_SIZE", pkgHeaderSize);
Tom Joseph1630f392021-06-29 04:30:03 -0700226 throw InternalFailure();
227 }
228
229 size_t offset = sizeof(pldm_package_header_information) + pkgVersion.size();
230 if (offset + sizeof(DeviceIDRecordCount) >= pkgHeaderSize)
231 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600232 error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
233 "PKG_HDR_SIZE", pkgHeaderSize);
Tom Joseph1630f392021-06-29 04:30:03 -0700234 throw InternalFailure();
235 }
236
237 auto deviceIdRecCount = static_cast<DeviceIDRecordCount>(pkgHdr[offset]);
238 offset += sizeof(DeviceIDRecordCount);
239
240 offset = parseFDIdentificationArea(deviceIdRecCount, pkgHdr, offset);
241 if (deviceIdRecCount != fwDeviceIDRecords.size())
242 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600243 error(
244 "DeviceIDRecordCount entries not found, DEVICE_ID_REC_COUNT={DREC_CNT}",
245 "DREC_CNT", deviceIdRecCount);
Tom Joseph1630f392021-06-29 04:30:03 -0700246 throw InternalFailure();
247 }
248 if (offset + sizeof(ComponentImageCount) >= pkgHeaderSize)
249 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600250 error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
251 "PKG_HDR_SIZE", pkgHeaderSize);
Tom Joseph1630f392021-06-29 04:30:03 -0700252 throw InternalFailure();
253 }
254
255 auto compImageCount = static_cast<ComponentImageCount>(
256 le16toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8)));
257 offset += sizeof(ComponentImageCount);
258
259 offset = parseCompImageInfoArea(compImageCount, pkgHdr, offset);
260 if (compImageCount != componentImageInfos.size())
261 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600262 error(
263 "ComponentImageCount entries not found, COMP_IMAGE_COUNT={COMP_IMG_CNT}",
264 "COMP_IMG_CNT", compImageCount);
Tom Joseph1630f392021-06-29 04:30:03 -0700265 throw InternalFailure();
266 }
267
268 if (offset + sizeof(PackageHeaderChecksum) != pkgHeaderSize)
269 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600270 error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
271 "PKG_HDR_SIZE", pkgHeaderSize);
Tom Joseph1630f392021-06-29 04:30:03 -0700272 throw InternalFailure();
273 }
274
275 auto calcChecksum = crc32(pkgHdr.data(), offset);
276 auto checksum = static_cast<PackageHeaderChecksum>(
277 le32toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8) |
278 (pkgHdr[offset + 2] << 16) | (pkgHdr[offset + 3] << 24)));
279 if (calcChecksum != checksum)
280 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600281 error(
282 "Parsing package header failed, CALC_CHECKSUM={CHK_SUM}, PKG_HDR_CHECKSUM={PKG_HDR_CHK_SUM}",
283 "CHK_SUM", calcChecksum, "PKG_HDR_CHK_SUM", checksum);
Tom Joseph1630f392021-06-29 04:30:03 -0700284 throw InternalFailure();
285 }
286
287 validatePkgTotalSize(pkgSize);
288}
289
290std::unique_ptr<PackageParser> parsePkgHeader(std::vector<uint8_t>& pkgData)
291{
292 constexpr std::array<uint8_t, PLDM_FWUP_UUID_LENGTH> hdrIdentifierv1{
293 0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43,
294 0x98, 0x00, 0xA0, 0x2F, 0x05, 0x9A, 0xCA, 0x02};
295 constexpr uint8_t pkgHdrVersion1 = 0x01;
296
297 pldm_package_header_information pkgHeader{};
298 variable_field pkgVersion{};
299 auto rc = decode_pldm_package_header_info(pkgData.data(), pkgData.size(),
300 &pkgHeader, &pkgVersion);
301 if (rc)
302 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600303 error("Decoding PLDM package header information failed, RC={RC}", "RC",
304 rc);
Tom Joseph1630f392021-06-29 04:30:03 -0700305 return nullptr;
306 }
307
308 if (std::equal(pkgHeader.uuid, pkgHeader.uuid + PLDM_FWUP_UUID_LENGTH,
309 hdrIdentifierv1.begin(), hdrIdentifierv1.end()) &&
310 (pkgHeader.package_header_format_version == pkgHdrVersion1))
311 {
312 PackageHeaderSize pkgHdrSize = pkgHeader.package_header_size;
313 ComponentBitmapBitLength componentBitmapBitLength =
314 pkgHeader.component_bitmap_bit_length;
315 return std::make_unique<PackageParserV1>(
316 pkgHdrSize, utils::toString(pkgVersion), componentBitmapBitLength);
317 }
318
319 return nullptr;
320}
321
322} // namespace fw_update
323
Patrick Williams6da4f912023-05-10 07:50:53 -0500324} // namespace pldm