blob: f9fbf876dc84b1bdb375b1c19c078968b3002865 [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
Lei YU25868182021-05-14 14:50:51 +08008#include <boost/asio/io_context.hpp>
Lei YU7d2fa142021-08-06 10:58:19 +08009#include <boost/asio/post.hpp>
Jayashankar Padatha0135602019-04-22 16:22:58 +053010#include <phosphor-logging/elog-errors.hpp>
11#include <phosphor-logging/elog.hpp>
Saqib Khanb9da6632017-09-13 09:48:37 -050012#include <phosphor-logging/log.hpp>
Adriana Kobylakaea48f22018-07-10 10:20:56 -050013#include <sdbusplus/exception.hpp>
Jayashankar Padatha0135602019-04-22 16:22:58 +053014#include <xyz/openbmc_project/Common/error.hpp>
Miguel Gomez21dad042020-06-26 20:54:48 +000015#include <xyz/openbmc_project/Software/Version/error.hpp>
Saqib Khanb9da6632017-09-13 09:48:37 -050016
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060017#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060018#include "image_verify.hpp"
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060019#endif
20
Lei YU25868182021-05-14 14:50:51 +080021extern boost::asio::io_context& getIOContext();
22
Saqib Khanb0774702017-05-23 16:02:41 -050023namespace phosphor
24{
25namespace software
26{
27namespace updater
28{
29
30namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
31
Saqib Khanb9da6632017-09-13 09:48:37 -050032using namespace phosphor::logging;
Adriana Kobylakaea48f22018-07-10 10:20:56 -050033using sdbusplus::exception::SdBusError;
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060034using InternalFailure =
35 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Jayashankar Padatha0135602019-04-22 16:22:58 +053036
37#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth9a9d7c22018-03-28 10:05:26 -050038namespace control = sdbusplus::xyz::openbmc_project::Control::server;
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060039#endif
40
Michael Tritzbed88af2017-07-19 16:00:06 -050041void Activation::subscribeToSystemdSignals()
42{
Adriana Kobylak2285fe02018-02-27 15:36:59 -060043 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
44 SYSTEMD_INTERFACE, "Subscribe");
Adriana Kobylakaea48f22018-07-10 10:20:56 -050045 try
46 {
47 this->bus.call_noreply(method);
48 }
49 catch (const SdBusError& e)
50 {
51 if (e.name() != nullptr &&
52 strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0)
53 {
54 // If an Activation attempt fails, the Unsubscribe method is not
55 // called. This may lead to an AlreadySubscribed error if the
56 // Activation is re-attempted.
57 }
58 else
59 {
60 log<level::ERR>("Error subscribing to systemd",
61 entry("ERROR=%s", e.what()));
62 }
63 }
Michael Tritzbed88af2017-07-19 16:00:06 -050064
65 return;
66}
67
Michael Tritzf2b5e0d2017-07-25 14:39:34 -050068void Activation::unsubscribeFromSystemdSignals()
69{
Adriana Kobylak2285fe02018-02-27 15:36:59 -060070 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
71 SYSTEMD_INTERFACE, "Unsubscribe");
Jayashankar Padatha0135602019-04-22 16:22:58 +053072 try
73 {
74 this->bus.call_noreply(method);
75 }
76 catch (const SdBusError& e)
77 {
78 log<level::ERR>("Error in unsubscribing from systemd signals",
79 entry("ERROR=%s", e.what()));
80 }
Michael Tritzf2b5e0d2017-07-25 14:39:34 -050081
82 return;
83}
84
Adriana Kobylak2285fe02018-02-27 15:36:59 -060085auto Activation::activation(Activations value) -> Activations
Saqib Khanb0774702017-05-23 16:02:41 -050086{
Adriana Kobylak8bd84c82018-01-24 14:19:24 -060087 if ((value != softwareServer::Activation::Activations::Active) &&
88 (value != softwareServer::Activation::Activations::Activating))
Saqib Khan4c1aec02017-07-06 11:46:13 -050089 {
90 redundancyPriority.reset(nullptr);
91 }
92
Saqib Khanb0774702017-05-23 16:02:41 -050093 if (value == softwareServer::Activation::Activations::Activating)
94 {
Lei YU7ab55e22021-05-19 13:26:53 +080095#ifdef WANT_SIGNATURE_VERIFY
96 fs::path uploadDir(IMG_UPLOAD_DIR);
97 if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
98 {
99 onVerifyFailed();
100 // Stop the activation process, if fieldMode is enabled.
101 if (parent.control::FieldMode::fieldModeEnabled())
102 {
103 return softwareServer::Activation::activation(
104 softwareServer::Activation::Activations::Failed);
105 }
106 }
107#endif
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800108
109#ifdef HOST_BIOS_UPGRADE
110 auto purpose = parent.versions.find(versionId)->second->purpose();
111 if (purpose == VersionPurpose::Host)
112 {
113 if (!activationProgress)
114 {
115 activationProgress =
116 std::make_unique<ActivationProgress>(bus, path);
117 }
118
119 // Enable systemd signals
120 subscribeToSystemdSignals();
121
122 // Set initial progress
123 activationProgress->progress(20);
124
125 // Initiate image writing to flash
126 flashWriteHost();
127
128 return softwareServer::Activation::activation(value);
129 }
130#endif
131
Miguel Gomez21dad042020-06-26 20:54:48 +0000132 auto versionStr = parent.versions.find(versionId)->second->version();
133
134 if (!minimum_ship_level::verify(versionStr))
135 {
136 using namespace phosphor::logging;
137 using IncompatibleErr = sdbusplus::xyz::openbmc_project::Software::
138 Version::Error::Incompatible;
139 using Incompatible =
140 xyz::openbmc_project::Software::Version::Incompatible;
141
142 report<IncompatibleErr>(
143 prev_entry<Incompatible::MIN_VERSION>(),
144 prev_entry<Incompatible::ACTUAL_VERSION>(),
145 prev_entry<Incompatible::VERSION_PURPOSE>());
146 return softwareServer::Activation::activation(
147 softwareServer::Activation::Activations::Failed);
148 }
149
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500150 if (!activationProgress)
151 {
152 activationProgress =
153 std::make_unique<ActivationProgress>(bus, path);
154 }
155
156 if (!activationBlocksTransition)
157 {
158 activationBlocksTransition =
159 std::make_unique<ActivationBlocksTransition>(bus, path);
160 }
161
162 activationProgress->progress(10);
163
Adriana Kobylaka6963592018-09-07 14:13:29 -0500164 parent.freeSpace(*this);
Lei YUa7853ee2018-05-23 11:13:12 +0800165
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500166 // Enable systemd signals
167 Activation::subscribeToSystemdSignals();
168
Lei YUa7853ee2018-05-23 11:13:12 +0800169 flashWrite();
170
Adriana Kobylak70f5bc02020-05-13 14:08:14 -0500171#if defined UBIFS_LAYOUT || defined MMC_LAYOUT
Lei YUa7853ee2018-05-23 11:13:12 +0800172
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500173 return softwareServer::Activation::activation(value);
Lei YUa7853ee2018-05-23 11:13:12 +0800174
Adriana Kobylak70f5bc02020-05-13 14:08:14 -0500175#else // STATIC_LAYOUT
Lei YUa7853ee2018-05-23 11:13:12 +0800176
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500177 onFlashWriteSuccess();
Lei YUa7853ee2018-05-23 11:13:12 +0800178 return softwareServer::Activation::activation(
179 softwareServer::Activation::Activations::Active);
180#endif
Saqib Khanb0774702017-05-23 16:02:41 -0500181 }
182 else
183 {
184 activationBlocksTransition.reset(nullptr);
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500185 activationProgress.reset(nullptr);
Saqib Khanb0774702017-05-23 16:02:41 -0500186 }
187 return softwareServer::Activation::activation(value);
188}
189
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500190void Activation::onFlashWriteSuccess()
191{
192 activationProgress->progress(100);
193
194 activationBlocksTransition.reset(nullptr);
195 activationProgress.reset(nullptr);
196
197 rwVolumeCreated = false;
198 roVolumeCreated = false;
199 ubootEnvVarsUpdated = false;
200 Activation::unsubscribeFromSystemdSignals();
201
202 storePurpose(versionId, parent.versions.find(versionId)->second->purpose());
203
204 if (!redundancyPriority)
205 {
206 redundancyPriority =
207 std::make_unique<RedundancyPriority>(bus, path, *this, 0);
208 }
209
210 // Remove version object from image manager
211 Activation::deleteImageManagerObject();
212
213 // Create active association
214 parent.createActiveAssociation(path);
215
216 // Create updateable association as this
217 // can be re-programmed.
218 parent.createUpdateableAssociation(path);
219
220 if (Activation::checkApplyTimeImmediate() == true)
221 {
222 log<level::INFO>("Image Active. ApplyTime is immediate, "
223 "rebooting BMC.");
224 Activation::rebootBmc();
225 }
226 else
227 {
228 log<level::INFO>("BMC image ready, need reboot to get activated.");
229 }
230
231 activation(softwareServer::Activation::Activations::Active);
232}
233
Saqib Khanee13e832017-10-23 12:53:11 -0500234void Activation::deleteImageManagerObject()
235{
Saqib Khanee13e832017-10-23 12:53:11 -0500236 // Call the Delete object for <versionID> inside image_manager
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600237 auto method = this->bus.new_method_call(VERSION_BUSNAME, path.c_str(),
238 "xyz.openbmc_project.Object.Delete",
239 "Delete");
Adriana Kobylak3b6a4cd2018-12-10 13:45:09 -0600240 try
241 {
242 bus.call_noreply(method);
243 }
244 catch (const SdBusError& e)
Saqib Khanee13e832017-10-23 12:53:11 -0500245 {
246 log<level::ERR>("Error in Deleting image from image manager",
Adriana Kobylak596466b2018-02-13 14:48:53 -0600247 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khanee13e832017-10-23 12:53:11 -0500248 return;
249 }
250}
251
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600252auto Activation::requestedActivation(RequestedActivations value)
253 -> RequestedActivations
Saqib Khanb0774702017-05-23 16:02:41 -0500254{
Michael Tritzbed88af2017-07-19 16:00:06 -0500255 rwVolumeCreated = false;
256 roVolumeCreated = false;
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500257 ubootEnvVarsUpdated = false;
Michael Tritzbed88af2017-07-19 16:00:06 -0500258
Saqib Khanb0774702017-05-23 16:02:41 -0500259 if ((value == softwareServer::Activation::RequestedActivations::Active) &&
260 (softwareServer::Activation::requestedActivation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600261 softwareServer::Activation::RequestedActivations::Active))
Saqib Khanb0774702017-05-23 16:02:41 -0500262 {
263 if ((softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600264 softwareServer::Activation::Activations::Ready) ||
Saqib Khanb0774702017-05-23 16:02:41 -0500265 (softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600266 softwareServer::Activation::Activations::Failed))
Saqib Khanb0774702017-05-23 16:02:41 -0500267 {
268 Activation::activation(
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600269 softwareServer::Activation::Activations::Activating);
Saqib Khanb0774702017-05-23 16:02:41 -0500270 }
271 }
272 return softwareServer::Activation::requestedActivation(value);
273}
274
Saqib Khan4c1aec02017-07-06 11:46:13 -0500275uint8_t RedundancyPriority::priority(uint8_t value)
276{
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500277 // Set the priority value so that the freePriority() function can order
278 // the versions by priority.
279 auto newPriority = softwareServer::RedundancyPriority::priority(value);
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500280 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500281 parent.parent.freePriority(value, parent.versionId);
282 return newPriority;
Saqib Khan4c1aec02017-07-06 11:46:13 -0500283}
284
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500285uint8_t RedundancyPriority::sdbusPriority(uint8_t value)
Saqib Khanf0382c32017-10-24 13:36:22 -0500286{
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500287 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500288 return softwareServer::RedundancyPriority::priority(value);
Saqib Khanf0382c32017-10-24 13:36:22 -0500289}
290
Michael Tritzbed88af2017-07-19 16:00:06 -0500291void Activation::unitStateChange(sdbusplus::message::message& msg)
292{
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500293 if (softwareServer::Activation::activation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600294 softwareServer::Activation::Activations::Activating)
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500295 {
296 return;
297 }
298
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800299#ifdef HOST_BIOS_UPGRADE
300 auto purpose = parent.versions.find(versionId)->second->purpose();
301 if (purpose == VersionPurpose::Host)
302 {
303 onStateChangesBios(msg);
304 return;
305 }
306#endif
307
Adriana Kobylak3ce563a2018-06-06 16:41:15 -0500308 onStateChanges(msg);
Michael Tritzbed88af2017-07-19 16:00:06 -0500309
310 return;
311}
312
Lei YU90532252018-05-24 11:15:24 +0800313#ifdef WANT_SIGNATURE_VERIFY
314bool Activation::verifySignature(const fs::path& imageDir,
315 const fs::path& confDir)
316{
317 using Signature = phosphor::software::image::Signature;
318
319 Signature signature(imageDir, confDir);
320
321 return signature.verify();
322}
323
324void Activation::onVerifyFailed()
325{
326 log<level::ERR>("Error occurred during image validation");
327 report<InternalFailure>();
328}
329#endif
330
Saqib Khanf37cefc2017-09-12 08:44:41 -0500331void ActivationBlocksTransition::enableRebootGuard()
332{
333 log<level::INFO>("BMC image activating - BMC reboots are disabled.");
334
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600335 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
336 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500337 method.append("reboot-guard-enable.service", "replace");
338 bus.call_noreply(method);
339}
340
341void ActivationBlocksTransition::disableRebootGuard()
342{
343 log<level::INFO>("BMC activation has ended - BMC reboots are re-enabled.");
344
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600345 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
346 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500347 method.append("reboot-guard-disable.service", "replace");
348 bus.call_noreply(method);
349}
Michael Tritzbed88af2017-07-19 16:00:06 -0500350
Jayashankar Padatha0135602019-04-22 16:22:58 +0530351bool Activation::checkApplyTimeImmediate()
352{
353 auto service = utils::getService(bus, applyTimeObjPath, applyTimeIntf);
354 if (service.empty())
355 {
356 log<level::INFO>("Error getting the service name for BMC image "
357 "ApplyTime. The BMC needs to be manually rebooted to "
358 "complete the image activation if needed "
359 "immediately.");
360 }
361 else
362 {
363
364 auto method = bus.new_method_call(service.c_str(), applyTimeObjPath,
365 dbusPropIntf, "Get");
366 method.append(applyTimeIntf, applyTimeProp);
367
368 try
369 {
370 auto reply = bus.call(method);
371
Patrick Williams24048b52020-05-13 17:51:30 -0500372 std::variant<std::string> result;
Jayashankar Padatha0135602019-04-22 16:22:58 +0530373 reply.read(result);
Patrick Williamse883fb82020-05-13 11:38:55 -0500374 auto applyTime = std::get<std::string>(result);
Jayashankar Padatha0135602019-04-22 16:22:58 +0530375 if (applyTime == applyTimeImmediate)
376 {
377 return true;
378 }
379 }
380 catch (const SdBusError& e)
381 {
382 log<level::ERR>("Error in getting ApplyTime",
383 entry("ERROR=%s", e.what()));
384 }
385 }
386 return false;
387}
388
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800389#ifdef HOST_BIOS_UPGRADE
390void Activation::flashWriteHost()
391{
392 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
393 SYSTEMD_INTERFACE, "StartUnit");
394 auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
395 method.append(biosServiceFile, "replace");
396 try
397 {
398 auto reply = bus.call(method);
399 }
400 catch (const SdBusError& e)
401 {
402 log<level::ERR>("Error in trying to upgrade Host Bios.");
403 report<InternalFailure>();
404 }
405}
406
407void Activation::onStateChangesBios(sdbusplus::message::message& msg)
408{
409 uint32_t newStateID{};
410 sdbusplus::message::object_path newStateObjPath;
411 std::string newStateUnit{};
412 std::string newStateResult{};
413
414 // Read the msg and populate each variable
415 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
416
417 auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
418
419 if (newStateUnit == biosServiceFile)
420 {
421 // unsubscribe to systemd signals
422 unsubscribeFromSystemdSignals();
423
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800424 if (newStateResult == "done")
425 {
Lei YU837de882020-11-03 19:21:14 +0800426 // Remove version object from image manager
427 deleteImageManagerObject();
428
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800429 // Set activation progress to 100
430 activationProgress->progress(100);
431
432 // Set Activation value to active
433 activation(softwareServer::Activation::Activations::Active);
434
435 log<level::INFO>("Bios upgrade completed successfully.");
Lei YU16aa28a2021-05-07 10:17:30 +0800436 parent.biosVersion->version(
437 parent.versions.find(versionId)->second->version());
Lei YU25868182021-05-14 14:50:51 +0800438
439 // Delete the uploaded activation
Lei YU7d2fa142021-08-06 10:58:19 +0800440 boost::asio::post(getIOContext(), [this]() {
441 this->parent.erase(this->versionId);
Lei YU25868182021-05-14 14:50:51 +0800442 });
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800443 }
444 else if (newStateResult == "failed")
445 {
446 // Set Activation value to Failed
447 activation(softwareServer::Activation::Activations::Failed);
448
449 log<level::ERR>("Bios upgrade failed.");
450 }
451 }
452
453 return;
454}
455
456#endif
457
Jayashankar Padatha0135602019-04-22 16:22:58 +0530458void Activation::rebootBmc()
459{
460 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
461 SYSTEMD_INTERFACE, "StartUnit");
462 method.append("force-reboot.service", "replace");
463 try
464 {
465 auto reply = bus.call(method);
466 }
467 catch (const SdBusError& e)
468 {
469 log<level::ALERT>("Error in trying to reboot the BMC. "
470 "The BMC needs to be manually rebooted to complete "
471 "the image activation.");
472 report<InternalFailure>();
473 }
474}
475
Saqib Khanb0774702017-05-23 16:02:41 -0500476} // namespace updater
477} // namespace software
478} // namespace phosphor