1*c6e8fb50SDeepak Kodihalli #pragma once 2*c6e8fb50SDeepak Kodihalli 3*c6e8fb50SDeepak Kodihalli #include "effecters.hpp" 4*c6e8fb50SDeepak Kodihalli 5*c6e8fb50SDeepak Kodihalli #include <stdint.h> 6*c6e8fb50SDeepak Kodihalli 7*c6e8fb50SDeepak Kodihalli #include <filesystem> 8*c6e8fb50SDeepak Kodihalli #include <fstream> 9*c6e8fb50SDeepak Kodihalli #include <functional> 10*c6e8fb50SDeepak Kodihalli #include <map> 11*c6e8fb50SDeepak Kodihalli #include <nlohmann/json.hpp> 12*c6e8fb50SDeepak Kodihalli #include <phosphor-logging/elog-errors.hpp> 13*c6e8fb50SDeepak Kodihalli #include <phosphor-logging/log.hpp> 14*c6e8fb50SDeepak Kodihalli #include <string> 15*c6e8fb50SDeepak Kodihalli #include <vector> 16*c6e8fb50SDeepak Kodihalli #include <xyz/openbmc_project/Common/error.hpp> 17*c6e8fb50SDeepak Kodihalli 18*c6e8fb50SDeepak Kodihalli #include "libpldm/platform.h" 19*c6e8fb50SDeepak Kodihalli 20*c6e8fb50SDeepak Kodihalli using namespace phosphor::logging; 21*c6e8fb50SDeepak Kodihalli using InternalFailure = 22*c6e8fb50SDeepak Kodihalli sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 23*c6e8fb50SDeepak Kodihalli namespace fs = std::filesystem; 24*c6e8fb50SDeepak Kodihalli 25*c6e8fb50SDeepak Kodihalli namespace pldm 26*c6e8fb50SDeepak Kodihalli { 27*c6e8fb50SDeepak Kodihalli 28*c6e8fb50SDeepak Kodihalli namespace responder 29*c6e8fb50SDeepak Kodihalli { 30*c6e8fb50SDeepak Kodihalli 31*c6e8fb50SDeepak Kodihalli namespace pdr 32*c6e8fb50SDeepak Kodihalli { 33*c6e8fb50SDeepak Kodihalli 34*c6e8fb50SDeepak Kodihalli using Type = uint8_t; 35*c6e8fb50SDeepak Kodihalli using Json = nlohmann::json; 36*c6e8fb50SDeepak Kodihalli using RecordHandle = uint32_t; 37*c6e8fb50SDeepak Kodihalli using Entry = std::vector<uint8_t>; 38*c6e8fb50SDeepak Kodihalli using Pdr = std::vector<Entry>; 39*c6e8fb50SDeepak Kodihalli 40*c6e8fb50SDeepak Kodihalli /** @class Repo 41*c6e8fb50SDeepak Kodihalli * 42*c6e8fb50SDeepak Kodihalli * @brief Abstract class describing the interface API to the PDR repository 43*c6e8fb50SDeepak Kodihalli * 44*c6e8fb50SDeepak Kodihalli * Concrete implementations of this must handle storing and addressing the 45*c6e8fb50SDeepak Kodihalli * PDR entries by a "record handle", which can be indices, offsets, etc. 46*c6e8fb50SDeepak Kodihalli */ 47*c6e8fb50SDeepak Kodihalli class Repo 48*c6e8fb50SDeepak Kodihalli { 49*c6e8fb50SDeepak Kodihalli public: 50*c6e8fb50SDeepak Kodihalli /** @brief Add a new entry to the PDR 51*c6e8fb50SDeepak Kodihalli * 52*c6e8fb50SDeepak Kodihalli * @param[in] entry - new PDR entry 53*c6e8fb50SDeepak Kodihalli */ 54*c6e8fb50SDeepak Kodihalli virtual void add(Entry&& entry) = 0; 55*c6e8fb50SDeepak Kodihalli 56*c6e8fb50SDeepak Kodihalli /** @brief Access PDR entry at inout record handle 57*c6e8fb50SDeepak Kodihalli * 58*c6e8fb50SDeepak Kodihalli * @param[in] handle - record handle 59*c6e8fb50SDeepak Kodihalli * 60*c6e8fb50SDeepak Kodihalli * @return Entry - PDR entry 61*c6e8fb50SDeepak Kodihalli */ 62*c6e8fb50SDeepak Kodihalli virtual Entry at(RecordHandle handle) const = 0; 63*c6e8fb50SDeepak Kodihalli 64*c6e8fb50SDeepak Kodihalli /** @brief Get next available record handle for assignment 65*c6e8fb50SDeepak Kodihalli * 66*c6e8fb50SDeepak Kodihalli * @return RecordHandle - PDR record handle 67*c6e8fb50SDeepak Kodihalli */ 68*c6e8fb50SDeepak Kodihalli virtual RecordHandle getNextRecordHandle() const = 0; 69*c6e8fb50SDeepak Kodihalli 70*c6e8fb50SDeepak Kodihalli /** @brief Get record handle immediately suceeding the input record 71*c6e8fb50SDeepak Kodihalli * handle 72*c6e8fb50SDeepak Kodihalli * 73*c6e8fb50SDeepak Kodihalli * @param[in] current - input record handle 74*c6e8fb50SDeepak Kodihalli * 75*c6e8fb50SDeepak Kodihalli * @return RecordHandle - PDR record handle 76*c6e8fb50SDeepak Kodihalli */ 77*c6e8fb50SDeepak Kodihalli virtual RecordHandle getNextRecordHandle(RecordHandle current) const = 0; 78*c6e8fb50SDeepak Kodihalli 79*c6e8fb50SDeepak Kodihalli /** @brief Get number of entries in the PDR 80*c6e8fb50SDeepak Kodihalli * 81*c6e8fb50SDeepak Kodihalli * @return size_t - number of entries 82*c6e8fb50SDeepak Kodihalli */ 83*c6e8fb50SDeepak Kodihalli virtual size_t numEntries() const = 0; 84*c6e8fb50SDeepak Kodihalli 85*c6e8fb50SDeepak Kodihalli /** @brief Check if PDR is empty 86*c6e8fb50SDeepak Kodihalli * 87*c6e8fb50SDeepak Kodihalli * @return bool - true if PDR is empty, false otherwise 88*c6e8fb50SDeepak Kodihalli */ 89*c6e8fb50SDeepak Kodihalli virtual bool empty() const = 0; 90*c6e8fb50SDeepak Kodihalli 91*c6e8fb50SDeepak Kodihalli /** @brief Empty the PDR 92*c6e8fb50SDeepak Kodihalli */ 93*c6e8fb50SDeepak Kodihalli virtual void makeEmpty() = 0; 94*c6e8fb50SDeepak Kodihalli }; 95*c6e8fb50SDeepak Kodihalli 96*c6e8fb50SDeepak Kodihalli namespace internal 97*c6e8fb50SDeepak Kodihalli { 98*c6e8fb50SDeepak Kodihalli 99*c6e8fb50SDeepak Kodihalli /** @brief Parse PDR JSON file and output Json object 100*c6e8fb50SDeepak Kodihalli * 101*c6e8fb50SDeepak Kodihalli * @param[in] path - path of PDR JSON file 102*c6e8fb50SDeepak Kodihalli * 103*c6e8fb50SDeepak Kodihalli * @return Json - Json object 104*c6e8fb50SDeepak Kodihalli */ 105*c6e8fb50SDeepak Kodihalli inline Json readJson(const std::string& path) 106*c6e8fb50SDeepak Kodihalli { 107*c6e8fb50SDeepak Kodihalli std::ifstream jsonFile(path); 108*c6e8fb50SDeepak Kodihalli if (!jsonFile.is_open()) 109*c6e8fb50SDeepak Kodihalli { 110*c6e8fb50SDeepak Kodihalli log<level::INFO>("Error opening PDR JSON file", 111*c6e8fb50SDeepak Kodihalli entry("PATH=%s", path.c_str())); 112*c6e8fb50SDeepak Kodihalli return {}; 113*c6e8fb50SDeepak Kodihalli } 114*c6e8fb50SDeepak Kodihalli 115*c6e8fb50SDeepak Kodihalli return Json::parse(jsonFile); 116*c6e8fb50SDeepak Kodihalli } 117*c6e8fb50SDeepak Kodihalli 118*c6e8fb50SDeepak Kodihalli /** @class IndexedRepo 119*c6e8fb50SDeepak Kodihalli * 120*c6e8fb50SDeepak Kodihalli * @brief Inherits and implements Repo 121*c6e8fb50SDeepak Kodihalli * 122*c6e8fb50SDeepak Kodihalli * Stores the PDR as a vector of entries, and addresses PDR entries based on an 123*c6e8fb50SDeepak Kodihalli * incrementing record handle, starting at 1. 124*c6e8fb50SDeepak Kodihalli */ 125*c6e8fb50SDeepak Kodihalli class IndexedRepo : public Repo 126*c6e8fb50SDeepak Kodihalli { 127*c6e8fb50SDeepak Kodihalli public: 128*c6e8fb50SDeepak Kodihalli void add(Entry&& entry) 129*c6e8fb50SDeepak Kodihalli { 130*c6e8fb50SDeepak Kodihalli repo.emplace_back(std::move(entry)); 131*c6e8fb50SDeepak Kodihalli } 132*c6e8fb50SDeepak Kodihalli 133*c6e8fb50SDeepak Kodihalli Entry at(RecordHandle handle) const 134*c6e8fb50SDeepak Kodihalli { 135*c6e8fb50SDeepak Kodihalli if (!handle) 136*c6e8fb50SDeepak Kodihalli { 137*c6e8fb50SDeepak Kodihalli handle = 1; 138*c6e8fb50SDeepak Kodihalli } 139*c6e8fb50SDeepak Kodihalli return repo.at(handle - 1); 140*c6e8fb50SDeepak Kodihalli } 141*c6e8fb50SDeepak Kodihalli 142*c6e8fb50SDeepak Kodihalli RecordHandle getNextRecordHandle() const 143*c6e8fb50SDeepak Kodihalli { 144*c6e8fb50SDeepak Kodihalli return repo.size() + 1; 145*c6e8fb50SDeepak Kodihalli } 146*c6e8fb50SDeepak Kodihalli 147*c6e8fb50SDeepak Kodihalli RecordHandle getNextRecordHandle(RecordHandle current) const 148*c6e8fb50SDeepak Kodihalli { 149*c6e8fb50SDeepak Kodihalli if (current >= repo.size()) 150*c6e8fb50SDeepak Kodihalli { 151*c6e8fb50SDeepak Kodihalli return 0; 152*c6e8fb50SDeepak Kodihalli } 153*c6e8fb50SDeepak Kodihalli if (!current) 154*c6e8fb50SDeepak Kodihalli { 155*c6e8fb50SDeepak Kodihalli current = 1; 156*c6e8fb50SDeepak Kodihalli } 157*c6e8fb50SDeepak Kodihalli return current + 1; 158*c6e8fb50SDeepak Kodihalli } 159*c6e8fb50SDeepak Kodihalli 160*c6e8fb50SDeepak Kodihalli size_t numEntries() const 161*c6e8fb50SDeepak Kodihalli { 162*c6e8fb50SDeepak Kodihalli return repo.size(); 163*c6e8fb50SDeepak Kodihalli } 164*c6e8fb50SDeepak Kodihalli 165*c6e8fb50SDeepak Kodihalli bool empty() const 166*c6e8fb50SDeepak Kodihalli { 167*c6e8fb50SDeepak Kodihalli return repo.empty(); 168*c6e8fb50SDeepak Kodihalli } 169*c6e8fb50SDeepak Kodihalli 170*c6e8fb50SDeepak Kodihalli void makeEmpty() 171*c6e8fb50SDeepak Kodihalli { 172*c6e8fb50SDeepak Kodihalli repo.clear(); 173*c6e8fb50SDeepak Kodihalli } 174*c6e8fb50SDeepak Kodihalli 175*c6e8fb50SDeepak Kodihalli private: 176*c6e8fb50SDeepak Kodihalli Pdr repo{}; 177*c6e8fb50SDeepak Kodihalli }; 178*c6e8fb50SDeepak Kodihalli 179*c6e8fb50SDeepak Kodihalli /** @brief Parse PDR JSONs and build PDR repository 180*c6e8fb50SDeepak Kodihalli * 181*c6e8fb50SDeepak Kodihalli * @param[in] dir - directory housing platform specific PDR JSON files 182*c6e8fb50SDeepak Kodihalli * @tparam[in] repo - instance of concrete implementation of Repo 183*c6e8fb50SDeepak Kodihalli */ 184*c6e8fb50SDeepak Kodihalli template <typename T> 185*c6e8fb50SDeepak Kodihalli void generate(const std::string& dir, T& repo) 186*c6e8fb50SDeepak Kodihalli { 187*c6e8fb50SDeepak Kodihalli using namespace internal; 188*c6e8fb50SDeepak Kodihalli // A map of PDR type to a lambda that handles creation of that PDR type. 189*c6e8fb50SDeepak Kodihalli // The lambda essentially would parse the platform specific PDR JSONs to 190*c6e8fb50SDeepak Kodihalli // generate the PDR structures. This function iterates through the map to 191*c6e8fb50SDeepak Kodihalli // invoke all lambdas, so that all PDR types can be created. 192*c6e8fb50SDeepak Kodihalli std::map<Type, std::function<void(const Json& json, T& repo)>> generators = 193*c6e8fb50SDeepak Kodihalli {{PLDM_STATE_EFFECTER_PDR, [](const auto& json, T& repo) { 194*c6e8fb50SDeepak Kodihalli static const std::vector<Json> emptyList{}; 195*c6e8fb50SDeepak Kodihalli static const Json empty{}; 196*c6e8fb50SDeepak Kodihalli auto entries = json.value("entries", emptyList); 197*c6e8fb50SDeepak Kodihalli for (const auto& e : entries) 198*c6e8fb50SDeepak Kodihalli { 199*c6e8fb50SDeepak Kodihalli size_t pdrSize = 0; 200*c6e8fb50SDeepak Kodihalli auto effecters = e.value("effecters", emptyList); 201*c6e8fb50SDeepak Kodihalli static const Json empty{}; 202*c6e8fb50SDeepak Kodihalli for (const auto& effecter : effecters) 203*c6e8fb50SDeepak Kodihalli { 204*c6e8fb50SDeepak Kodihalli auto set = effecter.value("set", empty); 205*c6e8fb50SDeepak Kodihalli auto statesSize = set.value("size", 0); 206*c6e8fb50SDeepak Kodihalli if (!statesSize) 207*c6e8fb50SDeepak Kodihalli { 208*c6e8fb50SDeepak Kodihalli log<level::ERR>( 209*c6e8fb50SDeepak Kodihalli "Malformed PDR JSON - no state set info", 210*c6e8fb50SDeepak Kodihalli entry("TYPE=%d", PLDM_STATE_EFFECTER_PDR)); 211*c6e8fb50SDeepak Kodihalli elog<InternalFailure>(); 212*c6e8fb50SDeepak Kodihalli } 213*c6e8fb50SDeepak Kodihalli pdrSize += sizeof(state_effecter_possible_states) - 214*c6e8fb50SDeepak Kodihalli sizeof(bitfield8_t) + 215*c6e8fb50SDeepak Kodihalli (sizeof(bitfield8_t) * statesSize); 216*c6e8fb50SDeepak Kodihalli } 217*c6e8fb50SDeepak Kodihalli pdrSize += sizeof(pldm_state_effecter_pdr) - sizeof(uint8_t); 218*c6e8fb50SDeepak Kodihalli 219*c6e8fb50SDeepak Kodihalli Entry pdrEntry{}; 220*c6e8fb50SDeepak Kodihalli pdrEntry.resize(pdrSize); 221*c6e8fb50SDeepak Kodihalli 222*c6e8fb50SDeepak Kodihalli pldm_state_effecter_pdr* pdr = 223*c6e8fb50SDeepak Kodihalli reinterpret_cast<pldm_state_effecter_pdr*>( 224*c6e8fb50SDeepak Kodihalli pdrEntry.data()); 225*c6e8fb50SDeepak Kodihalli pdr->hdr.record_handle = repo.getNextRecordHandle(); 226*c6e8fb50SDeepak Kodihalli pdr->hdr.version = 1; 227*c6e8fb50SDeepak Kodihalli pdr->hdr.type = PLDM_STATE_EFFECTER_PDR; 228*c6e8fb50SDeepak Kodihalli pdr->hdr.record_change_num = 0; 229*c6e8fb50SDeepak Kodihalli pdr->hdr.length = pdrSize - sizeof(pldm_pdr_hdr); 230*c6e8fb50SDeepak Kodihalli 231*c6e8fb50SDeepak Kodihalli pdr->terminus_handle = 0; 232*c6e8fb50SDeepak Kodihalli pdr->effecter_id = effecter::nextId(); 233*c6e8fb50SDeepak Kodihalli pdr->entity_type = e.value("type", 0); 234*c6e8fb50SDeepak Kodihalli pdr->entity_instance = e.value("instance", 0); 235*c6e8fb50SDeepak Kodihalli pdr->container_id = e.value("container", 0); 236*c6e8fb50SDeepak Kodihalli pdr->effecter_semantic_id = 0; 237*c6e8fb50SDeepak Kodihalli pdr->effecter_init = PLDM_NO_INIT; 238*c6e8fb50SDeepak Kodihalli pdr->has_description_pdr = false; 239*c6e8fb50SDeepak Kodihalli pdr->composite_effecter_count = effecters.size(); 240*c6e8fb50SDeepak Kodihalli 241*c6e8fb50SDeepak Kodihalli uint8_t* start = pdrEntry.data() + 242*c6e8fb50SDeepak Kodihalli sizeof(pldm_state_effecter_pdr) - 243*c6e8fb50SDeepak Kodihalli sizeof(uint8_t); 244*c6e8fb50SDeepak Kodihalli for (const auto& effecter : effecters) 245*c6e8fb50SDeepak Kodihalli { 246*c6e8fb50SDeepak Kodihalli auto set = effecter.value("set", empty); 247*c6e8fb50SDeepak Kodihalli state_effecter_possible_states* possibleStates = 248*c6e8fb50SDeepak Kodihalli reinterpret_cast<state_effecter_possible_states*>( 249*c6e8fb50SDeepak Kodihalli start); 250*c6e8fb50SDeepak Kodihalli possibleStates->state_set_id = set.value("id", 0); 251*c6e8fb50SDeepak Kodihalli possibleStates->possible_states_size = 252*c6e8fb50SDeepak Kodihalli set.value("size", 0); 253*c6e8fb50SDeepak Kodihalli 254*c6e8fb50SDeepak Kodihalli start += sizeof(possibleStates->state_set_id) + 255*c6e8fb50SDeepak Kodihalli sizeof(possibleStates->possible_states_size); 256*c6e8fb50SDeepak Kodihalli static const std::vector<uint8_t> emptyStates{}; 257*c6e8fb50SDeepak Kodihalli auto states = set.value("states", emptyStates); 258*c6e8fb50SDeepak Kodihalli for (const auto& state : states) 259*c6e8fb50SDeepak Kodihalli { 260*c6e8fb50SDeepak Kodihalli auto index = state / 8; 261*c6e8fb50SDeepak Kodihalli auto bit = state - (index * 8); 262*c6e8fb50SDeepak Kodihalli bitfield8_t* bf = 263*c6e8fb50SDeepak Kodihalli reinterpret_cast<bitfield8_t*>(start + index); 264*c6e8fb50SDeepak Kodihalli bf->byte |= 1 << bit; 265*c6e8fb50SDeepak Kodihalli } 266*c6e8fb50SDeepak Kodihalli start += possibleStates->possible_states_size; 267*c6e8fb50SDeepak Kodihalli } 268*c6e8fb50SDeepak Kodihalli repo.add(std::move(pdrEntry)); 269*c6e8fb50SDeepak Kodihalli } 270*c6e8fb50SDeepak Kodihalli }}}; 271*c6e8fb50SDeepak Kodihalli 272*c6e8fb50SDeepak Kodihalli auto eraseLen = strlen(".json"); 273*c6e8fb50SDeepak Kodihalli Type pdrType{}; 274*c6e8fb50SDeepak Kodihalli for (const auto& dirEntry : fs::directory_iterator(dir)) 275*c6e8fb50SDeepak Kodihalli { 276*c6e8fb50SDeepak Kodihalli try 277*c6e8fb50SDeepak Kodihalli { 278*c6e8fb50SDeepak Kodihalli auto json = readJson(dirEntry.path().string()); 279*c6e8fb50SDeepak Kodihalli if (!json.empty()) 280*c6e8fb50SDeepak Kodihalli { 281*c6e8fb50SDeepak Kodihalli auto fileName = dirEntry.path().filename().string(); 282*c6e8fb50SDeepak Kodihalli fileName.erase(fileName.end() - eraseLen); 283*c6e8fb50SDeepak Kodihalli pdrType = stoi(fileName); 284*c6e8fb50SDeepak Kodihalli generators.at(pdrType)(json, repo); 285*c6e8fb50SDeepak Kodihalli } 286*c6e8fb50SDeepak Kodihalli } 287*c6e8fb50SDeepak Kodihalli catch (const InternalFailure& e) 288*c6e8fb50SDeepak Kodihalli { 289*c6e8fb50SDeepak Kodihalli } 290*c6e8fb50SDeepak Kodihalli catch (const std::exception& e) 291*c6e8fb50SDeepak Kodihalli { 292*c6e8fb50SDeepak Kodihalli log<level::ERR>("Failed parsing PDR JSON file", 293*c6e8fb50SDeepak Kodihalli entry("TYPE=%d", pdrType), 294*c6e8fb50SDeepak Kodihalli entry("ERROR=%s", e.what())); 295*c6e8fb50SDeepak Kodihalli report<InternalFailure>(); 296*c6e8fb50SDeepak Kodihalli } 297*c6e8fb50SDeepak Kodihalli } 298*c6e8fb50SDeepak Kodihalli } 299*c6e8fb50SDeepak Kodihalli 300*c6e8fb50SDeepak Kodihalli } // namespace internal 301*c6e8fb50SDeepak Kodihalli 302*c6e8fb50SDeepak Kodihalli /** @brief Build (if not built already) and retrieve PDR 303*c6e8fb50SDeepak Kodihalli * 304*c6e8fb50SDeepak Kodihalli * @param[in] dir - directory housing platform specific PDR JSON files 305*c6e8fb50SDeepak Kodihalli * 306*c6e8fb50SDeepak Kodihalli * @return Repo& - Reference to instance of pdr::Repo 307*c6e8fb50SDeepak Kodihalli */ 308*c6e8fb50SDeepak Kodihalli Repo& get(const std::string& dir); 309*c6e8fb50SDeepak Kodihalli 310*c6e8fb50SDeepak Kodihalli } // namespace pdr 311*c6e8fb50SDeepak Kodihalli } // namespace responder 312*c6e8fb50SDeepak Kodihalli } // namespace pldm 313