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