blob: 9a014fd3f2a834c8ba2b4c97b8e4809dbc662a2f [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>
7#include <string>
8
9namespace fs = std::filesystem;
10
11namespace analyzer
12{
Zane Shelleya9b44342021-08-08 17:15:52 -050013//------------------------------------------------------------------------------
14
15std::shared_ptr<Resolution>
Zane Shelley7698b302021-08-09 16:00:03 -050016 RasDataParser::getResolution(const libhei::Signature& i_signature)
Zane Shelleya9b44342021-08-08 17:15:52 -050017{
Zane Shelley2fbd2672022-02-03 13:56:35 -060018 nlohmann::json data;
19
20 try
21 {
22 data = iv_dataFiles.at(i_signature.getChip().getType());
23 }
24 catch (const std::out_of_range& e)
25 {
26 trace::err("No RAS data defined for chip type: 0x%08x",
27 i_signature.getChip().getType());
28 throw; // caught later downstream
29 }
Zane Shelley7698b302021-08-09 16:00:03 -050030
31 const auto action = parseSignature(data, i_signature);
32
Zane Shelley2fbd2672022-02-03 13:56:35 -060033 std::shared_ptr<Resolution> resolution;
34
35 try
36 {
37 resolution = parseAction(data, action);
38 }
39 catch (...)
40 {
41 trace::err("Unable to get resolution for action: %s", action.c_str());
42 throw; // caught later downstream
43 }
44
45 return resolution;
Zane Shelleya9b44342021-08-08 17:15:52 -050046}
47
48//------------------------------------------------------------------------------
49
Caleb Palmer1a4f0e72022-11-07 15:08:01 -060050bool __checkActionForFlag(const std::string& i_action,
51 const std::string& i_flag,
52 const nlohmann::json& i_data)
53{
54 bool o_isFlagSet = false;
55
56 // Loop through the array of actions.
57 for (const auto& a : i_data.at("actions").at(i_action))
58 {
59 // Get the action type
60 auto type = a.at("type").get<std::string>();
61
62 // If the action is another action, recursively call this function
63 if ("action" == type)
64 {
65 auto name = a.at("name").get<std::string>();
66 o_isFlagSet = __checkActionForFlag(name, i_flag, i_data);
67 if (o_isFlagSet)
68 {
69 break;
70 }
71 }
72 // If the action is a flag, check if it's the one
73 else if ("flag" == type)
74 {
75 auto name = a.at("name").get<std::string>();
76 if (name == i_flag)
77 {
78 o_isFlagSet = true;
79 break;
80 }
81 }
82 }
83
84 return o_isFlagSet;
85}
86
87//------------------------------------------------------------------------------
88
Caleb Palmerf1184392022-10-07 15:17:22 -050089bool RasDataParser::isFlagSet(const libhei::Signature& i_signature,
Caleb Palmer1a4f0e72022-11-07 15:08:01 -060090 const RasDataFlags i_flag) const
Caleb Palmerf1184392022-10-07 15:17:22 -050091{
92 bool o_isFlagSet = false;
93
94 // List of all flag enums mapping to their corresponding string
95 std::map<RasDataFlags, std::string> flagMap = {
96 {SUE_SOURCE, "sue_source"},
97 {SUE_SEEN, "sue_seen"},
98 {CS_POSSIBLE, "cs_possible"},
99 {RECOVERED_ERROR, "recovered_error"},
100 {INFORMATIONAL_ONLY, "informational_only"},
101 {MNFG_INFORMATIONAL_ONLY, "mnfg_informational_only"},
102 {MASK_BUT_DONT_CLEAR, "mask_but_dont_clear"},
103 {CRC_RELATED_ERR, "crc_related_err"},
104 {CRC_ROOT_CAUSE, "crc_root_cause"},
105 {ODP_DATA_CORRUPT_SIDE_EFFECT, "odp_data_corrupt_side_effect"},
106 {ODP_DATA_CORRUPT_ROOT_CAUSE, "odp_data_corrupt_root_cause"},
107 };
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600108 std::string strFlag = flagMap[i_flag];
Caleb Palmerf1184392022-10-07 15:17:22 -0500109
110 // If the input flag does not exist in the map, that's a code bug.
111 assert(0 != flagMap.count(i_flag));
112
113 nlohmann::json data;
114 try
115 {
116 data = iv_dataFiles.at(i_signature.getChip().getType());
117 }
118 catch (const std::out_of_range& e)
119 {
120 trace::err("No RAS data defined for chip type: 0x%08x",
121 i_signature.getChip().getType());
122 throw; // caught later downstream
123 }
124
125 // Get the signature keys. All are hex (lower case) with no prefix.
126 char buf[5];
127 sprintf(buf, "%04x", i_signature.getId());
128 std::string id{buf};
129
130 sprintf(buf, "%02x", i_signature.getBit());
131 std::string bit{buf};
132
133 // Get the list of flags in string format from the data.
134 if (data.at("signatures").at(id).at(bit).contains("flags"))
135 {
136 auto flags = data.at("signatures")
137 .at(id)
138 .at(bit)
139 .at("flags")
140 .get<std::vector<std::string>>();
141
142 // Check if the input flag exists
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600143 if (flags.end() != std::find(flags.begin(), flags.end(), strFlag))
Caleb Palmerf1184392022-10-07 15:17:22 -0500144 {
145 o_isFlagSet = true;
146 }
147 }
148
149 // If the flag hasn't been found, check if it was defined as part of the
150 // action for this input signature.
151 if (!o_isFlagSet)
152 {
153 const auto action = parseSignature(data, i_signature);
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600154 __checkActionForFlag(action, strFlag, data);
Caleb Palmerf1184392022-10-07 15:17:22 -0500155 }
156
157 return o_isFlagSet;
158}
159
160//------------------------------------------------------------------------------
161
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600162unsigned int
163 RasDataParser::getVersion(const libhei::Signature& i_signature) const
164{
165 unsigned int o_version = 0;
166
167 nlohmann::json data;
168 try
169 {
170 data = iv_dataFiles.at(i_signature.getChip().getType());
171 }
172 catch (const std::out_of_range& e)
173 {
174 trace::err("No RAS data defined for chip type: 0x%08x",
175 i_signature.getChip().getType());
176 throw; // caught later downstream
177 }
178
179 o_version = data.at("version").get<unsigned int>();
180
181 return o_version;
182}
183
184//------------------------------------------------------------------------------
185
Zane Shelleya9b44342021-08-08 17:15:52 -0500186void RasDataParser::initDataFiles()
187{
188 iv_dataFiles.clear(); // initially empty
189
190 // Get the RAS data schema files from the package `schema` subdirectory.
191 fs::path schemaDir{PACKAGE_DIR "schema"};
Zane Shelleyee54c992021-08-08 17:46:48 -0500192 auto schemaRegex = R"(ras-data-schema-v[0-9]{2}\.json)";
193 std::vector<fs::path> schemaPaths;
194 util::findFiles(schemaDir, schemaRegex, schemaPaths);
Zane Shelleya9b44342021-08-08 17:15:52 -0500195
Zane Shelleyee54c992021-08-08 17:46:48 -0500196 // Parse each of the schema files.
197 std::map<unsigned int, nlohmann::json> schemaFiles;
198 for (const auto& path : schemaPaths)
199 {
200 // Trace each data file for debug.
201 trace::inf("File found: path=%s", path.string().c_str());
Zane Shelleya9b44342021-08-08 17:15:52 -0500202
Zane Shelleyee54c992021-08-08 17:46:48 -0500203 // Open the file.
204 std::ifstream file{path};
205 assert(file.good()); // The file must be readable.
Zane Shelleya9b44342021-08-08 17:15:52 -0500206
Zane Shelley2fbd2672022-02-03 13:56:35 -0600207 try
208 {
209 // Parse the JSON.
210 auto schema = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -0500211
Zane Shelley2fbd2672022-02-03 13:56:35 -0600212 // Get the schema version.
213 auto version = schema.at("version").get<unsigned int>();
Zane Shelleyee54c992021-08-08 17:46:48 -0500214
Zane Shelley2fbd2672022-02-03 13:56:35 -0600215 // Keep track of the schemas.
216 auto ret = schemaFiles.emplace(version, schema);
217 assert(ret.second); // Should not have duplicate entries
218 }
219 catch (...)
220 {
221 trace::err("Failed to parse file: %s", path.string().c_str());
222 throw; // caught later downstream
223 }
Zane Shelleyee54c992021-08-08 17:46:48 -0500224 }
225
226 // Get the RAS data files from the package `data` subdirectory.
Zane Shelleya9b44342021-08-08 17:15:52 -0500227 fs::path dataDir{PACKAGE_DIR "ras-data"};
228 std::vector<fs::path> dataPaths;
229 util::findFiles(dataDir, R"(.*\.json)", dataPaths);
230
231 // Parse each of the data files.
232 for (const auto& path : dataPaths)
233 {
234 // Trace each data file for debug.
235 trace::inf("File found: path=%s", path.string().c_str());
236
237 // Open the file.
238 std::ifstream file{path};
239 assert(file.good()); // The file must be readable.
240
Zane Shelley2fbd2672022-02-03 13:56:35 -0600241 try
242 {
243 // Parse the JSON.
244 const auto data = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -0500245
Zane Shelley2fbd2672022-02-03 13:56:35 -0600246 // Get the data version.
247 auto version = data.at("version").get<unsigned int>();
Zane Shelleyee54c992021-08-08 17:46:48 -0500248
Zane Shelley2fbd2672022-02-03 13:56:35 -0600249 // Get the schema for this file.
250 auto schema = schemaFiles.at(version);
Zane Shelleyee54c992021-08-08 17:46:48 -0500251
Zane Shelley2fbd2672022-02-03 13:56:35 -0600252 // Validate the data against the schema.
253 assert(util::validateJson(schema, data));
Zane Shelleya9b44342021-08-08 17:15:52 -0500254
Zane Shelley2fbd2672022-02-03 13:56:35 -0600255 // Get the chip model/EC level from the data. The value is currently
256 // stored as a string representation of the hex value. So it will
257 // have to be converted to an integer.
258 libhei::ChipType_t chipType =
259 std::stoul(data.at("model_ec").get<std::string>(), 0, 16);
Zane Shelleya9b44342021-08-08 17:15:52 -0500260
Zane Shelley2fbd2672022-02-03 13:56:35 -0600261 // So far, so good. Add the entry.
262 auto ret = iv_dataFiles.emplace(chipType, data);
263 assert(ret.second); // Should not have duplicate entries
264 }
265 catch (...)
266 {
267 trace::err("Failed to parse file: %s", path.string().c_str());
268 throw; // caught later downstream
269 }
Zane Shelleya9b44342021-08-08 17:15:52 -0500270 }
271}
272
273//------------------------------------------------------------------------------
274
Caleb Palmer1a4f0e72022-11-07 15:08:01 -0600275std::string
276 RasDataParser::parseSignature(const nlohmann::json& i_data,
277 const libhei::Signature& i_signature) const
Zane Shelley7698b302021-08-09 16:00:03 -0500278{
279 // Get the signature keys. All are hex (lower case) with no prefix.
280 char buf[5];
281 sprintf(buf, "%04x", i_signature.getId());
282 std::string id{buf};
283
284 sprintf(buf, "%02x", i_signature.getBit());
285 std::string bit{buf};
286
287 sprintf(buf, "%02x", i_signature.getInstance());
288 std::string inst{buf};
289
Zane Shelley2fbd2672022-02-03 13:56:35 -0600290 std::string action;
291
292 try
293 {
294 action =
295 i_data.at("signatures").at(id).at(bit).at(inst).get<std::string>();
296 }
297 catch (const std::out_of_range& e)
298 {
299 trace::err("No action defined for signature: %s %s %s", id.c_str(),
300 bit.c_str(), inst.c_str());
Caleb Palmere36866c2022-10-31 15:14:29 -0500301
302 if (1 == i_data.at("version").get<unsigned int>())
303 {
304 throw; // caught later downstream
305 }
306 else
307 {
308 // Default to 'level2_M_th1' if no signature is found.
309 action = "level2_M_th1";
310 }
Zane Shelley2fbd2672022-02-03 13:56:35 -0600311 }
312
Zane Shelley7698b302021-08-09 16:00:03 -0500313 // Return the action.
Zane Shelley2fbd2672022-02-03 13:56:35 -0600314 return action;
Zane Shelley7698b302021-08-09 16:00:03 -0500315}
316
317//------------------------------------------------------------------------------
318
Zane Shelley5d63cef2021-09-17 18:10:17 -0500319std::tuple<callout::BusType, std::string>
320 RasDataParser::parseBus(const nlohmann::json& i_data,
321 const std::string& i_name)
322{
323 auto bus = i_data.at("buses").at(i_name);
324
325 // clang-format off
326 static const std::map<std::string, callout::BusType> m =
327 {
328 {"SMP_BUS", callout::BusType::SMP_BUS},
329 {"OMI_BUS", callout::BusType::OMI_BUS},
330 };
331 // clang-format on
332
333 auto busType = m.at(bus.at("type").get<std::string>());
334
335 std::string unitPath{}; // default empty if unit does not exist
336 if (bus.contains("unit"))
337 {
Zane Shelley3e8f2952022-01-18 13:29:30 -0600338 auto unit = bus.at("unit").get<std::string>();
339 unitPath = i_data.at("units").at(unit).get<std::string>();
Zane Shelley5d63cef2021-09-17 18:10:17 -0500340 }
341
342 return std::make_tuple(busType, unitPath);
343}
344
345//------------------------------------------------------------------------------
346
Zane Shelley7698b302021-08-09 16:00:03 -0500347std::shared_ptr<Resolution>
348 RasDataParser::parseAction(const nlohmann::json& i_data,
349 const std::string& i_action)
350{
351 auto o_list = std::make_shared<ResolutionList>();
352
353 // This function will be called recursively and we want to prevent cyclic
354 // recursion.
355 static std::vector<std::string> stack;
356 assert(stack.end() == std::find(stack.begin(), stack.end(), i_action));
357 stack.push_back(i_action);
358
359 // Iterate the action list and apply the changes.
360 for (const auto& a : i_data.at("actions").at(i_action))
361 {
362 auto type = a.at("type").get<std::string>();
363
364 if ("action" == type)
365 {
366 auto name = a.at("name").get<std::string>();
367
368 o_list->push(parseAction(i_data, name));
369 }
370 else if ("callout_self" == type)
371 {
372 auto priority = a.at("priority").get<std::string>();
373 auto guard = a.at("guard").get<bool>();
374
Zane Shelleye4bfb472021-08-10 12:47:32 -0500375 std::string path{}; // Must be empty to callout the chip.
376
377 o_list->push(std::make_shared<HardwareCalloutResolution>(
378 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500379 }
380 else if ("callout_unit" == type)
381 {
382 auto name = a.at("name").get<std::string>();
383 auto priority = a.at("priority").get<std::string>();
384 auto guard = a.at("guard").get<bool>();
385
Zane Shelleye4bfb472021-08-10 12:47:32 -0500386 auto path = i_data.at("units").at(name).get<std::string>();
387
388 o_list->push(std::make_shared<HardwareCalloutResolution>(
389 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500390 }
391 else if ("callout_connected" == type)
392 {
393 auto name = a.at("name").get<std::string>();
394 auto priority = a.at("priority").get<std::string>();
395 auto guard = a.at("guard").get<bool>();
396
Zane Shelley5d63cef2021-09-17 18:10:17 -0500397 auto busData = parseBus(i_data, name);
398
399 o_list->push(std::make_shared<ConnectedCalloutResolution>(
400 std::get<0>(busData), std::get<1>(busData),
401 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500402 }
403 else if ("callout_bus" == type)
404 {
Zane Shelley4757a7b2021-09-20 22:23:38 -0500405 auto name = a.at("name").get<std::string>();
406 auto priority = a.at("priority").get<std::string>();
407 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500408
Zane Shelley4757a7b2021-09-20 22:23:38 -0500409 auto busData = parseBus(i_data, name);
410
411 o_list->push(std::make_shared<BusCalloutResolution>(
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_clock" == type)
416 {
Zane Shelley84721d92021-09-08 13:30:27 -0500417 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500418 auto priority = a.at("priority").get<std::string>();
419 auto guard = a.at("guard").get<bool>();
420
Zane Shelley84721d92021-09-08 13:30:27 -0500421 // clang-format off
422 static const std::map<std::string, callout::ClockType> m =
423 {
424 {"OSC_REF_CLOCK_0", callout::ClockType::OSC_REF_CLOCK_0},
425 {"OSC_REF_CLOCK_1", callout::ClockType::OSC_REF_CLOCK_1},
Zane Shelleyd195b712022-01-26 13:26:34 -0600426 {"TOD_CLOCK", callout::ClockType::TOD_CLOCK},
Zane Shelley84721d92021-09-08 13:30:27 -0500427 };
428 // clang-format on
429
430 o_list->push(std::make_shared<ClockCalloutResolution>(
431 m.at(name), getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500432 }
433 else if ("callout_procedure" == type)
434 {
435 auto name = a.at("name").get<std::string>();
436 auto priority = a.at("priority").get<std::string>();
437
438 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500439 static const std::map<std::string, callout::Procedure> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500440 {
Zane Shelleyd8b70182022-03-10 10:50:22 -0600441 {"LEVEL2", callout::Procedure::NEXTLVL},
442 {"SUE_SEEN", callout::Procedure::SUE_SEEN},
Zane Shelley7698b302021-08-09 16:00:03 -0500443 };
444 // clang-format on
445
446 o_list->push(std::make_shared<ProcedureCalloutResolution>(
447 m.at(name), getPriority(priority)));
448 }
449 else if ("callout_part" == type)
450 {
451 auto name = a.at("name").get<std::string>();
452 auto priority = a.at("priority").get<std::string>();
453
Zane Shelleya4134772022-01-10 17:22:44 -0600454 // clang-format off
455 static const std::map<std::string, callout::PartType> m =
456 {
457 {"PNOR", callout::PartType::PNOR},
458 };
459 // clang-format on
460
461 o_list->push(std::make_shared<PartCalloutResolution>(
462 m.at(name), getPriority(priority)));
Zane Shelley7698b302021-08-09 16:00:03 -0500463 }
464 else if ("plugin" == type)
465 {
466 auto name = a.at("name").get<std::string>();
Zane Shelleye13a9f92021-12-16 21:19:11 -0600467 auto inst = a.at("instance").get<unsigned int>();
Zane Shelley7698b302021-08-09 16:00:03 -0500468
Zane Shelleye13a9f92021-12-16 21:19:11 -0600469 o_list->push(std::make_shared<PluginResolution>(name, inst));
Zane Shelley7698b302021-08-09 16:00:03 -0500470 }
Caleb Palmerf1184392022-10-07 15:17:22 -0500471 else if ("flag" == type)
472 {
473 // No action, flags will be handled with the isFlagSet function
474 }
Zane Shelley7698b302021-08-09 16:00:03 -0500475 else
476 {
477 throw std::logic_error("Unsupported action type: " + type);
478 }
479 }
480
481 // Done with this action pop it off the stack.
482 stack.pop_back();
483
484 return o_list;
485}
486
487//------------------------------------------------------------------------------
488
Zane Shelleyc85716c2021-08-17 10:54:06 -0500489callout::Priority RasDataParser::getPriority(const std::string& i_priority)
Zane Shelley7698b302021-08-09 16:00:03 -0500490{
491 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500492 static const std::map<std::string, callout::Priority> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500493 {
Zane Shelleyc85716c2021-08-17 10:54:06 -0500494 {"HIGH", callout::Priority::HIGH},
495 {"MED", callout::Priority::MED},
496 {"MED_A", callout::Priority::MED_A},
497 {"MED_B", callout::Priority::MED_B},
498 {"MED_C", callout::Priority::MED_C},
499 {"LOW", callout::Priority::LOW},
Zane Shelley7698b302021-08-09 16:00:03 -0500500 };
501 // clang-format on
502
503 return m.at(i_priority);
504}
505
506//------------------------------------------------------------------------------
507
Zane Shelleya9b44342021-08-08 17:15:52 -0500508} // namespace analyzer