1 #include "phal_service_actions.hpp"
2 
3 #include <attributes_info.H>
4 #include <libphal.H>
5 
6 #include <libguard/guard_interface.hpp>
7 #include <libguard/include/guard_record.hpp>
8 #include <phosphor-logging/lg2.hpp>
9 
10 #include <format>
11 
12 using GardType = openpower::guard::GardType;
13 
14 namespace openpower
15 {
16 namespace pels
17 {
18 namespace phal
19 {
20 
21 /**
22  * @brief Helper function to get gard type based on
23  *        the given GardType string
24  *
25  * @param[in] guardTypeStr guard type enum value as a string
26  *
27  * @return GardType on success
28  *         Empty optional on failure
29  */
30 std::optional<GardType> getGardType(const std::string& guardTypeStr)
31 {
32     const std::unordered_map<std::string, GardType> gardTypeMap = {
33         {"GARD_Fatal", GardType::GARD_Fatal},
34         {"GARD_User_Manual", GardType::GARD_User_Manual},
35         {"GARD_Predictive", GardType::GARD_Predictive},
36         {"GARD_Spare", GardType::GARD_Spare},
37         {"GARD_Unrecoverable", GardType::GARD_Unrecoverable},
38     };
39 
40     auto it = gardTypeMap.find(guardTypeStr);
41     if (it != gardTypeMap.end())
42     {
43         return it->second;
44     }
45     else
46     {
47         lg2::error("Invalid GardType ({GUARDTYPE})", "GUARDTYPE", guardTypeStr);
48     }
49     return std::nullopt;
50 }
51 
52 /**
53  * @brief Helper function to create guard records.
54  *
55  * User need to fill the JSON callouts array with below keywords/data
56  * "Entitypath": entity path of the hardware from the PHAL device tree.
57  * "Guardtype": The hardware isolation severity which is defined in
58  *              xyz.openbmc_project.HardwareIsolation.Entry
59  * "Guarded": boolean, true to create gurad records.
60  *
61  * @param[in] jsonCallouts - The array of JSON callouts, or an empty object.
62  * @param[in] plid - The PEL ID to be associated with the guard
63  * @param[in] dataIface - The DataInterface object
64  */
65 void createGuardRecords(const nlohmann::json& jsonCallouts, uint32_t plid,
66                         const DataInterfaceBase& dataIface)
67 {
68     if (jsonCallouts.empty())
69     {
70         return;
71     }
72 
73     if (!jsonCallouts.is_array())
74     {
75         lg2::error("GUARD: Callout JSON isn't an array");
76         return;
77     }
78     for (const auto& _callout : jsonCallouts)
79     {
80         try
81         {
82             // Check Callout data conatains Guarded requests.
83             if (!_callout.contains("Guarded"))
84             {
85                 continue;
86             }
87             if (!_callout.at("Guarded").get<bool>())
88             {
89                 continue;
90             }
91             // Get Entity path required for guard D-bus method
92             // "CreateWithEntityPath"
93             if (!_callout.contains("EntityPath"))
94             {
95                 lg2::error(
96                     "GUARD: Callout data, missing EntityPath information");
97                 continue;
98             }
99             using EntityPath = std::vector<uint8_t>;
100 
101             auto entityPath = _callout.at("EntityPath").get<EntityPath>();
102 
103             std::stringstream ss;
104             std::ranges::for_each(entityPath, [&ss](const auto& ele) {
105                 ss << std::format("{:02x} ", ele);
106             });
107 
108             std::string s = ss.str();
109             lg2::info("GUARD: ({GUARD_TARGET})", "GUARD_TARGET", s);
110 
111             // Get Guard type
112             std::string guardTypeStr = "GARD_Predictive";
113             if (!_callout.contains("GuardType"))
114             {
115                 lg2::error(
116                     "GUARD: doesn't have Severity, setting to GARD_Predictive");
117             }
118             else
119             {
120                 guardTypeStr = _callout.at("GuardType").get<std::string>();
121             }
122 
123             GardType eGuardType =
124                 getGardType(guardTypeStr).value_or(GardType::GARD_Predictive);
125             dataIface.createGuardRecord(entityPath, eGuardType, plid);
126         }
127         catch (const std::exception& e)
128         {
129             lg2::info("GUARD: Failed entry creation exception:({EXCEPTION})",
130                       "EXCEPTION", e);
131         }
132     }
133 }
134 
135 /**
136  * @brief Helper function to create deconfig records.
137  *
138  * User need to fill the JSON callouts array with below keywords/data
139  * "EntityPath": entity path of the hardware from the PHAL device tree.
140  * "Deconfigured": boolean, true to create deconfigure records.
141  *
142  * libphal api is used for creating deconfigure records, which includes
143  * update HWAS_STATE attribute to non functional with PLID information.
144  *
145  * @param[in] jsonCallouts - The array of JSON callouts, or an empty object.
146  * @param[in] plid - PLID value
147  */
148 void createDeconfigRecords(const nlohmann::json& jsonCallouts, uint32_t plid)
149 {
150     using namespace openpower::phal::pdbg;
151 
152     if (jsonCallouts.empty())
153     {
154         return;
155     }
156 
157     if (!jsonCallouts.is_array())
158     {
159         lg2::error("Deconfig: Callout JSON isn't an array");
160         return;
161     }
162     for (const auto& _callout : jsonCallouts)
163     {
164         try
165         {
166             // Check Callout data conatains Guarded requests.
167             if (!_callout.contains("Deconfigured"))
168             {
169                 continue;
170             }
171 
172             if (!_callout.at("Deconfigured").get<bool>())
173             {
174                 continue;
175             }
176 
177             if (!_callout.contains("EntityPath"))
178             {
179                 lg2::error(
180                     "Deconfig: Callout data missing EntityPath information");
181                 continue;
182             }
183             using EntityPath = std::vector<uint8_t>;
184             auto entityPath = _callout.at("EntityPath").get<EntityPath>();
185             lg2::info("Deconfig: adding deconfigure record");
186             // convert to libphal required format.
187             ATTR_PHYS_BIN_PATH_Type physBinPath;
188             std::copy(entityPath.begin(), entityPath.end(), physBinPath);
189             // libphal api to deconfigure the target
190             openpower::phal::pdbg::deconfigureTgt(physBinPath, plid);
191         }
192         catch (const std::exception& e)
193         {
194             lg2::info(
195                 "Deconfig: Failed to create records, exception:({EXCEPTION})",
196                 "EXCEPTION", e);
197         }
198     }
199 }
200 
201 void createServiceActions(const nlohmann::json& jsonCallouts,
202                           const DataInterfaceBase& dataIface, uint32_t plid)
203 {
204     // Create Guard records.
205     createGuardRecords(jsonCallouts, plid, dataIface);
206     // Create Deconfigure records.
207     createDeconfigRecords(jsonCallouts, plid);
208 }
209 
210 } // namespace phal
211 } // namespace pels
212 } // namespace openpower
213