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