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 <fcntl.h> 18 #include <unistd.h> 19 20 #include <cereal/access.hpp> 21 #include <cereal/archives/json.hpp> 22 #include <cereal/cereal.hpp> 23 #include <cereal/types/vector.hpp> 24 #include <experimental/filesystem> 25 #include <fstream> 26 #include <iostream> 27 #include <phosphor-logging/elog-errors.hpp> 28 #include <xyz/openbmc_project/Common/error.hpp> 29 #include <xyz/openbmc_project/State/Boot/PostCode/server.hpp> 30 #include <xyz/openbmc_project/State/Host/server.hpp> 31 32 #define MaxPostCodeCycles 100 33 34 const static constexpr char *PostCodePath = 35 "/xyz/openbmc_project/state/boot/raw"; 36 const static constexpr char *PropertiesIntf = "org.freedesktop.DBus.Properties"; 37 const static constexpr char *PostCodeListPath = 38 "/var/lib/phosphor-post-code-manager/"; 39 const static constexpr char *CurrentBootCycleIndexName = 40 "CurrentBootCycleIndex"; 41 const static constexpr char *HostStatePath = "/xyz/openbmc_project/state/host0"; 42 43 struct EventDeleter 44 { 45 void operator()(sd_event *event) const 46 { 47 event = sd_event_unref(event); 48 } 49 }; 50 using EventPtr = std::unique_ptr<sd_event, EventDeleter>; 51 namespace fs = std::experimental::filesystem; 52 namespace StateServer = sdbusplus::xyz::openbmc_project::State::server; 53 54 using post_code = 55 sdbusplus::xyz::openbmc_project::State::Boot::server::PostCode; 56 57 struct PostCode : sdbusplus::server::object_t<post_code> 58 { 59 PostCode(sdbusplus::bus::bus &bus, const char *path, EventPtr &event) : 60 sdbusplus::server::object_t<post_code>(bus, path), bus(bus), 61 propertiesChangedSignalRaw( 62 bus, 63 sdbusplus::bus::match::rules::type::signal() + 64 sdbusplus::bus::match::rules::member("PropertiesChanged") + 65 sdbusplus::bus::match::rules::path(PostCodePath) + 66 sdbusplus::bus::match::rules::interface(PropertiesIntf), 67 [this](sdbusplus::message::message &msg) { 68 std::string objectName; 69 std::map<std::string, sdbusplus::message::variant<uint64_t>> 70 msgData; 71 msg.read(objectName, msgData); 72 // Check if it was the Value property that changed. 73 auto valPropMap = msgData.find("Value"); 74 { 75 if (valPropMap != msgData.end()) 76 { 77 this->savePostCodes( 78 sdbusplus::message::variant_ns::get<uint64_t>( 79 valPropMap->second)); 80 } 81 } 82 }), 83 propertiesChangedSignalCurrentHostState( 84 bus, 85 sdbusplus::bus::match::rules::type::signal() + 86 sdbusplus::bus::match::rules::member("PropertiesChanged") + 87 sdbusplus::bus::match::rules::path(HostStatePath) + 88 sdbusplus::bus::match::rules::interface(PropertiesIntf), 89 [this](sdbusplus::message::message &msg) { 90 std::string objectName; 91 std::map<std::string, sdbusplus::message::variant<std::string>> 92 msgData; 93 msg.read(objectName, msgData); 94 // Check if it was the Value property that changed. 95 auto valPropMap = msgData.find("CurrentHostState"); 96 { 97 if (valPropMap != msgData.end()) 98 { 99 StateServer::Host::HostState currentHostState = 100 StateServer::Host::convertHostStateFromString( 101 sdbusplus::message::variant_ns::get< 102 std::string>(valPropMap->second)); 103 if (currentHostState == 104 StateServer::Host::HostState::Off) 105 { 106 if (this->currentBootCycleIndex() >= 107 this->maxBootCycleNum()) 108 { 109 this->currentBootCycleIndex(1); 110 } 111 else 112 { 113 this->currentBootCycleIndex( 114 this->currentBootCycleIndex() + 1); 115 } 116 this->postCodes.clear(); 117 } 118 } 119 } 120 }) 121 { 122 phosphor::logging::log<phosphor::logging::level::INFO>( 123 "PostCode is created"); 124 auto dir = fs::path(PostCodeListPath); 125 fs::create_directories(dir); 126 strPostCodeListPath = PostCodeListPath; 127 strCurrentBootCycleIndexName = CurrentBootCycleIndexName; 128 uint16_t index = 0; 129 deserialize( 130 fs::path(strPostCodeListPath + strCurrentBootCycleIndexName), 131 index); 132 currentBootCycleIndex(index); 133 maxBootCycleNum(MaxPostCodeCycles); 134 if (currentBootCycleIndex() >= maxBootCycleNum()) 135 { 136 currentBootCycleIndex(1); 137 } 138 else 139 { 140 currentBootCycleIndex(currentBootCycleIndex() + 1); 141 } 142 } 143 ~PostCode() 144 { 145 } 146 147 std::vector<uint64_t> getPostCodes(uint16_t index) override; 148 149 private: 150 sdbusplus::bus::bus &bus; 151 std::vector<uint64_t> postCodes; 152 std::string strPostCodeListPath; 153 std::string strCurrentBootCycleIndexName; 154 void savePostCodes(uint64_t code); 155 sdbusplus::bus::match_t propertiesChangedSignalRaw; 156 sdbusplus::bus::match_t propertiesChangedSignalCurrentHostState; 157 fs::path serialize(const std::string &path); 158 bool deserialize(const fs::path &path, uint16_t &index); 159 bool deserializePostCodes(const fs::path &path, 160 std::vector<uint64_t> &codes); 161 }; 162