blob: 75d99fff99ad3addb2526d5e4eda384bb83b0057 [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>
Jayashankar Padatha0135602019-04-22 16:22:58 +05309#include <phosphor-logging/elog-errors.hpp>
10#include <phosphor-logging/elog.hpp>
Saqib Khanb9da6632017-09-13 09:48:37 -050011#include <phosphor-logging/log.hpp>
Adriana Kobylakaea48f22018-07-10 10:20:56 -050012#include <sdbusplus/exception.hpp>
Jayashankar Padatha0135602019-04-22 16:22:58 +053013#include <xyz/openbmc_project/Common/error.hpp>
Miguel Gomez21dad042020-06-26 20:54:48 +000014#include <xyz/openbmc_project/Software/Version/error.hpp>
Saqib Khanb9da6632017-09-13 09:48:37 -050015
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060016#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060017#include "image_verify.hpp"
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060018#endif
19
Lei YU25868182021-05-14 14:50:51 +080020extern boost::asio::io_context& getIOContext();
21
Saqib Khanb0774702017-05-23 16:02:41 -050022namespace phosphor
23{
24namespace software
25{
26namespace updater
27{
28
29namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
30
Saqib Khanb9da6632017-09-13 09:48:37 -050031using namespace phosphor::logging;
Adriana Kobylakaea48f22018-07-10 10:20:56 -050032using sdbusplus::exception::SdBusError;
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060033using InternalFailure =
34 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Jayashankar Padatha0135602019-04-22 16:22:58 +053035
36#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth9a9d7c22018-03-28 10:05:26 -050037namespace control = sdbusplus::xyz::openbmc_project::Control::server;
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060038#endif
39
Michael Tritzbed88af2017-07-19 16:00:06 -050040void Activation::subscribeToSystemdSignals()
41{
Adriana Kobylak2285fe02018-02-27 15:36:59 -060042 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
43 SYSTEMD_INTERFACE, "Subscribe");
Adriana Kobylakaea48f22018-07-10 10:20:56 -050044 try
45 {
46 this->bus.call_noreply(method);
47 }
48 catch (const SdBusError& e)
49 {
50 if (e.name() != nullptr &&
51 strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0)
52 {
53 // If an Activation attempt fails, the Unsubscribe method is not
54 // called. This may lead to an AlreadySubscribed error if the
55 // Activation is re-attempted.
56 }
57 else
58 {
59 log<level::ERR>("Error subscribing to systemd",
60 entry("ERROR=%s", e.what()));
61 }
62 }
Michael Tritzbed88af2017-07-19 16:00:06 -050063
64 return;
65}
66
Michael Tritzf2b5e0d2017-07-25 14:39:34 -050067void Activation::unsubscribeFromSystemdSignals()
68{
Adriana Kobylak2285fe02018-02-27 15:36:59 -060069 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
70 SYSTEMD_INTERFACE, "Unsubscribe");
Jayashankar Padatha0135602019-04-22 16:22:58 +053071 try
72 {
73 this->bus.call_noreply(method);
74 }
75 catch (const SdBusError& e)
76 {
77 log<level::ERR>("Error in unsubscribing from systemd signals",
78 entry("ERROR=%s", e.what()));
79 }
Michael Tritzf2b5e0d2017-07-25 14:39:34 -050080
81 return;
82}
83
Adriana Kobylak2285fe02018-02-27 15:36:59 -060084auto Activation::activation(Activations value) -> Activations
Saqib Khanb0774702017-05-23 16:02:41 -050085{
Adriana Kobylak8bd84c82018-01-24 14:19:24 -060086 if ((value != softwareServer::Activation::Activations::Active) &&
87 (value != softwareServer::Activation::Activations::Activating))
Saqib Khan4c1aec02017-07-06 11:46:13 -050088 {
89 redundancyPriority.reset(nullptr);
90 }
91
Saqib Khanb0774702017-05-23 16:02:41 -050092 if (value == softwareServer::Activation::Activations::Activating)
93 {
Lei YU7ab55e22021-05-19 13:26:53 +080094#ifdef WANT_SIGNATURE_VERIFY
95 fs::path uploadDir(IMG_UPLOAD_DIR);
96 if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
97 {
98 onVerifyFailed();
99 // Stop the activation process, if fieldMode is enabled.
100 if (parent.control::FieldMode::fieldModeEnabled())
101 {
102 return softwareServer::Activation::activation(
103 softwareServer::Activation::Activations::Failed);
104 }
105 }
106#endif
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800107
108#ifdef HOST_BIOS_UPGRADE
109 auto purpose = parent.versions.find(versionId)->second->purpose();
110 if (purpose == VersionPurpose::Host)
111 {
112 if (!activationProgress)
113 {
114 activationProgress =
115 std::make_unique<ActivationProgress>(bus, path);
116 }
117
118 // Enable systemd signals
119 subscribeToSystemdSignals();
120
121 // Set initial progress
122 activationProgress->progress(20);
123
124 // Initiate image writing to flash
125 flashWriteHost();
126
127 return softwareServer::Activation::activation(value);
128 }
129#endif
130
Miguel Gomez21dad042020-06-26 20:54:48 +0000131 auto versionStr = parent.versions.find(versionId)->second->version();
132
133 if (!minimum_ship_level::verify(versionStr))
134 {
135 using namespace phosphor::logging;
136 using IncompatibleErr = sdbusplus::xyz::openbmc_project::Software::
137 Version::Error::Incompatible;
138 using Incompatible =
139 xyz::openbmc_project::Software::Version::Incompatible;
140
141 report<IncompatibleErr>(
142 prev_entry<Incompatible::MIN_VERSION>(),
143 prev_entry<Incompatible::ACTUAL_VERSION>(),
144 prev_entry<Incompatible::VERSION_PURPOSE>());
145 return softwareServer::Activation::activation(
146 softwareServer::Activation::Activations::Failed);
147 }
148
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500149 if (!activationProgress)
150 {
151 activationProgress =
152 std::make_unique<ActivationProgress>(bus, path);
153 }
154
155 if (!activationBlocksTransition)
156 {
157 activationBlocksTransition =
158 std::make_unique<ActivationBlocksTransition>(bus, path);
159 }
160
161 activationProgress->progress(10);
162
Adriana Kobylaka6963592018-09-07 14:13:29 -0500163 parent.freeSpace(*this);
Lei YUa7853ee2018-05-23 11:13:12 +0800164
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500165 // Enable systemd signals
166 Activation::subscribeToSystemdSignals();
167
Lei YUa7853ee2018-05-23 11:13:12 +0800168 flashWrite();
169
Adriana Kobylak70f5bc02020-05-13 14:08:14 -0500170#if defined UBIFS_LAYOUT || defined MMC_LAYOUT
Lei YUa7853ee2018-05-23 11:13:12 +0800171
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500172 return softwareServer::Activation::activation(value);
Lei YUa7853ee2018-05-23 11:13:12 +0800173
Adriana Kobylak70f5bc02020-05-13 14:08:14 -0500174#else // STATIC_LAYOUT
Lei YUa7853ee2018-05-23 11:13:12 +0800175
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500176 onFlashWriteSuccess();
Lei YUa7853ee2018-05-23 11:13:12 +0800177 return softwareServer::Activation::activation(
178 softwareServer::Activation::Activations::Active);
179#endif
Saqib Khanb0774702017-05-23 16:02:41 -0500180 }
181 else
182 {
183 activationBlocksTransition.reset(nullptr);
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500184 activationProgress.reset(nullptr);
Saqib Khanb0774702017-05-23 16:02:41 -0500185 }
186 return softwareServer::Activation::activation(value);
187}
188
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500189void Activation::onFlashWriteSuccess()
190{
191 activationProgress->progress(100);
192
193 activationBlocksTransition.reset(nullptr);
194 activationProgress.reset(nullptr);
195
196 rwVolumeCreated = false;
197 roVolumeCreated = false;
198 ubootEnvVarsUpdated = false;
199 Activation::unsubscribeFromSystemdSignals();
200
201 storePurpose(versionId, parent.versions.find(versionId)->second->purpose());
202
203 if (!redundancyPriority)
204 {
205 redundancyPriority =
206 std::make_unique<RedundancyPriority>(bus, path, *this, 0);
207 }
208
209 // Remove version object from image manager
210 Activation::deleteImageManagerObject();
211
212 // Create active association
213 parent.createActiveAssociation(path);
214
215 // Create updateable association as this
216 // can be re-programmed.
217 parent.createUpdateableAssociation(path);
218
219 if (Activation::checkApplyTimeImmediate() == true)
220 {
221 log<level::INFO>("Image Active. ApplyTime is immediate, "
222 "rebooting BMC.");
223 Activation::rebootBmc();
224 }
225 else
226 {
227 log<level::INFO>("BMC image ready, need reboot to get activated.");
228 }
229
230 activation(softwareServer::Activation::Activations::Active);
231}
232
Saqib Khanee13e832017-10-23 12:53:11 -0500233void Activation::deleteImageManagerObject()
234{
Saqib Khanee13e832017-10-23 12:53:11 -0500235 // Call the Delete object for <versionID> inside image_manager
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600236 auto method = this->bus.new_method_call(VERSION_BUSNAME, path.c_str(),
237 "xyz.openbmc_project.Object.Delete",
238 "Delete");
Adriana Kobylak3b6a4cd2018-12-10 13:45:09 -0600239 try
240 {
241 bus.call_noreply(method);
242 }
243 catch (const SdBusError& e)
Saqib Khanee13e832017-10-23 12:53:11 -0500244 {
245 log<level::ERR>("Error in Deleting image from image manager",
Adriana Kobylak596466b2018-02-13 14:48:53 -0600246 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khanee13e832017-10-23 12:53:11 -0500247 return;
248 }
249}
250
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600251auto Activation::requestedActivation(RequestedActivations value)
252 -> RequestedActivations
Saqib Khanb0774702017-05-23 16:02:41 -0500253{
Michael Tritzbed88af2017-07-19 16:00:06 -0500254 rwVolumeCreated = false;
255 roVolumeCreated = false;
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500256 ubootEnvVarsUpdated = false;
Michael Tritzbed88af2017-07-19 16:00:06 -0500257
Saqib Khanb0774702017-05-23 16:02:41 -0500258 if ((value == softwareServer::Activation::RequestedActivations::Active) &&
259 (softwareServer::Activation::requestedActivation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600260 softwareServer::Activation::RequestedActivations::Active))
Saqib Khanb0774702017-05-23 16:02:41 -0500261 {
262 if ((softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600263 softwareServer::Activation::Activations::Ready) ||
Saqib Khanb0774702017-05-23 16:02:41 -0500264 (softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600265 softwareServer::Activation::Activations::Failed))
Saqib Khanb0774702017-05-23 16:02:41 -0500266 {
267 Activation::activation(
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600268 softwareServer::Activation::Activations::Activating);
Saqib Khanb0774702017-05-23 16:02:41 -0500269 }
270 }
271 return softwareServer::Activation::requestedActivation(value);
272}
273
Saqib Khan4c1aec02017-07-06 11:46:13 -0500274uint8_t RedundancyPriority::priority(uint8_t value)
275{
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500276 // Set the priority value so that the freePriority() function can order
277 // the versions by priority.
278 auto newPriority = softwareServer::RedundancyPriority::priority(value);
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500279 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500280 parent.parent.freePriority(value, parent.versionId);
281 return newPriority;
Saqib Khan4c1aec02017-07-06 11:46:13 -0500282}
283
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500284uint8_t RedundancyPriority::sdbusPriority(uint8_t value)
Saqib Khanf0382c32017-10-24 13:36:22 -0500285{
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500286 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500287 return softwareServer::RedundancyPriority::priority(value);
Saqib Khanf0382c32017-10-24 13:36:22 -0500288}
289
Michael Tritzbed88af2017-07-19 16:00:06 -0500290void Activation::unitStateChange(sdbusplus::message::message& msg)
291{
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500292 if (softwareServer::Activation::activation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600293 softwareServer::Activation::Activations::Activating)
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500294 {
295 return;
296 }
297
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800298#ifdef HOST_BIOS_UPGRADE
299 auto purpose = parent.versions.find(versionId)->second->purpose();
300 if (purpose == VersionPurpose::Host)
301 {
302 onStateChangesBios(msg);
303 return;
304 }
305#endif
306
Adriana Kobylak3ce563a2018-06-06 16:41:15 -0500307 onStateChanges(msg);
Michael Tritzbed88af2017-07-19 16:00:06 -0500308
309 return;
310}
311
Lei YU90532252018-05-24 11:15:24 +0800312#ifdef WANT_SIGNATURE_VERIFY
313bool Activation::verifySignature(const fs::path& imageDir,
314 const fs::path& confDir)
315{
316 using Signature = phosphor::software::image::Signature;
317
318 Signature signature(imageDir, confDir);
319
320 return signature.verify();
321}
322
323void Activation::onVerifyFailed()
324{
325 log<level::ERR>("Error occurred during image validation");
326 report<InternalFailure>();
327}
328#endif
329
Saqib Khanf37cefc2017-09-12 08:44:41 -0500330void ActivationBlocksTransition::enableRebootGuard()
331{
332 log<level::INFO>("BMC image activating - BMC reboots are disabled.");
333
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600334 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
335 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500336 method.append("reboot-guard-enable.service", "replace");
337 bus.call_noreply(method);
338}
339
340void ActivationBlocksTransition::disableRebootGuard()
341{
342 log<level::INFO>("BMC activation has ended - BMC reboots are re-enabled.");
343
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600344 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
345 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500346 method.append("reboot-guard-disable.service", "replace");
347 bus.call_noreply(method);
348}
Michael Tritzbed88af2017-07-19 16:00:06 -0500349
Jayashankar Padatha0135602019-04-22 16:22:58 +0530350bool Activation::checkApplyTimeImmediate()
351{
352 auto service = utils::getService(bus, applyTimeObjPath, applyTimeIntf);
353 if (service.empty())
354 {
355 log<level::INFO>("Error getting the service name for BMC image "
356 "ApplyTime. The BMC needs to be manually rebooted to "
357 "complete the image activation if needed "
358 "immediately.");
359 }
360 else
361 {
362
363 auto method = bus.new_method_call(service.c_str(), applyTimeObjPath,
364 dbusPropIntf, "Get");
365 method.append(applyTimeIntf, applyTimeProp);
366
367 try
368 {
369 auto reply = bus.call(method);
370
Patrick Williams24048b52020-05-13 17:51:30 -0500371 std::variant<std::string> result;
Jayashankar Padatha0135602019-04-22 16:22:58 +0530372 reply.read(result);
Patrick Williamse883fb82020-05-13 11:38:55 -0500373 auto applyTime = std::get<std::string>(result);
Jayashankar Padatha0135602019-04-22 16:22:58 +0530374 if (applyTime == applyTimeImmediate)
375 {
376 return true;
377 }
378 }
379 catch (const SdBusError& e)
380 {
381 log<level::ERR>("Error in getting ApplyTime",
382 entry("ERROR=%s", e.what()));
383 }
384 }
385 return false;
386}
387
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800388#ifdef HOST_BIOS_UPGRADE
389void Activation::flashWriteHost()
390{
391 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
392 SYSTEMD_INTERFACE, "StartUnit");
393 auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
394 method.append(biosServiceFile, "replace");
395 try
396 {
397 auto reply = bus.call(method);
398 }
399 catch (const SdBusError& e)
400 {
401 log<level::ERR>("Error in trying to upgrade Host Bios.");
402 report<InternalFailure>();
403 }
404}
405
406void Activation::onStateChangesBios(sdbusplus::message::message& msg)
407{
408 uint32_t newStateID{};
409 sdbusplus::message::object_path newStateObjPath;
410 std::string newStateUnit{};
411 std::string newStateResult{};
412
413 // Read the msg and populate each variable
414 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
415
416 auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
417
418 if (newStateUnit == biosServiceFile)
419 {
420 // unsubscribe to systemd signals
421 unsubscribeFromSystemdSignals();
422
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800423 if (newStateResult == "done")
424 {
Lei YU837de882020-11-03 19:21:14 +0800425 // Remove version object from image manager
426 deleteImageManagerObject();
427
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800428 // Set activation progress to 100
429 activationProgress->progress(100);
430
431 // Set Activation value to active
432 activation(softwareServer::Activation::Activations::Active);
433
434 log<level::INFO>("Bios upgrade completed successfully.");
Lei YU16aa28a2021-05-07 10:17:30 +0800435 parent.biosVersion->version(
436 parent.versions.find(versionId)->second->version());
Lei YU25868182021-05-14 14:50:51 +0800437
438 // Delete the uploaded activation
439 getIOService().post([&parent = parent, versionId = versionId]() {
440 parent.erase(versionId);
441 });
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800442 }
443 else if (newStateResult == "failed")
444 {
445 // Set Activation value to Failed
446 activation(softwareServer::Activation::Activations::Failed);
447
448 log<level::ERR>("Bios upgrade failed.");
449 }
450 }
451
452 return;
453}
454
455#endif
456
Jayashankar Padatha0135602019-04-22 16:22:58 +0530457void Activation::rebootBmc()
458{
459 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
460 SYSTEMD_INTERFACE, "StartUnit");
461 method.append("force-reboot.service", "replace");
462 try
463 {
464 auto reply = bus.call(method);
465 }
466 catch (const SdBusError& e)
467 {
468 log<level::ALERT>("Error in trying to reboot the BMC. "
469 "The BMC needs to be manually rebooted to complete "
470 "the image activation.");
471 report<InternalFailure>();
472 }
473}
474
Saqib Khanb0774702017-05-23 16:02:41 -0500475} // namespace updater
476} // namespace software
477} // namespace phosphor