1 #pragma once
2 
3 #include "pdr.hpp"
4 #include "pdr_utils.hpp"
5 
6 #include <config.h>
7 #include <libpldm/platform.h>
8 
9 #include <phosphor-logging/lg2.hpp>
10 
11 PHOSPHOR_LOG2_USING;
12 
13 namespace pldm
14 {
15 namespace responder
16 {
17 namespace pdr_state_effecter
18 {
19 using Json = nlohmann::json;
20 
21 static const Json empty{};
22 
23 /** @brief Parse PDR JSON file and generate state effecter PDR structure
24  *
25  *  @param[in] json - the JSON Object with the state effecter PDR
26  *  @param[out] handler - the Parser of PLDM command handler
27  *  @param[out] repo - pdr::RepoInterface
28  *
29  */
30 template <class DBusInterface, class Handler>
31 void generateStateEffecterPDR(const DBusInterface& dBusIntf, const Json& json,
32                               Handler& handler, pdr_utils::RepoInterface& repo)
33 {
34     static const std::vector<Json> emptyList{};
35     auto entries = json.value("entries", emptyList);
36     for (const auto& e : entries)
37     {
38         size_t pdrSize = 0;
39         auto effecters = e.value("effecters", emptyList);
40         for (const auto& effecter : effecters)
41         {
42             auto set = effecter.value("set", empty);
43             auto statesSize = set.value("size", 0);
44             if (!statesSize)
45             {
46                 error(
47                     "Malformed PDR JSON return pdrEntry;- no state set info, TYPE={STATE_EFFECTER_PDR}",
48                     "STATE_EFFECTER_PDR",
49                     static_cast<unsigned>(PLDM_STATE_EFFECTER_PDR));
50                 throw InternalFailure();
51             }
52             pdrSize += sizeof(state_effecter_possible_states) -
53                        sizeof(bitfield8_t) + (sizeof(bitfield8_t) * statesSize);
54         }
55         pdrSize += sizeof(pldm_state_effecter_pdr) - sizeof(uint8_t);
56 
57         std::vector<uint8_t> entry{};
58         entry.resize(pdrSize);
59 
60         pldm_state_effecter_pdr* pdr =
61             reinterpret_cast<pldm_state_effecter_pdr*>(entry.data());
62         if (!pdr)
63         {
64             error("Failed to get state effecter PDR.");
65             continue;
66         }
67         pdr->hdr.record_handle = 0;
68         pdr->hdr.version = 1;
69         pdr->hdr.type = PLDM_STATE_EFFECTER_PDR;
70         pdr->hdr.record_change_num = 0;
71         pdr->hdr.length = pdrSize - sizeof(pldm_pdr_hdr);
72 
73         pdr->terminus_handle = TERMINUS_HANDLE;
74         pdr->effecter_id = handler.getNextEffecterId();
75 
76         try
77         {
78             std::string entity_path = e.value("entity_path", "");
79             auto& associatedEntityMap = handler.getAssociateEntityMap();
80             if (entity_path != "" && associatedEntityMap.find(entity_path) !=
81                                          associatedEntityMap.end())
82             {
83                 pdr->entity_type =
84                     associatedEntityMap.at(entity_path).entity_type;
85                 pdr->entity_instance =
86                     associatedEntityMap.at(entity_path).entity_instance_num;
87                 pdr->container_id =
88                     associatedEntityMap.at(entity_path).entity_container_id;
89             }
90             else
91             {
92                 pdr->entity_type = e.value("type", 0);
93                 pdr->entity_instance = e.value("instance", 0);
94                 pdr->container_id = e.value("container", 0);
95 
96                 // do not create the PDR when the FRU or the entity path is not
97                 // present
98                 if (!pdr->entity_type)
99                 {
100                     std::cerr << "The entity path for the FRU is not present."
101                               << std::endl;
102                     continue;
103                 }
104             }
105         }
106         catch (const std::exception& ex)
107         {
108             pdr->entity_type = e.value("type", 0);
109             pdr->entity_instance = e.value("instance", 0);
110             pdr->container_id = e.value("container", 0);
111         }
112 
113         pdr->effecter_semantic_id = 0;
114         pdr->effecter_init = PLDM_NO_INIT;
115         pdr->has_description_pdr = false;
116         pdr->composite_effecter_count = effecters.size();
117 
118         pldm::responder::pdr_utils::DbusMappings dbusMappings{};
119         pldm::responder::pdr_utils::DbusValMaps dbusValMaps{};
120         uint8_t* start =
121             entry.data() + sizeof(pldm_state_effecter_pdr) - sizeof(uint8_t);
122         for (const auto& effecter : effecters)
123         {
124             auto set = effecter.value("set", empty);
125             state_effecter_possible_states* possibleStates =
126                 reinterpret_cast<state_effecter_possible_states*>(start);
127             possibleStates->state_set_id = set.value("id", 0);
128             possibleStates->possible_states_size = set.value("size", 0);
129 
130             start += sizeof(possibleStates->state_set_id) +
131                      sizeof(possibleStates->possible_states_size);
132             static const std::vector<uint8_t> emptyStates{};
133             pldm::responder::pdr_utils::PossibleValues stateValues;
134             auto states = set.value("states", emptyStates);
135             for (const auto& state : states)
136             {
137                 auto index = state / 8;
138                 auto bit = state - (index * 8);
139                 bitfield8_t* bf = reinterpret_cast<bitfield8_t*>(start + index);
140                 bf->byte |= 1 << bit;
141                 stateValues.emplace_back(state);
142             }
143             start += possibleStates->possible_states_size;
144 
145             auto dbusEntry = effecter.value("dbus", empty);
146             auto objectPath = dbusEntry.value("path", "");
147             auto interface = dbusEntry.value("interface", "");
148             auto propertyName = dbusEntry.value("property_name", "");
149             auto propertyType = dbusEntry.value("property_type", "");
150 
151             pldm::responder::pdr_utils::StatestoDbusVal dbusIdToValMap{};
152             pldm::utils::DBusMapping dbusMapping{};
153             try
154             {
155                 auto service =
156                     dBusIntf.getService(objectPath.c_str(), interface.c_str());
157 
158                 dbusMapping = pldm::utils::DBusMapping{
159                     objectPath, interface, propertyName, propertyType};
160                 dbusIdToValMap = pldm::responder::pdr_utils::populateMapping(
161                     propertyType, dbusEntry["property_values"], stateValues);
162             }
163             catch (const std::exception& e)
164             {
165                 error(
166                     "D-Bus object path does not exist, effecter ID: {EFFECTER_ID}",
167                     "EFFECTER_ID", static_cast<uint16_t>(pdr->effecter_id));
168             }
169 
170             dbusMappings.emplace_back(std::move(dbusMapping));
171             dbusValMaps.emplace_back(std::move(dbusIdToValMap));
172         }
173         handler.addDbusObjMaps(
174             pdr->effecter_id,
175             std::make_tuple(std::move(dbusMappings), std::move(dbusValMaps)));
176         pldm::responder::pdr_utils::PdrEntry pdrEntry{};
177         pdrEntry.data = entry.data();
178         pdrEntry.size = pdrSize;
179         repo.addRecord(pdrEntry);
180     }
181 }
182 
183 } // namespace pdr_state_effecter
184 } // namespace responder
185 } // namespace pldm
186