xref: /openbmc/openpower-vpd-parser/vpd-manager/src/bios_handler.cpp (revision 2bbe7f35edd385a42d43471c4587961b1bb3243d)
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>
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>
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 
83 void IbmBiosHandler::biosAttributesCallback(sdbusplus::message_t& i_msg)
84 {
85     if (i_msg.is_method_error())
86     {
87         logging::logMessage("Error in reading BIOS attribute signal. ");
88         return;
89     }
90 
91     std::string l_objPath;
92     types::BiosBaseTableType l_propMap;
93     i_msg.read(l_objPath, l_propMap);
94 
95     for (auto l_property : l_propMap)
96     {
97         if (l_property.first != "BaseBIOSTable")
98         {
99             // Looking for change in Base BIOS table only.
100             continue;
101         }
102 
103         if (auto l_attributeList =
104                 std::get_if<std::map<std::string, types::BiosProperty>>(
105                     &(l_property.second)))
106         {
107             for (const auto& l_attribute : *l_attributeList)
108             {
109                 if (auto l_val = std::get_if<std::string>(
110                         &(std::get<5>(std::get<1>(l_attribute)))))
111                 {
112                     std::string l_attributeName = std::get<0>(l_attribute);
113                     if (l_attributeName == "hb_memory_mirror_mode")
114                     {
115                         saveAmmToVpd(*l_val);
116                     }
117 
118                     if (l_attributeName == "pvm_keep_and_clear")
119                     {
120                         saveKeepAndClearToVpd(*l_val);
121                     }
122 
123                     if (l_attributeName == "pvm_create_default_lpar")
124                     {
125                         saveCreateDefaultLparToVpd(*l_val);
126                     }
127 
128                     if (l_attributeName == "pvm_clear_nvram")
129                     {
130                         saveClearNvramToVpd(*l_val);
131                     }
132 
133                     continue;
134                 }
135 
136                 if (auto l_val = std::get_if<int64_t>(
137                         &(std::get<5>(std::get<1>(l_attribute)))))
138                 {
139                     std::string l_attributeName = std::get<0>(l_attribute);
140                     if (l_attributeName == "hb_field_core_override")
141                     {
142                         saveFcoToVpd(*l_val);
143                     }
144                 }
145             }
146         }
147         else
148         {
149             logging::logMessage("Invalid type received for BIOS table.");
150             EventLogger::createSyncPel(
151                 types::ErrorType::FirmwareError, types::SeverityType::Warning,
152                 __FILE__, __FUNCTION__, 0,
153                 std::string("Invalid type received for BIOS table."),
154                 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
155             break;
156         }
157     }
158 }
159 
160 void IbmBiosHandler::backUpOrRestoreBiosAttributes()
161 {
162     // process FCO
163     processFieldCoreOverride();
164 
165     // process AMM
166     processActiveMemoryMirror();
167 
168     // process LPAR
169     processCreateDefaultLpar();
170 
171     // process clear NVRAM
172     processClearNvram();
173 
174     // process keep and clear
175     processKeepAndClear();
176 }
177 
178 types::BiosAttributeCurrentValue IbmBiosHandler::readBiosAttribute(
179     const std::string& i_attributeName)
180 {
181     types::BiosAttributeCurrentValue l_attrValueVariant =
182         dbusUtility::biosGetAttributeMethodCall(i_attributeName);
183 
184     return l_attrValueVariant;
185 }
186 
187 void IbmBiosHandler::processFieldCoreOverride()
188 {
189     // TODO: Should we avoid doing this at runtime?
190 
191     // Read required keyword from Dbus.
192     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
193         constants::pimServiceName, constants::systemVpdInvPath,
194         constants::vsysInf, constants::kwdRG);
195 
196     if (auto l_fcoInVpd = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
197     {
198         // default length of the keyword is 4 bytes.
199         if (l_fcoInVpd->size() != constants::VALUE_4)
200         {
201             logging::logMessage(
202                 "Invalid value read for FCO from D-Bus. Skipping.");
203         }
204 
205         //  If FCO in VPD contains anything other that ASCII Space, restore to
206         //  BIOS
207         if (std::any_of(l_fcoInVpd->cbegin(), l_fcoInVpd->cend(),
208                         [](uint8_t l_val) {
209                             return l_val != constants::ASCII_OF_SPACE;
210                         }))
211         {
212             // Restore the data to BIOS.
213             saveFcoToBios(*l_fcoInVpd);
214         }
215         else
216         {
217             types::BiosAttributeCurrentValue l_attrValueVariant =
218                 readBiosAttribute("hb_field_core_override");
219 
220             if (auto l_fcoInBios = std::get_if<int64_t>(&l_attrValueVariant))
221             {
222                 // save the BIOS data to VPD
223                 saveFcoToVpd(*l_fcoInBios);
224 
225                 return;
226             }
227             logging::logMessage("Invalid type recieved for FCO from BIOS.");
228         }
229         return;
230     }
231     logging::logMessage("Invalid type recieved for FCO from VPD.");
232 }
233 
234 void IbmBiosHandler::saveFcoToVpd(int64_t i_fcoInBios)
235 {
236     if (i_fcoInBios < 0)
237     {
238         logging::logMessage("Invalid FCO value in BIOS. Skip updating to VPD");
239         return;
240     }
241 
242     // Read required keyword from Dbus.
243     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
244         constants::pimServiceName, constants::systemVpdInvPath,
245         constants::vsysInf, constants::kwdRG);
246 
247     if (auto l_fcoInVpd = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
248     {
249         // default length of the keyword is 4 bytes.
250         if (l_fcoInVpd->size() != constants::VALUE_4)
251         {
252             logging::logMessage(
253                 "Invalid value read for FCO from D-Bus. Skipping.");
254             return;
255         }
256 
257         // convert to VPD value type
258         types::BinaryVector l_biosValInVpdFormat = {
259             0, 0, 0, static_cast<uint8_t>(i_fcoInBios)};
260 
261         // Update only when the data are different.
262         if (std::memcmp(l_biosValInVpdFormat.data(), l_fcoInVpd->data(),
263                         constants::VALUE_4) != constants::SUCCESS)
264         {
265             if (constants::FAILURE ==
266                 m_manager->updateKeyword(
267                     SYSTEM_VPD_FILE_PATH,
268                     types::IpzData(constants::vsysInf, constants::kwdRG,
269                                    l_biosValInVpdFormat)))
270             {
271                 logging::logMessage(
272                     "Failed to update " + std::string(constants::kwdRG) +
273                     " keyword to VPD.");
274             }
275         }
276     }
277     else
278     {
279         logging::logMessage("Invalid type read for FCO from DBus.");
280     }
281 }
282 
283 void IbmBiosHandler::saveFcoToBios(const types::BinaryVector& i_fcoVal)
284 {
285     if (i_fcoVal.size() != constants::VALUE_4)
286     {
287         logging::logMessage("Bad size for FCO received. Skip writing to BIOS");
288         return;
289     }
290 
291     types::PendingBIOSAttrs l_pendingBiosAttribute;
292     l_pendingBiosAttribute.push_back(std::make_pair(
293         "hb_field_core_override",
294         std::make_tuple(
295             "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer",
296             i_fcoVal.at(constants::VALUE_3))));
297 
298     if (!dbusUtility::writeDbusProperty(
299             constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
300             constants::biosConfigMgrInterface, "PendingAttributes",
301             l_pendingBiosAttribute))
302     {
303         // TODO: Should we log informational PEL here as well?
304         logging::logMessage(
305             "DBus call to update FCO value in pending attribute failed. ");
306     }
307 }
308 
309 void IbmBiosHandler::saveAmmToVpd(const std::string& i_memoryMirrorMode)
310 {
311     if (i_memoryMirrorMode.empty())
312     {
313         logging::logMessage(
314             "Empty memory mirror mode value from BIOS. Skip writing to VPD");
315         return;
316     }
317 
318     // Read existing value.
319     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
320         constants::pimServiceName, constants::systemVpdInvPath,
321         constants::vsysInf, constants::kwdAMM);
322 
323     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
324     {
325         auto l_ammValInVpd = *l_pVal;
326 
327         types::BinaryVector l_valToUpdateInVpd{
328             (i_memoryMirrorMode == "Enabled" ? constants::AMM_ENABLED_IN_VPD
329                                              : constants::AMM_DISABLED_IN_VPD)};
330 
331         // Check if value is already updated on VPD.
332         if (l_ammValInVpd.at(0) == l_valToUpdateInVpd.at(0))
333         {
334             return;
335         }
336 
337         if (constants::FAILURE ==
338             m_manager->updateKeyword(
339                 SYSTEM_VPD_FILE_PATH,
340                 types::IpzData(constants::vsysInf, constants::kwdAMM,
341                                l_valToUpdateInVpd)))
342         {
343             logging::logMessage(
344                 "Failed to update " + std::string(constants::kwdAMM) +
345                 " keyword to VPD");
346         }
347     }
348     else
349     {
350         // TODO: Add PEL
351         logging::logMessage(
352             "Invalid type read for memory mirror mode value from DBus. Skip writing to VPD");
353     }
354 }
355 
356 void IbmBiosHandler::saveAmmToBios(const uint8_t& i_ammVal)
357 {
358     const std::string l_valtoUpdate =
359         (i_ammVal == constants::VALUE_2) ? "Enabled" : "Disabled";
360 
361     types::PendingBIOSAttrs l_pendingBiosAttribute;
362     l_pendingBiosAttribute.push_back(std::make_pair(
363         "hb_memory_mirror_mode",
364         std::make_tuple(
365             "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
366             l_valtoUpdate)));
367 
368     if (!dbusUtility::writeDbusProperty(
369             constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
370             constants::biosConfigMgrInterface, "PendingAttributes",
371             l_pendingBiosAttribute))
372     {
373         // TODO: Should we log informational PEL here as well?
374         logging::logMessage(
375             "DBus call to update AMM value in pending attribute failed.");
376     }
377 }
378 
379 void IbmBiosHandler::processActiveMemoryMirror()
380 {
381     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
382         constants::pimServiceName, constants::systemVpdInvPath,
383         constants::vsysInf, constants::kwdAMM);
384 
385     if (auto pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
386     {
387         auto l_ammValInVpd = *pVal;
388 
389         // Check if active memory mirror value is default in VPD.
390         if (l_ammValInVpd.at(0) == constants::VALUE_0)
391         {
392             types::BiosAttributeCurrentValue l_attrValueVariant =
393                 readBiosAttribute("hb_memory_mirror_mode");
394 
395             if (auto pVal = std::get_if<std::string>(&l_attrValueVariant))
396             {
397                 saveAmmToVpd(*pVal);
398                 return;
399             }
400             logging::logMessage(
401                 "Invalid type recieved for auto memory mirror mode from BIOS.");
402             return;
403         }
404         else
405         {
406             saveAmmToBios(l_ammValInVpd.at(0));
407         }
408         return;
409     }
410     logging::logMessage(
411         "Invalid type recieved for auto memory mirror mode from VPD.");
412 }
413 
414 void IbmBiosHandler::saveCreateDefaultLparToVpd(
415     const std::string& i_createDefaultLparVal)
416 {
417     if (i_createDefaultLparVal.empty())
418     {
419         logging::logMessage(
420             "Empty value received for Lpar from BIOS. Skip writing in VPD.");
421         return;
422     }
423 
424     // Read required keyword from DBus as we need to set only a Bit.
425     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
426         constants::pimServiceName, constants::systemVpdInvPath,
427         constants::vsysInf, constants::kwdClearNVRAM_CreateLPAR);
428 
429     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
430     {
431         commonUtility::toLower(
432             const_cast<std::string&>(i_createDefaultLparVal));
433 
434         // Check for second bit. Bit set for enabled else disabled.
435         if (((((*l_pVal).at(0) & 0x02) == 0x02) &&
436              (i_createDefaultLparVal.compare("enabled") ==
437               constants::STR_CMP_SUCCESS)) ||
438             ((((*l_pVal).at(0) & 0x02) == 0x00) &&
439              (i_createDefaultLparVal.compare("disabled") ==
440               constants::STR_CMP_SUCCESS)))
441         {
442             // Values are same, Don;t update.
443             return;
444         }
445 
446         types::BinaryVector l_valToUpdateInVpd;
447         if (i_createDefaultLparVal.compare("enabled") ==
448             constants::STR_CMP_SUCCESS)
449         {
450             // 2nd Bit is used to store the value.
451             l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) | 0x02);
452         }
453         else
454         {
455             // 2nd Bit is used to store the value.
456             l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) & ~(0x02));
457         }
458 
459         if (-1 == m_manager->updateKeyword(
460                       SYSTEM_VPD_FILE_PATH,
461                       types::IpzData(constants::vsysInf,
462                                      constants::kwdClearNVRAM_CreateLPAR,
463                                      l_valToUpdateInVpd)))
464         {
465             logging::logMessage(
466                 "Failed to update " +
467                 std::string(constants::kwdClearNVRAM_CreateLPAR) +
468                 " keyword to VPD");
469         }
470 
471         return;
472     }
473     logging::logMessage(
474         "Invalid type recieved for create default Lpar from VPD.");
475 }
476 
477 void IbmBiosHandler::saveCreateDefaultLparToBios(
478     const std::string& i_createDefaultLparVal)
479 {
480     // checking for exact length as it is a string and can have garbage value.
481     if (i_createDefaultLparVal.size() != constants::VALUE_1)
482     {
483         logging::logMessage(
484             "Bad size for Create default LPAR in VPD. Skip writing to BIOS.");
485         return;
486     }
487 
488     std::string l_valtoUpdate =
489         (i_createDefaultLparVal.at(0) & 0x02) ? "Enabled" : "Disabled";
490 
491     types::PendingBIOSAttrs l_pendingBiosAttribute;
492     l_pendingBiosAttribute.push_back(std::make_pair(
493         "pvm_create_default_lpar",
494         std::make_tuple(
495             "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
496             l_valtoUpdate)));
497 
498     if (!dbusUtility::writeDbusProperty(
499             constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
500             constants::biosConfigMgrInterface, "PendingAttributes",
501             l_pendingBiosAttribute))
502     {
503         logging::logMessage(
504             "DBus call to update lpar value in pending attribute failed.");
505     }
506 
507     return;
508 }
509 
510 void IbmBiosHandler::processCreateDefaultLpar()
511 {
512     // Read required keyword from DBus.
513     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
514         constants::pimServiceName, constants::systemVpdInvPath,
515         constants::vsysInf, constants::kwdClearNVRAM_CreateLPAR);
516 
517     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
518     {
519         saveCreateDefaultLparToBios(std::to_string(l_pVal->at(0)));
520         return;
521     }
522     logging::logMessage(
523         "Invalid type recieved for create default Lpar from VPD.");
524 }
525 
526 void IbmBiosHandler::saveClearNvramToVpd(const std::string& i_clearNvramVal)
527 {
528     if (i_clearNvramVal.empty())
529     {
530         logging::logMessage(
531             "Empty value received for clear NVRAM from BIOS. Skip updating to VPD.");
532         return;
533     }
534 
535     // Read required keyword from DBus as we need to set only a Bit.
536     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
537         constants::pimServiceName, constants::systemVpdInvPath,
538         constants::vsysInf, constants::kwdClearNVRAM_CreateLPAR);
539 
540     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
541     {
542         commonUtility::toLower(const_cast<std::string&>(i_clearNvramVal));
543 
544         // Check for third bit. Bit set for enabled else disabled.
545         if (((((*l_pVal).at(0) & 0x04) == 0x04) &&
546              (i_clearNvramVal.compare("enabled") ==
547               constants::STR_CMP_SUCCESS)) ||
548             ((((*l_pVal).at(0) & 0x04) == 0x00) &&
549              (i_clearNvramVal.compare("disabled") ==
550               constants::STR_CMP_SUCCESS)))
551         {
552             // Don't update, values are same.
553             return;
554         }
555 
556         types::BinaryVector l_valToUpdateInVpd;
557         if (i_clearNvramVal.compare("enabled") == constants::STR_CMP_SUCCESS)
558         {
559             // 3rd bit is used to store the value.
560             l_valToUpdateInVpd.emplace_back(
561                 (*l_pVal).at(0) | constants::VALUE_4);
562         }
563         else
564         {
565             // 3rd bit is used to store the value.
566             l_valToUpdateInVpd.emplace_back(
567                 (*l_pVal).at(0) & ~(constants::VALUE_4));
568         }
569 
570         if (-1 == m_manager->updateKeyword(
571                       SYSTEM_VPD_FILE_PATH,
572                       types::IpzData(constants::vsysInf,
573                                      constants::kwdClearNVRAM_CreateLPAR,
574                                      l_valToUpdateInVpd)))
575         {
576             logging::logMessage(
577                 "Failed to update " +
578                 std::string(constants::kwdClearNVRAM_CreateLPAR) +
579                 " keyword to VPD");
580         }
581 
582         return;
583     }
584     logging::logMessage("Invalid type recieved for clear NVRAM from VPD.");
585 }
586 
587 void IbmBiosHandler::saveClearNvramToBios(const std::string& i_clearNvramVal)
588 {
589     // Check for the exact length as it is a string and it can have a garbage
590     // value.
591     if (i_clearNvramVal.size() != constants::VALUE_1)
592     {
593         logging::logMessage(
594             "Bad size for clear NVRAM in VPD. Skip writing to BIOS.");
595         return;
596     }
597 
598     // 3rd bit is used to store clear NVRAM value.
599     std::string l_valtoUpdate =
600         (i_clearNvramVal.at(0) & constants::VALUE_4) ? "Enabled" : "Disabled";
601 
602     types::PendingBIOSAttrs l_pendingBiosAttribute;
603     l_pendingBiosAttribute.push_back(std::make_pair(
604         "pvm_clear_nvram",
605         std::make_tuple(
606             "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
607             l_valtoUpdate)));
608 
609     if (!dbusUtility::writeDbusProperty(
610             constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
611             constants::biosConfigMgrInterface, "PendingAttributes",
612             l_pendingBiosAttribute))
613     {
614         logging::logMessage(
615             "DBus call to update NVRAM value in pending attribute failed.");
616     }
617 }
618 
619 void IbmBiosHandler::processClearNvram()
620 {
621     // Read required keyword from VPD.
622     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
623         constants::pimServiceName, constants::systemVpdInvPath,
624         constants::vsysInf, constants::kwdClearNVRAM_CreateLPAR);
625 
626     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
627     {
628         saveClearNvramToBios(std::to_string(l_pVal->at(0)));
629         return;
630     }
631     logging::logMessage("Invalid type recieved for clear NVRAM from VPD.");
632 }
633 
634 void IbmBiosHandler::saveKeepAndClearToVpd(const std::string& i_KeepAndClearVal)
635 {
636     if (i_KeepAndClearVal.empty())
637     {
638         logging::logMessage(
639             "Empty value received for keep and clear from BIOS. Skip updating to VPD.");
640         return;
641     }
642 
643     // Read required keyword from DBus as we need to set only a Bit.
644     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
645         constants::pimServiceName, constants::systemVpdInvPath,
646         constants::vsysInf, constants::kwdKeepAndClear);
647 
648     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
649     {
650         commonUtility::toLower(const_cast<std::string&>(i_KeepAndClearVal));
651 
652         // Check for first bit. Bit set for enabled else disabled.
653         if (((((*l_pVal).at(0) & 0x01) == 0x01) &&
654              (i_KeepAndClearVal.compare("enabled") ==
655               constants::STR_CMP_SUCCESS)) ||
656             ((((*l_pVal).at(0) & 0x01) == 0x00) &&
657              (i_KeepAndClearVal.compare("disabled") ==
658               constants::STR_CMP_SUCCESS)))
659         {
660             // Don't update, values are same.
661             return;
662         }
663 
664         types::BinaryVector l_valToUpdateInVpd;
665         if (i_KeepAndClearVal.compare("enabled") == constants::STR_CMP_SUCCESS)
666         {
667             // 1st bit is used to store the value.
668             l_valToUpdateInVpd.emplace_back(
669                 (*l_pVal).at(0) | constants::VALUE_1);
670         }
671         else
672         {
673             // 1st bit is used to store the value.
674             l_valToUpdateInVpd.emplace_back(
675                 (*l_pVal).at(0) & ~(constants::VALUE_1));
676         }
677 
678         if (-1 ==
679             m_manager->updateKeyword(
680                 SYSTEM_VPD_FILE_PATH,
681                 types::IpzData(constants::vsysInf, constants::kwdKeepAndClear,
682                                l_valToUpdateInVpd)))
683         {
684             logging::logMessage(
685                 "Failed to update " + std::string(constants::kwdKeepAndClear) +
686                 " keyword to VPD");
687         }
688 
689         return;
690     }
691     logging::logMessage("Invalid type recieved for keep and clear from VPD.");
692 }
693 
694 void IbmBiosHandler::saveKeepAndClearToBios(
695     const std::string& i_KeepAndClearVal)
696 {
697     // checking for exact length as it is a string and can have garbage value.
698     if (i_KeepAndClearVal.size() != constants::VALUE_1)
699     {
700         logging::logMessage(
701             "Bad size for keep and clear in VPD. Skip writing to BIOS.");
702         return;
703     }
704 
705     // 1st bit is used to store keep and clear value.
706     std::string l_valtoUpdate =
707         (i_KeepAndClearVal.at(0) & constants::VALUE_1) ? "Enabled" : "Disabled";
708 
709     types::PendingBIOSAttrs l_pendingBiosAttribute;
710     l_pendingBiosAttribute.push_back(std::make_pair(
711         "pvm_keep_and_clear",
712         std::make_tuple(
713             "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
714             l_valtoUpdate)));
715 
716     if (!dbusUtility::writeDbusProperty(
717             constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
718             constants::biosConfigMgrInterface, "PendingAttributes",
719             l_pendingBiosAttribute))
720     {
721         logging::logMessage(
722             "DBus call to update keep and clear value in pending attribute failed.");
723     }
724 }
725 
726 void IbmBiosHandler::processKeepAndClear()
727 {
728     // Read required keyword from VPD.
729     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
730         constants::pimServiceName, constants::systemVpdInvPath,
731         constants::vsysInf, constants::kwdKeepAndClear);
732 
733     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
734     {
735         saveKeepAndClearToBios(std::to_string(l_pVal->at(0)));
736         return;
737     }
738     logging::logMessage("Invalid type recieved for keep and clear from VPD.");
739 }
740 } // namespace vpd
741