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
849cfb138SRiya Dixit #include <phosphor-logging/lg2.hpp>
91630f399STom Joseph #include <xyz/openbmc_project/Common/error.hpp>
101630f399STom Joseph
111630f399STom Joseph #include <memory>
121630f399STom Joseph
1349cfb138SRiya Dixit PHOSPHOR_LOG2_USING;
1449cfb138SRiya Dixit
151630f399STom Joseph namespace pldm
161630f399STom Joseph {
171630f399STom Joseph
181630f399STom Joseph namespace fw_update
191630f399STom Joseph {
201630f399STom Joseph
211630f399STom Joseph using InternalFailure =
221630f399STom Joseph sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
231630f399STom Joseph
parseFDIdentificationArea(DeviceIDRecordCount deviceIdRecCount,const std::vector<uint8_t> & pkgHdr,size_t offset)241630f399STom Joseph size_t PackageParser::parseFDIdentificationArea(
251630f399STom Joseph DeviceIDRecordCount deviceIdRecCount, const std::vector<uint8_t>& pkgHdr,
261630f399STom Joseph size_t offset)
271630f399STom Joseph {
281630f399STom Joseph size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
291630f399STom Joseph
301630f399STom Joseph while (deviceIdRecCount-- && (pkgHdrRemainingSize > 0))
311630f399STom Joseph {
321630f399STom Joseph pldm_firmware_device_id_record deviceIdRecHeader{};
331630f399STom Joseph variable_field applicableComponents{};
341630f399STom Joseph variable_field compImageSetVersionStr{};
351630f399STom Joseph variable_field recordDescriptors{};
361630f399STom Joseph variable_field fwDevicePkgData{};
371630f399STom Joseph
381630f399STom Joseph auto rc = decode_firmware_device_id_record(
391630f399STom Joseph pkgHdr.data() + offset, pkgHdrRemainingSize,
401630f399STom Joseph componentBitmapBitLength, &deviceIdRecHeader, &applicableComponents,
411630f399STom Joseph &compImageSetVersionStr, &recordDescriptors, &fwDevicePkgData);
421630f399STom Joseph if (rc)
431630f399STom Joseph {
4476f2c60aSRiya Dixit error(
4576f2c60aSRiya Dixit "Failed to decode firmware device ID record, response code '{RC}'",
4676f2c60aSRiya Dixit "RC", 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 {
6249cfb138SRiya Dixit error(
6376f2c60aSRiya Dixit "Failed to decode descriptor type value of type '{TYPE}' and length '{LENGTH}', response code '{RC}'",
6476f2c60aSRiya Dixit "TYPE", descriptorType, "LENGTH", recordDescriptors.length,
6549cfb138SRiya Dixit "RC", rc);
661630f399STom Joseph throw InternalFailure();
671630f399STom Joseph }
681630f399STom Joseph
691630f399STom Joseph if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
701630f399STom Joseph {
711630f399STom Joseph descriptors.emplace(
721630f399STom Joseph descriptorType,
731630f399STom Joseph DescriptorData{descriptorData.ptr,
741630f399STom Joseph descriptorData.ptr + descriptorData.length});
751630f399STom Joseph }
761630f399STom Joseph else
771630f399STom Joseph {
781630f399STom Joseph uint8_t descTitleStrType = 0;
791630f399STom Joseph variable_field descTitleStr{};
801630f399STom Joseph variable_field vendorDefinedDescData{};
811630f399STom Joseph
821630f399STom Joseph rc = decode_vendor_defined_descriptor_value(
831630f399STom Joseph descriptorData.ptr, descriptorData.length,
841630f399STom Joseph &descTitleStrType, &descTitleStr, &vendorDefinedDescData);
851630f399STom Joseph if (rc)
861630f399STom Joseph {
8749cfb138SRiya Dixit error(
8876f2c60aSRiya Dixit "Failed to decode vendor-defined descriptor value of type '{TYPE}' and length '{LENGTH}', response code '{RC}'",
8976f2c60aSRiya Dixit "TYPE", descriptorType, "LENGTH",
9076f2c60aSRiya Dixit recordDescriptors.length, "RC", rc);
911630f399STom Joseph throw InternalFailure();
921630f399STom Joseph }
931630f399STom Joseph
941630f399STom Joseph descriptors.emplace(
951630f399STom Joseph descriptorType,
961630f399STom Joseph std::make_tuple(utils::toString(descTitleStr),
971630f399STom Joseph VendorDefinedDescriptorData{
981630f399STom Joseph vendorDefinedDescData.ptr,
991630f399STom Joseph vendorDefinedDescData.ptr +
1001630f399STom Joseph vendorDefinedDescData.length}));
1011630f399STom Joseph }
1021630f399STom Joseph
1031630f399STom Joseph auto nextDescriptorOffset =
1041630f399STom Joseph sizeof(pldm_descriptor_tlv().descriptor_type) +
1051630f399STom Joseph sizeof(pldm_descriptor_tlv().descriptor_length) +
1061630f399STom Joseph descriptorData.length;
1071630f399STom Joseph recordDescriptors.ptr += nextDescriptorOffset;
1081630f399STom Joseph recordDescriptors.length -= nextDescriptorOffset;
1091630f399STom Joseph }
1101630f399STom Joseph
1111630f399STom Joseph DeviceUpdateOptionFlags deviceUpdateOptionFlags =
1121630f399STom Joseph deviceIdRecHeader.device_update_option_flags.value;
1131630f399STom Joseph
1141630f399STom Joseph ApplicableComponents componentsList;
1151630f399STom Joseph
1161630f399STom Joseph for (size_t varBitfieldIdx = 0;
1171630f399STom Joseph varBitfieldIdx < applicableComponents.length; varBitfieldIdx++)
1181630f399STom Joseph {
1191630f399STom Joseph std::bitset<8> entry{*(applicableComponents.ptr + varBitfieldIdx)};
1201630f399STom Joseph for (size_t idx = 0; idx < entry.size(); idx++)
1211630f399STom Joseph {
1221630f399STom Joseph if (entry[idx])
1231630f399STom Joseph {
1241630f399STom Joseph componentsList.emplace_back(
1251630f399STom Joseph idx + (varBitfieldIdx * entry.size()));
1261630f399STom Joseph }
1271630f399STom Joseph }
1281630f399STom Joseph }
1291630f399STom Joseph
1301630f399STom Joseph fwDeviceIDRecords.emplace_back(std::make_tuple(
1311630f399STom Joseph deviceUpdateOptionFlags, componentsList,
1321630f399STom Joseph utils::toString(compImageSetVersionStr), std::move(descriptors),
133*16c2a0a0SPatrick Williams FirmwareDevicePackageData{
134*16c2a0a0SPatrick Williams fwDevicePkgData.ptr,
135*16c2a0a0SPatrick Williams fwDevicePkgData.ptr + fwDevicePkgData.length}));
1361630f399STom Joseph offset += deviceIdRecHeader.record_length;
1371630f399STom Joseph pkgHdrRemainingSize -= deviceIdRecHeader.record_length;
1381630f399STom Joseph }
1391630f399STom Joseph
1401630f399STom Joseph return offset;
1411630f399STom Joseph }
1421630f399STom Joseph
parseCompImageInfoArea(ComponentImageCount compImageCount,const std::vector<uint8_t> & pkgHdr,size_t offset)1431630f399STom Joseph size_t PackageParser::parseCompImageInfoArea(ComponentImageCount compImageCount,
1441630f399STom Joseph const std::vector<uint8_t>& pkgHdr,
1451630f399STom Joseph size_t offset)
1461630f399STom Joseph {
1471630f399STom Joseph size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
1481630f399STom Joseph
1491630f399STom Joseph while (compImageCount-- && (pkgHdrRemainingSize > 0))
1501630f399STom Joseph {
1511630f399STom Joseph pldm_component_image_information compImageInfo{};
1521630f399STom Joseph variable_field compVersion{};
1531630f399STom Joseph
154*16c2a0a0SPatrick Williams auto rc = decode_pldm_comp_image_info(
155*16c2a0a0SPatrick Williams pkgHdr.data() + offset, pkgHdrRemainingSize, &compImageInfo,
156*16c2a0a0SPatrick Williams &compVersion);
1571630f399STom Joseph if (rc)
1581630f399STom Joseph {
15976f2c60aSRiya Dixit error(
16076f2c60aSRiya Dixit "Failed to decode component image information, response code '{RC}'",
16176f2c60aSRiya Dixit "RC", rc);
1621630f399STom Joseph throw InternalFailure();
1631630f399STom Joseph }
1641630f399STom Joseph
1651630f399STom Joseph CompClassification compClassification =
1661630f399STom Joseph compImageInfo.comp_classification;
1671630f399STom Joseph CompIdentifier compIdentifier = compImageInfo.comp_identifier;
1681630f399STom Joseph CompComparisonStamp compComparisonTime =
1691630f399STom Joseph compImageInfo.comp_comparison_stamp;
1701630f399STom Joseph CompOptions compOptions = compImageInfo.comp_options.value;
1711630f399STom Joseph ReqCompActivationMethod reqCompActivationMethod =
1721630f399STom Joseph compImageInfo.requested_comp_activation_method.value;
1731630f399STom Joseph CompLocationOffset compLocationOffset =
1741630f399STom Joseph compImageInfo.comp_location_offset;
1751630f399STom Joseph CompSize compSize = compImageInfo.comp_size;
1761630f399STom Joseph
1771630f399STom Joseph componentImageInfos.emplace_back(std::make_tuple(
1781630f399STom Joseph compClassification, compIdentifier, compComparisonTime, compOptions,
1791630f399STom Joseph reqCompActivationMethod, compLocationOffset, compSize,
1801630f399STom Joseph utils::toString(compVersion)));
1811630f399STom Joseph offset += sizeof(pldm_component_image_information) +
1821630f399STom Joseph compImageInfo.comp_version_string_length;
1831630f399STom Joseph pkgHdrRemainingSize -= sizeof(pldm_component_image_information) +
1841630f399STom Joseph compImageInfo.comp_version_string_length;
1851630f399STom Joseph }
1861630f399STom Joseph
1871630f399STom Joseph return offset;
1881630f399STom Joseph }
1891630f399STom Joseph
validatePkgTotalSize(uintmax_t pkgSize)1901630f399STom Joseph void PackageParser::validatePkgTotalSize(uintmax_t pkgSize)
1911630f399STom Joseph {
1921630f399STom Joseph uintmax_t calcPkgSize = pkgHeaderSize;
1931630f399STom Joseph for (const auto& componentImageInfo : componentImageInfos)
1941630f399STom Joseph {
1951630f399STom Joseph CompLocationOffset compLocOffset = std::get<static_cast<size_t>(
1961630f399STom Joseph ComponentImageInfoPos::CompLocationOffsetPos)>(componentImageInfo);
1971630f399STom Joseph CompSize compSize =
1981630f399STom Joseph std::get<static_cast<size_t>(ComponentImageInfoPos::CompSizePos)>(
1991630f399STom Joseph componentImageInfo);
2001630f399STom Joseph
2011630f399STom Joseph if (compLocOffset != calcPkgSize)
2021630f399STom Joseph {
20349cfb138SRiya Dixit auto cmpVersion = std::get<static_cast<size_t>(
20449cfb138SRiya Dixit ComponentImageInfoPos::CompVersionPos)>(componentImageInfo);
20549cfb138SRiya Dixit error(
20676f2c60aSRiya Dixit "Failed to validate the component location offset '{OFFSET}' for version '{COMPONENT_VERSION}' and package size '{SIZE}'",
20776f2c60aSRiya Dixit "OFFSET", compLocOffset, "COMPONENT_VERSION", cmpVersion,
20876f2c60aSRiya Dixit "SIZE", calcPkgSize);
2091630f399STom Joseph throw InternalFailure();
2101630f399STom Joseph }
2111630f399STom Joseph
2121630f399STom Joseph calcPkgSize += compSize;
2131630f399STom Joseph }
2141630f399STom Joseph
2151630f399STom Joseph if (calcPkgSize != pkgSize)
2161630f399STom Joseph {
21749cfb138SRiya Dixit error(
21876f2c60aSRiya Dixit "Failed to match package size '{PKG_SIZE}' to calculated package size '{CALCULATED_PACKAGE_SIZE}'.",
21976f2c60aSRiya Dixit "PKG_SIZE", pkgSize, "CALCULATED_PACKAGE_SIZE", calcPkgSize);
2201630f399STom Joseph throw InternalFailure();
2211630f399STom Joseph }
2221630f399STom Joseph }
2231630f399STom Joseph
parse(const std::vector<uint8_t> & pkgHdr,uintmax_t pkgSize)2241630f399STom Joseph void PackageParserV1::parse(const std::vector<uint8_t>& pkgHdr,
2251630f399STom Joseph uintmax_t pkgSize)
2261630f399STom Joseph {
2271630f399STom Joseph if (pkgHeaderSize != pkgHdr.size())
2281630f399STom Joseph {
22976f2c60aSRiya Dixit error("Invalid package header size '{PKG_HDR_SIZE}' ", "PKG_HDR_SIZE",
23076f2c60aSRiya Dixit pkgHeaderSize);
2311630f399STom Joseph throw InternalFailure();
2321630f399STom Joseph }
2331630f399STom Joseph
2341630f399STom Joseph size_t offset = sizeof(pldm_package_header_information) + pkgVersion.size();
2351630f399STom Joseph if (offset + sizeof(DeviceIDRecordCount) >= pkgHeaderSize)
2361630f399STom Joseph {
23776f2c60aSRiya Dixit error("Failed to parse package header of size '{PKG_HDR_SIZE}'",
23849cfb138SRiya Dixit "PKG_HDR_SIZE", pkgHeaderSize);
2391630f399STom Joseph throw InternalFailure();
2401630f399STom Joseph }
2411630f399STom Joseph
2421630f399STom Joseph auto deviceIdRecCount = static_cast<DeviceIDRecordCount>(pkgHdr[offset]);
2431630f399STom Joseph offset += sizeof(DeviceIDRecordCount);
2441630f399STom Joseph
2451630f399STom Joseph offset = parseFDIdentificationArea(deviceIdRecCount, pkgHdr, offset);
2461630f399STom Joseph if (deviceIdRecCount != fwDeviceIDRecords.size())
2471630f399STom Joseph {
24876f2c60aSRiya Dixit error("Failed to find DeviceIDRecordCount {DREC_CNT} entries",
24949cfb138SRiya Dixit "DREC_CNT", deviceIdRecCount);
2501630f399STom Joseph throw InternalFailure();
2511630f399STom Joseph }
2521630f399STom Joseph if (offset + sizeof(ComponentImageCount) >= pkgHeaderSize)
2531630f399STom Joseph {
25476f2c60aSRiya Dixit error("Failed to parsing package header of size '{PKG_HDR_SIZE}'",
25549cfb138SRiya Dixit "PKG_HDR_SIZE", pkgHeaderSize);
2561630f399STom Joseph throw InternalFailure();
2571630f399STom Joseph }
2581630f399STom Joseph
2591630f399STom Joseph auto compImageCount = static_cast<ComponentImageCount>(
2601630f399STom Joseph le16toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8)));
2611630f399STom Joseph offset += sizeof(ComponentImageCount);
2621630f399STom Joseph
2631630f399STom Joseph offset = parseCompImageInfoArea(compImageCount, pkgHdr, offset);
2641630f399STom Joseph if (compImageCount != componentImageInfos.size())
2651630f399STom Joseph {
26676f2c60aSRiya Dixit error("Failed to find ComponentImageCount '{COMP_IMG_CNT}' entries",
26749cfb138SRiya Dixit "COMP_IMG_CNT", compImageCount);
2681630f399STom Joseph throw InternalFailure();
2691630f399STom Joseph }
2701630f399STom Joseph
2711630f399STom Joseph if (offset + sizeof(PackageHeaderChecksum) != pkgHeaderSize)
2721630f399STom Joseph {
27376f2c60aSRiya Dixit error("Failed to parse package header of size '{PKG_HDR_SIZE}'",
27449cfb138SRiya Dixit "PKG_HDR_SIZE", pkgHeaderSize);
2751630f399STom Joseph throw InternalFailure();
2761630f399STom Joseph }
2771630f399STom Joseph
2781630f399STom Joseph auto calcChecksum = crc32(pkgHdr.data(), offset);
2791630f399STom Joseph auto checksum = static_cast<PackageHeaderChecksum>(
2801630f399STom Joseph le32toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8) |
2811630f399STom Joseph (pkgHdr[offset + 2] << 16) | (pkgHdr[offset + 3] << 24)));
2821630f399STom Joseph if (calcChecksum != checksum)
2831630f399STom Joseph {
28449cfb138SRiya Dixit error(
28576f2c60aSRiya Dixit "Failed to parse package header for calculated checksum '{CALCULATED_CHECKSUM}' and header checksum '{PACKAGE_HEADER_CHECKSUM}'",
28676f2c60aSRiya Dixit "CALCULATED_CHECKSUM", calcChecksum, "PACKAGE_HEADER_CHECKSUM",
28776f2c60aSRiya Dixit checksum);
2881630f399STom Joseph throw InternalFailure();
2891630f399STom Joseph }
2901630f399STom Joseph
2911630f399STom Joseph validatePkgTotalSize(pkgSize);
2921630f399STom Joseph }
2931630f399STom Joseph
parsePkgHeader(std::vector<uint8_t> & pkgData)2941630f399STom Joseph std::unique_ptr<PackageParser> parsePkgHeader(std::vector<uint8_t>& pkgData)
2951630f399STom Joseph {
2961630f399STom Joseph constexpr std::array<uint8_t, PLDM_FWUP_UUID_LENGTH> hdrIdentifierv1{
2971630f399STom Joseph 0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43,
2981630f399STom Joseph 0x98, 0x00, 0xA0, 0x2F, 0x05, 0x9A, 0xCA, 0x02};
2991630f399STom Joseph constexpr uint8_t pkgHdrVersion1 = 0x01;
3001630f399STom Joseph
3011630f399STom Joseph pldm_package_header_information pkgHeader{};
3021630f399STom Joseph variable_field pkgVersion{};
3031630f399STom Joseph auto rc = decode_pldm_package_header_info(pkgData.data(), pkgData.size(),
3041630f399STom Joseph &pkgHeader, &pkgVersion);
3051630f399STom Joseph if (rc)
3061630f399STom Joseph {
30776f2c60aSRiya Dixit error(
30876f2c60aSRiya Dixit "Failed to decode PLDM package header information, response code '{RC}'",
30976f2c60aSRiya Dixit "RC", rc);
3101630f399STom Joseph return nullptr;
3111630f399STom Joseph }
3121630f399STom Joseph
3131630f399STom Joseph if (std::equal(pkgHeader.uuid, pkgHeader.uuid + PLDM_FWUP_UUID_LENGTH,
3141630f399STom Joseph hdrIdentifierv1.begin(), hdrIdentifierv1.end()) &&
3151630f399STom Joseph (pkgHeader.package_header_format_version == pkgHdrVersion1))
3161630f399STom Joseph {
3171630f399STom Joseph PackageHeaderSize pkgHdrSize = pkgHeader.package_header_size;
3181630f399STom Joseph ComponentBitmapBitLength componentBitmapBitLength =
3191630f399STom Joseph pkgHeader.component_bitmap_bit_length;
3201630f399STom Joseph return std::make_unique<PackageParserV1>(
3211630f399STom Joseph pkgHdrSize, utils::toString(pkgVersion), componentBitmapBitLength);
3221630f399STom Joseph }
3231630f399STom Joseph
3241630f399STom Joseph return nullptr;
3251630f399STom Joseph }
3261630f399STom Joseph
3271630f399STom Joseph } // namespace fw_update
3281630f399STom Joseph
3291630f399STom Joseph } // namespace pldm
330