xref: /openbmc/libpldm/bindings/cpp/firmware_update.cpp (revision d6a957481638b00a49aed15d04b60d3d32fede54)
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