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 <nlohmann/json.hpp> 22 #include <phosphor-logging/elog-errors.hpp> 23 #include <sdbusplus/timer.hpp> 24 #include <xyz/openbmc_project/Collection/DeleteAll/server.hpp> 25 #include <xyz/openbmc_project/Common/error.hpp> 26 #include <xyz/openbmc_project/State/Boot/PostCode/server.hpp> 27 #include <xyz/openbmc_project/State/Host/server.hpp> 28 29 #include <chrono> 30 #include <filesystem> 31 #include <fstream> 32 #include <iostream> 33 34 const static constexpr char* CurrentBootCycleCountName = 35 "CurrentBootCycleCount"; 36 const static constexpr char* CurrentBootCycleIndexName = 37 "CurrentBootCycleIndex"; 38 39 const static constexpr char* PostCodePath = 40 "/xyz/openbmc_project/state/boot/raw"; 41 const static constexpr char* PostCodeListPathPrefix = 42 "/var/lib/phosphor-post-code-manager/host"; 43 const static constexpr char* HostStatePathPrefix = 44 "/xyz/openbmc_project/state/host"; 45 const static constexpr char* PostCodeDataVersionName = "PostCodeDataVersion"; 46 const static constexpr uint16_t PostCodeDataVersion = 1; 47 48 struct EventDeleter 49 { operator ()EventDeleter50 void operator()(sd_event* event) const 51 { 52 sd_event_unref(event); 53 } 54 }; 55 using EventPtr = std::unique_ptr<sd_event, EventDeleter>; 56 using primarycode_t = std::vector<uint8_t>; 57 using secondarycode_t = std::vector<uint8_t>; 58 using postcode_t = std::tuple<primarycode_t, secondarycode_t>; 59 namespace fs = std::filesystem; 60 namespace StateServer = sdbusplus::xyz::openbmc_project::State::server; 61 62 using post_code = 63 sdbusplus::xyz::openbmc_project::State::Boot::server::PostCode; 64 using delete_all = 65 sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll; 66 67 struct PostCodeEvent 68 { 69 std::string name; 70 nlohmann::json args; 71 void raise() const; 72 }; 73 74 struct PostCodeHandler 75 { 76 std::string name; 77 std::string description; 78 primarycode_t primary; 79 std::optional<secondarycode_t> secondary; 80 std::vector<std::string> targets; 81 std::optional<PostCodeEvent> event; 82 }; 83 84 struct PostCodeHandlers 85 { 86 std::vector<PostCodeHandler> handlers; 87 void handle(postcode_t code); 88 const PostCodeHandler* find(postcode_t code); 89 void load(const std::string& path); 90 }; 91 92 struct PostCode : sdbusplus::server::object_t<post_code, delete_all> 93 { PostCodePostCode94 PostCode(sdbusplus::bus_t& bus, const char* path, EventPtr& event, 95 int nodeIndex, PostCodeHandlers& handlers) : 96 sdbusplus::server::object_t<post_code, delete_all>(bus, path), bus(bus), 97 event(event), node(nodeIndex), 98 postCodeListPath(PostCodeListPathPrefix + std::to_string(node)), 99 propertiesChangedSignalRaw( 100 bus, 101 sdbusplus::bus::match::rules::propertiesChanged( 102 PostCodePath + std::to_string(node), 103 "xyz.openbmc_project.State.Boot.Raw"), 104 [this](sdbusplus::message_t& msg) { 105 std::string intfName; 106 std::map<std::string, std::variant<postcode_t>> msgData; 107 msg.read(intfName, msgData); 108 // Check if it was the Value property that changed. 109 auto valPropMap = msgData.find("Value"); 110 if (valPropMap != msgData.end()) 111 { 112 this->savePostCodes( 113 std::get<postcode_t>(valPropMap->second)); 114 } 115 }), 116 propertiesChangedSignalCurrentHostState( 117 bus, 118 sdbusplus::bus::match::rules::propertiesChanged( 119 HostStatePathPrefix + std::to_string(node), 120 "xyz.openbmc_project.State.Host"), __anon43c04d960202PostCode121 [this](sdbusplus::message_t& msg) { 122 std::string intfName; 123 std::map<std::string, std::variant<std::string>> msgData; 124 msg.read(intfName, msgData); 125 // Check if it was the Value property that changed. 126 auto valPropMap = msgData.find("CurrentHostState"); 127 if (valPropMap != msgData.end()) 128 { 129 StateServer::Host::HostState currentHostState = 130 StateServer::Host::convertHostStateFromString( 131 std::get<std::string>(valPropMap->second)); 132 if (currentHostState == StateServer::Host::HostState::Off) 133 { 134 if (this->postCodes.empty()) 135 { 136 std::cerr 137 << "HostState changed to OFF. Empty " 138 "postcode log, keep boot cycle at " 139 << this->currentBootCycleIndex << std::endl; 140 } 141 else 142 { 143 this->postCodes.clear(); 144 } 145 } 146 } 147 }), 148 postCodeHandlers(std::move(handlers)) 149 { 150 phosphor::logging::log<phosphor::logging::level::INFO>( 151 "PostCode is created"); 152 fs::create_directories(postCodeListPath); 153 uint16_t version = 0; 154 if (!deserialize(postCodeListPath / PostCodeDataVersionName, version) || 155 version != PostCodeDataVersion) 156 { 157 phosphor::logging::log<phosphor::logging::level::INFO>( 158 "This version of post code data is not supported"); 159 fs::remove_all(postCodeListPath); 160 fs::create_directories(postCodeListPath); 161 postCodes.clear(); 162 currentBootCycleIndex = 0; 163 currentBootCycleCount(0); 164 } 165 else 166 { 167 deserialize(postCodeListPath / CurrentBootCycleIndexName, 168 currentBootCycleIndex); 169 uint16_t count = 0; 170 deserialize(postCodeListPath / CurrentBootCycleCountName, count); 171 currentBootCycleCount(count); 172 } 173 maxBootCycleNum(MAX_BOOT_CYCLE_COUNT); 174 } ~PostCodePostCode175 ~PostCode() {} 176 177 std::vector<postcode_t> getPostCodes(uint16_t index) override; 178 std::map<uint64_t, postcode_t> getPostCodesWithTimeStamp( 179 uint16_t index) override; 180 void deleteAll() override; 181 182 private: 183 void incrBootCycle(); 184 uint16_t getBootNum(const uint16_t index) const; 185 186 std::unique_ptr<sdbusplus::Timer> timer; 187 sdbusplus::bus_t& bus; 188 EventPtr& event; 189 int node; 190 std::chrono::time_point<std::chrono::steady_clock> firstPostCodeTimeSteady; 191 uint64_t firstPostCodeUsSinceEpoch; 192 std::map<uint64_t, postcode_t> postCodes; 193 fs::path postCodeListPath; 194 uint16_t currentBootCycleIndex = 0; 195 sdbusplus::bus::match_t propertiesChangedSignalRaw; 196 sdbusplus::bus::match_t propertiesChangedSignalCurrentHostState; 197 198 void savePostCodes(postcode_t code); 199 fs::path serialize(const fs::path& 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 PostCodeHandlers postCodeHandlers; 204 }; 205