blob: de0a60d4ea601165d5aee5bd281309d113985c00 [file] [log] [blame]
Zane Shelleya9b44342021-08-08 17:15:52 -05001#include <analyzer/ras-data/ras-data-parser.hpp>
2#include <util/data_file.hpp>
3#include <util/trace.hpp>
4
5#include <filesystem>
6#include <fstream>
Zane Shelley02d59af2023-02-07 17:52:34 -06007#include <stdexcept>
Zane Shelleya9b44342021-08-08 17:15:52 -05008#include <string>
9
10namespace fs = std::filesystem;
11
12namespace analyzer
13{
Zane Shelleya9b44342021-08-08 17:15:52 -050014//------------------------------------------------------------------------------
15
16std::shared_ptr<Resolution>
Zane Shelley7698b302021-08-09 16:00:03 -050017 RasDataParser::getResolution(const libhei::Signature& i_signature)
Zane Shelleya9b44342021-08-08 17:15:52 -050018{
Zane Shelley2fbd2672022-02-03 13:56:35 -060019 nlohmann::json data;
20
21 try
22 {
23 data = iv_dataFiles.at(i_signature.getChip().getType());
24 }
25 catch (const std::out_of_range& e)
26 {
27 trace::err("No RAS data defined for chip type: 0x%08x",
28 i_signature.getChip().getType());
29 throw; // caught later downstream
30 }
Zane Shelley7698b302021-08-09 16:00:03 -050031
32 const auto action = parseSignature(data, i_signature);
33
Zane Shelley2fbd2672022-02-03 13:56:35 -060034 std::shared_ptr<Resolution> resolution;
35
36 try
37 {
38 resolution = parseAction(data, action);
39 }
40 catch (...)
41 {
42 trace::err("Unable to get resolution for action: %s", action.c_str());
43 throw; // caught later downstream
44 }
45
46 return resolution;
Zane Shelleya9b44342021-08-08 17:15:52 -050047}
48
49//------------------------------------------------------------------------------
50
Caleb Palmer1a4f0e72022-11-07 15:08:01 -060051bool __checkActionForFlag(const std::string& i_action,
52 const std::string& i_flag,
53 const nlohmann::json& i_data)
54{
55 bool o_isFlagSet = false;
56
57 // Loop through the array of actions.
58 for (const auto& a : i_data.at("actions").at(i_action))
59 {
60 // Get the action type
61 auto type = a.at("type").get<std::string>();
62
63 // If the action is another action, recursively call this function
64 if ("action" == type)
65 {
Patrick Williams27dd6362023-05-10 07:51:20 -050066 auto name = a.at("name").get<std::string>();
Caleb Palmer1a4f0e72022-11-07 15:08:01 -060067 o_isFlagSet = __checkActionForFlag(name, i_flag, i_data);
68 if (o_isFlagSet)
69 {
70 break;
71 }
72 }
73 // If the action is a flag, check if it's the one
74 else if ("flag" == type)
75 {
76 auto name = a.at("name").get<std::string>();
77 if (name == i_flag)
78 {
79 o_isFlagSet = true;
80 break;
81 }
82 }
83 }
84
85 return o_isFlagSet;
86}
87
88//------------------------------------------------------------------------------
89
Caleb Palmerf1184392022-10-07 15:17:22 -050090bool RasDataParser::isFlagSet(const libhei::Signature& i_signature,
Caleb Palmer1a4f0e72022-11-07 15:08:01 -060091 const RasDataFlags i_flag) const
Caleb Palmerf1184392022-10-07 15:17:22 -050092{
93 bool o_isFlagSet = false;
94
95 // List of all flag enums mapping to their corresponding string
96 std::map<RasDataFlags, std::string> flagMap = {
97 {SUE_SOURCE, "sue_source"},
98 {SUE_SEEN, "sue_seen"},
99 {CS_POSSIBLE, "cs_possible"},
100 {RECOVERED_ERROR, "recovered_error"},
101 {INFORMATIONAL_ONLY, "informational_only"},
102 {MNFG_INFORMATIONAL_ONLY, "mnfg_informational_only"},
103 {MASK_BUT_DONT_CLEAR, "mask_but_dont_clear"},
104 {CRC_RELATED_ERR, "crc_related_err"},
105 {CRC_ROOT_CAUSE, "crc_root_cause"},
106 {ODP_DATA_CORRUPT_SIDE_EFFECT, "odp_data_corrupt_side_effect"},
107 {ODP_DATA_CORRUPT_ROOT_CAUSE, "odp_data_corrupt_root_cause"},
Caleb Palmer51f82022023-02-22 16:09:09 -0600108 {ATTN_FROM_OCMB, "attn_from_ocmb"},
Caleb Palmerf1184392022-10-07 15:17:22 -0500109 };
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600110 std::string strFlag = flagMap[i_flag];
Caleb Palmerf1184392022-10-07 15:17:22 -0500111
112 // If the input flag does not exist in the map, that's a code bug.
113 assert(0 != flagMap.count(i_flag));
114
115 nlohmann::json data;
116 try
117 {
118 data = iv_dataFiles.at(i_signature.getChip().getType());
119 }
120 catch (const std::out_of_range& e)
121 {
122 trace::err("No RAS data defined for chip type: 0x%08x",
123 i_signature.getChip().getType());
124 throw; // caught later downstream
125 }
126
127 // Get the signature keys. All are hex (lower case) with no prefix.
128 char buf[5];
129 sprintf(buf, "%04x", i_signature.getId());
130 std::string id{buf};
131
132 sprintf(buf, "%02x", i_signature.getBit());
133 std::string bit{buf};
134
135 // Get the list of flags in string format from the data.
Zane Shelley02d59af2023-02-07 17:52:34 -0600136 try
Caleb Palmerf1184392022-10-07 15:17:22 -0500137 {
138 auto flags = data.at("signatures")
139 .at(id)
140 .at(bit)
141 .at("flags")
142 .get<std::vector<std::string>>();
143
144 // Check if the input flag exists
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600145 if (flags.end() != std::find(flags.begin(), flags.end(), strFlag))
Caleb Palmerf1184392022-10-07 15:17:22 -0500146 {
147 o_isFlagSet = true;
148 }
149 }
Zane Shelley5836f4a2023-02-09 14:28:08 -0600150 catch (const nlohmann::json::out_of_range& e)
Zane Shelley02d59af2023-02-07 17:52:34 -0600151 {
152 // Do nothing. Assume there is no flag defined. If for some reason
153 // the `id` or `bit` were not defined, that will be cause below when the
154 // signture is parsed.
155 }
Caleb Palmerf1184392022-10-07 15:17:22 -0500156
157 // If the flag hasn't been found, check if it was defined as part of the
158 // action for this input signature.
159 if (!o_isFlagSet)
160 {
161 const auto action = parseSignature(data, i_signature);
Zane Shelley02d59af2023-02-07 17:52:34 -0600162 try
163 {
164 __checkActionForFlag(action, strFlag, data);
165 }
Zane Shelley5836f4a2023-02-09 14:28:08 -0600166 catch (const nlohmann::json::out_of_range& e)
Zane Shelley02d59af2023-02-07 17:52:34 -0600167 {
168 // Again, do nothing. Assume there is no flag defined. If for some
169 // reason the action is not defined, that will be handled later when
170 // attempting to get the resolution.
171 }
Caleb Palmerf1184392022-10-07 15:17:22 -0500172 }
173
174 return o_isFlagSet;
175}
176
177//------------------------------------------------------------------------------
178
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600179unsigned int
180 RasDataParser::getVersion(const libhei::Signature& i_signature) const
181{
182 unsigned int o_version = 0;
183
184 nlohmann::json data;
185 try
186 {
187 data = iv_dataFiles.at(i_signature.getChip().getType());
188 }
189 catch (const std::out_of_range& e)
190 {
191 trace::err("No RAS data defined for chip type: 0x%08x",
192 i_signature.getChip().getType());
193 throw; // caught later downstream
194 }
195
196 o_version = data.at("version").get<unsigned int>();
197
198 return o_version;
199}
200
201//------------------------------------------------------------------------------
202
Zane Shelleya9b44342021-08-08 17:15:52 -0500203void RasDataParser::initDataFiles()
204{
205 iv_dataFiles.clear(); // initially empty
206
207 // Get the RAS data schema files from the package `schema` subdirectory.
208 fs::path schemaDir{PACKAGE_DIR "schema"};
Zane Shelleyee54c992021-08-08 17:46:48 -0500209 auto schemaRegex = R"(ras-data-schema-v[0-9]{2}\.json)";
210 std::vector<fs::path> schemaPaths;
211 util::findFiles(schemaDir, schemaRegex, schemaPaths);
Zane Shelleya9b44342021-08-08 17:15:52 -0500212
Zane Shelleyee54c992021-08-08 17:46:48 -0500213 // Parse each of the schema files.
214 std::map<unsigned int, nlohmann::json> schemaFiles;
215 for (const auto& path : schemaPaths)
216 {
217 // Trace each data file for debug.
218 trace::inf("File found: path=%s", path.string().c_str());
Zane Shelleya9b44342021-08-08 17:15:52 -0500219
Zane Shelleyee54c992021-08-08 17:46:48 -0500220 // Open the file.
221 std::ifstream file{path};
222 assert(file.good()); // The file must be readable.
Zane Shelleya9b44342021-08-08 17:15:52 -0500223
Zane Shelley2fbd2672022-02-03 13:56:35 -0600224 try
225 {
226 // Parse the JSON.
227 auto schema = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -0500228
Zane Shelley2fbd2672022-02-03 13:56:35 -0600229 // Get the schema version.
230 auto version = schema.at("version").get<unsigned int>();
Zane Shelley93b001c2023-03-24 17:45:04 -0500231 assert(2 <= version); // check support version
Zane Shelleyee54c992021-08-08 17:46:48 -0500232
Zane Shelley2fbd2672022-02-03 13:56:35 -0600233 // Keep track of the schemas.
234 auto ret = schemaFiles.emplace(version, schema);
235 assert(ret.second); // Should not have duplicate entries
236 }
237 catch (...)
238 {
239 trace::err("Failed to parse file: %s", path.string().c_str());
240 throw; // caught later downstream
241 }
Zane Shelleyee54c992021-08-08 17:46:48 -0500242 }
243
244 // Get the RAS data files from the package `data` subdirectory.
Zane Shelleya9b44342021-08-08 17:15:52 -0500245 fs::path dataDir{PACKAGE_DIR "ras-data"};
246 std::vector<fs::path> dataPaths;
247 util::findFiles(dataDir, R"(.*\.json)", dataPaths);
248
249 // Parse each of the data files.
250 for (const auto& path : dataPaths)
251 {
252 // Trace each data file for debug.
253 trace::inf("File found: path=%s", path.string().c_str());
254
255 // Open the file.
256 std::ifstream file{path};
257 assert(file.good()); // The file must be readable.
258
Zane Shelley2fbd2672022-02-03 13:56:35 -0600259 try
260 {
261 // Parse the JSON.
262 const auto data = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -0500263
Zane Shelley2fbd2672022-02-03 13:56:35 -0600264 // Get the data version.
265 auto version = data.at("version").get<unsigned int>();
Zane Shelley93b001c2023-03-24 17:45:04 -0500266 assert(2 <= version); // check support version
Zane Shelleyee54c992021-08-08 17:46:48 -0500267
Zane Shelley2fbd2672022-02-03 13:56:35 -0600268 // Get the schema for this file.
269 auto schema = schemaFiles.at(version);
Zane Shelleyee54c992021-08-08 17:46:48 -0500270
Zane Shelley2fbd2672022-02-03 13:56:35 -0600271 // Validate the data against the schema.
272 assert(util::validateJson(schema, data));
Zane Shelleya9b44342021-08-08 17:15:52 -0500273
Zane Shelley2fbd2672022-02-03 13:56:35 -0600274 // Get the chip model/EC level from the data. The value is currently
275 // stored as a string representation of the hex value. So it will
276 // have to be converted to an integer.
277 libhei::ChipType_t chipType =
278 std::stoul(data.at("model_ec").get<std::string>(), 0, 16);
Zane Shelleya9b44342021-08-08 17:15:52 -0500279
Zane Shelley2fbd2672022-02-03 13:56:35 -0600280 // So far, so good. Add the entry.
281 auto ret = iv_dataFiles.emplace(chipType, data);
282 assert(ret.second); // Should not have duplicate entries
283 }
284 catch (...)
285 {
286 trace::err("Failed to parse file: %s", path.string().c_str());
287 throw; // caught later downstream
288 }
Zane Shelleya9b44342021-08-08 17:15:52 -0500289 }
290}
291
292//------------------------------------------------------------------------------
293
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600294std::string
295 RasDataParser::parseSignature(const nlohmann::json& i_data,
296 const libhei::Signature& i_signature) const
Zane Shelley7698b302021-08-09 16:00:03 -0500297{
298 // Get the signature keys. All are hex (lower case) with no prefix.
299 char buf[5];
300 sprintf(buf, "%04x", i_signature.getId());
301 std::string id{buf};
302
303 sprintf(buf, "%02x", i_signature.getBit());
304 std::string bit{buf};
305
306 sprintf(buf, "%02x", i_signature.getInstance());
307 std::string inst{buf};
308
Zane Shelley2fbd2672022-02-03 13:56:35 -0600309 std::string action;
310
311 try
312 {
313 action =
314 i_data.at("signatures").at(id).at(bit).at(inst).get<std::string>();
315 }
Zane Shelley5836f4a2023-02-09 14:28:08 -0600316 catch (const nlohmann::json::out_of_range& e)
Zane Shelley2fbd2672022-02-03 13:56:35 -0600317 {
318 trace::err("No action defined for signature: %s %s %s", id.c_str(),
319 bit.c_str(), inst.c_str());
Caleb Palmere36866c2022-10-31 15:14:29 -0500320
Zane Shelley93b001c2023-03-24 17:45:04 -0500321 // Default to 'level2_M_th1' if no signature is found.
322 action = "level2_M_th1";
Zane Shelley2fbd2672022-02-03 13:56:35 -0600323 }
324
Zane Shelley7698b302021-08-09 16:00:03 -0500325 // Return the action.
Zane Shelley2fbd2672022-02-03 13:56:35 -0600326 return action;
Zane Shelley7698b302021-08-09 16:00:03 -0500327}
328
329//------------------------------------------------------------------------------
330
Zane Shelley5d63cef2021-09-17 18:10:17 -0500331std::tuple<callout::BusType, std::string>
332 RasDataParser::parseBus(const nlohmann::json& i_data,
333 const std::string& i_name)
334{
335 auto bus = i_data.at("buses").at(i_name);
336
337 // clang-format off
338 static const std::map<std::string, callout::BusType> m =
339 {
340 {"SMP_BUS", callout::BusType::SMP_BUS},
341 {"OMI_BUS", callout::BusType::OMI_BUS},
342 };
343 // clang-format on
344
345 auto busType = m.at(bus.at("type").get<std::string>());
346
347 std::string unitPath{}; // default empty if unit does not exist
348 if (bus.contains("unit"))
349 {
Zane Shelley3e8f2952022-01-18 13:29:30 -0600350 auto unit = bus.at("unit").get<std::string>();
Patrick Williams27dd6362023-05-10 07:51:20 -0500351 unitPath = i_data.at("units").at(unit).get<std::string>();
Zane Shelley5d63cef2021-09-17 18:10:17 -0500352 }
353
354 return std::make_tuple(busType, unitPath);
355}
356
357//------------------------------------------------------------------------------
358
Zane Shelley7698b302021-08-09 16:00:03 -0500359std::shared_ptr<Resolution>
360 RasDataParser::parseAction(const nlohmann::json& i_data,
361 const std::string& i_action)
362{
363 auto o_list = std::make_shared<ResolutionList>();
364
365 // This function will be called recursively and we want to prevent cyclic
366 // recursion.
367 static std::vector<std::string> stack;
368 assert(stack.end() == std::find(stack.begin(), stack.end(), i_action));
369 stack.push_back(i_action);
370
371 // Iterate the action list and apply the changes.
372 for (const auto& a : i_data.at("actions").at(i_action))
373 {
374 auto type = a.at("type").get<std::string>();
375
376 if ("action" == type)
377 {
378 auto name = a.at("name").get<std::string>();
379
380 o_list->push(parseAction(i_data, name));
381 }
382 else if ("callout_self" == type)
383 {
384 auto priority = a.at("priority").get<std::string>();
Patrick Williams27dd6362023-05-10 07:51:20 -0500385 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500386
Zane Shelleye4bfb472021-08-10 12:47:32 -0500387 std::string path{}; // Must be empty to callout the chip.
388
389 o_list->push(std::make_shared<HardwareCalloutResolution>(
390 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500391 }
392 else if ("callout_unit" == type)
393 {
Patrick Williams27dd6362023-05-10 07:51:20 -0500394 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500395 auto priority = a.at("priority").get<std::string>();
Patrick Williams27dd6362023-05-10 07:51:20 -0500396 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500397
Zane Shelleye4bfb472021-08-10 12:47:32 -0500398 auto path = i_data.at("units").at(name).get<std::string>();
399
400 o_list->push(std::make_shared<HardwareCalloutResolution>(
401 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500402 }
403 else if ("callout_connected" == type)
404 {
Patrick Williams27dd6362023-05-10 07:51:20 -0500405 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500406 auto priority = a.at("priority").get<std::string>();
Patrick Williams27dd6362023-05-10 07:51:20 -0500407 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500408
Zane Shelley5d63cef2021-09-17 18:10:17 -0500409 auto busData = parseBus(i_data, name);
410
411 o_list->push(std::make_shared<ConnectedCalloutResolution>(
412 std::get<0>(busData), std::get<1>(busData),
413 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500414 }
415 else if ("callout_bus" == type)
416 {
Patrick Williams27dd6362023-05-10 07:51:20 -0500417 auto name = a.at("name").get<std::string>();
Zane Shelley4757a7b2021-09-20 22:23:38 -0500418 auto priority = a.at("priority").get<std::string>();
Patrick Williams27dd6362023-05-10 07:51:20 -0500419 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500420
Zane Shelley4757a7b2021-09-20 22:23:38 -0500421 auto busData = parseBus(i_data, name);
422
423 o_list->push(std::make_shared<BusCalloutResolution>(
424 std::get<0>(busData), std::get<1>(busData),
425 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500426 }
427 else if ("callout_clock" == type)
428 {
Patrick Williams27dd6362023-05-10 07:51:20 -0500429 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500430 auto priority = a.at("priority").get<std::string>();
Patrick Williams27dd6362023-05-10 07:51:20 -0500431 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500432
Zane Shelley84721d92021-09-08 13:30:27 -0500433 // clang-format off
434 static const std::map<std::string, callout::ClockType> m =
435 {
436 {"OSC_REF_CLOCK_0", callout::ClockType::OSC_REF_CLOCK_0},
437 {"OSC_REF_CLOCK_1", callout::ClockType::OSC_REF_CLOCK_1},
Zane Shelleyd195b712022-01-26 13:26:34 -0600438 {"TOD_CLOCK", callout::ClockType::TOD_CLOCK},
Zane Shelley84721d92021-09-08 13:30:27 -0500439 };
440 // clang-format on
441
442 o_list->push(std::make_shared<ClockCalloutResolution>(
443 m.at(name), getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500444 }
445 else if ("callout_procedure" == type)
446 {
Patrick Williams27dd6362023-05-10 07:51:20 -0500447 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500448 auto priority = a.at("priority").get<std::string>();
449
450 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500451 static const std::map<std::string, callout::Procedure> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500452 {
Zane Shelleyd8b70182022-03-10 10:50:22 -0600453 {"LEVEL2", callout::Procedure::NEXTLVL},
454 {"SUE_SEEN", callout::Procedure::SUE_SEEN},
Zane Shelley7698b302021-08-09 16:00:03 -0500455 };
456 // clang-format on
457
458 o_list->push(std::make_shared<ProcedureCalloutResolution>(
459 m.at(name), getPriority(priority)));
460 }
461 else if ("callout_part" == type)
462 {
Patrick Williams27dd6362023-05-10 07:51:20 -0500463 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500464 auto priority = a.at("priority").get<std::string>();
465
Zane Shelleya4134772022-01-10 17:22:44 -0600466 // clang-format off
467 static const std::map<std::string, callout::PartType> m =
468 {
469 {"PNOR", callout::PartType::PNOR},
470 };
471 // clang-format on
472
473 o_list->push(std::make_shared<PartCalloutResolution>(
474 m.at(name), getPriority(priority)));
Zane Shelley7698b302021-08-09 16:00:03 -0500475 }
476 else if ("plugin" == type)
477 {
478 auto name = a.at("name").get<std::string>();
Zane Shelleye13a9f92021-12-16 21:19:11 -0600479 auto inst = a.at("instance").get<unsigned int>();
Zane Shelley7698b302021-08-09 16:00:03 -0500480
Zane Shelleye13a9f92021-12-16 21:19:11 -0600481 o_list->push(std::make_shared<PluginResolution>(name, inst));
Zane Shelley7698b302021-08-09 16:00:03 -0500482 }
Caleb Palmerf1184392022-10-07 15:17:22 -0500483 else if ("flag" == type)
484 {
485 // No action, flags will be handled with the isFlagSet function
486 }
Zane Shelley7698b302021-08-09 16:00:03 -0500487 else
488 {
489 throw std::logic_error("Unsupported action type: " + type);
490 }
491 }
492
493 // Done with this action pop it off the stack.
494 stack.pop_back();
495
496 return o_list;
497}
498
499//------------------------------------------------------------------------------
500
Zane Shelleyc85716c2021-08-17 10:54:06 -0500501callout::Priority RasDataParser::getPriority(const std::string& i_priority)
Zane Shelley7698b302021-08-09 16:00:03 -0500502{
503 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500504 static const std::map<std::string, callout::Priority> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500505 {
Zane Shelleyc85716c2021-08-17 10:54:06 -0500506 {"HIGH", callout::Priority::HIGH},
507 {"MED", callout::Priority::MED},
508 {"MED_A", callout::Priority::MED_A},
509 {"MED_B", callout::Priority::MED_B},
510 {"MED_C", callout::Priority::MED_C},
511 {"LOW", callout::Priority::LOW},
Zane Shelley7698b302021-08-09 16:00:03 -0500512 };
513 // clang-format on
514
515 return m.at(i_priority);
516}
517
518//------------------------------------------------------------------------------
519
Zane Shelleya9b44342021-08-08 17:15:52 -0500520} // namespace analyzer