xref: /openbmc/phosphor-post-code-manager/inc/post_code.hpp (revision 8290e0f3297a2c5cbaa8d872d5cf8e19166ca177)
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 <phosphor-logging/elog-errors.hpp>
22 #include <xyz/openbmc_project/Collection/DeleteAll/server.hpp>
23 #include <xyz/openbmc_project/Common/error.hpp>
24 #include <xyz/openbmc_project/State/Boot/PostCode/server.hpp>
25 #include <xyz/openbmc_project/State/Host/server.hpp>
26 
27 #include <chrono>
28 #include <filesystem>
29 #include <fstream>
30 #include <iostream>
31 
32 const static constexpr char* CurrentBootCycleCountName =
33     "CurrentBootCycleCount";
34 const static constexpr char* CurrentBootCycleIndexName =
35     "CurrentBootCycleIndex";
36 
37 const static constexpr char* PostCodePath =
38     "/xyz/openbmc_project/state/boot/raw";
39 const static constexpr char* PostCodeListPathPrefix =
40     "/var/lib/phosphor-post-code-manager/host";
41 const static constexpr char* HostStatePathPrefix =
42     "/xyz/openbmc_project/state/host";
43 
44 struct EventDeleter
45 {
46     void operator()(sd_event* event) const
47     {
48         sd_event_unref(event);
49     }
50 };
51 using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
52 using primarycode_t = uint64_t;
53 using secondarycode_t = std::vector<uint8_t>;
54 using postcode_t = std::tuple<primarycode_t, secondarycode_t>;
55 namespace fs = std::filesystem;
56 namespace StateServer = sdbusplus::xyz::openbmc_project::State::server;
57 
58 using post_code =
59     sdbusplus::xyz::openbmc_project::State::Boot::server::PostCode;
60 using delete_all =
61     sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll;
62 
63 struct PostCode : sdbusplus::server::object_t<post_code, delete_all>
64 {
65     PostCode(sdbusplus::bus_t& bus, const char* path, int nodeIndex) :
66         sdbusplus::server::object_t<post_code, delete_all>(bus, path), bus(bus),
67         node(nodeIndex),
68         postCodeListPath(PostCodeListPathPrefix + std::to_string(node)),
69         propertiesChangedSignalRaw(
70             bus,
71             sdbusplus::bus::match::rules::propertiesChanged(
72                 PostCodePath + std::to_string(node),
73                 "xyz.openbmc_project.State.Boot.Raw"),
74             [this](sdbusplus::message_t& msg) {
75                 std::string intfName;
76                 std::map<std::string, std::variant<postcode_t>> msgData;
77                 msg.read(intfName, msgData);
78                 // Check if it was the Value property that changed.
79                 auto valPropMap = msgData.find("Value");
80                 if (valPropMap != msgData.end())
81                 {
82                     this->savePostCodes(
83                         std::get<postcode_t>(valPropMap->second));
84                 }
85             }),
86         propertiesChangedSignalCurrentHostState(
87             bus,
88             sdbusplus::bus::match::rules::propertiesChanged(
89                 HostStatePathPrefix + std::to_string(node),
90                 "xyz.openbmc_project.State.Host"),
91             [this](sdbusplus::message_t& msg) {
92                 std::string intfName;
93                 std::map<std::string, std::variant<std::string>> msgData;
94                 msg.read(intfName, msgData);
95                 // Check if it was the Value property that changed.
96                 auto valPropMap = msgData.find("CurrentHostState");
97                 if (valPropMap != msgData.end())
98                 {
99                     StateServer::Host::HostState currentHostState =
100                         StateServer::Host::convertHostStateFromString(
101                             std::get<std::string>(valPropMap->second));
102                     if (currentHostState == StateServer::Host::HostState::Off)
103                     {
104                         if (this->postCodes.empty())
105                         {
106                             std::cerr << "HostState changed to OFF. Empty "
107                                          "postcode log, keep boot cycle at "
108                                       << this->currentBootCycleIndex
109                                       << std::endl;
110                         }
111                         else
112                         {
113                             this->postCodes.clear();
114                         }
115                     }
116                 }
117             })
118     {
119         phosphor::logging::log<phosphor::logging::level::INFO>(
120             "PostCode is created");
121         fs::create_directories(postCodeListPath);
122         deserialize(postCodeListPath / CurrentBootCycleIndexName,
123                     currentBootCycleIndex);
124         uint16_t count = 0;
125         deserialize(postCodeListPath / CurrentBootCycleCountName, count);
126         currentBootCycleCount(count);
127         maxBootCycleNum(MAX_BOOT_CYCLE_COUNT);
128     }
129     ~PostCode() {}
130 
131     std::vector<postcode_t> getPostCodes(uint16_t index) override;
132     std::map<uint64_t, postcode_t>
133         getPostCodesWithTimeStamp(uint16_t index) override;
134     void deleteAll() override;
135 
136   private:
137     void incrBootCycle();
138     uint16_t getBootNum(const uint16_t index) const;
139 
140     sdbusplus::bus_t& bus;
141     int node;
142     std::chrono::time_point<std::chrono::steady_clock> firstPostCodeTimeSteady;
143     uint64_t firstPostCodeUsSinceEpoch;
144     std::map<uint64_t, postcode_t> postCodes;
145     fs::path postCodeListPath;
146     uint16_t currentBootCycleIndex = 0;
147     sdbusplus::bus::match_t propertiesChangedSignalRaw;
148     sdbusplus::bus::match_t propertiesChangedSignalCurrentHostState;
149 
150     void savePostCodes(postcode_t code);
151     fs::path serialize(const fs::path& path);
152     bool deserialize(const fs::path& path, uint16_t& index);
153     bool deserializePostCodes(const fs::path& path,
154                               std::map<uint64_t, postcode_t>& codes);
155 };
156