1 #include "phal_service_actions.hpp"
2 
3 #include <attributes_info.H>
4 #include <fmt/format.h>
5 #include <libphal.H>
6 
7 #include <phosphor-logging/log.hpp>
8 
9 namespace openpower
10 {
11 namespace pels
12 {
13 namespace phal
14 {
15 using namespace phosphor::logging;
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  */
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         log<level::ERR>(
43             fmt::format("GUARD: Unsupported GardType [{}] was given ",
44                         "to get the hardware isolation entry severity type",
45                         guardType.c_str())
46                 .c_str());
47     }
48     return std::nullopt;
49 }
50 
51 /**
52  * @brief Helper function to create guard records.
53  *
54  * User need to fill the JSON callouts array with below keywords/data
55  * "Entitypath": entity path of the hardware from the PHAL device tree.
56  * "Guardtype": The hardware isolation severity which is defined in
57  *              xyz.openbmc_project.HardwareIsolation.Entry
58  * "Guarded": boolean, true to create gurad records.
59  *
60  * @param[in] jsonCallouts - The array of JSON callouts, or an empty object.
61  * @param[in] path - The BMC error log object path
62  * @param[in] dataIface - The DataInterface object
63  */
64 void createGuardRecords(const nlohmann::json& jsonCallouts,
65                         const std::string& path,
66                         const DataInterfaceBase& dataIface)
67 {
68     if (jsonCallouts.empty())
69     {
70         return;
71     }
72 
73     if (!jsonCallouts.is_array())
74     {
75         log<level::ERR>("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                 log<level::ERR>(
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             for (uint32_t a = 0; a < sizeof(ATTR_PHYS_BIN_PATH_Type); a++)
105             {
106                 ss << " 0x" << std::hex << static_cast<int>(entityPath[a]);
107             }
108             std::string s = ss.str();
109             log<level::INFO>(fmt::format("GUARD :({})", s).c_str());
110 
111             // Get Guard type
112             auto severity = EntrySeverity::Warning;
113             if (!_callout.contains("GuardType"))
114             {
115                 log<level::ERR>(
116                     "GUARD: doesn't have Severity, setting to warning");
117             }
118             else
119             {
120                 auto guardType = _callout.at("GuardType").get<std::string>();
121                 // convert GuardType to severity type.
122                 auto sType = getEntrySeverityType(guardType);
123                 if (sType.has_value())
124                 {
125                     severity = sType.value();
126                 }
127             }
128             // Create guard record
129             auto type = sdbusplus::xyz::openbmc_project::HardwareIsolation::
130                 server::convertForMessage(severity);
131             dataIface.createGuardRecord(entityPath, type, path);
132         }
133         catch (const std::exception& e)
134         {
135             log<level::INFO>(
136                 fmt::format("GUARD: Failed entry creation exception:({})",
137                             e.what())
138                     .c_str());
139         }
140     }
141 }
142 
143 /**
144  * @brief Helper function to create deconfig records.
145  *
146  * User need to fill the JSON callouts array with below keywords/data
147  * "EntityPath": entity path of the hardware from the PHAL device tree.
148  * "Deconfigured": boolean, true to create deconfigure records.
149  *
150  * libphal api is used for creating deconfigure records, which includes
151  * update HWAS_STATE attribute to non functional with PLID information.
152  *
153  * @param[in] jsonCallouts - The array of JSON callouts, or an empty object.
154  * @param[in] plid - PLID value
155  */
156 void createDeconfigRecords(const nlohmann::json& jsonCallouts,
157                            const uint32_t plid)
158 {
159     using namespace openpower::phal::pdbg;
160 
161     if (jsonCallouts.empty())
162     {
163         return;
164     }
165 
166     if (!jsonCallouts.is_array())
167     {
168         log<level::ERR>("Deconfig: Callout JSON isn't an array");
169         return;
170     }
171     for (const auto& _callout : jsonCallouts)
172     {
173         try
174         {
175             // Check Callout data conatains Guarded requests.
176             if (!_callout.contains("Deconfigured"))
177             {
178                 continue;
179             }
180 
181             if (!_callout.at("Deconfigured").get<bool>())
182             {
183                 continue;
184             }
185 
186             if (!_callout.contains("EntityPath"))
187             {
188                 log<level::ERR>(
189                     "Deconfig: Callout data missing EntityPath information");
190                 continue;
191             }
192             using EntityPath = std::vector<uint8_t>;
193             auto entityPath = _callout.at("EntityPath").get<EntityPath>();
194             log<level::INFO>("Deconfig: adding deconfigure record");
195             // convert to libphal required format.
196             ATTR_PHYS_BIN_PATH_Type physBinPath;
197             std::copy(entityPath.begin(), entityPath.end(), physBinPath);
198             // libphal api to deconfigure the target
199             if (!pdbg_targets_init(NULL))
200             {
201                 log<level::ERR>("pdbg_targets_init failed, skipping deconfig "
202                                 "record update");
203                 return;
204             }
205             openpower::phal::pdbg::deconfigureTgt(physBinPath, plid);
206         }
207         catch (const std::exception& e)
208         {
209             log<level::INFO>(
210                 fmt::format(
211                     "Deconfig: Failed to create records, exception:({})",
212                     e.what())
213                     .c_str());
214         }
215     }
216 }
217 
218 void createServiceActions(const nlohmann::json& jsonCallouts,
219                           const std::string& path,
220                           const DataInterfaceBase& dataIface,
221                           const uint32_t plid)
222 {
223     // Create Guard records.
224     createGuardRecords(jsonCallouts, path, dataIface);
225     // Create Deconfigure records.
226     createDeconfigRecords(jsonCallouts, plid);
227 }
228 
229 } // namespace phal
230 } // namespace pels
231 } // namespace openpower
232