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