blob: e9b7bff19edb260442bc83b1094921fd57b4745e [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"},
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 Shelleyee54c992021-08-08 17:46:48 -0500231
Zane Shelley2fbd2672022-02-03 13:56:35 -0600232 // Keep track of the schemas.
233 auto ret = schemaFiles.emplace(version, schema);
234 assert(ret.second); // Should not have duplicate entries
235 }
236 catch (...)
237 {
238 trace::err("Failed to parse file: %s", path.string().c_str());
239 throw; // caught later downstream
240 }
Zane Shelleyee54c992021-08-08 17:46:48 -0500241 }
242
243 // Get the RAS data files from the package `data` subdirectory.
Zane Shelleya9b44342021-08-08 17:15:52 -0500244 fs::path dataDir{PACKAGE_DIR "ras-data"};
245 std::vector<fs::path> dataPaths;
246 util::findFiles(dataDir, R"(.*\.json)", dataPaths);
247
248 // Parse each of the data files.
249 for (const auto& path : dataPaths)
250 {
251 // Trace each data file for debug.
252 trace::inf("File found: path=%s", path.string().c_str());
253
254 // Open the file.
255 std::ifstream file{path};
256 assert(file.good()); // The file must be readable.
257
Zane Shelley2fbd2672022-02-03 13:56:35 -0600258 try
259 {
260 // Parse the JSON.
261 const auto data = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -0500262
Zane Shelley2fbd2672022-02-03 13:56:35 -0600263 // Get the data version.
264 auto version = data.at("version").get<unsigned int>();
Zane Shelleyee54c992021-08-08 17:46:48 -0500265
Zane Shelley2fbd2672022-02-03 13:56:35 -0600266 // Get the schema for this file.
267 auto schema = schemaFiles.at(version);
Zane Shelleyee54c992021-08-08 17:46:48 -0500268
Zane Shelley2fbd2672022-02-03 13:56:35 -0600269 // Validate the data against the schema.
270 assert(util::validateJson(schema, data));
Zane Shelleya9b44342021-08-08 17:15:52 -0500271
Zane Shelley2fbd2672022-02-03 13:56:35 -0600272 // Get the chip model/EC level from the data. The value is currently
273 // stored as a string representation of the hex value. So it will
274 // have to be converted to an integer.
275 libhei::ChipType_t chipType =
276 std::stoul(data.at("model_ec").get<std::string>(), 0, 16);
Zane Shelleya9b44342021-08-08 17:15:52 -0500277
Zane Shelley2fbd2672022-02-03 13:56:35 -0600278 // So far, so good. Add the entry.
279 auto ret = iv_dataFiles.emplace(chipType, data);
280 assert(ret.second); // Should not have duplicate entries
281 }
282 catch (...)
283 {
284 trace::err("Failed to parse file: %s", path.string().c_str());
285 throw; // caught later downstream
286 }
Zane Shelleya9b44342021-08-08 17:15:52 -0500287 }
288}
289
290//------------------------------------------------------------------------------
291
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600292std::string
293 RasDataParser::parseSignature(const nlohmann::json& i_data,
294 const libhei::Signature& i_signature) const
Zane Shelley7698b302021-08-09 16:00:03 -0500295{
296 // Get the signature keys. All are hex (lower case) with no prefix.
297 char buf[5];
298 sprintf(buf, "%04x", i_signature.getId());
299 std::string id{buf};
300
301 sprintf(buf, "%02x", i_signature.getBit());
302 std::string bit{buf};
303
304 sprintf(buf, "%02x", i_signature.getInstance());
305 std::string inst{buf};
306
Zane Shelley2fbd2672022-02-03 13:56:35 -0600307 std::string action;
308
309 try
310 {
311 action =
312 i_data.at("signatures").at(id).at(bit).at(inst).get<std::string>();
313 }
Zane Shelley5836f4a2023-02-09 14:28:08 -0600314 catch (const nlohmann::json::out_of_range& e)
Zane Shelley2fbd2672022-02-03 13:56:35 -0600315 {
316 trace::err("No action defined for signature: %s %s %s", id.c_str(),
317 bit.c_str(), inst.c_str());
Caleb Palmere36866c2022-10-31 15:14:29 -0500318
319 if (1 == i_data.at("version").get<unsigned int>())
320 {
321 throw; // caught later downstream
322 }
323 else
324 {
325 // Default to 'level2_M_th1' if no signature is found.
326 action = "level2_M_th1";
327 }
Zane Shelley2fbd2672022-02-03 13:56:35 -0600328 }
329
Zane Shelley7698b302021-08-09 16:00:03 -0500330 // Return the action.
Zane Shelley2fbd2672022-02-03 13:56:35 -0600331 return action;
Zane Shelley7698b302021-08-09 16:00:03 -0500332}
333
334//------------------------------------------------------------------------------
335
Zane Shelley5d63cef2021-09-17 18:10:17 -0500336std::tuple<callout::BusType, std::string>
337 RasDataParser::parseBus(const nlohmann::json& i_data,
338 const std::string& i_name)
339{
340 auto bus = i_data.at("buses").at(i_name);
341
342 // clang-format off
343 static const std::map<std::string, callout::BusType> m =
344 {
345 {"SMP_BUS", callout::BusType::SMP_BUS},
346 {"OMI_BUS", callout::BusType::OMI_BUS},
347 };
348 // clang-format on
349
350 auto busType = m.at(bus.at("type").get<std::string>());
351
352 std::string unitPath{}; // default empty if unit does not exist
353 if (bus.contains("unit"))
354 {
Zane Shelley3e8f2952022-01-18 13:29:30 -0600355 auto unit = bus.at("unit").get<std::string>();
356 unitPath = i_data.at("units").at(unit).get<std::string>();
Zane Shelley5d63cef2021-09-17 18:10:17 -0500357 }
358
359 return std::make_tuple(busType, unitPath);
360}
361
362//------------------------------------------------------------------------------
363
Zane Shelley7698b302021-08-09 16:00:03 -0500364std::shared_ptr<Resolution>
365 RasDataParser::parseAction(const nlohmann::json& i_data,
366 const std::string& i_action)
367{
368 auto o_list = std::make_shared<ResolutionList>();
369
370 // This function will be called recursively and we want to prevent cyclic
371 // recursion.
372 static std::vector<std::string> stack;
373 assert(stack.end() == std::find(stack.begin(), stack.end(), i_action));
374 stack.push_back(i_action);
375
376 // Iterate the action list and apply the changes.
377 for (const auto& a : i_data.at("actions").at(i_action))
378 {
379 auto type = a.at("type").get<std::string>();
380
381 if ("action" == type)
382 {
383 auto name = a.at("name").get<std::string>();
384
385 o_list->push(parseAction(i_data, name));
386 }
387 else if ("callout_self" == type)
388 {
389 auto priority = a.at("priority").get<std::string>();
390 auto guard = a.at("guard").get<bool>();
391
Zane Shelleye4bfb472021-08-10 12:47:32 -0500392 std::string path{}; // Must be empty to callout the chip.
393
394 o_list->push(std::make_shared<HardwareCalloutResolution>(
395 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500396 }
397 else if ("callout_unit" == type)
398 {
399 auto name = a.at("name").get<std::string>();
400 auto priority = a.at("priority").get<std::string>();
401 auto guard = a.at("guard").get<bool>();
402
Zane Shelleye4bfb472021-08-10 12:47:32 -0500403 auto path = i_data.at("units").at(name).get<std::string>();
404
405 o_list->push(std::make_shared<HardwareCalloutResolution>(
406 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500407 }
408 else if ("callout_connected" == type)
409 {
410 auto name = a.at("name").get<std::string>();
411 auto priority = a.at("priority").get<std::string>();
412 auto guard = a.at("guard").get<bool>();
413
Zane Shelley5d63cef2021-09-17 18:10:17 -0500414 auto busData = parseBus(i_data, name);
415
416 o_list->push(std::make_shared<ConnectedCalloutResolution>(
417 std::get<0>(busData), std::get<1>(busData),
418 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500419 }
420 else if ("callout_bus" == type)
421 {
Zane Shelley4757a7b2021-09-20 22:23:38 -0500422 auto name = a.at("name").get<std::string>();
423 auto priority = a.at("priority").get<std::string>();
424 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500425
Zane Shelley4757a7b2021-09-20 22:23:38 -0500426 auto busData = parseBus(i_data, name);
427
428 o_list->push(std::make_shared<BusCalloutResolution>(
429 std::get<0>(busData), std::get<1>(busData),
430 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500431 }
432 else if ("callout_clock" == type)
433 {
Zane Shelley84721d92021-09-08 13:30:27 -0500434 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500435 auto priority = a.at("priority").get<std::string>();
436 auto guard = a.at("guard").get<bool>();
437
Zane Shelley84721d92021-09-08 13:30:27 -0500438 // clang-format off
439 static const std::map<std::string, callout::ClockType> m =
440 {
441 {"OSC_REF_CLOCK_0", callout::ClockType::OSC_REF_CLOCK_0},
442 {"OSC_REF_CLOCK_1", callout::ClockType::OSC_REF_CLOCK_1},
Zane Shelleyd195b712022-01-26 13:26:34 -0600443 {"TOD_CLOCK", callout::ClockType::TOD_CLOCK},
Zane Shelley84721d92021-09-08 13:30:27 -0500444 };
445 // clang-format on
446
447 o_list->push(std::make_shared<ClockCalloutResolution>(
448 m.at(name), getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500449 }
450 else if ("callout_procedure" == type)
451 {
452 auto name = a.at("name").get<std::string>();
453 auto priority = a.at("priority").get<std::string>();
454
455 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500456 static const std::map<std::string, callout::Procedure> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500457 {
Zane Shelleyd8b70182022-03-10 10:50:22 -0600458 {"LEVEL2", callout::Procedure::NEXTLVL},
459 {"SUE_SEEN", callout::Procedure::SUE_SEEN},
Zane Shelley7698b302021-08-09 16:00:03 -0500460 };
461 // clang-format on
462
463 o_list->push(std::make_shared<ProcedureCalloutResolution>(
464 m.at(name), getPriority(priority)));
465 }
466 else if ("callout_part" == type)
467 {
468 auto name = a.at("name").get<std::string>();
469 auto priority = a.at("priority").get<std::string>();
470
Zane Shelleya4134772022-01-10 17:22:44 -0600471 // clang-format off
472 static const std::map<std::string, callout::PartType> m =
473 {
474 {"PNOR", callout::PartType::PNOR},
475 };
476 // clang-format on
477
478 o_list->push(std::make_shared<PartCalloutResolution>(
479 m.at(name), getPriority(priority)));
Zane Shelley7698b302021-08-09 16:00:03 -0500480 }
481 else if ("plugin" == type)
482 {
483 auto name = a.at("name").get<std::string>();
Zane Shelleye13a9f92021-12-16 21:19:11 -0600484 auto inst = a.at("instance").get<unsigned int>();
Zane Shelley7698b302021-08-09 16:00:03 -0500485
Zane Shelleye13a9f92021-12-16 21:19:11 -0600486 o_list->push(std::make_shared<PluginResolution>(name, inst));
Zane Shelley7698b302021-08-09 16:00:03 -0500487 }
Caleb Palmerf1184392022-10-07 15:17:22 -0500488 else if ("flag" == type)
489 {
490 // No action, flags will be handled with the isFlagSet function
491 }
Zane Shelley7698b302021-08-09 16:00:03 -0500492 else
493 {
494 throw std::logic_error("Unsupported action type: " + type);
495 }
496 }
497
498 // Done with this action pop it off the stack.
499 stack.pop_back();
500
501 return o_list;
502}
503
504//------------------------------------------------------------------------------
505
Zane Shelleyc85716c2021-08-17 10:54:06 -0500506callout::Priority RasDataParser::getPriority(const std::string& i_priority)
Zane Shelley7698b302021-08-09 16:00:03 -0500507{
508 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500509 static const std::map<std::string, callout::Priority> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500510 {
Zane Shelleyc85716c2021-08-17 10:54:06 -0500511 {"HIGH", callout::Priority::HIGH},
512 {"MED", callout::Priority::MED},
513 {"MED_A", callout::Priority::MED_A},
514 {"MED_B", callout::Priority::MED_B},
515 {"MED_C", callout::Priority::MED_C},
516 {"LOW", callout::Priority::LOW},
Zane Shelley7698b302021-08-09 16:00:03 -0500517 };
518 // clang-format on
519
520 return m.at(i_priority);
521}
522
523//------------------------------------------------------------------------------
524
Zane Shelleya9b44342021-08-08 17:15:52 -0500525} // namespace analyzer