blob: 2d348a021c5e08b06a256e8bce3ff6ed02ca664a [file] [log] [blame]
Alexander Hansen00b3cae2024-11-26 17:32:33 +01001#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>
Alexander Hansencc372352025-01-14 14:15:39 +010020#include <functional>
21
22PHOSPHOR_LOG2_USING;
Alexander Hansen00b3cae2024-11-26 17:32:33 +010023
24using namespace pldm::fw_update;
25
26namespace pldm_package_util
27{
28
29std::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
Alexander Hansencc372352025-01-14 14:15:39 +010039 debug("parsing package header");
Alexander Hansen00b3cae2024-11-26 17:32:33 +010040
41 std::unique_ptr<PackageParser> packageParser =
42 pldm::fw_update::parsePackageHeader(pkgData);
43
44 if (packageParser == nullptr)
45 {
Alexander Hansencc372352025-01-14 14:15:39 +010046 error("could not parse package header");
Alexander Hansen00b3cae2024-11-26 17:32:33 +010047 return packageParser;
48 }
49
Alexander Hansencc372352025-01-14 14:15:39 +010050 debug("parsing package, pkg header size: {N}", "N",
51 packageParser->pkgHeaderSize);
Alexander Hansen00b3cae2024-11-26 17:32:33 +010052
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
Alexander Hansencc372352025-01-14 14:15:39 +010063int readImagePackage(FILE* file, uint8_t* packageData, const size_t packageSize)
Alexander Hansen00b3cae2024-11-26 17:32:33 +010064{
Alexander Hansencc372352025-01-14 14:15:39 +010065 if (file == NULL || packageData == NULL)
Alexander Hansen00b3cae2024-11-26 17:32:33 +010066 {
67 return 1;
68 }
69
Alexander Hansencc372352025-01-14 14:15:39 +010070 if (packageSize == 0)
Alexander Hansen00b3cae2024-11-26 17:32:33 +010071 {
Alexander Hansencc372352025-01-14 14:15:39 +010072 error("Package size is 0");
Alexander Hansen00b3cae2024-11-26 17:32:33 +010073 return 1;
74 }
75
Alexander Hansencc372352025-01-14 14:15:39 +010076 debug("reading {NBYTES} bytes from file", "NBYTES", packageSize);
Alexander Hansen00b3cae2024-11-26 17:32:33 +010077
78 // Read the package into memory
Alexander Hansencc372352025-01-14 14:15:39 +010079 if (fread(packageData, 1, packageSize, file) != packageSize)
Alexander Hansen00b3cae2024-11-26 17:32:33 +010080 {
81 perror("Failed to read package data");
82 fclose(file);
83 return 1;
84 }
85
86 return 0;
87}
88
Alexander Hansencc372352025-01-14 14:15:39 +010089std::unique_ptr<void, std::function<void(void*)>> mmapImagePackage(
90 sdbusplus::message::unix_fd image, size_t* sizeOut)
Alexander Hansen00b3cae2024-11-26 17:32:33 +010091{
Alexander Hansencc372352025-01-14 14:15:39 +010092 debug("open fd {FD}", "FD", int(image));
Alexander Hansen00b3cae2024-11-26 17:32:33 +010093
94 off_t size = lseek(image.fd, 0, SEEK_END);
95
96 if (size < 0)
97 {
Alexander Hansencc372352025-01-14 14:15:39 +010098 error("failed to determine file size");
Alexander Hansen00b3cae2024-11-26 17:32:33 +010099 perror("error:");
Alexander Hansencc372352025-01-14 14:15:39 +0100100 return nullptr;
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100101 }
102
Alexander Hansencc372352025-01-14 14:15:39 +0100103 *sizeOut = size;
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100104
Alexander Hansencc372352025-01-14 14:15:39 +0100105 debug("file size: {SIZE}", "SIZE", (uint64_t)size);
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100106
107 void* data = mmap(nullptr, size, PROT_READ, MAP_SHARED, image.fd, 0);
108
109 if (data == MAP_FAILED)
110 {
Alexander Hansencc372352025-01-14 14:15:39 +0100111 error("could not mmap the image");
112 return nullptr;
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100113 }
114
Alexander Hansencc372352025-01-14 14:15:39 +0100115 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;
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100125}
126
127bool 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 {
Alexander Hansencc372352025-01-14 14:15:39 +0100145 debug("descriptor does not have the vendor defined descriptor info");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100146 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
156bool 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 {
Alexander Hansencc372352025-01-14 14:15:39 +0100168 error("did not find iana enterprise id");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100169 return false;
170 }
171
172 auto viana = desc[0x1];
173
174 if (!std::holds_alternative<DescriptorData>(viana))
175 {
Alexander Hansencc372352025-01-14 14:15:39 +0100176 error("did not find iana enterprise id");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100177 return false;
178 }
179
180 const DescriptorData& dd = std::get<DescriptorData>(viana);
181
182 if (dd.size() != 4)
183 {
Alexander Hansencc372352025-01-14 14:15:39 +0100184 error("descriptor data wrong size ( != 4) for vendor iana");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100185 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
193bool fwDeviceIDRecordMatches(const FirmwareDeviceIDRecord& record,
194 uint32_t vendorIANA, const std::string& compatible)
195{
196 return fwDeviceIDRecordMatchesIANA(record, vendorIANA) &&
197 fwDeviceIDRecordMatchesCompatible(record, compatible);
198}
199
200ssize_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
215int extractMatchingComponentImage(
216 const std::shared_ptr<PackageParser>& packageParser,
217 const std::string& compatible, uint32_t vendorIANA,
Alexander Hansencc372352025-01-14 14:15:39 +0100218 uint32_t* componentOffsetOut, size_t* componentSizeOut,
219 std::string& componentVersionOut)
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100220{
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 {
Alexander Hansencc372352025-01-14 14:15:39 +0100230 error(
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100231 "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 {
Alexander Hansencc372352025-01-14 14:15:39 +0100245 error("did not find an applicable component image for the device");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100246 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 {
Alexander Hansencc372352025-01-14 14:15:39 +0100256 error("applicable component out of bounds");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100257 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
Alexander Hansencc372352025-01-14 14:15:39 +0100265 *componentOffsetOut = off;
266 *componentSizeOut = size;
267 componentVersionOut = std::get<7>(c);
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100268
269 return EXIT_SUCCESS;
270}
271
272} // namespace pldm_package_util