xref: /openbmc/openpower-vpd-parser/vpd-manager/src/bios_handler.cpp (revision e621c063f1f293f510d5e10ee63f33c1ea27d70e)
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("VSYS", 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::utilInf, 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("UTIL", constants::kwdAMM, l_valToUpdateInVpd)))
341         {
342             logging::logMessage(
343                 "Failed to update " + std::string(constants::kwdAMM) +
344                 " keyword to VPD");
345         }
346     }
347     else
348     {
349         // TODO: Add PEL
350         logging::logMessage(
351             "Invalid type read for memory mirror mode value from DBus. Skip writing to VPD");
352     }
353 }
354 
355 void IbmBiosHandler::saveAmmToBios(const uint8_t& i_ammVal)
356 {
357     const std::string l_valtoUpdate =
358         (i_ammVal == constants::VALUE_2) ? "Enabled" : "Disabled";
359 
360     types::PendingBIOSAttrs l_pendingBiosAttribute;
361     l_pendingBiosAttribute.push_back(std::make_pair(
362         "hb_memory_mirror_mode",
363         std::make_tuple(
364             "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
365             l_valtoUpdate)));
366 
367     if (!dbusUtility::writeDbusProperty(
368             constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
369             constants::biosConfigMgrInterface, "PendingAttributes",
370             l_pendingBiosAttribute))
371     {
372         // TODO: Should we log informational PEL here as well?
373         logging::logMessage(
374             "DBus call to update AMM value in pending attribute failed.");
375     }
376 }
377 
378 void IbmBiosHandler::processActiveMemoryMirror()
379 {
380     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
381         constants::pimServiceName, constants::systemVpdInvPath,
382         constants::utilInf, constants::kwdAMM);
383 
384     if (auto pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
385     {
386         auto l_ammValInVpd = *pVal;
387 
388         // Check if active memory mirror value is default in VPD.
389         if (l_ammValInVpd.at(0) == constants::VALUE_0)
390         {
391             types::BiosAttributeCurrentValue l_attrValueVariant =
392                 readBiosAttribute("hb_memory_mirror_mode");
393 
394             if (auto pVal = std::get_if<std::string>(&l_attrValueVariant))
395             {
396                 saveAmmToVpd(*pVal);
397                 return;
398             }
399             logging::logMessage(
400                 "Invalid type recieved for auto memory mirror mode from BIOS.");
401             return;
402         }
403         else
404         {
405             saveAmmToBios(l_ammValInVpd.at(0));
406         }
407         return;
408     }
409     logging::logMessage(
410         "Invalid type recieved for auto memory mirror mode from VPD.");
411 }
412 
413 void IbmBiosHandler::saveCreateDefaultLparToVpd(
414     const std::string& i_createDefaultLparVal)
415 {
416     if (i_createDefaultLparVal.empty())
417     {
418         logging::logMessage(
419             "Empty value received for Lpar from BIOS. Skip writing in VPD.");
420         return;
421     }
422 
423     // Read required keyword from DBus as we need to set only a Bit.
424     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
425         constants::pimServiceName, constants::systemVpdInvPath,
426         constants::utilInf, constants::kwdClearNVRAM_CreateLPAR);
427 
428     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
429     {
430         commonUtility::toLower(
431             const_cast<std::string&>(i_createDefaultLparVal));
432 
433         // Check for second bit. Bit set for enabled else disabled.
434         if (((((*l_pVal).at(0) & 0x02) == 0x02) &&
435              (i_createDefaultLparVal.compare("enabled") ==
436               constants::STR_CMP_SUCCESS)) ||
437             ((((*l_pVal).at(0) & 0x02) == 0x00) &&
438              (i_createDefaultLparVal.compare("disabled") ==
439               constants::STR_CMP_SUCCESS)))
440         {
441             // Values are same, Don;t update.
442             return;
443         }
444 
445         types::BinaryVector l_valToUpdateInVpd;
446         if (i_createDefaultLparVal.compare("enabled") ==
447             constants::STR_CMP_SUCCESS)
448         {
449             // 2nd Bit is used to store the value.
450             l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) | 0x02);
451         }
452         else
453         {
454             // 2nd Bit is used to store the value.
455             l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) & ~(0x02));
456         }
457 
458         if (-1 ==
459             m_manager->updateKeyword(
460                 SYSTEM_VPD_FILE_PATH,
461                 types::IpzData("UTIL", constants::kwdClearNVRAM_CreateLPAR,
462                                l_valToUpdateInVpd)))
463         {
464             logging::logMessage(
465                 "Failed to update " +
466                 std::string(constants::kwdClearNVRAM_CreateLPAR) +
467                 " keyword to VPD");
468         }
469 
470         return;
471     }
472     logging::logMessage(
473         "Invalid type recieved for create default Lpar from VPD.");
474 }
475 
476 void IbmBiosHandler::saveCreateDefaultLparToBios(
477     const std::string& i_createDefaultLparVal)
478 {
479     // checking for exact length as it is a string and can have garbage value.
480     if (i_createDefaultLparVal.size() != constants::VALUE_1)
481     {
482         logging::logMessage(
483             "Bad size for Create default LPAR in VPD. Skip writing to BIOS.");
484         return;
485     }
486 
487     std::string l_valtoUpdate =
488         (i_createDefaultLparVal.at(0) & 0x02) ? "Enabled" : "Disabled";
489 
490     types::PendingBIOSAttrs l_pendingBiosAttribute;
491     l_pendingBiosAttribute.push_back(std::make_pair(
492         "pvm_create_default_lpar",
493         std::make_tuple(
494             "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
495             l_valtoUpdate)));
496 
497     if (!dbusUtility::writeDbusProperty(
498             constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
499             constants::biosConfigMgrInterface, "PendingAttributes",
500             l_pendingBiosAttribute))
501     {
502         logging::logMessage(
503             "DBus call to update lpar value in pending attribute failed.");
504     }
505 
506     return;
507 }
508 
509 void IbmBiosHandler::processCreateDefaultLpar()
510 {
511     // Read required keyword from DBus.
512     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
513         constants::pimServiceName, constants::systemVpdInvPath,
514         constants::utilInf, constants::kwdClearNVRAM_CreateLPAR);
515 
516     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
517     {
518         saveCreateDefaultLparToBios(std::to_string(l_pVal->at(0)));
519         return;
520     }
521     logging::logMessage(
522         "Invalid type recieved for create default Lpar from VPD.");
523 }
524 
525 void IbmBiosHandler::saveClearNvramToVpd(const std::string& i_clearNvramVal)
526 {
527     if (i_clearNvramVal.empty())
528     {
529         logging::logMessage(
530             "Empty value received for clear NVRAM from BIOS. Skip updating to VPD.");
531         return;
532     }
533 
534     // Read required keyword from DBus as we need to set only a Bit.
535     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
536         constants::pimServiceName, constants::systemVpdInvPath,
537         constants::utilInf, constants::kwdClearNVRAM_CreateLPAR);
538 
539     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
540     {
541         commonUtility::toLower(const_cast<std::string&>(i_clearNvramVal));
542 
543         // Check for third bit. Bit set for enabled else disabled.
544         if (((((*l_pVal).at(0) & 0x04) == 0x04) &&
545              (i_clearNvramVal.compare("enabled") ==
546               constants::STR_CMP_SUCCESS)) ||
547             ((((*l_pVal).at(0) & 0x04) == 0x00) &&
548              (i_clearNvramVal.compare("disabled") ==
549               constants::STR_CMP_SUCCESS)))
550         {
551             // Don't update, values are same.
552             return;
553         }
554 
555         types::BinaryVector l_valToUpdateInVpd;
556         if (i_clearNvramVal.compare("enabled") == constants::STR_CMP_SUCCESS)
557         {
558             // 3rd bit is used to store the value.
559             l_valToUpdateInVpd.emplace_back(
560                 (*l_pVal).at(0) | constants::VALUE_4);
561         }
562         else
563         {
564             // 3rd bit is used to store the value.
565             l_valToUpdateInVpd.emplace_back(
566                 (*l_pVal).at(0) & ~(constants::VALUE_4));
567         }
568 
569         if (-1 ==
570             m_manager->updateKeyword(
571                 SYSTEM_VPD_FILE_PATH,
572                 types::IpzData("UTIL", constants::kwdClearNVRAM_CreateLPAR,
573                                l_valToUpdateInVpd)))
574         {
575             logging::logMessage(
576                 "Failed to update " +
577                 std::string(constants::kwdClearNVRAM_CreateLPAR) +
578                 " keyword to VPD");
579         }
580 
581         return;
582     }
583     logging::logMessage("Invalid type recieved for clear NVRAM from VPD.");
584 }
585 
586 void IbmBiosHandler::saveClearNvramToBios(const std::string& i_clearNvramVal)
587 {
588     // Check for the exact length as it is a string and it can have a garbage
589     // value.
590     if (i_clearNvramVal.size() != constants::VALUE_1)
591     {
592         logging::logMessage(
593             "Bad size for clear NVRAM in VPD. Skip writing to BIOS.");
594         return;
595     }
596 
597     // 3rd bit is used to store clear NVRAM value.
598     std::string l_valtoUpdate =
599         (i_clearNvramVal.at(0) & constants::VALUE_4) ? "Enabled" : "Disabled";
600 
601     types::PendingBIOSAttrs l_pendingBiosAttribute;
602     l_pendingBiosAttribute.push_back(std::make_pair(
603         "pvm_clear_nvram",
604         std::make_tuple(
605             "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
606             l_valtoUpdate)));
607 
608     if (!dbusUtility::writeDbusProperty(
609             constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
610             constants::biosConfigMgrInterface, "PendingAttributes",
611             l_pendingBiosAttribute))
612     {
613         logging::logMessage(
614             "DBus call to update NVRAM value in pending attribute failed.");
615     }
616 }
617 
618 void IbmBiosHandler::processClearNvram()
619 {
620     // Read required keyword from VPD.
621     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
622         constants::pimServiceName, constants::systemVpdInvPath,
623         constants::utilInf, constants::kwdClearNVRAM_CreateLPAR);
624 
625     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
626     {
627         saveClearNvramToBios(std::to_string(l_pVal->at(0)));
628         return;
629     }
630     logging::logMessage("Invalid type recieved for clear NVRAM from VPD.");
631 }
632 
633 void IbmBiosHandler::saveKeepAndClearToVpd(const std::string& i_KeepAndClearVal)
634 {
635     if (i_KeepAndClearVal.empty())
636     {
637         logging::logMessage(
638             "Empty value received for keep and clear from BIOS. Skip updating to VPD.");
639         return;
640     }
641 
642     // Read required keyword from DBus as we need to set only a Bit.
643     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
644         constants::pimServiceName, constants::systemVpdInvPath,
645         constants::utilInf, constants::kwdKeepAndClear);
646 
647     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
648     {
649         commonUtility::toLower(const_cast<std::string&>(i_KeepAndClearVal));
650 
651         // Check for first bit. Bit set for enabled else disabled.
652         if (((((*l_pVal).at(0) & 0x01) == 0x01) &&
653              (i_KeepAndClearVal.compare("enabled") ==
654               constants::STR_CMP_SUCCESS)) ||
655             ((((*l_pVal).at(0) & 0x01) == 0x00) &&
656              (i_KeepAndClearVal.compare("disabled") ==
657               constants::STR_CMP_SUCCESS)))
658         {
659             // Don't update, values are same.
660             return;
661         }
662 
663         types::BinaryVector l_valToUpdateInVpd;
664         if (i_KeepAndClearVal.compare("enabled") == constants::STR_CMP_SUCCESS)
665         {
666             // 1st bit is used to store the value.
667             l_valToUpdateInVpd.emplace_back(
668                 (*l_pVal).at(0) | constants::VALUE_1);
669         }
670         else
671         {
672             // 1st bit is used to store the value.
673             l_valToUpdateInVpd.emplace_back(
674                 (*l_pVal).at(0) & ~(constants::VALUE_1));
675         }
676 
677         if (-1 == m_manager->updateKeyword(
678                       SYSTEM_VPD_FILE_PATH,
679                       types::IpzData("UTIL", constants::kwdKeepAndClear,
680                                      l_valToUpdateInVpd)))
681         {
682             logging::logMessage(
683                 "Failed to update " + std::string(constants::kwdKeepAndClear) +
684                 " keyword to VPD");
685         }
686 
687         return;
688     }
689     logging::logMessage("Invalid type recieved for keep and clear from VPD.");
690 }
691 
692 void IbmBiosHandler::saveKeepAndClearToBios(
693     const std::string& i_KeepAndClearVal)
694 {
695     // checking for exact length as it is a string and can have garbage value.
696     if (i_KeepAndClearVal.size() != constants::VALUE_1)
697     {
698         logging::logMessage(
699             "Bad size for keep and clear in VPD. Skip writing to BIOS.");
700         return;
701     }
702 
703     // 1st bit is used to store keep and clear value.
704     std::string l_valtoUpdate =
705         (i_KeepAndClearVal.at(0) & constants::VALUE_1) ? "Enabled" : "Disabled";
706 
707     types::PendingBIOSAttrs l_pendingBiosAttribute;
708     l_pendingBiosAttribute.push_back(std::make_pair(
709         "pvm_keep_and_clear",
710         std::make_tuple(
711             "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
712             l_valtoUpdate)));
713 
714     if (!dbusUtility::writeDbusProperty(
715             constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
716             constants::biosConfigMgrInterface, "PendingAttributes",
717             l_pendingBiosAttribute))
718     {
719         logging::logMessage(
720             "DBus call to update keep and clear value in pending attribute failed.");
721     }
722 }
723 
724 void IbmBiosHandler::processKeepAndClear()
725 {
726     // Read required keyword from VPD.
727     auto l_kwdValueVariant = dbusUtility::readDbusProperty(
728         constants::pimServiceName, constants::systemVpdInvPath,
729         constants::utilInf, constants::kwdKeepAndClear);
730 
731     if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
732     {
733         saveKeepAndClearToBios(std::to_string(l_pVal->at(0)));
734         return;
735     }
736     logging::logMessage("Invalid type recieved for keep and clear from VPD.");
737 }
738 } // namespace vpd
739