blob: 73dd2292d84a4dbbffb60c2a91587816597b4eb0 [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#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
14namespace vpd
15{
16// Template declaration to define APIs.
17template class BiosHandler<IbmBiosHandler>;
18
19template <typename T>
20void 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
68template <typename T>
69void 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
82void 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 {
Sunny Srivastavab7818d12025-04-13 13:21:36 +0530148 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);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500154 break;
155 }
156 }
157}
158
159void 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
Patrick Williams43fedab2025-02-03 14:28:05 -0500177types::BiosAttributeCurrentValue IbmBiosHandler::readBiosAttribute(
178 const std::string& i_attributeName)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500179{
180 types::BiosAttributeCurrentValue l_attrValueVariant =
181 dbusUtility::biosGetAttributeMethodCall(i_attributeName);
182
183 return l_attrValueVariant;
184}
185
186void 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
233void 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
282void 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
RekhaAparna01c532b182025-02-19 19:56:49 -0600297 if (!dbusUtility::writeDbusProperty(
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500298 constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
299 constants::biosConfigMgrInterface, "PendingAttributes",
RekhaAparna01c532b182025-02-19 19:56:49 -0600300 l_pendingBiosAttribute))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500301 {
302 // TODO: Should we log informational PEL here as well?
303 logging::logMessage(
RekhaAparna01c532b182025-02-19 19:56:49 -0600304 "DBus call to update FCO value in pending attribute failed. ");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500305 }
306}
307
308void 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
Anupama B R3aca2932025-03-05 22:37:15 -0600354void IbmBiosHandler::saveAmmToBios(const uint8_t& i_ammVal)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500355{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500356 const std::string l_valtoUpdate =
Anupama B R3aca2932025-03-05 22:37:15 -0600357 (i_ammVal == constants::VALUE_2) ? "Enabled" : "Disabled";
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500358
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
RekhaAparna01c532b182025-02-19 19:56:49 -0600366 if (!dbusUtility::writeDbusProperty(
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500367 constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
368 constants::biosConfigMgrInterface, "PendingAttributes",
RekhaAparna01c532b182025-02-19 19:56:49 -0600369 l_pendingBiosAttribute))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500370 {
371 // TODO: Should we log informational PEL here as well?
372 logging::logMessage(
RekhaAparna01c532b182025-02-19 19:56:49 -0600373 "DBus call to update AMM value in pending attribute failed.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500374 }
375}
376
377void 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 {
Anupama B R3aca2932025-03-05 22:37:15 -0600404 saveAmmToBios(l_ammValInVpd.at(0));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500405 }
406 return;
407 }
408 logging::logMessage(
409 "Invalid type recieved for auto memory mirror mode from VPD.");
410}
411
412void 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
475void 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
RekhaAparna01c532b182025-02-19 19:56:49 -0600496 if (!dbusUtility::writeDbusProperty(
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500497 constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
498 constants::biosConfigMgrInterface, "PendingAttributes",
RekhaAparna01c532b182025-02-19 19:56:49 -0600499 l_pendingBiosAttribute))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500500 {
501 logging::logMessage(
RekhaAparna01c532b182025-02-19 19:56:49 -0600502 "DBus call to update lpar value in pending attribute failed.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500503 }
504
505 return;
506}
507
508void 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
524void 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
585void 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
RekhaAparna01c532b182025-02-19 19:56:49 -0600607 if (!dbusUtility::writeDbusProperty(
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500608 constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
609 constants::biosConfigMgrInterface, "PendingAttributes",
RekhaAparna01c532b182025-02-19 19:56:49 -0600610 l_pendingBiosAttribute))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500611 {
612 logging::logMessage(
RekhaAparna01c532b182025-02-19 19:56:49 -0600613 "DBus call to update NVRAM value in pending attribute failed.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500614 }
615}
616
617void 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
632void 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
Patrick Williams43fedab2025-02-03 14:28:05 -0500691void IbmBiosHandler::saveKeepAndClearToBios(
692 const std::string& i_KeepAndClearVal)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500693{
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
RekhaAparna01c532b182025-02-19 19:56:49 -0600713 if (!dbusUtility::writeDbusProperty(
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500714 constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
715 constants::biosConfigMgrInterface, "PendingAttributes",
RekhaAparna01c532b182025-02-19 19:56:49 -0600716 l_pendingBiosAttribute))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500717 {
718 logging::logMessage(
RekhaAparna01c532b182025-02-19 19:56:49 -0600719 "DBus call to update keep and clear value in pending attribute failed.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500720 }
721}
722
723void 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