blob: da8fec0947f2b44d40fdcc31caea718820dbda97 [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());
165 throw; // caught later downstream
166 }
167
Zane Shelley7698b302021-08-09 16:00:03 -0500168 // Return the action.
Zane Shelley2fbd2672022-02-03 13:56:35 -0600169 return action;
Zane Shelley7698b302021-08-09 16:00:03 -0500170}
171
172//------------------------------------------------------------------------------
173
Zane Shelley5d63cef2021-09-17 18:10:17 -0500174std::tuple<callout::BusType, std::string>
175 RasDataParser::parseBus(const nlohmann::json& i_data,
176 const std::string& i_name)
177{
178 auto bus = i_data.at("buses").at(i_name);
179
180 // clang-format off
181 static const std::map<std::string, callout::BusType> m =
182 {
183 {"SMP_BUS", callout::BusType::SMP_BUS},
184 {"OMI_BUS", callout::BusType::OMI_BUS},
185 };
186 // clang-format on
187
188 auto busType = m.at(bus.at("type").get<std::string>());
189
190 std::string unitPath{}; // default empty if unit does not exist
191 if (bus.contains("unit"))
192 {
Zane Shelley3e8f2952022-01-18 13:29:30 -0600193 auto unit = bus.at("unit").get<std::string>();
194 unitPath = i_data.at("units").at(unit).get<std::string>();
Zane Shelley5d63cef2021-09-17 18:10:17 -0500195 }
196
197 return std::make_tuple(busType, unitPath);
198}
199
200//------------------------------------------------------------------------------
201
Zane Shelley7698b302021-08-09 16:00:03 -0500202std::shared_ptr<Resolution>
203 RasDataParser::parseAction(const nlohmann::json& i_data,
204 const std::string& i_action)
205{
206 auto o_list = std::make_shared<ResolutionList>();
207
208 // This function will be called recursively and we want to prevent cyclic
209 // recursion.
210 static std::vector<std::string> stack;
211 assert(stack.end() == std::find(stack.begin(), stack.end(), i_action));
212 stack.push_back(i_action);
213
214 // Iterate the action list and apply the changes.
215 for (const auto& a : i_data.at("actions").at(i_action))
216 {
217 auto type = a.at("type").get<std::string>();
218
219 if ("action" == type)
220 {
221 auto name = a.at("name").get<std::string>();
222
223 o_list->push(parseAction(i_data, name));
224 }
225 else if ("callout_self" == type)
226 {
227 auto priority = a.at("priority").get<std::string>();
228 auto guard = a.at("guard").get<bool>();
229
Zane Shelleye4bfb472021-08-10 12:47:32 -0500230 std::string path{}; // Must be empty to callout the chip.
231
232 o_list->push(std::make_shared<HardwareCalloutResolution>(
233 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500234 }
235 else if ("callout_unit" == type)
236 {
237 auto name = a.at("name").get<std::string>();
238 auto priority = a.at("priority").get<std::string>();
239 auto guard = a.at("guard").get<bool>();
240
Zane Shelleye4bfb472021-08-10 12:47:32 -0500241 auto path = i_data.at("units").at(name).get<std::string>();
242
243 o_list->push(std::make_shared<HardwareCalloutResolution>(
244 path, getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500245 }
246 else if ("callout_connected" == type)
247 {
248 auto name = a.at("name").get<std::string>();
249 auto priority = a.at("priority").get<std::string>();
250 auto guard = a.at("guard").get<bool>();
251
Zane Shelley5d63cef2021-09-17 18:10:17 -0500252 auto busData = parseBus(i_data, name);
253
254 o_list->push(std::make_shared<ConnectedCalloutResolution>(
255 std::get<0>(busData), std::get<1>(busData),
256 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500257 }
258 else if ("callout_bus" == type)
259 {
Zane Shelley4757a7b2021-09-20 22:23:38 -0500260 auto name = a.at("name").get<std::string>();
261 auto priority = a.at("priority").get<std::string>();
262 auto guard = a.at("guard").get<bool>();
Zane Shelley7698b302021-08-09 16:00:03 -0500263
Zane Shelley4757a7b2021-09-20 22:23:38 -0500264 auto busData = parseBus(i_data, name);
265
266 o_list->push(std::make_shared<BusCalloutResolution>(
267 std::get<0>(busData), std::get<1>(busData),
268 getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500269 }
270 else if ("callout_clock" == type)
271 {
Zane Shelley84721d92021-09-08 13:30:27 -0500272 auto name = a.at("name").get<std::string>();
Zane Shelley7698b302021-08-09 16:00:03 -0500273 auto priority = a.at("priority").get<std::string>();
274 auto guard = a.at("guard").get<bool>();
275
Zane Shelley84721d92021-09-08 13:30:27 -0500276 // clang-format off
277 static const std::map<std::string, callout::ClockType> m =
278 {
279 {"OSC_REF_CLOCK_0", callout::ClockType::OSC_REF_CLOCK_0},
280 {"OSC_REF_CLOCK_1", callout::ClockType::OSC_REF_CLOCK_1},
Zane Shelleyd195b712022-01-26 13:26:34 -0600281 {"TOD_CLOCK", callout::ClockType::TOD_CLOCK},
Zane Shelley84721d92021-09-08 13:30:27 -0500282 };
283 // clang-format on
284
285 o_list->push(std::make_shared<ClockCalloutResolution>(
286 m.at(name), getPriority(priority), guard));
Zane Shelley7698b302021-08-09 16:00:03 -0500287 }
288 else if ("callout_procedure" == type)
289 {
290 auto name = a.at("name").get<std::string>();
291 auto priority = a.at("priority").get<std::string>();
292
293 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500294 static const std::map<std::string, callout::Procedure> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500295 {
Zane Shelleyc85716c2021-08-17 10:54:06 -0500296 {"LEVEL2", callout::Procedure::NEXTLVL},
Zane Shelley7698b302021-08-09 16:00:03 -0500297 };
298 // clang-format on
299
300 o_list->push(std::make_shared<ProcedureCalloutResolution>(
301 m.at(name), getPriority(priority)));
302 }
303 else if ("callout_part" == type)
304 {
305 auto name = a.at("name").get<std::string>();
306 auto priority = a.at("priority").get<std::string>();
307
Zane Shelleya4134772022-01-10 17:22:44 -0600308 // clang-format off
309 static const std::map<std::string, callout::PartType> m =
310 {
311 {"PNOR", callout::PartType::PNOR},
312 };
313 // clang-format on
314
315 o_list->push(std::make_shared<PartCalloutResolution>(
316 m.at(name), getPriority(priority)));
Zane Shelley7698b302021-08-09 16:00:03 -0500317 }
318 else if ("plugin" == type)
319 {
320 auto name = a.at("name").get<std::string>();
Zane Shelleye13a9f92021-12-16 21:19:11 -0600321 auto inst = a.at("instance").get<unsigned int>();
Zane Shelley7698b302021-08-09 16:00:03 -0500322
Zane Shelleye13a9f92021-12-16 21:19:11 -0600323 o_list->push(std::make_shared<PluginResolution>(name, inst));
Zane Shelley7698b302021-08-09 16:00:03 -0500324 }
325 else
326 {
327 throw std::logic_error("Unsupported action type: " + type);
328 }
329 }
330
331 // Done with this action pop it off the stack.
332 stack.pop_back();
333
334 return o_list;
335}
336
337//------------------------------------------------------------------------------
338
Zane Shelleyc85716c2021-08-17 10:54:06 -0500339callout::Priority RasDataParser::getPriority(const std::string& i_priority)
Zane Shelley7698b302021-08-09 16:00:03 -0500340{
341 // clang-format off
Zane Shelleyc85716c2021-08-17 10:54:06 -0500342 static const std::map<std::string, callout::Priority> m =
Zane Shelley7698b302021-08-09 16:00:03 -0500343 {
Zane Shelleyc85716c2021-08-17 10:54:06 -0500344 {"HIGH", callout::Priority::HIGH},
345 {"MED", callout::Priority::MED},
346 {"MED_A", callout::Priority::MED_A},
347 {"MED_B", callout::Priority::MED_B},
348 {"MED_C", callout::Priority::MED_C},
349 {"LOW", callout::Priority::LOW},
Zane Shelley7698b302021-08-09 16:00:03 -0500350 };
351 // clang-format on
352
353 return m.at(i_priority);
354}
355
356//------------------------------------------------------------------------------
357
Zane Shelleya9b44342021-08-08 17:15:52 -0500358} // namespace analyzer