blob: cb251a6739dc28806ca2a446e8a3facb288b3803 [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
243void BiosHandler::saveFCOToBIOS(const std::string& fcoVal)
244{
245 if (fcoVal.size() != 4)
246 {
247 std::cerr << "Bad size for FCO in VPD: " << fcoVal.size() << std::endl;
248 return;
249 }
250 PendingBIOSAttrsType biosAttrs;
251 biosAttrs.push_back(
252 std::make_pair("hb_field_core_override",
253 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
254 "AttributeType.Integer",
255 fcoVal.at(3))));
256
257 std::cout << "Set hb_field_core_override to: "
258 << static_cast<int>(fcoVal.at(3)) << std::endl;
259
260 setBusProperty<PendingBIOSAttrsType>(
261 "xyz.openbmc_project.BIOSConfigManager",
262 "/xyz/openbmc_project/bios_config/manager",
263 "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes",
264 biosAttrs);
265}
266
267void BiosHandler::saveAMMToBIOS(const std::string& ammVal)
268{
269 if (ammVal.size() != 1)
270 {
271 std::cerr << "Bad size for AMM in VPD: " << ammVal.size() << std::endl;
272 return;
273 }
274
275 // Make sure data in VPD is sane
276 if (ammVal.at(0) != 1 && ammVal.at(0) != 2)
277 {
278 std::cerr << "Bad value for AMM read from VPD: "
279 << static_cast<int>(ammVal.at(0)) << std::endl;
280 return;
281 }
282 PendingBIOSAttrsType biosAttrs;
283 biosAttrs.push_back(std::make_pair(
284 "hb_memory_mirror_mode",
285 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
286 "AttributeType.Enumeration",
287 (ammVal.at(0) == 2) ? "Enabled" : "Disabled")));
288
289 std::cout << "Set hb_memory_mirror_mode to: "
290 << ((ammVal.at(0) == 2) ? "Enabled" : "Disabled") << std::endl;
291
292 setBusProperty<PendingBIOSAttrsType>(
293 "xyz.openbmc_project.BIOSConfigManager",
294 "/xyz/openbmc_project/bios_config/manager",
295 "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes",
296 biosAttrs);
297}
298
299void BiosHandler::restoreBIOSAttribs()
300{
301 // TODO: We could make this slightly more scalable by defining a table of
302 // attributes and their corresponding VPD keywords. However, that needs much
303 // more thought.
304 std::cout << "Attempting BIOS attribute reset" << std::endl;
305 // Check if the VPD contains valid data for FCO and AMM *and* that it
306 // differs from the data already in the attributes. If so, set the BIOS
307 // attributes as per the value in the VPD.
308 // If the VPD contains default data, then initialize the VPD keywords with
309 // data taken from the BIOS.
310 auto fcoInVPD = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "RG");
311 auto ammInVPD = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.UTIL", "D0");
312 auto fcoInBIOS = readBIOSFCO();
313 auto ammInBIOS = readBIOSAMM();
314
315 if (fcoInVPD == " ")
316 {
317 saveFCOToVPD(fcoInBIOS);
318 }
319 else
320 {
321 saveFCOToBIOS(fcoInVPD);
322 }
323
324 if (ammInVPD.at(0) == 0)
325 {
326 saveAMMToVPD(ammInBIOS);
327 }
328 else
329 {
330 saveAMMToBIOS(ammInVPD);
331 }
332
333 // Start listener now that we have done the restore
334 listenBiosAttribs();
335}
336} // namespace manager
337} // namespace vpd
338} // namespace openpower