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