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 <phosphor-logging/elog-errors.hpp> 22 #include <sdbusplus/timer.hpp> 23 #include <xyz/openbmc_project/Collection/DeleteAll/server.hpp> 24 #include <xyz/openbmc_project/Common/error.hpp> 25 #include <xyz/openbmc_project/State/Boot/PostCode/server.hpp> 26 #include <xyz/openbmc_project/State/Host/server.hpp> 27 28 #include <chrono> 29 #include <filesystem> 30 #include <fstream> 31 #include <iostream> 32 33 const static constexpr char* CurrentBootCycleCountName = 34 "CurrentBootCycleCount"; 35 const static constexpr char* CurrentBootCycleIndexName = 36 "CurrentBootCycleIndex"; 37 38 const static constexpr char* PostCodePath = 39 "/xyz/openbmc_project/state/boot/raw"; 40 const static constexpr char* PostCodeListPathPrefix = 41 "/var/lib/phosphor-post-code-manager/host"; 42 const static constexpr char* HostStatePathPrefix = 43 "/xyz/openbmc_project/state/host"; 44 45 struct EventDeleter 46 { operator ()EventDeleter47 void operator()(sd_event* event) const 48 { 49 sd_event_unref(event); 50 } 51 }; 52 using EventPtr = std::unique_ptr<sd_event, EventDeleter>; 53 using primarycode_t = std::vector<uint8_t>; 54 using secondarycode_t = std::vector<uint8_t>; 55 using postcode_t = std::tuple<primarycode_t, secondarycode_t>; 56 namespace fs = std::filesystem; 57 namespace StateServer = sdbusplus::xyz::openbmc_project::State::server; 58 59 using post_code = 60 sdbusplus::xyz::openbmc_project::State::Boot::server::PostCode; 61 using delete_all = 62 sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll; 63 64 struct PostCode : sdbusplus::server::object_t<post_code, delete_all> 65 { PostCodePostCode66 PostCode(sdbusplus::bus_t& bus, const char* path, EventPtr& event, 67 int nodeIndex) : 68 sdbusplus::server::object_t<post_code, delete_all>(bus, path), bus(bus), 69 event(event), node(nodeIndex), 70 postCodeListPath(PostCodeListPathPrefix + std::to_string(node)), 71 propertiesChangedSignalRaw( 72 bus, 73 sdbusplus::bus::match::rules::propertiesChanged( 74 PostCodePath + std::to_string(node), 75 "xyz.openbmc_project.State.Boot.Raw"), 76 [this](sdbusplus::message_t& msg) { 77 std::string intfName; 78 std::map<std::string, std::variant<postcode_t>> msgData; 79 msg.read(intfName, msgData); 80 // Check if it was the Value property that changed. 81 auto valPropMap = msgData.find("Value"); 82 if (valPropMap != msgData.end()) 83 { 84 this->savePostCodes( 85 std::get<postcode_t>(valPropMap->second)); 86 } 87 }), 88 propertiesChangedSignalCurrentHostState( 89 bus, 90 sdbusplus::bus::match::rules::propertiesChanged( 91 HostStatePathPrefix + std::to_string(node), 92 "xyz.openbmc_project.State.Host"), __anon43c04d960202PostCode93 [this](sdbusplus::message_t& msg) { 94 std::string intfName; 95 std::map<std::string, std::variant<std::string>> msgData; 96 msg.read(intfName, msgData); 97 // Check if it was the Value property that changed. 98 auto valPropMap = msgData.find("CurrentHostState"); 99 if (valPropMap != msgData.end()) 100 { 101 StateServer::Host::HostState currentHostState = 102 StateServer::Host::convertHostStateFromString( 103 std::get<std::string>(valPropMap->second)); 104 if (currentHostState == StateServer::Host::HostState::Off) 105 { 106 if (this->postCodes.empty()) 107 { 108 std::cerr 109 << "HostState changed to OFF. Empty " 110 "postcode log, keep boot cycle at " 111 << this->currentBootCycleIndex << std::endl; 112 } 113 else 114 { 115 this->postCodes.clear(); 116 } 117 } 118 } 119 }) 120 { 121 phosphor::logging::log<phosphor::logging::level::INFO>( 122 "PostCode is created"); 123 fs::create_directories(postCodeListPath); 124 deserialize(postCodeListPath / CurrentBootCycleIndexName, 125 currentBootCycleIndex); 126 uint16_t count = 0; 127 deserialize(postCodeListPath / CurrentBootCycleCountName, count); 128 currentBootCycleCount(count); 129 maxBootCycleNum(MAX_BOOT_CYCLE_COUNT); 130 } ~PostCodePostCode131 ~PostCode() {} 132 133 std::vector<postcode_t> getPostCodes(uint16_t index) override; 134 std::map<uint64_t, postcode_t> 135 getPostCodesWithTimeStamp(uint16_t index) override; 136 void deleteAll() override; 137 138 private: 139 void incrBootCycle(); 140 uint16_t getBootNum(const uint16_t index) const; 141 142 std::unique_ptr<sdbusplus::Timer> timer; 143 sdbusplus::bus_t& bus; 144 EventPtr& event; 145 int node; 146 std::chrono::time_point<std::chrono::steady_clock> firstPostCodeTimeSteady; 147 uint64_t firstPostCodeUsSinceEpoch; 148 std::map<uint64_t, postcode_t> postCodes; 149 fs::path postCodeListPath; 150 uint16_t currentBootCycleIndex = 0; 151 sdbusplus::bus::match_t propertiesChangedSignalRaw; 152 sdbusplus::bus::match_t propertiesChangedSignalCurrentHostState; 153 154 void savePostCodes(postcode_t code); 155 fs::path serialize(const fs::path& path); 156 bool deserialize(const fs::path& path, uint16_t& index); 157 bool deserializePostCodes(const fs::path& path, 158 std::map<uint64_t, postcode_t>& codes); 159 }; 160