xref: /openbmc/openpower-vpd-parser/vpd-manager/src/bios_handler.cpp (revision 5d144981293918a7c3fb7d56165a61f299d76503)
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