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