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