blob: b7c14af76f9561cfca4019e89f81cdffbb6b2d02 [file] [log] [blame]
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001/*
2 * Copyright (c) 2018 Intel Corporation.
3 * Copyright (c) 2018-present Facebook.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "xyz/openbmc_project/Common/error.hpp"
Vijay Khemkae7d23d02019-03-08 13:13:40 -080019
Cosmo Chou99d42b62024-08-15 10:42:47 +080020#include <boost/crc.hpp>
Patrick Williams2405ae92023-05-10 07:50:09 -050021#include <commandutils.hpp>
22#include <ipmid/api-types.hpp>
Vijay Khemka63c99be2020-05-27 19:14:35 -070023#include <ipmid/api.hpp>
Vijay Khemka1b6fae32019-03-25 17:43:01 -070024#include <ipmid/utils.hpp>
Vijay Khemka63c99be2020-05-27 19:14:35 -070025#include <nlohmann/json.hpp>
26#include <oemcommands.hpp>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080027#include <phosphor-logging/log.hpp>
28#include <sdbusplus/bus.hpp>
Patrick Williams2405ae92023-05-10 07:50:09 -050029#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
30#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
31#include <xyz/openbmc_project/Control/Boot/Type/server.hpp>
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +053032
Vijay Khemka63c99be2020-05-27 19:14:35 -070033#include <array>
34#include <cstring>
35#include <fstream>
Liora Guo4006fe72025-08-19 15:21:24 +080036#include <functional>
Vijay Khemka63c99be2020-05-27 19:14:35 -070037#include <iomanip>
38#include <iostream>
Liora Guo4006fe72025-08-19 15:21:24 +080039#include <optional>
Patrick Williams2405ae92023-05-10 07:50:09 -050040#include <regex>
Vijay Khemka63c99be2020-05-27 19:14:35 -070041#include <sstream>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080042#include <string>
43#include <vector>
44
45#define SIZE_IANA_ID 3
46
47namespace ipmi
48{
Vijay Khemkaa7231892019-10-11 11:35:05 -070049
50using namespace phosphor::logging;
51
Karthikeyan Pasupathie1ff81f2022-11-21 17:54:46 +053052void getSelectorPosition(size_t& position);
Vijay Khemkae7d23d02019-03-08 13:13:40 -080053static void registerOEMFunctions() __attribute__((constructor));
Patrick Williamscd315e02022-07-22 19:26:52 -050054sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h
Vijay Khemkae7d23d02019-03-08 13:13:40 -080055static constexpr size_t maxFRUStringLength = 0x3F;
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +053056constexpr uint8_t cmdSetSystemGuid = 0xEF;
Vijay Khemkae7d23d02019-03-08 13:13:40 -080057
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +053058constexpr uint8_t cmdSetQDimmInfo = 0x12;
59constexpr uint8_t cmdGetQDimmInfo = 0x13;
60
Cosmo Chou7ab87bb2024-06-28 10:47:44 +080061constexpr ipmi_ret_t ccInvalidParam = 0x80;
62
Vijay Khemka63c99be2020-05-27 19:14:35 -070063int plat_udbg_get_post_desc(uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*,
64 uint8_t*);
65int plat_udbg_get_gpio_desc(uint8_t, uint8_t*, uint8_t*, uint8_t*, uint8_t*,
66 uint8_t*);
Patrick Williams5e589482024-07-13 16:18:13 -050067int plat_udbg_get_frame_data(uint8_t, uint8_t, uint8_t*, uint8_t*, uint8_t*);
Vijay Khemka63c99be2020-05-27 19:14:35 -070068ipmi_ret_t plat_udbg_control_panel(uint8_t, uint8_t, uint8_t, uint8_t*,
69 uint8_t*);
70int sendMeCmd(uint8_t, uint8_t, std::vector<uint8_t>&, std::vector<uint8_t>&);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -070071
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +053072int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
73 std::vector<uint8_t>&);
74
Vijay Khemkafeaa9812019-08-27 15:08:08 -070075nlohmann::json oemData __attribute__((init_priority(101)));
Vijay Khemka1b6fae32019-03-25 17:43:01 -070076
Cosmo Chou99d42b62024-08-15 10:42:47 +080077constexpr const char* certPath = "/mnt/data/host/bios-rootcert";
78
Vijay Khemkaf2246ce2020-05-27 14:26:35 -070079static constexpr size_t GUID_SIZE = 16;
80// TODO Make offset and location runtime configurable to ensure we
81// can make each define their own locations.
82static constexpr off_t OFFSET_SYS_GUID = 0x17F0;
83static constexpr const char* FRU_EEPROM = "/sys/bus/i2c/devices/6-0054/eeprom";
Delphine CC Chiu7bb45922023-04-10 13:34:04 +080084void flushOemData();
Vijay Khemkaf2246ce2020-05-27 14:26:35 -070085
Vijay Khemka1b6fae32019-03-25 17:43:01 -070086enum class LanParam : uint8_t
87{
88 INPROGRESS = 0,
89 AUTHSUPPORT = 1,
90 AUTHENABLES = 2,
91 IP = 3,
92 IPSRC = 4,
93 MAC = 5,
94 SUBNET = 6,
95 GATEWAY = 12,
96 VLAN = 20,
97 CIPHER_SUITE_COUNT = 22,
98 CIPHER_SUITE_ENTRIES = 23,
99 IPV6 = 59,
100};
101
Vijay Khemkaa7231892019-10-11 11:35:05 -0700102namespace network
103{
104
105constexpr auto ROOT = "/xyz/openbmc_project/network";
106constexpr auto SERVICE = "xyz.openbmc_project.Network";
107constexpr auto IPV4_TYPE = "ipv4";
108constexpr auto IPV6_TYPE = "ipv6";
109constexpr auto IPV4_PREFIX = "169.254";
110constexpr auto IPV6_PREFIX = "fe80";
111constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP";
112constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress";
Potin Lai8d1a81e2022-12-20 11:13:45 +0800113constexpr auto IPV4_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
114constexpr auto IPV6_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv6";
Vijay Khemkaa7231892019-10-11 11:35:05 -0700115
Vijay Khemka63c99be2020-05-27 19:14:35 -0700116bool isLinkLocalIP(const std::string& address)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700117{
118 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
119}
120
Patrick Williamscd315e02022-07-22 19:26:52 -0500121DbusObjectInfo getIPObject(sdbusplus::bus_t& bus, const std::string& interface,
Vijay Khemka63c99be2020-05-27 19:14:35 -0700122 const std::string& serviceRoot,
Potin Lai8d1a81e2022-12-20 11:13:45 +0800123 const std::string& protocol,
124 const std::string& ethdev)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700125{
Potin Lai8d1a81e2022-12-20 11:13:45 +0800126 auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, ethdev);
Vijay Khemkaa7231892019-10-11 11:35:05 -0700127
128 if (objectTree.empty())
129 {
130 log<level::ERR>("No Object has implemented the IP interface",
131 entry("INTERFACE=%s", interface.c_str()));
132 }
133
134 DbusObjectInfo objectInfo;
135
Vijay Khemka63c99be2020-05-27 19:14:35 -0700136 for (auto& object : objectTree)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700137 {
Patrick Williams010dee02024-08-16 15:19:44 -0400138 auto variant =
139 ipmi::getDbusProperty(bus, object.second.begin()->first,
140 object.first, IP_INTERFACE, "Type");
Potin Lai8d1a81e2022-12-20 11:13:45 +0800141 if (std::get<std::string>(variant) != protocol)
142 {
143 continue;
144 }
145
146 variant = ipmi::getDbusProperty(bus, object.second.begin()->first,
147 object.first, IP_INTERFACE, "Address");
Vijay Khemkaa7231892019-10-11 11:35:05 -0700148
149 objectInfo = std::make_pair(object.first, object.second.begin()->first);
150
151 // if LinkLocalIP found look for Non-LinkLocalIP
152 if (isLinkLocalIP(std::get<std::string>(variant)))
153 {
154 continue;
155 }
156 else
157 {
158 break;
159 }
160 }
161 return objectInfo;
162}
163
164} // namespace network
165
Jayashree-Df0cf6652020-11-30 11:03:30 +0530166namespace boot
167{
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530168using BootSource =
169 sdbusplus::xyz::openbmc_project::Control::Boot::server::Source::Sources;
170using BootMode =
171 sdbusplus::xyz::openbmc_project::Control::Boot::server::Mode::Modes;
172using BootType =
173 sdbusplus::xyz::openbmc_project::Control::Boot::server::Type::Types;
Jayashree-Df0cf6652020-11-30 11:03:30 +0530174
Jayashree-Df0cf6652020-11-30 11:03:30 +0530175using IpmiValue = uint8_t;
176
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530177std::map<IpmiValue, BootSource> sourceIpmiToDbus = {
178 {0x0f, BootSource::Default}, {0x00, BootSource::RemovableMedia},
179 {0x01, BootSource::Network}, {0x02, BootSource::Disk},
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800180 {0x03, BootSource::ExternalMedia}, {0x04, BootSource::RemovableMedia},
181 {0x09, BootSource::Network}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530182
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800183std::map<IpmiValue, BootMode> modeIpmiToDbus = {{0x04, BootMode::Setup},
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530184 {0x00, BootMode::Regular}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530185
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530186std::map<IpmiValue, BootType> typeIpmiToDbus = {{0x00, BootType::Legacy},
187 {0x01, BootType::EFI}};
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530188
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530189std::map<std::optional<BootSource>, IpmiValue> sourceDbusToIpmi = {
190 {BootSource::Default, 0x0f},
191 {BootSource::RemovableMedia, 0x00},
192 {BootSource::Network, 0x01},
193 {BootSource::Disk, 0x02},
194 {BootSource::ExternalMedia, 0x03}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530195
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530196std::map<std::optional<BootMode>, IpmiValue> modeDbusToIpmi = {
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800197 {BootMode::Setup, 0x04}, {BootMode::Regular, 0x00}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530198
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530199std::map<std::optional<BootType>, IpmiValue> typeDbusToIpmi = {
200 {BootType::Legacy, 0x00}, {BootType::EFI, 0x01}};
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530201
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800202static constexpr auto bootEnableIntf = "xyz.openbmc_project.Object.Enable";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530203static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
204static constexpr auto bootSourceIntf =
205 "xyz.openbmc_project.Control.Boot.Source";
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530206static constexpr auto bootTypeIntf = "xyz.openbmc_project.Control.Boot.Type";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530207static constexpr auto bootSourceProp = "BootSource";
208static constexpr auto bootModeProp = "BootMode";
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530209static constexpr auto bootTypeProp = "BootType";
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800210static constexpr auto bootEnableProp = "Enabled";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530211
Jayashree-Df0cf6652020-11-30 11:03:30 +0530212std::tuple<std::string, std::string> objPath(size_t id)
213{
214 std::string hostName = "host" + std::to_string(id);
Patrick Williams010dee02024-08-16 15:19:44 -0400215 std::string bootObjPath =
216 "/xyz/openbmc_project/control/" + hostName + "/boot";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530217 return std::make_tuple(std::move(bootObjPath), std::move(hostName));
218}
219
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800220/* Helper functions to set boot order */
221void setBootOrder(std::string bootObjPath, const std::vector<uint8_t>& bootSeq,
222 std::string bootOrderKey)
223{
224 if (bootSeq.size() != SIZE_BOOT_ORDER)
225 {
226 phosphor::logging::log<phosphor::logging::level::ERR>(
227 "Invalid Boot order length received");
228 return;
229 }
230
231 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
232
233 uint8_t mode = bootSeq.front();
234
235 // SETTING BOOT MODE PROPERTY
236 uint8_t bootModeBit = mode & 0x04;
237 auto bootValue = ipmi::boot::modeIpmiToDbus.at(bootModeBit);
238
239 std::string bootOption =
240 sdbusplus::message::convert_to_string<boot::BootMode>(bootValue);
241
Patrick Williams010dee02024-08-16 15:19:44 -0400242 std::string service =
243 getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800244 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
245 ipmi::boot::bootModeProp, bootOption);
246
247 // SETTING BOOT SOURCE PROPERTY
248 auto bootOrder = ipmi::boot::sourceIpmiToDbus.at(bootSeq.at(1));
249 std::string bootSource =
250 sdbusplus::message::convert_to_string<boot::BootSource>(bootOrder);
251
252 service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath);
253 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf,
254 ipmi::boot::bootSourceProp, bootSource);
255
256 // SETTING BOOT TYPE PROPERTY
257 uint8_t bootTypeBit = mode & 0x01;
258 auto bootTypeVal = ipmi::boot::typeIpmiToDbus.at(bootTypeBit);
259
260 std::string bootType =
261 sdbusplus::message::convert_to_string<boot::BootType>(bootTypeVal);
262
263 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
264
265 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf,
266 ipmi::boot::bootTypeProp, bootType);
267
268 // Set the valid bit to boot enabled property
269 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath);
270
271 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootEnableIntf,
272 ipmi::boot::bootEnableProp,
273 (mode & BOOT_MODE_BOOT_FLAG) ? true : false);
274
275 nlohmann::json bootMode;
276
277 bootMode["UEFI"] = (mode & BOOT_MODE_UEFI) ? true : false;
278 bootMode["CMOS_CLR"] = (mode & BOOT_MODE_CMOS_CLR) ? true : false;
279 bootMode["FORCE_BOOT"] = (mode & BOOT_MODE_FORCE_BOOT) ? true : false;
280 bootMode["BOOT_FLAG"] = (mode & BOOT_MODE_BOOT_FLAG) ? true : false;
281 oemData[bootOrderKey][KEY_BOOT_MODE] = bootMode;
282
283 /* Initialize boot sequence array */
284 oemData[bootOrderKey][KEY_BOOT_SEQ] = {};
285 for (size_t i = 1; i < SIZE_BOOT_ORDER; i++)
286 {
287 if (bootSeq.at(i) >= BOOT_SEQ_ARRAY_SIZE)
288 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = "NA";
289 else
290 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] =
291 bootSeqDefine[bootSeq.at(i)];
292 }
293
294 flushOemData();
295}
296
297void getBootOrder(std::string bootObjPath, std::vector<uint8_t>& bootSeq,
298 std::string hostName)
299{
300 if (oemData.find(hostName) == oemData.end())
301 {
302 /* Return default boot order 0100090203ff */
303 bootSeq.push_back(BOOT_MODE_UEFI);
304 bootSeq.push_back(static_cast<uint8_t>(bootMap["USB_DEV"]));
305 bootSeq.push_back(static_cast<uint8_t>(bootMap["NET_IPV6"]));
306 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_HDD"]));
307 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_CD"]));
308 bootSeq.push_back(0xff);
309
310 phosphor::logging::log<phosphor::logging::level::INFO>(
311 "Set default boot order");
312 setBootOrder(bootObjPath, bootSeq, hostName);
313 return;
314 }
315
316 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
317
318 // GETTING PROPERTY OF MODE INTERFACE
319
Patrick Williams010dee02024-08-16 15:19:44 -0400320 std::string service =
321 getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
322 Value variant =
323 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
324 ipmi::boot::bootModeProp);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800325
326 auto bootMode = sdbusplus::message::convert_from_string<boot::BootMode>(
327 std::get<std::string>(variant));
328
329 uint8_t bootOption = ipmi::boot::modeDbusToIpmi.at(bootMode);
330
331 // GETTING PROPERTY OF TYPE INTERFACE
332
333 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
Patrick Williams010dee02024-08-16 15:19:44 -0400334 variant =
335 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf,
336 ipmi::boot::bootTypeProp);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800337
338 auto bootType = sdbusplus::message::convert_from_string<boot::BootType>(
339 std::get<std::string>(variant));
340
341 // Get the valid bit to boot enabled property
342 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath);
Patrick Williams010dee02024-08-16 15:19:44 -0400343 variant =
344 getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootEnableIntf,
345 ipmi::boot::bootEnableProp);
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800346
347 bool validFlag = std::get<bool>(variant);
348
349 uint8_t bootTypeVal = ipmi::boot::typeDbusToIpmi.at(bootType);
350
351 bootSeq.push_back(bootOption | bootTypeVal);
352
353 if (validFlag)
354 {
355 bootSeq.front() |= BOOT_MODE_BOOT_FLAG;
356 }
357
358 nlohmann::json bootModeJson = oemData[hostName][KEY_BOOT_MODE];
359 if (bootModeJson["CMOS_CLR"])
360 bootSeq.front() |= BOOT_MODE_CMOS_CLR;
361
362 for (int i = 1; i < SIZE_BOOT_ORDER; i++)
363 {
364 std::string seqStr = oemData[hostName][KEY_BOOT_SEQ][i - 1];
365 if (bootMap.find(seqStr) != bootMap.end())
366 bootSeq.push_back(bootMap[seqStr]);
367 else
368 bootSeq.push_back(0xff);
369 }
370}
371
Jayashree-Df0cf6652020-11-30 11:03:30 +0530372} // namespace boot
373
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700374//----------------------------------------------------------------------
375// Helper functions for storing oem data
376//----------------------------------------------------------------------
377
378void flushOemData()
379{
380 std::ofstream file(JSON_OEM_DATA_FILE);
381 file << oemData;
Vijay Khemkafeaa9812019-08-27 15:08:08 -0700382 file.close();
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700383 return;
384}
385
Vijay Khemka63c99be2020-05-27 19:14:35 -0700386std::string bytesToStr(uint8_t* byte, int len)
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700387{
388 std::stringstream ss;
389 int i;
390
391 ss << std::hex;
392 for (i = 0; i < len; i++)
393 {
394 ss << std::setw(2) << std::setfill('0') << (int)byte[i];
395 }
396
397 return ss.str();
398}
399
Vijay Khemka63c99be2020-05-27 19:14:35 -0700400int strToBytes(std::string& str, uint8_t* data)
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700401{
402 std::string sstr;
Willy Tue39f9392022-06-15 13:24:20 -0700403 size_t i;
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700404
405 for (i = 0; i < (str.length()) / 2; i++)
406 {
407 sstr = str.substr(i * 2, 2);
408 data[i] = (uint8_t)std::strtol(sstr.c_str(), NULL, 16);
409 }
410 return i;
411}
412
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +0530413int readDimmType(std::string& data, uint8_t param)
414{
415 nlohmann::json dimmObj;
416 /* Get dimm type names stored in json file */
417 std::ifstream file(JSON_DIMM_TYPE_FILE);
418 if (file)
419 {
420 file >> dimmObj;
421 file.close();
422 }
423 else
424 {
425 phosphor::logging::log<phosphor::logging::level::ERR>(
426 "DIMM type names file not found",
427 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE));
428 return -1;
429 }
430
431 std::string dimmKey = "dimm_type" + std::to_string(param);
432 auto obj = dimmObj[dimmKey]["short_name"];
433 data = obj;
434 return 0;
435}
436
Liora Guo4006fe72025-08-19 15:21:24 +0800437static std::optional<std::string> findIpAddress(
438 sdbusplus::bus_t& bus, const std::string& protocol,
439 const std::vector<std::string>& ifaces)
440{
441 for (auto& dev : ifaces)
442 {
443 try
444 {
445 auto ipObjectInfo =
446 ipmi::network::getIPObject(bus, ipmi::network::IP_INTERFACE,
447 ipmi::network::ROOT, protocol, dev);
448
449 auto props = ipmi::getAllDbusProperties(
450 bus, ipObjectInfo.second, ipObjectInfo.first,
451 ipmi::network::IP_INTERFACE);
452
453 auto addr = std::get<std::string>(props.at("Address"));
454 if (!addr.empty())
455 return addr;
456 }
457 catch (const sdbusplus::exception::SdBusError&)
458 {}
459 }
460 return std::nullopt;
461}
462static std::optional<std::string> findMacAddress(
463 sdbusplus::bus_t& bus, const std::vector<std::string>& ifaces)
464{
465 for (auto& dev : ifaces)
466 {
467 try
468 {
469 auto [path, obj] = ipmi::getDbusObject(
470 bus, ipmi::network::MAC_INTERFACE, ipmi::network::ROOT, dev);
471
472 auto var = ipmi::getDbusProperty(
473 bus, obj, path, ipmi::network::MAC_INTERFACE, "MACAddress");
474
475 auto mac = std::get<std::string>(var);
476 if (!mac.empty())
477 return mac;
478 }
479 catch (const sdbusplus::exception::SdBusError&)
480 {}
481 }
482 return std::nullopt;
483}
484
Vijay Khemka63c99be2020-05-27 19:14:35 -0700485ipmi_ret_t getNetworkData(uint8_t lan_param, char* data)
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700486{
Liora Guo4006fe72025-08-19 15:21:24 +0800487 static const std::vector<std::string> ifaces{"eth0", "eth1"};
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700488
Liora Guo4006fe72025-08-19 15:21:24 +0800489 sdbusplus::bus_t bus(ipmid_get_sd_bus_connection());
490 ipmi_ret_t rc = IPMI_CC_OK;
491 std::optional<std::string> result;
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700492
493 switch (static_cast<LanParam>(lan_param))
494 {
Vijay Khemkad1194022020-05-27 18:58:33 -0700495 case LanParam::IP:
Liora Guo4006fe72025-08-19 15:21:24 +0800496 result = findIpAddress(bus, ipmi::network::IPV4_PROTOCOL, ifaces);
497 lg2::info("Found IP Address: {ADDR}", "ADDR",
498 result.value_or("Not Found"));
499 break;
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700500
Vijay Khemkad1194022020-05-27 18:58:33 -0700501 case LanParam::IPV6:
Liora Guo4006fe72025-08-19 15:21:24 +0800502 result = findIpAddress(bus, ipmi::network::IPV6_PROTOCOL, ifaces);
503 lg2::info("Found IPv6 Address: {ADDR}", "ADDR",
504 result.value_or("Not Found"));
505 break;
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700506
Vijay Khemkad1194022020-05-27 18:58:33 -0700507 case LanParam::MAC:
Liora Guo4006fe72025-08-19 15:21:24 +0800508 result = findMacAddress(bus, ifaces);
509 lg2::info("Found MAC Address: {ADDR}", "ADDR",
510 result.value_or("Not Found"));
511 break;
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700512
513 default:
Liora Guo4006fe72025-08-19 15:21:24 +0800514 return IPMI_CC_PARM_OUT_OF_RANGE;
515 }
516
517 if (!result.has_value())
518 {
519 rc = IPMI_CC_UNSPECIFIED_ERROR;
520 data[0] = '\0';
521 }
522 else
523 {
524 std::strcpy(data, result->c_str());
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700525 }
526 return rc;
527}
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800528
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530529bool isMultiHostPlatform()
530{
531 bool platform;
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +0530532 if (hostInstances == "0")
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530533 {
534 platform = false;
535 }
536 else
537 {
538 platform = true;
539 }
540 return platform;
541}
Liora Guo4006fe72025-08-19 15:21:24 +0800542static std::optional<std::string> findFruPathByInterface(
543 sdbusplus::bus_t& dbus, const std::string& interfaceName,
544 std::function<bool(const std::string&)> predicate)
Daniel Hsud8d95a32024-05-27 16:05:25 +0800545{
Liora Guo4006fe72025-08-19 15:21:24 +0800546 const int depth = 0;
Daniel Hsud8d95a32024-05-27 16:05:25 +0800547 std::vector<std::string> paths;
Daniel Hsud8d95a32024-05-27 16:05:25 +0800548
549 auto mapperCall = dbus.new_method_call(
550 "xyz.openbmc_project.ObjectMapper",
551 "/xyz/openbmc_project/object_mapper",
552 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
Liora Guo4006fe72025-08-19 15:21:24 +0800553 mapperCall.append("/xyz/openbmc_project/inventory/", depth,
554 std::array<const char*, 1>{interfaceName.c_str()});
Daniel Hsud8d95a32024-05-27 16:05:25 +0800555
Daniel Hsud8d95a32024-05-27 16:05:25 +0800556 try
557 {
558 auto reply = dbus.call(mapperCall);
559 reply.read(paths);
560 }
Liora Guo4006fe72025-08-19 15:21:24 +0800561 catch (const sdbusplus::exception_t& e)
Daniel Hsud8d95a32024-05-27 16:05:25 +0800562 {
563 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Liora Guo4006fe72025-08-19 15:21:24 +0800564 return std::nullopt;
Daniel Hsud8d95a32024-05-27 16:05:25 +0800565 }
566
567 for (const auto& path : paths)
568 {
Liora Guo4006fe72025-08-19 15:21:24 +0800569 if (predicate(path))
570 {
571 return path;
572 }
573 }
574 return std::nullopt;
575}
576
577// return "" equals failed
578std::string getMotherBoardFruPath()
579{
580 sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection());
581
582 bool platform = isMultiHostPlatform();
583 size_t hostPosition;
584 if (platform)
585 getSelectorPosition(hostPosition);
586
587 if (hostPosition == 0)
588 {
589 if (auto path = findFruPathByInterface(
590 dbus, "xyz.openbmc_project.Inventory.Item.Bmc",
591 [](const std::string&) { return true; }))
592 {
593 lg2::info("[1] Found Motherboard: {PATH}", "PATH", *path);
594 return *path;
595 }
Daniel Hsud8d95a32024-05-27 16:05:25 +0800596 }
597
Liora Guo4006fe72025-08-19 15:21:24 +0800598 size_t targetIndex = (hostPosition > 0 ? hostPosition - 1 : 0);
599 auto predNth = [targetIndex,
600 counter = size_t{0}](const std::string& /*path*/) mutable {
601 return (counter++ == targetIndex);
602 };
603
604 if (auto path = findFruPathByInterface(
605 dbus, "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
606 predNth))
607 {
608 lg2::info("[2] Found Motherboard: {PATH}", "PATH", *path);
609 return *path;
610 }
611
612 phosphor::logging::log<phosphor::logging::level::ERR>(
613 "getMotherBoardFruPath: no valid FRU path found");
Daniel Hsud8d95a32024-05-27 16:05:25 +0800614 return "";
615}
616
617// return "" equals failed
618std::string getMotherBoardFruName()
619{
620 std::string path = getMotherBoardFruPath();
621 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
622 std::string service = "xyz.openbmc_project.EntityManager";
623
624 try
625 {
626 auto value = ipmi::getDbusProperty(
627 *dbus, service, path, "xyz.openbmc_project.Inventory.Item.Board",
628 "Name");
629 return std::get<std::string>(value);
630 }
631 catch (sdbusplus::exception_t& e)
632 {
633 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
634 return "";
635 }
636}
637
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800638// return code: 0 successful
Vijay Khemka63c99be2020-05-27 19:14:35 -0700639int8_t getFruData(std::string& data, std::string& name)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800640{
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530641 size_t pos;
642 static constexpr const auto depth = 0;
643 std::vector<std::string> paths;
644 std::string machinePath;
Daniel Hsud8d95a32024-05-27 16:05:25 +0800645 std::string baseBoard = getMotherBoardFruPath();
646 baseBoard = baseBoard.empty() ? "Baseboard" : baseBoard;
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530647
648 bool platform = isMultiHostPlatform();
649 if (platform == true)
650 {
Karthikeyan Pasupathie1ff81f2022-11-21 17:54:46 +0530651 getSelectorPosition(pos);
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530652 }
653
654 sd_bus* bus = NULL;
655 int ret = sd_bus_default_system(&bus);
656 if (ret < 0)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800657 {
658 phosphor::logging::log<phosphor::logging::level::ERR>(
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530659 "Failed to connect to system bus",
660 phosphor::logging::entry("ERRNO=0x%X", -ret));
661 sd_bus_unref(bus);
662 return -1;
663 }
Patrick Williamscd315e02022-07-22 19:26:52 -0500664 sdbusplus::bus_t dbus(bus);
Patrick Williams010dee02024-08-16 15:19:44 -0400665 auto mapperCall = dbus.new_method_call(
666 "xyz.openbmc_project.ObjectMapper",
667 "/xyz/openbmc_project/object_mapper",
668 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530669 static constexpr std::array<const char*, 1> interface = {
670 "xyz.openbmc_project.Inventory.Decorator.Asset"};
671 mapperCall.append("/xyz/openbmc_project/inventory/", depth, interface);
672
673 try
674 {
675 auto reply = dbus.call(mapperCall);
676 reply.read(paths);
677 }
678 catch (sdbusplus::exception_t& e)
679 {
680 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800681 return -1;
682 }
683
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530684 for (const auto& path : paths)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800685 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530686 if (platform == true)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800687 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530688 if (pos == BMC_POS)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800689 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530690 machinePath = baseBoard;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800691 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530692 else
693 {
694 machinePath = "_" + std::to_string(pos);
695 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800696 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530697 else
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800698 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530699 machinePath = baseBoard;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800700 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530701
702 auto found = path.find(machinePath);
Patrick Williams123cbcc2022-06-24 06:13:59 -0500703 if (found == std::string::npos)
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530704 {
705 continue;
706 }
707
708 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
709 std::string service = getService(
710 *dbus, "xyz.openbmc_project.Inventory.Decorator.Asset", path);
711
712 auto Value = ipmi::getDbusProperty(
713 *dbus, service, path,
714 "xyz.openbmc_project.Inventory.Decorator.Asset", name);
715
716 data = std::get<std::string>(Value);
717 return 0;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800718 }
719 return -1;
720}
721
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +0530722int8_t sysConfig(std::vector<std::string>& data, size_t pos)
723{
724 nlohmann::json sysObj;
725 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(pos);
726 std::string result, typeName;
727 uint8_t res[MAX_BUF];
728
729 /* Get sysConfig data stored in json file */
730 std::ifstream file(JSON_OEM_DATA_FILE);
731 if (file)
732 {
733 file >> sysObj;
734 file.close();
735 }
736 else
737 {
738 phosphor::logging::log<phosphor::logging::level::ERR>(
739 "oemData file not found",
740 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE));
741 return -1;
742 }
743
744 if (sysObj.find(dimmInfo) == sysObj.end())
745 {
746 phosphor::logging::log<phosphor::logging::level::ERR>(
747 "sysconfig key not available",
748 phosphor::logging::entry("SYS_JSON_KEY=%s", dimmInfo.c_str()));
749 return -1;
750 }
751 /* Get dimm type names stored in json file */
752 nlohmann::json dimmObj;
753 std::ifstream dimmFile(JSON_DIMM_TYPE_FILE);
754 if (file)
755 {
756 dimmFile >> dimmObj;
757 dimmFile.close();
758 }
759 else
760 {
761 phosphor::logging::log<phosphor::logging::level::ERR>(
762 "DIMM type names file not found",
763 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE));
764 return -1;
765 }
766 std::vector<std::string> a;
767 for (auto& j : dimmObj.items())
768 {
769 std::string name = j.key();
770 a.push_back(name);
771 }
772
773 uint8_t len = a.size();
774 for (uint8_t ii = 0; ii < len; ii++)
775 {
776 std::string indKey = std::to_string(ii);
777 std::string speedSize = sysObj[dimmInfo][indKey][DIMM_SPEED];
778 strToBytes(speedSize, res);
779 auto speed = (res[1] << 8 | res[0]);
780 size_t dimmSize = ((res[3] << 8 | res[2]) / 1000);
781
782 if (dimmSize == 0)
783 {
784 std::cerr << "Dimm information not available for slot_" +
785 std::to_string(ii)
786 << std::endl;
787 continue;
788 }
789 std::string type = sysObj[dimmInfo][indKey][DIMM_TYPE];
790 std::string dualInlineMem = sysObj[dimmInfo][indKey][KEY_DIMM_TYPE];
791 strToBytes(type, res);
792 size_t dimmType = res[0];
793 if (dimmVenMap.find(dimmType) == dimmVenMap.end())
794 {
795 typeName = "unknown";
796 }
797 else
798 {
799 typeName = dimmVenMap[dimmType];
800 }
801 result = dualInlineMem + "/" + typeName + "/" + std::to_string(speed) +
802 "MHz" + "/" + std::to_string(dimmSize) + "GB";
803 data.push_back(result);
804 }
805 return 0;
806}
807
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +0530808int8_t procInfo(std::string& result, size_t pos)
809{
810 std::vector<char> data;
811 uint8_t res[MAX_BUF];
812 std::string procIndex = "00";
813 nlohmann::json proObj;
814 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(pos);
815 /* Get processor data stored in json file */
816 std::ifstream file(JSON_OEM_DATA_FILE);
817 if (file)
818 {
819 file >> proObj;
820 file.close();
821 }
822 else
823 {
824 phosphor::logging::log<phosphor::logging::level::ERR>(
825 "oemData file not found",
826 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE));
827 return -1;
828 }
829 if (proObj.find(procInfo) == proObj.end())
830 {
831 phosphor::logging::log<phosphor::logging::level::ERR>(
832 "processor info key not available",
833 phosphor::logging::entry("PROC_JSON_KEY=%s", procInfo.c_str()));
834 return -1;
835 }
836 std::string procName = proObj[procInfo][procIndex][KEY_PROC_NAME];
837 std::string basicInfo = proObj[procInfo][procIndex][KEY_BASIC_INFO];
838 // Processor Product Name
839 strToBytes(procName, res);
840 data.assign(reinterpret_cast<char*>(&res),
841 reinterpret_cast<char*>(&res) + sizeof(res));
842
843 std::string s(data.begin(), data.end());
844 std::regex regex(" ");
845 std::vector<std::string> productName(
846 std::sregex_token_iterator(s.begin(), s.end(), regex, -1),
847 std::sregex_token_iterator());
848
849 // Processor core and frequency
850 strToBytes(basicInfo, res);
851 uint16_t coreNum = res[0];
852 double procFrequency = (float)(res[4] << 8 | res[3]) / 1000;
853 result = "CPU:" + productName[2] + "/" + std::to_string(procFrequency) +
854 "GHz" + "/" + std::to_string(coreNum) + "c";
855 return 0;
856}
857
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800858typedef struct
859{
860 uint8_t cur_power_state;
861 uint8_t last_power_event;
862 uint8_t misc_power_state;
863 uint8_t front_panel_button_cap_status;
864} ipmi_get_chassis_status_t;
865
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800866//----------------------------------------------------------------------
867// Get Debug Frame Info
868//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400869ipmi_ret_t ipmiOemDbgGetFrameInfo(
870 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
871 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800872{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700873 uint8_t* req = reinterpret_cast<uint8_t*>(request);
874 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Peter Yinb340aa22024-07-08 16:07:55 +0800875 uint8_t num_frames = debugCardFrameSize;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800876
877 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
878 res[SIZE_IANA_ID] = num_frames;
879 *data_len = SIZE_IANA_ID + 1;
880
George Liu2f454992025-07-02 16:43:57 +0800881 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800882}
883
884//----------------------------------------------------------------------
885// Get Debug Updated Frames
886//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400887ipmi_ret_t ipmiOemDbgGetUpdFrames(
888 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
889 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800890{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700891 uint8_t* req = reinterpret_cast<uint8_t*>(request);
892 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800893 uint8_t num_updates = 3;
894 *data_len = 4;
895
896 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
897 res[SIZE_IANA_ID] = num_updates;
898 *data_len = SIZE_IANA_ID + num_updates + 1;
899 res[SIZE_IANA_ID + 1] = 1; // info page update
900 res[SIZE_IANA_ID + 2] = 2; // cri sel update
901 res[SIZE_IANA_ID + 3] = 3; // cri sensor update
902
George Liu2f454992025-07-02 16:43:57 +0800903 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800904}
905
906//----------------------------------------------------------------------
907// Get Debug POST Description
908//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400909ipmi_ret_t ipmiOemDbgGetPostDesc(
910 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
911 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800912{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700913 uint8_t* req = reinterpret_cast<uint8_t*>(request);
914 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800915 uint8_t index = 0;
916 uint8_t next = 0;
917 uint8_t end = 0;
918 uint8_t phase = 0;
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700919 uint8_t descLen = 0;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800920 int ret;
921
922 index = req[3];
923 phase = req[4];
924
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700925 ret = plat_udbg_get_post_desc(index, &next, phase, &end, &descLen, &res[8]);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800926 if (ret)
927 {
928 memcpy(res, req, SIZE_IANA_ID); // IANA ID
929 *data_len = SIZE_IANA_ID;
George Liu2f454992025-07-02 16:43:57 +0800930 return ipmi::ccUnspecifiedError;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800931 }
932
933 memcpy(res, req, SIZE_IANA_ID); // IANA ID
934 res[3] = index;
935 res[4] = next;
936 res[5] = phase;
937 res[6] = end;
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700938 res[7] = descLen;
939 *data_len = SIZE_IANA_ID + 5 + descLen;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800940
George Liu2f454992025-07-02 16:43:57 +0800941 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800942}
943
944//----------------------------------------------------------------------
945// Get Debug GPIO Description
946//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400947ipmi_ret_t ipmiOemDbgGetGpioDesc(
948 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
949 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800950{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700951 uint8_t* req = reinterpret_cast<uint8_t*>(request);
952 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800953
Vijay Khemka38183d62019-08-28 16:19:33 -0700954 uint8_t index = 0;
955 uint8_t next = 0;
956 uint8_t level = 0;
957 uint8_t pinDef = 0;
958 uint8_t descLen = 0;
959 int ret;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800960
Vijay Khemka38183d62019-08-28 16:19:33 -0700961 index = req[3];
962
963 ret = plat_udbg_get_gpio_desc(index, &next, &level, &pinDef, &descLen,
964 &res[8]);
965 if (ret)
966 {
967 memcpy(res, req, SIZE_IANA_ID); // IANA ID
968 *data_len = SIZE_IANA_ID;
George Liu2f454992025-07-02 16:43:57 +0800969 return ipmi::ccUnspecifiedError;
Vijay Khemka38183d62019-08-28 16:19:33 -0700970 }
971
972 memcpy(res, req, SIZE_IANA_ID); // IANA ID
973 res[3] = index;
974 res[4] = next;
975 res[5] = level;
976 res[6] = pinDef;
977 res[7] = descLen;
978 *data_len = SIZE_IANA_ID + 5 + descLen;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800979
George Liu2f454992025-07-02 16:43:57 +0800980 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800981}
982
983//----------------------------------------------------------------------
984// Get Debug Frame Data
985//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -0400986ipmi_ret_t ipmiOemDbgGetFrameData(
987 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
988 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800989{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700990 uint8_t* req = reinterpret_cast<uint8_t*>(request);
991 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800992 uint8_t frame;
993 uint8_t page;
994 uint8_t next;
995 uint8_t count;
996 int ret;
997
998 frame = req[3];
999 page = req[4];
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001000
1001 ret = plat_udbg_get_frame_data(frame, page, &next, &count, &res[7]);
1002 if (ret)
1003 {
1004 memcpy(res, req, SIZE_IANA_ID); // IANA ID
1005 *data_len = SIZE_IANA_ID;
George Liu2f454992025-07-02 16:43:57 +08001006 return ipmi::ccUnspecifiedError;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001007 }
1008
1009 memcpy(res, req, SIZE_IANA_ID); // IANA ID
1010 res[3] = frame;
1011 res[4] = page;
1012 res[5] = next;
1013 res[6] = count;
1014 *data_len = SIZE_IANA_ID + 4 + count;
1015
George Liu2f454992025-07-02 16:43:57 +08001016 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001017}
1018
1019//----------------------------------------------------------------------
1020// Get Debug Control Panel
1021//----------------------------------------------------------------------
Patrick Williams010dee02024-08-16 15:19:44 -04001022ipmi_ret_t ipmiOemDbgGetCtrlPanel(
1023 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
1024 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001025{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001026 uint8_t* req = reinterpret_cast<uint8_t*>(request);
1027 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001028
1029 uint8_t panel;
1030 uint8_t operation;
1031 uint8_t item;
1032 uint8_t count;
1033 ipmi_ret_t ret;
1034
1035 panel = req[3];
1036 operation = req[4];
1037 item = req[5];
1038
1039 ret = plat_udbg_control_panel(panel, operation, item, &count, &res[3]);
1040
1041 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
1042 *data_len = SIZE_IANA_ID + count;
1043
1044 return ret;
1045}
1046
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001047//----------------------------------------------------------------------
1048// Set Dimm Info (CMD_OEM_SET_DIMM_INFO)
1049//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001050ipmi_ret_t ipmiOemSetDimmInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1051 ipmi_response_t, ipmi_data_len_t data_len,
1052 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001053{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001054 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001055
1056 uint8_t index = req[0];
1057 uint8_t type = req[1];
1058 uint16_t speed;
1059 uint32_t size;
1060
1061 memcpy(&speed, &req[2], 2);
1062 memcpy(&size, &req[4], 4);
1063
1064 std::stringstream ss;
1065 ss << std::hex;
1066 ss << std::setw(2) << std::setfill('0') << (int)index;
1067
1068 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_INDEX] = index;
1069 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_TYPE] = type;
1070 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SPEED] = speed;
1071 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SIZE] = size;
1072
1073 flushOemData();
1074
1075 *data_len = 0;
1076
George Liu2f454992025-07-02 16:43:57 +08001077 return ipmi::ccSuccess;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001078}
1079
1080//----------------------------------------------------------------------
1081// Get Board ID (CMD_OEM_GET_BOARD_ID)
1082//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001083ipmi_ret_t ipmiOemGetBoardID(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1084 ipmi_response_t, ipmi_data_len_t data_len,
1085 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001086{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001087 /* TODO: Needs to implement this after GPIO implementation */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001088 *data_len = 0;
1089
George Liu2f454992025-07-02 16:43:57 +08001090 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001091}
1092
Bonnie Lo4ae63e72023-02-09 15:27:54 +08001093//----------------------------------------------------------------------
1094// Get port 80 record (CMD_OEM_GET_80PORT_RECORD)
1095//----------------------------------------------------------------------
Patrick Williams1caf0482025-02-01 08:21:34 -05001096ipmi::RspType<std::vector<uint8_t>> ipmiOemGet80PortRecord(
1097 ipmi::Context::ptr ctx)
Bonnie Lo4ae63e72023-02-09 15:27:54 +08001098{
1099 auto postCodeService = "xyz.openbmc_project.State.Boot.PostCode" +
1100 std::to_string(ctx->hostIdx + 1);
1101 auto postCodeObjPath = "/xyz/openbmc_project/State/Boot/PostCode" +
1102 std::to_string(ctx->hostIdx + 1);
1103 constexpr auto postCodeInterface =
1104 "xyz.openbmc_project.State.Boot.PostCode";
1105 const static uint16_t lastestPostCodeIndex = 1;
1106 constexpr const auto maxPostCodeLen =
1107 224; // The length must be lower than IPMB limitation
1108 size_t startIndex = 0;
1109
1110 std::vector<std::tuple<uint64_t, std::vector<uint8_t>>> postCodes;
1111 std::vector<uint8_t> resData;
1112
1113 auto conn = getSdBus();
1114 /* Get the post codes by calling GetPostCodes method */
Patrick Williams010dee02024-08-16 15:19:44 -04001115 auto msg =
1116 conn->new_method_call(postCodeService.c_str(), postCodeObjPath.c_str(),
1117 postCodeInterface, "GetPostCodes");
Bonnie Lo4ae63e72023-02-09 15:27:54 +08001118 msg.append(lastestPostCodeIndex);
1119
1120 try
1121 {
1122 auto reply = conn->call(msg);
1123 reply.read(postCodes);
1124 }
1125 catch (const sdbusplus::exception::SdBusError& e)
1126 {
1127 phosphor::logging::log<phosphor::logging::level::ERR>(
1128 "IPMI Get80PortRecord Failed in call method",
1129 phosphor::logging::entry("ERROR=%s", e.what()));
1130 return ipmi::responseUnspecifiedError();
1131 }
1132
1133 /* Get post code data */
1134 for (size_t i = 0; i < postCodes.size(); ++i)
1135 {
1136 uint64_t primaryPostCode = std::get<uint64_t>(postCodes[i]);
1137 for (int j = postCodeSize - 1; j >= 0; --j)
1138 {
1139 uint8_t postCode =
1140 ((primaryPostCode >> (sizeof(uint64_t) * j)) & 0xFF);
1141 resData.emplace_back(postCode);
1142 }
1143 }
1144
1145 std::vector<uint8_t> response;
1146 if (resData.size() > maxPostCodeLen)
1147 {
1148 startIndex = resData.size() - maxPostCodeLen;
1149 }
1150
1151 response.assign(resData.begin() + startIndex, resData.end());
1152
1153 return ipmi::responseSuccess(response);
1154}
1155
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001156//----------------------------------------------------------------------
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001157// Set Boot Order (CMD_OEM_SET_BOOT_ORDER)
1158//----------------------------------------------------------------------
Patrick Williams1caf0482025-02-01 08:21:34 -05001159ipmi::RspType<std::vector<uint8_t>> ipmiOemSetBootOrder(
1160 ipmi::Context::ptr ctx, std::vector<uint8_t> bootSeq)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001161{
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001162 size_t len = bootSeq.size();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001163
1164 if (len != SIZE_BOOT_ORDER)
1165 {
1166 phosphor::logging::log<phosphor::logging::level::ERR>(
1167 "Invalid Boot order length received");
Jayashree-Df0cf6652020-11-30 11:03:30 +05301168 return ipmi::responseReqDataLenInvalid();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001169 }
1170
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +05301171 std::optional<size_t> hostId = findHost(ctx->hostIdx);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001172
Jayashree-Df0cf6652020-11-30 11:03:30 +05301173 if (!hostId)
1174 {
1175 phosphor::logging::log<phosphor::logging::level::ERR>(
1176 "Invalid Host Id received");
1177 return ipmi::responseInvalidCommand();
1178 }
1179 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
1180
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001181 ipmi::boot::setBootOrder(bootObjPath, bootSeq, hostName);
Jayashree-Df0cf6652020-11-30 11:03:30 +05301182
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001183 return ipmi::responseSuccess(bootSeq);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001184}
1185
1186//----------------------------------------------------------------------
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001187// Get Boot Order (CMD_OEM_GET_BOOT_ORDER)
1188//----------------------------------------------------------------------
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001189ipmi::RspType<std::vector<uint8_t>> ipmiOemGetBootOrder(ipmi::Context::ptr ctx)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001190{
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001191 std::vector<uint8_t> bootSeq;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001192
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +05301193 std::optional<size_t> hostId = findHost(ctx->hostIdx);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001194
Jayashree-Df0cf6652020-11-30 11:03:30 +05301195 if (!hostId)
1196 {
1197 phosphor::logging::log<phosphor::logging::level::ERR>(
1198 "Invalid Host Id received");
1199 return ipmi::responseInvalidCommand();
1200 }
1201 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
1202
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001203 ipmi::boot::getBootOrder(bootObjPath, bootSeq, hostName);
Jayashree-Df0cf6652020-11-30 11:03:30 +05301204
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001205 return ipmi::responseSuccess(bootSeq);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001206}
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001207// Set Machine Config Info (CMD_OEM_SET_MACHINE_CONFIG_INFO)
1208//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001209ipmi_ret_t ipmiOemSetMachineCfgInfo(ipmi_netfn_t, ipmi_cmd_t,
1210 ipmi_request_t request, ipmi_response_t,
1211 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001212{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001213 machineConfigInfo_t* req = reinterpret_cast<machineConfigInfo_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001214 uint8_t len = *data_len;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001215
1216 *data_len = 0;
1217
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001218 if (len < sizeof(machineConfigInfo_t))
1219 {
1220 phosphor::logging::log<phosphor::logging::level::ERR>(
1221 "Invalid machine configuration length received");
George Liu2f454992025-07-02 16:43:57 +08001222 return ipmi::ccReqDataLenInvalid;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001223 }
1224
Vijay Khemka63c99be2020-05-27 19:14:35 -07001225 if (req->chassis_type >= sizeof(chassisType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001226 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = "UNKNOWN";
1227 else
1228 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] =
1229 chassisType[req->chassis_type];
1230
Vijay Khemka63c99be2020-05-27 19:14:35 -07001231 if (req->mb_type >= sizeof(mbType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001232 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = "UNKNOWN";
1233 else
1234 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = mbType[req->mb_type];
1235
1236 oemData[KEY_MC_CONFIG][KEY_MC_PROC_CNT] = req->proc_cnt;
1237 oemData[KEY_MC_CONFIG][KEY_MC_MEM_CNT] = req->mem_cnt;
1238 oemData[KEY_MC_CONFIG][KEY_MC_HDD35_CNT] = req->hdd35_cnt;
1239 oemData[KEY_MC_CONFIG][KEY_MC_HDD25_CNT] = req->hdd25_cnt;
1240
Vijay Khemka63c99be2020-05-27 19:14:35 -07001241 if (req->riser_type >= sizeof(riserType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001242 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = "UNKNOWN";
1243 else
1244 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = riserType[req->riser_type];
1245
1246 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC] = {};
1247 int i = 0;
1248 if (req->pcie_card_loc & BIT_0)
1249 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT1";
1250 if (req->pcie_card_loc & BIT_1)
1251 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT2";
1252 if (req->pcie_card_loc & BIT_2)
1253 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT3";
1254 if (req->pcie_card_loc & BIT_3)
1255 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT4";
1256
Vijay Khemka63c99be2020-05-27 19:14:35 -07001257 if (req->slot1_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001258 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = "UNKNOWN";
1259 else
1260 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] =
1261 pcieType[req->slot1_pcie_type];
1262
Vijay Khemka63c99be2020-05-27 19:14:35 -07001263 if (req->slot2_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001264 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = "UNKNOWN";
1265 else
1266 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] =
1267 pcieType[req->slot2_pcie_type];
1268
Vijay Khemka63c99be2020-05-27 19:14:35 -07001269 if (req->slot3_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001270 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = "UNKNOWN";
1271 else
1272 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] =
1273 pcieType[req->slot3_pcie_type];
1274
Vijay Khemka63c99be2020-05-27 19:14:35 -07001275 if (req->slot4_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001276 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = "UNKNOWN";
1277 else
1278 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] =
1279 pcieType[req->slot4_pcie_type];
1280
1281 oemData[KEY_MC_CONFIG][KEY_MC_AEP_CNT] = req->aep_mem_cnt;
1282
1283 flushOemData();
1284
George Liu2f454992025-07-02 16:43:57 +08001285 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001286}
1287
1288//----------------------------------------------------------------------
1289// Set POST start (CMD_OEM_SET_POST_START)
1290//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001291ipmi_ret_t ipmiOemSetPostStart(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1292 ipmi_response_t, ipmi_data_len_t data_len,
1293 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001294{
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001295 phosphor::logging::log<phosphor::logging::level::INFO>("POST Start Event");
1296
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001297 /* Do nothing, return success */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001298 *data_len = 0;
George Liu2f454992025-07-02 16:43:57 +08001299 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001300}
1301
1302//----------------------------------------------------------------------
1303// Set POST End (CMD_OEM_SET_POST_END)
1304//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001305ipmi_ret_t ipmiOemSetPostEnd(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1306 ipmi_response_t, ipmi_data_len_t data_len,
1307 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001308{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001309 struct timespec ts;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001310
1311 phosphor::logging::log<phosphor::logging::level::INFO>("POST End Event");
1312
1313 *data_len = 0;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001314
1315 // Timestamp post end time.
1316 clock_gettime(CLOCK_REALTIME, &ts);
1317 oemData[KEY_TS_SLED] = ts.tv_sec;
1318 flushOemData();
1319
1320 // Sync time with system
1321 // TODO: Add code for syncing time
1322
George Liu2f454992025-07-02 16:43:57 +08001323 return ipmi::ccSuccess;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001324}
1325
1326//----------------------------------------------------------------------
1327// Set PPIN Info (CMD_OEM_SET_PPIN_INFO)
1328//----------------------------------------------------------------------
1329// Inform BMC about PPIN data of 8 bytes for each CPU
1330//
1331// Request:
1332// Byte 1:8 – CPU0 PPIN data
1333// Optional:
1334// Byte 9:16 – CPU1 PPIN data
1335//
1336// Response:
1337// Byte 1 – Completion Code
Willy Tue39f9392022-06-15 13:24:20 -07001338ipmi_ret_t ipmiOemSetPPINInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1339 ipmi_response_t, ipmi_data_len_t data_len,
1340 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001341{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001342 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001343 std::string ppinStr;
1344 int len;
1345
1346 if (*data_len > SIZE_CPU_PPIN * 2)
1347 len = SIZE_CPU_PPIN * 2;
1348 else
1349 len = *data_len;
1350 *data_len = 0;
1351
1352 ppinStr = bytesToStr(req, len);
1353 oemData[KEY_PPIN_INFO] = ppinStr.c_str();
1354 flushOemData();
1355
George Liu2f454992025-07-02 16:43:57 +08001356 return ipmi::ccSuccess;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001357}
1358
1359//----------------------------------------------------------------------
1360// Set ADR Trigger (CMD_OEM_SET_ADR_TRIGGER)
1361//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001362ipmi_ret_t ipmiOemSetAdrTrigger(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1363 ipmi_response_t, ipmi_data_len_t data_len,
1364 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001365{
1366 /* Do nothing, return success */
1367 *data_len = 0;
George Liu2f454992025-07-02 16:43:57 +08001368 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001369}
1370
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001371// Helper function to set guid at offset in EEPROM
Willy Tue39f9392022-06-15 13:24:20 -07001372[[maybe_unused]] static int setGUID(off_t offset, uint8_t* guid)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001373{
1374 int fd = -1;
1375 ssize_t len;
1376 int ret = 0;
cchouxb2ae88b2023-09-13 00:35:36 +08001377 std::string eepromPath = FRU_EEPROM;
1378
1379 // find the eeprom path of MB FRU
1380 auto device = getMbFruDevice();
1381 if (device)
1382 {
1383 auto [bus, address] = *device;
1384 std::stringstream ss;
1385 ss << "/sys/bus/i2c/devices/" << static_cast<int>(bus) << "-"
1386 << std::setw(4) << std::setfill('0') << std::hex
1387 << static_cast<int>(address) << "/eeprom";
1388 eepromPath = ss.str();
1389 }
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001390
1391 errno = 0;
1392
1393 // Check if file is present
cchouxb2ae88b2023-09-13 00:35:36 +08001394 if (access(eepromPath.c_str(), F_OK) == -1)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001395 {
cchouxb2ae88b2023-09-13 00:35:36 +08001396 std::cerr << "Unable to access: " << eepromPath << std::endl;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001397 return errno;
1398 }
1399
1400 // Open the file
cchouxb2ae88b2023-09-13 00:35:36 +08001401 fd = open(eepromPath.c_str(), O_WRONLY);
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001402 if (fd == -1)
1403 {
cchouxb2ae88b2023-09-13 00:35:36 +08001404 std::cerr << "Unable to open: " << eepromPath << std::endl;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001405 return errno;
1406 }
1407
1408 // seek to the offset
1409 lseek(fd, offset, SEEK_SET);
1410
1411 // Write bytes to location
1412 len = write(fd, guid, GUID_SIZE);
1413 if (len != GUID_SIZE)
1414 {
1415 phosphor::logging::log<phosphor::logging::level::ERR>(
1416 "GUID write data to EEPROM failed");
1417 ret = errno;
1418 }
1419
1420 close(fd);
1421 return ret;
1422}
1423
1424//----------------------------------------------------------------------
1425// Set System GUID (CMD_OEM_SET_SYSTEM_GUID)
1426//----------------------------------------------------------------------
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301427#if BIC_ENABLED
Bonnie Lo3f671272022-10-12 15:46:45 +08001428ipmi::RspType<> ipmiOemSetSystemGuid(ipmi::Context::ptr ctx,
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301429 std::vector<uint8_t> reqData)
1430{
1431 std::vector<uint8_t> respData;
1432
1433 if (reqData.size() != GUID_SIZE) // 16bytes
1434 {
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301435 return ipmi::responseReqDataLenInvalid();
1436 }
1437
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301438 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
1439
1440 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
1441 return ipmi::responseUnspecifiedError();
1442
1443 return ipmi::responseSuccess();
1444}
1445
1446#else
Potin Laid5353ca2022-08-11 04:52:11 +00001447ipmi_ret_t ipmiOemSetSystemGuid(ipmi_netfn_t, ipmi_cmd_t,
1448 ipmi_request_t request, ipmi_response_t,
1449 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001450{
1451 uint8_t* req = reinterpret_cast<uint8_t*>(request);
1452
1453 if (*data_len != GUID_SIZE) // 16bytes
1454 {
1455 *data_len = 0;
George Liu2f454992025-07-02 16:43:57 +08001456 return ipmi::ccReqDataLenInvalid;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001457 }
1458
1459 *data_len = 0;
1460
1461 if (setGUID(OFFSET_SYS_GUID, req))
1462 {
George Liu2f454992025-07-02 16:43:57 +08001463 return ipmi::ccUnspecifiedError;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001464 }
George Liu2f454992025-07-02 16:43:57 +08001465 return ipmi::ccSuccess;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001466}
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301467#endif
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001468
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001469//----------------------------------------------------------------------
1470// Set Bios Flash Info (CMD_OEM_SET_BIOS_FLASH_INFO)
1471//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001472ipmi_ret_t ipmiOemSetBiosFlashInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1473 ipmi_response_t, ipmi_data_len_t data_len,
1474 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001475{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001476 /* Do nothing, return success */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001477 *data_len = 0;
George Liu2f454992025-07-02 16:43:57 +08001478 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001479}
1480
1481//----------------------------------------------------------------------
1482// Set PPR (CMD_OEM_SET_PPR)
1483//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001484ipmi_ret_t ipmiOemSetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1485 ipmi_response_t, ipmi_data_len_t data_len,
1486 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001487{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001488 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001489 uint8_t pprCnt, pprAct, pprIndex;
1490 uint8_t selParam = req[0];
1491 uint8_t len = *data_len;
1492 std::stringstream ss;
1493 std::string str;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001494
1495 *data_len = 0;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001496
1497 switch (selParam)
1498 {
1499 case PPR_ACTION:
1500 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) ==
1501 oemData[KEY_PPR].end())
1502 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1503
1504 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1505 if (pprCnt == 0)
1506 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1507
1508 pprAct = req[1];
1509 /* Check if ppr is enabled or disabled */
1510 if (!(pprAct & 0x80))
1511 pprAct = 0;
1512
1513 oemData[KEY_PPR][KEY_PPR_ACTION] = pprAct;
1514 break;
1515 case PPR_ROW_COUNT:
1516 if (req[1] > 100)
George Liu2f454992025-07-02 16:43:57 +08001517 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001518
1519 oemData[KEY_PPR][KEY_PPR_ROW_COUNT] = req[1];
1520 break;
1521 case PPR_ROW_ADDR:
1522 pprIndex = req[1];
1523 if (pprIndex > 100)
George Liu2f454992025-07-02 16:43:57 +08001524 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001525
1526 if (len < PPR_ROW_ADDR_LEN + 1)
1527 {
1528 phosphor::logging::log<phosphor::logging::level::ERR>(
1529 "Invalid PPR Row Address length received");
George Liu2f454992025-07-02 16:43:57 +08001530 return ipmi::ccReqDataLenInvalid;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001531 }
1532
1533 ss << std::hex;
1534 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1535
1536 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1537
1538 str = bytesToStr(&req[1], PPR_ROW_ADDR_LEN);
1539 oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR] = str.c_str();
1540 break;
1541 case PPR_HISTORY_DATA:
1542 pprIndex = req[1];
1543 if (pprIndex > 100)
George Liu2f454992025-07-02 16:43:57 +08001544 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001545
1546 if (len < PPR_HST_DATA_LEN + 1)
1547 {
1548 phosphor::logging::log<phosphor::logging::level::ERR>(
1549 "Invalid PPR history data length received");
George Liu2f454992025-07-02 16:43:57 +08001550 return ipmi::ccReqDataLenInvalid;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001551 }
1552
1553 ss << std::hex;
1554 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1555
1556 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1557
1558 str = bytesToStr(&req[1], PPR_HST_DATA_LEN);
1559 oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA] = str.c_str();
1560 break;
1561 default:
George Liu2f454992025-07-02 16:43:57 +08001562 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001563 break;
1564 }
1565
1566 flushOemData();
1567
George Liu2f454992025-07-02 16:43:57 +08001568 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001569}
1570
1571//----------------------------------------------------------------------
1572// Get PPR (CMD_OEM_GET_PPR)
1573//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001574ipmi_ret_t ipmiOemGetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1575 ipmi_response_t response, ipmi_data_len_t data_len,
1576 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001577{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001578 uint8_t* req = reinterpret_cast<uint8_t*>(request);
1579 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001580 uint8_t pprCnt, pprIndex;
1581 uint8_t selParam = req[0];
1582 std::stringstream ss;
1583 std::string str;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001584
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001585 /* Any failure will return zero length data */
1586 *data_len = 0;
1587
1588 switch (selParam)
1589 {
1590 case PPR_ACTION:
1591 res[0] = 0;
1592 *data_len = 1;
1593
1594 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1595 oemData[KEY_PPR].end())
1596 {
1597 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1598 if (pprCnt != 0)
1599 {
1600 if (oemData[KEY_PPR].find(KEY_PPR_ACTION) !=
1601 oemData[KEY_PPR].end())
1602 {
1603 res[0] = oemData[KEY_PPR][KEY_PPR_ACTION];
1604 }
1605 }
1606 }
1607 break;
1608 case PPR_ROW_COUNT:
1609 res[0] = 0;
1610 *data_len = 1;
1611 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1612 oemData[KEY_PPR].end())
1613 res[0] = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1614 break;
1615 case PPR_ROW_ADDR:
1616 pprIndex = req[1];
1617 if (pprIndex > 100)
George Liu2f454992025-07-02 16:43:57 +08001618 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001619
1620 ss << std::hex;
1621 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1622
1623 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
George Liu2f454992025-07-02 16:43:57 +08001624 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001625
1626 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_ROW_ADDR) ==
1627 oemData[KEY_PPR][ss.str()].end())
George Liu2f454992025-07-02 16:43:57 +08001628 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001629
1630 str = oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR];
1631 *data_len = strToBytes(str, res);
1632 break;
1633 case PPR_HISTORY_DATA:
1634 pprIndex = req[1];
1635 if (pprIndex > 100)
George Liu2f454992025-07-02 16:43:57 +08001636 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001637
1638 ss << std::hex;
1639 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1640
1641 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
George Liu2f454992025-07-02 16:43:57 +08001642 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001643
1644 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_HST_DATA) ==
1645 oemData[KEY_PPR][ss.str()].end())
George Liu2f454992025-07-02 16:43:57 +08001646 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001647
1648 str = oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA];
1649 *data_len = strToBytes(str, res);
1650 break;
1651 default:
George Liu2f454992025-07-02 16:43:57 +08001652 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001653 break;
1654 }
1655
George Liu2f454992025-07-02 16:43:57 +08001656 return ipmi::ccSuccess;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001657}
1658
Alex Wang695ef4e2025-09-19 15:40:42 +08001659//----------------------------------------------------------------------
1660// Get FRU ID (CMD_OEM_GET_FRU_ID)
1661//----------------------------------------------------------------------
1662// BIOS issues this command to retrieve the FRU ID using the bus and slave
1663// address. FRU IDs are dynamic based on entity-manager probe orders so
1664// this allows a look-up based on known data from the host to identify a
1665// specific FRU.
1666//
1667// netfn 0x30, cmd 0x84
1668//
1669// Request:
1670// - Byte 1: bus
1671// - Byte 2: slave address
1672//
1673// Response:
1674// - Byte 1 - Completion Code
1675// - Byte 2 - FRU ID
1676
1677ipmi_ret_t ipmiOemGetFruId(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1678 ipmi_response_t response, ipmi_data_len_t data_len,
1679 ipmi_context_t)
1680{
1681 uint8_t* req = reinterpret_cast<uint8_t*>(request);
1682 uint8_t* res = reinterpret_cast<uint8_t*>(response);
1683 auto bus = sdbusplus::bus::new_default();
1684
1685 const uint32_t targetBus = req[0];
1686 const uint32_t targetAddress = req[1];
1687 *data_len = 1;
1688
1689 const std::string service = "xyz.openbmc_project.FruDevice";
1690 const std::string rootPath = "/xyz/openbmc_project/FruDevice";
1691
1692 auto method = bus.new_method_call(service.c_str(), "/",
1693 "org.freedesktop.DBus.ObjectManager",
1694 "GetManagedObjects");
1695
1696 auto reply = bus.call(method);
1697
1698 using PropertyValue = std::variant<std::string, uint32_t, int32_t, bool>;
1699
1700 std::map<sdbusplus::message::object_path,
1701 std::map<std::string, std::map<std::string, PropertyValue>>>
1702 objects;
1703
1704 reply.read(objects);
1705
1706 int index = 0;
1707 bool found = false;
1708
1709 for (const auto& [path, interfaces] : objects)
1710 {
1711 if (path.str.find(rootPath) != 0)
1712 continue;
1713
1714 auto it = interfaces.find("xyz.openbmc_project.FruDevice");
1715 if (it != interfaces.end())
1716 {
1717 const auto& properties = it->second;
1718
1719 auto busIt = properties.find("BUS");
1720 auto addrIt = properties.find("ADDRESS");
1721
1722 if (busIt != properties.end() && addrIt != properties.end())
1723 {
1724 try
1725 {
1726 uint32_t busValue = std::get<uint32_t>(busIt->second);
1727 uint32_t addrValue = std::get<uint32_t>(addrIt->second);
1728
1729 if (busValue == targetBus && addrValue == targetAddress)
1730 {
1731 std::cout
1732 << "Match found at index: " << index << std::endl;
1733 std::cout << "Path: " << path.str << std::endl;
1734 res[0] = index;
1735 found = true;
1736 break;
1737 }
1738 }
1739 catch (const std::bad_variant_access& e)
1740 {
1741 std::cerr << "️Unexpected property type at index " << index
1742 << std::endl;
1743 return -1;
1744 }
1745 }
1746 index++;
1747 }
1748 }
1749
1750 if (!found)
1751 {
1752 std::cout << "No matching FRU device found for BUS=" << targetBus
1753 << " and ADDRESS=" << targetAddress << std::endl;
1754 return -1;
1755 }
1756
1757 return ipmi::ccSuccess;
1758}
1759
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001760/* FB OEM QC Commands */
1761
1762//----------------------------------------------------------------------
1763// Set Proc Info (CMD_OEM_Q_SET_PROC_INFO)
1764//----------------------------------------------------------------------
1765//"Request:
1766// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1767// Byte 4 – Processor Index, 0 base
1768// Byte 5 – Parameter Selector
1769// Byte 6..N – Configuration parameter data (see below for Parameters
1770// of Processor Information)
1771// Response:
1772// Byte 1 – Completion code
1773//
1774// Parameter#1: (Processor Product Name)
1775//
1776// Byte 1..48 –Product name(ASCII code)
1777// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1778//
1779// Param#2: Processor Basic Information
1780// Byte 1 – Core Number
1781// Byte 2 – Thread Number (LSB)
1782// Byte 3 – Thread Number (MSB)
1783// Byte 4 – Processor frequency in MHz (LSB)
1784// Byte 5 – Processor frequency in MHz (MSB)
1785// Byte 6..7 – Revision
1786//
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301787
Patrick Williams010dee02024-08-16 15:19:44 -04001788ipmi::RspType<> ipmiOemQSetProcInfo(
1789 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t procIndex,
1790 uint8_t paramSel, std::vector<uint8_t> request)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001791{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001792 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001793 std::stringstream ss;
1794 std::string str;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301795 uint8_t len = request.size();
1796 auto hostId = findHost(ctx->hostIdx);
1797 if (!hostId)
1798 {
1799 phosphor::logging::log<phosphor::logging::level::ERR>(
1800 "Invalid Host Id received");
1801 return ipmi::responseInvalidCommand();
1802 }
1803 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001804 /* check for requested data params */
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301805 if (len < 5 || paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001806 {
1807 phosphor::logging::log<phosphor::logging::level::ERR>(
1808 "Invalid parameter received");
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301809 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001810 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001811 ss << std::hex;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301812 ss << std::setw(2) << std::setfill('0') << (int)procIndex;
1813 oemData[procInfo][ss.str()][KEY_PROC_INDEX] = procIndex;
1814 str = bytesToStr(request.data(), len);
1815 oemData[procInfo][ss.str()][cpuInfoKey[paramSel]] = str.c_str();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001816 flushOemData();
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301817 return ipmi::responseSuccess();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001818}
1819
1820//----------------------------------------------------------------------
1821// Get Proc Info (CMD_OEM_Q_GET_PROC_INFO)
1822//----------------------------------------------------------------------
1823// Request:
1824// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1825// Byte 4 – Processor Index, 0 base
1826// Byte 5 – Parameter Selector
1827// Response:
1828// Byte 1 – Completion code
1829// Byte 2..N – Configuration Parameter Data (see below for Parameters
1830// of Processor Information)
1831//
1832// Parameter#1: (Processor Product Name)
1833//
1834// Byte 1..48 –Product name(ASCII code)
1835// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1836//
1837// Param#2: Processor Basic Information
1838// Byte 1 – Core Number
1839// Byte 2 – Thread Number (LSB)
1840// Byte 3 – Thread Number (MSB)
1841// Byte 4 – Processor frequency in MHz (LSB)
1842// Byte 5 – Processor frequency in MHz (MSB)
1843// Byte 6..7 – Revision
1844//
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301845
Patrick Williams1caf0482025-02-01 08:21:34 -05001846ipmi::RspType<std::vector<uint8_t>> ipmiOemQGetProcInfo(
1847 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t procIndex,
1848 uint8_t paramSel)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001849{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001850 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001851 std::stringstream ss;
1852 std::string str;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301853 uint8_t res[MAX_BUF];
1854 auto hostId = findHost(ctx->hostIdx);
1855 if (!hostId)
1856 {
1857 phosphor::logging::log<phosphor::logging::level::ERR>(
1858 "Invalid Host Id received");
1859 return ipmi::responseInvalidCommand();
1860 }
1861 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId);
1862 if (paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001863 {
1864 phosphor::logging::log<phosphor::logging::level::ERR>(
1865 "Invalid parameter received");
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301866 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001867 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001868 ss << std::hex;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301869 ss << std::setw(2) << std::setfill('0') << (int)procIndex;
1870 if (oemData[procInfo].find(ss.str()) == oemData[procInfo].end())
1871 return ipmi::responseCommandNotAvailable();
1872 if (oemData[procInfo][ss.str()].find(cpuInfoKey[paramSel]) ==
1873 oemData[procInfo][ss.str()].end())
1874 return ipmi::responseCommandNotAvailable();
1875 str = oemData[procInfo][ss.str()][cpuInfoKey[paramSel]];
1876 int dataLen = strToBytes(str, res);
1877 std::vector<uint8_t> response(&res[0], &res[dataLen]);
1878 return ipmi::responseSuccess(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001879}
1880
1881//----------------------------------------------------------------------
1882// Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO)
1883//----------------------------------------------------------------------
1884// Request:
1885// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1886// Byte 4 – DIMM Index, 0 base
1887// Byte 5 – Parameter Selector
1888// Byte 6..N – Configuration parameter data (see below for Parameters
1889// of DIMM Information)
1890// Response:
1891// Byte 1 – Completion code
1892//
1893// Param#1 (DIMM Location):
1894// Byte 1 – DIMM Present
1895// Byte 1 – DIMM Present
1896// 01h – Present
1897// FFh – Not Present
1898// Byte 2 – Node Number, 0 base
1899// Byte 3 – Channel Number , 0 base
1900// Byte 4 – DIMM Number , 0 base
1901//
1902// Param#2 (DIMM Type):
1903// Byte 1 – DIMM Type
1904// Bit [7:6]
1905// For DDR3
1906// 00 – Normal Voltage (1.5V)
1907// 01 – Ultra Low Voltage (1.25V)
1908// 10 – Low Voltage (1.35V)
1909// 11 – Reserved
1910// For DDR4
1911// 00 – Reserved
1912// 01 – Reserved
1913// 10 – Reserved
1914// 11 – Normal Voltage (1.2V)
1915// Bit [5:0]
1916// 0x00 – SDRAM
1917// 0x01 – DDR-1 RAM
1918// 0x02 – Rambus
1919// 0x03 – DDR-2 RAM
1920// 0x04 – FBDIMM
1921// 0x05 – DDR-3 RAM
1922// 0x06 – DDR-4 RAM
1923//
1924// Param#3 (DIMM Speed):
1925// Byte 1..2 – DIMM speed in MHz, LSB
1926// Byte 3..6 – DIMM size in Mbytes, LSB
1927//
1928// Param#4 (Module Part Number):
1929// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1930//
1931// Param#5 (Module Serial Number):
1932// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1933//
1934// Param#6 (Module Manufacturer ID):
1935// Byte 1 - Module Manufacturer ID, LSB
1936// Byte 2 - Module Manufacturer ID, MSB
1937//
Patrick Williams010dee02024-08-16 15:19:44 -04001938ipmi::RspType<> ipmiOemQSetDimmInfo(
1939 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t dimmIndex,
1940 uint8_t paramSel, std::vector<uint8_t> request)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001941{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001942 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001943 std::stringstream ss;
1944 std::string str;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301945 uint8_t len = request.size();
1946 std::string dimmType;
1947 readDimmType(dimmType, dimmIndex);
Patrick Williams6d9e9a72022-07-18 10:30:50 -05001948 auto hostId = findHost(ctx->hostIdx);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301949 if (!hostId)
1950 {
1951 phosphor::logging::log<phosphor::logging::level::ERR>(
1952 "Invalid Host Id received");
1953 return ipmi::responseInvalidCommand();
1954 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001955
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301956 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001957
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301958 if (len < 3 || paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001959 {
1960 phosphor::logging::log<phosphor::logging::level::ERR>(
1961 "Invalid parameter received");
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301962 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001963 }
1964
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001965 ss << std::hex;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301966 ss << (int)dimmIndex;
1967 oemData[dimmInfo][ss.str()][KEY_DIMM_INDEX] = dimmIndex;
1968 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType;
1969 str = bytesToStr(request.data(), len);
1970 oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]] = str.c_str();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001971 flushOemData();
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301972 return ipmi::responseSuccess();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001973}
1974
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001975// Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO)
1976//----------------------------------------------------------------------
1977// Request:
1978// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1979// Byte 4 – DIMM Index, 0 base
1980// Byte 5 – Parameter Selector
1981// Byte 6..N – Configuration parameter data (see below for Parameters
1982// of DIMM Information)
1983// Response:
1984// Byte 1 – Completion code
1985// Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters
1986// of DIMM Information)
1987//
1988// Param#1 (DIMM Location):
1989// Byte 1 – DIMM Present
1990// Byte 1 – DIMM Present
1991// 01h – Present
1992// FFh – Not Present
1993// Byte 2 – Node Number, 0 base
1994// Byte 3 – Channel Number , 0 base
1995// Byte 4 – DIMM Number , 0 base
1996//
1997// Param#2 (DIMM Type):
1998// Byte 1 – DIMM Type
1999// Bit [7:6]
2000// For DDR3
2001// 00 – Normal Voltage (1.5V)
2002// 01 – Ultra Low Voltage (1.25V)
2003// 10 – Low Voltage (1.35V)
2004// 11 – Reserved
2005// For DDR4
2006// 00 – Reserved
2007// 01 – Reserved
2008// 10 – Reserved
2009// 11 – Normal Voltage (1.2V)
2010// Bit [5:0]
2011// 0x00 – SDRAM
2012// 0x01 – DDR-1 RAM
2013// 0x02 – Rambus
2014// 0x03 – DDR-2 RAM
2015// 0x04 – FBDIMM
2016// 0x05 – DDR-3 RAM
2017// 0x06 – DDR-4 RAM
2018//
2019// Param#3 (DIMM Speed):
2020// Byte 1..2 – DIMM speed in MHz, LSB
2021// Byte 3..6 – DIMM size in Mbytes, LSB
2022//
2023// Param#4 (Module Part Number):
2024// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
2025//
2026// Param#5 (Module Serial Number):
2027// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
2028//
2029// Param#6 (Module Manufacturer ID):
2030// Byte 1 - Module Manufacturer ID, LSB
2031// Byte 2 - Module Manufacturer ID, MSB
2032//
Patrick Williams1caf0482025-02-01 08:21:34 -05002033ipmi::RspType<std::vector<uint8_t>> ipmiOemQGetDimmInfo(
2034 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t dimmIndex,
2035 uint8_t paramSel)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002036{
Vijay Khemka63c99be2020-05-27 19:14:35 -07002037 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302038 uint8_t res[MAX_BUF];
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002039 std::stringstream ss;
2040 std::string str;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302041 std::string dimmType;
2042 readDimmType(dimmType, dimmIndex);
Patrick Williams6d9e9a72022-07-18 10:30:50 -05002043 auto hostId = findHost(ctx->hostIdx);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302044 if (!hostId)
2045 {
2046 phosphor::logging::log<phosphor::logging::level::ERR>(
2047 "Invalid Host Id received");
2048 return ipmi::responseInvalidCommand();
2049 }
2050 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002051
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302052 if (paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002053 {
2054 phosphor::logging::log<phosphor::logging::level::ERR>(
2055 "Invalid parameter received");
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302056 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002057 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002058 ss << std::hex;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302059 ss << (int)dimmIndex;
2060 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType;
2061 if (oemData[dimmInfo].find(ss.str()) == oemData[dimmInfo].end())
2062 return ipmi::responseCommandNotAvailable();
2063 if (oemData[dimmInfo][ss.str()].find(dimmInfoKey[paramSel]) ==
2064 oemData[dimmInfo][ss.str()].end())
2065 return ipmi::responseCommandNotAvailable();
2066 str = oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]];
2067 int data_length = strToBytes(str, res);
2068 std::vector<uint8_t> response(&res[0], &res[data_length]);
2069 return ipmi::responseSuccess(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002070}
2071
2072//----------------------------------------------------------------------
2073// Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO)
2074//----------------------------------------------------------------------
2075// BIOS issue this command to provide HDD information to BMC.
2076//
2077// BIOS just can get information by standard ATA / SMART command for
2078// OB SATA controller.
2079// BIOS can get
2080// 1. Serial Number
2081// 2. Model Name
2082// 3. HDD FW Version
2083// 4. HDD Capacity
2084// 5. HDD WWN
2085//
2086// Use Get HDD info Param #5 to know the MAX HDD info index.
2087//
2088// Request:
2089// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
2090// Byte 4 –
2091// [7:4] Reserved
2092// [3:0] HDD Controller Type
2093// 0x00 – BIOS
2094// 0x01 – Expander
2095// 0x02 – LSI
2096// Byte 5 – HDD Info Index, 0 base
2097// Byte 6 – Parameter Selector
2098// Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD
2099// Information)
2100//
2101// Response:
2102// Byte 1 – Completion Code
2103//
2104// Param#0 (HDD Location):
2105// Byte 1 – Controller
2106// [7:3] Device Number
2107// [2:0] Function Number
2108// For Intel C610 series (Wellsburg)
2109// D31:F2 (0xFA) – SATA control 1
2110// D31:F5 (0xFD) – SATA control 2
2111// D17:F4 (0x8C) – sSata control
2112// Byte 2 – Port Number
2113// Byte 3 – Location (0xFF: No HDD Present)
2114// BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param
2115// #1~4, #6, #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if
2116// the HDD present. BMC or other people who know the HDD location has
2117// responsibility for update Location info
2118//
2119// Param#1 (Serial Number):
2120// Bytes 1..33: HDD Serial Number
2121//
2122// Param#2 (Model Name):
2123// Byte 1..33 – HDD Model Name
2124//
2125// Param#3 (HDD FW Version):
2126// Byte 1..17 –HDD FW version
2127//
2128// Param#4 (Capacity):
2129// Byte 1..4 –HDD Block Size, LSB
2130// Byte 5..12 - HDD Block Number, LSB
2131// HDD Capacity = HDD Block size * HDD BLock number (Unit Byte)
2132//
2133// Param#5 (Max HDD Quantity):
2134// Byte 1 - Max HDD Quantity
2135// Max supported port numbers in this PCH
2136//
2137// Param#6 (HDD Type)
2138// Byte 1 – HDD Type
2139// 0h – Reserved
2140// 1h – SAS
2141// 2h – SATA
2142// 3h – PCIE SSD (NVME)
2143//
2144// Param#7 (HDD WWN)
2145// Data 1...8: HDD World Wide Name, LSB
2146//
Willy Tue39f9392022-06-15 13:24:20 -07002147ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t, ipmi_cmd_t,
2148 ipmi_request_t request, ipmi_response_t,
2149 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002150{
Vijay Khemka63c99be2020-05-27 19:14:35 -07002151 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
2152 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002153 uint8_t ctrlType = req->hddCtrlType & 0x0f;
2154 std::stringstream ss;
2155 std::string str;
2156 uint8_t len = *data_len;
2157
2158 *data_len = 0;
2159
2160 /* check for requested data params */
Bruce Hungb445feb2025-07-17 17:36:25 +08002161 if (len < 6 || req->paramSel >= numParam || ctrlType > 2)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002162 {
2163 phosphor::logging::log<phosphor::logging::level::ERR>(
2164 "Invalid parameter received");
George Liu2f454992025-07-02 16:43:57 +08002165 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002166 }
2167
2168 len = len - 6; // Get Actual data length
2169
2170 ss << std::hex;
2171 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
2172 oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType;
2173 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] =
2174 req->hddIndex;
2175
2176 str = bytesToStr(req->data, len);
2177 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
2178 [driveInfoKey[req->paramSel]] = str.c_str();
2179 flushOemData();
2180
George Liu2f454992025-07-02 16:43:57 +08002181 return ipmi::ccSuccess;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002182}
2183
2184//----------------------------------------------------------------------
2185// Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO)
2186//----------------------------------------------------------------------
2187// BMC needs to check HDD presented or not first. If NOT presented, return
2188// completion code 0xD5.
2189//
2190// Request:
2191// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
2192// Byte 4 –
2193//[7:4] Reserved
2194//[3:0] HDD Controller Type
2195// 0x00 – BIOS
2196// 0x01 – Expander
2197// 0x02 – LSI
2198// Byte 5 – HDD Index, 0 base
2199// Byte 6 – Parameter Selector (See Above Set HDD Information)
2200// Response:
2201// Byte 1 – Completion Code
2202// 0xD5 – Not support in current status (HDD Not Present)
2203// Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD
2204// Information)
2205//
Patrick Williams010dee02024-08-16 15:19:44 -04002206ipmi_ret_t ipmiOemQGetDriveInfo(
2207 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
2208 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002209{
Vijay Khemka63c99be2020-05-27 19:14:35 -07002210 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
2211 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
2212 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002213 uint8_t ctrlType = req->hddCtrlType & 0x0f;
2214 std::stringstream ss;
2215 std::string str;
2216
2217 *data_len = 0;
2218
2219 /* check for requested data params */
Bruce Hungb445feb2025-07-17 17:36:25 +08002220 if (req->paramSel >= numParam || ctrlType > 2)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002221 {
2222 phosphor::logging::log<phosphor::logging::level::ERR>(
2223 "Invalid parameter received");
George Liu2f454992025-07-02 16:43:57 +08002224 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002225 }
2226
2227 if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) ==
2228 oemData[KEY_Q_DRIVE_INFO].end())
2229 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2230
2231 ss << std::hex;
2232 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
2233
2234 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) ==
Bruce Hungb445feb2025-07-17 17:36:25 +08002235 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].end())
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002236 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2237
2238 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find(
Bruce Hungb445feb2025-07-17 17:36:25 +08002239 driveInfoKey[req->paramSel]) ==
2240 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].end())
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002241 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2242
2243 str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
Bruce Hungb445feb2025-07-17 17:36:25 +08002244 [driveInfoKey[req->paramSel]];
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002245 *data_len = strToBytes(str, res);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002246
George Liu2f454992025-07-02 16:43:57 +08002247 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002248}
2249
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302250/* Helper function for sending DCMI commands to ME/BIC and
2251 * getting response back
2252 */
Patrick Williams1caf0482025-02-01 08:21:34 -05002253ipmi::RspType<std::vector<uint8_t>> sendDCMICmd(
2254 [[maybe_unused]] ipmi::Context::ptr ctx, [[maybe_unused]] uint8_t cmd,
2255 std::vector<uint8_t>& cmdData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002256{
2257 std::vector<uint8_t> respData;
2258
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302259#if BIC_ENABLED
2260
2261 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
2262
2263 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, cmdData, respData))
2264 {
2265 return ipmi::responseUnspecifiedError();
2266 }
2267
2268#else
2269
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002270 /* Add group id as first byte to request for ME command */
2271 cmdData.insert(cmdData.begin(), groupDCMI);
2272
2273 if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData))
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302274 {
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002275 return ipmi::responseUnspecifiedError();
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302276 }
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002277
2278 /* Remove group id as first byte as it will be added by IPMID */
2279 respData.erase(respData.begin());
2280
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302281#endif
2282
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002283 return ipmi::responseSuccess(std::move(respData));
2284}
2285
2286/* DCMI Command handellers. */
2287
Patrick Williams010dee02024-08-16 15:19:44 -04002288ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerReading(
2289 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002290{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302291 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerReading, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002292}
2293
Patrick Williams010dee02024-08-16 15:19:44 -04002294ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerLimit(
2295 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002296{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302297 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002298}
2299
Patrick Williams010dee02024-08-16 15:19:44 -04002300ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMISetPowerLimit(
2301 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002302{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302303 return sendDCMICmd(ctx, ipmi::dcmi::cmdSetPowerLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002304}
2305
Patrick Williams010dee02024-08-16 15:19:44 -04002306ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIApplyPowerLimit(
2307 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002308{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302309 return sendDCMICmd(ctx, ipmi::dcmi::cmdActDeactivatePwrLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002310}
2311
Cosmo Chou99d42b62024-08-15 10:42:47 +08002312// Https Boot related functions
Patrick Williams010dee02024-08-16 15:19:44 -04002313ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsData(
2314 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou99d42b62024-08-15 10:42:47 +08002315{
2316 if (reqData.size() < sizeof(HttpsDataReq))
2317 return ipmi::responseReqDataLenInvalid();
2318
2319 const auto* pReq = reinterpret_cast<const HttpsDataReq*>(reqData.data());
2320 std::error_code ec;
2321 auto fileSize = std::filesystem::file_size(certPath, ec);
2322 if (ec)
2323 return ipmi::responseUnspecifiedError();
2324
2325 if (pReq->offset >= fileSize)
2326 return ipmi::responseInvalidFieldRequest();
2327
2328 std::ifstream file(certPath, std::ios::binary);
2329 if (!file)
2330 return ipmi::responseUnspecifiedError();
2331
2332 auto readLen = std::min<uint16_t>(pReq->length, fileSize - pReq->offset);
2333 std::vector<uint8_t> resData(readLen + 1);
2334 resData[0] = readLen;
2335 file.seekg(pReq->offset);
2336 file.read(reinterpret_cast<char*>(resData.data() + 1), readLen);
2337
2338 return ipmi::responseSuccess(resData);
2339}
2340
Patrick Williams010dee02024-08-16 15:19:44 -04002341ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsAttr(
2342 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou99d42b62024-08-15 10:42:47 +08002343{
2344 if (reqData.size() < sizeof(HttpsBootAttr))
2345 return ipmi::responseReqDataLenInvalid();
2346
2347 std::vector<uint8_t> resData;
2348
2349 switch (static_cast<HttpsBootAttr>(reqData[0]))
2350 {
2351 case HttpsBootAttr::certSize:
2352 {
2353 std::error_code ec;
2354 auto fileSize = std::filesystem::file_size(certPath, ec);
2355 if (ec || fileSize > std::numeric_limits<uint16_t>::max())
2356 return ipmi::responseUnspecifiedError();
2357
2358 uint16_t size = static_cast<uint16_t>(fileSize);
2359 resData.resize(sizeof(uint16_t));
2360 std::memcpy(resData.data(), &size, sizeof(uint16_t));
2361 break;
2362 }
2363 case HttpsBootAttr::certCrc:
2364 {
2365 std::ifstream file(certPath, std::ios::binary);
2366 if (!file)
2367 return ipmi::responseUnspecifiedError();
2368
2369 boost::crc_32_type result;
2370 char data[1024];
2371 while (file.read(data, sizeof(data)))
2372 result.process_bytes(data, file.gcount());
2373 if (file.gcount() > 0)
2374 result.process_bytes(data, file.gcount());
2375
2376 uint32_t crc = result.checksum();
2377 resData.resize(sizeof(uint32_t));
2378 std::memcpy(resData.data(), &crc, sizeof(uint32_t));
2379 break;
2380 }
2381 default:
2382 return ipmi::responseInvalidFieldRequest();
2383 }
2384
2385 return ipmi::responseSuccess(resData);
2386}
2387
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002388// OEM Crashdump related functions
2389static ipmi_ret_t setDumpState(CrdState& currState, CrdState newState)
2390{
2391 switch (newState)
2392 {
2393 case CrdState::waitData:
2394 if (currState == CrdState::packing)
2395 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2396 break;
2397 case CrdState::packing:
2398 if (currState != CrdState::waitData)
2399 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2400 break;
2401 case CrdState::free:
2402 break;
2403 default:
George Liu2f454992025-07-02 16:43:57 +08002404 return ipmi::ccUnspecifiedError;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002405 }
2406 currState = newState;
2407
George Liu2f454992025-07-02 16:43:57 +08002408 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002409}
2410
2411static ipmi_ret_t handleMcaBank(const CrashDumpHdr& hdr,
2412 std::span<const uint8_t> data,
2413 CrdState& currState, std::stringstream& ss)
2414{
2415 if (data.size() < sizeof(CrdMcaBank))
George Liu2f454992025-07-02 16:43:57 +08002416 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002417
2418 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2419 if (res)
2420 return res;
2421
2422 const auto* pBank = reinterpret_cast<const CrdMcaBank*>(data.data());
2423 ss << std::format(" Bank ID : 0x{:02X}, Core ID : 0x{:02X}\n",
2424 hdr.bankHdr.bankId, hdr.bankHdr.coreId);
2425 ss << std::format(" MCA_CTRL : 0x{:016X}\n", pBank->mcaCtrl);
2426 ss << std::format(" MCA_STATUS : 0x{:016X}\n", pBank->mcaSts);
2427 ss << std::format(" MCA_ADDR : 0x{:016X}\n", pBank->mcaAddr);
2428 ss << std::format(" MCA_MISC0 : 0x{:016X}\n", pBank->mcaMisc0);
2429 ss << std::format(" MCA_CTRL_MASK : 0x{:016X}\n", pBank->mcaCtrlMask);
2430 ss << std::format(" MCA_CONFIG : 0x{:016X}\n", pBank->mcaConfig);
2431 ss << std::format(" MCA_IPID : 0x{:016X}\n", pBank->mcaIpid);
2432 ss << std::format(" MCA_SYND : 0x{:016X}\n", pBank->mcaSynd);
2433 ss << std::format(" MCA_DESTAT : 0x{:016X}\n", pBank->mcaDestat);
2434 ss << std::format(" MCA_DEADDR : 0x{:016X}\n", pBank->mcaDeaddr);
2435 ss << std::format(" MCA_MISC1 : 0x{:016X}\n", pBank->mcaMisc1);
2436 ss << "\n";
2437
George Liu2f454992025-07-02 16:43:57 +08002438 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002439}
2440
2441template <typename T>
2442static ipmi_ret_t handleVirtualBank(std::span<const uint8_t> data,
2443 CrdState& currState, std::stringstream& ss)
2444{
2445 if (data.size() < sizeof(T))
George Liu2f454992025-07-02 16:43:57 +08002446 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002447
2448 const auto* pBank = reinterpret_cast<const T*>(data.data());
2449
2450 if (data.size() < sizeof(T) + sizeof(BankCorePair) * pBank->mcaCount)
George Liu2f454992025-07-02 16:43:57 +08002451 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002452
2453 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2454 if (res)
2455 return res;
2456
2457 ss << " Virtual Bank\n";
2458 ss << std::format(" S5_RESET_STATUS : 0x{:08X}\n", pBank->s5ResetSts);
2459 ss << std::format(" PM_BREAKEVENT : 0x{:08X}\n", pBank->breakevent);
2460 if constexpr (std::is_same_v<T, CrdVirtualBankV3>)
2461 {
2462 ss << std::format(" WARMCOLDRSTSTATUS : 0x{:08X}\n", pBank->rstSts);
2463 }
2464 ss << std::format(" PROCESSOR NUMBER : 0x{:04X}\n", pBank->procNum);
2465 ss << std::format(" APIC ID : 0x{:08X}\n", pBank->apicId);
2466 ss << std::format(" EAX : 0x{:08X}\n", pBank->eax);
2467 ss << std::format(" EBX : 0x{:08X}\n", pBank->ebx);
2468 ss << std::format(" ECX : 0x{:08X}\n", pBank->ecx);
2469 ss << std::format(" EDX : 0x{:08X}\n", pBank->edx);
2470 ss << " VALID LIST : ";
2471 for (size_t i = 0; i < pBank->mcaCount; i++)
2472 {
2473 ss << std::format("(0x{:02X},0x{:02X}) ", pBank->mcaList[i].bankId,
2474 pBank->mcaList[i].coreId);
2475 }
2476 ss << "\n\n";
2477
George Liu2f454992025-07-02 16:43:57 +08002478 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002479}
2480
2481static ipmi_ret_t handleCpuWdtBank(std::span<const uint8_t> data,
2482 CrdState& currState, std::stringstream& ss)
2483{
2484 if (data.size() < sizeof(CrdCpuWdtBank))
George Liu2f454992025-07-02 16:43:57 +08002485 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002486
2487 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2488 if (res)
2489 return res;
2490
2491 const auto* pBank = reinterpret_cast<const CrdCpuWdtBank*>(data.data());
2492 for (size_t i = 0; i < ccmNum; i++)
2493 {
2494 ss << std::format(" [CCM{}]\n", i);
2495 ss << std::format(" HwAssertStsHi : 0x{:08X}\n",
2496 pBank->hwAssertStsHi[i]);
2497 ss << std::format(" HwAssertStsLo : 0x{:08X}\n",
2498 pBank->hwAssertStsLo[i]);
2499 ss << std::format(" OrigWdtAddrLogHi : 0x{:08X}\n",
2500 pBank->origWdtAddrLogHi[i]);
2501 ss << std::format(" OrigWdtAddrLogLo : 0x{:08X}\n",
2502 pBank->origWdtAddrLogLo[i]);
2503 ss << std::format(" HwAssertMskHi : 0x{:08X}\n",
2504 pBank->hwAssertMskHi[i]);
2505 ss << std::format(" HwAssertMskLo : 0x{:08X}\n",
2506 pBank->hwAssertMskLo[i]);
2507 ss << std::format(" OrigWdtAddrLogStat : 0x{:08X}\n",
2508 pBank->origWdtAddrLogStat[i]);
2509 }
2510 ss << "\n";
2511
George Liu2f454992025-07-02 16:43:57 +08002512 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002513}
2514
2515template <size_t N>
Patrick Williams1caf0482025-02-01 08:21:34 -05002516static ipmi_ret_t handleHwAssertBank(const char* name,
2517 std::span<const uint8_t> data,
2518 CrdState& currState, std::stringstream& ss)
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002519{
2520 if (data.size() < sizeof(CrdHwAssertBank<N>))
George Liu2f454992025-07-02 16:43:57 +08002521 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002522
2523 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2524 if (res)
2525 return res;
2526
2527 const CrdHwAssertBank<N>* pBank =
2528 reinterpret_cast<const CrdHwAssertBank<N>*>(data.data());
2529
2530 for (size_t i = 0; i < N; i++)
2531 {
2532 ss << std::format(" [{}{}]\n", name, i);
2533 ss << std::format(" HwAssertStsHi : 0x{:08X}\n",
2534 pBank->hwAssertStsHi[i]);
2535 ss << std::format(" HwAssertStsLo : 0x{:08X}\n",
2536 pBank->hwAssertStsLo[i]);
2537 ss << std::format(" HwAssertMskHi : 0x{:08X}\n",
2538 pBank->hwAssertMskHi[i]);
2539 ss << std::format(" HwAssertMskLo : 0x{:08X}\n",
2540 pBank->hwAssertMskLo[i]);
2541 }
2542 ss << "\n";
2543
George Liu2f454992025-07-02 16:43:57 +08002544 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002545}
2546
2547static ipmi_ret_t handlePcieAerBank(std::span<const uint8_t> data,
2548 CrdState& currState, std::stringstream& ss)
2549{
2550 if (data.size() < sizeof(CrdPcieAerBank))
George Liu2f454992025-07-02 16:43:57 +08002551 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002552
2553 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2554 if (res)
2555 return res;
2556
2557 const auto* pBank = reinterpret_cast<const CrdPcieAerBank*>(data.data());
2558 ss << std::format(" [Bus{} Dev{} Fun{}]\n", pBank->bus, pBank->dev,
2559 pBank->fun);
2560 ss << std::format(" Command : 0x{:04X}\n",
2561 pBank->cmd);
2562 ss << std::format(" Status : 0x{:04X}\n",
2563 pBank->sts);
2564 ss << std::format(" Slot : 0x{:04X}\n",
2565 pBank->slot);
2566 ss << std::format(" Secondary Bus : 0x{:02X}\n",
2567 pBank->secondBus);
2568 ss << std::format(" Vendor ID : 0x{:04X}\n",
2569 pBank->vendorId);
2570 ss << std::format(" Device ID : 0x{:04X}\n",
2571 pBank->devId);
2572 ss << std::format(" Class Code : 0x{:02X}{:04X}\n",
2573 pBank->classCodeHi, pBank->classCodeLo);
2574 ss << std::format(" Bridge: Secondary Status : 0x{:04X}\n",
2575 pBank->secondSts);
2576 ss << std::format(" Bridge: Control : 0x{:04X}\n",
2577 pBank->ctrl);
2578 ss << std::format(" Uncorrectable Error Status : 0x{:08X}\n",
2579 pBank->uncorrErrSts);
2580 ss << std::format(" Uncorrectable Error Mask : 0x{:08X}\n",
2581 pBank->uncorrErrMsk);
2582 ss << std::format(" Uncorrectable Error Severity : 0x{:08X}\n",
2583 pBank->uncorrErrSeverity);
2584 ss << std::format(" Correctable Error Status : 0x{:08X}\n",
2585 pBank->corrErrSts);
2586 ss << std::format(" Correctable Error Mask : 0x{:08X}\n",
2587 pBank->corrErrMsk);
2588 ss << std::format(" Header Log DW0 : 0x{:08X}\n",
2589 pBank->hdrLogDw0);
2590 ss << std::format(" Header Log DW1 : 0x{:08X}\n",
2591 pBank->hdrLogDw1);
2592 ss << std::format(" Header Log DW2 : 0x{:08X}\n",
2593 pBank->hdrLogDw2);
2594 ss << std::format(" Header Log DW3 : 0x{:08X}\n",
2595 pBank->hdrLogDw3);
2596 ss << std::format(" Root Error Status : 0x{:08X}\n",
2597 pBank->rootErrSts);
2598 ss << std::format(" Correctable Error Source ID : 0x{:04X}\n",
2599 pBank->corrErrSrcId);
2600 ss << std::format(" Error Source ID : 0x{:04X}\n",
2601 pBank->errSrcId);
2602 ss << std::format(" Lane Error Status : 0x{:08X}\n",
2603 pBank->laneErrSts);
2604 ss << "\n";
2605
George Liu2f454992025-07-02 16:43:57 +08002606 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002607}
2608
2609static ipmi_ret_t handleWdtRegBank(std::span<const uint8_t> data,
2610 CrdState& currState, std::stringstream& ss)
2611{
2612 if (data.size() < sizeof(CrdWdtRegBank))
George Liu2f454992025-07-02 16:43:57 +08002613 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002614
2615 const auto* pBank = reinterpret_cast<const CrdWdtRegBank*>(data.data());
2616 if (data.size() < sizeof(CrdWdtRegBank) + sizeof(uint32_t) * pBank->count)
George Liu2f454992025-07-02 16:43:57 +08002617 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002618
2619 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2620 if (res)
2621 return res;
2622
2623 ss << std::format(" [NBIO{}] {}\n", pBank->nbio, pBank->name);
2624 ss << std::format(" Address: 0x{:08X}\n", pBank->addr);
2625 ss << std::format(" Data Count: {}\n", pBank->count);
2626 ss << " Data:\n";
2627 for (size_t i = 0; i < pBank->count; i++)
2628 {
2629 ss << std::format(" {}: 0x{:08X}\n", i, pBank->data[i]);
2630 }
2631 ss << "\n";
2632
George Liu2f454992025-07-02 16:43:57 +08002633 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002634}
2635
2636static ipmi_ret_t handleCrdHdrBank(std::span<const uint8_t> data,
2637 CrdState& currState, std::stringstream& ss)
2638{
2639 if (data.size() < sizeof(CrdHdrBank))
George Liu2f454992025-07-02 16:43:57 +08002640 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002641
2642 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2643 if (res)
2644 return res;
2645
2646 const auto* pBank = reinterpret_cast<const CrdHdrBank*>(data.data());
2647 ss << " Crashdump Header\n";
2648 ss << std::format(" CPU PPIN : 0x{:016X}\n", pBank->ppin);
2649 ss << std::format(" UCODE VERSION : 0x{:08X}\n", pBank->ucodeVer);
2650 ss << std::format(" PMIO 80h : 0x{:08X}\n", pBank->pmio);
2651 ss << std::format(
2652 " BIT0 - SMN Parity/SMN Timeouts PSP/SMU Parity and ECC/SMN On-Package Link Error : {}\n",
2653 pBank->pmio & 0x1);
2654 ss << std::format(" BIT2 - PSP Parity and ECC : {}\n",
2655 (pBank->pmio & 0x4) >> 2);
2656 ss << std::format(" BIT3 - SMN Timeouts SMU : {}\n",
2657 (pBank->pmio & 0x8) >> 3);
2658 ss << std::format(" BIT4 - SMN Off-Package Link Packet Error : {}\n",
2659 (pBank->pmio & 0x10) >> 4);
2660 ss << "\n";
2661
George Liu2f454992025-07-02 16:43:57 +08002662 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002663}
2664
2665static std::string getFilename(const std::filesystem::path& dir,
2666 const std::string& prefix)
2667{
2668 std::vector<int> indices;
2669 std::regex pattern(prefix + "(\\d+)\\.txt");
2670
2671 for (const auto& entry : std::filesystem::directory_iterator(dir))
2672 {
2673 std::string filename = entry.path().filename().string();
2674 std::smatch match;
2675 if (std::regex_match(filename, match, pattern))
2676 indices.push_back(std::stoi(match[1]));
2677 }
2678
2679 std::sort(indices.rbegin(), indices.rend());
2680 while (indices.size() > 2) // keep 3 files, so remove if more than 2
2681 {
2682 std::filesystem::remove(
2683 dir / (prefix + std::to_string(indices.back()) + ".txt"));
2684 indices.pop_back();
2685 }
2686
2687 int nextIndex = indices.empty() ? 1 : indices.front() + 1;
2688 return prefix + std::to_string(nextIndex) + ".txt";
2689}
2690
2691static ipmi_ret_t handleCtrlBank(std::span<const uint8_t> data,
2692 CrdState& currState, std::stringstream& ss)
2693{
2694 if (data.empty())
George Liu2f454992025-07-02 16:43:57 +08002695 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002696
2697 switch (static_cast<CrdCtrl>(data[0]))
2698 {
2699 case CrdCtrl::getState:
2700 break;
2701 case CrdCtrl::finish:
2702 {
2703 ipmi_ret_t res = setDumpState(currState, CrdState::packing);
2704 if (res)
2705 return res;
2706
2707 const std::filesystem::path dumpDir = "/var/lib/fb-ipmi-oem";
2708 std::string filename = getFilename(dumpDir, "crashdump_");
2709 std::ofstream outFile(dumpDir / filename);
2710 if (!outFile.is_open())
George Liu2f454992025-07-02 16:43:57 +08002711 return ipmi::ccUnspecifiedError;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002712
2713 auto now = std::chrono::system_clock::to_time_t(
2714 std::chrono::system_clock::now());
2715 outFile << "Crash Dump generated at: "
2716 << std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M:%S")
2717 << "\n\n";
2718 outFile << ss.str();
2719 outFile.close();
2720 ss.str("");
2721 ss.clear();
2722 setDumpState(currState, CrdState::free);
2723 break;
2724 }
2725 default:
2726 return ccInvalidParam;
2727 }
2728
George Liu2f454992025-07-02 16:43:57 +08002729 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002730}
2731
Patrick Williams010dee02024-08-16 15:19:44 -04002732ipmi::RspType<std::vector<uint8_t>> ipmiOemCrashdump(
2733 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002734{
2735 static CrdState dumpState = CrdState::free;
2736 static std::stringstream ss;
2737
2738 if (reqData.size() < sizeof(CrashDumpHdr))
2739 return ipmi::responseReqDataLenInvalid();
2740
2741 const auto* pHdr = reinterpret_cast<const CrashDumpHdr*>(reqData.data());
2742 std::span<const uint8_t> bData{reqData.data() + sizeof(CrashDumpHdr),
2743 reqData.size() - sizeof(CrashDumpHdr)};
2744 ipmi_ret_t res;
2745
2746 switch (pHdr->bankHdr.bankType)
2747 {
2748 case BankType::mca:
2749 res = handleMcaBank(*pHdr, bData, dumpState, ss);
2750 break;
2751 case BankType::virt:
2752 if (pHdr->bankHdr.version >= 3)
2753 {
2754 res = handleVirtualBank<CrdVirtualBankV3>(bData, dumpState, ss);
2755 break;
2756 }
2757 res = handleVirtualBank<CrdVirtualBankV2>(bData, dumpState, ss);
2758 break;
2759 case BankType::cpuWdt:
2760 res = handleCpuWdtBank(bData, dumpState, ss);
2761 break;
2762 case BankType::tcdx:
2763 res = handleHwAssertBank<tcdxNum>("TCDX", bData, dumpState, ss);
2764 break;
2765 case BankType::cake:
2766 res = handleHwAssertBank<cakeNum>("CAKE", bData, dumpState, ss);
2767 break;
2768 case BankType::pie0:
2769 res = handleHwAssertBank<pie0Num>("PIE", bData, dumpState, ss);
2770 break;
2771 case BankType::iom:
2772 res = handleHwAssertBank<iomNum>("IOM", bData, dumpState, ss);
2773 break;
2774 case BankType::ccix:
2775 res = handleHwAssertBank<ccixNum>("CCIX", bData, dumpState, ss);
2776 break;
2777 case BankType::cs:
2778 res = handleHwAssertBank<csNum>("CS", bData, dumpState, ss);
2779 break;
2780 case BankType::pcieAer:
2781 res = handlePcieAerBank(bData, dumpState, ss);
2782 break;
2783 case BankType::wdtReg:
2784 res = handleWdtRegBank(bData, dumpState, ss);
2785 break;
2786 case BankType::ctrl:
2787 res = handleCtrlBank(bData, dumpState, ss);
George Liu2f454992025-07-02 16:43:57 +08002788 if (res == ipmi::ccSuccess &&
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002789 static_cast<CrdCtrl>(bData[0]) == CrdCtrl::getState)
2790 {
2791 return ipmi::responseSuccess(
2792 std::vector<uint8_t>{static_cast<uint8_t>(dumpState)});
2793 }
2794 break;
2795 case BankType::crdHdr:
2796 res = handleCrdHdrBank(bData, dumpState, ss);
2797 break;
2798 default:
2799 return ipmi::responseInvalidFieldRequest();
2800 }
2801
2802 return ipmi::response(res);
2803}
2804
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002805static void registerOEMFunctions(void)
2806{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002807 /* Get OEM data from json file */
2808 std::ifstream file(JSON_OEM_DATA_FILE);
2809 if (file)
Vijay Khemkafeaa9812019-08-27 15:08:08 -07002810 {
Peter Yinac597172024-11-05 16:15:50 +08002811 try
2812 {
2813 file >> oemData;
2814 }
2815 // If parsing fails, initialize oemData as an empty JSON and
2816 // overwrite the file
2817 catch (const nlohmann::json::parse_error& e)
2818 {
2819 lg2::error("Error parsing JSON file: {ERROR}", "ERROR", e);
2820 oemData = nlohmann::json::object();
2821 std::ofstream outFile(JSON_OEM_DATA_FILE, std::ofstream::trunc);
2822 outFile << oemData.dump(4); // Write empty JSON object to the file
2823 outFile.close();
2824 }
Vijay Khemkafeaa9812019-08-27 15:08:08 -07002825 file.close();
2826 }
Peter Yinac597172024-11-05 16:15:50 +08002827 else
2828 {
2829 lg2::info("Failed to open JSON file.");
2830 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002831
Peter Yinac597172024-11-05 16:15:50 +08002832 lg2::info("Registering OEM commands.");
Vijay Khemka7c0aea42020-03-05 13:31:53 -08002833
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002834 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO,
2835 NULL, ipmiOemDbgGetFrameInfo,
2836 PRIVILEGE_USER); // get debug frame info
2837 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ,
2838 CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL,
2839 ipmiOemDbgGetUpdFrames,
2840 PRIVILEGE_USER); // get debug updated frames
2841 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC,
2842 NULL, ipmiOemDbgGetPostDesc,
2843 PRIVILEGE_USER); // get debug post description
2844 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC,
2845 NULL, ipmiOemDbgGetGpioDesc,
2846 PRIVILEGE_USER); // get debug gpio description
2847 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA,
2848 NULL, ipmiOemDbgGetFrameData,
2849 PRIVILEGE_USER); // get debug frame data
2850 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL,
2851 NULL, ipmiOemDbgGetCtrlPanel,
2852 PRIVILEGE_USER); // get debug control panel
George Liu0821a2e2025-04-03 10:12:10 +08002853 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_DIMM_INFO, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002854 ipmiOemSetDimmInfo,
2855 PRIVILEGE_USER); // Set Dimm Info
George Liu0821a2e2025-04-03 10:12:10 +08002856 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_BOARD_ID, NULL,
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002857 ipmiOemGetBoardID,
2858 PRIVILEGE_USER); // Get Board ID
Bonnie Lo4ae63e72023-02-09 15:27:54 +08002859 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnOemOne,
2860 CMD_OEM_GET_80PORT_RECORD, ipmi::Privilege::User,
2861 ipmiOemGet80PortRecord); // Get 80 Port Record
George Liu0821a2e2025-04-03 10:12:10 +08002862 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_MACHINE_CONFIG_INFO,
2863 NULL, ipmiOemSetMachineCfgInfo,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002864 PRIVILEGE_USER); // Set Machine Config Info
George Liu0821a2e2025-04-03 10:12:10 +08002865 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_POST_START, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002866 ipmiOemSetPostStart,
2867 PRIVILEGE_USER); // Set POST start
George Liu0821a2e2025-04-03 10:12:10 +08002868 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_POST_END, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002869 ipmiOemSetPostEnd,
2870 PRIVILEGE_USER); // Set POST End
George Liu0821a2e2025-04-03 10:12:10 +08002871 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_PPIN_INFO, NULL,
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002872 ipmiOemSetPPINInfo,
2873 PRIVILEGE_USER); // Set PPIN Info
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05302874#if BIC_ENABLED
2875
2876 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2877 ipmi::cmdSetSystemGuid, ipmi::Privilege::User,
2878 ipmiOemSetSystemGuid);
2879#else
2880
George Liu0821a2e2025-04-03 10:12:10 +08002881 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_SYSTEM_GUID, NULL,
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07002882 ipmiOemSetSystemGuid,
2883 PRIVILEGE_USER); // Set System GUID
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05302884#endif
George Liu0821a2e2025-04-03 10:12:10 +08002885 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_ADR_TRIGGER, NULL,
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002886 ipmiOemSetAdrTrigger,
2887 PRIVILEGE_USER); // Set ADR Trigger
George Liu0821a2e2025-04-03 10:12:10 +08002888 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_BIOS_FLASH_INFO, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002889 ipmiOemSetBiosFlashInfo,
2890 PRIVILEGE_USER); // Set Bios Flash Info
George Liu0821a2e2025-04-03 10:12:10 +08002891 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_PPR, NULL,
2892 ipmiOemSetPpr,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002893 PRIVILEGE_USER); // Set PPR
George Liu0821a2e2025-04-03 10:12:10 +08002894 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_PPR, NULL,
2895 ipmiOemGetPpr,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002896 PRIVILEGE_USER); // Get PPR
Alex Wang695ef4e2025-09-19 15:40:42 +08002897 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_FRU_ID, NULL,
2898 ipmiOemGetFruId,
2899 PRIVILEGE_USER); // Get FRU ID
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002900 /* FB OEM QC Commands */
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05302901 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2902 CMD_OEM_Q_SET_PROC_INFO, ipmi::Privilege::User,
2903 ipmiOemQSetProcInfo); // Set Proc Info
2904 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2905 CMD_OEM_Q_GET_PROC_INFO, ipmi::Privilege::User,
2906 ipmiOemQGetProcInfo); // Get Proc Info
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302907 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2908 ipmi::cmdSetQDimmInfo, ipmi::Privilege::User,
2909 ipmiOemQSetDimmInfo); // Set Dimm Info
2910 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2911 ipmi::cmdGetQDimmInfo, ipmi::Privilege::User,
2912 ipmiOemQGetDimmInfo); // Get Dimm Info
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002913 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL,
2914 ipmiOemQSetDriveInfo,
2915 PRIVILEGE_USER); // Set Drive Info
2916 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL,
2917 ipmiOemQGetDriveInfo,
2918 PRIVILEGE_USER); // Get Drive Info
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002919
2920 /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */
Patrick Williams010dee02024-08-16 15:19:44 -04002921 ipmi::registerGroupHandler(
2922 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerReading,
2923 ipmi::Privilege::User,
2924 ipmiOemDCMIGetPowerReading); // Get Power Reading
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002925
Patrick Williams010dee02024-08-16 15:19:44 -04002926 ipmi::registerGroupHandler(
2927 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerLimit,
2928 ipmi::Privilege::User,
2929 ipmiOemDCMIGetPowerLimit); // Get Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002930
Patrick Williams010dee02024-08-16 15:19:44 -04002931 ipmi::registerGroupHandler(
2932 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdSetPowerLimit,
2933 ipmi::Privilege::Operator,
2934 ipmiOemDCMISetPowerLimit); // Set Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002935
Patrick Williams010dee02024-08-16 15:19:44 -04002936 ipmi::registerGroupHandler(
2937 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdActDeactivatePwrLimit,
2938 ipmi::Privilege::Operator,
2939 ipmiOemDCMIApplyPowerLimit); // Apply Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002940
Jayashree-Df0cf6652020-11-30 11:03:30 +05302941 /* FB OEM BOOT ORDER COMMANDS */
2942 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2943 CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User,
2944 ipmiOemGetBootOrder); // Get Boot Order
2945
2946 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2947 CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User,
2948 ipmiOemSetBootOrder); // Set Boot Order
2949
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002950 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
Cosmo Chou99d42b62024-08-15 10:42:47 +08002951 CMD_OEM_GET_HTTPS_BOOT_DATA, ipmi::Privilege::User,
2952 ipmiOemGetHttpsData);
2953
2954 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2955 CMD_OEM_GET_HTTPS_BOOT_ATTR, ipmi::Privilege::User,
2956 ipmiOemGetHttpsAttr);
2957
2958 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002959 CMD_OEM_CRASHDUMP, ipmi::Privilege::User,
2960 ipmiOemCrashdump);
2961
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002962 return;
2963}
2964
2965} // namespace ipmi