blob: 24212775049cf508105be00068f07decfc671767 [file] [log] [blame]
Santosh Puranikf2d3b532022-04-19 06:44:07 -05001#include "config.h"
2
3#include "bios_handler.hpp"
4
5#include "const.hpp"
6#include "ibm_vpd_utils.hpp"
7#include "manager.hpp"
8#include "types.hpp"
9
10#include <iostream>
11#include <memory>
12#include <sdbusplus/bus.hpp>
13#include <string>
14#include <tuple>
15#include <variant>
16
17using namespace openpower::vpd;
18using namespace openpower::vpd::constants;
19
20namespace openpower
21{
22namespace vpd
23{
24namespace manager
25{
26void BiosHandler::checkAndListenPLDMService()
27{
28 // Setup a match on NameOwnerChanged to determine when PLDM is up. In
29 // the signal handler, call restoreBIOSAttribs
30 static std::shared_ptr<sdbusplus::bus::match::match> nameOwnerMatch =
31 std::make_shared<sdbusplus::bus::match::match>(
32 bus,
33 sdbusplus::bus::match::rules::nameOwnerChanged(
34 "xyz.openbmc_project.PLDM"),
35 [this](sdbusplus::message::message& msg) {
36 if (msg.is_method_error())
37 {
38 std::cerr << "Error in reading name owner signal "
39 << std::endl;
40 return;
41 }
42 std::string name;
43 std::string newOwner;
44 std::string oldOwner;
45
46 msg.read(name, oldOwner, newOwner);
47 if (newOwner != "" && name == "xyz.openbmc_project.PLDM")
48 {
49 this->restoreBIOSAttribs();
50 // We don't need the match anymore
51 nameOwnerMatch.reset();
52 }
53 });
54 // Check if PLDM is already running, if it is, we can go ahead and attempt
55 // to sync BIOS attributes (since PLDM would have initialized them by the
56 // time it acquires a bus name).
57 bool isPLDMRunning = false;
58 try
59 {
60 auto bus = sdbusplus::bus::new_default();
61 auto method =
62 bus.new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus",
63 "org.freedesktop.DBus", "NameHasOwner");
64 method.append("xyz.openbmc_project.PLDM");
65
66 auto result = bus.call(method);
67 result.read(isPLDMRunning);
68 }
69 catch (const sdbusplus::exception::SdBusError& e)
70 {
71 std::cerr << "Failed to check if PLDM is running, assume false"
72 << std::endl;
73 std::cerr << e.what() << std::endl;
74 }
75
76 std::cout << "Is PLDM running: " << isPLDMRunning << std::endl;
77
78 if (isPLDMRunning)
79 {
80 nameOwnerMatch.reset();
81 restoreBIOSAttribs();
82 }
83}
84
85void BiosHandler::listenBiosAttribs()
86{
87 static std::shared_ptr<sdbusplus::bus::match::match> biosMatcher =
88 std::make_shared<sdbusplus::bus::match::match>(
89 bus,
90 sdbusplus::bus::match::rules::propertiesChanged(
91 "/xyz/openbmc_project/bios_config/manager",
92 "xyz.openbmc_project.BIOSConfig.Manager"),
93 [this](sdbusplus::message::message& msg) {
94 biosAttribsCallback(msg);
95 });
96}
97
98void BiosHandler::biosAttribsCallback(sdbusplus::message::message& msg)
99{
100 if (msg.is_method_error())
101 {
102 std::cerr << "Error in reading BIOS attribute signal " << std::endl;
103 return;
104 }
105 using BiosProperty = std::tuple<
106 std::string, bool, std::string, std::string, std::string,
107 std::variant<int64_t, std::string>, std::variant<int64_t, std::string>,
108 std::vector<
109 std::tuple<std::string, std::variant<int64_t, std::string>>>>;
110 using BiosBaseTable = std::variant<std::map<std::string, BiosProperty>>;
111 using BiosBaseTableType = std::map<std::string, BiosBaseTable>;
112
113 std::string object;
114 BiosBaseTableType propMap;
115 msg.read(object, propMap);
116 for (auto prop : propMap)
117 {
118 if (prop.first == "BaseBIOSTable")
119 {
120 auto list = std::get<0>(prop.second);
121 for (const auto& item : list)
122 {
123 std::string attributeName = std::get<0>(item);
124 if (attributeName == "hb_memory_mirror_mode")
125 {
126 auto attrValue = std::get<5>(std::get<1>(item));
127 auto val = std::get_if<std::string>(&attrValue);
128 if (val)
129 {
130 saveAMMToVPD(*val);
131 }
132 }
133 else if (attributeName == "hb_field_core_override")
134 {
135 auto attrValue = std::get<5>(std::get<1>(item));
136 auto val = std::get_if<int64_t>(&attrValue);
137 if (val)
138 {
139 saveFCOToVPD(*val);
140 }
141 }
142 }
143 }
144 }
145}
146
147void BiosHandler::saveFCOToVPD(int64_t fcoVal)
148{
149 if (fcoVal == -1)
150 {
151 std::cerr << "Invalid FCO value from BIOS: " << fcoVal << std::endl;
152 return;
153 }
154
155 Binary vpdVal = {0, 0, 0, static_cast<uint8_t>(fcoVal)};
156 auto valInVPD = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "RG");
157
158 if (valInVPD.size() != 4)
159 {
160 std::cerr << "Read bad size for VSYS/RG: " << valInVPD.size()
161 << std::endl;
162 return;
163 }
164
165 if (valInVPD.at(3) != fcoVal)
166 {
167 std::cout << "Writing FCO to VPD: " << fcoVal << std::endl;
168 manager.writeKeyword(sdbusplus::message::object_path{SYSTEM_OBJECT},
169 "VSYS", "RG", vpdVal);
170 }
171}
172
173void BiosHandler::saveAMMToVPD(const std::string& mirrorMode)
174{
175 Binary vpdVal;
176 auto valInVPD = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.UTIL", "D0");
177
178 if (valInVPD.size() != 1)
179 {
180 std::cerr << "Read bad size for UTIL/D0: " << valInVPD.size()
181 << std::endl;
182 return;
183 }
184
185 if (mirrorMode != "Enabled" && mirrorMode != "Disabled")
186 {
187 std::cerr << "Bad value for Mirror mode BIOS arttribute: " << mirrorMode
188 << std::endl;
189 return;
190 }
191
192 // Write to VPD only if the value is not already what we want to write.
193 if (mirrorMode == "Enabled" && valInVPD.at(0) != 2)
194 {
195 vpdVal.emplace_back(2);
196 }
197 else if (mirrorMode == "Disabled" && valInVPD.at(0) != 1)
198 {
199 vpdVal.emplace_back(1);
200 }
201
202 if (!vpdVal.empty())
203 {
204 std::cout << "Writing AMM to VPD: " << static_cast<int>(vpdVal.at(0))
205 << std::endl;
206 manager.writeKeyword(sdbusplus::message::object_path{SYSTEM_OBJECT},
207 "UTIL", "D0", vpdVal);
208 }
209}
210
211int64_t BiosHandler::readBIOSFCO()
212{
213 int64_t fcoVal = -1;
214 auto val = readBIOSAttribute("hb_field_core_override");
215
216 if (auto pVal = std::get_if<int64_t>(&val))
217 {
218 fcoVal = *pVal;
219 }
220 else
221 {
222 std::cerr << "FCO is not an int" << std::endl;
223 }
224 return fcoVal;
225}
226
227std::string BiosHandler::readBIOSAMM()
228{
229 std::string ammVal{};
230 auto val = readBIOSAttribute("hb_memory_mirror_mode");
231
232 if (auto pVal = std::get_if<std::string>(&val))
233 {
234 ammVal = *pVal;
235 }
236 else
237 {
238 std::cerr << "AMM is not a string" << std::endl;
239 }
240 return ammVal;
241}
242
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500243void BiosHandler::saveFCOToBIOS(const std::string& fcoVal, int64_t fcoInBIOS)
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500244{
245 if (fcoVal.size() != 4)
246 {
247 std::cerr << "Bad size for FCO in VPD: " << fcoVal.size() << std::endl;
248 return;
249 }
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500250
251 // Need to write?
252 if (fcoInBIOS == static_cast<int64_t>(fcoVal.at(3)))
253 {
254 std::cout << "Skip FCO BIOS write, value is already: " << fcoInBIOS
255 << std::endl;
256 return;
257 }
258
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500259 PendingBIOSAttrsType biosAttrs;
260 biosAttrs.push_back(
261 std::make_pair("hb_field_core_override",
262 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
263 "AttributeType.Integer",
264 fcoVal.at(3))));
265
266 std::cout << "Set hb_field_core_override to: "
267 << static_cast<int>(fcoVal.at(3)) << std::endl;
268
269 setBusProperty<PendingBIOSAttrsType>(
270 "xyz.openbmc_project.BIOSConfigManager",
271 "/xyz/openbmc_project/bios_config/manager",
272 "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes",
273 biosAttrs);
274}
275
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500276void BiosHandler::saveAMMToBIOS(const std::string& ammVal,
277 const std::string& ammInBIOS)
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500278{
279 if (ammVal.size() != 1)
280 {
281 std::cerr << "Bad size for AMM in VPD: " << ammVal.size() << std::endl;
282 return;
283 }
284
285 // Make sure data in VPD is sane
286 if (ammVal.at(0) != 1 && ammVal.at(0) != 2)
287 {
288 std::cerr << "Bad value for AMM read from VPD: "
289 << static_cast<int>(ammVal.at(0)) << std::endl;
290 return;
291 }
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500292
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500293 // Need to write?
294 std::string toWrite = (ammVal.at(0) == 2) ? "Enabled" : "Disabled";
295 if (ammInBIOS == toWrite)
296 {
297 std::cout << "Skip AMM BIOS write, value is already: " << toWrite
298 << std::endl;
299 return;
300 }
301
302 PendingBIOSAttrsType biosAttrs;
303 biosAttrs.push_back(
304 std::make_pair("hb_memory_mirror_mode",
305 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
306 "AttributeType.Enumeration",
307 toWrite)));
308
309 std::cout << "Set hb_memory_mirror_mode to: " << toWrite << std::endl;
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500310
311 setBusProperty<PendingBIOSAttrsType>(
312 "xyz.openbmc_project.BIOSConfigManager",
313 "/xyz/openbmc_project/bios_config/manager",
314 "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes",
315 biosAttrs);
316}
317
318void BiosHandler::restoreBIOSAttribs()
319{
320 // TODO: We could make this slightly more scalable by defining a table of
321 // attributes and their corresponding VPD keywords. However, that needs much
322 // more thought.
323 std::cout << "Attempting BIOS attribute reset" << std::endl;
324 // Check if the VPD contains valid data for FCO and AMM *and* that it
325 // differs from the data already in the attributes. If so, set the BIOS
326 // attributes as per the value in the VPD.
327 // If the VPD contains default data, then initialize the VPD keywords with
328 // data taken from the BIOS.
329 auto fcoInVPD = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "RG");
330 auto ammInVPD = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.UTIL", "D0");
331 auto fcoInBIOS = readBIOSFCO();
332 auto ammInBIOS = readBIOSAMM();
333
334 if (fcoInVPD == " ")
335 {
336 saveFCOToVPD(fcoInBIOS);
337 }
338 else
339 {
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500340 saveFCOToBIOS(fcoInVPD, fcoInBIOS);
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500341 }
342
343 if (ammInVPD.at(0) == 0)
344 {
345 saveAMMToVPD(ammInBIOS);
346 }
347 else
348 {
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500349 saveAMMToBIOS(ammInVPD, ammInBIOS);
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500350 }
351
352 // Start listener now that we have done the restore
353 listenBiosAttribs();
354}
355} // namespace manager
356} // namespace vpd
357} // namespace openpower