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