xref: /openbmc/pldm/fw-update/package_parser.cpp (revision 49cfb138af156020599361584b20c9ed591eeeb6)
11630f399STom Joseph #include "package_parser.hpp"
21630f399STom Joseph 
31630f399STom Joseph #include "common/utils.hpp"
41630f399STom Joseph 
5c453e164SGeorge Liu #include <libpldm/firmware_update.h>
6c453e164SGeorge Liu #include <libpldm/utils.h>
7c453e164SGeorge Liu 
8*49cfb138SRiya Dixit #include <phosphor-logging/lg2.hpp>
91630f399STom Joseph #include <xyz/openbmc_project/Common/error.hpp>
101630f399STom Joseph 
111630f399STom Joseph #include <iostream>
121630f399STom Joseph #include <memory>
131630f399STom Joseph 
14*49cfb138SRiya Dixit PHOSPHOR_LOG2_USING;
15*49cfb138SRiya Dixit 
161630f399STom Joseph namespace pldm
171630f399STom Joseph {
181630f399STom Joseph 
191630f399STom Joseph namespace fw_update
201630f399STom Joseph {
211630f399STom Joseph 
221630f399STom Joseph using InternalFailure =
231630f399STom Joseph     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
241630f399STom Joseph 
251630f399STom Joseph size_t PackageParser::parseFDIdentificationArea(
261630f399STom Joseph     DeviceIDRecordCount deviceIdRecCount, const std::vector<uint8_t>& pkgHdr,
271630f399STom Joseph     size_t offset)
281630f399STom Joseph {
291630f399STom Joseph     size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
301630f399STom Joseph 
311630f399STom Joseph     while (deviceIdRecCount-- && (pkgHdrRemainingSize > 0))
321630f399STom Joseph     {
331630f399STom Joseph         pldm_firmware_device_id_record deviceIdRecHeader{};
341630f399STom Joseph         variable_field applicableComponents{};
351630f399STom Joseph         variable_field compImageSetVersionStr{};
361630f399STom Joseph         variable_field recordDescriptors{};
371630f399STom Joseph         variable_field fwDevicePkgData{};
381630f399STom Joseph 
391630f399STom Joseph         auto rc = decode_firmware_device_id_record(
401630f399STom Joseph             pkgHdr.data() + offset, pkgHdrRemainingSize,
411630f399STom Joseph             componentBitmapBitLength, &deviceIdRecHeader, &applicableComponents,
421630f399STom Joseph             &compImageSetVersionStr, &recordDescriptors, &fwDevicePkgData);
431630f399STom Joseph         if (rc)
441630f399STom Joseph         {
45*49cfb138SRiya Dixit             error("Decoding firmware device ID record failed, RC={RC}", "RC",
46*49cfb138SRiya Dixit                   rc);
471630f399STom Joseph             throw InternalFailure();
481630f399STom Joseph         }
491630f399STom Joseph 
501630f399STom Joseph         Descriptors descriptors{};
511630f399STom Joseph         while (deviceIdRecHeader.descriptor_count-- &&
521630f399STom Joseph                (recordDescriptors.length > 0))
531630f399STom Joseph         {
541630f399STom Joseph             uint16_t descriptorType = 0;
551630f399STom Joseph             variable_field descriptorData{};
561630f399STom Joseph 
571630f399STom Joseph             rc = decode_descriptor_type_length_value(
581630f399STom Joseph                 recordDescriptors.ptr, recordDescriptors.length,
591630f399STom Joseph                 &descriptorType, &descriptorData);
601630f399STom Joseph             if (rc)
611630f399STom Joseph             {
62*49cfb138SRiya Dixit                 error(
63*49cfb138SRiya Dixit                     "Decoding descriptor type, length and value failed, RC={RC}",
64*49cfb138SRiya Dixit                     "RC", rc);
651630f399STom Joseph                 throw InternalFailure();
661630f399STom Joseph             }
671630f399STom Joseph 
681630f399STom Joseph             if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
691630f399STom Joseph             {
701630f399STom Joseph                 descriptors.emplace(
711630f399STom Joseph                     descriptorType,
721630f399STom Joseph                     DescriptorData{descriptorData.ptr,
731630f399STom Joseph                                    descriptorData.ptr + descriptorData.length});
741630f399STom Joseph             }
751630f399STom Joseph             else
761630f399STom Joseph             {
771630f399STom Joseph                 uint8_t descTitleStrType = 0;
781630f399STom Joseph                 variable_field descTitleStr{};
791630f399STom Joseph                 variable_field vendorDefinedDescData{};
801630f399STom Joseph 
811630f399STom Joseph                 rc = decode_vendor_defined_descriptor_value(
821630f399STom Joseph                     descriptorData.ptr, descriptorData.length,
831630f399STom Joseph                     &descTitleStrType, &descTitleStr, &vendorDefinedDescData);
841630f399STom Joseph                 if (rc)
851630f399STom Joseph                 {
86*49cfb138SRiya Dixit                     error(
87*49cfb138SRiya Dixit                         "Decoding Vendor-defined descriptor value failed, RC={RC}",
88*49cfb138SRiya Dixit                         "RC", rc);
891630f399STom Joseph                     throw InternalFailure();
901630f399STom Joseph                 }
911630f399STom Joseph 
921630f399STom Joseph                 descriptors.emplace(
931630f399STom Joseph                     descriptorType,
941630f399STom Joseph                     std::make_tuple(utils::toString(descTitleStr),
951630f399STom Joseph                                     VendorDefinedDescriptorData{
961630f399STom Joseph                                         vendorDefinedDescData.ptr,
971630f399STom Joseph                                         vendorDefinedDescData.ptr +
981630f399STom Joseph                                             vendorDefinedDescData.length}));
991630f399STom Joseph             }
1001630f399STom Joseph 
1011630f399STom Joseph             auto nextDescriptorOffset =
1021630f399STom Joseph                 sizeof(pldm_descriptor_tlv().descriptor_type) +
1031630f399STom Joseph                 sizeof(pldm_descriptor_tlv().descriptor_length) +
1041630f399STom Joseph                 descriptorData.length;
1051630f399STom Joseph             recordDescriptors.ptr += nextDescriptorOffset;
1061630f399STom Joseph             recordDescriptors.length -= nextDescriptorOffset;
1071630f399STom Joseph         }
1081630f399STom Joseph 
1091630f399STom Joseph         DeviceUpdateOptionFlags deviceUpdateOptionFlags =
1101630f399STom Joseph             deviceIdRecHeader.device_update_option_flags.value;
1111630f399STom Joseph 
1121630f399STom Joseph         ApplicableComponents componentsList;
1131630f399STom Joseph 
1141630f399STom Joseph         for (size_t varBitfieldIdx = 0;
1151630f399STom Joseph              varBitfieldIdx < applicableComponents.length; varBitfieldIdx++)
1161630f399STom Joseph         {
1171630f399STom Joseph             std::bitset<8> entry{*(applicableComponents.ptr + varBitfieldIdx)};
1181630f399STom Joseph             for (size_t idx = 0; idx < entry.size(); idx++)
1191630f399STom Joseph             {
1201630f399STom Joseph                 if (entry[idx])
1211630f399STom Joseph                 {
1221630f399STom Joseph                     componentsList.emplace_back(
1231630f399STom Joseph                         idx + (varBitfieldIdx * entry.size()));
1241630f399STom Joseph                 }
1251630f399STom Joseph             }
1261630f399STom Joseph         }
1271630f399STom Joseph 
1281630f399STom Joseph         fwDeviceIDRecords.emplace_back(std::make_tuple(
1291630f399STom Joseph             deviceUpdateOptionFlags, componentsList,
1301630f399STom Joseph             utils::toString(compImageSetVersionStr), std::move(descriptors),
1311630f399STom Joseph             FirmwareDevicePackageData{fwDevicePkgData.ptr,
1321630f399STom Joseph                                       fwDevicePkgData.ptr +
1331630f399STom Joseph                                           fwDevicePkgData.length}));
1341630f399STom Joseph         offset += deviceIdRecHeader.record_length;
1351630f399STom Joseph         pkgHdrRemainingSize -= deviceIdRecHeader.record_length;
1361630f399STom Joseph     }
1371630f399STom Joseph 
1381630f399STom Joseph     return offset;
1391630f399STom Joseph }
1401630f399STom Joseph 
1411630f399STom Joseph size_t PackageParser::parseCompImageInfoArea(ComponentImageCount compImageCount,
1421630f399STom Joseph                                              const std::vector<uint8_t>& pkgHdr,
1431630f399STom Joseph                                              size_t offset)
1441630f399STom Joseph {
1451630f399STom Joseph     size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
1461630f399STom Joseph 
1471630f399STom Joseph     while (compImageCount-- && (pkgHdrRemainingSize > 0))
1481630f399STom Joseph     {
1491630f399STom Joseph         pldm_component_image_information compImageInfo{};
1501630f399STom Joseph         variable_field compVersion{};
1511630f399STom Joseph 
1521630f399STom Joseph         auto rc = decode_pldm_comp_image_info(pkgHdr.data() + offset,
1531630f399STom Joseph                                               pkgHdrRemainingSize,
1541630f399STom Joseph                                               &compImageInfo, &compVersion);
1551630f399STom Joseph         if (rc)
1561630f399STom Joseph         {
157*49cfb138SRiya Dixit             error("Decoding component image information failed, RC={RC}", "RC",
158*49cfb138SRiya Dixit                   rc);
1591630f399STom Joseph             throw InternalFailure();
1601630f399STom Joseph         }
1611630f399STom Joseph 
1621630f399STom Joseph         CompClassification compClassification =
1631630f399STom Joseph             compImageInfo.comp_classification;
1641630f399STom Joseph         CompIdentifier compIdentifier = compImageInfo.comp_identifier;
1651630f399STom Joseph         CompComparisonStamp compComparisonTime =
1661630f399STom Joseph             compImageInfo.comp_comparison_stamp;
1671630f399STom Joseph         CompOptions compOptions = compImageInfo.comp_options.value;
1681630f399STom Joseph         ReqCompActivationMethod reqCompActivationMethod =
1691630f399STom Joseph             compImageInfo.requested_comp_activation_method.value;
1701630f399STom Joseph         CompLocationOffset compLocationOffset =
1711630f399STom Joseph             compImageInfo.comp_location_offset;
1721630f399STom Joseph         CompSize compSize = compImageInfo.comp_size;
1731630f399STom Joseph 
1741630f399STom Joseph         componentImageInfos.emplace_back(std::make_tuple(
1751630f399STom Joseph             compClassification, compIdentifier, compComparisonTime, compOptions,
1761630f399STom Joseph             reqCompActivationMethod, compLocationOffset, compSize,
1771630f399STom Joseph             utils::toString(compVersion)));
1781630f399STom Joseph         offset += sizeof(pldm_component_image_information) +
1791630f399STom Joseph                   compImageInfo.comp_version_string_length;
1801630f399STom Joseph         pkgHdrRemainingSize -= sizeof(pldm_component_image_information) +
1811630f399STom Joseph                                compImageInfo.comp_version_string_length;
1821630f399STom Joseph     }
1831630f399STom Joseph 
1841630f399STom Joseph     return offset;
1851630f399STom Joseph }
1861630f399STom Joseph 
1871630f399STom Joseph void PackageParser::validatePkgTotalSize(uintmax_t pkgSize)
1881630f399STom Joseph {
1891630f399STom Joseph     uintmax_t calcPkgSize = pkgHeaderSize;
1901630f399STom Joseph     for (const auto& componentImageInfo : componentImageInfos)
1911630f399STom Joseph     {
1921630f399STom Joseph         CompLocationOffset compLocOffset = std::get<static_cast<size_t>(
1931630f399STom Joseph             ComponentImageInfoPos::CompLocationOffsetPos)>(componentImageInfo);
1941630f399STom Joseph         CompSize compSize =
1951630f399STom Joseph             std::get<static_cast<size_t>(ComponentImageInfoPos::CompSizePos)>(
1961630f399STom Joseph                 componentImageInfo);
1971630f399STom Joseph 
1981630f399STom Joseph         if (compLocOffset != calcPkgSize)
1991630f399STom Joseph         {
200*49cfb138SRiya Dixit             auto cmpVersion = std::get<static_cast<size_t>(
201*49cfb138SRiya Dixit                 ComponentImageInfoPos::CompVersionPos)>(componentImageInfo);
202*49cfb138SRiya Dixit             error(
203*49cfb138SRiya Dixit                 "Validating the component location offset failed, COMP_VERSION={COMP_VERS}",
204*49cfb138SRiya Dixit                 "COMP_VERS", cmpVersion);
2051630f399STom Joseph             throw InternalFailure();
2061630f399STom Joseph         }
2071630f399STom Joseph 
2081630f399STom Joseph         calcPkgSize += compSize;
2091630f399STom Joseph     }
2101630f399STom Joseph 
2111630f399STom Joseph     if (calcPkgSize != pkgSize)
2121630f399STom Joseph     {
213*49cfb138SRiya Dixit         error(
214*49cfb138SRiya Dixit             "Package size does not match calculated package size, PKG_SIZE={PKG_SIZE}, CALC_PKG_SIZE={CAL_PKG_SIZE}",
215*49cfb138SRiya Dixit             "PKG_SIZE", pkgSize, "CAL_PKG_SIZE", calcPkgSize);
2161630f399STom Joseph         throw InternalFailure();
2171630f399STom Joseph     }
2181630f399STom Joseph }
2191630f399STom Joseph 
2201630f399STom Joseph void PackageParserV1::parse(const std::vector<uint8_t>& pkgHdr,
2211630f399STom Joseph                             uintmax_t pkgSize)
2221630f399STom Joseph {
2231630f399STom Joseph     if (pkgHeaderSize != pkgHdr.size())
2241630f399STom Joseph     {
225*49cfb138SRiya Dixit         error("Package header size is invalid, PKG_HDR_SIZE={PKG_HDR_SIZE}",
226*49cfb138SRiya Dixit               "PKG_HDR_SIZE", pkgHeaderSize);
2271630f399STom Joseph         throw InternalFailure();
2281630f399STom Joseph     }
2291630f399STom Joseph 
2301630f399STom Joseph     size_t offset = sizeof(pldm_package_header_information) + pkgVersion.size();
2311630f399STom Joseph     if (offset + sizeof(DeviceIDRecordCount) >= pkgHeaderSize)
2321630f399STom Joseph     {
233*49cfb138SRiya Dixit         error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
234*49cfb138SRiya Dixit               "PKG_HDR_SIZE", pkgHeaderSize);
2351630f399STom Joseph         throw InternalFailure();
2361630f399STom Joseph     }
2371630f399STom Joseph 
2381630f399STom Joseph     auto deviceIdRecCount = static_cast<DeviceIDRecordCount>(pkgHdr[offset]);
2391630f399STom Joseph     offset += sizeof(DeviceIDRecordCount);
2401630f399STom Joseph 
2411630f399STom Joseph     offset = parseFDIdentificationArea(deviceIdRecCount, pkgHdr, offset);
2421630f399STom Joseph     if (deviceIdRecCount != fwDeviceIDRecords.size())
2431630f399STom Joseph     {
244*49cfb138SRiya Dixit         error(
245*49cfb138SRiya Dixit             "DeviceIDRecordCount entries not found, DEVICE_ID_REC_COUNT={DREC_CNT}",
246*49cfb138SRiya Dixit             "DREC_CNT", deviceIdRecCount);
2471630f399STom Joseph         throw InternalFailure();
2481630f399STom Joseph     }
2491630f399STom Joseph     if (offset + sizeof(ComponentImageCount) >= pkgHeaderSize)
2501630f399STom Joseph     {
251*49cfb138SRiya Dixit         error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
252*49cfb138SRiya Dixit               "PKG_HDR_SIZE", pkgHeaderSize);
2531630f399STom Joseph         throw InternalFailure();
2541630f399STom Joseph     }
2551630f399STom Joseph 
2561630f399STom Joseph     auto compImageCount = static_cast<ComponentImageCount>(
2571630f399STom Joseph         le16toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8)));
2581630f399STom Joseph     offset += sizeof(ComponentImageCount);
2591630f399STom Joseph 
2601630f399STom Joseph     offset = parseCompImageInfoArea(compImageCount, pkgHdr, offset);
2611630f399STom Joseph     if (compImageCount != componentImageInfos.size())
2621630f399STom Joseph     {
263*49cfb138SRiya Dixit         error(
264*49cfb138SRiya Dixit             "ComponentImageCount entries not found, COMP_IMAGE_COUNT={COMP_IMG_CNT}",
265*49cfb138SRiya Dixit             "COMP_IMG_CNT", compImageCount);
2661630f399STom Joseph         throw InternalFailure();
2671630f399STom Joseph     }
2681630f399STom Joseph 
2691630f399STom Joseph     if (offset + sizeof(PackageHeaderChecksum) != pkgHeaderSize)
2701630f399STom Joseph     {
271*49cfb138SRiya Dixit         error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
272*49cfb138SRiya Dixit               "PKG_HDR_SIZE", pkgHeaderSize);
2731630f399STom Joseph         throw InternalFailure();
2741630f399STom Joseph     }
2751630f399STom Joseph 
2761630f399STom Joseph     auto calcChecksum = crc32(pkgHdr.data(), offset);
2771630f399STom Joseph     auto checksum = static_cast<PackageHeaderChecksum>(
2781630f399STom Joseph         le32toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8) |
2791630f399STom Joseph                 (pkgHdr[offset + 2] << 16) | (pkgHdr[offset + 3] << 24)));
2801630f399STom Joseph     if (calcChecksum != checksum)
2811630f399STom Joseph     {
282*49cfb138SRiya Dixit         error(
283*49cfb138SRiya Dixit             "Parsing package header failed, CALC_CHECKSUM={CHK_SUM}, PKG_HDR_CHECKSUM={PKG_HDR_CHK_SUM}",
284*49cfb138SRiya Dixit             "CHK_SUM", calcChecksum, "PKG_HDR_CHK_SUM", checksum);
2851630f399STom Joseph         throw InternalFailure();
2861630f399STom Joseph     }
2871630f399STom Joseph 
2881630f399STom Joseph     validatePkgTotalSize(pkgSize);
2891630f399STom Joseph }
2901630f399STom Joseph 
2911630f399STom Joseph std::unique_ptr<PackageParser> parsePkgHeader(std::vector<uint8_t>& pkgData)
2921630f399STom Joseph {
2931630f399STom Joseph     constexpr std::array<uint8_t, PLDM_FWUP_UUID_LENGTH> hdrIdentifierv1{
2941630f399STom Joseph         0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43,
2951630f399STom Joseph         0x98, 0x00, 0xA0, 0x2F, 0x05, 0x9A, 0xCA, 0x02};
2961630f399STom Joseph     constexpr uint8_t pkgHdrVersion1 = 0x01;
2971630f399STom Joseph 
2981630f399STom Joseph     pldm_package_header_information pkgHeader{};
2991630f399STom Joseph     variable_field pkgVersion{};
3001630f399STom Joseph     auto rc = decode_pldm_package_header_info(pkgData.data(), pkgData.size(),
3011630f399STom Joseph                                               &pkgHeader, &pkgVersion);
3021630f399STom Joseph     if (rc)
3031630f399STom Joseph     {
304*49cfb138SRiya Dixit         error("Decoding PLDM package header information failed, RC={RC}", "RC",
305*49cfb138SRiya Dixit               rc);
3061630f399STom Joseph         return nullptr;
3071630f399STom Joseph     }
3081630f399STom Joseph 
3091630f399STom Joseph     if (std::equal(pkgHeader.uuid, pkgHeader.uuid + PLDM_FWUP_UUID_LENGTH,
3101630f399STom Joseph                    hdrIdentifierv1.begin(), hdrIdentifierv1.end()) &&
3111630f399STom Joseph         (pkgHeader.package_header_format_version == pkgHdrVersion1))
3121630f399STom Joseph     {
3131630f399STom Joseph         PackageHeaderSize pkgHdrSize = pkgHeader.package_header_size;
3141630f399STom Joseph         ComponentBitmapBitLength componentBitmapBitLength =
3151630f399STom Joseph             pkgHeader.component_bitmap_bit_length;
3161630f399STom Joseph         return std::make_unique<PackageParserV1>(
3171630f399STom Joseph             pkgHdrSize, utils::toString(pkgVersion), componentBitmapBitLength);
3181630f399STom Joseph     }
3191630f399STom Joseph 
3201630f399STom Joseph     return nullptr;
3211630f399STom Joseph }
3221630f399STom Joseph 
3231630f399STom Joseph } // namespace fw_update
3241630f399STom Joseph 
3251630f399STom Joseph } // namespace pldm