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