blob: f27050438ea5cdd98e8568fb4f4a8754760697f2 [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"
Miguel Gomez21dad042020-06-26 20:54:48 +00005#include "msl_verify.hpp"
Saqib Khan5d532672017-08-09 10:44:50 -05006#include "serialize.hpp"
Gunnar Millsb0ce9962018-09-07 13:39:10 -05007
Jayashankar Padatha0135602019-04-22 16:22:58 +05308#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/elog.hpp>
Saqib Khanb9da6632017-09-13 09:48:37 -050010#include <phosphor-logging/log.hpp>
Adriana Kobylakaea48f22018-07-10 10:20:56 -050011#include <sdbusplus/exception.hpp>
Jayashankar Padatha0135602019-04-22 16:22:58 +053012#include <xyz/openbmc_project/Common/error.hpp>
Miguel Gomez21dad042020-06-26 20:54:48 +000013#include <xyz/openbmc_project/Software/Version/error.hpp>
Saqib Khanb9da6632017-09-13 09:48:37 -050014
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060015#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060016#include "image_verify.hpp"
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060017#endif
18
Saqib Khanb0774702017-05-23 16:02:41 -050019namespace phosphor
20{
21namespace software
22{
23namespace updater
24{
25
26namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
27
Saqib Khanb9da6632017-09-13 09:48:37 -050028using namespace phosphor::logging;
Adriana Kobylakaea48f22018-07-10 10:20:56 -050029using sdbusplus::exception::SdBusError;
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060030using InternalFailure =
31 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Jayashankar Padatha0135602019-04-22 16:22:58 +053032
33#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth9a9d7c22018-03-28 10:05:26 -050034namespace control = sdbusplus::xyz::openbmc_project::Control::server;
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060035#endif
36
Michael Tritzbed88af2017-07-19 16:00:06 -050037void Activation::subscribeToSystemdSignals()
38{
Adriana Kobylak2285fe02018-02-27 15:36:59 -060039 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
40 SYSTEMD_INTERFACE, "Subscribe");
Adriana Kobylakaea48f22018-07-10 10:20:56 -050041 try
42 {
43 this->bus.call_noreply(method);
44 }
45 catch (const SdBusError& e)
46 {
47 if (e.name() != nullptr &&
48 strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0)
49 {
50 // If an Activation attempt fails, the Unsubscribe method is not
51 // called. This may lead to an AlreadySubscribed error if the
52 // Activation is re-attempted.
53 }
54 else
55 {
56 log<level::ERR>("Error subscribing to systemd",
57 entry("ERROR=%s", e.what()));
58 }
59 }
Michael Tritzbed88af2017-07-19 16:00:06 -050060
61 return;
62}
63
Michael Tritzf2b5e0d2017-07-25 14:39:34 -050064void Activation::unsubscribeFromSystemdSignals()
65{
Adriana Kobylak2285fe02018-02-27 15:36:59 -060066 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
67 SYSTEMD_INTERFACE, "Unsubscribe");
Jayashankar Padatha0135602019-04-22 16:22:58 +053068 try
69 {
70 this->bus.call_noreply(method);
71 }
72 catch (const SdBusError& e)
73 {
74 log<level::ERR>("Error in unsubscribing from systemd signals",
75 entry("ERROR=%s", e.what()));
76 }
Michael Tritzf2b5e0d2017-07-25 14:39:34 -050077
78 return;
79}
80
Adriana Kobylak2285fe02018-02-27 15:36:59 -060081auto Activation::activation(Activations value) -> Activations
Saqib Khanb0774702017-05-23 16:02:41 -050082{
Adriana Kobylak8bd84c82018-01-24 14:19:24 -060083 if ((value != softwareServer::Activation::Activations::Active) &&
84 (value != softwareServer::Activation::Activations::Activating))
Saqib Khan4c1aec02017-07-06 11:46:13 -050085 {
86 redundancyPriority.reset(nullptr);
87 }
88
Saqib Khanb0774702017-05-23 16:02:41 -050089 if (value == softwareServer::Activation::Activations::Activating)
90 {
Lei YU7ab55e22021-05-19 13:26:53 +080091#ifdef WANT_SIGNATURE_VERIFY
92 fs::path uploadDir(IMG_UPLOAD_DIR);
93 if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
94 {
95 onVerifyFailed();
96 // Stop the activation process, if fieldMode is enabled.
97 if (parent.control::FieldMode::fieldModeEnabled())
98 {
99 return softwareServer::Activation::activation(
100 softwareServer::Activation::Activations::Failed);
101 }
102 }
103#endif
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800104
105#ifdef HOST_BIOS_UPGRADE
106 auto purpose = parent.versions.find(versionId)->second->purpose();
107 if (purpose == VersionPurpose::Host)
108 {
109 if (!activationProgress)
110 {
111 activationProgress =
112 std::make_unique<ActivationProgress>(bus, path);
113 }
114
115 // Enable systemd signals
116 subscribeToSystemdSignals();
117
118 // Set initial progress
119 activationProgress->progress(20);
120
121 // Initiate image writing to flash
122 flashWriteHost();
123
124 return softwareServer::Activation::activation(value);
125 }
126#endif
127
Miguel Gomez21dad042020-06-26 20:54:48 +0000128 auto versionStr = parent.versions.find(versionId)->second->version();
129
130 if (!minimum_ship_level::verify(versionStr))
131 {
132 using namespace phosphor::logging;
133 using IncompatibleErr = sdbusplus::xyz::openbmc_project::Software::
134 Version::Error::Incompatible;
135 using Incompatible =
136 xyz::openbmc_project::Software::Version::Incompatible;
137
138 report<IncompatibleErr>(
139 prev_entry<Incompatible::MIN_VERSION>(),
140 prev_entry<Incompatible::ACTUAL_VERSION>(),
141 prev_entry<Incompatible::VERSION_PURPOSE>());
142 return softwareServer::Activation::activation(
143 softwareServer::Activation::Activations::Failed);
144 }
145
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500146 if (!activationProgress)
147 {
148 activationProgress =
149 std::make_unique<ActivationProgress>(bus, path);
150 }
151
152 if (!activationBlocksTransition)
153 {
154 activationBlocksTransition =
155 std::make_unique<ActivationBlocksTransition>(bus, path);
156 }
157
158 activationProgress->progress(10);
159
Adriana Kobylaka6963592018-09-07 14:13:29 -0500160 parent.freeSpace(*this);
Lei YUa7853ee2018-05-23 11:13:12 +0800161
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500162 // Enable systemd signals
163 Activation::subscribeToSystemdSignals();
164
Lei YUa7853ee2018-05-23 11:13:12 +0800165 flashWrite();
166
Adriana Kobylak70f5bc02020-05-13 14:08:14 -0500167#if defined UBIFS_LAYOUT || defined MMC_LAYOUT
Lei YUa7853ee2018-05-23 11:13:12 +0800168
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500169 return softwareServer::Activation::activation(value);
Lei YUa7853ee2018-05-23 11:13:12 +0800170
Adriana Kobylak70f5bc02020-05-13 14:08:14 -0500171#else // STATIC_LAYOUT
Lei YUa7853ee2018-05-23 11:13:12 +0800172
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500173 onFlashWriteSuccess();
Lei YUa7853ee2018-05-23 11:13:12 +0800174 return softwareServer::Activation::activation(
175 softwareServer::Activation::Activations::Active);
176#endif
Saqib Khanb0774702017-05-23 16:02:41 -0500177 }
178 else
179 {
180 activationBlocksTransition.reset(nullptr);
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500181 activationProgress.reset(nullptr);
Saqib Khanb0774702017-05-23 16:02:41 -0500182 }
183 return softwareServer::Activation::activation(value);
184}
185
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500186void Activation::onFlashWriteSuccess()
187{
188 activationProgress->progress(100);
189
190 activationBlocksTransition.reset(nullptr);
191 activationProgress.reset(nullptr);
192
193 rwVolumeCreated = false;
194 roVolumeCreated = false;
195 ubootEnvVarsUpdated = false;
196 Activation::unsubscribeFromSystemdSignals();
197
198 storePurpose(versionId, parent.versions.find(versionId)->second->purpose());
199
200 if (!redundancyPriority)
201 {
202 redundancyPriority =
203 std::make_unique<RedundancyPriority>(bus, path, *this, 0);
204 }
205
206 // Remove version object from image manager
207 Activation::deleteImageManagerObject();
208
209 // Create active association
210 parent.createActiveAssociation(path);
211
212 // Create updateable association as this
213 // can be re-programmed.
214 parent.createUpdateableAssociation(path);
215
216 if (Activation::checkApplyTimeImmediate() == true)
217 {
218 log<level::INFO>("Image Active. ApplyTime is immediate, "
219 "rebooting BMC.");
220 Activation::rebootBmc();
221 }
222 else
223 {
224 log<level::INFO>("BMC image ready, need reboot to get activated.");
225 }
226
227 activation(softwareServer::Activation::Activations::Active);
228}
229
Saqib Khanee13e832017-10-23 12:53:11 -0500230void Activation::deleteImageManagerObject()
231{
Saqib Khanee13e832017-10-23 12:53:11 -0500232 // Call the Delete object for <versionID> inside image_manager
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600233 auto method = this->bus.new_method_call(VERSION_BUSNAME, path.c_str(),
234 "xyz.openbmc_project.Object.Delete",
235 "Delete");
Adriana Kobylak3b6a4cd2018-12-10 13:45:09 -0600236 try
237 {
238 bus.call_noreply(method);
239 }
240 catch (const SdBusError& e)
Saqib Khanee13e832017-10-23 12:53:11 -0500241 {
242 log<level::ERR>("Error in Deleting image from image manager",
Adriana Kobylak596466b2018-02-13 14:48:53 -0600243 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khanee13e832017-10-23 12:53:11 -0500244 return;
245 }
246}
247
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600248auto Activation::requestedActivation(RequestedActivations value)
249 -> RequestedActivations
Saqib Khanb0774702017-05-23 16:02:41 -0500250{
Michael Tritzbed88af2017-07-19 16:00:06 -0500251 rwVolumeCreated = false;
252 roVolumeCreated = false;
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500253 ubootEnvVarsUpdated = false;
Michael Tritzbed88af2017-07-19 16:00:06 -0500254
Saqib Khanb0774702017-05-23 16:02:41 -0500255 if ((value == softwareServer::Activation::RequestedActivations::Active) &&
256 (softwareServer::Activation::requestedActivation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600257 softwareServer::Activation::RequestedActivations::Active))
Saqib Khanb0774702017-05-23 16:02:41 -0500258 {
259 if ((softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600260 softwareServer::Activation::Activations::Ready) ||
Saqib Khanb0774702017-05-23 16:02:41 -0500261 (softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600262 softwareServer::Activation::Activations::Failed))
Saqib Khanb0774702017-05-23 16:02:41 -0500263 {
264 Activation::activation(
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600265 softwareServer::Activation::Activations::Activating);
Saqib Khanb0774702017-05-23 16:02:41 -0500266 }
267 }
268 return softwareServer::Activation::requestedActivation(value);
269}
270
Saqib Khan4c1aec02017-07-06 11:46:13 -0500271uint8_t RedundancyPriority::priority(uint8_t value)
272{
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500273 // Set the priority value so that the freePriority() function can order
274 // the versions by priority.
275 auto newPriority = softwareServer::RedundancyPriority::priority(value);
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500276 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500277 parent.parent.freePriority(value, parent.versionId);
278 return newPriority;
Saqib Khan4c1aec02017-07-06 11:46:13 -0500279}
280
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500281uint8_t RedundancyPriority::sdbusPriority(uint8_t value)
Saqib Khanf0382c32017-10-24 13:36:22 -0500282{
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500283 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500284 return softwareServer::RedundancyPriority::priority(value);
Saqib Khanf0382c32017-10-24 13:36:22 -0500285}
286
Michael Tritzbed88af2017-07-19 16:00:06 -0500287void Activation::unitStateChange(sdbusplus::message::message& msg)
288{
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500289 if (softwareServer::Activation::activation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600290 softwareServer::Activation::Activations::Activating)
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500291 {
292 return;
293 }
294
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800295#ifdef HOST_BIOS_UPGRADE
296 auto purpose = parent.versions.find(versionId)->second->purpose();
297 if (purpose == VersionPurpose::Host)
298 {
299 onStateChangesBios(msg);
300 return;
301 }
302#endif
303
Adriana Kobylak3ce563a2018-06-06 16:41:15 -0500304 onStateChanges(msg);
Michael Tritzbed88af2017-07-19 16:00:06 -0500305
306 return;
307}
308
Lei YU90532252018-05-24 11:15:24 +0800309#ifdef WANT_SIGNATURE_VERIFY
310bool Activation::verifySignature(const fs::path& imageDir,
311 const fs::path& confDir)
312{
313 using Signature = phosphor::software::image::Signature;
314
315 Signature signature(imageDir, confDir);
316
317 return signature.verify();
318}
319
320void Activation::onVerifyFailed()
321{
322 log<level::ERR>("Error occurred during image validation");
323 report<InternalFailure>();
324}
325#endif
326
Saqib Khanf37cefc2017-09-12 08:44:41 -0500327void ActivationBlocksTransition::enableRebootGuard()
328{
329 log<level::INFO>("BMC image activating - BMC reboots are disabled.");
330
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600331 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
332 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500333 method.append("reboot-guard-enable.service", "replace");
334 bus.call_noreply(method);
335}
336
337void ActivationBlocksTransition::disableRebootGuard()
338{
339 log<level::INFO>("BMC activation has ended - BMC reboots are re-enabled.");
340
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600341 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
342 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500343 method.append("reboot-guard-disable.service", "replace");
344 bus.call_noreply(method);
345}
Michael Tritzbed88af2017-07-19 16:00:06 -0500346
Jayashankar Padatha0135602019-04-22 16:22:58 +0530347bool Activation::checkApplyTimeImmediate()
348{
349 auto service = utils::getService(bus, applyTimeObjPath, applyTimeIntf);
350 if (service.empty())
351 {
352 log<level::INFO>("Error getting the service name for BMC image "
353 "ApplyTime. The BMC needs to be manually rebooted to "
354 "complete the image activation if needed "
355 "immediately.");
356 }
357 else
358 {
359
360 auto method = bus.new_method_call(service.c_str(), applyTimeObjPath,
361 dbusPropIntf, "Get");
362 method.append(applyTimeIntf, applyTimeProp);
363
364 try
365 {
366 auto reply = bus.call(method);
367
Patrick Williams24048b52020-05-13 17:51:30 -0500368 std::variant<std::string> result;
Jayashankar Padatha0135602019-04-22 16:22:58 +0530369 reply.read(result);
Patrick Williamse883fb82020-05-13 11:38:55 -0500370 auto applyTime = std::get<std::string>(result);
Jayashankar Padatha0135602019-04-22 16:22:58 +0530371 if (applyTime == applyTimeImmediate)
372 {
373 return true;
374 }
375 }
376 catch (const SdBusError& e)
377 {
378 log<level::ERR>("Error in getting ApplyTime",
379 entry("ERROR=%s", e.what()));
380 }
381 }
382 return false;
383}
384
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800385#ifdef HOST_BIOS_UPGRADE
386void Activation::flashWriteHost()
387{
388 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
389 SYSTEMD_INTERFACE, "StartUnit");
390 auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
391 method.append(biosServiceFile, "replace");
392 try
393 {
394 auto reply = bus.call(method);
395 }
396 catch (const SdBusError& e)
397 {
398 log<level::ERR>("Error in trying to upgrade Host Bios.");
399 report<InternalFailure>();
400 }
401}
402
403void Activation::onStateChangesBios(sdbusplus::message::message& msg)
404{
405 uint32_t newStateID{};
406 sdbusplus::message::object_path newStateObjPath;
407 std::string newStateUnit{};
408 std::string newStateResult{};
409
410 // Read the msg and populate each variable
411 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
412
413 auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
414
415 if (newStateUnit == biosServiceFile)
416 {
417 // unsubscribe to systemd signals
418 unsubscribeFromSystemdSignals();
419
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800420 if (newStateResult == "done")
421 {
Lei YU837de882020-11-03 19:21:14 +0800422 // Remove version object from image manager
423 deleteImageManagerObject();
424
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800425 // Set activation progress to 100
426 activationProgress->progress(100);
427
428 // Set Activation value to active
429 activation(softwareServer::Activation::Activations::Active);
430
431 log<level::INFO>("Bios upgrade completed successfully.");
432 }
433 else if (newStateResult == "failed")
434 {
435 // Set Activation value to Failed
436 activation(softwareServer::Activation::Activations::Failed);
437
438 log<level::ERR>("Bios upgrade failed.");
439 }
440 }
441
442 return;
443}
444
445#endif
446
Jayashankar Padatha0135602019-04-22 16:22:58 +0530447void Activation::rebootBmc()
448{
449 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
450 SYSTEMD_INTERFACE, "StartUnit");
451 method.append("force-reboot.service", "replace");
452 try
453 {
454 auto reply = bus.call(method);
455 }
456 catch (const SdBusError& e)
457 {
458 log<level::ALERT>("Error in trying to reboot the BMC. "
459 "The BMC needs to be manually rebooted to complete "
460 "the image activation.");
461 report<InternalFailure>();
462 }
463}
464
Saqib Khanb0774702017-05-23 16:02:41 -0500465} // namespace updater
466} // namespace software
467} // namespace phosphor