blob: 8ad510d57048ddd513231f6b26a17d6e291400db [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 Palmerf1184392022-10-07 15:17:22 -050050bool RasDataParser::isFlagSet(const libhei::Signature& i_signature,
51 const RasDataFlags i_flag)
52{
53 bool o_isFlagSet = false;
54
55 // List of all flag enums mapping to their corresponding string
56 std::map<RasDataFlags, std::string> flagMap = {
57 {SUE_SOURCE, "sue_source"},
58 {SUE_SEEN, "sue_seen"},
59 {CS_POSSIBLE, "cs_possible"},
60 {RECOVERED_ERROR, "recovered_error"},
61 {INFORMATIONAL_ONLY, "informational_only"},
62 {MNFG_INFORMATIONAL_ONLY, "mnfg_informational_only"},
63 {MASK_BUT_DONT_CLEAR, "mask_but_dont_clear"},
64 {CRC_RELATED_ERR, "crc_related_err"},
65 {CRC_ROOT_CAUSE, "crc_root_cause"},
66 {ODP_DATA_CORRUPT_SIDE_EFFECT, "odp_data_corrupt_side_effect"},
67 {ODP_DATA_CORRUPT_ROOT_CAUSE, "odp_data_corrupt_root_cause"},
68 };
69
70 // If the input flag does not exist in the map, that's a code bug.
71 assert(0 != flagMap.count(i_flag));
72
73 nlohmann::json data;
74 try
75 {
76 data = iv_dataFiles.at(i_signature.getChip().getType());
77 }
78 catch (const std::out_of_range& e)
79 {
80 trace::err("No RAS data defined for chip type: 0x%08x",
81 i_signature.getChip().getType());
82 throw; // caught later downstream
83 }
84
85 // Get the signature keys. All are hex (lower case) with no prefix.
86 char buf[5];
87 sprintf(buf, "%04x", i_signature.getId());
88 std::string id{buf};
89
90 sprintf(buf, "%02x", i_signature.getBit());
91 std::string bit{buf};
92
93 // Get the list of flags in string format from the data.
94 if (data.at("signatures").at(id).at(bit).contains("flags"))
95 {
96 auto flags = data.at("signatures")
97 .at(id)
98 .at(bit)
99 .at("flags")
100 .get<std::vector<std::string>>();
101
102 // Check if the input flag exists
103 if (flags.end() !=
104 std::find(flags.begin(), flags.end(), flagMap[i_flag]))
105 {
106 o_isFlagSet = true;
107 }
108 }
109
110 // If the flag hasn't been found, check if it was defined as part of the
111 // action for this input signature.
112 if (!o_isFlagSet)
113 {
114 const auto action = parseSignature(data, i_signature);
115 for (const auto& a : data.at("actions").at(action))
116 {
117 auto type = a.at("type").get<std::string>();
118 if ("flag" == type)
119 {
120 auto name = a.at("name").get<std::string>();
121 if (name == flagMap[i_flag])
122 {
123 o_isFlagSet = true;
124 break;
125 }
126 }
127 }
128 }
129
130 return o_isFlagSet;
131}
132
133//------------------------------------------------------------------------------
134
Zane Shelleya9b44342021-08-08 17:15:52 -0500135void RasDataParser::initDataFiles()
136{
137 iv_dataFiles.clear(); // initially empty
138
139 // Get the RAS data schema files from the package `schema` subdirectory.
140 fs::path schemaDir{PACKAGE_DIR "schema"};
Zane Shelleyee54c992021-08-08 17:46:48 -0500141 auto schemaRegex = R"(ras-data-schema-v[0-9]{2}\.json)";
142 std::vector<fs::path> schemaPaths;
143 util::findFiles(schemaDir, schemaRegex, schemaPaths);
Zane Shelleya9b44342021-08-08 17:15:52 -0500144
Zane Shelleyee54c992021-08-08 17:46:48 -0500145 // Parse each of the schema files.
146 std::map<unsigned int, nlohmann::json> schemaFiles;
147 for (const auto& path : schemaPaths)
148 {
149 // Trace each data file for debug.
150 trace::inf("File found: path=%s", path.string().c_str());
Zane Shelleya9b44342021-08-08 17:15:52 -0500151
Zane Shelleyee54c992021-08-08 17:46:48 -0500152 // Open the file.
153 std::ifstream file{path};
154 assert(file.good()); // The file must be readable.
Zane Shelleya9b44342021-08-08 17:15:52 -0500155
Zane Shelley2fbd2672022-02-03 13:56:35 -0600156 try
157 {
158 // Parse the JSON.
159 auto schema = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -0500160
Zane Shelley2fbd2672022-02-03 13:56:35 -0600161 // Get the schema version.
162 auto version = schema.at("version").get<unsigned int>();
Zane Shelleyee54c992021-08-08 17:46:48 -0500163
Zane Shelley2fbd2672022-02-03 13:56:35 -0600164 // Keep track of the schemas.
165 auto ret = schemaFiles.emplace(version, schema);
166 assert(ret.second); // Should not have duplicate entries
167 }
168 catch (...)
169 {
170 trace::err("Failed to parse file: %s", path.string().c_str());
171 throw; // caught later downstream
172 }
Zane Shelleyee54c992021-08-08 17:46:48 -0500173 }
174
175 // Get the RAS data files from the package `data` subdirectory.
Zane Shelleya9b44342021-08-08 17:15:52 -0500176 fs::path dataDir{PACKAGE_DIR "ras-data"};
177 std::vector<fs::path> dataPaths;
178 util::findFiles(dataDir, R"(.*\.json)", dataPaths);
179
180 // Parse each of the data files.
181 for (const auto& path : dataPaths)
182 {
183 // Trace each data file for debug.
184 trace::inf("File found: path=%s", path.string().c_str());
185
186 // Open the file.
187 std::ifstream file{path};
188 assert(file.good()); // The file must be readable.
189
Zane Shelley2fbd2672022-02-03 13:56:35 -0600190 try
191 {
192 // Parse the JSON.
193 const auto data = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -0500194
Zane Shelley2fbd2672022-02-03 13:56:35 -0600195 // Get the data version.
196 auto version = data.at("version").get<unsigned int>();
Zane Shelleyee54c992021-08-08 17:46:48 -0500197
Zane Shelley2fbd2672022-02-03 13:56:35 -0600198 // Get the schema for this file.
199 auto schema = schemaFiles.at(version);
Zane Shelleyee54c992021-08-08 17:46:48 -0500200
Zane Shelley2fbd2672022-02-03 13:56:35 -0600201 // Validate the data against the schema.
202 assert(util::validateJson(schema, data));
Zane Shelleya9b44342021-08-08 17:15:52 -0500203
Zane Shelley2fbd2672022-02-03 13:56:35 -0600204 // Get the chip model/EC level from the data. The value is currently
205 // stored as a string representation of the hex value. So it will
206 // have to be converted to an integer.
207 libhei::ChipType_t chipType =
208 std::stoul(data.at("model_ec").get<std::string>(), 0, 16);
Zane Shelleya9b44342021-08-08 17:15:52 -0500209
Zane Shelley2fbd2672022-02-03 13:56:35 -0600210 // So far, so good. Add the entry.
211 auto ret = iv_dataFiles.emplace(chipType, data);
212 assert(ret.second); // Should not have duplicate entries
213 }
214 catch (...)
215 {
216 trace::err("Failed to parse file: %s", path.string().c_str());
217 throw; // caught later downstream
218 }
Zane Shelleya9b44342021-08-08 17:15:52 -0500219 }
220}
221
222//------------------------------------------------------------------------------
223
Zane Shelley7698b302021-08-09 16:00:03 -0500224std::string RasDataParser::parseSignature(const nlohmann::json& i_data,
225 const libhei::Signature& i_signature)
226{
227 // Get the signature keys. All are hex (lower case) with no prefix.
228 char buf[5];
229 sprintf(buf, "%04x", i_signature.getId());
230 std::string id{buf};
231
232 sprintf(buf, "%02x", i_signature.getBit());
233 std::string bit{buf};
234
235 sprintf(buf, "%02x", i_signature.getInstance());
236 std::string inst{buf};
237
Zane Shelley2fbd2672022-02-03 13:56:35 -0600238 std::string action;
239
240 try
241 {
242 action =
243 i_data.at("signatures").at(id).at(bit).at(inst).get<std::string>();
244 }
245 catch (const std::out_of_range& e)
246 {
247 trace::err("No action defined for signature: %s %s %s", id.c_str(),
248 bit.c_str(), inst.c_str());
Caleb Palmere36866c2022-10-31 15:14:29 -0500249
250 if (1 == i_data.at("version").get<unsigned int>())
251 {
252 throw; // caught later downstream
253 }
254 else
255 {
256 // Default to 'level2_M_th1' if no signature is found.
257 action = "level2_M_th1";
258 }
Zane Shelley2fbd2672022-02-03 13:56:35 -0600259 }
260
Zane Shelley7698b302021-08-09 16:00:03 -0500261 // Return the action.
Zane Shelley2fbd2672022-02-03 13:56:35 -0600262 return action;
Zane Shelley7698b302021-08-09 16:00:03 -0500263}
264
265//------------------------------------------------------------------------------
266
Zane Shelley5d63cef2021-09-17 18:10:17 -0500267std::tuple<callout::BusType, std::string>
268 RasDataParser::parseBus(const nlohmann::json& i_data,
269 const std::string& i_name)
270{
271 auto bus = i_data.at("buses").at(i_name);
272
273 // clang-format off
274 static const std::map<std::string, callout::BusType> m =
275 {
276 {"SMP_BUS", callout::BusType::SMP_BUS},
277 {"OMI_BUS", callout::BusType::OMI_BUS},
278 };
279 // clang-format on
280
281 auto busType = m.at(bus.at("type").get<std::string>());
282
283 std::string unitPath{}; // default empty if unit does not exist
284 if (bus.contains("unit"))
285 {
Zane Shelley3e8f2952022-01-18 13:29:30 -0600286 auto unit = bus.at("unit").get<std::string>();
287 unitPath = i_data.at("units").at(unit).get<std::string>();
Zane Shelley5d63cef2021-09-17 18:10:17 -0500288 }
289
290 return std::make_tuple(busType, unitPath);
291}
292
293//------------------------------------------------------------------------------
294
Zane Shelley7698b302021-08-09 16:00:03 -0500295std::shared_ptr<Resolution>
296 RasDataParser::parseAction(const nlohmann::json& i_data,
297 const std::string& i_action)
298{
299 auto o_list = std::make_shared<ResolutionList>();
300
301 // This function will be called recursively and we want to prevent cyclic
302 // recursion.
303 static std::vector<std::string> stack;
304 assert(stack.end() == std::find(stack.begin(), stack.end(), i_action));
305 stack.push_back(i_action);
306
307 // Iterate the action list and apply the changes.
308 for (const auto& a : i_data.at("actions").at(i_action))
309 {
310 auto type = a.at("type").get<std::string>();
311
312 if ("action" == type)
313 {
314 auto name = a.at("name").get<std::string>();
315
316 o_list->push(parseAction(i_data, name));
317 }
318 else if ("callout_self" == type)
319 {
320 auto priority = a.at("priority").get<std::string>();
321 auto guard = a.at("guard").get<bool>();
322
Zane Shelleye4bfb472021-08-10 12:47:32 -0500323 std::string path{}; // Must be empty to callout the chip.
324
325 o_list->push(std::make_shared<HardwareCalloutResolution>(
326 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500327 }
328 else if ("callout_unit" == type)
329 {
330 auto name = a.at("name").get<std::string>();
331 auto priority = a.at("priority").get<std::string>();
332 auto guard = a.at("guard").get<bool>();
333
Zane Shelleye4bfb472021-08-10 12:47:32 -0500334 auto path = i_data.at("units").at(name).get<std::string>();
335
336 o_list->push(std::make_shared<HardwareCalloutResolution>(
337 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500338 }
339 else if ("callout_connected" == type)
340 {
341 auto name = a.at("name").get<std::string>();
342 auto priority = a.at("priority").get<std::string>();
343 auto guard = a.at("guard").get<bool>();
344
Zane Shelley5d63cef2021-09-17 18:10:17 -0500345 auto busData = parseBus(i_data, name);
346
347 o_list->push(std::make_shared<ConnectedCalloutResolution>(
348 std::get<0>(busData), std::get<1>(busData),
349 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500350 }
351 else if ("callout_bus" == type)
352 {
Zane Shelley4757a7b2021-09-20 22:23:38 -0500353 auto name = a.at("name").get<std::string>();
354 auto priority = a.at("priority").get<std::string>();
355 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500356
Zane Shelley4757a7b2021-09-20 22:23:38 -0500357 auto busData = parseBus(i_data, name);
358
359 o_list->push(std::make_shared<BusCalloutResolution>(
360 std::get<0>(busData), std::get<1>(busData),
361 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500362 }
363 else if ("callout_clock" == type)
364 {
Zane Shelley84721d92021-09-08 13:30:27 -0500365 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500366 auto priority = a.at("priority").get<std::string>();
367 auto guard = a.at("guard").get<bool>();
368
Zane Shelley84721d92021-09-08 13:30:27 -0500369 // clang-format off
370 static const std::map<std::string, callout::ClockType> m =
371 {
372 {"OSC_REF_CLOCK_0", callout::ClockType::OSC_REF_CLOCK_0},
373 {"OSC_REF_CLOCK_1", callout::ClockType::OSC_REF_CLOCK_1},
Zane Shelleyd195b712022-01-26 13:26:34 -0600374 {"TOD_CLOCK", callout::ClockType::TOD_CLOCK},
Zane Shelley84721d92021-09-08 13:30:27 -0500375 };
376 // clang-format on
377
378 o_list->push(std::make_shared<ClockCalloutResolution>(
379 m.at(name), getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500380 }
381 else if ("callout_procedure" == type)
382 {
383 auto name = a.at("name").get<std::string>();
384 auto priority = a.at("priority").get<std::string>();
385
386 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500387 static const std::map<std::string, callout::Procedure> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500388 {
Zane Shelleyd8b70182022-03-10 10:50:22 -0600389 {"LEVEL2", callout::Procedure::NEXTLVL},
390 {"SUE_SEEN", callout::Procedure::SUE_SEEN},
Zane Shelley7698b302021-08-09 16:00:03 -0500391 };
392 // clang-format on
393
394 o_list->push(std::make_shared<ProcedureCalloutResolution>(
395 m.at(name), getPriority(priority)));
396 }
397 else if ("callout_part" == type)
398 {
399 auto name = a.at("name").get<std::string>();
400 auto priority = a.at("priority").get<std::string>();
401
Zane Shelleya4134772022-01-10 17:22:44 -0600402 // clang-format off
403 static const std::map<std::string, callout::PartType> m =
404 {
405 {"PNOR", callout::PartType::PNOR},
406 };
407 // clang-format on
408
409 o_list->push(std::make_shared<PartCalloutResolution>(
410 m.at(name), getPriority(priority)));
Zane Shelley7698b302021-08-09 16:00:03 -0500411 }
412 else if ("plugin" == type)
413 {
414 auto name = a.at("name").get<std::string>();
Zane Shelleye13a9f92021-12-16 21:19:11 -0600415 auto inst = a.at("instance").get<unsigned int>();
Zane Shelley7698b302021-08-09 16:00:03 -0500416
Zane Shelleye13a9f92021-12-16 21:19:11 -0600417 o_list->push(std::make_shared<PluginResolution>(name, inst));
Zane Shelley7698b302021-08-09 16:00:03 -0500418 }
Caleb Palmerf1184392022-10-07 15:17:22 -0500419 else if ("flag" == type)
420 {
421 // No action, flags will be handled with the isFlagSet function
422 }
Zane Shelley7698b302021-08-09 16:00:03 -0500423 else
424 {
425 throw std::logic_error("Unsupported action type: " + type);
426 }
427 }
428
429 // Done with this action pop it off the stack.
430 stack.pop_back();
431
432 return o_list;
433}
434
435//------------------------------------------------------------------------------
436
Zane Shelleyc85716c2021-08-17 10:54:06 -0500437callout::Priority RasDataParser::getPriority(const std::string& i_priority)
Zane Shelley7698b302021-08-09 16:00:03 -0500438{
439 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500440 static const std::map<std::string, callout::Priority> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500441 {
Zane Shelleyc85716c2021-08-17 10:54:06 -0500442 {"HIGH", callout::Priority::HIGH},
443 {"MED", callout::Priority::MED},
444 {"MED_A", callout::Priority::MED_A},
445 {"MED_B", callout::Priority::MED_B},
446 {"MED_C", callout::Priority::MED_C},
447 {"LOW", callout::Priority::LOW},
Zane Shelley7698b302021-08-09 16:00:03 -0500448 };
449 // clang-format on
450
451 return m.at(i_priority);
452}
453
454//------------------------------------------------------------------------------
455
Zane Shelleya9b44342021-08-08 17:15:52 -0500456} // namespace analyzer