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