blob: 0db676c333bc3123790ac7c98db50182dd970bee [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
Alexander Hansen7dfe0722025-06-24 13:49:58 +020053 packageParser->parse(pkgData, pkgData.size());
Alexander Hansen00b3cae2024-11-26 17:32:33 +010054
55 return packageParser;
56}
57
Alexander Hansencc372352025-01-14 14:15:39 +010058int readImagePackage(FILE* file, uint8_t* packageData, const size_t packageSize)
Alexander Hansen00b3cae2024-11-26 17:32:33 +010059{
Alexander Hansencc372352025-01-14 14:15:39 +010060 if (file == NULL || packageData == NULL)
Alexander Hansen00b3cae2024-11-26 17:32:33 +010061 {
62 return 1;
63 }
64
Alexander Hansencc372352025-01-14 14:15:39 +010065 if (packageSize == 0)
Alexander Hansen00b3cae2024-11-26 17:32:33 +010066 {
Alexander Hansencc372352025-01-14 14:15:39 +010067 error("Package size is 0");
Alexander Hansen00b3cae2024-11-26 17:32:33 +010068 return 1;
69 }
70
Alexander Hansencc372352025-01-14 14:15:39 +010071 debug("reading {NBYTES} bytes from file", "NBYTES", packageSize);
Alexander Hansen00b3cae2024-11-26 17:32:33 +010072
73 // Read the package into memory
Alexander Hansencc372352025-01-14 14:15:39 +010074 if (fread(packageData, 1, packageSize, file) != packageSize)
Alexander Hansen00b3cae2024-11-26 17:32:33 +010075 {
76 perror("Failed to read package data");
77 fclose(file);
78 return 1;
79 }
80
81 return 0;
82}
83
Alexander Hansencc372352025-01-14 14:15:39 +010084std::unique_ptr<void, std::function<void(void*)>> mmapImagePackage(
85 sdbusplus::message::unix_fd image, size_t* sizeOut)
Alexander Hansen00b3cae2024-11-26 17:32:33 +010086{
Alexander Hansencc372352025-01-14 14:15:39 +010087 debug("open fd {FD}", "FD", int(image));
Alexander Hansen00b3cae2024-11-26 17:32:33 +010088
89 off_t size = lseek(image.fd, 0, SEEK_END);
90
91 if (size < 0)
92 {
Alexander Hansencc372352025-01-14 14:15:39 +010093 error("failed to determine file size");
Alexander Hansen00b3cae2024-11-26 17:32:33 +010094 perror("error:");
Alexander Hansencc372352025-01-14 14:15:39 +010095 return nullptr;
Alexander Hansen00b3cae2024-11-26 17:32:33 +010096 }
97
Alexander Hansencc372352025-01-14 14:15:39 +010098 *sizeOut = size;
Alexander Hansen00b3cae2024-11-26 17:32:33 +010099
Alexander Hansencc372352025-01-14 14:15:39 +0100100 debug("file size: {SIZE}", "SIZE", (uint64_t)size);
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100101
102 void* data = mmap(nullptr, size, PROT_READ, MAP_SHARED, image.fd, 0);
103
104 if (data == MAP_FAILED)
105 {
Alexander Hansencc372352025-01-14 14:15:39 +0100106 error("could not mmap the image");
107 return nullptr;
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100108 }
109
Alexander Hansencc372352025-01-14 14:15:39 +0100110 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;
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100120}
121
122bool 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 {
Alexander Hansencc372352025-01-14 14:15:39 +0100140 debug("descriptor does not have the vendor defined descriptor info");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100141 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
151bool 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 {
Alexander Hansencc372352025-01-14 14:15:39 +0100163 error("did not find iana enterprise id");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100164 return false;
165 }
166
167 auto viana = desc[0x1];
168
169 if (!std::holds_alternative<DescriptorData>(viana))
170 {
Alexander Hansencc372352025-01-14 14:15:39 +0100171 error("did not find iana enterprise id");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100172 return false;
173 }
174
175 const DescriptorData& dd = std::get<DescriptorData>(viana);
176
177 if (dd.size() != 4)
178 {
Alexander Hansencc372352025-01-14 14:15:39 +0100179 error("descriptor data wrong size ( != 4) for vendor iana");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100180 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
188bool fwDeviceIDRecordMatches(const FirmwareDeviceIDRecord& record,
189 uint32_t vendorIANA, const std::string& compatible)
190{
191 return fwDeviceIDRecordMatchesIANA(record, vendorIANA) &&
192 fwDeviceIDRecordMatchesCompatible(record, compatible);
193}
194
195ssize_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
210int extractMatchingComponentImage(
211 const std::shared_ptr<PackageParser>& packageParser,
212 const std::string& compatible, uint32_t vendorIANA,
Alexander Hansencc372352025-01-14 14:15:39 +0100213 uint32_t* componentOffsetOut, size_t* componentSizeOut,
214 std::string& componentVersionOut)
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100215{
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 {
Alexander Hansencc372352025-01-14 14:15:39 +0100225 error(
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100226 "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 {
Alexander Hansencc372352025-01-14 14:15:39 +0100240 error("did not find an applicable component image for the device");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100241 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 {
Alexander Hansencc372352025-01-14 14:15:39 +0100251 error("applicable component out of bounds");
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100252 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
Alexander Hansencc372352025-01-14 14:15:39 +0100260 *componentOffsetOut = off;
261 *componentSizeOut = size;
262 componentVersionOut = std::get<7>(c);
Alexander Hansen00b3cae2024-11-26 17:32:33 +0100263
264 return EXIT_SUCCESS;
265}
266
267} // namespace pldm_package_util