blob: ba2610ad0d7dc5e04cbc505df130e7d12fcb7d34 [file] [log] [blame]
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001/*
2// Copyright (c) 2020 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Arun Lal K Me7725612021-07-15 18:20:58 +000017#include "biosxml.hpp"
18
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080019#include <openssl/sha.h>
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080020
21#include <biosconfigcommands.hpp>
22#include <boost/crc.hpp>
23#include <boost/process/child.hpp>
24#include <boost/process/io.hpp>
25#include <ipmid/api.hpp>
26#include <ipmid/message.hpp>
27#include <ipmid/message/types.hpp>
28#include <ipmid/types.hpp>
29#include <ipmid/utils.hpp>
30#include <nlohmann/json.hpp>
31#include <oemcommands.hpp>
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080032#include <sdbusplus/bus.hpp>
33#include <sdbusplus/message/types.hpp>
34
35#include <filesystem>
Suryakanth Sekarcc402592021-04-01 15:02:10 +053036#include <string_view>
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080037
38namespace ipmi
39{
Arun Lal K Mb0caca02021-09-05 22:09:33 +000040static bool flushNVOOBdata();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080041static void registerBIOSConfigFunctions() __attribute__((constructor));
42
43// Define BIOS config related Completion Code
44using Cc = uint8_t;
45static constexpr Cc ipmiCCPayloadPayloadPacketMissed = 0x80;
46static constexpr Cc ipmiCCBIOSPasswordInitNotDone = 0x80;
47static constexpr Cc ipmiCCPayloadChecksumFailed = 0x81;
48static constexpr Cc ipmiCCNotSupportedInCurrentState = 0x82;
49static constexpr Cc ipmiCCPayloadPayloadInComplete = 0x83;
50static constexpr Cc ipmiCCBIOSCapabilityInitNotDone = 0x85;
51static constexpr Cc ipmiCCPayloadLengthIllegal = 0x85;
52
53static constexpr uint8_t userPasswordChanged = (1 << 5);
54static constexpr uint8_t adminPasswordChanged = (1 << 4);
Snehalatha Venkatesh6346e982022-03-09 06:49:18 +000055static constexpr uint8_t restoreDefaultValues = (1 << 7);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080056
57static constexpr const char* biosConfigFolder = "/var/oob";
58static constexpr const char* biosConfigNVPath = "/var/oob/nvoobdata.dat";
59static constexpr const uint8_t algoSHA384 = 2;
Ayushi Smriti32381872021-06-23 11:05:48 +053060static constexpr const uint8_t algoSHA256 = 1;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080061static constexpr const uint8_t biosCapOffsetBit = 0x3;
62static constexpr uint16_t maxGetPayloadDataSize = 4096;
63static constexpr const char* biosXMLFilePath = "/var/oob/bios.xml";
64static constexpr const char* biosXMLFilePath1 = "/var/oob/tempbios.xml";
65
66static constexpr const char* biosConfigBaseMgrPath =
67 "/xyz/openbmc_project/bios_config/manager";
68static constexpr const char* biosConfigIntf =
69 "xyz.openbmc_project.BIOSConfig.Manager";
70static constexpr const char* resetBIOSSettingsProp = "ResetBIOSSettings";
71/*baseBIOSTable
72map{attributeName,struct{attributeType,readonlyStatus,displayname,
73 description,menuPath,current,default,
74 array{struct{optionstring,optionvalue}}}}
75*/
Arun Lal K Me7725612021-07-15 18:20:58 +000076
77bios::BiosBaseTableType attributesData;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080078
79NVOOBdata gNVOOBdata;
80
81enum class PTState : uint8_t
82{
83 StartTransfer = 0,
84 InProgress = 1,
85 EndTransfer = 2,
86 UserAbort = 3
87};
88enum class PStatus : uint8_t
89{
90 Unknown = 0,
91 Valid = 1,
92 Corrupted = 2
93};
94enum class PType : uint8_t
95{
96 IntelXMLType0 = 0,
97 IntelXMLType1 = 1,
98 OTAPayload = 5,
99};
100
101//
102// GetPayload Payload status enumeration
103//
104enum class GetPayloadParameter : uint8_t
105{
106 GetPayloadInfo = 0, // 0
107 GetPayloadData = 1, // 1
Matt Simmering2daecd62022-05-19 12:50:53 -0700108 GetPayloadStatus = 2,
109 MaxPayloadParameters
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800110};
111
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000112namespace payload1
113{
114
115enum class AttributesType : uint8_t
116{
117 unknown = 0,
118 string,
Arun Lal K Md2d60ab2021-12-29 19:42:03 +0000119 integer,
120 enumeration
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000121};
122
123using PendingAttributesType =
Jason M. Bills0748c692022-09-08 15:34:08 -0700124 std::map<std::string, std::tuple<std::string, ipmi::DbusVariant>>;
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000125
126AttributesType getAttrType(const std::string_view typeDbus)
127{
128 if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager."
129 "AttributeType.String")
130 {
131 return AttributesType::string;
132 }
133 else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
134 "Manager.AttributeType.Integer")
135 {
136 return AttributesType::integer;
137 }
Arun Lal K Md2d60ab2021-12-29 19:42:03 +0000138 else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
139 "Manager.AttributeType.Enumeration")
140 {
141 return AttributesType::enumeration;
142 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000143
144 return AttributesType::unknown;
145}
146
147bool fillPayloadData(std::string& payloadData,
Jason M. Bills0748c692022-09-08 15:34:08 -0700148 const ipmi::DbusVariant& attributes,
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000149 const std::string_view key, AttributesType& attrType)
150{
151 payloadData += key;
152 payloadData += '=';
153
Arun Lal K Md2d60ab2021-12-29 19:42:03 +0000154 if (attrType == AttributesType::string ||
155 attrType == AttributesType::enumeration)
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000156 {
157 if (!std::holds_alternative<std::string>(attributes))
158 {
159 phosphor::logging::log<phosphor::logging::level::ERR>(
160 "fillPayloadData: No string data in attributes");
161 return false;
162 }
163 payloadData += std::get<std::string>(attributes);
164 }
165 else if (attrType == AttributesType::integer)
166 {
167 if (!std::holds_alternative<int64_t>(attributes))
168 {
169 phosphor::logging::log<phosphor::logging::level::ERR>(
170 "fillPayloadData: No int64_t data in attributes");
171 return false;
172 }
173 payloadData += std::to_string(std::get<int64_t>(attributes));
174 }
175 else
176 {
177 phosphor::logging::log<phosphor::logging::level::ERR>(
178 "fillPayloadData: Unsupported attribute type");
179 return false;
180 }
181
182 payloadData += '\n';
183
184 return true;
185}
186
Vernon Mauerydcff1502022-09-28 11:12:46 -0700187bool getPendingList(ipmi::Context::ptr& ctx, std::string& payloadData)
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000188{
189 std::variant<PendingAttributesType> pendingAttributesData;
190 boost::system::error_code ec;
191
192 payloadData.clear();
193
194 auto dbus = getSdBus();
195 if (!dbus)
196 {
197 phosphor::logging::log<phosphor::logging::level::ERR>(
198 "getPendingList: getSdBus() failed");
199 return false;
200 }
201
Patrick Williams1bcced02024-08-16 15:20:24 -0400202 std::string service =
203 getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000204
205 try
206 {
207 pendingAttributesData =
208 dbus->yield_method_call<std::variant<PendingAttributesType>>(
209 ctx->yield, ec, service,
210 "/xyz/openbmc_project/bios_config/manager",
211 "org.freedesktop.DBus.Properties", "Get",
212 "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes");
213 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500214 catch (const std::exception& ex)
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000215 {
216 phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
217 return false;
218 }
219
220 if (ec)
221 {
222 std::string err = "getPendingList: error while trying to get "
223 "PendingAttributes, error = ";
224 err += ec.message();
225
226 phosphor::logging::log<phosphor::logging::level::ERR>(err.c_str());
227
228 return false;
229 }
230
231 const PendingAttributesType* pendingAttributes =
232 std::get_if<PendingAttributesType>(&pendingAttributesData);
233 if (!pendingAttributes)
234 {
235 phosphor::logging::log<phosphor::logging::level::ERR>(
236 "getPendingList: pendingAttributes is null");
237 return false;
238 }
239
240 for (const auto& [key, attributes] : *pendingAttributes)
241 {
242 const std::string& itemType = std::get<0>(attributes);
243 AttributesType attrType = getAttrType(itemType);
244
245 if (!fillPayloadData(payloadData, std::get<1>(attributes), key,
246 attrType))
247 {
248 return false;
249 }
250 }
251
252 if (payloadData.empty())
253 {
254 phosphor::logging::log<phosphor::logging::level::ERR>(
255 "getPendingList: payloadData is empty");
256 return false;
257 }
258
259 return true;
260}
261bool updatePayloadFile(std::string& payloadFilePath, std::string payloadData)
262{
263 std::ofstream payloadFile(payloadFilePath,
264 std::ios::out | std::ios::binary);
265
266 payloadFile << payloadData;
267
268 if (!payloadFile.good())
269 {
270 return false;
271 }
272
273 return true;
274}
275
276bool computeCheckSum(std::string& payloadFilePath,
277 boost::crc_32_type& calcChecksum)
278{
279 std::ifstream payloadFile(payloadFilePath.c_str(),
280 std::ios::in | std::ios::binary | std::ios::ate);
281
282 if (!payloadFile.good())
283 {
284 phosphor::logging::log<phosphor::logging::level::ERR>(
285 "computeCheckSum: Cannot open Payload1 file");
286 return false;
287 }
288
289 payloadFile.seekg(0, payloadFile.end);
290 int length = payloadFile.tellg();
291 payloadFile.seekg(0, payloadFile.beg);
292
293 if (maxGetPayloadDataSize < length)
294 {
295 phosphor::logging::log<phosphor::logging::level::ERR>(
296 "computeCheckSum: length > maxGetPayloadDataSize");
297 return false;
298 }
299
300 std::unique_ptr<char[]> payloadBuffer(new char[length]);
301
302 payloadFile.read(payloadBuffer.get(), length);
303 uint32_t readCount = payloadFile.gcount();
304
305 calcChecksum.process_bytes(payloadBuffer.get(), readCount);
306
307 return true;
308}
309
310bool updatePayloadInfo(std::string& payloadFilePath)
311{
312 boost::crc_32_type calcChecksum;
313
314 uint8_t payloadType = static_cast<uint8_t>(ipmi::PType::IntelXMLType1);
315 auto& payloadInfo = gNVOOBdata.payloadInfo[payloadType];
316
317 if (!computeCheckSum(payloadFilePath, calcChecksum))
318 {
319 phosphor::logging::log<phosphor::logging::level::ERR>(
320 "updatePayloadInfo: Cannot compute checksum for Payload1 file");
321 return false;
322 }
323
324 payloadInfo.payloadVersion = 0;
325 payloadInfo.payloadflag = 0;
326 payloadInfo.payloadReservationID = rand();
327
328 payloadInfo.payloadType = payloadType;
329
330 payloadInfo.payloadTotalChecksum = calcChecksum.checksum();
331 payloadInfo.payloadCurrentChecksum = payloadInfo.payloadTotalChecksum;
332
333 payloadInfo.payloadStatus = (static_cast<uint8_t>(ipmi::PStatus::Valid));
334
335 struct stat filestat;
336 /* Get entry's information. */
337 if (!stat(payloadFilePath.c_str(), &filestat))
338 {
339 payloadInfo.payloadTimeStamp = filestat.st_mtime;
340 payloadInfo.payloadTotalSize = filestat.st_size;
341 payloadInfo.payloadCurrentSize = filestat.st_size;
342 payloadInfo.actualTotalPayloadWritten = filestat.st_size;
343 }
344 else
345 {
346 phosphor::logging::log<phosphor::logging::level::ERR>(
347 "updatePayloadInfo: Cannot get file status for Payload1 file");
348 return false;
349 }
350
351 if (!flushNVOOBdata())
352 {
353 phosphor::logging::log<phosphor::logging::level::ERR>(
354 "updatePayloadInfo: flushNVOOBdata failed");
355 return false;
356 }
357
358 return true;
359}
360
Vernon Mauerydcff1502022-09-28 11:12:46 -0700361bool update(ipmi::Context::ptr& ctx)
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000362{
363 std::string payloadFilePath =
364 "/var/oob/Payload" +
365 std::to_string(static_cast<uint8_t>(ipmi::PType::IntelXMLType1));
366
367 std::string payloadData;
368
369 if (!getPendingList(ctx, payloadData))
370 {
371 phosphor::logging::log<phosphor::logging::level::ERR>(
372 "payload1::update : getPendingList() failed");
373 return false;
374 }
375
376 if (!updatePayloadFile(payloadFilePath, payloadData))
377 {
378 phosphor::logging::log<phosphor::logging::level::ERR>(
379 "payload1::update : updatePayloadFile() failed");
380 return false;
381 }
382
383 if (!updatePayloadInfo(payloadFilePath))
384 {
385 phosphor::logging::log<phosphor::logging::level::ERR>(
386 "payload1::update : updatePayloadInfo() failed");
387 return false;
388 }
389
390 return true;
391}
392} // namespace payload1
393
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800394/** @brief implement to set the BaseBIOSTable property
395 * @returns status
396 */
Arun Lal K Me7725612021-07-15 18:20:58 +0000397static bool sendAllAttributes(std::string service)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800398{
Arun Lal K Me7725612021-07-15 18:20:58 +0000399 std::shared_ptr<sdbusplus::asio::connection> pSdBusPlus = getSdBus();
400
401 if (pSdBusPlus)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800402 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000403 try
404 {
405 pSdBusPlus->async_method_call(
406 [](const boost::system::error_code ec) {
Patrick Williams1bcced02024-08-16 15:20:24 -0400407 /* No more need to keep attributes data in memory */
408 attributesData.clear();
Arun Lal K Me7725612021-07-15 18:20:58 +0000409
Patrick Williams1bcced02024-08-16 15:20:24 -0400410 if (ec)
411 {
412 phosphor::logging::log<phosphor::logging::level::ERR>(
413 "sendAllAttributes error: send all attributes - "
414 "failed");
415 return;
416 }
Arun Lal K Me7725612021-07-15 18:20:58 +0000417
Patrick Williams1bcced02024-08-16 15:20:24 -0400418 phosphor::logging::log<phosphor::logging::level::INFO>(
419 "sendAllAttributes: send all attributes - done");
420 },
Arun Lal K Me7725612021-07-15 18:20:58 +0000421 service, biosConfigBaseMgrPath,
422 "org.freedesktop.DBus.Properties", "Set", biosConfigIntf,
423 "BaseBIOSTable",
424 std::variant<bios::BiosBaseTableType>(attributesData));
425
426 return true;
427 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500428 catch (const std::exception& ex)
Arun Lal K Me7725612021-07-15 18:20:58 +0000429 {
430 phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
431 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800432 }
Arun Lal K Me7725612021-07-15 18:20:58 +0000433
434 return false;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800435}
436
437/** @brief implement to flush the updated data in nv space
438 * @returns status
439 */
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000440static bool flushNVOOBdata()
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800441{
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000442 std::ofstream outFile(biosConfigNVPath, std::ios::binary);
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000443
444 outFile.seekp(std::ios_base::beg);
445 const char* writedata = reinterpret_cast<const char*>(&gNVOOBdata);
446 outFile.write(writedata, sizeof(struct NVOOBdata));
447
448 if (!outFile.good())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800449 {
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000450 return false;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800451 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000452
453 return true;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800454}
455
456/** @brief implement to get the System State
457 * @returns status
458 */
Arun Lal K M382dc972022-01-20 22:18:23 +0000459static bool getPostCompleted()
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800460{
Arun Lal K M382dc972022-01-20 22:18:23 +0000461 /*
462 * In case of failure we treat postCompleted as true.
463 * So that BIOS config commands is not accepted by BMC by mistake.
464 */
465 bool postCompleted = true;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800466
467 try
468 {
469 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -0400470 Value variant = getDbusProperty(
471 *dbus, "xyz.openbmc_project.State.Host0",
472 "/xyz/openbmc_project/state/host0",
473 "xyz.openbmc_project.State.OperatingSystem.Status",
474 "OperatingSystemState");
Arun Lal K M382dc972022-01-20 22:18:23 +0000475 auto& value = std::get<std::string>(variant);
476
477 // The short strings "Standby" is deprecated in favor of the
478 // full enum strings. Support for the short strings will be
479 // removed in the future.
480 postCompleted = (value == "Standby") ||
481 (value == "xyz.openbmc_project.State.OperatingSystem."
482 "Status.OSStatus.Standby");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800483 }
484 catch (const std::exception& e)
485 {
Arun Lal K M382dc972022-01-20 22:18:23 +0000486 phosphor::logging::log<phosphor::logging::level::ERR>(
Potin Lai4c042402024-02-26 15:18:39 +0800487 "'getDbusProperty' failed to read xyz.openbmc_project.State.Host0");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800488 }
Arun Lal K M382dc972022-01-20 22:18:23 +0000489
490 return postCompleted;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800491}
492
493/** @brief implement to get the Rest BIOS property
494 * @returns status
495 */
496static int getResetBIOSSettings(uint8_t& ResetFlag)
497{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800498 try
499 {
500 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -0400501 std::string service =
502 getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800503 Value variant = getDbusProperty(*dbus, service, biosConfigBaseMgrPath,
504 biosConfigIntf, resetBIOSSettingsProp);
Suryakanth Sekarcc402592021-04-01 15:02:10 +0530505
506 std::string_view ResetStr = std::get<std::string>(variant);
507 if (ResetStr ==
508 "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.NoAction")
509 {
510 ResetFlag = 0;
511 }
512 else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag."
513 "FactoryDefaults")
514 {
515 ResetFlag = 1;
516 }
517 else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag."
518 "FailSafeDefaults")
519 {
520 ResetFlag = 2;
521 }
522 else
523 {
524 return ipmi::ccUnspecifiedError;
525 }
526
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800527 return ipmi::ccSuccess;
528 }
529 catch (const std::exception& e)
530 {
531 return ipmi::ccUnspecifiedError;
532 }
533}
534
Arun Lal K Me7725612021-07-15 18:20:58 +0000535/** @brief Get attributes data (bios base table) from bios.xml
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800536 */
Arun Lal K Me7725612021-07-15 18:20:58 +0000537static bool generateAttributesData()
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800538{
Arun Lal K Me7725612021-07-15 18:20:58 +0000539 try
540 {
541 bios::Xml biosxml(biosXMLFilePath);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800542
Arun Lal K Me7725612021-07-15 18:20:58 +0000543 if (!biosxml.doDepexCompute())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800544 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000545 phosphor::logging::log<phosphor::logging::level::ERR>(
546 "'depex' compute failed");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800547 }
Arun Lal K Me7725612021-07-15 18:20:58 +0000548
549 if (!biosxml.getBaseTable(attributesData))
550 {
551 phosphor::logging::log<phosphor::logging::level::ERR>(
552 "Failed to get bios base table");
553 }
554 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500555 catch (const std::exception& ex)
Arun Lal K Me7725612021-07-15 18:20:58 +0000556 {
557 phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
558 return false;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800559 }
560
Arun Lal K Me7725612021-07-15 18:20:58 +0000561 return true;
562}
563
564/** @brief Generate attributes data from bios.xml
565 * and send attributes data (bios base table) to dbus using set method.
566 */
567static void generateAndSendAttributesData(std::string service,
568 uint8_t payloadType)
569{
570 if (!generateAttributesData())
571 {
572 phosphor::logging::log<phosphor::logging::level::ERR>(
573 "generateAndSendAttributesData: generateAttributesData - failed");
574 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
575 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
576 return;
577 }
578
579 phosphor::logging::log<phosphor::logging::level::INFO>(
580 "generateAndSendAttributesData : generateAttributesData is done");
581
582 if (!sendAllAttributes(service))
583 {
584 phosphor::logging::log<phosphor::logging::level::ERR>(
585 "generateAndSendAttributesData: sendAllAttributes - failed");
586 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
587 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
588 return;
589 }
590
591 phosphor::logging::log<phosphor::logging::level::INFO>(
592 "generateAndSendAttributesData : sendAllAttributes is done");
593 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
594 static_cast<uint8_t>(ipmi::PStatus::Valid);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800595}
596
597/** @brief implement executing the linux command to uncompress and generate the
598 * xmlfile
599 * @param[in] linux command
600 * @returns status
601 */
602template <typename... ArgTypes>
603static int generateBIOSXMLFile(const char* path, ArgTypes&&... tArgs)
604{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800605 boost::process::child execProg(path, const_cast<char*>(tArgs)...,
606 boost::process::std_out > biosXMLFilePath);
607 execProg.wait();
608 return execProg.exit_code();
609}
610
611/** @brief implements to clean up the temp/ existing payload file
612 **/
613static void cleanUpPayloadFile(uint8_t& payloadType)
614{
615 // Clear the payload Information
616 std::string FilePath = "/var/oob/temp" + std::to_string(payloadType);
617 unlink(FilePath.c_str());
618 FilePath = "/var/oob/Payload" + std::to_string(payloadType);
619 unlink(FilePath.c_str());
620 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
621 {
622 unlink("/var/oob/Payload1");
623 gNVOOBdata.payloadInfo[static_cast<uint8_t>(ipmi::PType::IntelXMLType1)]
624 .payloadStatus = static_cast<uint8_t>(ipmi::PStatus::Unknown);
625 }
626}
627
628/** @brief implements to create the oob folders and nv space
629 **/
630static Cc InitNVOOBdata()
631{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800632 if (!(std::filesystem::exists(biosConfigFolder)))
633 {
634 std::filesystem::create_directory(biosConfigFolder);
635 }
636
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000637 std::ifstream ifs(biosConfigNVPath, std::ios::in | std::ios::binary);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800638
639 if (ifs.good())
640 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000641 ifs.seekg(std::ios_base::beg);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800642 ifs.read(reinterpret_cast<char*>(&gNVOOBdata),
643 sizeof(struct NVOOBdata));
644 ifs.close();
645 return ipmi::ccSuccess;
646 }
647 return ipmi::ccResponseError;
648}
649
Vernon Mauerydcff1502022-09-28 11:12:46 -0700650ipmi::RspType<> ipmiOEMSetBIOSCap(ipmi::Context::ptr&, uint8_t BIOSCapabilties,
651 uint8_t reserved1, uint8_t reserved2,
652 uint8_t reserved3)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800653{
Arun Lal K M3a1be322022-02-08 21:37:30 +0000654 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800655 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800656 return ipmi::response(ipmiCCNotSupportedInCurrentState);
657 }
Arun Lal K M3a1be322022-02-08 21:37:30 +0000658
659 if (reserved1 != 0 || reserved2 != 0 || reserved3 != 0)
660 {
661 return ipmi::responseInvalidFieldRequest();
662 }
663
664 gNVOOBdata.mBIOSCapabilities.OOBCapability = BIOSCapabilties;
665 gNVOOBdata.mIsBIOSCapInitDone = true;
666
667 flushNVOOBdata();
668 return ipmi::responseSuccess();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800669}
670
671ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t>
Vernon Mauerydcff1502022-09-28 11:12:46 -0700672 ipmiOEMGetBIOSCap(ipmi::Context::ptr&)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800673{
674 if (gNVOOBdata.mIsBIOSCapInitDone)
675 {
676 return ipmi::responseSuccess(gNVOOBdata.mBIOSCapabilities.OOBCapability,
677 0, 0, 0);
678 }
679 else
680 {
681 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
682 }
683}
684
Patrick Williams1bcced02024-08-16 15:20:24 -0400685ipmi::RspType<uint32_t>
686 ipmiOEMSetPayload(ipmi::Context::ptr&, uint8_t paramSel,
687 uint8_t payloadType, std::vector<uint8_t> payload)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800688{
689 uint8_t biosCapOffsetBit = 2; // BIT:1 0-OOB BIOS config not supported
690 // 1-OOB BIOS config is supported
691
692 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
693 {
694 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
695 }
Arun Lal K M382dc972022-01-20 22:18:23 +0000696
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800697 // Validate the Payload Type
698 if (payloadType > maxPayloadSupported)
699 {
700 return ipmi::responseInvalidFieldRequest();
701 }
702
703 // We should support this Payload type 0 command only in KCS Interface
704 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
705 {
Arun Lal K M3a1be322022-02-08 21:37:30 +0000706 if (getPostCompleted())
707 {
708 return ipmi::response(ipmiCCNotSupportedInCurrentState);
709 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800710 }
711
712 switch (static_cast<PTState>(paramSel))
713 {
714 case ipmi::PTState::StartTransfer:
715 {
716 PayloadStartTransfer* pPayloadStartTransfer =
717 reinterpret_cast<PayloadStartTransfer*>(payload.data());
718 if (payload.size() < sizeof(PayloadStartTransfer))
719 {
720 phosphor::logging::log<phosphor::logging::level::ERR>(
721 "ipmiOEMSetPayload: BIOS Config Payload size is not "
722 "correct");
723 return ipmi::responseReqDataLenInvalid();
724 }
725 cleanUpPayloadFile(payloadType);
726
727 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = rand();
728 gNVOOBdata.payloadInfo[payloadType].payloadTotalChecksum =
729 pPayloadStartTransfer->payloadTotalChecksum;
730 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
731 pPayloadStartTransfer->payloadTotalSize;
732 gNVOOBdata.payloadInfo[payloadType].payloadVersion =
733 pPayloadStartTransfer->payloadVersion;
734 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten = 0;
735 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
736 static_cast<uint8_t>(ipmi::PStatus::Unknown);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000737 gNVOOBdata.payloadInfo[payloadType].payloadType = payloadType;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800738
739 return ipmi::responseSuccess(
740 gNVOOBdata.payloadInfo[payloadType].payloadReservationID);
741 }
742 break;
743
744 case ipmi::PTState::InProgress:
745 {
746 PayloadInProgress* pPayloadInProgress =
747 reinterpret_cast<PayloadInProgress*>(payload.data());
748 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
749
750 if (payload.size() < sizeof(PayloadInProgress))
751 {
752 phosphor::logging::log<phosphor::logging::level::ERR>(
753 "BIOS Config Payload size is not correct");
754 return ipmi::responseReqDataLenInvalid();
755 }
756
757 if (pPayloadInProgress->payloadReservationID !=
758 payloadInfo.payloadReservationID)
759 {
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000760 phosphor::logging::log<phosphor::logging::level::ERR>(
761 "BIOS Config Payload reservation ID is not correct");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800762 return ipmi::responseInvalidReservationId();
763 }
764 payloadInfo.payloadCurrentSize =
765 pPayloadInProgress->payloadCurrentSize;
766 // Need to verify the current Payload Checksum
767 const uint8_t* data =
768 reinterpret_cast<const uint8_t*>(payload.data());
769 // we have to remove the current size, current offset, current
770 // length,checksum bytes , reservation bytes
771 boost::crc_32_type calcChecksum;
772 calcChecksum.process_bytes(data + 16, payload.size() - 16);
773 if (calcChecksum.checksum() !=
774 pPayloadInProgress->payloadCurrentChecksum)
775 {
776 phosphor::logging::log<phosphor::logging::level::ERR>(
777 "ipmiOEMSetPayload: Payload Checksum Failed");
778 return ipmi::response(ipmiCCPayloadChecksumFailed);
779 }
780 // store the data in temp file
Patrick Williams1bcced02024-08-16 15:20:24 -0400781 std::string FilePath =
782 "/var/oob/temp" + std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800783
784 std::ofstream outFile(FilePath, std::ios::binary | std::ios::app);
785 outFile.seekp(pPayloadInProgress->payloadOffset);
786 // we have to remove the current size, current offset, current
787 // length,checksum bytes , reservation bytes
788
789 const char* writedata =
790 reinterpret_cast<const char*>(payload.data());
791 outFile.write(writedata + 16, payload.size() - 16);
792 outFile.close();
793
794 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
795 static_cast<uint8_t>(ipmi::PStatus::Unknown);
796 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten +=
797 payloadInfo.payloadCurrentSize;
798 return ipmi::responseSuccess(payloadInfo.payloadCurrentSize);
799 }
800 break;
801 case ipmi::PTState::EndTransfer:
802 {
803 PayloadEndTransfer* pPayloadEndTransfer =
804 reinterpret_cast<PayloadEndTransfer*>(payload.data());
805 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
806 if (pPayloadEndTransfer->payloadReservationID !=
807 payloadInfo.payloadReservationID)
808 {
809 return ipmi::responseInvalidReservationId();
810 }
811 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
812 static_cast<uint8_t>(ipmi::PStatus::Unknown);
813
814 if (gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten !=
815 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize)
816 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800817 return ipmi::response(ipmiCCPayloadPayloadInComplete);
818 }
Patrick Williams1bcced02024-08-16 15:20:24 -0400819 std::string tempFilePath =
820 "/var/oob/temp" + std::to_string(payloadType);
821 std::string payloadFilePath =
822 "/var/oob/Payload" + std::to_string(payloadType);
823 auto renamestatus =
824 std::rename(tempFilePath.c_str(), payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800825 if (renamestatus)
826 {
827 phosphor::logging::log<phosphor::logging::level::ERR>(
828 "ipmiOEMSetPayload: Renaming Payload file - failed");
829 }
830
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800831 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
832 {
833 // Unzip the Intel format XML file type 0
834 auto response = generateBIOSXMLFile("/usr/bin/lzcat", "-d",
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000835 payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800836 if (response)
837 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800838 phosphor::logging::log<phosphor::logging::level::ERR>(
839 "ipmiOEMSetPayload: generateBIOSXMLFile - failed");
840 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
841 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
842 return ipmi::response(ipmiCCPayloadPayloadPacketMissed);
843 }
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000844 phosphor::logging::log<phosphor::logging::level::INFO>(
845 " ipmiOEMSetPayload : Convert XML into native-dbus DONE");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000846
Arun Lal K Me7725612021-07-15 18:20:58 +0000847 /* So that we don't block the call */
848 auto io = getIoContext();
849 auto dbus = getSdBus();
850 if (io && dbus)
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000851 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000852 std::string service = getService(*dbus, biosConfigIntf,
853 biosConfigBaseMgrPath);
854
855 boost::asio::post(*io, [service, payloadType] {
856 generateAndSendAttributesData(service, payloadType);
857 });
858 }
859 else
860 {
861 phosphor::logging::log<phosphor::logging::level::INFO>(
862 "ipmiOEMSetPayload: Unable to get io context or sdbus");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000863 return ipmi::responseResponseError();
864 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800865 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800866
867 struct stat filestat;
868
869 /* Get entry's information. */
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000870 if (!stat(payloadFilePath.c_str(), &filestat))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800871 {
872 gNVOOBdata.payloadInfo[payloadType].payloadTimeStamp =
873 filestat.st_mtime;
874 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
875 filestat.st_size;
Snehalatha Venkatesh0d0dc342022-01-20 11:36:56 +0000876 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
877 static_cast<uint8_t>(ipmi::PStatus::Valid);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800878 }
879 else
880 {
881 return ipmi::responseResponseError();
882 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800883 flushNVOOBdata();
884 return ipmi::responseSuccess(
885 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten);
886 }
887 break;
888 case ipmi::PTState::UserAbort:
889 {
890 PayloadEndTransfer* pPayloadEndTransfer =
891 reinterpret_cast<PayloadEndTransfer*>(payload.data());
892 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
893 if (pPayloadEndTransfer->payloadReservationID !=
894 payloadInfo.payloadReservationID)
895 {
896 return ipmi::responseInvalidReservationId();
897 }
898 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = 0;
899 gNVOOBdata.payloadInfo[payloadType].payloadType = 0;
900 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = 0;
901 // Delete the temp file
Patrick Williams1bcced02024-08-16 15:20:24 -0400902 std::string tempFilePath =
903 "/var/oob/temp" + std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800904 unlink(tempFilePath.c_str());
905 flushNVOOBdata();
906 return ipmi::responseSuccess();
907 }
908 break;
909 default:
910 return ipmi::responseInvalidFieldRequest();
911 }
912 return ipmi::responseResponseError();
913}
914
915ipmi::RspType<message::Payload>
Vernon Mauerydcff1502022-09-28 11:12:46 -0700916 ipmiOEMGetPayload(ipmi::Context::ptr& ctx, uint8_t paramSel,
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800917 uint8_t payloadType, ipmi::message::Payload& payload)
918{
919 // 1-OOB BIOS config is supported
920 message::Payload retValue;
921
Matt Simmering2daecd62022-05-19 12:50:53 -0700922 if (static_cast<GetPayloadParameter>(paramSel) >=
923 ipmi::GetPayloadParameter::MaxPayloadParameters)
924 {
925 return ipmi::responseInvalidFieldRequest();
926 }
927
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800928 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
929 {
930 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
931 }
932 // Validate the Payload Type
933 if (payloadType > maxPayloadSupported)
934 {
935 return ipmi::responseInvalidFieldRequest();
936 }
937
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000938 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType1))
939 {
940 if (!payload1::update(ctx))
941 {
942 phosphor::logging::log<phosphor::logging::level::ERR>(
943 "ipmiOEMGetPayload: unable to update NVOOBdata for payloadType "
944 "= IntelXMLType1");
945 return ipmi::response(ipmi::ccUnspecifiedError);
946 }
947 }
948
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800949 struct PayloadInfo res = gNVOOBdata.payloadInfo[payloadType];
950
951 switch (static_cast<GetPayloadParameter>(paramSel))
952 {
953 case ipmi::GetPayloadParameter::GetPayloadInfo:
954 {
Patrick Williams1bcced02024-08-16 15:20:24 -0400955 std::string payloadFilePath =
956 "/var/oob/Payload" + std::to_string(payloadType);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000957
958 std::ifstream ifs(payloadFilePath,
959 std::ios::in | std::ios::binary | std::ios::ate);
960
961 if (!ifs.good())
962 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000963 phosphor::logging::log<phosphor::logging::level::ERR>(
964 "ipmiOEMGetPayload: Payload File Error");
965 // File does not exist code here
966 return ipmi::response(ipmi::ccUnspecifiedError);
967 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000968
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000969 ifs.close();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800970 retValue.pack(res.payloadVersion);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000971 retValue.pack(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800972 retValue.pack(res.payloadTotalSize);
973 retValue.pack(res.payloadTotalChecksum);
974 retValue.pack(res.payloadflag);
975 retValue.pack(res.payloadStatus);
976 retValue.pack(res.payloadTimeStamp);
977
978 return ipmi::responseSuccess(std::move(retValue));
979 }
980
981 break;
982 case ipmi::GetPayloadParameter::GetPayloadData:
983 {
984 if (res.payloadStatus ==
985 (static_cast<uint8_t>(ipmi::PStatus::Valid)))
986 {
987 std::vector<uint32_t> reqData;
988 if (payload.unpack(reqData) || !payload.fullyUnpacked())
989 {
990 return ipmi::responseReqDataLenInvalid();
991 }
992 uint32_t offset = reqData.at(0);
993 uint32_t length = reqData.at(1);
Patrick Williams1bcced02024-08-16 15:20:24 -0400994 std::string payloadFilePath =
995 "/var/oob/Payload" + std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800996
Snehalatha Venkatesh0d0dc342022-01-20 11:36:56 +0000997 if (length > static_cast<uint32_t>(maxGetPayloadDataSize))
Snehalatha Venkatesh2ff15bf2021-12-30 11:51:14 +0000998 {
999 phosphor::logging::log<phosphor::logging::level::ERR>(
1000 "ipmiOEMGetPayload: length > maxGetPayloadDataSize",
1001 phosphor::logging::entry("LENGTH=%d", length),
1002 phosphor::logging::entry("maxGetPayloadDataSize=%d",
1003 maxGetPayloadDataSize));
1004 return ipmi::responseInvalidFieldRequest();
1005 }
1006
Patrick Williams1bcced02024-08-16 15:20:24 -04001007 std::ifstream ifs(payloadFilePath,
1008 std::ios::in | std::ios::binary |
1009 std::ios::ate);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001010
1011 if (!ifs.good())
1012 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001013 phosphor::logging::log<phosphor::logging::level::ERR>(
1014 "ipmiOEMGetPayload: Payload File Error");
1015 // File does not exist code here
1016 return ipmi::response(ipmi::ccUnspecifiedError);
1017 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001018 std::ifstream::pos_type fileSize = ifs.tellg();
1019 // Total file data within given offset
Vernon Mauerydcff1502022-09-28 11:12:46 -07001020 if (fileSize < static_cast<int64_t>(offset))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001021 {
Snehalatha Venkatesh2ff15bf2021-12-30 11:51:14 +00001022 phosphor::logging::log<phosphor::logging::level::ERR>(
1023 "ipmiOEMGetPayload: filesize < offset");
1024 return ipmi::responseInvalidFieldRequest();
1025 }
1026
1027 if ((static_cast<uint64_t>(fileSize) - offset) < length)
1028 {
1029 phosphor::logging::log<phosphor::logging::level::ERR>(
1030 "ipmiOEMGetPayload: (filesize - offset) < length ");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001031 return ipmi::responseInvalidFieldRequest();
1032 }
1033
1034 ifs.seekg(offset, std::ios::beg);
1035 std::array<uint8_t, maxGetPayloadDataSize> Buffer;
1036 ifs.read(reinterpret_cast<char*>(Buffer.data()), length);
1037 uint32_t readCount = ifs.gcount();
1038 ifs.close();
1039
1040 boost::crc_32_type calcChecksum;
1041 calcChecksum.process_bytes(
1042 reinterpret_cast<char*>(Buffer.data()), readCount);
1043 uint32_t chkSum = calcChecksum.checksum();
1044 retValue.pack(payloadType);
1045 retValue.pack(readCount);
1046 retValue.pack(chkSum);
1047
Vernon Mauerydcff1502022-09-28 11:12:46 -07001048 for (uint32_t i = 0; i < readCount; i++)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001049 {
1050 retValue.pack(Buffer.at(i));
1051 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +00001052
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001053 return ipmi::responseSuccess(std::move(retValue));
1054 }
1055 else
1056 {
1057 return ipmi::responseResponseError();
1058 }
1059 }
1060 break;
1061 case ipmi::GetPayloadParameter::GetPayloadStatus:
1062 {
1063 retValue.pack(gNVOOBdata.payloadInfo[payloadType].payloadStatus);
1064 return ipmi::responseSuccess(std::move(retValue));
1065 }
1066 break;
1067 default:
1068 return ipmi::responseInvalidFieldRequest();
1069 }
1070 return ipmi::responseInvalidFieldRequest();
1071}
1072
1073ipmi::RspType<> ipmiOEMSetBIOSHashInfo(
Vernon Mauerydcff1502022-09-28 11:12:46 -07001074 ipmi::Context::ptr&, std::array<uint8_t, maxSeedSize>& pwdSeed,
Ayushi Smriti32381872021-06-23 11:05:48 +05301075 uint8_t algoInfo, std::array<uint8_t, maxHashSize>& adminPwdHash)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001076{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001077 // We should not support this command after System Booted - After Exit Boot
1078 // service called
Arun Lal K M382dc972022-01-20 22:18:23 +00001079 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001080 {
Ayushi Smriti32381872021-06-23 11:05:48 +05301081 return ipmi::response(ipmiCCNotSupportedInCurrentState);
1082 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001083
Ayushi Smriti32381872021-06-23 11:05:48 +05301084 nlohmann::json json;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001085
Ayushi Smriti32381872021-06-23 11:05:48 +05301086 if ((algoInfo & 0xF) == algoSHA384)
1087 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001088 json["HashAlgo"] = "SHA384";
Ayushi Smriti32381872021-06-23 11:05:48 +05301089 }
1090 else if ((algoInfo & 0xF) == algoSHA256)
1091 {
1092 json["HashAlgo"] = "SHA256";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001093 }
1094 else
1095 {
Ayushi Smriti32381872021-06-23 11:05:48 +05301096 return ipmi::responseInvalidFieldRequest();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001097 }
Ayushi Smriti32381872021-06-23 11:05:48 +05301098
1099 json["Seed"] = pwdSeed;
1100 json["IsAdminPwdChanged"] = false;
1101 json["AdminPwdHash"] = adminPwdHash;
1102 json["IsUserPwdChanged"] = false;
1103
1104 std::array<uint8_t, maxHashSize> userPwdHash;
1105 userPwdHash.fill({}); // initializing with 0 as user password hash field
1106 // is not used presently
1107 json["UserPwdHash"] = userPwdHash;
1108 json["StatusFlag"] = algoInfo;
1109
1110 std::string hashFilePath = "/var/lib/bios-settings-manager/seedData";
1111 std::ofstream ofs(hashFilePath, std::ios::out);
1112 const auto& writeData = json.dump();
1113 ofs << writeData;
1114 ofs.close();
1115 return ipmi::responseSuccess();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001116}
1117
Ayushi Smriti32381872021-06-23 11:05:48 +05301118ipmi::RspType<std::array<uint8_t, maxSeedSize>, uint8_t,
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001119 std::array<uint8_t, maxHashSize>>
Vernon Mauerydcff1502022-09-28 11:12:46 -07001120 ipmiOEMGetBIOSHash(ipmi::Context::ptr&)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001121{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001122 nlohmann::json data = nullptr;
1123
Arun Lal K M1d0bac92022-02-11 00:23:13 +00001124 // We should not support this command after System Booted - After Exit Boot
1125 // service called
Arun Lal K M3a1be322022-02-08 21:37:30 +00001126 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001127 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001128 return ipmi::response(ipmiCCNotSupportedInCurrentState);
1129 }
Arun Lal K M3a1be322022-02-08 21:37:30 +00001130
1131 std::string HashFilePath = "/var/lib/bios-settings-manager/seedData";
1132
1133 std::ifstream devIdFile(HashFilePath);
1134 if (!devIdFile.is_open())
1135 {
1136 return ipmi::responseResponseError();
1137 }
1138
1139 try
1140 {
1141 data = nlohmann::json::parse(devIdFile, nullptr, false);
1142 }
1143 catch (const nlohmann::json::parse_error& e)
1144 {
1145 return ipmi::responseResponseError();
1146 }
1147
1148 if (data.is_discarded())
1149 {
1150 return ipmi::responseResponseError();
1151 }
1152
1153 std::array<uint8_t, maxHashSize> newAdminHash;
1154 std::array<uint8_t, maxSeedSize> seed;
1155
1156 uint8_t flag = 0;
1157 uint8_t adminPwdChangedFlag = 0;
1158 if (!data.is_discarded())
1159 {
Arun Lal K M3a1be322022-02-08 21:37:30 +00001160 adminPwdChangedFlag = data["IsAdminPwdChanged"];
1161 newAdminHash = data["AdminPwdHash"];
1162 seed = data["Seed"];
1163 }
1164
1165 auto status = getResetBIOSSettings(flag);
1166 if (status)
1167 {
1168 return ipmi::responseResponseError();
1169 }
Snehalatha Venkatesh6346e982022-03-09 06:49:18 +00001170 if (flag)
1171 {
1172 flag |= restoreDefaultValues;
1173 }
Arun Lal K M3a1be322022-02-08 21:37:30 +00001174 if (adminPwdChangedFlag)
1175 {
1176 flag |= adminPasswordChanged;
1177 }
1178
1179 std::copy(std::begin(newAdminHash), std::end(newAdminHash),
1180 std::begin(newAdminHash));
1181
1182 return ipmi::responseSuccess(seed, flag, newAdminHash);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001183}
1184
1185static void registerBIOSConfigFunctions(void)
1186{
1187 phosphor::logging::log<phosphor::logging::level::INFO>(
1188 "BIOSConfig module initialization");
1189 InitNVOOBdata();
1190
1191 registerHandler(prioOemBase, intel::netFnGeneral,
1192 intel::general::cmdSetBIOSCap, Privilege::Admin,
1193 ipmiOEMSetBIOSCap);
1194
1195 registerHandler(prioOemBase, intel::netFnGeneral,
1196 intel::general::cmdGetBIOSCap, Privilege::User,
1197 ipmiOEMGetBIOSCap);
1198 registerHandler(prioOemBase, intel::netFnGeneral,
1199 intel::general::cmdSetBIOSPwdHashInfo, Privilege::Admin,
1200 ipmiOEMSetBIOSHashInfo);
1201
1202 registerHandler(prioOemBase, intel::netFnGeneral,
1203 intel::general::cmdGetBIOSPwdHash, Privilege::User,
1204 ipmiOEMGetBIOSHash);
1205
1206 registerHandler(prioOemBase, intel::netFnGeneral,
1207 intel::general::cmdGetPayload, Privilege::User,
1208 ipmiOEMGetPayload);
1209 registerHandler(prioOemBase, intel::netFnGeneral,
1210 intel::general::cmdSetPayload, Privilege::Admin,
1211 ipmiOEMSetPayload);
1212
1213 return;
1214}
1215
1216} // namespace ipmi