1 #include "pldm_package_util.hpp" 2 3 #include "package_parser.hpp" 4 #include "types.hpp" 5 6 #include <fcntl.h> 7 #include <libpldm/base.h> 8 #include <libpldm/firmware_update.h> 9 #include <libpldm/pldm_types.h> 10 #include <libpldm/utils.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <sys/mman.h> 14 15 #include <phosphor-logging/lg2.hpp> 16 #include <sdbusplus/message/native_types.hpp> 17 18 #include <cassert> 19 #include <cstring> 20 #include <functional> 21 22 PHOSPHOR_LOG2_USING; 23 24 using namespace pldm::fw_update; 25 26 namespace pldm_package_util 27 { 28 29 std::shared_ptr<PackageParser> parsePLDMPackage(const uint8_t* buf, size_t size) 30 { 31 std::vector<uint8_t> pkgData; 32 33 pkgData.reserve(size); 34 for (size_t i = 0; i < size; i++) 35 { 36 pkgData.push_back(buf[i]); 37 } 38 39 debug("parsing package header"); 40 41 std::unique_ptr<PackageParser> packageParser = 42 pldm::fw_update::parsePackageHeader(pkgData); 43 44 if (packageParser == nullptr) 45 { 46 error("could not parse package header"); 47 return packageParser; 48 } 49 50 debug("parsing package, pkg header size: {N}", "N", 51 packageParser->pkgHeaderSize); 52 53 packageParser->parse(pkgData, pkgData.size()); 54 55 return packageParser; 56 } 57 58 int readImagePackage(FILE* file, uint8_t* packageData, const size_t packageSize) 59 { 60 if (file == NULL || packageData == NULL) 61 { 62 return 1; 63 } 64 65 if (packageSize == 0) 66 { 67 error("Package size is 0"); 68 return 1; 69 } 70 71 debug("reading {NBYTES} bytes from file", "NBYTES", packageSize); 72 73 // Read the package into memory 74 if (fread(packageData, 1, packageSize, file) != packageSize) 75 { 76 perror("Failed to read package data"); 77 fclose(file); 78 return 1; 79 } 80 81 return 0; 82 } 83 84 std::unique_ptr<void, std::function<void(void*)>> mmapImagePackage( 85 sdbusplus::message::unix_fd image, size_t* sizeOut) 86 { 87 debug("open fd {FD}", "FD", int(image)); 88 89 off_t size = lseek(image.fd, 0, SEEK_END); 90 91 if (size < 0) 92 { 93 error("failed to determine file size"); 94 perror("error:"); 95 return nullptr; 96 } 97 98 *sizeOut = size; 99 100 debug("file size: {SIZE}", "SIZE", (uint64_t)size); 101 102 void* data = mmap(nullptr, size, PROT_READ, MAP_SHARED, image.fd, 0); 103 104 if (data == MAP_FAILED) 105 { 106 error("could not mmap the image"); 107 return nullptr; 108 } 109 110 using mmapUniquePtr = std::unique_ptr<void, std::function<void(void*)>>; 111 112 mmapUniquePtr dataUnique(data, [size](void* arg) { 113 if (munmap(arg, size) != 0) 114 { 115 error("Failed to un map the PLDM package"); 116 } 117 }); 118 119 return dataUnique; 120 } 121 122 bool fwDeviceIDRecordMatchesCompatible(const FirmwareDeviceIDRecord& record, 123 const std::string& compatible) 124 { 125 Descriptors desc = std::get<3>(record); 126 if (desc.empty()) 127 { 128 return false; 129 } 130 131 if (!desc.contains(0xffff)) 132 { 133 return false; 134 } 135 136 auto v = desc[0xffff]; 137 138 if (!std::holds_alternative<VendorDefinedDescriptorInfo>(v)) 139 { 140 debug("descriptor does not have the vendor defined descriptor info"); 141 return false; 142 } 143 144 auto data = std::get<VendorDefinedDescriptorInfo>(v); 145 146 std::string actualCompatible = std::get<VendorDefinedDescriptorTitle>(data); 147 148 return compatible == actualCompatible; 149 } 150 151 bool fwDeviceIDRecordMatchesIANA(const FirmwareDeviceIDRecord& record, 152 uint32_t vendorIANA) 153 { 154 Descriptors desc = std::get<3>(record); 155 156 if (desc.empty()) 157 { 158 return false; 159 } 160 161 if (!desc.contains(0x1)) 162 { 163 error("did not find iana enterprise id"); 164 return false; 165 } 166 167 auto viana = desc[0x1]; 168 169 if (!std::holds_alternative<DescriptorData>(viana)) 170 { 171 error("did not find iana enterprise id"); 172 return false; 173 } 174 175 const DescriptorData& dd = std::get<DescriptorData>(viana); 176 177 if (dd.size() != 4) 178 { 179 error("descriptor data wrong size ( != 4) for vendor iana"); 180 return false; 181 } 182 183 const uint32_t actualIANA = dd[0] | dd[1] << 8 | dd[2] << 16 | dd[3] << 24; 184 185 return actualIANA == vendorIANA; 186 } 187 188 bool fwDeviceIDRecordMatches(const FirmwareDeviceIDRecord& record, 189 uint32_t vendorIANA, const std::string& compatible) 190 { 191 return fwDeviceIDRecordMatchesIANA(record, vendorIANA) && 192 fwDeviceIDRecordMatchesCompatible(record, compatible); 193 } 194 195 ssize_t findMatchingDeviceDescriptorIndex( 196 const FirmwareDeviceIDRecords& records, uint32_t vendorIANA, 197 const std::string& compatible) 198 { 199 for (size_t i = 0; i < records.size(); i++) 200 { 201 const FirmwareDeviceIDRecord& record = records[i]; 202 if (fwDeviceIDRecordMatches(record, vendorIANA, compatible)) 203 { 204 return (ssize_t)i; 205 } 206 } 207 return -1; 208 } 209 210 int extractMatchingComponentImage( 211 const std::shared_ptr<PackageParser>& packageParser, 212 const std::string& compatible, uint32_t vendorIANA, 213 uint32_t* componentOffsetOut, size_t* componentSizeOut, 214 std::string& componentVersionOut) 215 { 216 const FirmwareDeviceIDRecords& fwDeviceIdRecords = 217 packageParser->getFwDeviceIDRecords(); 218 219 // find fw descriptor matching vendor iana and compatible 220 ssize_t deviceDescriptorIndex = findMatchingDeviceDescriptorIndex( 221 fwDeviceIdRecords, vendorIANA, compatible); 222 223 if (deviceDescriptorIndex < 0) 224 { 225 error( 226 "did not find a matching device descriptor for {IANA}, {COMPATIBLE}", 227 "IANA", lg2::hex, vendorIANA, "COMPATIBLE", compatible); 228 return EXIT_FAILURE; 229 } 230 231 const FirmwareDeviceIDRecord& descriptor = 232 fwDeviceIdRecords[deviceDescriptorIndex]; 233 // find applicable components 234 // iterate over components to find the applicable component 235 236 ApplicableComponents ac = std::get<1>(descriptor); 237 238 if (ac.empty()) 239 { 240 error("did not find an applicable component image for the device"); 241 return EXIT_FAILURE; 242 } 243 244 // component is 0 based index 245 const size_t component = ac[0]; 246 247 const ComponentImageInfos& cs = packageParser->getComponentImageInfos(); 248 249 if (component >= cs.size()) 250 { 251 error("applicable component out of bounds"); 252 return EXIT_FAILURE; 253 } 254 255 const ComponentImageInfo& c = cs[component]; 256 257 CompLocationOffset off = std::get<5>(c); 258 CompSize size = std::get<6>(c); 259 260 *componentOffsetOut = off; 261 *componentSizeOut = size; 262 componentVersionOut = std::get<7>(c); 263 264 return EXIT_SUCCESS; 265 } 266 267 } // namespace pldm_package_util 268