blob: e8042ff3b076046adf2efa94c8c64d30fb6722f9 [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{
13
14//------------------------------------------------------------------------------
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
51void RasDataParser::initDataFiles()
52{
53 iv_dataFiles.clear(); // initially empty
54
55 // Get the RAS data schema files from the package `schema` subdirectory.
56 fs::path schemaDir{PACKAGE_DIR "schema"};
Zane Shelleyee54c992021-08-08 17:46:48 -050057 auto schemaRegex = R"(ras-data-schema-v[0-9]{2}\.json)";
58 std::vector<fs::path> schemaPaths;
59 util::findFiles(schemaDir, schemaRegex, schemaPaths);
Zane Shelleya9b44342021-08-08 17:15:52 -050060
Zane Shelleyee54c992021-08-08 17:46:48 -050061 // Parse each of the schema files.
62 std::map<unsigned int, nlohmann::json> schemaFiles;
63 for (const auto& path : schemaPaths)
64 {
65 // Trace each data file for debug.
66 trace::inf("File found: path=%s", path.string().c_str());
Zane Shelleya9b44342021-08-08 17:15:52 -050067
Zane Shelleyee54c992021-08-08 17:46:48 -050068 // Open the file.
69 std::ifstream file{path};
70 assert(file.good()); // The file must be readable.
Zane Shelleya9b44342021-08-08 17:15:52 -050071
Zane Shelley2fbd2672022-02-03 13:56:35 -060072 try
73 {
74 // Parse the JSON.
75 auto schema = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -050076
Zane Shelley2fbd2672022-02-03 13:56:35 -060077 // Get the schema version.
78 auto version = schema.at("version").get<unsigned int>();
Zane Shelleyee54c992021-08-08 17:46:48 -050079
Zane Shelley2fbd2672022-02-03 13:56:35 -060080 // Keep track of the schemas.
81 auto ret = schemaFiles.emplace(version, schema);
82 assert(ret.second); // Should not have duplicate entries
83 }
84 catch (...)
85 {
86 trace::err("Failed to parse file: %s", path.string().c_str());
87 throw; // caught later downstream
88 }
Zane Shelleyee54c992021-08-08 17:46:48 -050089 }
90
91 // Get the RAS data files from the package `data` subdirectory.
Zane Shelleya9b44342021-08-08 17:15:52 -050092 fs::path dataDir{PACKAGE_DIR "ras-data"};
93 std::vector<fs::path> dataPaths;
94 util::findFiles(dataDir, R"(.*\.json)", dataPaths);
95
96 // Parse each of the data files.
97 for (const auto& path : dataPaths)
98 {
99 // Trace each data file for debug.
100 trace::inf("File found: path=%s", path.string().c_str());
101
102 // Open the file.
103 std::ifstream file{path};
104 assert(file.good()); // The file must be readable.
105
Zane Shelley2fbd2672022-02-03 13:56:35 -0600106 try
107 {
108 // Parse the JSON.
109 const auto data = nlohmann::json::parse(file);
Zane Shelleya9b44342021-08-08 17:15:52 -0500110
Zane Shelley2fbd2672022-02-03 13:56:35 -0600111 // Get the data version.
112 auto version = data.at("version").get<unsigned int>();
Zane Shelleyee54c992021-08-08 17:46:48 -0500113
Zane Shelley2fbd2672022-02-03 13:56:35 -0600114 // Get the schema for this file.
115 auto schema = schemaFiles.at(version);
Zane Shelleyee54c992021-08-08 17:46:48 -0500116
Zane Shelley2fbd2672022-02-03 13:56:35 -0600117 // Validate the data against the schema.
118 assert(util::validateJson(schema, data));
Zane Shelleya9b44342021-08-08 17:15:52 -0500119
Zane Shelley2fbd2672022-02-03 13:56:35 -0600120 // Get the chip model/EC level from the data. The value is currently
121 // stored as a string representation of the hex value. So it will
122 // have to be converted to an integer.
123 libhei::ChipType_t chipType =
124 std::stoul(data.at("model_ec").get<std::string>(), 0, 16);
Zane Shelleya9b44342021-08-08 17:15:52 -0500125
Zane Shelley2fbd2672022-02-03 13:56:35 -0600126 // So far, so good. Add the entry.
127 auto ret = iv_dataFiles.emplace(chipType, data);
128 assert(ret.second); // Should not have duplicate entries
129 }
130 catch (...)
131 {
132 trace::err("Failed to parse file: %s", path.string().c_str());
133 throw; // caught later downstream
134 }
Zane Shelleya9b44342021-08-08 17:15:52 -0500135 }
136}
137
138//------------------------------------------------------------------------------
139
Zane Shelley7698b302021-08-09 16:00:03 -0500140std::string RasDataParser::parseSignature(const nlohmann::json& i_data,
141 const libhei::Signature& i_signature)
142{
143 // Get the signature keys. All are hex (lower case) with no prefix.
144 char buf[5];
145 sprintf(buf, "%04x", i_signature.getId());
146 std::string id{buf};
147
148 sprintf(buf, "%02x", i_signature.getBit());
149 std::string bit{buf};
150
151 sprintf(buf, "%02x", i_signature.getInstance());
152 std::string inst{buf};
153
Zane Shelley2fbd2672022-02-03 13:56:35 -0600154 std::string action;
155
156 try
157 {
158 action =
159 i_data.at("signatures").at(id).at(bit).at(inst).get<std::string>();
160 }
161 catch (const std::out_of_range& e)
162 {
163 trace::err("No action defined for signature: %s %s %s", id.c_str(),
164 bit.c_str(), inst.c_str());
Caleb Palmere36866c2022-10-31 15:14:29 -0500165
166 if (1 == i_data.at("version").get<unsigned int>())
167 {
168 throw; // caught later downstream
169 }
170 else
171 {
172 // Default to 'level2_M_th1' if no signature is found.
173 action = "level2_M_th1";
174 }
Zane Shelley2fbd2672022-02-03 13:56:35 -0600175 }
176
Zane Shelley7698b302021-08-09 16:00:03 -0500177 // Return the action.
Zane Shelley2fbd2672022-02-03 13:56:35 -0600178 return action;
Zane Shelley7698b302021-08-09 16:00:03 -0500179}
180
181//------------------------------------------------------------------------------
182
Zane Shelley5d63cef2021-09-17 18:10:17 -0500183std::tuple<callout::BusType, std::string>
184 RasDataParser::parseBus(const nlohmann::json& i_data,
185 const std::string& i_name)
186{
187 auto bus = i_data.at("buses").at(i_name);
188
189 // clang-format off
190 static const std::map<std::string, callout::BusType> m =
191 {
192 {"SMP_BUS", callout::BusType::SMP_BUS},
193 {"OMI_BUS", callout::BusType::OMI_BUS},
194 };
195 // clang-format on
196
197 auto busType = m.at(bus.at("type").get<std::string>());
198
199 std::string unitPath{}; // default empty if unit does not exist
200 if (bus.contains("unit"))
201 {
Zane Shelley3e8f2952022-01-18 13:29:30 -0600202 auto unit = bus.at("unit").get<std::string>();
203 unitPath = i_data.at("units").at(unit).get<std::string>();
Zane Shelley5d63cef2021-09-17 18:10:17 -0500204 }
205
206 return std::make_tuple(busType, unitPath);
207}
208
209//------------------------------------------------------------------------------
210
Zane Shelley7698b302021-08-09 16:00:03 -0500211std::shared_ptr<Resolution>
212 RasDataParser::parseAction(const nlohmann::json& i_data,
213 const std::string& i_action)
214{
215 auto o_list = std::make_shared<ResolutionList>();
216
217 // This function will be called recursively and we want to prevent cyclic
218 // recursion.
219 static std::vector<std::string> stack;
220 assert(stack.end() == std::find(stack.begin(), stack.end(), i_action));
221 stack.push_back(i_action);
222
223 // Iterate the action list and apply the changes.
224 for (const auto& a : i_data.at("actions").at(i_action))
225 {
226 auto type = a.at("type").get<std::string>();
227
228 if ("action" == type)
229 {
230 auto name = a.at("name").get<std::string>();
231
232 o_list->push(parseAction(i_data, name));
233 }
234 else if ("callout_self" == type)
235 {
236 auto priority = a.at("priority").get<std::string>();
237 auto guard = a.at("guard").get<bool>();
238
Zane Shelleye4bfb472021-08-10 12:47:32 -0500239 std::string path{}; // Must be empty to callout the chip.
240
241 o_list->push(std::make_shared<HardwareCalloutResolution>(
242 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500243 }
244 else if ("callout_unit" == type)
245 {
246 auto name = a.at("name").get<std::string>();
247 auto priority = a.at("priority").get<std::string>();
248 auto guard = a.at("guard").get<bool>();
249
Zane Shelleye4bfb472021-08-10 12:47:32 -0500250 auto path = i_data.at("units").at(name).get<std::string>();
251
252 o_list->push(std::make_shared<HardwareCalloutResolution>(
253 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500254 }
255 else if ("callout_connected" == type)
256 {
257 auto name = a.at("name").get<std::string>();
258 auto priority = a.at("priority").get<std::string>();
259 auto guard = a.at("guard").get<bool>();
260
Zane Shelley5d63cef2021-09-17 18:10:17 -0500261 auto busData = parseBus(i_data, name);
262
263 o_list->push(std::make_shared<ConnectedCalloutResolution>(
264 std::get<0>(busData), std::get<1>(busData),
265 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500266 }
267 else if ("callout_bus" == type)
268 {
Zane Shelley4757a7b2021-09-20 22:23:38 -0500269 auto name = a.at("name").get<std::string>();
270 auto priority = a.at("priority").get<std::string>();
271 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500272
Zane Shelley4757a7b2021-09-20 22:23:38 -0500273 auto busData = parseBus(i_data, name);
274
275 o_list->push(std::make_shared<BusCalloutResolution>(
276 std::get<0>(busData), std::get<1>(busData),
277 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500278 }
279 else if ("callout_clock" == type)
280 {
Zane Shelley84721d92021-09-08 13:30:27 -0500281 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500282 auto priority = a.at("priority").get<std::string>();
283 auto guard = a.at("guard").get<bool>();
284
Zane Shelley84721d92021-09-08 13:30:27 -0500285 // clang-format off
286 static const std::map<std::string, callout::ClockType> m =
287 {
288 {"OSC_REF_CLOCK_0", callout::ClockType::OSC_REF_CLOCK_0},
289 {"OSC_REF_CLOCK_1", callout::ClockType::OSC_REF_CLOCK_1},
Zane Shelleyd195b712022-01-26 13:26:34 -0600290 {"TOD_CLOCK", callout::ClockType::TOD_CLOCK},
Zane Shelley84721d92021-09-08 13:30:27 -0500291 };
292 // clang-format on
293
294 o_list->push(std::make_shared<ClockCalloutResolution>(
295 m.at(name), getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500296 }
297 else if ("callout_procedure" == type)
298 {
299 auto name = a.at("name").get<std::string>();
300 auto priority = a.at("priority").get<std::string>();
301
302 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500303 static const std::map<std::string, callout::Procedure> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500304 {
Zane Shelleyd8b70182022-03-10 10:50:22 -0600305 {"LEVEL2", callout::Procedure::NEXTLVL},
306 {"SUE_SEEN", callout::Procedure::SUE_SEEN},
Zane Shelley7698b302021-08-09 16:00:03 -0500307 };
308 // clang-format on
309
310 o_list->push(std::make_shared<ProcedureCalloutResolution>(
311 m.at(name), getPriority(priority)));
312 }
313 else if ("callout_part" == type)
314 {
315 auto name = a.at("name").get<std::string>();
316 auto priority = a.at("priority").get<std::string>();
317
Zane Shelleya4134772022-01-10 17:22:44 -0600318 // clang-format off
319 static const std::map<std::string, callout::PartType> m =
320 {
321 {"PNOR", callout::PartType::PNOR},
322 };
323 // clang-format on
324
325 o_list->push(std::make_shared<PartCalloutResolution>(
326 m.at(name), getPriority(priority)));
Zane Shelley7698b302021-08-09 16:00:03 -0500327 }
328 else if ("plugin" == type)
329 {
330 auto name = a.at("name").get<std::string>();
Zane Shelleye13a9f92021-12-16 21:19:11 -0600331 auto inst = a.at("instance").get<unsigned int>();
Zane Shelley7698b302021-08-09 16:00:03 -0500332
Zane Shelleye13a9f92021-12-16 21:19:11 -0600333 o_list->push(std::make_shared<PluginResolution>(name, inst));
Zane Shelley7698b302021-08-09 16:00:03 -0500334 }
335 else
336 {
337 throw std::logic_error("Unsupported action type: " + type);
338 }
339 }
340
341 // Done with this action pop it off the stack.
342 stack.pop_back();
343
344 return o_list;
345}
346
347//------------------------------------------------------------------------------
348
Zane Shelleyc85716c2021-08-17 10:54:06 -0500349callout::Priority RasDataParser::getPriority(const std::string& i_priority)
Zane Shelley7698b302021-08-09 16:00:03 -0500350{
351 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500352 static const std::map<std::string, callout::Priority> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500353 {
Zane Shelleyc85716c2021-08-17 10:54:06 -0500354 {"HIGH", callout::Priority::HIGH},
355 {"MED", callout::Priority::MED},
356 {"MED_A", callout::Priority::MED_A},
357 {"MED_B", callout::Priority::MED_B},
358 {"MED_C", callout::Priority::MED_C},
359 {"LOW", callout::Priority::LOW},
Zane Shelley7698b302021-08-09 16:00:03 -0500360 };
361 // clang-format on
362
363 return m.at(i_priority);
364}
365
366//------------------------------------------------------------------------------
367
Zane Shelleya9b44342021-08-08 17:15:52 -0500368} // namespace analyzer