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