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