blob: 4864f6a9b905d6484f26786ddeb2ab63789dd823 [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlerf9bae182019-10-09 13:37:38 -050016#include "src.hpp"
17
Matt Spinler717de422020-06-04 13:10:14 -050018#include "device_callouts.hpp"
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080019#include "json_utils.hpp"
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080020#include "pel_values.hpp"
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +080021#ifdef PELTOOL
22#include <Python.h>
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080023
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +080024#include <nlohmann/json.hpp>
Patrick Williams2544b412022-10-04 08:41:06 -050025
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +080026#include <sstream>
27#endif
Matt Spinler0bacc8e2023-07-07 16:25:39 -050028#include <phosphor-logging/lg2.hpp>
Matt Spinlerf9bae182019-10-09 13:37:38 -050029
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -050030#include <format>
31
Matt Spinlerf9bae182019-10-09 13:37:38 -050032namespace openpower
33{
34namespace pels
35{
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080036namespace pv = openpower::pels::pel_values;
37namespace rg = openpower::pels::message;
Matt Spinler85f61a62020-06-03 16:28:55 -050038using namespace std::string_literals;
Matt Spinlerf9bae182019-10-09 13:37:38 -050039
Matt Spinler075e5ba2020-02-21 15:46:00 -060040constexpr size_t ccinSize = 4;
41
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +080042#ifdef PELTOOL
Sumit Kumar516935a2021-04-14 13:00:54 -050043using orderedJSON = nlohmann::ordered_json;
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +080044
45void pyDecRef(PyObject* pyObj)
46{
47 Py_XDECREF(pyObj);
48}
49
50/**
51 * @brief Returns a JSON string to append to SRC section.
52 *
53 * The returning string will contain a JSON object, but without
54 * the outer {}. If the input JSON isn't a JSON object (dict), then
55 * one will be created with the input added to a 'SRC Details' key.
56 *
57 * @param[in] json - The JSON to convert to a string
58 *
59 * @return std::string - The JSON string
60 */
Sumit Kumar516935a2021-04-14 13:00:54 -050061std::string prettyJSON(const orderedJSON& json)
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +080062{
Sumit Kumar516935a2021-04-14 13:00:54 -050063 orderedJSON output;
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +080064 if (!json.is_object())
65 {
66 output["SRC Details"] = json;
67 }
68 else
69 {
70 for (const auto& [key, value] : json.items())
71 {
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +080072 output["SRC Details"][key] = value;
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +080073 }
74 }
75
76 // Let nlohmann do the pretty printing.
77 std::stringstream stream;
78 stream << std::setw(4) << output;
79
80 auto jsonString = stream.str();
81
82 // Now it looks like:
83 // {
84 // "Key": "Value",
85 // ...
86 // }
87
88 // Replace the { and the following newline, and the } and its
89 // preceeding newline.
90 jsonString.erase(0, 2);
91
92 auto pos = jsonString.find_last_of('}');
93 jsonString.erase(pos - 1);
94
95 return jsonString;
96}
97
98/**
99 * @brief Call Python modules to parse the data into a JSON string
100 *
101 * The module to call is based on the Creator Subsystem ID under the namespace
102 * "srcparsers". For example: "srcparsers.xsrc.xsrc" where "x" is the Creator
103 * Subsystem ID in ASCII lowercase.
104 *
105 * All modules must provide the following:
106 * Function: parseSRCToJson
107 * Argument list:
108 * 1. (str) ASCII string (Hex Word 1)
109 * 2. (str) Hex Word 2
110 * 3. (str) Hex Word 3
111 * 4. (str) Hex Word 4
112 * 5. (str) Hex Word 5
113 * 6. (str) Hex Word 6
114 * 7. (str) Hex Word 7
115 * 8. (str) Hex Word 8
116 * 9. (str) Hex Word 9
117 *-Return data:
118 * 1. (str) JSON string
119 *
120 * @param[in] hexwords - Vector of strings of Hexwords 1-9
121 * @param[in] creatorID - The creatorID from the Private Header section
122 * @return std::optional<std::string> - The JSON string if it could be created,
123 * else std::nullopt
124 */
125std::optional<std::string> getPythonJSON(std::vector<std::string>& hexwords,
126 uint8_t creatorID)
127{
Matt Spinlerbe952d22022-07-01 11:30:11 -0500128 PyObject *pName, *pModule, *eType, *eValue, *eTraceback;
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800129 std::string pErrStr;
130 std::string module = getNumberString("%c", tolower(creatorID)) + "src";
131 pName = PyUnicode_FromString(
132 std::string("srcparsers." + module + "." + module).c_str());
133 std::unique_ptr<PyObject, decltype(&pyDecRef)> modNamePtr(pName, &pyDecRef);
134 pModule = PyImport_Import(pName);
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800135 if (pModule == NULL)
136 {
137 pErrStr = "No error string found";
138 PyErr_Fetch(&eType, &eValue, &eTraceback);
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800139 if (eType)
140 {
141 Py_XDECREF(eType);
142 }
143 if (eTraceback)
144 {
145 Py_XDECREF(eTraceback);
146 }
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800147 if (eValue)
148 {
149 PyObject* pStr = PyObject_Str(eValue);
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800150 Py_XDECREF(eValue);
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800151 if (pStr)
152 {
153 pErrStr = PyUnicode_AsUTF8(pStr);
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800154 Py_XDECREF(pStr);
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800155 }
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800156 }
157 }
158 else
159 {
Patrick Williams075c7922024-08-16 15:19:49 -0400160 std::unique_ptr<PyObject, decltype(&pyDecRef)> modPtr(
161 pModule, &pyDecRef);
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800162 std::string funcToCall = "parseSRCToJson";
Matt Spinlerbe952d22022-07-01 11:30:11 -0500163 PyObject* pKey = PyUnicode_FromString(funcToCall.c_str());
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800164 std::unique_ptr<PyObject, decltype(&pyDecRef)> keyPtr(pKey, &pyDecRef);
Matt Spinlerbe952d22022-07-01 11:30:11 -0500165 PyObject* pDict = PyModule_GetDict(pModule);
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800166 Py_INCREF(pDict);
167 if (!PyDict_Contains(pDict, pKey))
168 {
169 Py_DECREF(pDict);
Matt Spinler0bacc8e2023-07-07 16:25:39 -0500170 lg2::error(
171 "Python module error. Function missing: {FUNC}, SRC = {SRC}, module = {MODULE}",
172 "FUNC", funcToCall, "SRC", hexwords.front(), "MODULE", module);
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800173 return std::nullopt;
174 }
Matt Spinlerbe952d22022-07-01 11:30:11 -0500175 PyObject* pFunc = PyDict_GetItemString(pDict, funcToCall.c_str());
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800176 Py_DECREF(pDict);
177 Py_INCREF(pFunc);
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800178 if (PyCallable_Check(pFunc))
179 {
Matt Spinlerbe952d22022-07-01 11:30:11 -0500180 PyObject* pArgs = PyTuple_New(9);
Patrick Williams075c7922024-08-16 15:19:49 -0400181 std::unique_ptr<PyObject, decltype(&pyDecRef)> argPtr(
182 pArgs, &pyDecRef);
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800183 for (size_t i = 0; i < 9; i++)
184 {
Matt Spinlerc1984032023-01-05 10:09:59 -0600185 std::string arg{"00000000"};
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800186 if (i < hexwords.size())
187 {
Matt Spinlerc1984032023-01-05 10:09:59 -0600188 arg = hexwords[i];
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800189 }
Matt Spinlerc1984032023-01-05 10:09:59 -0600190 PyTuple_SetItem(pArgs, i, Py_BuildValue("s", arg.c_str()));
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800191 }
Matt Spinlerbe952d22022-07-01 11:30:11 -0500192 PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800193 Py_DECREF(pFunc);
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800194 if (pResult)
195 {
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800196 std::unique_ptr<PyObject, decltype(&pyDecRef)> resPtr(
197 pResult, &pyDecRef);
Matt Spinler91f6d3a2025-05-22 08:32:49 -0500198
199 if (pResult == Py_None)
200 {
201 return std::nullopt;
202 }
203
Patrick Williams075c7922024-08-16 15:19:49 -0400204 PyObject* pBytes =
205 PyUnicode_AsEncodedString(pResult, "utf-8", "~E~");
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800206 std::unique_ptr<PyObject, decltype(&pyDecRef)> pyBytePtr(
207 pBytes, &pyDecRef);
208 const char* output = PyBytes_AS_STRING(pBytes);
209 try
210 {
Matt Spinlerbb1c1d52021-06-03 13:18:48 -0600211 orderedJSON json = orderedJSON::parse(output);
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800212 if ((json.is_object() && !json.empty()) ||
213 (json.is_array() && json.size() > 0) ||
214 (json.is_string() && json != ""))
215 {
216 return prettyJSON(json);
217 }
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800218 }
Patrick Williams66491c62021-10-06 12:23:37 -0500219 catch (const std::exception& e)
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800220 {
Matt Spinler0bacc8e2023-07-07 16:25:39 -0500221 lg2::error(
222 "Bad JSON from parser. Error = {ERROR}, SRC = {SRC}, module = {MODULE}",
223 "ERROR", e, "SRC", hexwords.front(), "MODULE", module);
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800224 return std::nullopt;
225 }
226 }
227 else
228 {
229 pErrStr = "No error string found";
230 PyErr_Fetch(&eType, &eValue, &eTraceback);
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800231 if (eType)
232 {
233 Py_XDECREF(eType);
234 }
235 if (eTraceback)
236 {
237 Py_XDECREF(eTraceback);
238 }
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800239 if (eValue)
240 {
241 PyObject* pStr = PyObject_Str(eValue);
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800242 Py_XDECREF(eValue);
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800243 if (pStr)
244 {
245 pErrStr = PyUnicode_AsUTF8(pStr);
Harisuddin Mohamed Isa69c18272021-05-29 13:18:45 +0800246 Py_XDECREF(pStr);
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800247 }
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800248 }
249 }
250 }
251 }
252 if (!pErrStr.empty())
253 {
Matt Spinler0bacc8e2023-07-07 16:25:39 -0500254 lg2::debug("Python exception thrown by parser. Error = {ERROR}, "
255 "SRC = {SRC}, module = {MODULE}",
256 "ERROR", pErrStr, "SRC", hexwords.front(), "MODULE", module);
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800257 }
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800258 return std::nullopt;
259}
260#endif
261
Matt Spinlerf9bae182019-10-09 13:37:38 -0500262void SRC::unflatten(Stream& stream)
263{
264 stream >> _header >> _version >> _flags >> _reserved1B >> _wordCount >>
265 _reserved2B >> _size;
266
267 for (auto& word : _hexData)
268 {
269 stream >> word;
270 }
271
272 _asciiString = std::make_unique<src::AsciiString>(stream);
273
274 if (hasAdditionalSections())
275 {
276 // The callouts section is currently the only extra subsection type
277 _callouts = std::make_unique<src::Callouts>(stream);
278 }
279}
280
Matt Spinler06885452019-11-06 10:35:42 -0600281void SRC::flatten(Stream& stream) const
Matt Spinlerf9bae182019-10-09 13:37:38 -0500282{
283 stream << _header << _version << _flags << _reserved1B << _wordCount
284 << _reserved2B << _size;
285
286 for (auto& word : _hexData)
287 {
288 stream << word;
289 }
290
291 _asciiString->flatten(stream);
292
293 if (_callouts)
294 {
295 _callouts->flatten(stream);
296 }
297}
298
299SRC::SRC(Stream& pel)
300{
301 try
302 {
303 unflatten(pel);
304 validate();
305 }
306 catch (const std::exception& e)
307 {
Matt Spinler0bacc8e2023-07-07 16:25:39 -0500308 lg2::error("Cannot unflatten SRC, error = {ERROR}", "ERROR", e);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500309 _valid = false;
310 }
311}
312
Matt Spinler075e5ba2020-02-21 15:46:00 -0600313SRC::SRC(const message::Entry& regEntry, const AdditionalData& additionalData,
Matt Spinler5a90a952020-08-27 09:39:03 -0500314 const nlohmann::json& jsonCallouts, const DataInterfaceBase& dataIface)
Matt Spinlerbd716f02019-10-15 10:54:11 -0500315{
316 _header.id = static_cast<uint16_t>(SectionID::primarySRC);
317 _header.version = srcSectionVersion;
318 _header.subType = srcSectionSubtype;
319 _header.componentID = regEntry.componentID;
320
321 _version = srcVersion;
322
323 _flags = 0;
Vijay Lobof3702bb2021-04-09 15:10:19 -0500324
Matt Spinlerbd716f02019-10-15 10:54:11 -0500325 _reserved1B = 0;
326
327 _wordCount = numSRCHexDataWords + 1;
328
329 _reserved2B = 0;
330
331 // There are multiple fields encoded in the hex data words.
332 std::for_each(_hexData.begin(), _hexData.end(),
333 [](auto& word) { word = 0; });
Matt Spinler7c619182020-07-27 15:15:11 -0500334
335 // Hex Word 2 Nibbles:
336 // MIGVEPFF
337 // M: Partition dump status = 0
338 // I: System boot state = TODO
339 // G: Partition Boot type = 0
Sumit Kumar9d43a722021-08-24 09:46:19 -0500340 // V: BMC dump status
Matt Spinler7c619182020-07-27 15:15:11 -0500341 // E: Platform boot mode = 0 (side = temporary, speed = fast)
Sumit Kumar9d43a722021-08-24 09:46:19 -0500342 // P: Platform dump status
Matt Spinler7c619182020-07-27 15:15:11 -0500343 // FF: SRC format, set below
344
Vijay Lobo875b6c72021-10-20 17:38:56 -0500345 setProgressCode(dataIface);
Matt Spinlerbd716f02019-10-15 10:54:11 -0500346 setBMCFormat();
347 setBMCPosition();
Matt Spinler075e5ba2020-02-21 15:46:00 -0600348 setMotherboardCCIN(dataIface);
349
Matt Spinlerda5b76b2023-06-01 15:56:57 -0500350 if (regEntry.src.checkstopFlag)
351 {
352 setErrorStatusFlag(ErrorStatusFlags::hwCheckstop);
353 }
354
Matt Spinler3fe93e92023-04-14 14:06:59 -0500355 if (regEntry.src.deconfigFlag)
356 {
357 setErrorStatusFlag(ErrorStatusFlags::deconfigured);
358 }
359
Matt Spinlerbd716f02019-10-15 10:54:11 -0500360 // Fill in the last 4 words from the AdditionalData property contents.
361 setUserDefinedHexWords(regEntry, additionalData);
362
363 _asciiString = std::make_unique<src::AsciiString>(regEntry);
364
Sumit Kumar50bfa692022-01-06 06:48:26 -0600365 // Check for additional data - PEL_SUBSYSTEM
366 auto ss = additionalData.getValue("PEL_SUBSYSTEM");
367 if (ss)
368 {
Matt Spinler6f07df32025-05-09 11:42:39 -0500369 auto eventSubsystem = std::stoul(*ss, nullptr, 16);
Patrick Williams075c7922024-08-16 15:19:49 -0400370 std::string subsystem =
371 pv::getValue(eventSubsystem, pel_values::subsystemValues);
Sumit Kumar50bfa692022-01-06 06:48:26 -0600372 if (subsystem == "invalid")
373 {
Matt Spinler0bacc8e2023-07-07 16:25:39 -0500374 lg2::warning("SRC: Invalid SubSystem value: {VAL}", "VAL", lg2::hex,
375 eventSubsystem);
Sumit Kumar50bfa692022-01-06 06:48:26 -0600376 }
377 else
378 {
379 _asciiString->setByte(2, eventSubsystem);
380 }
381 }
382
Matt Spinler5a90a952020-08-27 09:39:03 -0500383 addCallouts(regEntry, additionalData, jsonCallouts, dataIface);
Matt Spinlerbd716f02019-10-15 10:54:11 -0500384
385 _size = baseSRCSize;
386 _size += _callouts ? _callouts->flattenedSize() : 0;
Matt Spinlere2eb14a2025-05-09 13:34:51 -0500387 _header.size = Section::headerSize() + _size;
Matt Spinlerbd716f02019-10-15 10:54:11 -0500388
389 _valid = true;
390}
391
392void SRC::setUserDefinedHexWords(const message::Entry& regEntry,
393 const AdditionalData& ad)
394{
395 if (!regEntry.src.hexwordADFields)
396 {
397 return;
398 }
399
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800400 // Save the AdditionalData value corresponding to the first element of
401 // adName tuple into _hexData[wordNum].
Matt Spinlerbd716f02019-10-15 10:54:11 -0500402 for (const auto& [wordNum, adName] : *regEntry.src.hexwordADFields)
403 {
404 // Can only set words 6 - 9
405 if (!isUserDefinedWord(wordNum))
406 {
Patrick Williams075c7922024-08-16 15:19:49 -0400407 std::string msg =
408 "SRC user data word out of range: " + std::to_string(wordNum);
Matt Spinler85f61a62020-06-03 16:28:55 -0500409 addDebugData(msg);
Matt Spinlerbd716f02019-10-15 10:54:11 -0500410 continue;
411 }
412
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800413 auto value = ad.getValue(std::get<0>(adName));
Matt Spinlerbd716f02019-10-15 10:54:11 -0500414 if (value)
415 {
416 _hexData[getWordIndexFromWordNum(wordNum)] =
417 std::strtoul(value.value().c_str(), nullptr, 0);
418 }
419 else
420 {
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800421 std::string msg = "Source for user data SRC word not found: " +
422 std::get<0>(adName);
Matt Spinler85f61a62020-06-03 16:28:55 -0500423 addDebugData(msg);
Matt Spinlerbd716f02019-10-15 10:54:11 -0500424 }
425 }
426}
427
Matt Spinler075e5ba2020-02-21 15:46:00 -0600428void SRC::setMotherboardCCIN(const DataInterfaceBase& dataIface)
429{
430 uint32_t ccin = 0;
431 auto ccinString = dataIface.getMotherboardCCIN();
432
433 try
434 {
435 if (ccinString.size() == ccinSize)
436 {
Matt Spinler6f07df32025-05-09 11:42:39 -0500437 ccin = std::stoi(ccinString, nullptr, 16);
Matt Spinler075e5ba2020-02-21 15:46:00 -0600438 }
439 }
Patrick Williams66491c62021-10-06 12:23:37 -0500440 catch (const std::exception& e)
Matt Spinler075e5ba2020-02-21 15:46:00 -0600441 {
Matt Spinler0bacc8e2023-07-07 16:25:39 -0500442 lg2::warning("Could not convert motherboard CCIN {CCIN} to a number",
443 "CCIN", ccinString);
Matt Spinler075e5ba2020-02-21 15:46:00 -0600444 return;
445 }
446
447 // Set the first 2 bytes
448 _hexData[1] |= ccin << 16;
449}
450
Matt Spinlerf9bae182019-10-09 13:37:38 -0500451void SRC::validate()
452{
453 bool failed = false;
454
455 if ((header().id != static_cast<uint16_t>(SectionID::primarySRC)) &&
456 (header().id != static_cast<uint16_t>(SectionID::secondarySRC)))
457 {
Matt Spinler0bacc8e2023-07-07 16:25:39 -0500458 lg2::error("Invalid SRC section ID: {ID}", "ID", lg2::hex, header().id);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500459 failed = true;
460 }
461
462 // Check the version in the SRC, not in the header
Matt Spinlerbd716f02019-10-15 10:54:11 -0500463 if (_version != srcVersion)
Matt Spinlerf9bae182019-10-09 13:37:38 -0500464 {
Matt Spinler0bacc8e2023-07-07 16:25:39 -0500465 lg2::error("Invalid SRC version: {VERSION}", "VERSION", lg2::hex,
466 header().version);
Matt Spinlerf9bae182019-10-09 13:37:38 -0500467 failed = true;
468 }
469
470 _valid = failed ? false : true;
471}
472
Matt Spinler075e5ba2020-02-21 15:46:00 -0600473bool SRC::isBMCSRC() const
474{
475 auto as = asciiString();
476 if (as.length() >= 2)
477 {
478 uint8_t errorType = strtoul(as.substr(0, 2).c_str(), nullptr, 16);
479 return (errorType == static_cast<uint8_t>(SRCType::bmcError) ||
480 errorType == static_cast<uint8_t>(SRCType::powerError));
481 }
482 return false;
483}
484
Matt Spinler4deed972023-04-28 14:09:22 -0500485bool SRC::isHostbootSRC() const
486{
487 auto as = asciiString();
488 if (as.length() >= 2)
489 {
490 uint8_t errorType = strtoul(as.substr(0, 2).c_str(), nullptr, 16);
491 return errorType == static_cast<uint8_t>(SRCType::hostbootError);
492 }
493 return false;
494}
495
Patrick Williams075c7922024-08-16 15:19:49 -0400496std::optional<std::string> SRC::getErrorDetails(
497 message::Registry& registry, DetailLevel type, bool toCache) const
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800498{
499 const std::string jsonIndent(indentLevel, 0x20);
500 std::string errorOut;
Matt Spinler075e5ba2020-02-21 15:46:00 -0600501 if (isBMCSRC())
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800502 {
503 auto entry = registry.lookup("0x" + asciiString().substr(4, 4),
504 rg::LookupType::reasonCode, toCache);
505 if (entry)
506 {
507 errorOut.append(jsonIndent + "\"Error Details\": {\n");
508 auto errorMsg = getErrorMessage(*entry);
509 if (errorMsg)
510 {
511 if (type == DetailLevel::message)
512 {
513 return errorMsg.value();
514 }
515 else
516 {
517 jsonInsert(errorOut, "Message", errorMsg.value(), 2);
518 }
519 }
520 if (entry->src.hexwordADFields)
521 {
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800522 std::map<size_t, std::tuple<std::string, std::string>>
523 adFields = entry->src.hexwordADFields.value();
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800524 for (const auto& hexwordMap : adFields)
525 {
Zane Shelleye8db29b2021-11-13 10:34:07 -0600526 auto srcValue = getNumberString(
Harisuddin Mohamed Isa1a1b0df2020-11-23 16:34:36 +0800527 "0x%X",
Zane Shelleye8db29b2021-11-13 10:34:07 -0600528 _hexData[getWordIndexFromWordNum(hexwordMap.first)]);
529
530 auto srcKey = std::get<0>(hexwordMap.second);
531 auto srcDesc = std::get<1>(hexwordMap.second);
532
533 // Only include this hex word in the error details if the
534 // description exists.
535 if (!srcDesc.empty())
536 {
537 std::vector<std::string> valueDescr;
538 valueDescr.push_back(srcValue);
539 valueDescr.push_back(srcDesc);
540 jsonInsertArray(errorOut, srcKey, valueDescr, 2);
541 }
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800542 }
543 }
544 errorOut.erase(errorOut.size() - 2);
545 errorOut.append("\n");
546 errorOut.append(jsonIndent + "},\n");
547 return errorOut;
548 }
549 }
550 return std::nullopt;
551}
552
Patrick Williams25291152025-02-01 08:21:42 -0500553std::optional<std::string> SRC::getErrorMessage(
554 const message::Entry& regEntry) const
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800555{
556 try
557 {
558 if (regEntry.doc.messageArgSources)
559 {
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800560 std::vector<uint32_t> argSourceVals;
561 std::string message;
562 const auto& argValues = regEntry.doc.messageArgSources.value();
563 for (size_t i = 0; i < argValues.size(); ++i)
564 {
565 argSourceVals.push_back(_hexData[getWordIndexFromWordNum(
566 argValues[i].back() - '0')]);
567 }
Patrick Williams0230abb2021-04-19 14:32:50 -0500568
569 auto it = std::begin(regEntry.doc.message);
570 auto it_end = std::end(regEntry.doc.message);
571
572 while (it != it_end)
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800573 {
Patrick Williams0230abb2021-04-19 14:32:50 -0500574 if (*it == '%')
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800575 {
Patrick Williams0230abb2021-04-19 14:32:50 -0500576 ++it;
577
578 size_t wordIndex = *it - '0';
579 if (isdigit(*it) && wordIndex >= 1 &&
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800580 static_cast<uint16_t>(wordIndex) <=
581 argSourceVals.size())
582 {
583 message.append(getNumberString(
Zane Shelley39936e32021-11-13 16:19:34 -0600584 "0x%08X", argSourceVals[wordIndex - 1]));
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800585 }
586 else
587 {
Patrick Williams0230abb2021-04-19 14:32:50 -0500588 message.append("%" + std::string(1, *it));
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800589 }
590 }
591 else
592 {
Patrick Williams0230abb2021-04-19 14:32:50 -0500593 message.push_back(*it);
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800594 }
Patrick Williams0230abb2021-04-19 14:32:50 -0500595 ++it;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800596 }
Patrick Williams0230abb2021-04-19 14:32:50 -0500597
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800598 return message;
599 }
600 else
601 {
602 return regEntry.doc.message;
603 }
604 }
605 catch (const std::exception& e)
606 {
Matt Spinler0bacc8e2023-07-07 16:25:39 -0500607 lg2::error(
608 "Cannot get error message from registry entry, error = {ERROR}",
609 "ERROR", e);
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800610 }
611 return std::nullopt;
612}
613
614std::optional<std::string> SRC::getCallouts() const
615{
616 if (!_callouts)
617 {
618 return std::nullopt;
619 }
620 std::string printOut;
621 const std::string jsonIndent(indentLevel, 0x20);
622 const auto& callout = _callouts->callouts();
623 const auto& compDescrp = pv::failingComponentType;
624 printOut.append(jsonIndent + "\"Callout Section\": {\n");
625 jsonInsert(printOut, "Callout Count", std::to_string(callout.size()), 2);
626 printOut.append(jsonIndent + jsonIndent + "\"Callouts\": [");
627 for (auto& entry : callout)
628 {
629 printOut.append("{\n");
630 if (entry->fruIdentity())
631 {
632 jsonInsert(
633 printOut, "FRU Type",
634 compDescrp.at(entry->fruIdentity()->failingComponentType()), 3);
635 jsonInsert(printOut, "Priority",
636 pv::getValue(entry->priority(),
637 pel_values::calloutPriorityValues),
638 3);
639 if (!entry->locationCode().empty())
640 {
641 jsonInsert(printOut, "Location Code", entry->locationCode(), 3);
642 }
643 if (entry->fruIdentity()->getPN().has_value())
644 {
645 jsonInsert(printOut, "Part Number",
646 entry->fruIdentity()->getPN().value(), 3);
647 }
648 if (entry->fruIdentity()->getMaintProc().has_value())
649 {
Matt Spinler9e8b49e2020-09-10 13:15:26 -0500650 jsonInsert(printOut, "Procedure",
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800651 entry->fruIdentity()->getMaintProc().value(), 3);
652 if (pv::procedureDesc.find(
653 entry->fruIdentity()->getMaintProc().value()) !=
654 pv::procedureDesc.end())
655 {
656 jsonInsert(
657 printOut, "Description",
658 pv::procedureDesc.at(
659 entry->fruIdentity()->getMaintProc().value()),
660 3);
661 }
662 }
663 if (entry->fruIdentity()->getCCIN().has_value())
664 {
665 jsonInsert(printOut, "CCIN",
666 entry->fruIdentity()->getCCIN().value(), 3);
667 }
668 if (entry->fruIdentity()->getSN().has_value())
669 {
670 jsonInsert(printOut, "Serial Number",
671 entry->fruIdentity()->getSN().value(), 3);
672 }
673 }
674 if (entry->pceIdentity())
675 {
676 const auto& pceIdentMtms = entry->pceIdentity()->mtms();
677 if (!pceIdentMtms.machineTypeAndModel().empty())
678 {
679 jsonInsert(printOut, "PCE MTMS",
680 pceIdentMtms.machineTypeAndModel() + "_" +
681 pceIdentMtms.machineSerialNumber(),
682 3);
683 }
684 if (!entry->pceIdentity()->enclosureName().empty())
685 {
686 jsonInsert(printOut, "PCE Name",
687 entry->pceIdentity()->enclosureName(), 3);
688 }
689 }
690 if (entry->mru())
691 {
692 const auto& mruCallouts = entry->mru()->mrus();
693 std::string mruId;
694 for (auto& element : mruCallouts)
695 {
696 if (!mruId.empty())
697 {
698 mruId.append(", " + getNumberString("%08X", element.id));
699 }
700 else
701 {
702 mruId.append(getNumberString("%08X", element.id));
703 }
704 }
705 jsonInsert(printOut, "MRU Id", mruId, 3);
706 }
707 printOut.erase(printOut.size() - 2);
708 printOut.append("\n" + jsonIndent + jsonIndent + "}, ");
709 };
710 printOut.erase(printOut.size() - 2);
711 printOut.append("]\n" + jsonIndent + "}");
712 return printOut;
713}
714
Patrick Williams25291152025-02-01 08:21:42 -0500715std::optional<std::string> SRC::getJSON(message::Registry& registry,
716 const std::vector<std::string>& plugins
717 [[maybe_unused]],
718 uint8_t creatorID) const
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800719{
720 std::string ps;
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800721 std::vector<std::string> hexwords;
Harisuddin Mohamed Isabebeb942020-03-12 17:12:24 +0800722 jsonInsert(ps, pv::sectionVer, getNumberString("%d", _header.version), 1);
723 jsonInsert(ps, pv::subSection, getNumberString("%d", _header.subType), 1);
Matt Spinlerb832aa52023-03-21 15:32:34 -0500724 jsonInsert(ps, pv::createdBy,
725 getComponentName(_header.componentID, creatorID), 1);
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800726 jsonInsert(ps, "SRC Version", getNumberString("0x%02X", _version), 1);
Harisuddin Mohamed Isac32e5512020-02-06 18:05:21 +0800727 jsonInsert(ps, "SRC Format", getNumberString("0x%02X", _hexData[0] & 0xFF),
728 1);
729 jsonInsert(ps, "Virtual Progress SRC",
730 pv::boolString.at(_flags & virtualProgressSRC), 1);
731 jsonInsert(ps, "I5/OS Service Event Bit",
732 pv::boolString.at(_flags & i5OSServiceEventBit), 1);
733 jsonInsert(ps, "Hypervisor Dump Initiated",
734 pv::boolString.at(_flags & hypDumpInit), 1);
Matt Spinler075e5ba2020-02-21 15:46:00 -0600735
736 if (isBMCSRC())
737 {
738 std::string ccinString;
739 uint32_t ccin = _hexData[1] >> 16;
740
741 if (ccin)
742 {
743 ccinString = getNumberString("%04X", ccin);
744 }
745 // The PEL spec calls it a backplane, so call it that here.
746 jsonInsert(ps, "Backplane CCIN", ccinString, 1);
Matt Spinlerafa2c792020-08-27 11:01:39 -0500747
Sumit Kumar3e274432021-09-14 06:37:56 -0500748 jsonInsert(ps, "Terminate FW Error",
749 pv::boolString.at(
750 _hexData[3] &
751 static_cast<uint32_t>(ErrorStatusFlags::terminateFwErr)),
752 1);
Matt Spinler4deed972023-04-28 14:09:22 -0500753 }
754
755 if (isBMCSRC() || isHostbootSRC())
756 {
Matt Spinlerafa2c792020-08-27 11:01:39 -0500757 jsonInsert(ps, "Deconfigured",
758 pv::boolString.at(
759 _hexData[3] &
760 static_cast<uint32_t>(ErrorStatusFlags::deconfigured)),
761 1);
762
763 jsonInsert(
764 ps, "Guarded",
Patrick Williams075c7922024-08-16 15:19:49 -0400765 pv::boolString.at(
766 _hexData[3] & static_cast<uint32_t>(ErrorStatusFlags::guarded)),
Matt Spinlerafa2c792020-08-27 11:01:39 -0500767 1);
Matt Spinler075e5ba2020-02-21 15:46:00 -0600768 }
769
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800770 auto errorDetails = getErrorDetails(registry, DetailLevel::json, true);
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800771 if (errorDetails)
772 {
773 ps.append(errorDetails.value());
774 }
775 jsonInsert(ps, "Valid Word Count", getNumberString("0x%02X", _wordCount),
776 1);
777 std::string refcode = asciiString();
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800778 hexwords.push_back(refcode);
Harisuddin Mohamed Isafecaa572020-03-11 16:04:50 +0800779 std::string extRefcode;
780 size_t pos = refcode.find(0x20);
781 if (pos != std::string::npos)
782 {
783 size_t nextPos = refcode.find_first_not_of(0x20, pos);
784 if (nextPos != std::string::npos)
785 {
786 extRefcode = trimEnd(refcode.substr(nextPos));
787 }
788 refcode.erase(pos);
789 }
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800790 jsonInsert(ps, "Reference Code", refcode, 1);
Harisuddin Mohamed Isafecaa572020-03-11 16:04:50 +0800791 if (!extRefcode.empty())
792 {
793 jsonInsert(ps, "Extended Reference Code", extRefcode, 1);
794 }
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800795 for (size_t i = 2; i <= _wordCount; i++)
796 {
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800797 std::string tmpWord =
798 getNumberString("%08X", _hexData[getWordIndexFromWordNum(i)]);
799 jsonInsert(ps, "Hex Word " + std::to_string(i), tmpWord, 1);
800 hexwords.push_back(tmpWord);
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800801 }
802 auto calloutJson = getCallouts();
803 if (calloutJson)
804 {
805 ps.append(calloutJson.value());
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800806 ps.append(",\n");
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800807 }
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800808 std::string subsystem = getNumberString("%c", tolower(creatorID));
809 bool srcDetailExists = false;
810#ifdef PELTOOL
811 if (std::find(plugins.begin(), plugins.end(), subsystem + "src") !=
812 plugins.end())
813 {
814 auto pyJson = getPythonJSON(hexwords, creatorID);
815 if (pyJson)
816 {
817 ps.append(pyJson.value());
818 srcDetailExists = true;
819 }
820 }
821#endif
822 if (!srcDetailExists)
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800823 {
824 ps.erase(ps.size() - 2);
825 }
826 return ps;
827}
828
Matt Spinler03984582020-04-09 13:17:58 -0500829void SRC::addCallouts(const message::Entry& regEntry,
830 const AdditionalData& additionalData,
Matt Spinler5a90a952020-08-27 09:39:03 -0500831 const nlohmann::json& jsonCallouts,
Matt Spinlered046852020-03-13 13:58:15 -0500832 const DataInterfaceBase& dataIface)
833{
Patrick Williams075c7922024-08-16 15:19:49 -0400834 auto registryCallouts =
835 getRegistryCallouts(regEntry, additionalData, dataIface);
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500836
Matt Spinlered046852020-03-13 13:58:15 -0500837 auto item = additionalData.getValue("CALLOUT_INVENTORY_PATH");
Miguel Gomez53ef1552020-10-14 21:16:32 +0000838 auto priority = additionalData.getValue("CALLOUT_PRIORITY");
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500839
Miguel Gomez53ef1552020-10-14 21:16:32 +0000840 std::optional<CalloutPriority> calloutPriority;
841
842 // Only H, M or L priority values.
843 if (priority && !(*priority).empty())
844 {
845 uint8_t p = (*priority)[0];
846 if (p == 'H' || p == 'M' || p == 'L')
847 {
848 calloutPriority = static_cast<CalloutPriority>(p);
849 }
850 }
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500851 // If the first registry callout says to use the passed in inventory
852 // path to get the location code for a symbolic FRU callout with a
853 // trusted location code, then do not add the inventory path as a
854 // normal FRU callout.
855 bool useInvForSymbolicFRULocCode =
856 !registryCallouts.empty() && registryCallouts[0].useInventoryLocCode &&
857 !registryCallouts[0].symbolicFRUTrusted.empty();
858
859 if (item && !useInvForSymbolicFRULocCode)
Matt Spinlered046852020-03-13 13:58:15 -0500860 {
Miguel Gomez53ef1552020-10-14 21:16:32 +0000861 addInventoryCallout(*item, calloutPriority, std::nullopt, dataIface);
Matt Spinlered046852020-03-13 13:58:15 -0500862 }
863
Matt Spinler717de422020-06-04 13:10:14 -0500864 addDevicePathCallouts(additionalData, dataIface);
Matt Spinler03984582020-04-09 13:17:58 -0500865
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500866 addRegistryCallouts(registryCallouts, dataIface,
867 (useInvForSymbolicFRULocCode) ? item : std::nullopt);
Matt Spinler5a90a952020-08-27 09:39:03 -0500868
869 if (!jsonCallouts.empty())
870 {
871 addJSONCallouts(jsonCallouts, dataIface);
872 }
Matt Spinlered046852020-03-13 13:58:15 -0500873}
874
Matt Spinler7b923722025-03-19 13:17:23 -0500875void SRC::addLocationCodeOnlyCallout(const std::string& locationCode,
876 const CalloutPriority priority)
877{
878 std::string empty;
879 std::vector<src::MRU::MRUCallout> mrus;
880 auto callout = std::make_unique<src::Callout>(priority, locationCode, empty,
881 empty, empty, mrus);
882 createCalloutsObject();
883 _callouts->addCallout(std::move(callout));
884}
885
Matt Spinlered046852020-03-13 13:58:15 -0500886void SRC::addInventoryCallout(const std::string& inventoryPath,
Matt Spinleraf191c72020-06-04 11:35:13 -0500887 const std::optional<CalloutPriority>& priority,
888 const std::optional<std::string>& locationCode,
Matt Spinlerb8cb60f2020-08-27 10:55:55 -0500889 const DataInterfaceBase& dataIface,
890 const std::vector<src::MRU::MRUCallout>& mrus)
Matt Spinlered046852020-03-13 13:58:15 -0500891{
892 std::string locCode;
893 std::string fn;
894 std::string ccin;
895 std::string sn;
896 std::unique_ptr<src::Callout> callout;
897
Matt Spinlered046852020-03-13 13:58:15 -0500898 try
899 {
Matt Spinleraf191c72020-06-04 11:35:13 -0500900 // Use the passed in location code if there otherwise look it up
901 if (locationCode)
902 {
903 locCode = *locationCode;
904 }
905 else
906 {
907 locCode = dataIface.getLocationCode(inventoryPath);
908 }
Matt Spinlered046852020-03-13 13:58:15 -0500909
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500910 try
911 {
912 dataIface.getHWCalloutFields(inventoryPath, fn, ccin, sn);
913
Patrick Williams075c7922024-08-16 15:19:49 -0400914 CalloutPriority p =
915 priority ? priority.value() : CalloutPriority::high;
Matt Spinleraf191c72020-06-04 11:35:13 -0500916
Patrick Williams075c7922024-08-16 15:19:49 -0400917 callout =
918 std::make_unique<src::Callout>(p, locCode, fn, ccin, sn, mrus);
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500919 }
Patrick Williams45e83522022-07-22 19:26:52 -0500920 catch (const sdbusplus::exception_t& e)
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500921 {
Patrick Williams075c7922024-08-16 15:19:49 -0400922 std::string msg =
923 "No VPD found for " + inventoryPath + ": " + e.what();
Matt Spinler85f61a62020-06-03 16:28:55 -0500924 addDebugData(msg);
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500925
926 // Just create the callout with empty FRU fields
Matt Spinlerb8cb60f2020-08-27 10:55:55 -0500927 callout = std::make_unique<src::Callout>(
928 CalloutPriority::high, locCode, fn, ccin, sn, mrus);
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500929 }
Matt Spinlered046852020-03-13 13:58:15 -0500930 }
Patrick Williams45e83522022-07-22 19:26:52 -0500931 catch (const sdbusplus::exception_t& e)
Matt Spinlered046852020-03-13 13:58:15 -0500932 {
Matt Spinler85f61a62020-06-03 16:28:55 -0500933 std::string msg = "Could not get location code for " + inventoryPath +
934 ": " + e.what();
935 addDebugData(msg);
Matt Spinlered046852020-03-13 13:58:15 -0500936
Matt Spinler479b6922021-08-17 16:34:59 -0500937 // Don't add a callout in this case, because:
938 // 1) With how the inventory is primed, there is no case where
939 // a location code is expected to be missing. This implies
940 // the caller is passing in something invalid.
941 // 2) The addDebugData call above will put the passed in path into
942 // a user data section that can be seen by development for debug.
943 // 3) Even if we wanted to do a 'no_vpd_for_fru' sort of maint.
944 // procedure, we don't have a good way to indicate to the user
945 // anything about the intended callout (they won't see user data).
946 // 4) Creating a new standalone event log for this problem isn't
947 // possible from inside a PEL section.
Matt Spinlered046852020-03-13 13:58:15 -0500948 }
949
Matt Spinler479b6922021-08-17 16:34:59 -0500950 if (callout)
951 {
952 createCalloutsObject();
953 _callouts->addCallout(std::move(callout));
954 }
Matt Spinler03984582020-04-09 13:17:58 -0500955}
Matt Spinlered046852020-03-13 13:58:15 -0500956
Patrick Williams075c7922024-08-16 15:19:49 -0400957std::vector<message::RegistryCallout> SRC::getRegistryCallouts(
958 const message::Entry& regEntry, const AdditionalData& additionalData,
959 const DataInterfaceBase& dataIface)
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500960{
961 std::vector<message::RegistryCallout> registryCallouts;
962
963 if (regEntry.callouts)
964 {
Matt Spinler9a50c8d2021-04-12 14:22:26 -0500965 std::vector<std::string> systemNames;
966
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500967 try
968 {
Matt Spinler9a50c8d2021-04-12 14:22:26 -0500969 systemNames = dataIface.getSystemNames();
970 }
971 catch (const std::exception& e)
972 {
973 // Compatible interface not available yet
974 }
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500975
Matt Spinler9a50c8d2021-04-12 14:22:26 -0500976 try
977 {
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500978 registryCallouts = message::Registry::getCallouts(
979 regEntry.callouts.value(), systemNames, additionalData);
980 }
981 catch (const std::exception& e)
982 {
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -0500983 addDebugData(std::format(
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500984 "Error parsing PEL message registry callout JSON: {}",
985 e.what()));
986 }
987 }
988
989 return registryCallouts;
990}
991
992void SRC::addRegistryCallouts(
993 const std::vector<message::RegistryCallout>& callouts,
994 const DataInterfaceBase& dataIface,
995 std::optional<std::string> trustedSymbolicFRUInvPath)
Matt Spinler03984582020-04-09 13:17:58 -0500996{
997 try
998 {
Matt Spinlerf00f9d02020-10-23 09:14:22 -0500999 for (const auto& callout : callouts)
Matt Spinler03984582020-04-09 13:17:58 -05001000 {
Matt Spinlerf00f9d02020-10-23 09:14:22 -05001001 addRegistryCallout(callout, dataIface, trustedSymbolicFRUInvPath);
1002
1003 // Only the first callout gets the inventory path
1004 if (trustedSymbolicFRUInvPath)
1005 {
1006 trustedSymbolicFRUInvPath = std::nullopt;
1007 }
Matt Spinler03984582020-04-09 13:17:58 -05001008 }
1009 }
Patrick Williams66491c62021-10-06 12:23:37 -05001010 catch (const std::exception& e)
Matt Spinler03984582020-04-09 13:17:58 -05001011 {
Patrick Williams075c7922024-08-16 15:19:49 -04001012 std::string msg =
1013 "Error parsing PEL message registry callout JSON: "s + e.what();
Matt Spinler85f61a62020-06-03 16:28:55 -05001014 addDebugData(msg);
Matt Spinler03984582020-04-09 13:17:58 -05001015 }
1016}
1017
Matt Spinlerf00f9d02020-10-23 09:14:22 -05001018void SRC::addRegistryCallout(
1019 const message::RegistryCallout& regCallout,
1020 const DataInterfaceBase& dataIface,
1021 const std::optional<std::string>& trustedSymbolicFRUInvPath)
Matt Spinler03984582020-04-09 13:17:58 -05001022{
1023 std::unique_ptr<src::Callout> callout;
Matt Spinler03984582020-04-09 13:17:58 -05001024 auto locCode = regCallout.locCode;
Matt Spinler7b923722025-03-19 13:17:23 -05001025 bool locExpanded = true;
Matt Spinler03984582020-04-09 13:17:58 -05001026
Matt Spinleraf191c72020-06-04 11:35:13 -05001027 if (!locCode.empty())
1028 {
1029 try
1030 {
1031 locCode = dataIface.expandLocationCode(locCode, 0);
1032 }
1033 catch (const std::exception& e)
1034 {
Patrick Williams2544b412022-10-04 08:41:06 -05001035 auto msg = "Unable to expand location code " + locCode + ": " +
1036 e.what();
Matt Spinleraf191c72020-06-04 11:35:13 -05001037 addDebugData(msg);
Matt Spinler7b923722025-03-19 13:17:23 -05001038 locExpanded = false;
Matt Spinleraf191c72020-06-04 11:35:13 -05001039 }
1040 }
1041
Matt Spinler03984582020-04-09 13:17:58 -05001042 // Via the PEL values table, get the priority enum.
1043 // The schema will have validated the priority was a valid value.
Patrick Williams075c7922024-08-16 15:19:49 -04001044 auto priorityIt =
1045 pv::findByName(regCallout.priority, pv::calloutPriorityValues);
Matt Spinler03984582020-04-09 13:17:58 -05001046 assert(priorityIt != pv::calloutPriorityValues.end());
1047 auto priority =
1048 static_cast<CalloutPriority>(std::get<pv::fieldValuePos>(*priorityIt));
1049
1050 if (!regCallout.procedure.empty())
1051 {
1052 // Procedure callout
Matt Spinler2edce4e2024-01-17 11:13:51 -06001053 callout = std::make_unique<src::Callout>(priority, regCallout.procedure,
1054 src::CalloutValueType::raw);
Matt Spinler03984582020-04-09 13:17:58 -05001055 }
1056 else if (!regCallout.symbolicFRU.empty())
1057 {
1058 // Symbolic FRU callout
1059 callout = std::make_unique<src::Callout>(
1060 priority, regCallout.symbolicFRU, locCode, false);
1061 }
1062 else if (!regCallout.symbolicFRUTrusted.empty())
1063 {
1064 // Symbolic FRU with trusted location code callout
Matt Spinler7b923722025-03-19 13:17:23 -05001065 bool trusted = false;
Matt Spinler03984582020-04-09 13:17:58 -05001066
Matt Spinlerf00f9d02020-10-23 09:14:22 -05001067 // Use the location code from the inventory path if there is one.
1068 if (trustedSymbolicFRUInvPath)
1069 {
1070 try
1071 {
1072 locCode = dataIface.getLocationCode(*trustedSymbolicFRUInvPath);
Matt Spinler7b923722025-03-19 13:17:23 -05001073 trusted = true;
Matt Spinlerf00f9d02020-10-23 09:14:22 -05001074 }
1075 catch (const std::exception& e)
1076 {
1077 addDebugData(
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -05001078 std::format("Could not get location code for {}: {}",
Matt Spinlerf00f9d02020-10-23 09:14:22 -05001079 *trustedSymbolicFRUInvPath, e.what()));
1080 locCode.clear();
1081 }
1082 }
1083
Matt Spinler7b923722025-03-19 13:17:23 -05001084 // Can only trust the location code if it isn't empty and is expanded.
1085 if (!locCode.empty() && locExpanded)
1086 {
1087 trusted = true;
1088 }
1089
Matt Spinler03984582020-04-09 13:17:58 -05001090 // The registry wants it to be trusted, but that requires a valid
1091 // location code for it to actually be.
1092 callout = std::make_unique<src::Callout>(
Matt Spinler7b923722025-03-19 13:17:23 -05001093 priority, regCallout.symbolicFRUTrusted, locCode, trusted);
Matt Spinler03984582020-04-09 13:17:58 -05001094 }
1095 else
1096 {
Matt Spinleraf191c72020-06-04 11:35:13 -05001097 // A hardware callout
Matt Spinler7b923722025-03-19 13:17:23 -05001098
1099 // If couldn't expand the location code, don't bother
1100 // looking up the inventory path.
1101 if (!locExpanded && !locCode.empty())
1102 {
1103 addLocationCodeOnlyCallout(locCode, priority);
1104 return;
1105 }
1106
Matt Spinlerbad056b2023-01-25 14:16:57 -06001107 std::vector<std::string> inventoryPaths;
Matt Spinleraf191c72020-06-04 11:35:13 -05001108
1109 try
1110 {
1111 // Get the inventory item from the unexpanded location code
Matt Spinlerbad056b2023-01-25 14:16:57 -06001112 inventoryPaths =
Matt Spinler2f9225a2020-08-05 12:58:49 -05001113 dataIface.getInventoryFromLocCode(regCallout.locCode, 0, false);
Matt Spinleraf191c72020-06-04 11:35:13 -05001114 }
1115 catch (const std::exception& e)
1116 {
1117 std::string msg =
1118 "Unable to get inventory path from location code: " + locCode +
1119 ": " + e.what();
1120 addDebugData(msg);
Matt Spinler7b923722025-03-19 13:17:23 -05001121 if (!locCode.empty())
1122 {
1123 // Still add a callout with just the location code.
1124 addLocationCodeOnlyCallout(locCode, priority);
1125 }
Matt Spinleraf191c72020-06-04 11:35:13 -05001126 return;
1127 }
1128
Matt Spinlerbad056b2023-01-25 14:16:57 -06001129 // Just use first path returned since they all point to the same FRU.
1130 addInventoryCallout(inventoryPaths[0], priority, locCode, dataIface);
Matt Spinler03984582020-04-09 13:17:58 -05001131 }
1132
1133 if (callout)
1134 {
1135 createCalloutsObject();
1136 _callouts->addCallout(std::move(callout));
1137 }
1138}
Matt Spinlered046852020-03-13 13:58:15 -05001139
Matt Spinler717de422020-06-04 13:10:14 -05001140void SRC::addDevicePathCallouts(const AdditionalData& additionalData,
1141 const DataInterfaceBase& dataIface)
1142{
1143 std::vector<device_callouts::Callout> callouts;
1144 auto i2cBus = additionalData.getValue("CALLOUT_IIC_BUS");
1145 auto i2cAddr = additionalData.getValue("CALLOUT_IIC_ADDR");
1146 auto devPath = additionalData.getValue("CALLOUT_DEVICE_PATH");
1147
1148 // A device callout contains either:
1149 // * CALLOUT_ERRNO, CALLOUT_DEVICE_PATH
1150 // * CALLOUT_ERRNO, CALLOUT_IIC_BUS, CALLOUT_IIC_ADDR
1151 // We don't care about the errno.
1152
1153 if (devPath)
1154 {
1155 try
1156 {
1157 callouts = device_callouts::getCallouts(*devPath,
1158 dataIface.getSystemNames());
1159 }
1160 catch (const std::exception& e)
1161 {
1162 addDebugData(e.what());
1163 callouts.clear();
1164 }
1165 }
1166 else if (i2cBus && i2cAddr)
1167 {
1168 size_t bus;
1169 uint8_t address;
1170
1171 try
1172 {
1173 // If /dev/i2c- is prepended, remove it
1174 if (i2cBus->find("/dev/i2c-") != std::string::npos)
1175 {
1176 *i2cBus = i2cBus->substr(9);
1177 }
1178
1179 bus = stoul(*i2cBus, nullptr, 0);
1180 address = stoul(*i2cAddr, nullptr, 0);
1181 }
1182 catch (const std::exception& e)
1183 {
Patrick Williams075c7922024-08-16 15:19:49 -04001184 std::string msg =
1185 "Invalid CALLOUT_IIC_BUS " + *i2cBus + " or CALLOUT_IIC_ADDR " +
1186 *i2cAddr + " in AdditionalData property";
Matt Spinler717de422020-06-04 13:10:14 -05001187 addDebugData(msg);
1188 return;
1189 }
1190
1191 try
1192 {
1193 callouts = device_callouts::getI2CCallouts(
1194 bus, address, dataIface.getSystemNames());
1195 }
1196 catch (const std::exception& e)
1197 {
1198 addDebugData(e.what());
1199 callouts.clear();
1200 }
1201 }
1202
1203 for (const auto& callout : callouts)
1204 {
1205 // The priority shouldn't be invalid, but check just in case.
1206 CalloutPriority priority = CalloutPriority::high;
1207
1208 if (!callout.priority.empty())
1209 {
1210 auto p = pel_values::findByValue(
1211 static_cast<uint32_t>(callout.priority[0]),
1212 pel_values::calloutPriorityValues);
1213
1214 if (p != pel_values::calloutPriorityValues.end())
1215 {
1216 priority = static_cast<CalloutPriority>(callout.priority[0]);
1217 }
1218 else
1219 {
Matt Spinlerd7654dc2025-05-09 11:47:50 -05001220 auto msg =
1221 std::string{
1222 "Invalid priority found in dev callout JSON: "} +
Matt Spinler717de422020-06-04 13:10:14 -05001223 callout.priority[0];
1224 addDebugData(msg);
1225 }
1226 }
1227
Matt Spinler0d92b522021-06-16 13:28:17 -06001228 std::optional<std::string> locCode;
1229
1230 try
1231 {
1232 locCode = dataIface.expandLocationCode(callout.locationCode, 0);
1233 }
1234 catch (const std::exception& e)
1235 {
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -05001236 auto msg = std::format("Unable to expand location code {}: {}",
Matt Spinler0d92b522021-06-16 13:28:17 -06001237 callout.locationCode, e.what());
1238 addDebugData(msg);
Matt Spinler7b923722025-03-19 13:17:23 -05001239
1240 // Add the callout with just the unexpanded location code.
1241 addLocationCodeOnlyCallout(callout.locationCode, priority);
1242 continue;
Matt Spinler0d92b522021-06-16 13:28:17 -06001243 }
1244
Matt Spinler717de422020-06-04 13:10:14 -05001245 try
1246 {
Matt Spinlerbad056b2023-01-25 14:16:57 -06001247 auto inventoryPaths = dataIface.getInventoryFromLocCode(
Matt Spinler2f9225a2020-08-05 12:58:49 -05001248 callout.locationCode, 0, false);
Matt Spinler717de422020-06-04 13:10:14 -05001249
Matt Spinlerbad056b2023-01-25 14:16:57 -06001250 // Just use first path returned since they all
1251 // point to the same FRU.
1252 addInventoryCallout(inventoryPaths[0], priority, locCode,
1253 dataIface);
Matt Spinler717de422020-06-04 13:10:14 -05001254 }
1255 catch (const std::exception& e)
1256 {
1257 std::string msg =
1258 "Unable to get inventory path from location code: " +
1259 callout.locationCode + ": " + e.what();
1260 addDebugData(msg);
Matt Spinler7b923722025-03-19 13:17:23 -05001261 // Add the callout with just the location code.
1262 addLocationCodeOnlyCallout(callout.locationCode, priority);
1263 continue;
Matt Spinler717de422020-06-04 13:10:14 -05001264 }
1265
1266 // Until the code is there to convert these MRU value strings to
1267 // the official MRU values in the callout objects, just store
1268 // the MRU name in the debug UserData section.
1269 if (!callout.mru.empty())
1270 {
1271 std::string msg = "MRU: " + callout.mru;
1272 addDebugData(msg);
1273 }
1274
1275 // getCallouts() may have generated some debug data it stored
1276 // in a callout object. Save it as well.
1277 if (!callout.debug.empty())
1278 {
1279 addDebugData(callout.debug);
1280 }
1281 }
1282}
1283
Matt Spinler5a90a952020-08-27 09:39:03 -05001284void SRC::addJSONCallouts(const nlohmann::json& jsonCallouts,
1285 const DataInterfaceBase& dataIface)
1286{
1287 if (jsonCallouts.empty())
1288 {
1289 return;
1290 }
1291
1292 if (!jsonCallouts.is_array())
1293 {
1294 addDebugData("Callout JSON isn't an array");
1295 return;
1296 }
1297
1298 for (const auto& callout : jsonCallouts)
1299 {
1300 try
1301 {
1302 addJSONCallout(callout, dataIface);
1303 }
1304 catch (const std::exception& e)
1305 {
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -05001306 addDebugData(std::format(
Matt Spinler5a90a952020-08-27 09:39:03 -05001307 "Failed extracting callout data from JSON: {}", e.what()));
1308 }
1309 }
1310}
1311
1312void SRC::addJSONCallout(const nlohmann::json& jsonCallout,
1313 const DataInterfaceBase& dataIface)
1314{
Matt Spinler3bdd0112020-08-27 10:24:34 -05001315 auto priority = getPriorityFromJSON(jsonCallout);
1316 std::string locCode;
1317 std::string unexpandedLocCode;
1318 std::unique_ptr<src::Callout> callout;
1319
1320 // Expand the location code if it's there
1321 if (jsonCallout.contains("LocationCode"))
1322 {
1323 unexpandedLocCode = jsonCallout.at("LocationCode").get<std::string>();
1324
1325 try
1326 {
1327 locCode = dataIface.expandLocationCode(unexpandedLocCode, 0);
1328 }
1329 catch (const std::exception& e)
1330 {
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -05001331 addDebugData(std::format("Unable to expand location code {}: {}",
Matt Spinler3bdd0112020-08-27 10:24:34 -05001332 unexpandedLocCode, e.what()));
1333 // Use the value from the JSON so at least there's something
1334 locCode = unexpandedLocCode;
1335 }
1336 }
1337
1338 // Create either a procedure, symbolic FRU, or normal FRU callout.
1339 if (jsonCallout.contains("Procedure"))
1340 {
1341 auto procedure = jsonCallout.at("Procedure").get<std::string>();
1342
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001343 // If it's the registry name instead of the raw name, convert.
1344 if (pv::maintenanceProcedures.find(procedure) !=
1345 pv::maintenanceProcedures.end())
1346 {
1347 procedure = pv::maintenanceProcedures.at(procedure);
1348 }
1349
Matt Spinler3bdd0112020-08-27 10:24:34 -05001350 callout = std::make_unique<src::Callout>(
1351 static_cast<CalloutPriority>(priority), procedure,
1352 src::CalloutValueType::raw);
1353 }
1354 else if (jsonCallout.contains("SymbolicFRU"))
1355 {
1356 auto fru = jsonCallout.at("SymbolicFRU").get<std::string>();
1357
Matt Spinler3c7ec6d2022-05-06 08:50:20 -05001358 // If it's the registry name instead of the raw name, convert.
1359 if (pv::symbolicFRUs.find(fru) != pv::symbolicFRUs.end())
1360 {
1361 fru = pv::symbolicFRUs.at(fru);
1362 }
1363
Matt Spinler3bdd0112020-08-27 10:24:34 -05001364 bool trusted = false;
1365 if (jsonCallout.contains("TrustedLocationCode") && !locCode.empty())
1366 {
1367 trusted = jsonCallout.at("TrustedLocationCode").get<bool>();
1368 }
1369
1370 callout = std::make_unique<src::Callout>(
1371 static_cast<CalloutPriority>(priority), fru,
1372 src::CalloutValueType::raw, locCode, trusted);
1373 }
1374 else
1375 {
1376 // A hardware FRU
1377 std::string inventoryPath;
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001378 std::vector<src::MRU::MRUCallout> mrus;
Matt Spinler3bdd0112020-08-27 10:24:34 -05001379
1380 if (jsonCallout.contains("InventoryPath"))
1381 {
1382 inventoryPath = jsonCallout.at("InventoryPath").get<std::string>();
1383 }
1384 else
1385 {
1386 if (unexpandedLocCode.empty())
1387 {
1388 throw std::runtime_error{"JSON callout needs either an "
1389 "inventory path or location code"};
1390 }
1391
1392 try
1393 {
Matt Spinlerbad056b2023-01-25 14:16:57 -06001394 auto inventoryPaths = dataIface.getInventoryFromLocCode(
Matt Spinler3bdd0112020-08-27 10:24:34 -05001395 unexpandedLocCode, 0, false);
Matt Spinlerbad056b2023-01-25 14:16:57 -06001396 // Just use first path returned since they all
1397 // point to the same FRU.
1398 inventoryPath = inventoryPaths[0];
Matt Spinler3bdd0112020-08-27 10:24:34 -05001399 }
1400 catch (const std::exception& e)
1401 {
Matt Spinler7b923722025-03-19 13:17:23 -05001402 addDebugData(std::format("Unable to get inventory path from "
1403 "location code: {}: {}",
1404 unexpandedLocCode, e.what()));
1405 addLocationCodeOnlyCallout(locCode, priority);
1406 return;
Matt Spinler3bdd0112020-08-27 10:24:34 -05001407 }
1408 }
1409
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001410 if (jsonCallout.contains("MRUs"))
1411 {
1412 mrus = getMRUsFromJSON(jsonCallout.at("MRUs"));
1413 }
1414
Matt Spinler3bdd0112020-08-27 10:24:34 -05001415 // If the location code was also passed in, use that here too
1416 // so addInventoryCallout doesn't have to look it up.
1417 std::optional<std::string> lc;
1418 if (!locCode.empty())
1419 {
1420 lc = locCode;
1421 }
1422
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001423 addInventoryCallout(inventoryPath, priority, lc, dataIface, mrus);
Matt Spinlerafa2c792020-08-27 11:01:39 -05001424
1425 if (jsonCallout.contains("Deconfigured"))
1426 {
1427 if (jsonCallout.at("Deconfigured").get<bool>())
1428 {
1429 setErrorStatusFlag(ErrorStatusFlags::deconfigured);
1430 }
1431 }
1432
1433 if (jsonCallout.contains("Guarded"))
1434 {
1435 if (jsonCallout.at("Guarded").get<bool>())
1436 {
1437 setErrorStatusFlag(ErrorStatusFlags::guarded);
1438 }
1439 }
Matt Spinler3bdd0112020-08-27 10:24:34 -05001440 }
1441
1442 if (callout)
1443 {
1444 createCalloutsObject();
1445 _callouts->addCallout(std::move(callout));
1446 }
1447}
1448
1449CalloutPriority SRC::getPriorityFromJSON(const nlohmann::json& json)
1450{
1451 // Looks like:
1452 // {
1453 // "Priority": "H"
1454 // }
1455 auto p = json.at("Priority").get<std::string>();
1456 if (p.empty())
1457 {
1458 throw std::runtime_error{"Priority field in callout is empty"};
1459 }
1460
1461 auto priority = static_cast<CalloutPriority>(p.front());
1462
1463 // Validate it
1464 auto priorityIt = pv::findByValue(static_cast<uint32_t>(priority),
1465 pv::calloutPriorityValues);
1466 if (priorityIt == pv::calloutPriorityValues.end())
1467 {
1468 throw std::runtime_error{
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -05001469 std::format("Invalid priority '{}' found in JSON callout", p)};
Matt Spinler3bdd0112020-08-27 10:24:34 -05001470 }
1471
1472 return priority;
Matt Spinler5a90a952020-08-27 09:39:03 -05001473}
1474
Patrick Williams25291152025-02-01 08:21:42 -05001475std::vector<src::MRU::MRUCallout> SRC::getMRUsFromJSON(
1476 const nlohmann::json& mruJSON)
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001477{
1478 std::vector<src::MRU::MRUCallout> mrus;
1479
1480 // Looks like:
1481 // [
1482 // {
1483 // "ID": 100,
1484 // "Priority": "H"
1485 // }
1486 // ]
1487 if (!mruJSON.is_array())
1488 {
1489 addDebugData("MRU callout JSON is not an array");
1490 return mrus;
1491 }
1492
1493 for (const auto& mruCallout : mruJSON)
1494 {
1495 try
1496 {
1497 auto priority = getPriorityFromJSON(mruCallout);
1498 auto id = mruCallout.at("ID").get<uint32_t>();
1499
1500 src::MRU::MRUCallout mru{static_cast<uint32_t>(priority), id};
1501 mrus.push_back(std::move(mru));
1502 }
1503 catch (const std::exception& e)
1504 {
Jayanth Othayoth1aa90d42023-09-13 04:25:45 -05001505 addDebugData(std::format("Invalid MRU entry in JSON: {}: {}",
Matt Spinlerb8cb60f2020-08-27 10:55:55 -05001506 mruCallout.dump(), e.what()));
1507 }
1508 }
1509
1510 return mrus;
1511}
1512
Sumit Kumar3e274432021-09-14 06:37:56 -05001513std::vector<uint8_t> SRC::getSrcStruct()
1514{
1515 std::vector<uint8_t> data;
1516 Stream stream{data};
1517
1518 //------ Ref section 4.3 in PEL doc---
1519 //------ SRC Structure 40 bytes-------
1520 // Byte-0 | Byte-1 | Byte-2 | Byte-3 |
1521 // -----------------------------------
1522 // 02 | 08 | 00 | 09 | ==> Header
1523 // 00 | 00 | 00 | 48 | ==> Header
1524 // 00 | 00 | 00 | 00 | ==> Hex data word-2
1525 // 00 | 00 | 00 | 00 | ==> Hex data word-3
1526 // 00 | 00 | 00 | 00 | ==> Hex data word-4
1527 // 20 | 00 | 00 | 00 | ==> Hex data word-5
1528 // 00 | 00 | 00 | 00 | ==> Hex data word-6
1529 // 00 | 00 | 00 | 00 | ==> Hex data word-7
1530 // 00 | 00 | 00 | 00 | ==> Hex data word-8
1531 // 00 | 00 | 00 | 00 | ==> Hex data word-9
1532 // -----------------------------------
1533 // ASCII string - 8 bytes |
1534 // -----------------------------------
1535 // ASCII space NULL - 24 bytes |
1536 // -----------------------------------
1537 //_size = Base SRC struct: 8 byte header + hex data section + ASCII string
1538
1539 uint8_t flags = (_flags | postOPPanel);
1540
1541 stream << _version << flags << _reserved1B << _wordCount << _reserved2B
1542 << _size;
1543
1544 for (auto& word : _hexData)
1545 {
1546 stream << word;
1547 }
1548
1549 _asciiString->flatten(stream);
1550
1551 return data;
1552}
1553
Vijay Lobo875b6c72021-10-20 17:38:56 -05001554void SRC::setProgressCode(const DataInterfaceBase& dataIface)
1555{
1556 std::vector<uint8_t> progressSRC;
1557
1558 try
1559 {
1560 progressSRC = dataIface.getRawProgressSRC();
1561 }
1562 catch (const std::exception& e)
1563 {
Matt Spinler0bacc8e2023-07-07 16:25:39 -05001564 lg2::error("Error getting progress code: {ERROR}", "ERROR", e);
Vijay Lobo875b6c72021-10-20 17:38:56 -05001565 return;
1566 }
1567
1568 _hexData[2] = getProgressCode(progressSRC);
1569}
1570
1571uint32_t SRC::getProgressCode(std::vector<uint8_t>& rawProgressSRC)
1572{
1573 uint32_t progressCode = 0;
1574
1575 // A valid progress SRC is at least 72 bytes
1576 if (rawProgressSRC.size() < 72)
1577 {
1578 return progressCode;
1579 }
1580
1581 try
1582 {
1583 // The ASCII string field in progress SRCs starts at offset 40.
1584 // Take the first 8 characters to put in the uint32:
1585 // "CC009189" -> 0xCC009189
1586 Stream stream{rawProgressSRC, 40};
1587 src::AsciiString aString{stream};
1588 auto progressCodeString = aString.get().substr(0, 8);
1589
1590 if (std::all_of(progressCodeString.begin(), progressCodeString.end(),
1591 [](char c) {
Patrick Williams075c7922024-08-16 15:19:49 -04001592 return std::isxdigit(static_cast<unsigned char>(c));
1593 }))
Vijay Lobo875b6c72021-10-20 17:38:56 -05001594 {
1595 progressCode = std::stoul(progressCodeString, nullptr, 16);
1596 }
1597 }
1598 catch (const std::exception& e)
1599 {}
1600
1601 return progressCode;
1602}
1603
Matt Spinlerf9bae182019-10-09 13:37:38 -05001604} // namespace pels
1605} // namespace openpower