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