blob: 417852e544b9407a142362d98805fc2cbab9278c [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
Patrick Williams2eb01762022-07-22 19:26:56 -050030 static std::shared_ptr<sdbusplus::bus::match_t> nameOwnerMatch =
31 std::make_shared<sdbusplus::bus::match_t>(
Santosh Puranikf2d3b532022-04-19 06:44:07 -050032 bus,
33 sdbusplus::bus::match::rules::nameOwnerChanged(
34 "xyz.openbmc_project.PLDM"),
Patrick Williams2eb01762022-07-22 19:26:56 -050035 [this](sdbusplus::message_t& msg) {
Santosh Puranikf2d3b532022-04-19 06:44:07 -050036 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{
Patrick Williams2eb01762022-07-22 19:26:56 -050087 static std::shared_ptr<sdbusplus::bus::match_t> biosMatcher =
88 std::make_shared<sdbusplus::bus::match_t>(
Santosh Puranikf2d3b532022-04-19 06:44:07 -050089 bus,
90 sdbusplus::bus::match::rules::propertiesChanged(
91 "/xyz/openbmc_project/bios_config/manager",
92 "xyz.openbmc_project.BIOSConfig.Manager"),
Patrick Williams2eb01762022-07-22 19:26:56 -050093 [this](sdbusplus::message_t& msg) { biosAttribsCallback(msg); });
Santosh Puranikf2d3b532022-04-19 06:44:07 -050094}
95
Patrick Williams2eb01762022-07-22 19:26:56 -050096void BiosHandler::biosAttribsCallback(sdbusplus::message_t& msg)
Santosh Puranikf2d3b532022-04-19 06:44:07 -050097{
98 if (msg.is_method_error())
99 {
100 std::cerr << "Error in reading BIOS attribute signal " << std::endl;
101 return;
102 }
103 using BiosProperty = std::tuple<
104 std::string, bool, std::string, std::string, std::string,
105 std::variant<int64_t, std::string>, std::variant<int64_t, std::string>,
106 std::vector<
107 std::tuple<std::string, std::variant<int64_t, std::string>>>>;
108 using BiosBaseTable = std::variant<std::map<std::string, BiosProperty>>;
109 using BiosBaseTableType = std::map<std::string, BiosBaseTable>;
110
111 std::string object;
112 BiosBaseTableType propMap;
113 msg.read(object, propMap);
114 for (auto prop : propMap)
115 {
116 if (prop.first == "BaseBIOSTable")
117 {
118 auto list = std::get<0>(prop.second);
119 for (const auto& item : list)
120 {
121 std::string attributeName = std::get<0>(item);
122 if (attributeName == "hb_memory_mirror_mode")
123 {
124 auto attrValue = std::get<5>(std::get<1>(item));
125 auto val = std::get_if<std::string>(&attrValue);
126 if (val)
127 {
128 saveAMMToVPD(*val);
129 }
130 }
131 else if (attributeName == "hb_field_core_override")
132 {
133 auto attrValue = std::get<5>(std::get<1>(item));
134 auto val = std::get_if<int64_t>(&attrValue);
135 if (val)
136 {
137 saveFCOToVPD(*val);
138 }
139 }
140 }
141 }
142 }
143}
144
145void BiosHandler::saveFCOToVPD(int64_t fcoVal)
146{
147 if (fcoVal == -1)
148 {
149 std::cerr << "Invalid FCO value from BIOS: " << fcoVal << std::endl;
150 return;
151 }
152
153 Binary vpdVal = {0, 0, 0, static_cast<uint8_t>(fcoVal)};
154 auto valInVPD = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "RG");
155
156 if (valInVPD.size() != 4)
157 {
158 std::cerr << "Read bad size for VSYS/RG: " << valInVPD.size()
159 << std::endl;
160 return;
161 }
162
163 if (valInVPD.at(3) != fcoVal)
164 {
165 std::cout << "Writing FCO to VPD: " << fcoVal << std::endl;
166 manager.writeKeyword(sdbusplus::message::object_path{SYSTEM_OBJECT},
167 "VSYS", "RG", vpdVal);
168 }
169}
170
171void BiosHandler::saveAMMToVPD(const std::string& mirrorMode)
172{
173 Binary vpdVal;
174 auto valInVPD = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.UTIL", "D0");
175
176 if (valInVPD.size() != 1)
177 {
178 std::cerr << "Read bad size for UTIL/D0: " << valInVPD.size()
179 << std::endl;
180 return;
181 }
182
183 if (mirrorMode != "Enabled" && mirrorMode != "Disabled")
184 {
185 std::cerr << "Bad value for Mirror mode BIOS arttribute: " << mirrorMode
186 << std::endl;
187 return;
188 }
189
190 // Write to VPD only if the value is not already what we want to write.
191 if (mirrorMode == "Enabled" && valInVPD.at(0) != 2)
192 {
193 vpdVal.emplace_back(2);
194 }
195 else if (mirrorMode == "Disabled" && valInVPD.at(0) != 1)
196 {
197 vpdVal.emplace_back(1);
198 }
199
200 if (!vpdVal.empty())
201 {
202 std::cout << "Writing AMM to VPD: " << static_cast<int>(vpdVal.at(0))
203 << std::endl;
204 manager.writeKeyword(sdbusplus::message::object_path{SYSTEM_OBJECT},
205 "UTIL", "D0", vpdVal);
206 }
207}
208
209int64_t BiosHandler::readBIOSFCO()
210{
211 int64_t fcoVal = -1;
212 auto val = readBIOSAttribute("hb_field_core_override");
213
214 if (auto pVal = std::get_if<int64_t>(&val))
215 {
216 fcoVal = *pVal;
217 }
218 else
219 {
220 std::cerr << "FCO is not an int" << std::endl;
221 }
222 return fcoVal;
223}
224
225std::string BiosHandler::readBIOSAMM()
226{
227 std::string ammVal{};
228 auto val = readBIOSAttribute("hb_memory_mirror_mode");
229
230 if (auto pVal = std::get_if<std::string>(&val))
231 {
232 ammVal = *pVal;
233 }
234 else
235 {
236 std::cerr << "AMM is not a string" << std::endl;
237 }
238 return ammVal;
239}
240
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500241void BiosHandler::saveFCOToBIOS(const std::string& fcoVal, int64_t fcoInBIOS)
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500242{
243 if (fcoVal.size() != 4)
244 {
245 std::cerr << "Bad size for FCO in VPD: " << fcoVal.size() << std::endl;
246 return;
247 }
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500248
249 // Need to write?
250 if (fcoInBIOS == static_cast<int64_t>(fcoVal.at(3)))
251 {
252 std::cout << "Skip FCO BIOS write, value is already: " << fcoInBIOS
253 << std::endl;
254 return;
255 }
256
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500257 PendingBIOSAttrsType biosAttrs;
258 biosAttrs.push_back(
259 std::make_pair("hb_field_core_override",
260 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
261 "AttributeType.Integer",
262 fcoVal.at(3))));
263
264 std::cout << "Set hb_field_core_override to: "
265 << static_cast<int>(fcoVal.at(3)) << std::endl;
266
267 setBusProperty<PendingBIOSAttrsType>(
268 "xyz.openbmc_project.BIOSConfigManager",
269 "/xyz/openbmc_project/bios_config/manager",
270 "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes",
271 biosAttrs);
272}
273
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500274void BiosHandler::saveAMMToBIOS(const std::string& ammVal,
275 const std::string& ammInBIOS)
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500276{
277 if (ammVal.size() != 1)
278 {
279 std::cerr << "Bad size for AMM in VPD: " << ammVal.size() << std::endl;
280 return;
281 }
282
283 // Make sure data in VPD is sane
284 if (ammVal.at(0) != 1 && ammVal.at(0) != 2)
285 {
286 std::cerr << "Bad value for AMM read from VPD: "
287 << static_cast<int>(ammVal.at(0)) << std::endl;
288 return;
289 }
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500290
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500291 // Need to write?
292 std::string toWrite = (ammVal.at(0) == 2) ? "Enabled" : "Disabled";
293 if (ammInBIOS == toWrite)
294 {
295 std::cout << "Skip AMM BIOS write, value is already: " << toWrite
296 << std::endl;
297 return;
298 }
299
300 PendingBIOSAttrsType biosAttrs;
301 biosAttrs.push_back(
302 std::make_pair("hb_memory_mirror_mode",
303 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
304 "AttributeType.Enumeration",
305 toWrite)));
306
307 std::cout << "Set hb_memory_mirror_mode to: " << toWrite << std::endl;
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500308
309 setBusProperty<PendingBIOSAttrsType>(
310 "xyz.openbmc_project.BIOSConfigManager",
311 "/xyz/openbmc_project/bios_config/manager",
312 "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes",
313 biosAttrs);
314}
315
316void BiosHandler::restoreBIOSAttribs()
317{
318 // TODO: We could make this slightly more scalable by defining a table of
319 // attributes and their corresponding VPD keywords. However, that needs much
320 // more thought.
321 std::cout << "Attempting BIOS attribute reset" << std::endl;
322 // Check if the VPD contains valid data for FCO and AMM *and* that it
323 // differs from the data already in the attributes. If so, set the BIOS
324 // attributes as per the value in the VPD.
325 // If the VPD contains default data, then initialize the VPD keywords with
326 // data taken from the BIOS.
327 auto fcoInVPD = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "RG");
328 auto ammInVPD = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.UTIL", "D0");
329 auto fcoInBIOS = readBIOSFCO();
330 auto ammInBIOS = readBIOSAMM();
331
332 if (fcoInVPD == " ")
333 {
334 saveFCOToVPD(fcoInBIOS);
335 }
336 else
337 {
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500338 saveFCOToBIOS(fcoInVPD, fcoInBIOS);
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500339 }
340
341 if (ammInVPD.at(0) == 0)
342 {
343 saveAMMToVPD(ammInBIOS);
344 }
345 else
346 {
Santosh Puranikf7f8da62022-05-06 13:01:19 -0500347 saveAMMToBIOS(ammInVPD, ammInBIOS);
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500348 }
349
350 // Start listener now that we have done the restore
351 listenBiosAttribs();
352}
353} // namespace manager
354} // namespace vpd
355} // namespace openpower