blob: ae92f652eedad942fe9c39b847e061bacc9735a4 [file] [log] [blame]
AppaRao Pulie63eeda2019-07-05 16:25:38 +05301/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
AppaRao Puli88aa33b2019-07-18 23:49:55 +053017#include <systemd/sd-journal.h>
18
AppaRao Pulie63eeda2019-07-05 16:25:38 +053019#include "pfr_mgr.hpp"
AppaRao Puli88aa33b2019-07-18 23:49:55 +053020#include "pfr.hpp"
AppaRao Puli46cead92019-07-22 16:50:09 +053021#include <boost/asio.hpp>
AppaRao Pulie63eeda2019-07-05 16:25:38 +053022
AppaRao Puli88aa33b2019-07-18 23:49:55 +053023// Caches the last Recovery/Panic Count to
24// identify any new Recovery/panic actions.
25/* TODO: When BMC Reset's, these values will be lost
26 * Persist this info using settingsd */
27static uint8_t lastRecoveryCount = 0;
28static uint8_t lastPanicCount = 0;
29static uint8_t lastMajorErr = 0;
30static uint8_t lastMinorErr = 0;
31
32static bool stateTimerRunning = false;
AppaRao Puli46cead92019-07-22 16:50:09 +053033bool finishedSettingChkPoint = false;
34static constexpr uint8_t bmcBootFinishedChkPoint = 0x09;
35
AppaRao Puli88aa33b2019-07-18 23:49:55 +053036std::unique_ptr<boost::asio::steady_timer> stateTimer = nullptr;
AppaRao Puli46cead92019-07-22 16:50:09 +053037std::unique_ptr<boost::asio::steady_timer> initTimer = nullptr;
AppaRao Puli88aa33b2019-07-18 23:49:55 +053038
AppaRao Pulie4e95652019-07-19 16:52:01 +053039std::vector<std::unique_ptr<intel::pfr::PfrVersion>> pfrVersionObjects;
40std::unique_ptr<intel::pfr::PfrConfig> pfrConfigObject;
41
42using namespace intel::pfr;
43// List holds <ObjPath> <ImageType> <VersionPurpose>
44static std::vector<std::tuple<std::string, ImageType, std::string>>
45 verComponentList = {
46 std::make_tuple("bmc_active", ImageType::bmcActive, versionPurposeBMC),
47 std::make_tuple("bmc_recovery", ImageType::bmcRecovery,
48 versionPurposeBMC),
49 std::make_tuple("bios_active", ImageType::biosActive,
50 versionPurposeHost),
51 std::make_tuple("bios_recovery", ImageType::biosRecovery,
52 versionPurposeHost),
53 std::make_tuple("cpld", ImageType::cpld, versionPurposeOther)};
54
AppaRao Puli88aa33b2019-07-18 23:49:55 +053055// Recovery reason map. { <CPLD association>, <Recovery Reason> }
56static std::map<uint8_t, std::string> recoveryReasonMap = {
57 {0x01, "PCH active authentication failure"},
58 {0x02, "PCH recovery authentication failure"},
AppaRao Pulidbe184d2019-10-09 18:04:22 +053059 {0x03, "ME launch failure"},
60 {0x04, "ACM launch failure"},
61 {0x05, "IBB launch failure"},
62 {0x06, "OBB launch failure"},
63 {0x07, "BMC active authentication failure"},
64 {0x08, "BMC recovery authentication failure"},
65 {0x09, "BMC launch failure"},
66 {0x0A, "CPLD watchdog expired"}};
AppaRao Puli88aa33b2019-07-18 23:49:55 +053067
68// Panic Reason map. { <CPLD association>, <Panic reason> }
69static std::map<uint8_t, std::string> panicReasonMap = {
AppaRao Pulidbe184d2019-10-09 18:04:22 +053070 {0x01, "CPLD watchdog expired"},
71 {0x02, "BMC watchdog expired"},
72 {0x03, "ME watchdog expired"},
73 {0x04, "ACM watchdog expired"},
74 {0x05, "IBB watchdog expired"},
75 {0x06, "OBB watchdog expired"},
AppaRao Puli88aa33b2019-07-18 23:49:55 +053076 {0x07, "BMC active authentication failure"},
77 {0x08, "BMC recovery authentication failure"},
78 {0x09, "PCH active authentication failure"},
79 {0x0A, "PCH recovery authentication failure"},
AppaRao Pulidbe184d2019-10-09 18:04:22 +053080 {0x0B, "ME authentication failure"},
81 {0x0C, "ACM or IBB or OBB authentication failure"},
82 {0x0D, "PCH update intent"},
83 {0x0E, "BMC update intent"},
84 {0x0F, "BMC reset detected"}};
AppaRao Puli88aa33b2019-07-18 23:49:55 +053085
AppaRao Pulie4e95652019-07-19 16:52:01 +053086static void updateDbusPropertiesCache()
87{
88 for (const auto& pfrVerObj : pfrVersionObjects)
89 {
90 pfrVerObj->updateVersion();
91 }
92
93 // Update provisoningStatus properties
94 pfrConfigObject->updateProvisioningStatus();
95
96 phosphor::logging::log<phosphor::logging::level::INFO>(
97 "PFR Manager service cache data updated.");
98}
99
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530100static void logLastRecoveryEvent()
101{
102 uint8_t reason = 0;
103 if (0 !=
104 intel::pfr::readCpldReg(intel::pfr::ActionType::recoveryReason, reason))
105 {
106 return;
107 }
108
109 std::map<uint8_t, std::string>::const_iterator it =
110 recoveryReasonMap.find(reason);
111 if (it == recoveryReasonMap.end())
112 {
113 // No matching found. So just return without logging event.
114 return;
115 }
116
AppaRao Pulidbe184d2019-10-09 18:04:22 +0530117 sd_journal_send(
118 "MESSAGE=%s", "Platform firmware recovered.", "PRIORITY=%i", LOG_ERR,
119 "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.PlatformFirmwareEvent",
120 "REDFISH_MESSAGE_ARGS=%s,%s", "recovery", it->second.c_str(), NULL);
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530121}
122
123static void logLastPanicEvent()
124{
125 uint8_t reason = 0;
126 if (0 !=
127 intel::pfr::readCpldReg(intel::pfr::ActionType::panicReason, reason))
128 {
129 return;
130 }
131
132 std::map<uint8_t, std::string>::const_iterator it =
133 panicReasonMap.find(reason);
134 if (it == panicReasonMap.end())
135 {
136 // No matching found. So just return without logging event.
137 return;
138 }
139
AppaRao Pulidbe184d2019-10-09 18:04:22 +0530140 sd_journal_send(
141 "MESSAGE=%s", "Platform panic event triggered.", "PRIORITY=%i", LOG_ERR,
142 "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.PlatformFirmwareEvent",
143 "REDFISH_MESSAGE_ARGS=%s,%s", "panic", it->second.c_str(), NULL);
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530144}
145
146static void checkAndLogEvents()
147{
148 uint8_t currPanicCount = 0;
149 if (0 == intel::pfr::readCpldReg(intel::pfr::ActionType::panicCount,
150 currPanicCount))
151 {
152 if (lastPanicCount != currPanicCount)
153 {
154 // Update cached data and log redfish event by reading reason.
155 lastPanicCount = currPanicCount;
156 logLastPanicEvent();
157 }
158 }
159
160 uint8_t currRecoveryCount = 0;
161 if (0 == intel::pfr::readCpldReg(intel::pfr::ActionType::recoveryCount,
162 currRecoveryCount))
163 {
164 if (lastRecoveryCount != currRecoveryCount)
165 {
166 // Update cached data and log redfish event by reading reason.
167 lastRecoveryCount = currRecoveryCount;
168 logLastRecoveryEvent();
169 }
170 }
171
172 uint8_t majorErr = 0;
173 uint8_t minorErr = 0;
174 if ((0 == intel::pfr::readCpldReg(intel::pfr::ActionType::majorError,
175 majorErr)) ||
176 (0 ==
177 intel::pfr::readCpldReg(intel::pfr::ActionType::minorError, minorErr)))
178 {
179 if ((lastMajorErr != majorErr) || (lastMinorErr != minorErr))
180 {
181 lastMajorErr = majorErr;
182 lastMinorErr = minorErr;
183
184 if (majorErr || minorErr)
185 {
AppaRao Pulidbe184d2019-10-09 18:04:22 +0530186 std::string errorStr =
187 toHexString(majorErr) + "." + toHexString(minorErr);
188 sd_journal_send("MESSAGE=%s",
189 "Error occurred on platform firmware.",
190 "PRIORITY=%i", LOG_ERR, "REDFISH_MESSAGE_ID=%s",
191 "OpenBMC.0.1.PlatformFirmwareError",
192 "REDFISH_MESSAGE_ARGS=%s", errorStr, NULL);
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530193 }
194 }
195 }
196}
197
198static void monitorPlatformStateChange(
199 sdbusplus::asio::object_server& server,
200 std::shared_ptr<sdbusplus::asio::connection>& conn)
201{
202 constexpr size_t pollTimeout = 10; // seconds
203 stateTimer->expires_after(std::chrono::seconds(pollTimeout));
204 stateTimer->async_wait(
205 [&server, &conn](const boost::system::error_code& ec) {
206 if (ec == boost::asio::error::operation_aborted)
207 {
208 // Timer reset.
209 return;
210 }
211 if (ec)
212 {
213 // Platform State Monitor - Timer cancelled.
214 return;
215 }
216 checkAndLogEvents();
217 monitorPlatformStateChange(server, conn);
218 });
219}
220
AppaRao Puli46cead92019-07-22 16:50:09 +0530221void checkAndSetCheckpoint(sdbusplus::asio::object_server& server,
222 std::shared_ptr<sdbusplus::asio::connection>& conn)
223{
224 // Check whether systemd completed all the loading.
225 conn->async_method_call(
226 [&server, &conn](boost::system::error_code ec,
227 const std::variant<uint64_t>& value) {
228 if (ec)
229 {
230 phosphor::logging::log<phosphor::logging::level::ERR>(
231 "async_method_call error: FinishTimestamp failed");
232 return;
233 }
234 if (std::get<uint64_t>(value))
235 {
236 if (!finishedSettingChkPoint)
237 {
238 finishedSettingChkPoint = true;
239 intel::pfr::setBMCBootCheckpoint(bmcBootFinishedChkPoint);
240 }
241 }
242 else
243 {
244 // FIX-ME: Latest up-stream sync caused issue in receiving
245 // StartupFinished signal. Unable to get StartupFinished signal
246 // from systemd1 hence using poll method too, to trigger it
247 // properly.
248 constexpr size_t pollTimeout = 10; // seconds
249 initTimer->expires_after(std::chrono::seconds(pollTimeout));
250 initTimer->async_wait([&server, &conn](
251 const boost::system::error_code& ec) {
252 if (ec == boost::asio::error::operation_aborted)
253 {
254 // Timer reset.
255 return;
256 }
257 if (ec)
258 {
259 phosphor::logging::log<phosphor::logging::level::ERR>(
260 "Set boot Checkpoint - async wait error.");
261 return;
262 }
263 checkAndSetCheckpoint(server, conn);
264 });
265 }
266 },
267 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
268 "org.freedesktop.DBus.Properties", "Get",
269 "org.freedesktop.systemd1.Manager", "FinishTimestamp");
270}
271
AppaRao Pulie63eeda2019-07-05 16:25:38 +0530272int main()
273{
274 // setup connection to dbus
275 boost::asio::io_service io;
276 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530277 stateTimer = std::make_unique<boost::asio::steady_timer>(io);
AppaRao Puli46cead92019-07-22 16:50:09 +0530278 initTimer = std::make_unique<boost::asio::steady_timer>(io);
AppaRao Pulicc1ed682019-10-01 12:29:40 +0530279 conn->request_name("xyz.openbmc_project.PFR.Manager");
AppaRao Pulie4e95652019-07-19 16:52:01 +0530280 auto server = sdbusplus::asio::object_server(conn);
AppaRao Pulie63eeda2019-07-05 16:25:38 +0530281
AppaRao Pulicc1ed682019-10-01 12:29:40 +0530282 // Create PFR attributes object and interface
AppaRao Pulie4e95652019-07-19 16:52:01 +0530283 pfrConfigObject = std::make_unique<intel::pfr::PfrConfig>(server, conn);
AppaRao Pulie63eeda2019-07-05 16:25:38 +0530284
AppaRao Pulie4e95652019-07-19 16:52:01 +0530285 pfrVersionObjects.clear();
AppaRao Pulie63eeda2019-07-05 16:25:38 +0530286 // Create Software objects using Versions interface
AppaRao Pulie4e95652019-07-19 16:52:01 +0530287 for (const auto& entry : verComponentList)
AppaRao Pulie63eeda2019-07-05 16:25:38 +0530288 {
AppaRao Pulie4e95652019-07-19 16:52:01 +0530289 pfrVersionObjects.emplace_back(std::make_unique<intel::pfr::PfrVersion>(
290 server, conn, std::get<0>(entry), std::get<1>(entry),
291 std::get<2>(entry)));
AppaRao Pulie63eeda2019-07-05 16:25:38 +0530292 }
293
AppaRao Puli46cead92019-07-22 16:50:09 +0530294 // Monitor Boot finished signal and set the checkpoint 9 to
295 // notify CPLD about BMC boot finish.
296 auto bootFinishedSignal = std::make_unique<sdbusplus::bus::match::match>(
297 static_cast<sdbusplus::bus::bus&>(*conn),
298 "type='signal',"
299 "member='StartupFinished',path='/org/freedesktop/systemd1',"
300 "interface='org.freedesktop.systemd1.Manager'",
301 [&server, &conn](sdbusplus::message::message& msg) {
302 if (!finishedSettingChkPoint)
303 {
304 finishedSettingChkPoint = true;
305 intel::pfr::setBMCBootCheckpoint(bmcBootFinishedChkPoint);
306 }
307 });
308 checkAndSetCheckpoint(server, conn);
309
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530310 // Capture the Chassis state and Start the monitor timer
311 // if state changed to 'On'. Run timer until OS boot.
312 // Stop timer if state changed to 'Off'.
313 static auto matchChassisState = sdbusplus::bus::match::match(
314 static_cast<sdbusplus::bus::bus&>(*conn),
315 "type='signal',member='PropertiesChanged', "
316 "interface='org.freedesktop.DBus.Properties', "
317 "sender='xyz.openbmc_project.State.Chassis', "
318 "arg0namespace='xyz.openbmc_project.State.Chassis'",
319 [&server, &conn](sdbusplus::message::message& message) {
320 std::string intfName;
321 std::map<std::string, std::variant<std::string>> properties;
322 message.read(intfName, properties);
323
324 const auto it = properties.find("CurrentPowerState");
325 if (it != properties.end())
326 {
327 const std::string* state =
328 std::get_if<std::string>(&it->second);
329 if (state != nullptr)
330 {
331 if ((*state ==
332 "xyz.openbmc_project.State.Chassis.PowerState.On") &&
333 (!stateTimerRunning))
334 {
335 stateTimerRunning = true;
336 monitorPlatformStateChange(server, conn);
337 }
338 else if ((*state == "xyz.openbmc_project.State.Chassis."
339 "PowerState.Off") &&
340 (stateTimerRunning))
341 {
342 stateTimer->cancel();
343 checkAndLogEvents();
344 stateTimerRunning = false;
345 }
346 }
AppaRao Pulie4e95652019-07-19 16:52:01 +0530347
348 // Update the D-Bus properties when chassis state changes.
349 updateDbusPropertiesCache();
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530350 }
351 });
352
353 // Capture the Host state and Start the monitor timer
354 // if state changed to 'Running'. Run timer until OS boot.
355 // Stop timer if state changed to 'Off'.
356 static auto matchHostState = sdbusplus::bus::match::match(
357 static_cast<sdbusplus::bus::bus&>(*conn),
358 "type='signal',member='PropertiesChanged', "
359 "interface='org.freedesktop.DBus.Properties', "
360 "sender='xyz.openbmc_project.State.Chassis', "
361 "arg0namespace='xyz.openbmc_project.State.Host'",
362 [&server, &conn](sdbusplus::message::message& message) {
363 std::string intfName;
364 std::map<std::string, std::variant<std::string>> properties;
365 message.read(intfName, properties);
366
367 const auto it = properties.find("CurrentHostState");
368 if (it != properties.end())
369 {
370 const std::string* state =
371 std::get_if<std::string>(&it->second);
372 if (state != nullptr)
373 {
374 if ((*state ==
375 "xyz.openbmc_project.State.Host.HostState.Running") &&
376 (!stateTimerRunning))
377 {
378 stateTimerRunning = true;
379 monitorPlatformStateChange(server, conn);
380 }
381 else if (((*state == "xyz.openbmc_project.State.Host."
382 "HostState.Off") ||
383 (*state == "xyz.openbmc_project.State.Host."
384 "HostState.Quiesced")) &&
385 (stateTimerRunning))
386 {
387 stateTimer->cancel();
388 checkAndLogEvents();
389 stateTimerRunning = false;
390 }
391 }
AppaRao Pulie4e95652019-07-19 16:52:01 +0530392
393 // Update the D-Bus properties when host state changes.
394 updateDbusPropertiesCache();
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530395 }
396 });
397
398 // Capture the OS state change and stop monitor timer
399 // if OS boots completly or becomes Inactive.
400 // start timer in other cases to mnitor states.
401 static auto matchOsState = sdbusplus::bus::match::match(
402 static_cast<sdbusplus::bus::bus&>(*conn),
403 "type='signal',member='PropertiesChanged', "
404 "interface='org.freedesktop.DBus.Properties', "
405 "sender='xyz.openbmc_project.State.Chassis', "
406 "arg0namespace='xyz.openbmc_project.State.OperatingSystem.Status'",
407 [&server, &conn](sdbusplus::message::message& message) {
408 std::string intfName;
409 std::map<std::string, std::variant<std::string>> properties;
410 message.read(intfName, properties);
411
412 const auto it = properties.find("OperatingSystemState");
413 if (it != properties.end())
414 {
415 const std::string* state =
416 std::get_if<std::string>(&it->second);
417 if (state != nullptr)
418 {
419 if (((*state == "BootComplete") ||
420 (*state == "Inactive")) &&
421 (stateTimerRunning))
422 {
423 stateTimer->cancel();
424 checkAndLogEvents();
425 stateTimerRunning = false;
426 }
427 else if (!stateTimerRunning)
428 {
429 stateTimerRunning = true;
430 monitorPlatformStateChange(server, conn);
431 }
432 }
433 }
434 });
435
436 // First time, check and log events if any.
437 checkAndLogEvents();
438
AppaRao Pulie63eeda2019-07-05 16:25:38 +0530439 phosphor::logging::log<phosphor::logging::level::INFO>(
440 "Intel PFR service started successfully");
441
442 io.run();
443
444 return 0;
445}