blob: d031855088f682bca414c1f58c3661d58f24da7e [file] [log] [blame]
Sampa Misraaea5dde2020-08-31 08:33:47 -05001#include "inband_code_update.hpp"
2
Sagar Srinivas78a225a2020-08-27 00:52:20 -05003#include "libpldmresponder/pdr.hpp"
Sampa Misraaea5dde2020-08-31 08:33:47 -05004#include "oem_ibm_handler.hpp"
5#include "xyz/openbmc_project/Common/error.hpp"
6
Adriana Kobylak727f7382020-09-01 14:38:25 -05007#include <arpa/inet.h>
George Liuc453e162022-12-21 17:16:23 +08008#include <libpldm/entity.h>
Adriana Kobylak727f7382020-09-01 14:38:25 -05009
Archana Kakanie26d13f2025-03-09 23:17:46 -050010#include <nlohmann/json.hpp>
Riya Dixit49cfb132023-03-02 04:26:53 -060011#include <phosphor-logging/lg2.hpp>
Sampa Misraaea5dde2020-08-31 08:33:47 -050012#include <sdbusplus/server.hpp>
13#include <xyz/openbmc_project/Dump/NewDump/server.hpp>
14
15#include <exception>
Adriana Kobylak727f7382020-09-01 14:38:25 -050016#include <fstream>
Riya Dixit49cfb132023-03-02 04:26:53 -060017
18PHOSPHOR_LOG2_USING;
19
Sampa Misraaea5dde2020-08-31 08:33:47 -050020namespace pldm
21{
Brad Bishop5079ac42021-08-19 18:35:06 -040022using namespace utils;
23
Sampa Misraaea5dde2020-08-31 08:33:47 -050024namespace responder
25{
26using namespace oem_ibm_platform;
Archana Kakani97a0f482025-03-10 05:39:38 -050027using namespace oem_ibm_bios;
Sampa Misraaea5dde2020-08-31 08:33:47 -050028
Adriana Kobylakfa810d72020-10-16 16:27:28 -050029/** @brief Directory where the lid files without a header are stored */
30auto lidDirPath = fs::path(LID_STAGING_DIR) / "lid";
31
Adriana Kobylaka1f158c2020-11-09 12:47:29 -060032/** @brief Directory where the image files are stored as they are built */
33auto imageDirPath = fs::path(LID_STAGING_DIR) / "image";
34
Adriana Kobylak837fb472020-10-16 16:53:42 -050035/** @brief Directory where the code update tarball files are stored */
36auto updateDirPath = fs::path(LID_STAGING_DIR) / "update";
37
Adriana Kobylaka1f158c2020-11-09 12:47:29 -060038/** @brief The file name of the code update tarball */
39constexpr auto tarImageName = "image.tar";
40
Adriana Kobylak837fb472020-10-16 16:53:42 -050041/** @brief The file name of the hostfw image */
Adriana Kobylak131327e2021-03-10 18:45:24 +000042constexpr auto hostfwImageName = "image-hostfw";
Adriana Kobylak837fb472020-10-16 16:53:42 -050043
Adriana Kobylaka1f158c2020-11-09 12:47:29 -060044/** @brief The path to the code update tarball file */
45auto tarImagePath = fs::path(imageDirPath) / tarImageName;
46
Adriana Kobylak837fb472020-10-16 16:53:42 -050047/** @brief The path to the hostfw image */
48auto hostfwImagePath = fs::path(imageDirPath) / hostfwImageName;
49
50/** @brief The path to the tarball file expected by the phosphor software
51 * manager */
52auto updateImagePath = fs::path("/tmp/images") / tarImageName;
53
Archana Kakanie26d13f2025-03-09 23:17:46 -050054/** @brief Current boot side */
55constexpr auto bootSideAttrName = "fw_boot_side_current";
56
57/** @brief Next boot side */
58constexpr auto bootNextSideAttrName = "fw_boot_side";
59
Sampa Misraaea5dde2020-08-31 08:33:47 -050060std::string CodeUpdate::fetchCurrentBootSide()
61{
62 return currBootSide;
63}
64
65std::string CodeUpdate::fetchNextBootSide()
66{
67 return nextBootSide;
68}
69
70int CodeUpdate::setCurrentBootSide(const std::string& currSide)
71{
72 currBootSide = currSide;
73 return PLDM_SUCCESS;
74}
75
76int CodeUpdate::setNextBootSide(const std::string& nextSide)
77{
Archana Kakanie26d13f2025-03-09 23:17:46 -050078 info("setNextBootSide, nextSide={NXT_SIDE}", "NXT_SIDE", nextSide);
79 pldm_boot_side_data pldmBootSideData = readBootSideFile();
80 currBootSide =
81 (pldmBootSideData.current_boot_side == "Perm" ? Pside : Tside);
Sampa Misraaea5dde2020-08-31 08:33:47 -050082 nextBootSide = nextSide;
Archana Kakanie26d13f2025-03-09 23:17:46 -050083 pldmBootSideData.next_boot_side = (nextSide == Pside ? "Perm" : "Temp");
Sampa Misraaea5dde2020-08-31 08:33:47 -050084 std::string objPath{};
85 if (nextBootSide == currBootSide)
86 {
Archana Kakanie26d13f2025-03-09 23:17:46 -050087 info(
88 "Current bootside is same as next boot side, setting priority of running version 0");
Sampa Misraaea5dde2020-08-31 08:33:47 -050089 objPath = runningVersion;
90 }
91 else
92 {
Archana Kakanie26d13f2025-03-09 23:17:46 -050093 info(
94 "Current bootside is not same as next boot side, setting priority of non running version 0");
Sampa Misraaea5dde2020-08-31 08:33:47 -050095 objPath = nonRunningVersion;
96 }
97 if (objPath.empty())
98 {
Riya Dixit49cfb132023-03-02 04:26:53 -060099 error("no nonRunningVersion present");
Sampa Misraaea5dde2020-08-31 08:33:47 -0500100 return PLDM_PLATFORM_INVALID_STATE_VALUE;
101 }
102
Archana Kakanie26d13f2025-03-09 23:17:46 -0500103 try
104 {
105 auto priorityPropValue = dBusIntf->getDbusPropertyVariant(
106 objPath.c_str(), "Priority", redundancyIntf);
107 const auto& priorityValue = std::get<uint8_t>(priorityPropValue);
108 if (priorityValue == 0)
109 {
110 // Requested next boot side is already set
111 return PLDM_SUCCESS;
112 }
113 }
114 catch (const std::exception& e)
115 {
116 // Alternate side may not be present due to a failed code update
117 error("Alternate side may not be present due to a failed code update. "
118 "ERROR: {ERR}",
119 "ERR", e);
120 return PLDM_PLATFORM_INVALID_STATE_VALUE;
121 }
122
Sampa Misraaea5dde2020-08-31 08:33:47 -0500123 pldm::utils::DBusMapping dbusMapping{objPath, redundancyIntf, "Priority",
124 "uint8_t"};
125 uint8_t val = 0;
126 pldm::utils::PropertyValue value = static_cast<uint8_t>(val);
127 try
128 {
129 dBusIntf->setDbusProperty(dbusMapping, value);
130 }
131 catch (const std::exception& e)
132 {
Riya Dixitfc84f632024-04-06 14:00:02 -0500133 error("Failed to set the next boot side to {PATH} , error - {ERROR}",
134 "PATH", objPath, "ERROR", e);
Sampa Misraaea5dde2020-08-31 08:33:47 -0500135 return PLDM_ERROR;
136 }
Archana Kakanie26d13f2025-03-09 23:17:46 -0500137 writeBootSideFile(pldmBootSideData);
Sampa Misraaea5dde2020-08-31 08:33:47 -0500138 return PLDM_SUCCESS;
139}
140
Sagar Srinivascfdbca72020-09-22 10:03:35 -0500141int CodeUpdate::setRequestedApplyTime()
142{
143 int rc = PLDM_SUCCESS;
144 pldm::utils::PropertyValue value =
145 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
146 DBusMapping dbusMapping;
147 dbusMapping.objectPath = "/xyz/openbmc_project/software/apply_time";
148 dbusMapping.interface = "xyz.openbmc_project.Software.ApplyTime";
149 dbusMapping.propertyName = "RequestedApplyTime";
150 dbusMapping.propertyType = "string";
151 try
152 {
153 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
154 }
155 catch (const std::exception& e)
156 {
Sagar Srinivas90403472023-08-21 06:08:55 -0500157 error(
Riya Dixitfc84f632024-04-06 14:00:02 -0500158 "Failed to set property '{PROPERTY}' at path '{PATH}' and interface '{INTERFACE}', error - {ERROR}",
159 "PATH", dbusMapping.objectPath, "INTERFACE", dbusMapping.interface,
160 "PROPERTY", dbusMapping.propertyName, "ERROR", e);
Sagar Srinivascfdbca72020-09-22 10:03:35 -0500161 rc = PLDM_ERROR;
162 }
163 return rc;
164}
165
166int CodeUpdate::setRequestedActivation()
167{
168 int rc = PLDM_SUCCESS;
169 pldm::utils::PropertyValue value =
170 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active";
171 DBusMapping dbusMapping;
172 dbusMapping.objectPath = newImageId;
173 dbusMapping.interface = "xyz.openbmc_project.Software.Activation";
174 dbusMapping.propertyName = "RequestedActivation";
175 dbusMapping.propertyType = "string";
176 try
177 {
178 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
179 }
180 catch (const std::exception& e)
181 {
Sagar Srinivas90403472023-08-21 06:08:55 -0500182 error(
Riya Dixitfc84f632024-04-06 14:00:02 -0500183 "Failed to set property {PROPERTY} at path '{PATH}' and interface '{INTERFACE}', error - {ERROR}",
184 "PATH", dbusMapping.objectPath, "INTERFACE", dbusMapping.interface,
185 "PROPERTY", dbusMapping.propertyName, "ERROR", e);
Sagar Srinivascfdbca72020-09-22 10:03:35 -0500186 rc = PLDM_ERROR;
187 }
Sagar Srinivascfdbca72020-09-22 10:03:35 -0500188 return rc;
189}
190
Sampa Misraaea5dde2020-08-31 08:33:47 -0500191void CodeUpdate::setVersions()
192{
Archana Kakanie26d13f2025-03-09 23:17:46 -0500193 PendingAttributesList biosAttrList;
Sampa Misraaea5dde2020-08-31 08:33:47 -0500194 static constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
195 static constexpr auto functionalObjPath =
196 "/xyz/openbmc_project/software/functional";
197 static constexpr auto activeObjPath =
198 "/xyz/openbmc_project/software/active";
199 static constexpr auto propIntf = "org.freedesktop.DBus.Properties";
Archana Kakani97a0f482025-03-10 05:39:38 -0500200 static constexpr auto pathIntf = "xyz.openbmc_project.Common.FilePath";
Sampa Misraaea5dde2020-08-31 08:33:47 -0500201
202 auto& bus = dBusIntf->getBus();
Sampa Misraaea5dde2020-08-31 08:33:47 -0500203 try
204 {
205 auto method = bus.new_method_call(mapperService, functionalObjPath,
206 propIntf, "Get");
207 method.append("xyz.openbmc_project.Association", "endpoints");
208 std::variant<std::vector<std::string>> paths;
209
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500210 auto reply = bus.call(method, dbusTimeout);
Sampa Misraaea5dde2020-08-31 08:33:47 -0500211 reply.read(paths);
212
213 runningVersion = std::get<std::vector<std::string>>(paths)[0];
Archana Kakani97a0f482025-03-10 05:39:38 -0500214 auto runningPathPropValue = dBusIntf->getDbusPropertyVariant(
215 runningVersion.c_str(), "Path", pathIntf);
216 const auto& runningPath = std::get<std::string>(runningPathPropValue);
Sampa Misraaea5dde2020-08-31 08:33:47 -0500217
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400218 auto method1 =
219 bus.new_method_call(mapperService, activeObjPath, propIntf, "Get");
Sampa Misraaea5dde2020-08-31 08:33:47 -0500220 method1.append("xyz.openbmc_project.Association", "endpoints");
221
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500222 auto reply1 = bus.call(method1, dbusTimeout);
Sampa Misraaea5dde2020-08-31 08:33:47 -0500223 reply1.read(paths);
224 for (const auto& path : std::get<std::vector<std::string>>(paths))
225 {
226 if (path != runningVersion)
227 {
228 nonRunningVersion = path;
229 break;
230 }
231 }
Archana Kakanie26d13f2025-03-09 23:17:46 -0500232 if (!fs::exists(bootSideDirPath))
233 {
234 pldm_boot_side_data pldmBootSideData;
235 std::string nextBootSideBiosValue = "Temp";
236 auto attributeValue = getBiosAttrValue<std::string>("fw_boot_side");
237
238 // We enter this path during Genesis boot/boot after Factory reset.
239 // PLDM waits for Entity manager to populate System Type. After
240 // receiving system Type from EM it populates the bios attributes
241 // specific to that system We do not have bios attributes populated
242 // when we reach here so setting it to default value of the
243 // attribute as mentioned in the json files.
244 if (attributeValue.has_value())
245 {
246 nextBootSideBiosValue = attributeValue.value();
247 }
248 else
249 {
250 info(
Archana Kakani97a0f482025-03-10 05:39:38 -0500251 "Boot side is not initialized yet, so setting default value(Temp). Request was ignored to set the Boot side to {SIDE}",
252 "SIDE", nextBootSideBiosValue);
Archana Kakanie26d13f2025-03-09 23:17:46 -0500253 nextBootSideBiosValue = "Temp";
254 }
255 pldmBootSideData.current_boot_side = nextBootSideBiosValue;
256 pldmBootSideData.next_boot_side = nextBootSideBiosValue;
Archana Kakani97a0f482025-03-10 05:39:38 -0500257 pldmBootSideData.running_version_object = runningPath;
Archana Kakanie26d13f2025-03-09 23:17:46 -0500258
259 writeBootSideFile(pldmBootSideData);
260 biosAttrList.emplace_back(std::make_pair(
261 bootSideAttrName,
262 std::make_tuple(EnumAttribute,
263 pldmBootSideData.current_boot_side)));
264 biosAttrList.push_back(std::make_pair(
265 bootNextSideAttrName,
266 std::make_tuple(EnumAttribute,
267 pldmBootSideData.next_boot_side)));
268 setBiosAttr(biosAttrList);
269 }
270 else
271 {
272 pldm_boot_side_data pldmBootSideData = readBootSideFile();
Archana Kakani97a0f482025-03-10 05:39:38 -0500273 if (pldmBootSideData.running_version_object != runningPath)
Archana Kakanie26d13f2025-03-09 23:17:46 -0500274 {
275 info(
276 "BMC have booted with the new image runningPath={RUNN_PATH}",
Archana Kakani97a0f482025-03-10 05:39:38 -0500277 "RUNN_PATH", runningPath.c_str());
Archana Kakanie26d13f2025-03-09 23:17:46 -0500278 info("Previous Image was: {RUNN_VERS}", "RUNN_VERS",
279 pldmBootSideData.running_version_object);
280 auto current_boot_side =
281 (pldmBootSideData.current_boot_side == "Temp" ? "Perm"
282 : "Temp");
283 pldmBootSideData.current_boot_side = current_boot_side;
284 pldmBootSideData.next_boot_side = current_boot_side;
Archana Kakani97a0f482025-03-10 05:39:38 -0500285 pldmBootSideData.running_version_object = runningPath;
Archana Kakanie26d13f2025-03-09 23:17:46 -0500286 writeBootSideFile(pldmBootSideData);
287 biosAttrList.emplace_back(std::make_pair(
288 bootSideAttrName,
289 std::make_tuple(EnumAttribute,
290 pldmBootSideData.current_boot_side)));
291 biosAttrList.push_back(std::make_pair(
292 bootNextSideAttrName,
293 std::make_tuple(EnumAttribute,
294 pldmBootSideData.next_boot_side)));
295 setBiosAttr(biosAttrList);
296 }
297 else
298 {
299 info(
300 "BMC have booted with the previous image runningPath={RUNN_PATH}",
301 "RUNN_PATH", pldmBootSideData.running_version_object);
302 pldm_boot_side_data pldmBootSideData = readBootSideFile();
303 pldmBootSideData.next_boot_side =
304 pldmBootSideData.current_boot_side;
305 writeBootSideFile(pldmBootSideData);
306 biosAttrList.emplace_back(std::make_pair(
307 bootSideAttrName,
308 std::make_tuple(EnumAttribute,
309 pldmBootSideData.current_boot_side)));
310 biosAttrList.push_back(std::make_pair(
311 bootNextSideAttrName,
312 std::make_tuple(EnumAttribute,
313 pldmBootSideData.next_boot_side)));
314 setBiosAttr(biosAttrList);
315 }
316 currBootSide =
317 (pldmBootSideData.current_boot_side == "Temp" ? Tside : Pside);
318 nextBootSide =
319 (pldmBootSideData.next_boot_side == "Temp" ? Tside : Pside);
320 }
Sampa Misraaea5dde2020-08-31 08:33:47 -0500321 }
322 catch (const std::exception& e)
323 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600324 error(
Riya Dixitfc84f632024-04-06 14:00:02 -0500325 "Failed to make a d-bus call to Object Mapper Association, error - {ERROR}",
326 "ERROR", e);
Sampa Misraaea5dde2020-08-31 08:33:47 -0500327 return;
328 }
329
330 using namespace sdbusplus::bus::match::rules;
331 captureNextBootSideChange.push_back(
Patrick Williams84b790c2022-07-22 19:26:56 -0500332 std::make_unique<sdbusplus::bus::match_t>(
Sampa Misraaea5dde2020-08-31 08:33:47 -0500333 pldm::utils::DBusHandler::getBus(),
334 propertiesChanged(runningVersion, redundancyIntf),
Patrick Williams84b790c2022-07-22 19:26:56 -0500335 [this](sdbusplus::message_t& msg) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400336 DbusChangedProps props;
337 std::string iface;
338 msg.read(iface, props);
339 processPriorityChangeNotification(props);
340 }));
Patrick Williams84b790c2022-07-22 19:26:56 -0500341 fwUpdateMatcher.push_back(std::make_unique<sdbusplus::bus::match_t>(
Sampa Misraaea5dde2020-08-31 08:33:47 -0500342 pldm::utils::DBusHandler::getBus(),
343 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
344 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
Patrick Williams84b790c2022-07-22 19:26:56 -0500345 [this](sdbusplus::message_t& msg) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400346 DBusInterfaceAdded interfaces;
347 sdbusplus::message::object_path path;
348 msg.read(path, interfaces);
Sagar Srinivas9a64b4a2021-02-09 07:55:38 -0600349
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400350 for (auto& interface : interfaces)
Sampa Misraaea5dde2020-08-31 08:33:47 -0500351 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400352 if (interface.first ==
353 "xyz.openbmc_project.Software.Activation")
Patrick Williams6da4f912023-05-10 07:50:53 -0500354 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400355 auto imageInterface =
356 "xyz.openbmc_project.Software.Activation";
357 auto imageObjPath = path.str.c_str();
358
359 try
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500360 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400361 auto propVal = dBusIntf->getDbusPropertyVariant(
362 imageObjPath, "Activation", imageInterface);
Archana Kakanic23b6142025-02-19 04:04:20 -0600363 if (isCodeUpdateInProgress())
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500364 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400365 newImageId = path.str;
366 if (!imageActivationMatch)
367 {
368 imageActivationMatch = std::make_unique<
369 sdbusplus::bus::match_t>(
Sagar Srinivas9a64b4a2021-02-09 07:55:38 -0600370 pldm::utils::DBusHandler::getBus(),
371 propertiesChanged(newImageId,
372 "xyz.openbmc_project."
373 "Software.Activation"),
Patrick Williams84b790c2022-07-22 19:26:56 -0500374 [this](sdbusplus::message_t& msg) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400375 DbusChangedProps props;
376 std::string iface;
377 msg.read(iface, props);
378 const auto itr =
379 props.find("Activation");
380 if (itr != props.end())
381 {
382 PropertyValue value = itr->second;
383 auto propVal =
384 std::get<std::string>(value);
385 if (propVal ==
386 "xyz.openbmc_project.Software."
387 "Activation.Activations.Active")
388 {
389 CodeUpdateState state =
390 CodeUpdateState::END;
391 setCodeUpdateProgress(false);
392 auto sensorId =
393 getFirmwareUpdateSensor();
394 sendStateSensorEvent(
395 sensorId,
396 PLDM_STATE_SENSOR_STATE, 0,
397 uint8_t(state),
398 uint8_t(CodeUpdateState::
399 START));
400 newImageId.clear();
401 }
402 else if (propVal ==
403 "xyz.openbmc_project."
404 "Software.Activation."
405 "Activations.Failed" ||
406 propVal ==
407 "xyz.openbmc_"
408 "project.Software."
409 "Activation."
410 "Activations."
411 "Invalid")
412 {
413 CodeUpdateState state =
414 CodeUpdateState::FAIL;
415 setCodeUpdateProgress(false);
416 auto sensorId =
417 getFirmwareUpdateSensor();
418 sendStateSensorEvent(
419 sensorId,
420 PLDM_STATE_SENSOR_STATE, 0,
421 uint8_t(state),
422 uint8_t(CodeUpdateState::
423 START));
424 newImageId.clear();
425 }
426 }
427 });
428 }
429 auto rc = setRequestedActivation();
430 if (rc != PLDM_SUCCESS)
431 {
432 error("Could not set Requested Activation");
433 CodeUpdateState state = CodeUpdateState::FAIL;
434 setCodeUpdateProgress(false);
435 auto sensorId = getFirmwareUpdateSensor();
436 sendStateSensorEvent(
437 sensorId, PLDM_STATE_SENSOR_STATE, 0,
438 uint8_t(state),
439 uint8_t(CodeUpdateState::START));
440 }
441 break;
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500442 }
Archana Kakanic23b6142025-02-19 04:04:20 -0600443 else
444 {
445 // Out of band update
446 processRenameEvent();
447 }
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400448 }
449 catch (const sdbusplus::exception_t& e)
450 {
451 error(
452 "Failed to get activation status for interface '{INTERFACE}' and object path '{PATH}', error - {ERROR}",
453 "ERROR", e, "INTERFACE", imageInterface, "PATH",
454 imageObjPath);
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500455 }
Sampa Misraaea5dde2020-08-31 08:33:47 -0500456 }
457 }
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400458 }));
Sampa Misraaea5dde2020-08-31 08:33:47 -0500459}
460
Archana Kakanic23b6142025-02-19 04:04:20 -0600461void CodeUpdate::processRenameEvent()
462{
Archana Kakanie26d13f2025-03-09 23:17:46 -0500463 info("Processing Rename Event");
464
465 PendingAttributesList biosAttrList;
466 pldm_boot_side_data pldmBootSideData = readBootSideFile();
467 pldmBootSideData.current_boot_side = "Perm";
468 pldmBootSideData.next_boot_side = "Perm";
469
Archana Kakanic23b6142025-02-19 04:04:20 -0600470 currBootSide = Pside;
Archana Kakanie26d13f2025-03-09 23:17:46 -0500471 nextBootSide = Pside;
472
Archana Kakanic23b6142025-02-19 04:04:20 -0600473 auto sensorId = getBootSideRenameStateSensor();
Archana Kakanie26d13f2025-03-09 23:17:46 -0500474 info("Received sendor id for rename {ID}", "ID", sensorId);
Archana Kakanic23b6142025-02-19 04:04:20 -0600475 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
476 PLDM_OEM_IBM_BOOT_SIDE_RENAME_STATE_RENAMED,
477 PLDM_OEM_IBM_BOOT_SIDE_RENAME_STATE_NOT_RENAMED);
Archana Kakanie26d13f2025-03-09 23:17:46 -0500478 writeBootSideFile(pldmBootSideData);
479 biosAttrList.emplace_back(std::make_pair(
480 bootSideAttrName,
481 std::make_tuple(EnumAttribute, pldmBootSideData.current_boot_side)));
482 biosAttrList.push_back(std::make_pair(
483 bootNextSideAttrName,
484 std::make_tuple(EnumAttribute, pldmBootSideData.next_boot_side)));
485 setBiosAttr(biosAttrList);
486}
487
488void CodeUpdate::writeBootSideFile(const pldm_boot_side_data& pldmBootSideData)
489{
490 try
491 {
Archana Kakani97a0f482025-03-10 05:39:38 -0500492 fs::create_directories(fs::path(bootSideDirPath).parent_path());
Archana Kakanie26d13f2025-03-09 23:17:46 -0500493 std::ofstream writeFile(bootSideDirPath, std::ios::out);
494 if (!writeFile.is_open())
495 {
496 error("Failed to open bootside file {FILE} for writing", "FILE",
Archana Kakani97a0f482025-03-10 05:39:38 -0500497 bootSideDirPath);
Archana Kakanie26d13f2025-03-09 23:17:46 -0500498 return;
499 }
500
501 nlohmann::json data;
502 data["CurrentBootSide"] = pldmBootSideData.current_boot_side;
503 data["NextBootSide"] = pldmBootSideData.next_boot_side;
504 data["RunningObject"] = pldmBootSideData.running_version_object;
505
506 try
507 {
508 writeFile << data.dump(4);
509 }
510 catch (const nlohmann::json::exception& e)
511 {
512 error("JSON serialization for BootSide failed: {ERROR}", "ERROR",
513 e);
514 return;
515 }
516
517 writeFile.close();
518 }
519 catch (const std::exception& e)
520 {
521 error("Error {ERROR] while writing bootside file: {FILE}", "ERROR", e,
522 "FILE", bootSideDirPath);
523 }
524}
525
526pldm_boot_side_data CodeUpdate::readBootSideFile()
527{
528 pldm_boot_side_data pldmBootSideDataRead{};
529
Archana Kakani97a0f482025-03-10 05:39:38 -0500530 std::ifstream readFile(bootSideDirPath, std::ios::in);
Archana Kakanie26d13f2025-03-09 23:17:46 -0500531
532 if (!readFile)
533 {
534 error("Failed to read Bootside file");
535 return pldmBootSideDataRead;
536 }
537
538 nlohmann::json jsonBootSideData;
539 readFile >> jsonBootSideData;
540
541 pldm_boot_side_data data;
542 data.current_boot_side = jsonBootSideData.value("CurrentBootSide", "");
543 data.next_boot_side = jsonBootSideData.value("NextBootSide", "");
544 data.running_version_object = jsonBootSideData.value("RunningObject", "");
545
546 readFile.close();
547
548 return pldmBootSideDataRead;
Archana Kakanic23b6142025-02-19 04:04:20 -0600549}
550
Sampa Misraaea5dde2020-08-31 08:33:47 -0500551void CodeUpdate::processPriorityChangeNotification(
552 const DbusChangedProps& chProperties)
553{
Archana Kakani97a0f482025-03-10 05:39:38 -0500554 error("Processing priority change notification");
Sampa Misraaea5dde2020-08-31 08:33:47 -0500555 static constexpr auto propName = "Priority";
556 const auto it = chProperties.find(propName);
557 if (it == chProperties.end())
558 {
559 return;
560 }
561 uint8_t newVal = std::get<uint8_t>(it->second);
Archana Kakani97a0f482025-03-10 05:39:38 -0500562
563 pldm_boot_side_data pldmBootSideData = readBootSideFile();
564 pldmBootSideData.next_boot_side =
565 (newVal == 0)
566 ? pldmBootSideData.current_boot_side
567 : ((pldmBootSideData.current_boot_side == "Temp") ? "Perm"
568 : "Temp");
569 writeBootSideFile(pldmBootSideData);
570 nextBootSide = (pldmBootSideData.next_boot_side == "Temp" ? Tside : Pside);
571 std::string currNextBootSide;
572 auto attributeValue = getBiosAttrValue<std::string>(bootNextSideAttrName);
573 if (attributeValue.has_value())
574 {
575 currNextBootSide = attributeValue.value();
576 }
577
578 if (currNextBootSide == nextBootSide)
579 {
580 return;
581 }
582 PendingAttributesList biosAttrList;
583 biosAttrList.push_back(std::make_pair(
584 bootNextSideAttrName,
585 std::make_tuple(EnumAttribute, pldmBootSideData.next_boot_side)));
586 setBiosAttr(biosAttrList);
Sampa Misraaea5dde2020-08-31 08:33:47 -0500587}
588
589void CodeUpdate::setOemPlatformHandler(
590 pldm::responder::oem_platform::Handler* handler)
591{
592 oemPlatformHandler = handler;
593}
594
Varsha Kaverappa3ca29df2020-09-27 12:39:22 -0500595void CodeUpdate::clearDirPath(const std::string& dirPath)
596{
Manojkiran Eda78124cf2022-08-29 11:22:43 +0530597 if (!fs::is_directory(dirPath))
Varsha Kaverappa3ca29df2020-09-27 12:39:22 -0500598 {
Riya Dixitfc84f632024-04-06 14:00:02 -0500599 error("The directory '{PATH}' does not exist", "PATH", dirPath);
Manojkiran Eda78124cf2022-08-29 11:22:43 +0530600 return;
Varsha Kaverappa3ca29df2020-09-27 12:39:22 -0500601 }
Manojkiran Eda78124cf2022-08-29 11:22:43 +0530602 for (const auto& iter : fs::directory_iterator(dirPath))
603 {
604 fs::remove_all(iter);
605 }
Varsha Kaverappa3ca29df2020-09-27 12:39:22 -0500606}
607
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500608void CodeUpdate::sendStateSensorEvent(
609 uint16_t sensorId, enum sensor_event_class_states sensorEventClass,
610 uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState)
611{
612 pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler =
613 dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>(
614 oemPlatformHandler);
615 oemIbmPlatformHandler->sendStateSensorEvent(
616 sensorId, sensorEventClass, sensorOffset, eventState, prevEventState);
617}
618
619void CodeUpdate::deleteImage()
620{
621 static constexpr auto UPDATER_SERVICE =
622 "xyz.openbmc_project.Software.BMC.Updater";
623 static constexpr auto SW_OBJ_PATH = "/xyz/openbmc_project/software";
624 static constexpr auto DELETE_INTF =
625 "xyz.openbmc_project.Collection.DeleteAll";
626
627 auto& bus = dBusIntf->getBus();
628 try
629 {
630 auto method = bus.new_method_call(UPDATER_SERVICE, SW_OBJ_PATH,
631 DELETE_INTF, "DeleteAll");
vkaverap@in.ibm.com5b71b862023-08-21 05:19:04 +0000632 bus.call_noreply(method, dbusTimeout);
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500633 }
634 catch (const std::exception& e)
635 {
Sagar Srinivas90403472023-08-21 06:08:55 -0500636 error(
Riya Dixitfc84f632024-04-06 14:00:02 -0500637 "Failed to delete image at path '{PATH}' and interface '{INTERFACE}', error - {ERROR}",
638 "PATH", SW_OBJ_PATH, "INTERFACE", DELETE_INTF, "ERROR", e);
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500639 return;
640 }
641}
642
Sampa Misraaea5dde2020-08-31 08:33:47 -0500643uint8_t fetchBootSide(uint16_t entityInstance, CodeUpdate* codeUpdate)
644{
645 uint8_t sensorOpState = tSideNum;
Sampa Misraaea5dde2020-08-31 08:33:47 -0500646 if (entityInstance == 0)
647 {
648 auto currSide = codeUpdate->fetchCurrentBootSide();
649 if (currSide == Pside)
650 {
651 sensorOpState = pSideNum;
652 }
653 }
654 else if (entityInstance == 1)
655 {
656 auto nextSide = codeUpdate->fetchNextBootSide();
657 if (nextSide == Pside)
658 {
659 sensorOpState = pSideNum;
660 }
661 }
662 else
663 {
664 sensorOpState = PLDM_SENSOR_UNKNOWN;
665 }
666
667 return sensorOpState;
668}
669
670int setBootSide(uint16_t entityInstance, uint8_t currState,
671 const std::vector<set_effecter_state_field>& stateField,
672 CodeUpdate* codeUpdate)
673{
674 int rc = PLDM_SUCCESS;
675 auto side = (stateField[currState].effecter_state == pSideNum) ? "P" : "T";
676
677 if (entityInstance == 0)
678 {
679 rc = codeUpdate->setCurrentBootSide(side);
680 }
681 else if (entityInstance == 1)
682 {
683 rc = codeUpdate->setNextBootSide(side);
684 }
685 else
686 {
687 rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
688 }
689 return rc;
690}
691
Adriana Kobylak837fb472020-10-16 16:53:42 -0500692template <typename... T>
Patrick Williams6da4f912023-05-10 07:50:53 -0500693int executeCmd(const T&... t)
Adriana Kobylak837fb472020-10-16 16:53:42 -0500694{
695 std::stringstream cmd;
696 ((cmd << t << " "), ...) << std::endl;
697 FILE* pipe = popen(cmd.str().c_str(), "r");
698 if (!pipe)
699 {
700 throw std::runtime_error("popen() failed!");
701 }
702 int rc = pclose(pipe);
703 if (WEXITSTATUS(rc))
704 {
705 std::cerr << "Error executing: ";
706 ((std::cerr << " " << t), ...);
707 std::cerr << "\n";
708 return -1;
709 }
710
711 return 0;
712}
713
Adriana Kobylak727f7382020-09-01 14:38:25 -0500714int processCodeUpdateLid(const std::string& filePath)
715{
716 struct LidHeader
717 {
718 uint16_t magicNumber;
Adriana Kobylak86d14182020-10-16 16:11:08 -0500719 uint16_t headerVersion;
720 uint32_t lidNumber;
721 uint32_t lidDate;
722 uint16_t lidTime;
723 uint16_t lidClass;
724 uint32_t lidCrc;
725 uint32_t lidSize;
726 uint32_t headerSize;
Adriana Kobylak727f7382020-09-01 14:38:25 -0500727 };
728 LidHeader header;
729
730 std::ifstream ifs(filePath, std::ios::in | std::ios::binary);
731 if (!ifs)
732 {
Riya Dixitfc84f632024-04-06 14:00:02 -0500733 error("Failed to opening file '{FILE}' ifstream", "PATH", filePath);
Adriana Kobylak727f7382020-09-01 14:38:25 -0500734 return PLDM_ERROR;
735 }
736 ifs.seekg(0);
737 ifs.read(reinterpret_cast<char*>(&header), sizeof(header));
Adriana Kobylak727f7382020-09-01 14:38:25 -0500738
Adriana Kobylak86d14182020-10-16 16:11:08 -0500739 // File size should be the value of lid size minus the header size
740 auto fileSize = fs::file_size(filePath);
741 fileSize -= htonl(header.headerSize);
742 if (fileSize < htonl(header.lidSize))
743 {
744 // File is not completely written yet
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500745 ifs.close();
Adriana Kobylak86d14182020-10-16 16:11:08 -0500746 return PLDM_SUCCESS;
747 }
748
Adriana Kobylak727f7382020-09-01 14:38:25 -0500749 constexpr auto magicNumber = 0x0222;
750 if (htons(header.magicNumber) != magicNumber)
751 {
Riya Dixitfc84f632024-04-06 14:00:02 -0500752 error("Invalid magic number for file '{PATH}'", "PATH", filePath);
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500753 ifs.close();
Adriana Kobylak727f7382020-09-01 14:38:25 -0500754 return PLDM_ERROR;
755 }
756
Adriana Kobylaka1f158c2020-11-09 12:47:29 -0600757 fs::create_directories(imageDirPath);
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500758 fs::create_directories(lidDirPath);
759
Adriana Kobylaka1f158c2020-11-09 12:47:29 -0600760 constexpr auto bmcClass = 0x2000;
761 if (htons(header.lidClass) == bmcClass)
762 {
763 // Skip the header and concatenate the BMC LIDs into a tar file
764 std::ofstream ofs(tarImagePath,
765 std::ios::out | std::ios::binary | std::ios::app);
766 ifs.seekg(htonl(header.headerSize));
767 ofs << ifs.rdbuf();
768 ofs.flush();
769 ofs.close();
770 }
771 else
772 {
773 std::stringstream lidFileName;
774 lidFileName << std::hex << htonl(header.lidNumber) << ".lid";
775 auto lidNoHeaderPath = fs::path(lidDirPath) / lidFileName.str();
776 std::ofstream ofs(lidNoHeaderPath,
777 std::ios::out | std::ios::binary | std::ios::trunc);
778 ifs.seekg(htonl(header.headerSize));
779 ofs << ifs.rdbuf();
780 ofs.flush();
781 ofs.close();
782 }
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500783
784 ifs.close();
785 fs::remove(filePath);
Adriana Kobylak727f7382020-09-01 14:38:25 -0500786 return PLDM_SUCCESS;
787}
788
Adriana Kobylak9296f242021-09-22 15:52:00 +0000789int CodeUpdate::assembleCodeUpdateImage()
Adriana Kobylak837fb472020-10-16 16:53:42 -0500790{
Adriana Kobylak9296f242021-09-22 15:52:00 +0000791 pid_t pid = fork();
792
793 if (pid == 0)
Adriana Kobylak837fb472020-10-16 16:53:42 -0500794 {
Adriana Kobylak9296f242021-09-22 15:52:00 +0000795 pid_t nextPid = fork();
796 if (nextPid == 0)
797 {
798 // Create the hostfw squashfs image from the LID files without
799 // header
800 auto rc = executeCmd("/usr/sbin/mksquashfs", lidDirPath.c_str(),
801 hostfwImagePath.c_str(), "-all-root",
802 "-no-recovery");
803 if (rc < 0)
804 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600805 error("Error occurred during the mksqusquashfs call");
Adriana Kobylak9296f242021-09-22 15:52:00 +0000806 setCodeUpdateProgress(false);
807 auto sensorId = getFirmwareUpdateSensor();
808 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
809 uint8_t(CodeUpdateState::FAIL),
810 uint8_t(CodeUpdateState::START));
811 exit(EXIT_FAILURE);
812 }
813
814 fs::create_directories(updateDirPath);
815
816 // Extract the BMC tarball content
817 rc = executeCmd("/bin/tar", "-xf", tarImagePath.c_str(), "-C",
818 updateDirPath);
819 if (rc < 0)
820 {
821 setCodeUpdateProgress(false);
822 auto sensorId = getFirmwareUpdateSensor();
823 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
824 uint8_t(CodeUpdateState::FAIL),
825 uint8_t(CodeUpdateState::START));
826 exit(EXIT_FAILURE);
827 }
828
829 // Add the hostfw image to the directory where the contents were
830 // extracted
831 fs::copy_file(hostfwImagePath,
832 fs::path(updateDirPath) / hostfwImageName,
833 fs::copy_options::overwrite_existing);
834
835 // Remove the tarball file, then re-generate it with so that the
836 // hostfw image becomes part of the tarball
837 fs::remove(tarImagePath);
838 rc = executeCmd("/bin/tar", "-cf", tarImagePath, ".", "-C",
839 updateDirPath);
840 if (rc < 0)
841 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600842 error("Error occurred during the generation of the tarball");
Adriana Kobylak9296f242021-09-22 15:52:00 +0000843 setCodeUpdateProgress(false);
844 auto sensorId = getFirmwareUpdateSensor();
845 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
846 uint8_t(CodeUpdateState::FAIL),
847 uint8_t(CodeUpdateState::START));
848 exit(EXIT_FAILURE);
849 }
850
851 // Copy the tarball to the update directory to trigger the phosphor
852 // software manager to create a version interface
853 fs::copy_file(tarImagePath, updateImagePath,
854 fs::copy_options::overwrite_existing);
855
856 // Cleanup
857 fs::remove_all(updateDirPath);
858 fs::remove_all(lidDirPath);
859 fs::remove_all(imageDirPath);
860
861 exit(EXIT_SUCCESS);
862 }
863 else if (nextPid < 0)
864 {
Riya Dixitfc84f632024-04-06 14:00:02 -0500865 error("Failure occurred during fork, error number - {ERROR_NUM}",
866 "ERROR_NUM", errno);
Adriana Kobylak9296f242021-09-22 15:52:00 +0000867 exit(EXIT_FAILURE);
868 }
869
870 // Do nothing as parent. When parent exits, child will be reparented
871 // under init and be reaped properly.
872 exit(0);
873 }
874 else if (pid > 0)
875 {
876 int status;
877 if (waitpid(pid, &status, 0) < 0)
878 {
Riya Dixitfc84f632024-04-06 14:00:02 -0500879 error("Error occurred during waitpid, error number - {ERROR_NUM}",
880 "ERROR_NUM", errno);
Riya Dixit49cfb132023-03-02 04:26:53 -0600881
Adriana Kobylak9296f242021-09-22 15:52:00 +0000882 return PLDM_ERROR;
883 }
884 else if (WEXITSTATUS(status) != 0)
885 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600886 error(
Riya Dixitfc84f632024-04-06 14:00:02 -0500887 "Failed to execute the assembling of the image, status is {IMG_STATUS}",
Riya Dixit49cfb132023-03-02 04:26:53 -0600888 "IMG_STATUS", status);
Adriana Kobylak9296f242021-09-22 15:52:00 +0000889 return PLDM_ERROR;
890 }
891 }
892 else
893 {
Riya Dixitfc84f632024-04-06 14:00:02 -0500894 error("Error occurred during fork, error number - {ERROR_NUM}}",
895 "ERROR_NUM", errno);
Adriana Kobylak837fb472020-10-16 16:53:42 -0500896 return PLDM_ERROR;
897 }
898
Adriana Kobylak837fb472020-10-16 16:53:42 -0500899 return PLDM_SUCCESS;
900}
901
Sampa Misraaea5dde2020-08-31 08:33:47 -0500902} // namespace responder
903} // namespace pldm