xref: /openbmc/phosphor-post-code-manager/inc/post_code.hpp (revision 9d91a39a3a760358a4c1a5e89fb5ef57d1bd7995)
1 /*
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 #pragma once
17 #include <fcntl.h>
18 #include <unistd.h>
19 
20 #include <cereal/access.hpp>
21 #include <cereal/archives/json.hpp>
22 #include <cereal/cereal.hpp>
23 #include <cereal/types/map.hpp>
24 #include <cereal/types/vector.hpp>
25 #include <chrono>
26 #include <experimental/filesystem>
27 #include <fstream>
28 #include <iostream>
29 #include <phosphor-logging/elog-errors.hpp>
30 #include <xyz/openbmc_project/Collection/DeleteAll/server.hpp>
31 #include <xyz/openbmc_project/Common/error.hpp>
32 #include <xyz/openbmc_project/State/Boot/PostCode/server.hpp>
33 #include <xyz/openbmc_project/State/Host/server.hpp>
34 
35 #define MaxPostCodeCycles 100
36 
37 const static constexpr char *PostCodePath =
38     "/xyz/openbmc_project/state/boot/raw";
39 const static constexpr char *PropertiesIntf = "org.freedesktop.DBus.Properties";
40 const static constexpr char *PostCodeListPath =
41     "/var/lib/phosphor-post-code-manager/";
42 const static constexpr char *CurrentBootCycleCountName =
43     "CurrentBootCycleCount";
44 const static constexpr char *CurrentBootCycleIndexName =
45     "CurrentBootCycleIndex";
46 const static constexpr char *HostStatePath = "/xyz/openbmc_project/state/host0";
47 
48 struct EventDeleter
49 {
50     void operator()(sd_event *event) const
51     {
52         event = sd_event_unref(event);
53     }
54 };
55 using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
56 namespace fs = std::experimental::filesystem;
57 namespace StateServer = sdbusplus::xyz::openbmc_project::State::server;
58 
59 using post_code =
60     sdbusplus::xyz::openbmc_project::State::Boot::server::PostCode;
61 using delete_all =
62     sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll;
63 
64 struct PostCode : sdbusplus::server::object_t<post_code, delete_all>
65 {
66     PostCode(sdbusplus::bus::bus &bus, const char *path, EventPtr &event) :
67         sdbusplus::server::object_t<post_code, delete_all>(bus, path), bus(bus),
68         propertiesChangedSignalRaw(
69             bus,
70             sdbusplus::bus::match::rules::type::signal() +
71                 sdbusplus::bus::match::rules::member("PropertiesChanged") +
72                 sdbusplus::bus::match::rules::path(PostCodePath) +
73                 sdbusplus::bus::match::rules::interface(PropertiesIntf),
74             [this](sdbusplus::message::message &msg) {
75                 std::string objectName;
76                 std::map<std::string, std::variant<uint64_t>> msgData;
77                 msg.read(objectName, msgData);
78                 // Check if it was the Value property that changed.
79                 auto valPropMap = msgData.find("Value");
80                 {
81                     if (valPropMap != msgData.end())
82                     {
83                         this->savePostCodes(
84                             std::get<uint64_t>(valPropMap->second));
85                     }
86                 }
87             }),
88         propertiesChangedSignalCurrentHostState(
89             bus,
90             sdbusplus::bus::match::rules::type::signal() +
91                 sdbusplus::bus::match::rules::member("PropertiesChanged") +
92                 sdbusplus::bus::match::rules::path(HostStatePath) +
93                 sdbusplus::bus::match::rules::interface(PropertiesIntf),
94             [this](sdbusplus::message::message &msg) {
95                 std::string objectName;
96                 std::map<std::string, std::variant<std::string>> msgData;
97                 msg.read(objectName, msgData);
98                 // Check if it was the Value property that changed.
99                 auto valPropMap = msgData.find("CurrentHostState");
100                 {
101                     if (valPropMap != msgData.end())
102                     {
103                         StateServer::Host::HostState currentHostState =
104                             StateServer::Host::convertHostStateFromString(
105                                 std::get<std::string>(valPropMap->second));
106                         if (currentHostState ==
107                             StateServer::Host::HostState::Off)
108                         {
109                             if (this->postCodes.empty())
110                             {
111                                 std::cerr << "HostState changed to OFF. Empty "
112                                              "postcode log, keep boot cycle at "
113                                           << this->currentBootCycleIndex
114                                           << std::endl;
115                             }
116                             else
117                             {
118                                 this->postCodes.clear();
119                             }
120                         }
121                     }
122                 }
123             })
124     {
125         phosphor::logging::log<phosphor::logging::level::INFO>(
126             "PostCode is created");
127         auto dir = fs::path(PostCodeListPath);
128         fs::create_directories(dir);
129         strPostCodeListPath = PostCodeListPath;
130         strCurrentBootCycleIndexName = CurrentBootCycleIndexName;
131         uint16_t index = 0;
132         deserialize(
133             fs::path(strPostCodeListPath + strCurrentBootCycleIndexName),
134             index);
135         currentBootCycleIndex = index;
136         strCurrentBootCycleCountName = CurrentBootCycleCountName;
137         uint16_t count = 0;
138         deserialize(
139             fs::path(strPostCodeListPath + strCurrentBootCycleCountName),
140             count);
141         currentBootCycleCount(count);
142         maxBootCycleNum(MaxPostCodeCycles);
143     }
144     ~PostCode()
145     {
146     }
147 
148     std::vector<uint64_t> getPostCodes(uint16_t index) override;
149     std::map<uint64_t, uint64_t>
150         getPostCodesWithTimeStamp(uint16_t index) override;
151     void deleteAll() override;
152 
153   private:
154     void incrBootCycle();
155     uint16_t getBootNum(const uint16_t index) const;
156 
157     sdbusplus::bus::bus &bus;
158     std::chrono::time_point<std::chrono::steady_clock> firstPostCodeTimeSteady;
159     uint64_t firstPostCodeUsSinceEpoch;
160     std::map<uint64_t, uint64_t> postCodes;
161     std::string strPostCodeListPath;
162     std::string strCurrentBootCycleIndexName;
163     uint16_t currentBootCycleIndex;
164     std::string strCurrentBootCycleCountName;
165     void savePostCodes(uint64_t code);
166     sdbusplus::bus::match_t propertiesChangedSignalRaw;
167     sdbusplus::bus::match_t propertiesChangedSignalCurrentHostState;
168     fs::path serialize(const std::string &path);
169     bool deserialize(const fs::path &path, uint16_t &index);
170     bool deserializePostCodes(const fs::path &path,
171                               std::map<uint64_t, uint64_t> &codes);
172 };
173