1 #include "config.h"
2
3 #include "bios_handler.hpp"
4
5 #include "constants.hpp"
6 #include "logger.hpp"
7
8 #include <sdbusplus/bus/match.hpp>
9 #include <utility/common_utility.hpp>
10 #include <utility/dbus_utility.hpp>
11
12 #include <string>
13
14 namespace vpd
15 {
16 // Template declaration to define APIs.
17 template class BiosHandler<IbmBiosHandler>;
18
19 template <typename T>
checkAndListenPldmService()20 void BiosHandler<T>::checkAndListenPldmService()
21 {
22 // Setup a call back match on NameOwnerChanged to determine when PLDM is
23 // up.
24 static std::shared_ptr<sdbusplus::bus::match_t> l_nameOwnerMatch =
25 std::make_shared<sdbusplus::bus::match_t>(
26 *m_asioConn,
27 sdbusplus::bus::match::rules::nameOwnerChanged(
28 constants::pldmServiceName),
29 [this](sdbusplus::message_t& l_msg) {
30 if (l_msg.is_method_error())
31 {
32 logging::logMessage(
33 "Error in reading PLDM name owner changed signal.");
34 return;
35 }
36
37 std::string l_name;
38 std::string l_newOwner;
39 std::string l_oldOwner;
40
41 l_msg.read(l_name, l_oldOwner, l_newOwner);
42
43 if (!l_newOwner.empty() &&
44 (l_name.compare(constants::pldmServiceName) ==
45 constants::STR_CMP_SUCCESS))
46 {
47 m_specificBiosHandler->backUpOrRestoreBiosAttributes();
48
49 // Start listener now that we have done the restore.
50 listenBiosAttributes();
51
52 // We don't need the match anymore
53 l_nameOwnerMatch.reset();
54 }
55 });
56
57 // Based on PLDM service status reset owner match registered above and
58 // trigger BIOS attribute sync.
59 if (dbusUtility::isServiceRunning(constants::pldmServiceName))
60 {
61 l_nameOwnerMatch.reset();
62 m_specificBiosHandler->backUpOrRestoreBiosAttributes();
63
64 // Start listener now that we have done the restore.
65 listenBiosAttributes();
66 }
67 }
68
69 template <typename T>
listenBiosAttributes()70 void BiosHandler<T>::listenBiosAttributes()
71 {
72 static std::shared_ptr<sdbusplus::bus::match_t> l_biosMatch =
73 std::make_shared<sdbusplus::bus::match_t>(
74 *m_asioConn,
75 sdbusplus::bus::match::rules::propertiesChanged(
76 constants::biosConfigMgrObjPath,
77 constants::biosConfigMgrInterface),
78 [this](sdbusplus::message_t& l_msg) {
79 m_specificBiosHandler->biosAttributesCallback(l_msg);
80 });
81 }
82
IbmBiosHandler(const std::shared_ptr<Manager> & i_manager)83 IbmBiosHandler::IbmBiosHandler(const std::shared_ptr<Manager>& i_manager) :
84 m_manager(i_manager), m_logger(Logger::getLoggerInstance())
85 {
86 const std::shared_ptr<Worker>& l_workerObj = m_manager->getWorkerObj();
87 if (!l_workerObj)
88 {
89 throw std::runtime_error("Worker object is null in IbmBiosHandler");
90 }
91 nlohmann::json l_sysCfgJsonObj = l_workerObj->getSysCfgJsonObj();
92
93 if (l_sysCfgJsonObj.empty())
94 {
95 throw std::runtime_error("System Configuration JSON is empty");
96 }
97
98 std::string l_biosHandlerJsonCfgFilePath =
99 l_sysCfgJsonObj.value("biosHandlerJsonPath", "");
100
101 if (l_biosHandlerJsonCfgFilePath.empty())
102 {
103 throw std::runtime_error(
104 "Critical: BiosHandlerJsonPath key is missing in config file.");
105 }
106
107 uint16_t l_errCode = 0;
108 m_biosConfigJson =
109 jsonUtility::getParsedJson(l_biosHandlerJsonCfgFilePath, l_errCode);
110 if (l_errCode)
111 {
112 throw JsonException("Failed to parse Bios Config JSON, error : " +
113 commonUtility::getErrCodeMsg(l_errCode),
114 l_biosHandlerJsonCfgFilePath);
115 }
116
117 if (!m_biosConfigJson.contains("biosRecordKwMap"))
118 {
119 throw JsonException("Bios JSON is not valid.",
120 l_biosHandlerJsonCfgFilePath);
121 }
122 }
123
biosAttributesCallback(sdbusplus::message_t & i_msg)124 void IbmBiosHandler::biosAttributesCallback(sdbusplus::message_t& i_msg)
125 {
126 if (i_msg.is_method_error())
127 {
128 logging::logMessage("Error in reading BIOS attribute signal. ");
129 return;
130 }
131
132 std::string l_objPath;
133 types::BiosBaseTableType l_propMap;
134 i_msg.read(l_objPath, l_propMap);
135
136 // Build a lookup map once
137 std::unordered_map<std::string, nlohmann::json> l_attributeConfigMap;
138 for (const auto& entry : m_biosConfigJson["biosRecordKwMap"])
139 {
140 std::string attrName = entry.value("biosAttributeName", "");
141 if (!attrName.empty())
142 {
143 l_attributeConfigMap[attrName] = entry;
144 }
145 }
146
147 for (auto l_property : l_propMap)
148 {
149 if (l_property.first != "BaseBIOSTable")
150 {
151 // Looking for change in Base BIOS table only.
152 continue;
153 }
154
155 if (auto l_attributeList =
156 std::get_if<std::map<std::string, types::BiosProperty>>(
157 &(l_property.second)))
158 {
159 for (const auto& l_attribute : *l_attributeList)
160 {
161 std::string l_attributeName = std::get<0>(l_attribute);
162
163 // Find config entry once
164 auto configIt = l_attributeConfigMap.find(l_attributeName);
165 if (configIt == l_attributeConfigMap.end())
166 {
167 continue; // No config for this attribute
168 }
169
170 const auto& configEntry = configIt->second;
171
172 if (auto l_val = std::get_if<std::string>(
173 &(std::get<5>(std::get<1>(l_attribute)))))
174 {
175 if (l_attributeName == "hb_memory_mirror_mode")
176 {
177 saveAmmToVpd(*l_val, configEntry);
178 }
179
180 if (l_attributeName == "pvm_keep_and_clear")
181 {
182 saveKeepAndClearToVpd(*l_val, configEntry);
183 }
184
185 if (l_attributeName == "pvm_create_default_lpar")
186 {
187 saveCreateDefaultLparToVpd(*l_val, configEntry);
188 }
189
190 if (l_attributeName == "pvm_clear_nvram")
191 {
192 saveClearNvramToVpd(*l_val, configEntry);
193 }
194
195 continue;
196 }
197
198 if (auto l_val = std::get_if<int64_t>(
199 &(std::get<5>(std::get<1>(l_attribute)))))
200 {
201 std::string l_attributeName = std::get<0>(l_attribute);
202 if (l_attributeName == "hb_field_core_override")
203 {
204 saveFcoToVpd(*l_val, configEntry);
205 }
206 }
207 }
208 }
209 else
210 {
211 logging::logMessage("Invalid type received for BIOS table.");
212
213 m_logger->logMessage(
214 std::string("Invalid type received for BIOS table."),
215 PlaceHolder::PEL,
216 types::PelInfoTuple{types::ErrorType::FirmwareError,
217 types::SeverityType::Warning, 0,
218 std::nullopt, std::nullopt, std::nullopt,
219 std::nullopt});
220
221 break;
222 }
223 }
224 }
225
backUpOrRestoreBiosAttributes()226 void IbmBiosHandler::backUpOrRestoreBiosAttributes()
227 {
228 const std::unordered_map<std::string,
229 std::function<void(const nlohmann::json&)>>
230 handlers = {
231 {"hb_field_core_override",
232 [this](const auto& entry) { processFieldCoreOverride(entry); }},
233 {"hb_memory_mirror_mode",
234 [this](const auto& entry) { processActiveMemoryMirror(entry); }},
235 {"pvm_create_default_lpar",
236 [this](const auto& entry) { processCreateDefaultLpar(entry); }},
237 {"pvm_clear_nvram",
238 [this](const auto& entry) { processClearNvram(entry); }},
239 {"pvm_keep_and_clear",
240 [this](const auto& entry) { processKeepAndClear(entry); }}};
241
242 for (const auto& entry : m_biosConfigJson["biosRecordKwMap"])
243 {
244 std::string attrName = entry.value("biosAttributeName", "");
245 auto it = handlers.find(attrName);
246 if (it != handlers.end())
247 {
248 it->second(entry); // Run the respective function
249 }
250 }
251 }
252
readBiosAttribute(const std::string & i_attributeName)253 types::BiosAttributeCurrentValue IbmBiosHandler::readBiosAttribute(
254 const std::string& i_attributeName)
255 {
256 types::BiosAttributeCurrentValue l_attrValueVariant =
257 dbusUtility::biosGetAttributeMethodCall(i_attributeName);
258
259 return l_attrValueVariant;
260 }
261
processFieldCoreOverride(const nlohmann::json & i_attributeData)262 void IbmBiosHandler::processFieldCoreOverride(
263 const nlohmann::json& i_attributeData)
264 {
265 // TODO: Should we avoid doing this at runtime?
266 std::string l_keywordName = i_attributeData.value("keyword", "");
267 std::string l_recordName = i_attributeData.value("record", "");
268
269 if (l_recordName.empty() || l_keywordName.empty())
270 {
271 m_logger->logMessage(
272 "VPD mapping for hb_field_core_override not found in JSON config."
273 "Skipping BIOS and VPD sync for the same.");
274 return;
275 }
276
277 // Read required keyword from Dbus.
278 auto l_kwdValueVariant = dbusUtility::readDbusProperty(
279 constants::pimServiceName, constants::systemVpdInvPath,
280 constants::ipzVpdInf + l_recordName, l_keywordName);
281
282 if (auto l_fcoInVpd = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
283 {
284 // default length of the keyword is 4 bytes.
285 if (l_fcoInVpd->size() != constants::VALUE_4)
286 {
287 m_logger->logMessage(
288 "Invalid value read for FCO from D-Bus. Skipping.");
289 }
290
291 // If FCO in VPD contains anything other that ASCII Space, restore to
292 // BIOS
293 if (std::any_of(l_fcoInVpd->cbegin(), l_fcoInVpd->cend(),
294 [](uint8_t l_val) {
295 return l_val != constants::ASCII_OF_SPACE;
296 }))
297 {
298 // Restore the data to BIOS.
299 saveFcoToBios(*l_fcoInVpd);
300 }
301 else
302 {
303 types::BiosAttributeCurrentValue l_attrValueVariant =
304 readBiosAttribute("hb_field_core_override");
305
306 if (auto l_fcoInBios = std::get_if<int64_t>(&l_attrValueVariant))
307 {
308 // save the BIOS data to VPD
309 saveFcoToVpd(*l_fcoInBios, i_attributeData);
310
311 return;
312 }
313 m_logger->logMessage("Invalid type recieved for FCO from BIOS.");
314 }
315 return;
316 }
317 m_logger->logMessage("Invalid type recieved for FCO from VPD.");
318 }
319
saveFcoToVpd(int64_t i_fcoInBios,const nlohmann::json & i_attributeData)320 void IbmBiosHandler::saveFcoToVpd(int64_t i_fcoInBios,
321 const nlohmann::json& i_attributeData)
322 {
323 if (i_fcoInBios < 0)
324 {
325 m_logger->logMessage("Invalid FCO value in BIOS. Skip updating to VPD");
326 return;
327 }
328
329 std::string l_recordName = i_attributeData.value("record", "");
330 std::string l_keywordName = i_attributeData.value("keyword", "");
331
332 // The missing attribute check
333 if (l_recordName.empty() || l_keywordName.empty())
334 {
335 m_logger->logMessage(
336 "VPD mapping for hb_field_core_override not found in JSON config."
337 "Skipping BIOS and VPD sync for the same. ");
338 return;
339 }
340
341 // Read required keyword from Dbus.
342 auto l_kwdValueVariant = dbusUtility::readDbusProperty(
343 constants::pimServiceName, constants::systemVpdInvPath,
344 constants::ipzVpdInf + l_recordName, l_keywordName);
345
346 if (auto l_fcoInVpd = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
347 {
348 // default length of the keyword is 4 bytes.
349 if (l_fcoInVpd->size() != constants::VALUE_4)
350 {
351 m_logger->logMessage(
352 "Invalid value read for FCO from D-Bus. Skipping.");
353 return;
354 }
355
356 // convert to VPD value type
357 types::BinaryVector l_biosValInVpdFormat = {
358 0, 0, 0, static_cast<uint8_t>(i_fcoInBios)};
359
360 // Update only when the data are different.
361 if (std::memcmp(l_biosValInVpdFormat.data(), l_fcoInVpd->data(),
362 constants::VALUE_4) != constants::SUCCESS)
363 {
364 if (constants::FAILURE ==
365 m_manager->updateKeyword(
366 SYSTEM_VPD_FILE_PATH,
367 types::IpzData(constants::recVSYS, constants::kwdRG,
368 l_biosValInVpdFormat)))
369 {
370 m_logger->logMessage(
371 "Failed to update " + std::string(constants::kwdRG) +
372 " keyword to VPD.");
373 }
374 }
375 }
376 else
377 {
378 m_logger->logMessage("Invalid type read for FCO from DBus.");
379 }
380 }
381
saveFcoToBios(const types::BinaryVector & i_fcoVal)382 void IbmBiosHandler::saveFcoToBios(const types::BinaryVector& i_fcoVal)
383 {
384 if (i_fcoVal.size() != constants::VALUE_4)
385 {
386 m_logger->logMessage("Bad size for FCO received. Skip writing to BIOS");
387 return;
388 }
389
390 types::PendingBIOSAttrs l_pendingBiosAttribute;
391 l_pendingBiosAttribute.push_back(std::make_pair(
392 "hb_field_core_override",
393 std::make_tuple(
394 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer",
395 i_fcoVal.at(constants::VALUE_3))));
396
397 if (!dbusUtility::writeDbusProperty(
398 constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
399 constants::biosConfigMgrInterface, "PendingAttributes",
400 l_pendingBiosAttribute))
401 {
402 m_logger->logMessage(
403 "DBus call to update FCO value in pending attribute failed. ");
404
405 m_logger->logMessage(
406 std::string(
407 "DBus call to update FCO value in pending attribute failed"),
408 PlaceHolder::PEL,
409 types::PelInfoTuple{types::ErrorType::FirmwareError,
410 types::SeverityType::Informational, 0,
411 std::nullopt, std::nullopt, std::nullopt,
412 std::nullopt});
413 }
414 }
415
saveAmmToVpd(const std::string & i_memoryMirrorMode,const nlohmann::json & i_attributeData)416 void IbmBiosHandler::saveAmmToVpd(const std::string& i_memoryMirrorMode,
417 const nlohmann::json& i_attributeData)
418 {
419 if (i_memoryMirrorMode.empty())
420 {
421 m_logger->logMessage(
422 "Empty memory mirror mode value from BIOS. Skip writing to VPD");
423 return;
424 }
425
426 std::string l_keywordName = i_attributeData.value("keyword", "");
427 std::string l_recordName = i_attributeData.value("record", "");
428
429 // The missing attribute check
430 if (l_recordName.empty() || l_keywordName.empty())
431 {
432 m_logger->logMessage(
433 "VPD mapping for hb_memory_mirror_mode not found in JSON config."
434 "Skipping BIOS and VPD sync for the same. ");
435 return;
436 }
437
438 // Read existing value.
439 auto l_kwdValueVariant = dbusUtility::readDbusProperty(
440 constants::pimServiceName, constants::systemVpdInvPath,
441 constants::ipzVpdInf + l_recordName, l_keywordName);
442
443 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
444 {
445 auto l_ammValInVpd = *l_pVal;
446
447 types::BinaryVector l_valToUpdateInVpd{
448 (i_memoryMirrorMode == "Enabled" ? constants::AMM_ENABLED_IN_VPD
449 : constants::AMM_DISABLED_IN_VPD)};
450
451 // Check if value is already updated on VPD.
452 if (l_ammValInVpd.at(0) == l_valToUpdateInVpd.at(0))
453 {
454 return;
455 }
456
457 if (constants::FAILURE ==
458 m_manager->updateKeyword(
459 SYSTEM_VPD_FILE_PATH,
460 types::IpzData(constants::recVSYS, constants::kwdAMM,
461 l_valToUpdateInVpd)))
462 {
463 m_logger->logMessage(
464 "Failed to update " + std::string(constants::kwdAMM) +
465 " keyword to VPD");
466 }
467 }
468 else
469 {
470 m_logger->logMessage(
471 "Invalid type read for memory mirror mode value from DBus. Skip writing to VPD");
472
473 m_logger->logMessage(
474 std::string(
475 "Invalid type read for memory mirror mode value from DBus. Skip writing to VPD."),
476 PlaceHolder::PEL,
477 types::PelInfoTuple{types::ErrorType::FirmwareError,
478 types::SeverityType::Informational, 0,
479 std::nullopt, std::nullopt, std::nullopt,
480 std::nullopt});
481 }
482 }
483
saveAmmToBios(const uint8_t & i_ammVal)484 void IbmBiosHandler::saveAmmToBios(const uint8_t& i_ammVal)
485 {
486 const std::string l_valtoUpdate =
487 (i_ammVal == constants::VALUE_2) ? "Enabled" : "Disabled";
488
489 types::PendingBIOSAttrs l_pendingBiosAttribute;
490 l_pendingBiosAttribute.push_back(std::make_pair(
491 "hb_memory_mirror_mode",
492 std::make_tuple(
493 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
494 l_valtoUpdate)));
495
496 if (!dbusUtility::writeDbusProperty(
497 constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
498 constants::biosConfigMgrInterface, "PendingAttributes",
499 l_pendingBiosAttribute))
500 {
501 m_logger->logMessage(
502 "DBus call to update AMM value in pending attribute failed.");
503
504 m_logger->logMessage(
505 std::string(
506 "DBus call to update AMM value in pending attribute failed."),
507 PlaceHolder::PEL,
508 types::PelInfoTuple{types::ErrorType::FirmwareError,
509 types::SeverityType::Informational, 0,
510 std::nullopt, std::nullopt, std::nullopt,
511 std::nullopt});
512 }
513 }
514
processActiveMemoryMirror(const nlohmann::json & i_attributeData)515 void IbmBiosHandler::processActiveMemoryMirror(
516 const nlohmann::json& i_attributeData)
517 {
518 std::string l_keywordName = i_attributeData.value("keyword", "");
519 std::string l_recordName = i_attributeData.value("record", "");
520
521 // The missing attribute check
522 if (l_recordName.empty() || l_keywordName.empty())
523 {
524 m_logger->logMessage(
525 "VPD mapping for hb_memory_mirror_mode not found in JSON config."
526 "Skipping BIOS and VPD sync for the same. ");
527 return;
528 }
529
530 auto l_kwdValueVariant = dbusUtility::readDbusProperty(
531 constants::pimServiceName, constants::systemVpdInvPath,
532 constants::ipzVpdInf + l_recordName, l_keywordName);
533
534 if (auto pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
535 {
536 auto l_ammValInVpd = *pVal;
537
538 // Check if active memory mirror value is default in VPD.
539 if (l_ammValInVpd.at(0) == constants::VALUE_0)
540 {
541 types::BiosAttributeCurrentValue l_attrValueVariant =
542 readBiosAttribute("hb_memory_mirror_mode");
543
544 if (auto pVal = std::get_if<std::string>(&l_attrValueVariant))
545 {
546 saveAmmToVpd(*pVal, i_attributeData);
547 return;
548 }
549 m_logger->logMessage(
550 "Invalid type recieved for auto memory mirror mode from BIOS.");
551 return;
552 }
553 else
554 {
555 saveAmmToBios(l_ammValInVpd.at(0));
556 }
557 return;
558 }
559 m_logger->logMessage(
560 "Invalid type recieved for auto memory mirror mode from VPD.");
561
562 m_logger->logMessage(
563 std::string(
564 "Invalid type recieved for auto memory mirror mode from VPD."),
565 PlaceHolder::PEL,
566 types::PelInfoTuple{types::ErrorType::FirmwareError,
567 types::SeverityType::Informational, 0, std::nullopt,
568 std::nullopt, std::nullopt, std::nullopt});
569 }
570
saveCreateDefaultLparToVpd(const std::string & i_createDefaultLparVal,const nlohmann::json & i_attributeData)571 void IbmBiosHandler::saveCreateDefaultLparToVpd(
572 const std::string& i_createDefaultLparVal,
573 const nlohmann::json& i_attributeData)
574 {
575 if (i_createDefaultLparVal.empty())
576 {
577 m_logger->logMessage(
578 "Empty value received for Lpar from BIOS. Skip writing in VPD.");
579 return;
580 }
581
582 std::string l_keywordName = i_attributeData.value("keyword", "");
583 std::string l_recordName = i_attributeData.value("record", "");
584
585 // The missing attribute check
586 if (l_recordName.empty() || l_keywordName.empty())
587 {
588 m_logger->logMessage(
589 "VPD mapping for pvm_create_default_lpar not found in JSON config."
590 "Skipping BIOS and VPD sync for the same. ");
591 return;
592 }
593
594 // Read required keyword from DBus as we need to set only a Bit.
595 auto l_kwdValueVariant = dbusUtility::readDbusProperty(
596 constants::pimServiceName, constants::systemVpdInvPath,
597 constants::ipzVpdInf + l_recordName, l_keywordName);
598
599 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
600 {
601 commonUtility::toLower(
602 const_cast<std::string&>(i_createDefaultLparVal));
603
604 // Check for second bit. Bit set for enabled else disabled.
605 if (((((*l_pVal).at(0) & 0x02) == 0x02) &&
606 (i_createDefaultLparVal.compare("enabled") ==
607 constants::STR_CMP_SUCCESS)) ||
608 ((((*l_pVal).at(0) & 0x02) == 0x00) &&
609 (i_createDefaultLparVal.compare("disabled") ==
610 constants::STR_CMP_SUCCESS)))
611 {
612 // Values are same, Don;t update.
613 return;
614 }
615
616 types::BinaryVector l_valToUpdateInVpd;
617 if (i_createDefaultLparVal.compare("enabled") ==
618 constants::STR_CMP_SUCCESS)
619 {
620 // 2nd Bit is used to store the value.
621 l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) | 0x02);
622 }
623 else
624 {
625 // 2nd Bit is used to store the value.
626 l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) & ~(0x02));
627 }
628
629 if (-1 == m_manager->updateKeyword(
630 SYSTEM_VPD_FILE_PATH,
631 types::IpzData(constants::vsysInf,
632 constants::kwdClearNVRAM_CreateLPAR,
633 l_valToUpdateInVpd)))
634 {
635 m_logger->logMessage(
636 "Failed to update " +
637 std::string(constants::kwdClearNVRAM_CreateLPAR) +
638 " keyword to VPD");
639 }
640
641 return;
642 }
643 m_logger->logMessage(
644 "Invalid type recieved for create default Lpar from VPD.");
645 }
646
saveCreateDefaultLparToBios(const std::string & i_createDefaultLparVal)647 void IbmBiosHandler::saveCreateDefaultLparToBios(
648 const std::string& i_createDefaultLparVal)
649 {
650 // checking for exact length as it is a string and can have garbage value.
651 if (i_createDefaultLparVal.size() != constants::VALUE_1)
652 {
653 m_logger->logMessage(
654 "Bad size for Create default LPAR in VPD. Skip writing to BIOS.");
655 return;
656 }
657
658 std::string l_valtoUpdate =
659 (i_createDefaultLparVal.at(0) & 0x02) ? "Enabled" : "Disabled";
660
661 types::PendingBIOSAttrs l_pendingBiosAttribute;
662 l_pendingBiosAttribute.push_back(std::make_pair(
663 "pvm_create_default_lpar",
664 std::make_tuple(
665 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
666 l_valtoUpdate)));
667
668 if (!dbusUtility::writeDbusProperty(
669 constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
670 constants::biosConfigMgrInterface, "PendingAttributes",
671 l_pendingBiosAttribute))
672 {
673 m_logger->logMessage(
674 "DBus call to update lpar value in pending attribute failed.");
675
676 m_logger->logMessage(
677 std::string(
678 "DBus call to update lpar value in pending attribute failed."),
679 PlaceHolder::PEL,
680 types::PelInfoTuple{types::ErrorType::FirmwareError,
681 types::SeverityType::Informational, 0,
682 std::nullopt, std::nullopt, std::nullopt,
683 std::nullopt});
684 }
685
686 return;
687 }
688
processCreateDefaultLpar(const nlohmann::json & i_attributeData)689 void IbmBiosHandler::processCreateDefaultLpar(
690 const nlohmann::json& i_attributeData)
691 {
692 std::string l_keywordName = i_attributeData.value("keyword", "");
693 std::string l_recordName = i_attributeData.value("record", "");
694
695 // The missing attribute check
696 if (l_recordName.empty() || l_keywordName.empty())
697 {
698 m_logger->logMessage(
699 "VPD mapping for pvm_create_default_lpar not found in JSON config."
700 "Skipping BIOS and VPD sync for the same. ");
701 return;
702 }
703
704 // Read required keyword from DBus.
705 auto l_kwdValueVariant = dbusUtility::readDbusProperty(
706 constants::pimServiceName, constants::systemVpdInvPath,
707 constants::ipzVpdInf + l_recordName, l_keywordName);
708
709 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
710 {
711 saveCreateDefaultLparToBios(std::to_string(l_pVal->at(0)));
712 return;
713 }
714 m_logger->logMessage(
715 "Invalid type recieved for create default Lpar from VPD.");
716 }
717
saveClearNvramToVpd(const std::string & i_clearNvramVal,const nlohmann::json & i_attributeData)718 void IbmBiosHandler::saveClearNvramToVpd(const std::string& i_clearNvramVal,
719 const nlohmann::json& i_attributeData)
720 {
721 if (i_clearNvramVal.empty())
722 {
723 m_logger->logMessage(
724 "Empty value received for clear NVRAM from BIOS. Skip updating to VPD.");
725 return;
726 }
727
728 std::string l_keywordName = i_attributeData.value("keyword", "");
729 std::string l_recordName = i_attributeData.value("record", "");
730
731 // The missing attribute check
732 if (l_recordName.empty() || l_keywordName.empty())
733 {
734 m_logger->logMessage(
735 "VPD mapping for pvm_clear_nvram not found in JSON config."
736 "Skipping BIOS and VPD sync for the same. ");
737 return;
738 }
739
740 // Read required keyword from DBus as we need to set only a Bit.
741 auto l_kwdValueVariant = dbusUtility::readDbusProperty(
742 constants::pimServiceName, constants::systemVpdInvPath,
743 constants::ipzVpdInf + l_recordName, l_keywordName);
744
745 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
746 {
747 commonUtility::toLower(const_cast<std::string&>(i_clearNvramVal));
748
749 // Check for third bit. Bit set for enabled else disabled.
750 if (((((*l_pVal).at(0) & 0x04) == 0x04) &&
751 (i_clearNvramVal.compare("enabled") ==
752 constants::STR_CMP_SUCCESS)) ||
753 ((((*l_pVal).at(0) & 0x04) == 0x00) &&
754 (i_clearNvramVal.compare("disabled") ==
755 constants::STR_CMP_SUCCESS)))
756 {
757 // Don't update, values are same.
758 return;
759 }
760
761 types::BinaryVector l_valToUpdateInVpd;
762 if (i_clearNvramVal.compare("enabled") == constants::STR_CMP_SUCCESS)
763 {
764 // 3rd bit is used to store the value.
765 l_valToUpdateInVpd.emplace_back(
766 (*l_pVal).at(0) | constants::VALUE_4);
767 }
768 else
769 {
770 // 3rd bit is used to store the value.
771 l_valToUpdateInVpd.emplace_back(
772 (*l_pVal).at(0) & ~(constants::VALUE_4));
773 }
774
775 if (-1 == m_manager->updateKeyword(
776 SYSTEM_VPD_FILE_PATH,
777 types::IpzData(constants::vsysInf,
778 constants::kwdClearNVRAM_CreateLPAR,
779 l_valToUpdateInVpd)))
780 {
781 m_logger->logMessage(
782 "Failed to update " +
783 std::string(constants::kwdClearNVRAM_CreateLPAR) +
784 " keyword to VPD");
785 }
786
787 return;
788 }
789 m_logger->logMessage("Invalid type recieved for clear NVRAM from VPD.");
790 }
791
saveClearNvramToBios(const std::string & i_clearNvramVal)792 void IbmBiosHandler::saveClearNvramToBios(const std::string& i_clearNvramVal)
793 {
794 // Check for the exact length as it is a string and it can have a garbage
795 // value.
796 if (i_clearNvramVal.size() != constants::VALUE_1)
797 {
798 m_logger->logMessage(
799 "Bad size for clear NVRAM in VPD. Skip writing to BIOS.");
800 return;
801 }
802
803 // 3rd bit is used to store clear NVRAM value.
804 std::string l_valtoUpdate =
805 (i_clearNvramVal.at(0) & constants::VALUE_4) ? "Enabled" : "Disabled";
806
807 types::PendingBIOSAttrs l_pendingBiosAttribute;
808 l_pendingBiosAttribute.push_back(std::make_pair(
809 "pvm_clear_nvram",
810 std::make_tuple(
811 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
812 l_valtoUpdate)));
813
814 if (!dbusUtility::writeDbusProperty(
815 constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
816 constants::biosConfigMgrInterface, "PendingAttributes",
817 l_pendingBiosAttribute))
818 {
819 m_logger->logMessage(
820 "DBus call to update NVRAM value in pending attribute failed.");
821
822 m_logger->logMessage(
823 std::string(
824 "DBus call to update NVRAM value in pending attribute failed."),
825 PlaceHolder::PEL,
826 types::PelInfoTuple{types::ErrorType::FirmwareError,
827 types::SeverityType::Informational, 0,
828 std::nullopt, std::nullopt, std::nullopt,
829 std::nullopt});
830 }
831 }
832
processClearNvram(const nlohmann::json & i_attributeData)833 void IbmBiosHandler::processClearNvram(const nlohmann::json& i_attributeData)
834 {
835 std::string l_keywordName = i_attributeData.value("keyword", "");
836 std::string l_recordName = i_attributeData.value("record", "");
837
838 // The missing attribute check
839 if (l_recordName.empty() || l_keywordName.empty())
840 {
841 m_logger->logMessage(
842 "VPD mapping for pvm_clear_nvram not found in JSON config."
843 "Skipping BIOS and VPD sync for the same. ");
844 return;
845 }
846
847 // Read required keyword from VPD.
848 auto l_kwdValueVariant = dbusUtility::readDbusProperty(
849 constants::pimServiceName, constants::systemVpdInvPath,
850 constants::ipzVpdInf + l_recordName, l_keywordName);
851
852 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
853 {
854 saveClearNvramToBios(std::to_string(l_pVal->at(0)));
855 return;
856 }
857 m_logger->logMessage("Invalid type recieved for clear NVRAM from VPD.");
858 }
859
saveKeepAndClearToVpd(const std::string & i_KeepAndClearVal,const nlohmann::json & i_attributeData)860 void IbmBiosHandler::saveKeepAndClearToVpd(
861 const std::string& i_KeepAndClearVal, const nlohmann::json& i_attributeData)
862 {
863 if (i_KeepAndClearVal.empty())
864 {
865 m_logger->logMessage(
866 "Empty value received for keep and clear from BIOS. Skip updating to VPD.");
867 return;
868 }
869
870 std::string l_keywordName = i_attributeData.value("keyword", "");
871 std::string l_recordName = i_attributeData.value("record", "");
872
873 // The missing attribute check
874 if (l_recordName.empty() || l_keywordName.empty())
875 {
876 m_logger->logMessage(
877 "VPD mapping for pvm_keep_and_clear not found in JSON config."
878 "Skipping BIOS and VPD sync for the same. ");
879 return;
880 }
881
882 // Read required keyword from DBus as we need to set only a Bit.
883 auto l_kwdValueVariant = dbusUtility::readDbusProperty(
884 constants::pimServiceName, constants::systemVpdInvPath,
885 constants::ipzVpdInf + l_recordName, l_keywordName);
886
887 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
888 {
889 commonUtility::toLower(const_cast<std::string&>(i_KeepAndClearVal));
890
891 // Check for first bit. Bit set for enabled else disabled.
892 if (((((*l_pVal).at(0) & 0x01) == 0x01) &&
893 (i_KeepAndClearVal.compare("enabled") ==
894 constants::STR_CMP_SUCCESS)) ||
895 ((((*l_pVal).at(0) & 0x01) == 0x00) &&
896 (i_KeepAndClearVal.compare("disabled") ==
897 constants::STR_CMP_SUCCESS)))
898 {
899 // Don't update, values are same.
900 return;
901 }
902
903 types::BinaryVector l_valToUpdateInVpd;
904 if (i_KeepAndClearVal.compare("enabled") == constants::STR_CMP_SUCCESS)
905 {
906 // 1st bit is used to store the value.
907 l_valToUpdateInVpd.emplace_back(
908 (*l_pVal).at(0) | constants::VALUE_1);
909 }
910 else
911 {
912 // 1st bit is used to store the value.
913 l_valToUpdateInVpd.emplace_back(
914 (*l_pVal).at(0) & ~(constants::VALUE_1));
915 }
916
917 if (-1 ==
918 m_manager->updateKeyword(
919 SYSTEM_VPD_FILE_PATH,
920 types::IpzData(constants::vsysInf, constants::kwdKeepAndClear,
921 l_valToUpdateInVpd)))
922 {
923 m_logger->logMessage(
924 "Failed to update " + std::string(constants::kwdKeepAndClear) +
925 " keyword to VPD");
926 }
927
928 return;
929 }
930 m_logger->logMessage("Invalid type recieved for keep and clear from VPD.");
931 }
932
saveKeepAndClearToBios(const std::string & i_KeepAndClearVal)933 void IbmBiosHandler::saveKeepAndClearToBios(
934 const std::string& i_KeepAndClearVal)
935 {
936 // checking for exact length as it is a string and can have garbage value.
937 if (i_KeepAndClearVal.size() != constants::VALUE_1)
938 {
939 m_logger->logMessage(
940 "Bad size for keep and clear in VPD. Skip writing to BIOS.");
941 return;
942 }
943
944 // 1st bit is used to store keep and clear value.
945 std::string l_valtoUpdate =
946 (i_KeepAndClearVal.at(0) & constants::VALUE_1) ? "Enabled" : "Disabled";
947
948 types::PendingBIOSAttrs l_pendingBiosAttribute;
949 l_pendingBiosAttribute.push_back(std::make_pair(
950 "pvm_keep_and_clear",
951 std::make_tuple(
952 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
953 l_valtoUpdate)));
954
955 if (!dbusUtility::writeDbusProperty(
956 constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
957 constants::biosConfigMgrInterface, "PendingAttributes",
958 l_pendingBiosAttribute))
959 {
960 m_logger->logMessage(
961 "DBus call to update keep and clear value in pending attribute failed.");
962
963 m_logger->logMessage(
964 std::string(
965 "DBus call to update keep and clear value in pending attribute failed."),
966 PlaceHolder::PEL,
967 types::PelInfoTuple{types::ErrorType::FirmwareError,
968 types::SeverityType::Informational, 0,
969 std::nullopt, std::nullopt, std::nullopt,
970 std::nullopt});
971 }
972 }
973
processKeepAndClear(const nlohmann::json & i_attributeData)974 void IbmBiosHandler::processKeepAndClear(const nlohmann::json& i_attributeData)
975 {
976 std::string l_keywordName = i_attributeData.value("keyword", "");
977 std::string l_recordName = i_attributeData.value("record", "");
978
979 // The missing attribute check
980 if (l_recordName.empty() || l_keywordName.empty())
981 {
982 m_logger->logMessage(
983 "VPD mapping for pvm_keep_and_clear not found in JSON config."
984 "Skipping BIOS and VPD sync for the same. ");
985 return;
986 }
987
988 // Read required keyword from VPD.
989 auto l_kwdValueVariant = dbusUtility::readDbusProperty(
990 constants::pimServiceName, constants::systemVpdInvPath,
991 constants::ipzVpdInf + l_recordName, l_keywordName);
992
993 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
994 {
995 saveKeepAndClearToBios(std::to_string(l_pVal->at(0)));
996 return;
997 }
998 m_logger->logMessage("Invalid type recieved for keep and clear from VPD.");
999 }
1000 } // namespace vpd
1001