blob: 8b7e48271f529fe5a63e2e88c36cb98233566455 [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 {
66 auto name = a.at("name").get<std::string>();
67 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"},
108 };
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600109 std::string strFlag = flagMap[i_flag];
Caleb Palmerf1184392022-10-07 15:17:22 -0500110
111 // If the input flag does not exist in the map, that's a code bug.
112 assert(0 != flagMap.count(i_flag));
113
114 nlohmann::json data;
115 try
116 {
117 data = iv_dataFiles.at(i_signature.getChip().getType());
118 }
119 catch (const std::out_of_range& e)
120 {
121 trace::err("No RAS data defined for chip type: 0x%08x",
122 i_signature.getChip().getType());
123 throw; // caught later downstream
124 }
125
126 // Get the signature keys. All are hex (lower case) with no prefix.
127 char buf[5];
128 sprintf(buf, "%04x", i_signature.getId());
129 std::string id{buf};
130
131 sprintf(buf, "%02x", i_signature.getBit());
132 std::string bit{buf};
133
134 // Get the list of flags in string format from the data.
Zane Shelley02d59af2023-02-07 17:52:34 -0600135 try
Caleb Palmerf1184392022-10-07 15:17:22 -0500136 {
137 auto flags = data.at("signatures")
138 .at(id)
139 .at(bit)
140 .at("flags")
141 .get<std::vector<std::string>>();
142
143 // Check if the input flag exists
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600144 if (flags.end() != std::find(flags.begin(), flags.end(), strFlag))
Caleb Palmerf1184392022-10-07 15:17:22 -0500145 {
146 o_isFlagSet = true;
147 }
148 }
Zane Shelley5836f4a2023-02-09 14:28:08 -0600149 catch (const nlohmann::json::out_of_range& e)
Zane Shelley02d59af2023-02-07 17:52:34 -0600150 {
151 // Do nothing. Assume there is no flag defined. If for some reason
152 // the `id` or `bit` were not defined, that will be cause below when the
153 // signture is parsed.
154 }
Caleb Palmerf1184392022-10-07 15:17:22 -0500155
156 // If the flag hasn't been found, check if it was defined as part of the
157 // action for this input signature.
158 if (!o_isFlagSet)
159 {
160 const auto action = parseSignature(data, i_signature);
Zane Shelley02d59af2023-02-07 17:52:34 -0600161 try
162 {
163 __checkActionForFlag(action, strFlag, data);
164 }
Zane Shelley5836f4a2023-02-09 14:28:08 -0600165 catch (const nlohmann::json::out_of_range& e)
Zane Shelley02d59af2023-02-07 17:52:34 -0600166 {
167 // Again, do nothing. Assume there is no flag defined. If for some
168 // reason the action is not defined, that will be handled later when
169 // attempting to get the resolution.
170 }
Caleb Palmerf1184392022-10-07 15:17:22 -0500171 }
172
173 return o_isFlagSet;
174}
175
176//------------------------------------------------------------------------------
177
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600178unsigned int
179 RasDataParser::getVersion(const libhei::Signature& i_signature) const
180{
181 unsigned int o_version = 0;
182
183 nlohmann::json data;
184 try
185 {
186 data = iv_dataFiles.at(i_signature.getChip().getType());
187 }
188 catch (const std::out_of_range& e)
189 {
190 trace::err("No RAS data defined for chip type: 0x%08x",
191 i_signature.getChip().getType());
192 throw; // caught later downstream
193 }
194
195 o_version = data.at("version").get<unsigned int>();
196
197 return o_version;
198}
199
200//------------------------------------------------------------------------------
201
Zane Shelleya9b44342021-08-08 17:15:52 -0500202void RasDataParser::initDataFiles()
203{
204 iv_dataFiles.clear(); // initially empty
205
206 // Get the RAS data schema files from the package `schema` subdirectory.
207 fs::path schemaDir{PACKAGE_DIR "schema"};
Zane Shelleyee54c992021-08-08 17:46:48 -0500208 auto schemaRegex = R"(ras-data-schema-v[0-9]{2}\.json)";
209 std::vector<fs::path> schemaPaths;
210 util::findFiles(schemaDir, schemaRegex, schemaPaths);
Zane Shelleya9b44342021-08-08 17:15:52 -0500211
Zane Shelleyee54c992021-08-08 17:46:48 -0500212 // Parse each of the schema files.
213 std::map<unsigned int, nlohmann::json> schemaFiles;
214 for (const auto& path : schemaPaths)
215 {
216 // Trace each data file for debug.
217 trace::inf("File found: path=%s", path.string().c_str());
Zane Shelleya9b44342021-08-08 17:15:52 -0500218
Zane Shelleyee54c992021-08-08 17:46:48 -0500219 // Open the file.
220 std::ifstream file{path};
221 assert(file.good()); // The file must be readable.
Zane Shelleya9b44342021-08-08 17:15:52 -0500222
Zane Shelley2fbd2672022-02-03 13:56:35 -0600223 try
224 {
225 // Parse the JSON.
226 auto schema = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -0500227
Zane Shelley2fbd2672022-02-03 13:56:35 -0600228 // Get the schema version.
229 auto version = schema.at("version").get<unsigned int>();
Zane Shelleyee54c992021-08-08 17:46:48 -0500230
Zane Shelley2fbd2672022-02-03 13:56:35 -0600231 // Keep track of the schemas.
232 auto ret = schemaFiles.emplace(version, schema);
233 assert(ret.second); // Should not have duplicate entries
234 }
235 catch (...)
236 {
237 trace::err("Failed to parse file: %s", path.string().c_str());
238 throw; // caught later downstream
239 }
Zane Shelleyee54c992021-08-08 17:46:48 -0500240 }
241
242 // Get the RAS data files from the package `data` subdirectory.
Zane Shelleya9b44342021-08-08 17:15:52 -0500243 fs::path dataDir{PACKAGE_DIR "ras-data"};
244 std::vector<fs::path> dataPaths;
245 util::findFiles(dataDir, R"(.*\.json)", dataPaths);
246
247 // Parse each of the data files.
248 for (const auto& path : dataPaths)
249 {
250 // Trace each data file for debug.
251 trace::inf("File found: path=%s", path.string().c_str());
252
253 // Open the file.
254 std::ifstream file{path};
255 assert(file.good()); // The file must be readable.
256
Zane Shelley2fbd2672022-02-03 13:56:35 -0600257 try
258 {
259 // Parse the JSON.
260 const auto data = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -0500261
Zane Shelley2fbd2672022-02-03 13:56:35 -0600262 // Get the data version.
263 auto version = data.at("version").get<unsigned int>();
Zane Shelleyee54c992021-08-08 17:46:48 -0500264
Zane Shelley2fbd2672022-02-03 13:56:35 -0600265 // Get the schema for this file.
266 auto schema = schemaFiles.at(version);
Zane Shelleyee54c992021-08-08 17:46:48 -0500267
Zane Shelley2fbd2672022-02-03 13:56:35 -0600268 // Validate the data against the schema.
269 assert(util::validateJson(schema, data));
Zane Shelleya9b44342021-08-08 17:15:52 -0500270
Zane Shelley2fbd2672022-02-03 13:56:35 -0600271 // Get the chip model/EC level from the data. The value is currently
272 // stored as a string representation of the hex value. So it will
273 // have to be converted to an integer.
274 libhei::ChipType_t chipType =
275 std::stoul(data.at("model_ec").get<std::string>(), 0, 16);
Zane Shelleya9b44342021-08-08 17:15:52 -0500276
Zane Shelley2fbd2672022-02-03 13:56:35 -0600277 // So far, so good. Add the entry.
278 auto ret = iv_dataFiles.emplace(chipType, data);
279 assert(ret.second); // Should not have duplicate entries
280 }
281 catch (...)
282 {
283 trace::err("Failed to parse file: %s", path.string().c_str());
284 throw; // caught later downstream
285 }
Zane Shelleya9b44342021-08-08 17:15:52 -0500286 }
287}
288
289//------------------------------------------------------------------------------
290
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600291std::string
292 RasDataParser::parseSignature(const nlohmann::json& i_data,
293 const libhei::Signature& i_signature) const
Zane Shelley7698b302021-08-09 16:00:03 -0500294{
295 // Get the signature keys. All are hex (lower case) with no prefix.
296 char buf[5];
297 sprintf(buf, "%04x", i_signature.getId());
298 std::string id{buf};
299
300 sprintf(buf, "%02x", i_signature.getBit());
301 std::string bit{buf};
302
303 sprintf(buf, "%02x", i_signature.getInstance());
304 std::string inst{buf};
305
Zane Shelley2fbd2672022-02-03 13:56:35 -0600306 std::string action;
307
308 try
309 {
310 action =
311 i_data.at("signatures").at(id).at(bit).at(inst).get<std::string>();
312 }
Zane Shelley5836f4a2023-02-09 14:28:08 -0600313 catch (const nlohmann::json::out_of_range& e)
Zane Shelley2fbd2672022-02-03 13:56:35 -0600314 {
315 trace::err("No action defined for signature: %s %s %s", id.c_str(),
316 bit.c_str(), inst.c_str());
Caleb Palmere36866c2022-10-31 15:14:29 -0500317
318 if (1 == i_data.at("version").get<unsigned int>())
319 {
320 throw; // caught later downstream
321 }
322 else
323 {
324 // Default to 'level2_M_th1' if no signature is found.
325 action = "level2_M_th1";
326 }
Zane Shelley2fbd2672022-02-03 13:56:35 -0600327 }
328
Zane Shelley7698b302021-08-09 16:00:03 -0500329 // Return the action.
Zane Shelley2fbd2672022-02-03 13:56:35 -0600330 return action;
Zane Shelley7698b302021-08-09 16:00:03 -0500331}
332
333//------------------------------------------------------------------------------
334
Zane Shelley5d63cef2021-09-17 18:10:17 -0500335std::tuple<callout::BusType, std::string>
336 RasDataParser::parseBus(const nlohmann::json& i_data,
337 const std::string& i_name)
338{
339 auto bus = i_data.at("buses").at(i_name);
340
341 // clang-format off
342 static const std::map<std::string, callout::BusType> m =
343 {
344 {"SMP_BUS", callout::BusType::SMP_BUS},
345 {"OMI_BUS", callout::BusType::OMI_BUS},
346 };
347 // clang-format on
348
349 auto busType = m.at(bus.at("type").get<std::string>());
350
351 std::string unitPath{}; // default empty if unit does not exist
352 if (bus.contains("unit"))
353 {
Zane Shelley3e8f2952022-01-18 13:29:30 -0600354 auto unit = bus.at("unit").get<std::string>();
355 unitPath = i_data.at("units").at(unit).get<std::string>();
Zane Shelley5d63cef2021-09-17 18:10:17 -0500356 }
357
358 return std::make_tuple(busType, unitPath);
359}
360
361//------------------------------------------------------------------------------
362
Zane Shelley7698b302021-08-09 16:00:03 -0500363std::shared_ptr<Resolution>
364 RasDataParser::parseAction(const nlohmann::json& i_data,
365 const std::string& i_action)
366{
367 auto o_list = std::make_shared<ResolutionList>();
368
369 // This function will be called recursively and we want to prevent cyclic
370 // recursion.
371 static std::vector<std::string> stack;
372 assert(stack.end() == std::find(stack.begin(), stack.end(), i_action));
373 stack.push_back(i_action);
374
375 // Iterate the action list and apply the changes.
376 for (const auto& a : i_data.at("actions").at(i_action))
377 {
378 auto type = a.at("type").get<std::string>();
379
380 if ("action" == type)
381 {
382 auto name = a.at("name").get<std::string>();
383
384 o_list->push(parseAction(i_data, name));
385 }
386 else if ("callout_self" == type)
387 {
388 auto priority = a.at("priority").get<std::string>();
389 auto guard = a.at("guard").get<bool>();
390
Zane Shelleye4bfb472021-08-10 12:47:32 -0500391 std::string path{}; // Must be empty to callout the chip.
392
393 o_list->push(std::make_shared<HardwareCalloutResolution>(
394 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500395 }
396 else if ("callout_unit" == type)
397 {
398 auto name = a.at("name").get<std::string>();
399 auto priority = a.at("priority").get<std::string>();
400 auto guard = a.at("guard").get<bool>();
401
Zane Shelleye4bfb472021-08-10 12:47:32 -0500402 auto path = i_data.at("units").at(name).get<std::string>();
403
404 o_list->push(std::make_shared<HardwareCalloutResolution>(
405 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500406 }
407 else if ("callout_connected" == type)
408 {
409 auto name = a.at("name").get<std::string>();
410 auto priority = a.at("priority").get<std::string>();
411 auto guard = a.at("guard").get<bool>();
412
Zane Shelley5d63cef2021-09-17 18:10:17 -0500413 auto busData = parseBus(i_data, name);
414
415 o_list->push(std::make_shared<ConnectedCalloutResolution>(
416 std::get<0>(busData), std::get<1>(busData),
417 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500418 }
419 else if ("callout_bus" == type)
420 {
Zane Shelley4757a7b2021-09-20 22:23:38 -0500421 auto name = a.at("name").get<std::string>();
422 auto priority = a.at("priority").get<std::string>();
423 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500424
Zane Shelley4757a7b2021-09-20 22:23:38 -0500425 auto busData = parseBus(i_data, name);
426
427 o_list->push(std::make_shared<BusCalloutResolution>(
428 std::get<0>(busData), std::get<1>(busData),
429 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500430 }
431 else if ("callout_clock" == type)
432 {
Zane Shelley84721d92021-09-08 13:30:27 -0500433 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500434 auto priority = a.at("priority").get<std::string>();
435 auto guard = a.at("guard").get<bool>();
436
Zane Shelley84721d92021-09-08 13:30:27 -0500437 // clang-format off
438 static const std::map<std::string, callout::ClockType> m =
439 {
440 {"OSC_REF_CLOCK_0", callout::ClockType::OSC_REF_CLOCK_0},
441 {"OSC_REF_CLOCK_1", callout::ClockType::OSC_REF_CLOCK_1},
Zane Shelleyd195b712022-01-26 13:26:34 -0600442 {"TOD_CLOCK", callout::ClockType::TOD_CLOCK},
Zane Shelley84721d92021-09-08 13:30:27 -0500443 };
444 // clang-format on
445
446 o_list->push(std::make_shared<ClockCalloutResolution>(
447 m.at(name), getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500448 }
449 else if ("callout_procedure" == type)
450 {
451 auto name = a.at("name").get<std::string>();
452 auto priority = a.at("priority").get<std::string>();
453
454 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500455 static const std::map<std::string, callout::Procedure> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500456 {
Zane Shelleyd8b70182022-03-10 10:50:22 -0600457 {"LEVEL2", callout::Procedure::NEXTLVL},
458 {"SUE_SEEN", callout::Procedure::SUE_SEEN},
Zane Shelley7698b302021-08-09 16:00:03 -0500459 };
460 // clang-format on
461
462 o_list->push(std::make_shared<ProcedureCalloutResolution>(
463 m.at(name), getPriority(priority)));
464 }
465 else if ("callout_part" == type)
466 {
467 auto name = a.at("name").get<std::string>();
468 auto priority = a.at("priority").get<std::string>();
469
Zane Shelleya4134772022-01-10 17:22:44 -0600470 // clang-format off
471 static const std::map<std::string, callout::PartType> m =
472 {
473 {"PNOR", callout::PartType::PNOR},
474 };
475 // clang-format on
476
477 o_list->push(std::make_shared<PartCalloutResolution>(
478 m.at(name), getPriority(priority)));
Zane Shelley7698b302021-08-09 16:00:03 -0500479 }
480 else if ("plugin" == type)
481 {
482 auto name = a.at("name").get<std::string>();
Zane Shelleye13a9f92021-12-16 21:19:11 -0600483 auto inst = a.at("instance").get<unsigned int>();
Zane Shelley7698b302021-08-09 16:00:03 -0500484
Zane Shelleye13a9f92021-12-16 21:19:11 -0600485 o_list->push(std::make_shared<PluginResolution>(name, inst));
Zane Shelley7698b302021-08-09 16:00:03 -0500486 }
Caleb Palmerf1184392022-10-07 15:17:22 -0500487 else if ("flag" == type)
488 {
489 // No action, flags will be handled with the isFlagSet function
490 }
Zane Shelley7698b302021-08-09 16:00:03 -0500491 else
492 {
493 throw std::logic_error("Unsupported action type: " + type);
494 }
495 }
496
497 // Done with this action pop it off the stack.
498 stack.pop_back();
499
500 return o_list;
501}
502
503//------------------------------------------------------------------------------
504
Zane Shelleyc85716c2021-08-17 10:54:06 -0500505callout::Priority RasDataParser::getPriority(const std::string& i_priority)
Zane Shelley7698b302021-08-09 16:00:03 -0500506{
507 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500508 static const std::map<std::string, callout::Priority> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500509 {
Zane Shelleyc85716c2021-08-17 10:54:06 -0500510 {"HIGH", callout::Priority::HIGH},
511 {"MED", callout::Priority::MED},
512 {"MED_A", callout::Priority::MED_A},
513 {"MED_B", callout::Priority::MED_B},
514 {"MED_C", callout::Priority::MED_C},
515 {"LOW", callout::Priority::LOW},
Zane Shelley7698b302021-08-09 16:00:03 -0500516 };
517 // clang-format on
518
519 return m.at(i_priority);
520}
521
522//------------------------------------------------------------------------------
523
Zane Shelleya9b44342021-08-08 17:15:52 -0500524} // namespace analyzer