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