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