1*d6a95748SAlexander Hansen #include "libpldm++/firmware_update.hpp"
2*d6a95748SAlexander Hansen
3*d6a95748SAlexander Hansen #include "utils.hpp"
4*d6a95748SAlexander Hansen
5*d6a95748SAlexander Hansen #include <cassert>
6*d6a95748SAlexander Hansen #include <libpldm/firmware_update.h>
7*d6a95748SAlexander Hansen #include <libpldm/pldm_types.h>
8*d6a95748SAlexander Hansen #include <expected>
9*d6a95748SAlexander Hansen #include <span>
10*d6a95748SAlexander Hansen
11*d6a95748SAlexander Hansen using namespace std;
12*d6a95748SAlexander Hansen
13*d6a95748SAlexander Hansen LIBPLDM_ABI_STABLE
stable_nop()14*d6a95748SAlexander Hansen void pldm::fw_update::stable_nop()
15*d6a95748SAlexander Hansen {
16*d6a95748SAlexander Hansen }
17*d6a95748SAlexander Hansen
PackageParserError(std::string s)18*d6a95748SAlexander Hansen pldm::fw_update::PackageParserError::PackageParserError(std::string s)
19*d6a95748SAlexander Hansen : msg(std::move(s))
20*d6a95748SAlexander Hansen {
21*d6a95748SAlexander Hansen }
22*d6a95748SAlexander Hansen
PackageParserError(std::string s,int rc)23*d6a95748SAlexander Hansen pldm::fw_update::PackageParserError::PackageParserError(std::string s, int rc)
24*d6a95748SAlexander Hansen : msg(std::move(s)), rc(rc)
25*d6a95748SAlexander Hansen {
26*d6a95748SAlexander Hansen }
27*d6a95748SAlexander Hansen
28*d6a95748SAlexander Hansen std::expected<void, std::string>
helperParseFDDescriptor(struct pldm_descriptor * desc,std::map<uint16_t,std::unique_ptr<pldm::fw_update::DescriptorData>> & descriptors)29*d6a95748SAlexander Hansen pldm::fw_update::PackageParser::helperParseFDDescriptor(
30*d6a95748SAlexander Hansen struct pldm_descriptor *desc,
31*d6a95748SAlexander Hansen std::map<uint16_t, std::unique_ptr<pldm::fw_update::DescriptorData> >
32*d6a95748SAlexander Hansen &descriptors) noexcept
33*d6a95748SAlexander Hansen {
34*d6a95748SAlexander Hansen int rc;
35*d6a95748SAlexander Hansen variable_field descriptorData{};
36*d6a95748SAlexander Hansen descriptorData.ptr = (const uint8_t *)desc->descriptor_data;
37*d6a95748SAlexander Hansen descriptorData.length = desc->descriptor_length;
38*d6a95748SAlexander Hansen
39*d6a95748SAlexander Hansen if (desc->descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
40*d6a95748SAlexander Hansen descriptors.emplace(
41*d6a95748SAlexander Hansen desc->descriptor_type,
42*d6a95748SAlexander Hansen std::unique_ptr<pldm::fw_update::DescriptorData>(
43*d6a95748SAlexander Hansen new pldm::fw_update::DescriptorData{ std::vector(
44*d6a95748SAlexander Hansen descriptorData.ptr,
45*d6a95748SAlexander Hansen descriptorData.ptr +
46*d6a95748SAlexander Hansen descriptorData.length) }));
47*d6a95748SAlexander Hansen } else {
48*d6a95748SAlexander Hansen uint8_t descTitleStrType = 0;
49*d6a95748SAlexander Hansen variable_field descTitleStr{};
50*d6a95748SAlexander Hansen variable_field vendorDefinedDescData{};
51*d6a95748SAlexander Hansen
52*d6a95748SAlexander Hansen rc = decode_vendor_defined_descriptor_value(
53*d6a95748SAlexander Hansen descriptorData.ptr, descriptorData.length,
54*d6a95748SAlexander Hansen &descTitleStrType, &descTitleStr,
55*d6a95748SAlexander Hansen &vendorDefinedDescData);
56*d6a95748SAlexander Hansen if (rc) {
57*d6a95748SAlexander Hansen // concatenate error message manually instead of dragging in <format>
58*d6a95748SAlexander Hansen std::string msg =
59*d6a95748SAlexander Hansen "Failed to decode vendor-defined descriptor value of type '";
60*d6a95748SAlexander Hansen msg += std::to_string(desc->descriptor_type);
61*d6a95748SAlexander Hansen msg += "' and length '";
62*d6a95748SAlexander Hansen msg += std::to_string(descriptorData.length);
63*d6a95748SAlexander Hansen msg += "', response code ";
64*d6a95748SAlexander Hansen msg += std::to_string(rc);
65*d6a95748SAlexander Hansen
66*d6a95748SAlexander Hansen return std::unexpected(msg);
67*d6a95748SAlexander Hansen }
68*d6a95748SAlexander Hansen
69*d6a95748SAlexander Hansen auto descrTitleStr =
70*d6a95748SAlexander Hansen pldm::utils::toString(descTitleStrType, descTitleStr);
71*d6a95748SAlexander Hansen
72*d6a95748SAlexander Hansen if (!descrTitleStr.has_value()) {
73*d6a95748SAlexander Hansen return std::unexpected(descrTitleStr.error());
74*d6a95748SAlexander Hansen }
75*d6a95748SAlexander Hansen descriptors.emplace(
76*d6a95748SAlexander Hansen desc->descriptor_type,
77*d6a95748SAlexander Hansen std::unique_ptr<pldm::fw_update::DescriptorData>(
78*d6a95748SAlexander Hansen new pldm::fw_update::DescriptorData(
79*d6a95748SAlexander Hansen descrTitleStr.value(),
80*d6a95748SAlexander Hansen std::vector<uint8_t>{
81*d6a95748SAlexander Hansen vendorDefinedDescData.ptr,
82*d6a95748SAlexander Hansen vendorDefinedDescData.ptr +
83*d6a95748SAlexander Hansen vendorDefinedDescData
84*d6a95748SAlexander Hansen .length })));
85*d6a95748SAlexander Hansen }
86*d6a95748SAlexander Hansen return {};
87*d6a95748SAlexander Hansen }
88*d6a95748SAlexander Hansen
89*d6a95748SAlexander Hansen // @param[out] compList The list of indices into the component array
90*d6a95748SAlexander Hansen // @param[in] bitmap The bitmap of applicable components
getApplicableComponents(std::vector<size_t> & compList,struct variable_field & bitmap)91*d6a95748SAlexander Hansen static void getApplicableComponents(std::vector<size_t> &compList,
92*d6a95748SAlexander Hansen struct variable_field &bitmap)
93*d6a95748SAlexander Hansen {
94*d6a95748SAlexander Hansen for (size_t bitIdx = 0; bitIdx < bitmap.length * 8; bitIdx++) {
95*d6a95748SAlexander Hansen const uint8_t applicable =
96*d6a95748SAlexander Hansen ((*(bitmap.ptr + (bitIdx / 8))) >> (bitIdx % 8)) & 0x1;
97*d6a95748SAlexander Hansen
98*d6a95748SAlexander Hansen if (applicable) {
99*d6a95748SAlexander Hansen compList.emplace_back(bitIdx);
100*d6a95748SAlexander Hansen }
101*d6a95748SAlexander Hansen }
102*d6a95748SAlexander Hansen }
103*d6a95748SAlexander Hansen
104*d6a95748SAlexander Hansen pldm::fw_update::PackageParser::~PackageParser() = default;
105*d6a95748SAlexander Hansen
106*d6a95748SAlexander Hansen LIBPLDM_ABI_TESTING
107*d6a95748SAlexander Hansen std::expected<std::unique_ptr<pldm::fw_update::Package>,
108*d6a95748SAlexander Hansen pldm::fw_update::PackageParserError>
parse(const std::span<const uint8_t> & pkg,struct pldm_package_format_pin & pin)109*d6a95748SAlexander Hansen pldm::fw_update::PackageParser::parse(
110*d6a95748SAlexander Hansen const std::span<const uint8_t> &pkg,
111*d6a95748SAlexander Hansen struct pldm_package_format_pin &pin) noexcept
112*d6a95748SAlexander Hansen {
113*d6a95748SAlexander Hansen const size_t pkgSize = pkg.size();
114*d6a95748SAlexander Hansen
115*d6a95748SAlexander Hansen struct pldm_package package = {};
116*d6a95748SAlexander Hansen std::vector<FirmwareDeviceIDRecord> fwDeviceIDRecords = {};
117*d6a95748SAlexander Hansen pldm_package_header_information_pad hdr = {};
118*d6a95748SAlexander Hansen int rc;
119*d6a95748SAlexander Hansen
120*d6a95748SAlexander Hansen if (pin.format.revision > PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H) {
121*d6a95748SAlexander Hansen return std::unexpected(
122*d6a95748SAlexander Hansen PackageParserError("unsupported format revision"));
123*d6a95748SAlexander Hansen }
124*d6a95748SAlexander Hansen
125*d6a95748SAlexander Hansen rc = decode_pldm_firmware_update_package(pkg.data(), pkgSize, &pin,
126*d6a95748SAlexander Hansen &hdr, &package, 0);
127*d6a95748SAlexander Hansen
128*d6a95748SAlexander Hansen if (rc) {
129*d6a95748SAlexander Hansen return std::unexpected(PackageParserError(
130*d6a95748SAlexander Hansen "Failed to decode pldm package header", rc));
131*d6a95748SAlexander Hansen }
132*d6a95748SAlexander Hansen
133*d6a95748SAlexander Hansen pldm_package_firmware_device_id_record deviceIdRecordData{};
134*d6a95748SAlexander Hansen
135*d6a95748SAlexander Hansen foreach_pldm_package_firmware_device_id_record(package,
136*d6a95748SAlexander Hansen deviceIdRecordData, rc)
137*d6a95748SAlexander Hansen {
138*d6a95748SAlexander Hansen std::map<uint16_t, std::unique_ptr<DescriptorData> >
139*d6a95748SAlexander Hansen descriptors{};
140*d6a95748SAlexander Hansen struct pldm_descriptor descriptorData;
141*d6a95748SAlexander Hansen
142*d6a95748SAlexander Hansen foreach_pldm_package_firmware_device_id_record_descriptor(
143*d6a95748SAlexander Hansen package, deviceIdRecordData, descriptorData, rc)
144*d6a95748SAlexander Hansen {
145*d6a95748SAlexander Hansen auto result = helperParseFDDescriptor(&descriptorData,
146*d6a95748SAlexander Hansen descriptors);
147*d6a95748SAlexander Hansen
148*d6a95748SAlexander Hansen if (!result.has_value()) {
149*d6a95748SAlexander Hansen return std::unexpected(
150*d6a95748SAlexander Hansen PackageParserError(result.error()));
151*d6a95748SAlexander Hansen }
152*d6a95748SAlexander Hansen }
153*d6a95748SAlexander Hansen
154*d6a95748SAlexander Hansen if (rc) {
155*d6a95748SAlexander Hansen return std::unexpected(PackageParserError(
156*d6a95748SAlexander Hansen "Failed to decode pldm package firmware device id record",
157*d6a95748SAlexander Hansen rc));
158*d6a95748SAlexander Hansen }
159*d6a95748SAlexander Hansen
160*d6a95748SAlexander Hansen std::bitset<32> deviceUpdateOptionFlags =
161*d6a95748SAlexander Hansen deviceIdRecordData.device_update_option_flags.value;
162*d6a95748SAlexander Hansen
163*d6a95748SAlexander Hansen std::vector<size_t> componentsList;
164*d6a95748SAlexander Hansen
165*d6a95748SAlexander Hansen getApplicableComponents(
166*d6a95748SAlexander Hansen componentsList,
167*d6a95748SAlexander Hansen deviceIdRecordData.applicable_components.bitmap);
168*d6a95748SAlexander Hansen
169*d6a95748SAlexander Hansen std::vector<uint8_t> fwDevicePkgData = {};
170*d6a95748SAlexander Hansen
171*d6a95748SAlexander Hansen struct variable_field fw_device_pkg_data =
172*d6a95748SAlexander Hansen deviceIdRecordData.firmware_device_package_data;
173*d6a95748SAlexander Hansen
174*d6a95748SAlexander Hansen if (fw_device_pkg_data.length) {
175*d6a95748SAlexander Hansen fwDevicePkgData = { fw_device_pkg_data.ptr,
176*d6a95748SAlexander Hansen fw_device_pkg_data.ptr +
177*d6a95748SAlexander Hansen fw_device_pkg_data.length };
178*d6a95748SAlexander Hansen }
179*d6a95748SAlexander Hansen
180*d6a95748SAlexander Hansen auto imageSetVerStr = utils::toString(
181*d6a95748SAlexander Hansen deviceIdRecordData
182*d6a95748SAlexander Hansen .component_image_set_version_string_type,
183*d6a95748SAlexander Hansen deviceIdRecordData.component_image_set_version_string);
184*d6a95748SAlexander Hansen
185*d6a95748SAlexander Hansen if (!imageSetVerStr.has_value()) {
186*d6a95748SAlexander Hansen return std::unexpected(
187*d6a95748SAlexander Hansen PackageParserError(imageSetVerStr.error()));
188*d6a95748SAlexander Hansen }
189*d6a95748SAlexander Hansen
190*d6a95748SAlexander Hansen fwDeviceIDRecords.emplace_back(FirmwareDeviceIDRecord(
191*d6a95748SAlexander Hansen deviceUpdateOptionFlags, std::move(componentsList),
192*d6a95748SAlexander Hansen imageSetVerStr.value(), std::move(descriptors),
193*d6a95748SAlexander Hansen fwDevicePkgData));
194*d6a95748SAlexander Hansen }
195*d6a95748SAlexander Hansen
196*d6a95748SAlexander Hansen if (rc) {
197*d6a95748SAlexander Hansen return std::unexpected(PackageParserError(
198*d6a95748SAlexander Hansen "could not iterate fw device descriptors", rc));
199*d6a95748SAlexander Hansen }
200*d6a95748SAlexander Hansen
201*d6a95748SAlexander Hansen std::vector<ComponentImageInfo> componentImageInfos = {};
202*d6a95748SAlexander Hansen
203*d6a95748SAlexander Hansen struct pldm_package_component_image_information imageInfo;
204*d6a95748SAlexander Hansen foreach_pldm_package_component_image_information(package, imageInfo, rc)
205*d6a95748SAlexander Hansen {
206*d6a95748SAlexander Hansen const std::bitset<16> compOptions =
207*d6a95748SAlexander Hansen imageInfo.component_options.value;
208*d6a95748SAlexander Hansen const std::bitset<16> reqCompActivationMethod =
209*d6a95748SAlexander Hansen imageInfo.requested_component_activation_method.value;
210*d6a95748SAlexander Hansen
211*d6a95748SAlexander Hansen auto compVerStr =
212*d6a95748SAlexander Hansen utils::toString(imageInfo.component_version_string_type,
213*d6a95748SAlexander Hansen imageInfo.component_version_string);
214*d6a95748SAlexander Hansen
215*d6a95748SAlexander Hansen if (!compVerStr.has_value()) {
216*d6a95748SAlexander Hansen return std::unexpected(
217*d6a95748SAlexander Hansen PackageParserError(compVerStr.error()));
218*d6a95748SAlexander Hansen }
219*d6a95748SAlexander Hansen
220*d6a95748SAlexander Hansen componentImageInfos.emplace_back(ComponentImageInfo(
221*d6a95748SAlexander Hansen imageInfo.component_classification,
222*d6a95748SAlexander Hansen imageInfo.component_identifier,
223*d6a95748SAlexander Hansen imageInfo.component_comparison_stamp, compOptions,
224*d6a95748SAlexander Hansen reqCompActivationMethod, imageInfo.component_image,
225*d6a95748SAlexander Hansen compVerStr.value()));
226*d6a95748SAlexander Hansen }
227*d6a95748SAlexander Hansen
228*d6a95748SAlexander Hansen if (rc) {
229*d6a95748SAlexander Hansen return std::unexpected(PackageParserError(
230*d6a95748SAlexander Hansen "could not iterate component image area", rc));
231*d6a95748SAlexander Hansen }
232*d6a95748SAlexander Hansen
233*d6a95748SAlexander Hansen // We cannot do a std::make_unique here since since the constructor is private.
234*d6a95748SAlexander Hansen // We are friends but the constructor is called inside the template which is not a friend.
235*d6a95748SAlexander Hansen return std::unique_ptr<Package>(new Package(
236*d6a95748SAlexander Hansen std::move(fwDeviceIDRecords), std::move(componentImageInfos)));
237*d6a95748SAlexander Hansen }
238