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 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 { 44*76f2c60aSRiya Dixit error( 45*76f2c60aSRiya Dixit "Failed to decode firmware device ID record, response code '{RC}'", 46*76f2c60aSRiya 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( 63*76f2c60aSRiya Dixit "Failed to decode descriptor type value of type '{TYPE}' and length '{LENGTH}', response code '{RC}'", 64*76f2c60aSRiya 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( 88*76f2c60aSRiya Dixit "Failed to decode vendor-defined descriptor value of type '{TYPE}' and length '{LENGTH}', response code '{RC}'", 89*76f2c60aSRiya Dixit "TYPE", descriptorType, "LENGTH", 90*76f2c60aSRiya 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), 1331630f399STom Joseph FirmwareDevicePackageData{fwDevicePkgData.ptr, 1341630f399STom Joseph fwDevicePkgData.ptr + 1351630f399STom Joseph 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 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 1541630f399STom Joseph auto rc = decode_pldm_comp_image_info(pkgHdr.data() + offset, 1551630f399STom Joseph pkgHdrRemainingSize, 1561630f399STom Joseph &compImageInfo, &compVersion); 1571630f399STom Joseph if (rc) 1581630f399STom Joseph { 159*76f2c60aSRiya Dixit error( 160*76f2c60aSRiya Dixit "Failed to decode component image information, response code '{RC}'", 161*76f2c60aSRiya 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 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( 206*76f2c60aSRiya Dixit "Failed to validate the component location offset '{OFFSET}' for version '{COMPONENT_VERSION}' and package size '{SIZE}'", 207*76f2c60aSRiya Dixit "OFFSET", compLocOffset, "COMPONENT_VERSION", cmpVersion, 208*76f2c60aSRiya 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( 218*76f2c60aSRiya Dixit "Failed to match package size '{PKG_SIZE}' to calculated package size '{CALCULATED_PACKAGE_SIZE}'.", 219*76f2c60aSRiya Dixit "PKG_SIZE", pkgSize, "CALCULATED_PACKAGE_SIZE", calcPkgSize); 2201630f399STom Joseph throw InternalFailure(); 2211630f399STom Joseph } 2221630f399STom Joseph } 2231630f399STom Joseph 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 { 229*76f2c60aSRiya Dixit error("Invalid package header size '{PKG_HDR_SIZE}' ", "PKG_HDR_SIZE", 230*76f2c60aSRiya 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 { 237*76f2c60aSRiya 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 { 248*76f2c60aSRiya 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 { 254*76f2c60aSRiya 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 { 266*76f2c60aSRiya 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 { 273*76f2c60aSRiya 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( 285*76f2c60aSRiya Dixit "Failed to parse package header for calculated checksum '{CALCULATED_CHECKSUM}' and header checksum '{PACKAGE_HEADER_CHECKSUM}'", 286*76f2c60aSRiya Dixit "CALCULATED_CHECKSUM", calcChecksum, "PACKAGE_HEADER_CHECKSUM", 287*76f2c60aSRiya Dixit checksum); 2881630f399STom Joseph throw InternalFailure(); 2891630f399STom Joseph } 2901630f399STom Joseph 2911630f399STom Joseph validatePkgTotalSize(pkgSize); 2921630f399STom Joseph } 2931630f399STom Joseph 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 { 307*76f2c60aSRiya Dixit error( 308*76f2c60aSRiya Dixit "Failed to decode PLDM package header information, response code '{RC}'", 309*76f2c60aSRiya 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