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