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