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