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