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