xref: /openbmc/openpower-vpd-parser/vpd-manager/src/bios_handler.cpp (revision 022112bc235c7f91ee998bb131f06e212dee1f6a)
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 up.
23     static std::shared_ptr<sdbusplus::bus::match_t> l_nameOwnerMatch =
24         std::make_shared<sdbusplus::bus::match_t>(
25             *m_asioConn,
26             sdbusplus::bus::match::rules::nameOwnerChanged(
27                 constants::pldmServiceName),
28             [this](sdbusplus::message_t& l_msg) {
29                 if (l_msg.is_method_error())
30                 {
31                     logging::logMessage(
32                         "Error in reading PLDM name owner changed signal.");
33                     return;
34                 }
35 
36                 std::string l_name;
37                 std::string l_newOwner;
38                 std::string l_oldOwner;
39 
40                 l_msg.read(l_name, l_oldOwner, l_newOwner);
41 
42                 if (!l_newOwner.empty() &&
43                     (l_name.compare(constants::pldmServiceName) ==
44                      constants::STR_CMP_SUCCESS))
45                 {
46                     m_specificBiosHandler->backUpOrRestoreBiosAttributes();
47 
48                     // Start listener now that we have done the restore.
49                     listenBiosAttributes();
50 
51                     //  We don't need the match anymore
52                     l_nameOwnerMatch.reset();
53                 }
54             });
55 
56     // Based on PLDM service status reset owner match registered above and
57     // trigger BIOS attribute sync.
58     if (dbusUtility::isServiceRunning(constants::pldmServiceName))
59     {
60         l_nameOwnerMatch.reset();
61         m_specificBiosHandler->backUpOrRestoreBiosAttributes();
62 
63         // Start listener now that we have done the restore.
64         listenBiosAttributes();
65     }
66 }
67 
68 template <typename T>
69 void BiosHandler<T>::listenBiosAttributes()
70 {
71     static std::shared_ptr<sdbusplus::bus::match_t> l_biosMatch =
72         std::make_shared<sdbusplus::bus::match_t>(
73             *m_asioConn,
74             sdbusplus::bus::match::rules::propertiesChanged(
75                 constants::biosConfigMgrObjPath,
76                 constants::biosConfigMgrInterface),
77             [this](sdbusplus::message_t& l_msg) {
78                 m_specificBiosHandler->biosAttributesCallback(l_msg);
79             });
80 }
81 
82 void IbmBiosHandler::biosAttributesCallback(sdbusplus::message_t& i_msg)
83 {
84     if (i_msg.is_method_error())
85     {
86         logging::logMessage("Error in reading BIOS attribute signal. ");
87         return;
88     }
89 
90     std::string l_objPath;
91     types::BiosBaseTableType l_propMap;
92     i_msg.read(l_objPath, l_propMap);
93 
94     for (auto l_property : l_propMap)
95     {
96         if (l_property.first != "BaseBIOSTable")
97         {
98             // Looking for change in Base BIOS table only.
99             continue;
100         }
101 
102         if (auto l_attributeList =
103                 std::get_if<std::map<std::string, types::BiosProperty>>(
104                     &(l_property.second)))
105         {
106             for (const auto& l_attribute : *l_attributeList)
107             {
108                 if (auto l_val = std::get_if<std::string>(
109                         &(std::get<5>(std::get<1>(l_attribute)))))
110                 {
111                     std::string l_attributeName = std::get<0>(l_attribute);
112                     if (l_attributeName == "hb_memory_mirror_mode")
113                     {
114                         saveAmmToVpd(*l_val);
115                     }
116 
117                     if (l_attributeName == "pvm_keep_and_clear")
118                     {
119                         saveKeepAndClearToVpd(*l_val);
120                     }
121 
122                     if (l_attributeName == "pvm_create_default_lpar")
123                     {
124                         saveCreateDefaultLparToVpd(*l_val);
125                     }
126 
127                     if (l_attributeName == "pvm_clear_nvram")
128                     {
129                         saveClearNvramToVpd(*l_val);
130                     }
131 
132                     continue;
133                 }
134 
135                 if (auto l_val = std::get_if<int64_t>(
136                         &(std::get<5>(std::get<1>(l_attribute)))))
137                 {
138                     std::string l_attributeName = std::get<0>(l_attribute);
139                     if (l_attributeName == "hb_field_core_override")
140                     {
141                         saveFcoToVpd(*l_val);
142                     }
143                 }
144             }
145         }
146         else
147         {
148             // TODO: log a predicitive PEL.
149             logging::logMessage("Invalid typre received from BIOS table.");
150             break;
151         }
152     }
153 }
154 
155 void IbmBiosHandler::backUpOrRestoreBiosAttributes()
156 {
157     // process FCO
158     processFieldCoreOverride();
159 
160     // process AMM
161     processActiveMemoryMirror();
162 
163     // process LPAR
164     processCreateDefaultLpar();
165 
166     // process clear NVRAM
167     processClearNvram();
168 
169     // process keep and clear
170     processKeepAndClear();
171 }
172 
173 types::BiosAttributeCurrentValue IbmBiosHandler::readBiosAttribute(
174     const std::string& i_attributeName)
175 {
176     types::BiosAttributeCurrentValue l_attrValueVariant =
177         dbusUtility::biosGetAttributeMethodCall(i_attributeName);
178 
179     return l_attrValueVariant;
180 }
181 
182 void IbmBiosHandler::processFieldCoreOverride()
183 {
184     // TODO: Should we avoid doing this at runtime?
185 
186     // Read required keyword from Dbus.
187     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
188         constants::pimServiceName, constants::systemVpdInvPath,
189         constants::vsysInf, constants::kwdRG);
190 
191     if (auto l_fcoInVpd = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
192     {
193         // default length of the keyword is 4 bytes.
194         if (l_fcoInVpd->size() != constants::VALUE_4)
195         {
196             logging::logMessage(
197                 "Invalid value read for FCO from D-Bus. Skipping.");
198         }
199 
200         //  If FCO in VPD contains anything other that ASCII Space, restore to
201         //  BIOS
202         if (std::any_of(l_fcoInVpd->cbegin(), l_fcoInVpd->cend(),
203                         [](uint8_t l_val) {
204                             return l_val != constants::ASCII_OF_SPACE;
205                         }))
206         {
207             // Restore the data to BIOS.
208             saveFcoToBios(*l_fcoInVpd);
209         }
210         else
211         {
212             types::BiosAttributeCurrentValue l_attrValueVariant =
213                 readBiosAttribute("hb_field_core_override");
214 
215             if (auto l_fcoInBios = std::get_if<int64_t>(&l_attrValueVariant))
216             {
217                 // save the BIOS data to VPD
218                 saveFcoToVpd(*l_fcoInBios);
219 
220                 return;
221             }
222             logging::logMessage("Invalid type recieved for FCO from BIOS.");
223         }
224         return;
225     }
226     logging::logMessage("Invalid type recieved for FCO from VPD.");
227 }
228 
229 void IbmBiosHandler::saveFcoToVpd(int64_t i_fcoInBios)
230 {
231     if (i_fcoInBios < 0)
232     {
233         logging::logMessage("Invalid FCO value in BIOS. Skip updating to VPD");
234         return;
235     }
236 
237     // Read required keyword from Dbus.
238     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
239         constants::pimServiceName, constants::systemVpdInvPath,
240         constants::vsysInf, constants::kwdRG);
241 
242     if (auto l_fcoInVpd = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
243     {
244         // default length of the keyword is 4 bytes.
245         if (l_fcoInVpd->size() != constants::VALUE_4)
246         {
247             logging::logMessage(
248                 "Invalid value read for FCO from D-Bus. Skipping.");
249             return;
250         }
251 
252         // convert to VPD value type
253         types::BinaryVector l_biosValInVpdFormat = {
254             0, 0, 0, static_cast<uint8_t>(i_fcoInBios)};
255 
256         // Update only when the data are different.
257         if (std::memcmp(l_biosValInVpdFormat.data(), l_fcoInVpd->data(),
258                         constants::VALUE_4) != constants::SUCCESS)
259         {
260             if (constants::FAILURE ==
261                 m_manager->updateKeyword(
262                     SYSTEM_VPD_FILE_PATH,
263                     types::IpzData("VSYS", constants::kwdRG,
264                                    l_biosValInVpdFormat)))
265             {
266                 logging::logMessage(
267                     "Failed to update " + std::string(constants::kwdRG) +
268                     " keyword to VPD.");
269             }
270         }
271     }
272     else
273     {
274         logging::logMessage("Invalid type read for FCO from DBus.");
275     }
276 }
277 
278 void IbmBiosHandler::saveFcoToBios(const types::BinaryVector& i_fcoVal)
279 {
280     if (i_fcoVal.size() != constants::VALUE_4)
281     {
282         logging::logMessage("Bad size for FCO received. Skip writing to BIOS");
283         return;
284     }
285 
286     types::PendingBIOSAttrs l_pendingBiosAttribute;
287     l_pendingBiosAttribute.push_back(std::make_pair(
288         "hb_field_core_override",
289         std::make_tuple(
290             "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer",
291             i_fcoVal.at(constants::VALUE_3))));
292 
293     if (!dbusUtility::writeDbusProperty(
294             constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
295             constants::biosConfigMgrInterface, "PendingAttributes",
296             l_pendingBiosAttribute))
297     {
298         // TODO: Should we log informational PEL here as well?
299         logging::logMessage(
300             "DBus call to update FCO value in pending attribute failed. ");
301     }
302 }
303 
304 void IbmBiosHandler::saveAmmToVpd(const std::string& i_memoryMirrorMode)
305 {
306     if (i_memoryMirrorMode.empty())
307     {
308         logging::logMessage(
309             "Empty memory mirror mode value from BIOS. Skip writing to VPD");
310         return;
311     }
312 
313     // Read existing value.
314     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
315         constants::pimServiceName, constants::systemVpdInvPath,
316         constants::utilInf, constants::kwdAMM);
317 
318     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
319     {
320         auto l_ammValInVpd = *l_pVal;
321 
322         types::BinaryVector l_valToUpdateInVpd{
323             (i_memoryMirrorMode == "Enabled" ? constants::AMM_ENABLED_IN_VPD
324                                              : constants::AMM_DISABLED_IN_VPD)};
325 
326         // Check if value is already updated on VPD.
327         if (l_ammValInVpd.at(0) == l_valToUpdateInVpd.at(0))
328         {
329             return;
330         }
331 
332         if (constants::FAILURE ==
333             m_manager->updateKeyword(
334                 SYSTEM_VPD_FILE_PATH,
335                 types::IpzData("UTIL", constants::kwdAMM, l_valToUpdateInVpd)))
336         {
337             logging::logMessage(
338                 "Failed to update " + std::string(constants::kwdAMM) +
339                 " keyword to VPD");
340         }
341     }
342     else
343     {
344         // TODO: Add PEL
345         logging::logMessage(
346             "Invalid type read for memory mirror mode value from DBus. Skip writing to VPD");
347     }
348 }
349 
350 void IbmBiosHandler::saveAmmToBios(const std::string& i_ammVal)
351 {
352     if (i_ammVal.size() != constants::VALUE_1)
353     {
354         logging::logMessage("Bad size for AMM received, Skip writing to BIOS");
355         return;
356     }
357 
358     const std::string l_valtoUpdate =
359         (i_ammVal.at(0) == 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::utilInf, 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(std::to_string(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::utilInf, 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 ==
460             m_manager->updateKeyword(
461                 SYSTEM_VPD_FILE_PATH,
462                 types::IpzData("UTIL", 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::utilInf, 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::utilInf, 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 ==
571             m_manager->updateKeyword(
572                 SYSTEM_VPD_FILE_PATH,
573                 types::IpzData("UTIL", 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::utilInf, 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::utilInf, 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 == m_manager->updateKeyword(
679                       SYSTEM_VPD_FILE_PATH,
680                       types::IpzData("UTIL", constants::kwdKeepAndClear,
681                                      l_valToUpdateInVpd)))
682         {
683             logging::logMessage(
684                 "Failed to update " + std::string(constants::kwdKeepAndClear) +
685                 " keyword to VPD");
686         }
687 
688         return;
689     }
690     logging::logMessage("Invalid type recieved for keep and clear from VPD.");
691 }
692 
693 void IbmBiosHandler::saveKeepAndClearToBios(
694     const std::string& i_KeepAndClearVal)
695 {
696     // checking for exact length as it is a string and can have garbage value.
697     if (i_KeepAndClearVal.size() != constants::VALUE_1)
698     {
699         logging::logMessage(
700             "Bad size for keep and clear in VPD. Skip writing to BIOS.");
701         return;
702     }
703 
704     // 1st bit is used to store keep and clear value.
705     std::string l_valtoUpdate =
706         (i_KeepAndClearVal.at(0) & constants::VALUE_1) ? "Enabled" : "Disabled";
707 
708     types::PendingBIOSAttrs l_pendingBiosAttribute;
709     l_pendingBiosAttribute.push_back(std::make_pair(
710         "pvm_keep_and_clear",
711         std::make_tuple(
712             "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
713             l_valtoUpdate)));
714 
715     if (!dbusUtility::writeDbusProperty(
716             constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
717             constants::biosConfigMgrInterface, "PendingAttributes",
718             l_pendingBiosAttribute))
719     {
720         logging::logMessage(
721             "DBus call to update keep and clear value in pending attribute failed.");
722     }
723 }
724 
725 void IbmBiosHandler::processKeepAndClear()
726 {
727     // Read required keyword from VPD.
728     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
729         constants::pimServiceName, constants::systemVpdInvPath,
730         constants::utilInf, constants::kwdKeepAndClear);
731 
732     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
733     {
734         saveKeepAndClearToBios(std::to_string(l_pVal->at(0)));
735         return;
736     }
737     logging::logMessage("Invalid type recieved for keep and clear from VPD.");
738 }
739 } // namespace vpd
740