blob: f891877088db80b51431f91a08a227e697d33be1 [file] [log] [blame]
Saqib Khanb0774702017-05-23 16:02:41 -05001#include "activation.hpp"
Gunnar Millsb0ce9962018-09-07 13:39:10 -05002
Lei YU1be8d502018-06-20 11:48:36 +08003#include "images.hpp"
Saqib Khan4c1aec02017-07-06 11:46:13 -05004#include "item_updater.hpp"
Saqib Khan5d532672017-08-09 10:44:50 -05005#include "serialize.hpp"
Gunnar Millsb0ce9962018-09-07 13:39:10 -05006
Jayashankar Padatha0135602019-04-22 16:22:58 +05307#include <phosphor-logging/elog-errors.hpp>
8#include <phosphor-logging/elog.hpp>
Saqib Khanb9da6632017-09-13 09:48:37 -05009#include <phosphor-logging/log.hpp>
Adriana Kobylakaea48f22018-07-10 10:20:56 -050010#include <sdbusplus/exception.hpp>
Jayashankar Padatha0135602019-04-22 16:22:58 +053011#include <xyz/openbmc_project/Common/error.hpp>
Saqib Khanb9da6632017-09-13 09:48:37 -050012
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060013#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060014#include "image_verify.hpp"
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060015#endif
16
Saqib Khanb0774702017-05-23 16:02:41 -050017namespace phosphor
18{
19namespace software
20{
21namespace updater
22{
23
24namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
25
Saqib Khanb9da6632017-09-13 09:48:37 -050026using namespace phosphor::logging;
Adriana Kobylakaea48f22018-07-10 10:20:56 -050027using sdbusplus::exception::SdBusError;
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060028using InternalFailure =
29 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Jayashankar Padatha0135602019-04-22 16:22:58 +053030
31#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth9a9d7c22018-03-28 10:05:26 -050032namespace control = sdbusplus::xyz::openbmc_project::Control::server;
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060033#endif
34
Michael Tritzbed88af2017-07-19 16:00:06 -050035void Activation::subscribeToSystemdSignals()
36{
Adriana Kobylak2285fe02018-02-27 15:36:59 -060037 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
38 SYSTEMD_INTERFACE, "Subscribe");
Adriana Kobylakaea48f22018-07-10 10:20:56 -050039 try
40 {
41 this->bus.call_noreply(method);
42 }
43 catch (const SdBusError& e)
44 {
45 if (e.name() != nullptr &&
46 strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0)
47 {
48 // If an Activation attempt fails, the Unsubscribe method is not
49 // called. This may lead to an AlreadySubscribed error if the
50 // Activation is re-attempted.
51 }
52 else
53 {
54 log<level::ERR>("Error subscribing to systemd",
55 entry("ERROR=%s", e.what()));
56 }
57 }
Michael Tritzbed88af2017-07-19 16:00:06 -050058
59 return;
60}
61
Michael Tritzf2b5e0d2017-07-25 14:39:34 -050062void Activation::unsubscribeFromSystemdSignals()
63{
Adriana Kobylak2285fe02018-02-27 15:36:59 -060064 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
65 SYSTEMD_INTERFACE, "Unsubscribe");
Jayashankar Padatha0135602019-04-22 16:22:58 +053066 try
67 {
68 this->bus.call_noreply(method);
69 }
70 catch (const SdBusError& e)
71 {
72 log<level::ERR>("Error in unsubscribing from systemd signals",
73 entry("ERROR=%s", e.what()));
74 }
Michael Tritzf2b5e0d2017-07-25 14:39:34 -050075
76 return;
77}
78
Adriana Kobylak2285fe02018-02-27 15:36:59 -060079auto Activation::activation(Activations value) -> Activations
Saqib Khanb0774702017-05-23 16:02:41 -050080{
Saqib Khan4c1aec02017-07-06 11:46:13 -050081
Adriana Kobylak8bd84c82018-01-24 14:19:24 -060082 if ((value != softwareServer::Activation::Activations::Active) &&
83 (value != softwareServer::Activation::Activations::Activating))
Saqib Khan4c1aec02017-07-06 11:46:13 -050084 {
85 redundancyPriority.reset(nullptr);
86 }
87
Saqib Khanb0774702017-05-23 16:02:41 -050088 if (value == softwareServer::Activation::Activations::Activating)
89 {
Vijay Khemkae9f6c842020-01-14 14:32:39 -080090
91#ifdef HOST_BIOS_UPGRADE
92 auto purpose = parent.versions.find(versionId)->second->purpose();
93 if (purpose == VersionPurpose::Host)
94 {
95 if (!activationProgress)
96 {
97 activationProgress =
98 std::make_unique<ActivationProgress>(bus, path);
99 }
100
101 // Enable systemd signals
102 subscribeToSystemdSignals();
103
104 // Set initial progress
105 activationProgress->progress(20);
106
107 // Initiate image writing to flash
108 flashWriteHost();
109
110 return softwareServer::Activation::activation(value);
111 }
112#endif
113
Lei YUa7853ee2018-05-23 11:13:12 +0800114#ifdef UBIFS_LAYOUT
Michael Tritzbed88af2017-07-19 16:00:06 -0500115 if (rwVolumeCreated == false && roVolumeCreated == false)
Saqib Khanb0774702017-05-23 16:02:41 -0500116 {
Adriana Kobylakaea48f22018-07-10 10:20:56 -0500117 // Enable systemd signals
118 Activation::subscribeToSystemdSignals();
119
Adriana Kobylaka6963592018-09-07 14:13:29 -0500120 parent.freeSpace(*this);
Adriana Kobylak204e1e72018-01-24 16:00:05 -0600121
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500122 if (!activationProgress)
123 {
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600124 activationProgress =
125 std::make_unique<ActivationProgress>(bus, path);
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500126 }
127
Michael Tritzbed88af2017-07-19 16:00:06 -0500128 if (!activationBlocksTransition)
129 {
130 activationBlocksTransition =
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600131 std::make_unique<ActivationBlocksTransition>(bus, path);
Michael Tritzbed88af2017-07-19 16:00:06 -0500132 }
Saqib Khan4c1aec02017-07-06 11:46:13 -0500133
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -0600134#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -0600135 fs::path uploadDir(IMG_UPLOAD_DIR);
Lei YU90532252018-05-24 11:15:24 +0800136 if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -0600137 {
Lei YU90532252018-05-24 11:15:24 +0800138 onVerifyFailed();
Jayanth Othayoth9a9d7c22018-03-28 10:05:26 -0500139 // Stop the activation process, if fieldMode is enabled.
140 if (parent.control::FieldMode::fieldModeEnabled())
141 {
142 // Cleanup
143 activationBlocksTransition.reset(nullptr);
144 activationProgress.reset(nullptr);
Jayanth Othayoth9a9d7c22018-03-28 10:05:26 -0500145 return softwareServer::Activation::activation(
146 softwareServer::Activation::Activations::Failed);
147 }
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -0600148 }
149#endif
150
Adriana Kobylak9f89e2e2018-05-30 13:16:20 -0500151 flashWrite();
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500152
153 activationProgress->progress(10);
Michael Tritzbed88af2017-07-19 16:00:06 -0500154 }
155 else if (rwVolumeCreated == true && roVolumeCreated == true)
Saqib Khan4c1aec02017-07-06 11:46:13 -0500156 {
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500157 if (ubootEnvVarsUpdated == false)
Michael Tritzbed88af2017-07-19 16:00:06 -0500158 {
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500159 activationProgress->progress(90);
160
Adriana Kobylakec4eec32019-11-13 14:28:35 -0600161 storePurpose(
162 versionId,
163 parent.versions.find(versionId)->second->purpose());
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500164 if (!redundancyPriority)
165 {
166 redundancyPriority = std::make_unique<RedundancyPriority>(
167 bus, path, *this, 0);
168 }
Michael Tritzbed88af2017-07-19 16:00:06 -0500169 }
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500170 else
171 {
172 activationProgress->progress(100);
Saqib Khan4c1aec02017-07-06 11:46:13 -0500173
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500174 activationBlocksTransition.reset(nullptr);
175 activationProgress.reset(nullptr);
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500176
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500177 rwVolumeCreated = false;
178 roVolumeCreated = false;
179 ubootEnvVarsUpdated = false;
180 Activation::unsubscribeFromSystemdSignals();
Michael Tritzf2b5e0d2017-07-25 14:39:34 -0500181
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500182 // Remove version object from image manager
183 Activation::deleteImageManagerObject();
Michael Tritzf2b5e0d2017-07-25 14:39:34 -0500184
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500185 // Create active association
186 parent.createActiveAssociation(path);
Saqib Khanee13e832017-10-23 12:53:11 -0500187
AppaRao Pulibbebec72020-01-28 23:57:41 +0530188 // Create updateable association as this
189 // can be re-programmed.
190 parent.createUpdateableAssociation(path);
191
Jayashankar Padatha0135602019-04-22 16:22:58 +0530192 if (Activation::checkApplyTimeImmediate() == true)
193 {
194 log<level::INFO>("Image Active. ApplyTime is immediate, "
195 "rebooting BMC.");
196 Activation::rebootBmc();
197 }
198
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500199 return softwareServer::Activation::activation(
200 softwareServer::Activation::Activations::Active);
201 }
Michael Tritzbed88af2017-07-19 16:00:06 -0500202 }
Lei YUa7853ee2018-05-23 11:13:12 +0800203#else // !UBIFS_LAYOUT
204
Lei YU90532252018-05-24 11:15:24 +0800205#ifdef WANT_SIGNATURE_VERIFY
206 fs::path uploadDir(IMG_UPLOAD_DIR);
207 if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
208 {
209 onVerifyFailed();
210 // Stop the activation process, if fieldMode is enabled.
211 if (parent.control::FieldMode::fieldModeEnabled())
212 {
213 return softwareServer::Activation::activation(
214 softwareServer::Activation::Activations::Failed);
215 }
216 }
217#endif
Adriana Kobylaka6963592018-09-07 14:13:29 -0500218 parent.freeSpace(*this);
Lei YUa7853ee2018-05-23 11:13:12 +0800219
220 flashWrite();
221
Adriana Kobylakec4eec32019-11-13 14:28:35 -0600222 storePurpose(versionId,
223 parent.versions.find(versionId)->second->purpose());
Lei YUa7853ee2018-05-23 11:13:12 +0800224 if (!redundancyPriority)
225 {
226 redundancyPriority =
227 std::make_unique<RedundancyPriority>(bus, path, *this, 0);
228 }
229
230 // Remove version object from image manager
231 Activation::deleteImageManagerObject();
232
233 // Create active association
234 parent.createActiveAssociation(path);
235
Bright Cheng0d7198f2019-11-18 16:45:01 +0800236 if (Activation::checkApplyTimeImmediate() == true)
237 {
238 log<level::INFO>("Image Active. ApplyTime is immediate, "
239 "rebooting BMC.");
240 Activation::rebootBmc();
241 }
242 else
243 {
244 log<level::INFO>("BMC image ready, need reboot to get activated.");
245 }
246
Lei YUa7853ee2018-05-23 11:13:12 +0800247 return softwareServer::Activation::activation(
248 softwareServer::Activation::Activations::Active);
249#endif
Saqib Khanb0774702017-05-23 16:02:41 -0500250 }
251 else
252 {
253 activationBlocksTransition.reset(nullptr);
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500254 activationProgress.reset(nullptr);
Saqib Khanb0774702017-05-23 16:02:41 -0500255 }
256 return softwareServer::Activation::activation(value);
257}
258
Saqib Khanee13e832017-10-23 12:53:11 -0500259void Activation::deleteImageManagerObject()
260{
Saqib Khanee13e832017-10-23 12:53:11 -0500261 // Call the Delete object for <versionID> inside image_manager
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600262 auto method = this->bus.new_method_call(VERSION_BUSNAME, path.c_str(),
263 "xyz.openbmc_project.Object.Delete",
264 "Delete");
Adriana Kobylak3b6a4cd2018-12-10 13:45:09 -0600265 try
266 {
267 bus.call_noreply(method);
268 }
269 catch (const SdBusError& e)
Saqib Khanee13e832017-10-23 12:53:11 -0500270 {
271 log<level::ERR>("Error in Deleting image from image manager",
Adriana Kobylak596466b2018-02-13 14:48:53 -0600272 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khanee13e832017-10-23 12:53:11 -0500273 return;
274 }
275}
276
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600277auto Activation::requestedActivation(RequestedActivations value)
278 -> RequestedActivations
Saqib Khanb0774702017-05-23 16:02:41 -0500279{
Michael Tritzbed88af2017-07-19 16:00:06 -0500280 rwVolumeCreated = false;
281 roVolumeCreated = false;
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500282 ubootEnvVarsUpdated = false;
Michael Tritzbed88af2017-07-19 16:00:06 -0500283
Saqib Khanb0774702017-05-23 16:02:41 -0500284 if ((value == softwareServer::Activation::RequestedActivations::Active) &&
285 (softwareServer::Activation::requestedActivation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600286 softwareServer::Activation::RequestedActivations::Active))
Saqib Khanb0774702017-05-23 16:02:41 -0500287 {
288 if ((softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600289 softwareServer::Activation::Activations::Ready) ||
Saqib Khanb0774702017-05-23 16:02:41 -0500290 (softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600291 softwareServer::Activation::Activations::Failed))
Saqib Khanb0774702017-05-23 16:02:41 -0500292 {
293 Activation::activation(
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600294 softwareServer::Activation::Activations::Activating);
Saqib Khanb0774702017-05-23 16:02:41 -0500295 }
296 }
297 return softwareServer::Activation::requestedActivation(value);
298}
299
Saqib Khan4c1aec02017-07-06 11:46:13 -0500300uint8_t RedundancyPriority::priority(uint8_t value)
301{
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500302 // Set the priority value so that the freePriority() function can order
303 // the versions by priority.
304 auto newPriority = softwareServer::RedundancyPriority::priority(value);
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500305 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500306 parent.parent.freePriority(value, parent.versionId);
307 return newPriority;
Saqib Khan4c1aec02017-07-06 11:46:13 -0500308}
309
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500310uint8_t RedundancyPriority::sdbusPriority(uint8_t value)
Saqib Khanf0382c32017-10-24 13:36:22 -0500311{
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500312 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500313 return softwareServer::RedundancyPriority::priority(value);
Saqib Khanf0382c32017-10-24 13:36:22 -0500314}
315
Michael Tritzbed88af2017-07-19 16:00:06 -0500316void Activation::unitStateChange(sdbusplus::message::message& msg)
317{
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500318 if (softwareServer::Activation::activation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600319 softwareServer::Activation::Activations::Activating)
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500320 {
321 return;
322 }
323
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800324#ifdef HOST_BIOS_UPGRADE
325 auto purpose = parent.versions.find(versionId)->second->purpose();
326 if (purpose == VersionPurpose::Host)
327 {
328 onStateChangesBios(msg);
329 return;
330 }
331#endif
332
Adriana Kobylak3ce563a2018-06-06 16:41:15 -0500333 onStateChanges(msg);
Michael Tritzbed88af2017-07-19 16:00:06 -0500334
335 return;
336}
337
Lei YU90532252018-05-24 11:15:24 +0800338#ifdef WANT_SIGNATURE_VERIFY
339bool Activation::verifySignature(const fs::path& imageDir,
340 const fs::path& confDir)
341{
342 using Signature = phosphor::software::image::Signature;
343
344 Signature signature(imageDir, confDir);
345
346 return signature.verify();
347}
348
349void Activation::onVerifyFailed()
350{
351 log<level::ERR>("Error occurred during image validation");
352 report<InternalFailure>();
353}
354#endif
355
Saqib Khanf37cefc2017-09-12 08:44:41 -0500356void ActivationBlocksTransition::enableRebootGuard()
357{
358 log<level::INFO>("BMC image activating - BMC reboots are disabled.");
359
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600360 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
361 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500362 method.append("reboot-guard-enable.service", "replace");
363 bus.call_noreply(method);
364}
365
366void ActivationBlocksTransition::disableRebootGuard()
367{
368 log<level::INFO>("BMC activation has ended - BMC reboots are re-enabled.");
369
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600370 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
371 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500372 method.append("reboot-guard-disable.service", "replace");
373 bus.call_noreply(method);
374}
Michael Tritzbed88af2017-07-19 16:00:06 -0500375
Jayashankar Padatha0135602019-04-22 16:22:58 +0530376bool Activation::checkApplyTimeImmediate()
377{
378 auto service = utils::getService(bus, applyTimeObjPath, applyTimeIntf);
379 if (service.empty())
380 {
381 log<level::INFO>("Error getting the service name for BMC image "
382 "ApplyTime. The BMC needs to be manually rebooted to "
383 "complete the image activation if needed "
384 "immediately.");
385 }
386 else
387 {
388
389 auto method = bus.new_method_call(service.c_str(), applyTimeObjPath,
390 dbusPropIntf, "Get");
391 method.append(applyTimeIntf, applyTimeProp);
392
393 try
394 {
395 auto reply = bus.call(method);
396
Patrick Williams24048b52020-05-13 17:51:30 -0500397 std::variant<std::string> result;
Jayashankar Padatha0135602019-04-22 16:22:58 +0530398 reply.read(result);
Patrick Williamse883fb82020-05-13 11:38:55 -0500399 auto applyTime = std::get<std::string>(result);
Jayashankar Padatha0135602019-04-22 16:22:58 +0530400 if (applyTime == applyTimeImmediate)
401 {
402 return true;
403 }
404 }
405 catch (const SdBusError& e)
406 {
407 log<level::ERR>("Error in getting ApplyTime",
408 entry("ERROR=%s", e.what()));
409 }
410 }
411 return false;
412}
413
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800414#ifdef HOST_BIOS_UPGRADE
415void Activation::flashWriteHost()
416{
417 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
418 SYSTEMD_INTERFACE, "StartUnit");
419 auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
420 method.append(biosServiceFile, "replace");
421 try
422 {
423 auto reply = bus.call(method);
424 }
425 catch (const SdBusError& e)
426 {
427 log<level::ERR>("Error in trying to upgrade Host Bios.");
428 report<InternalFailure>();
429 }
430}
431
432void Activation::onStateChangesBios(sdbusplus::message::message& msg)
433{
434 uint32_t newStateID{};
435 sdbusplus::message::object_path newStateObjPath;
436 std::string newStateUnit{};
437 std::string newStateResult{};
438
439 // Read the msg and populate each variable
440 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
441
442 auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
443
444 if (newStateUnit == biosServiceFile)
445 {
446 // unsubscribe to systemd signals
447 unsubscribeFromSystemdSignals();
448
449 // Remove version object from image manager
450 deleteImageManagerObject();
451
452 if (newStateResult == "done")
453 {
454 // Set activation progress to 100
455 activationProgress->progress(100);
456
457 // Set Activation value to active
458 activation(softwareServer::Activation::Activations::Active);
459
460 log<level::INFO>("Bios upgrade completed successfully.");
461 }
462 else if (newStateResult == "failed")
463 {
464 // Set Activation value to Failed
465 activation(softwareServer::Activation::Activations::Failed);
466
467 log<level::ERR>("Bios upgrade failed.");
468 }
469 }
470
471 return;
472}
473
474#endif
475
Jayashankar Padatha0135602019-04-22 16:22:58 +0530476void Activation::rebootBmc()
477{
478 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
479 SYSTEMD_INTERFACE, "StartUnit");
480 method.append("force-reboot.service", "replace");
481 try
482 {
483 auto reply = bus.call(method);
484 }
485 catch (const SdBusError& e)
486 {
487 log<level::ALERT>("Error in trying to reboot the BMC. "
488 "The BMC needs to be manually rebooted to complete "
489 "the image activation.");
490 report<InternalFailure>();
491 }
492}
493
Saqib Khanb0774702017-05-23 16:02:41 -0500494} // namespace updater
495} // namespace software
496} // namespace phosphor