blob: 6b9dfb8733f05bda38a216eb779f6ed82eafebdf [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 YU90532252018-05-24 11:15:24 +0800114#ifdef WANT_SIGNATURE_VERIFY
115 fs::path uploadDir(IMG_UPLOAD_DIR);
116 if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
117 {
118 onVerifyFailed();
119 // Stop the activation process, if fieldMode is enabled.
120 if (parent.control::FieldMode::fieldModeEnabled())
121 {
122 return softwareServer::Activation::activation(
123 softwareServer::Activation::Activations::Failed);
124 }
125 }
126#endif
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500127
128 if (!activationProgress)
129 {
130 activationProgress =
131 std::make_unique<ActivationProgress>(bus, path);
132 }
133
134 if (!activationBlocksTransition)
135 {
136 activationBlocksTransition =
137 std::make_unique<ActivationBlocksTransition>(bus, path);
138 }
139
140 activationProgress->progress(10);
141
Adriana Kobylaka6963592018-09-07 14:13:29 -0500142 parent.freeSpace(*this);
Lei YUa7853ee2018-05-23 11:13:12 +0800143
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500144 // Enable systemd signals
145 Activation::subscribeToSystemdSignals();
146
Lei YUa7853ee2018-05-23 11:13:12 +0800147 flashWrite();
148
Adriana Kobylak70f5bc02020-05-13 14:08:14 -0500149#if defined UBIFS_LAYOUT || defined MMC_LAYOUT
Lei YUa7853ee2018-05-23 11:13:12 +0800150
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500151 return softwareServer::Activation::activation(value);
Lei YUa7853ee2018-05-23 11:13:12 +0800152
Adriana Kobylak70f5bc02020-05-13 14:08:14 -0500153#else // STATIC_LAYOUT
Lei YUa7853ee2018-05-23 11:13:12 +0800154
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500155 onFlashWriteSuccess();
Lei YUa7853ee2018-05-23 11:13:12 +0800156 return softwareServer::Activation::activation(
157 softwareServer::Activation::Activations::Active);
158#endif
Saqib Khanb0774702017-05-23 16:02:41 -0500159 }
160 else
161 {
162 activationBlocksTransition.reset(nullptr);
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500163 activationProgress.reset(nullptr);
Saqib Khanb0774702017-05-23 16:02:41 -0500164 }
165 return softwareServer::Activation::activation(value);
166}
167
Adriana Kobylakb824b2f2020-05-14 14:57:53 -0500168void Activation::onFlashWriteSuccess()
169{
170 activationProgress->progress(100);
171
172 activationBlocksTransition.reset(nullptr);
173 activationProgress.reset(nullptr);
174
175 rwVolumeCreated = false;
176 roVolumeCreated = false;
177 ubootEnvVarsUpdated = false;
178 Activation::unsubscribeFromSystemdSignals();
179
180 storePurpose(versionId, parent.versions.find(versionId)->second->purpose());
181
182 if (!redundancyPriority)
183 {
184 redundancyPriority =
185 std::make_unique<RedundancyPriority>(bus, path, *this, 0);
186 }
187
188 // Remove version object from image manager
189 Activation::deleteImageManagerObject();
190
191 // Create active association
192 parent.createActiveAssociation(path);
193
194 // Create updateable association as this
195 // can be re-programmed.
196 parent.createUpdateableAssociation(path);
197
198 if (Activation::checkApplyTimeImmediate() == true)
199 {
200 log<level::INFO>("Image Active. ApplyTime is immediate, "
201 "rebooting BMC.");
202 Activation::rebootBmc();
203 }
204 else
205 {
206 log<level::INFO>("BMC image ready, need reboot to get activated.");
207 }
208
209 activation(softwareServer::Activation::Activations::Active);
210}
211
Saqib Khanee13e832017-10-23 12:53:11 -0500212void Activation::deleteImageManagerObject()
213{
Saqib Khanee13e832017-10-23 12:53:11 -0500214 // Call the Delete object for <versionID> inside image_manager
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600215 auto method = this->bus.new_method_call(VERSION_BUSNAME, path.c_str(),
216 "xyz.openbmc_project.Object.Delete",
217 "Delete");
Adriana Kobylak3b6a4cd2018-12-10 13:45:09 -0600218 try
219 {
220 bus.call_noreply(method);
221 }
222 catch (const SdBusError& e)
Saqib Khanee13e832017-10-23 12:53:11 -0500223 {
224 log<level::ERR>("Error in Deleting image from image manager",
Adriana Kobylak596466b2018-02-13 14:48:53 -0600225 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khanee13e832017-10-23 12:53:11 -0500226 return;
227 }
228}
229
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600230auto Activation::requestedActivation(RequestedActivations value)
231 -> RequestedActivations
Saqib Khanb0774702017-05-23 16:02:41 -0500232{
Michael Tritzbed88af2017-07-19 16:00:06 -0500233 rwVolumeCreated = false;
234 roVolumeCreated = false;
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500235 ubootEnvVarsUpdated = false;
Michael Tritzbed88af2017-07-19 16:00:06 -0500236
Saqib Khanb0774702017-05-23 16:02:41 -0500237 if ((value == softwareServer::Activation::RequestedActivations::Active) &&
238 (softwareServer::Activation::requestedActivation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600239 softwareServer::Activation::RequestedActivations::Active))
Saqib Khanb0774702017-05-23 16:02:41 -0500240 {
241 if ((softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600242 softwareServer::Activation::Activations::Ready) ||
Saqib Khanb0774702017-05-23 16:02:41 -0500243 (softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600244 softwareServer::Activation::Activations::Failed))
Saqib Khanb0774702017-05-23 16:02:41 -0500245 {
246 Activation::activation(
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600247 softwareServer::Activation::Activations::Activating);
Saqib Khanb0774702017-05-23 16:02:41 -0500248 }
249 }
250 return softwareServer::Activation::requestedActivation(value);
251}
252
Saqib Khan4c1aec02017-07-06 11:46:13 -0500253uint8_t RedundancyPriority::priority(uint8_t value)
254{
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500255 // Set the priority value so that the freePriority() function can order
256 // the versions by priority.
257 auto newPriority = softwareServer::RedundancyPriority::priority(value);
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500258 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500259 parent.parent.freePriority(value, parent.versionId);
260 return newPriority;
Saqib Khan4c1aec02017-07-06 11:46:13 -0500261}
262
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500263uint8_t RedundancyPriority::sdbusPriority(uint8_t value)
Saqib Khanf0382c32017-10-24 13:36:22 -0500264{
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500265 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500266 return softwareServer::RedundancyPriority::priority(value);
Saqib Khanf0382c32017-10-24 13:36:22 -0500267}
268
Michael Tritzbed88af2017-07-19 16:00:06 -0500269void Activation::unitStateChange(sdbusplus::message::message& msg)
270{
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500271 if (softwareServer::Activation::activation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600272 softwareServer::Activation::Activations::Activating)
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500273 {
274 return;
275 }
276
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800277#ifdef HOST_BIOS_UPGRADE
278 auto purpose = parent.versions.find(versionId)->second->purpose();
279 if (purpose == VersionPurpose::Host)
280 {
281 onStateChangesBios(msg);
282 return;
283 }
284#endif
285
Adriana Kobylak3ce563a2018-06-06 16:41:15 -0500286 onStateChanges(msg);
Michael Tritzbed88af2017-07-19 16:00:06 -0500287
288 return;
289}
290
Lei YU90532252018-05-24 11:15:24 +0800291#ifdef WANT_SIGNATURE_VERIFY
292bool Activation::verifySignature(const fs::path& imageDir,
293 const fs::path& confDir)
294{
295 using Signature = phosphor::software::image::Signature;
296
297 Signature signature(imageDir, confDir);
298
299 return signature.verify();
300}
301
302void Activation::onVerifyFailed()
303{
304 log<level::ERR>("Error occurred during image validation");
305 report<InternalFailure>();
306}
307#endif
308
Saqib Khanf37cefc2017-09-12 08:44:41 -0500309void ActivationBlocksTransition::enableRebootGuard()
310{
311 log<level::INFO>("BMC image activating - BMC reboots are disabled.");
312
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600313 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
314 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500315 method.append("reboot-guard-enable.service", "replace");
316 bus.call_noreply(method);
317}
318
319void ActivationBlocksTransition::disableRebootGuard()
320{
321 log<level::INFO>("BMC activation has ended - BMC reboots are re-enabled.");
322
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600323 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
324 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500325 method.append("reboot-guard-disable.service", "replace");
326 bus.call_noreply(method);
327}
Michael Tritzbed88af2017-07-19 16:00:06 -0500328
Jayashankar Padatha0135602019-04-22 16:22:58 +0530329bool Activation::checkApplyTimeImmediate()
330{
331 auto service = utils::getService(bus, applyTimeObjPath, applyTimeIntf);
332 if (service.empty())
333 {
334 log<level::INFO>("Error getting the service name for BMC image "
335 "ApplyTime. The BMC needs to be manually rebooted to "
336 "complete the image activation if needed "
337 "immediately.");
338 }
339 else
340 {
341
342 auto method = bus.new_method_call(service.c_str(), applyTimeObjPath,
343 dbusPropIntf, "Get");
344 method.append(applyTimeIntf, applyTimeProp);
345
346 try
347 {
348 auto reply = bus.call(method);
349
Patrick Williams24048b52020-05-13 17:51:30 -0500350 std::variant<std::string> result;
Jayashankar Padatha0135602019-04-22 16:22:58 +0530351 reply.read(result);
Patrick Williamse883fb82020-05-13 11:38:55 -0500352 auto applyTime = std::get<std::string>(result);
Jayashankar Padatha0135602019-04-22 16:22:58 +0530353 if (applyTime == applyTimeImmediate)
354 {
355 return true;
356 }
357 }
358 catch (const SdBusError& e)
359 {
360 log<level::ERR>("Error in getting ApplyTime",
361 entry("ERROR=%s", e.what()));
362 }
363 }
364 return false;
365}
366
Vijay Khemkae9f6c842020-01-14 14:32:39 -0800367#ifdef HOST_BIOS_UPGRADE
368void Activation::flashWriteHost()
369{
370 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
371 SYSTEMD_INTERFACE, "StartUnit");
372 auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
373 method.append(biosServiceFile, "replace");
374 try
375 {
376 auto reply = bus.call(method);
377 }
378 catch (const SdBusError& e)
379 {
380 log<level::ERR>("Error in trying to upgrade Host Bios.");
381 report<InternalFailure>();
382 }
383}
384
385void Activation::onStateChangesBios(sdbusplus::message::message& msg)
386{
387 uint32_t newStateID{};
388 sdbusplus::message::object_path newStateObjPath;
389 std::string newStateUnit{};
390 std::string newStateResult{};
391
392 // Read the msg and populate each variable
393 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
394
395 auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
396
397 if (newStateUnit == biosServiceFile)
398 {
399 // unsubscribe to systemd signals
400 unsubscribeFromSystemdSignals();
401
402 // Remove version object from image manager
403 deleteImageManagerObject();
404
405 if (newStateResult == "done")
406 {
407 // Set activation progress to 100
408 activationProgress->progress(100);
409
410 // Set Activation value to active
411 activation(softwareServer::Activation::Activations::Active);
412
413 log<level::INFO>("Bios upgrade completed successfully.");
414 }
415 else if (newStateResult == "failed")
416 {
417 // Set Activation value to Failed
418 activation(softwareServer::Activation::Activations::Failed);
419
420 log<level::ERR>("Bios upgrade failed.");
421 }
422 }
423
424 return;
425}
426
427#endif
428
Jayashankar Padatha0135602019-04-22 16:22:58 +0530429void Activation::rebootBmc()
430{
431 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
432 SYSTEMD_INTERFACE, "StartUnit");
433 method.append("force-reboot.service", "replace");
434 try
435 {
436 auto reply = bus.call(method);
437 }
438 catch (const SdBusError& e)
439 {
440 log<level::ALERT>("Error in trying to reboot the BMC. "
441 "The BMC needs to be manually rebooted to complete "
442 "the image activation.");
443 report<InternalFailure>();
444 }
445}
446
Saqib Khanb0774702017-05-23 16:02:41 -0500447} // namespace updater
448} // namespace software
449} // namespace phosphor