blob: f8b1cf4e03d8c9f8737115d7d220fbc5b1440df1 [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();
Hariharan Rangasamy35f09ab2025-11-03 12:28:51 +0530583 size_t hostPosition = 0;
Liora Guo4006fe72025-08-19 15:21:24 +0800584 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
Patrick Williams90903802025-11-05 00:00:39 -05001700 auto objects = reply.unpack<std::map<
1701 sdbusplus::message::object_path,
1702 std::map<std::string, std::map<std::string, PropertyValue>>>>();
Alex Wang695ef4e2025-09-19 15:40:42 +08001703
1704 int index = 0;
1705 bool found = false;
1706
1707 for (const auto& [path, interfaces] : objects)
1708 {
1709 if (path.str.find(rootPath) != 0)
1710 continue;
1711
1712 auto it = interfaces.find("xyz.openbmc_project.FruDevice");
1713 if (it != interfaces.end())
1714 {
1715 const auto& properties = it->second;
1716
1717 auto busIt = properties.find("BUS");
1718 auto addrIt = properties.find("ADDRESS");
1719
1720 if (busIt != properties.end() && addrIt != properties.end())
1721 {
1722 try
1723 {
1724 uint32_t busValue = std::get<uint32_t>(busIt->second);
1725 uint32_t addrValue = std::get<uint32_t>(addrIt->second);
1726
1727 if (busValue == targetBus && addrValue == targetAddress)
1728 {
1729 std::cout
1730 << "Match found at index: " << index << std::endl;
1731 std::cout << "Path: " << path.str << std::endl;
1732 res[0] = index;
1733 found = true;
1734 break;
1735 }
1736 }
1737 catch (const std::bad_variant_access& e)
1738 {
1739 std::cerr << "️Unexpected property type at index " << index
1740 << std::endl;
1741 return -1;
1742 }
1743 }
1744 index++;
1745 }
1746 }
1747
1748 if (!found)
1749 {
1750 std::cout << "No matching FRU device found for BUS=" << targetBus
1751 << " and ADDRESS=" << targetAddress << std::endl;
1752 return -1;
1753 }
1754
1755 return ipmi::ccSuccess;
1756}
1757
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001758/* FB OEM QC Commands */
1759
1760//----------------------------------------------------------------------
1761// Set Proc Info (CMD_OEM_Q_SET_PROC_INFO)
1762//----------------------------------------------------------------------
1763//"Request:
1764// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1765// Byte 4 – Processor Index, 0 base
1766// Byte 5 – Parameter Selector
1767// Byte 6..N – Configuration parameter data (see below for Parameters
1768// of Processor Information)
1769// Response:
1770// Byte 1 – Completion code
1771//
1772// Parameter#1: (Processor Product Name)
1773//
1774// Byte 1..48 –Product name(ASCII code)
1775// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1776//
1777// Param#2: Processor Basic Information
1778// Byte 1 – Core Number
1779// Byte 2 – Thread Number (LSB)
1780// Byte 3 – Thread Number (MSB)
1781// Byte 4 – Processor frequency in MHz (LSB)
1782// Byte 5 – Processor frequency in MHz (MSB)
1783// Byte 6..7 – Revision
1784//
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301785
Patrick Williams010dee02024-08-16 15:19:44 -04001786ipmi::RspType<> ipmiOemQSetProcInfo(
1787 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t procIndex,
1788 uint8_t paramSel, std::vector<uint8_t> request)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001789{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001790 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001791 std::stringstream ss;
1792 std::string str;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301793 uint8_t len = request.size();
1794 auto hostId = findHost(ctx->hostIdx);
1795 if (!hostId)
1796 {
1797 phosphor::logging::log<phosphor::logging::level::ERR>(
1798 "Invalid Host Id received");
1799 return ipmi::responseInvalidCommand();
1800 }
1801 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001802 /* check for requested data params */
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301803 if (len < 5 || paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001804 {
1805 phosphor::logging::log<phosphor::logging::level::ERR>(
1806 "Invalid parameter received");
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301807 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001808 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001809 ss << std::hex;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301810 ss << std::setw(2) << std::setfill('0') << (int)procIndex;
1811 oemData[procInfo][ss.str()][KEY_PROC_INDEX] = procIndex;
1812 str = bytesToStr(request.data(), len);
1813 oemData[procInfo][ss.str()][cpuInfoKey[paramSel]] = str.c_str();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001814 flushOemData();
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301815 return ipmi::responseSuccess();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001816}
1817
1818//----------------------------------------------------------------------
1819// Get Proc Info (CMD_OEM_Q_GET_PROC_INFO)
1820//----------------------------------------------------------------------
1821// Request:
1822// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1823// Byte 4 – Processor Index, 0 base
1824// Byte 5 – Parameter Selector
1825// Response:
1826// Byte 1 – Completion code
1827// Byte 2..N – Configuration Parameter Data (see below for Parameters
1828// of Processor Information)
1829//
1830// Parameter#1: (Processor Product Name)
1831//
1832// Byte 1..48 –Product name(ASCII code)
1833// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1834//
1835// Param#2: Processor Basic Information
1836// Byte 1 – Core Number
1837// Byte 2 – Thread Number (LSB)
1838// Byte 3 – Thread Number (MSB)
1839// Byte 4 – Processor frequency in MHz (LSB)
1840// Byte 5 – Processor frequency in MHz (MSB)
1841// Byte 6..7 – Revision
1842//
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301843
Patrick Williams1caf0482025-02-01 08:21:34 -05001844ipmi::RspType<std::vector<uint8_t>> ipmiOemQGetProcInfo(
1845 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t procIndex,
1846 uint8_t paramSel)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001847{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001848 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001849 std::stringstream ss;
1850 std::string str;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301851 uint8_t res[MAX_BUF];
1852 auto hostId = findHost(ctx->hostIdx);
1853 if (!hostId)
1854 {
1855 phosphor::logging::log<phosphor::logging::level::ERR>(
1856 "Invalid Host Id received");
1857 return ipmi::responseInvalidCommand();
1858 }
1859 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId);
1860 if (paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001861 {
1862 phosphor::logging::log<phosphor::logging::level::ERR>(
1863 "Invalid parameter received");
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301864 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001865 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001866 ss << std::hex;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301867 ss << std::setw(2) << std::setfill('0') << (int)procIndex;
1868 if (oemData[procInfo].find(ss.str()) == oemData[procInfo].end())
1869 return ipmi::responseCommandNotAvailable();
1870 if (oemData[procInfo][ss.str()].find(cpuInfoKey[paramSel]) ==
1871 oemData[procInfo][ss.str()].end())
1872 return ipmi::responseCommandNotAvailable();
1873 str = oemData[procInfo][ss.str()][cpuInfoKey[paramSel]];
1874 int dataLen = strToBytes(str, res);
1875 std::vector<uint8_t> response(&res[0], &res[dataLen]);
1876 return ipmi::responseSuccess(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001877}
1878
1879//----------------------------------------------------------------------
1880// Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO)
1881//----------------------------------------------------------------------
1882// Request:
1883// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1884// Byte 4 – DIMM Index, 0 base
1885// Byte 5 – Parameter Selector
1886// Byte 6..N – Configuration parameter data (see below for Parameters
1887// of DIMM Information)
1888// Response:
1889// Byte 1 – Completion code
1890//
1891// Param#1 (DIMM Location):
1892// Byte 1 – DIMM Present
1893// Byte 1 – DIMM Present
1894// 01h – Present
1895// FFh – Not Present
1896// Byte 2 – Node Number, 0 base
1897// Byte 3 – Channel Number , 0 base
1898// Byte 4 – DIMM Number , 0 base
1899//
1900// Param#2 (DIMM Type):
1901// Byte 1 – DIMM Type
1902// Bit [7:6]
1903// For DDR3
1904// 00 – Normal Voltage (1.5V)
1905// 01 – Ultra Low Voltage (1.25V)
1906// 10 – Low Voltage (1.35V)
1907// 11 – Reserved
1908// For DDR4
1909// 00 – Reserved
1910// 01 – Reserved
1911// 10 – Reserved
1912// 11 – Normal Voltage (1.2V)
1913// Bit [5:0]
1914// 0x00 – SDRAM
1915// 0x01 – DDR-1 RAM
1916// 0x02 – Rambus
1917// 0x03 – DDR-2 RAM
1918// 0x04 – FBDIMM
1919// 0x05 – DDR-3 RAM
1920// 0x06 – DDR-4 RAM
1921//
1922// Param#3 (DIMM Speed):
1923// Byte 1..2 – DIMM speed in MHz, LSB
1924// Byte 3..6 – DIMM size in Mbytes, LSB
1925//
1926// Param#4 (Module Part Number):
1927// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1928//
1929// Param#5 (Module Serial Number):
1930// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1931//
1932// Param#6 (Module Manufacturer ID):
1933// Byte 1 - Module Manufacturer ID, LSB
1934// Byte 2 - Module Manufacturer ID, MSB
1935//
Patrick Williams010dee02024-08-16 15:19:44 -04001936ipmi::RspType<> ipmiOemQSetDimmInfo(
1937 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t dimmIndex,
1938 uint8_t paramSel, std::vector<uint8_t> request)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001939{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001940 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001941 std::stringstream ss;
1942 std::string str;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301943 uint8_t len = request.size();
1944 std::string dimmType;
1945 readDimmType(dimmType, dimmIndex);
Patrick Williams6d9e9a72022-07-18 10:30:50 -05001946 auto hostId = findHost(ctx->hostIdx);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301947 if (!hostId)
1948 {
1949 phosphor::logging::log<phosphor::logging::level::ERR>(
1950 "Invalid Host Id received");
1951 return ipmi::responseInvalidCommand();
1952 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001953
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301954 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001955
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301956 if (len < 3 || paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001957 {
1958 phosphor::logging::log<phosphor::logging::level::ERR>(
1959 "Invalid parameter received");
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301960 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001961 }
1962
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001963 ss << std::hex;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301964 ss << (int)dimmIndex;
1965 oemData[dimmInfo][ss.str()][KEY_DIMM_INDEX] = dimmIndex;
1966 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType;
1967 str = bytesToStr(request.data(), len);
1968 oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]] = str.c_str();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001969 flushOemData();
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301970 return ipmi::responseSuccess();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001971}
1972
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001973// Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO)
1974//----------------------------------------------------------------------
1975// Request:
1976// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1977// Byte 4 – DIMM Index, 0 base
1978// Byte 5 – Parameter Selector
1979// Byte 6..N – Configuration parameter data (see below for Parameters
1980// of DIMM Information)
1981// Response:
1982// Byte 1 – Completion code
1983// Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters
1984// of DIMM Information)
1985//
1986// Param#1 (DIMM Location):
1987// Byte 1 – DIMM Present
1988// Byte 1 – DIMM Present
1989// 01h – Present
1990// FFh – Not Present
1991// Byte 2 – Node Number, 0 base
1992// Byte 3 – Channel Number , 0 base
1993// Byte 4 – DIMM Number , 0 base
1994//
1995// Param#2 (DIMM Type):
1996// Byte 1 – DIMM Type
1997// Bit [7:6]
1998// For DDR3
1999// 00 – Normal Voltage (1.5V)
2000// 01 – Ultra Low Voltage (1.25V)
2001// 10 – Low Voltage (1.35V)
2002// 11 – Reserved
2003// For DDR4
2004// 00 – Reserved
2005// 01 – Reserved
2006// 10 – Reserved
2007// 11 – Normal Voltage (1.2V)
2008// Bit [5:0]
2009// 0x00 – SDRAM
2010// 0x01 – DDR-1 RAM
2011// 0x02 – Rambus
2012// 0x03 – DDR-2 RAM
2013// 0x04 – FBDIMM
2014// 0x05 – DDR-3 RAM
2015// 0x06 – DDR-4 RAM
2016//
2017// Param#3 (DIMM Speed):
2018// Byte 1..2 – DIMM speed in MHz, LSB
2019// Byte 3..6 – DIMM size in Mbytes, LSB
2020//
2021// Param#4 (Module Part Number):
2022// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
2023//
2024// Param#5 (Module Serial Number):
2025// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
2026//
2027// Param#6 (Module Manufacturer ID):
2028// Byte 1 - Module Manufacturer ID, LSB
2029// Byte 2 - Module Manufacturer ID, MSB
2030//
Patrick Williams1caf0482025-02-01 08:21:34 -05002031ipmi::RspType<std::vector<uint8_t>> ipmiOemQGetDimmInfo(
2032 ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t, uint8_t dimmIndex,
2033 uint8_t paramSel)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002034{
Vijay Khemka63c99be2020-05-27 19:14:35 -07002035 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302036 uint8_t res[MAX_BUF];
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002037 std::stringstream ss;
2038 std::string str;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302039 std::string dimmType;
2040 readDimmType(dimmType, dimmIndex);
Patrick Williams6d9e9a72022-07-18 10:30:50 -05002041 auto hostId = findHost(ctx->hostIdx);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302042 if (!hostId)
2043 {
2044 phosphor::logging::log<phosphor::logging::level::ERR>(
2045 "Invalid Host Id received");
2046 return ipmi::responseInvalidCommand();
2047 }
2048 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002049
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302050 if (paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002051 {
2052 phosphor::logging::log<phosphor::logging::level::ERR>(
2053 "Invalid parameter received");
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302054 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002055 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002056 ss << std::hex;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302057 ss << (int)dimmIndex;
2058 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType;
2059 if (oemData[dimmInfo].find(ss.str()) == oemData[dimmInfo].end())
2060 return ipmi::responseCommandNotAvailable();
2061 if (oemData[dimmInfo][ss.str()].find(dimmInfoKey[paramSel]) ==
2062 oemData[dimmInfo][ss.str()].end())
2063 return ipmi::responseCommandNotAvailable();
2064 str = oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]];
2065 int data_length = strToBytes(str, res);
2066 std::vector<uint8_t> response(&res[0], &res[data_length]);
2067 return ipmi::responseSuccess(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002068}
2069
2070//----------------------------------------------------------------------
2071// Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO)
2072//----------------------------------------------------------------------
2073// BIOS issue this command to provide HDD information to BMC.
2074//
2075// BIOS just can get information by standard ATA / SMART command for
2076// OB SATA controller.
2077// BIOS can get
2078// 1. Serial Number
2079// 2. Model Name
2080// 3. HDD FW Version
2081// 4. HDD Capacity
2082// 5. HDD WWN
2083//
2084// Use Get HDD info Param #5 to know the MAX HDD info index.
2085//
2086// Request:
2087// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
2088// Byte 4 –
2089// [7:4] Reserved
2090// [3:0] HDD Controller Type
2091// 0x00 – BIOS
2092// 0x01 – Expander
2093// 0x02 – LSI
2094// Byte 5 – HDD Info Index, 0 base
2095// Byte 6 – Parameter Selector
2096// Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD
2097// Information)
2098//
2099// Response:
2100// Byte 1 – Completion Code
2101//
2102// Param#0 (HDD Location):
2103// Byte 1 – Controller
2104// [7:3] Device Number
2105// [2:0] Function Number
2106// For Intel C610 series (Wellsburg)
2107// D31:F2 (0xFA) – SATA control 1
2108// D31:F5 (0xFD) – SATA control 2
2109// D17:F4 (0x8C) – sSata control
2110// Byte 2 – Port Number
2111// Byte 3 – Location (0xFF: No HDD Present)
2112// BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param
2113// #1~4, #6, #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if
2114// the HDD present. BMC or other people who know the HDD location has
2115// responsibility for update Location info
2116//
2117// Param#1 (Serial Number):
2118// Bytes 1..33: HDD Serial Number
2119//
2120// Param#2 (Model Name):
2121// Byte 1..33 – HDD Model Name
2122//
2123// Param#3 (HDD FW Version):
2124// Byte 1..17 –HDD FW version
2125//
2126// Param#4 (Capacity):
2127// Byte 1..4 –HDD Block Size, LSB
2128// Byte 5..12 - HDD Block Number, LSB
2129// HDD Capacity = HDD Block size * HDD BLock number (Unit Byte)
2130//
2131// Param#5 (Max HDD Quantity):
2132// Byte 1 - Max HDD Quantity
2133// Max supported port numbers in this PCH
2134//
2135// Param#6 (HDD Type)
2136// Byte 1 – HDD Type
2137// 0h – Reserved
2138// 1h – SAS
2139// 2h – SATA
2140// 3h – PCIE SSD (NVME)
2141//
2142// Param#7 (HDD WWN)
2143// Data 1...8: HDD World Wide Name, LSB
2144//
Willy Tue39f9392022-06-15 13:24:20 -07002145ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t, ipmi_cmd_t,
2146 ipmi_request_t request, ipmi_response_t,
2147 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002148{
Vijay Khemka63c99be2020-05-27 19:14:35 -07002149 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
2150 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002151 uint8_t ctrlType = req->hddCtrlType & 0x0f;
2152 std::stringstream ss;
2153 std::string str;
2154 uint8_t len = *data_len;
2155
2156 *data_len = 0;
2157
2158 /* check for requested data params */
Bruce Hungb445feb2025-07-17 17:36:25 +08002159 if (len < 6 || req->paramSel >= numParam || ctrlType > 2)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002160 {
2161 phosphor::logging::log<phosphor::logging::level::ERR>(
2162 "Invalid parameter received");
George Liu2f454992025-07-02 16:43:57 +08002163 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002164 }
2165
2166 len = len - 6; // Get Actual data length
2167
2168 ss << std::hex;
2169 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
2170 oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType;
2171 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] =
2172 req->hddIndex;
2173
2174 str = bytesToStr(req->data, len);
2175 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
2176 [driveInfoKey[req->paramSel]] = str.c_str();
2177 flushOemData();
2178
George Liu2f454992025-07-02 16:43:57 +08002179 return ipmi::ccSuccess;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002180}
2181
2182//----------------------------------------------------------------------
2183// Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO)
2184//----------------------------------------------------------------------
2185// BMC needs to check HDD presented or not first. If NOT presented, return
2186// completion code 0xD5.
2187//
2188// Request:
2189// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
2190// Byte 4 –
2191//[7:4] Reserved
2192//[3:0] HDD Controller Type
2193// 0x00 – BIOS
2194// 0x01 – Expander
2195// 0x02 – LSI
2196// Byte 5 – HDD Index, 0 base
2197// Byte 6 – Parameter Selector (See Above Set HDD Information)
2198// Response:
2199// Byte 1 – Completion Code
2200// 0xD5 – Not support in current status (HDD Not Present)
2201// Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD
2202// Information)
2203//
Patrick Williams010dee02024-08-16 15:19:44 -04002204ipmi_ret_t ipmiOemQGetDriveInfo(
2205 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
2206 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002207{
Vijay Khemka63c99be2020-05-27 19:14:35 -07002208 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
2209 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
2210 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002211 uint8_t ctrlType = req->hddCtrlType & 0x0f;
2212 std::stringstream ss;
2213 std::string str;
2214
2215 *data_len = 0;
2216
2217 /* check for requested data params */
Bruce Hungb445feb2025-07-17 17:36:25 +08002218 if (req->paramSel >= numParam || ctrlType > 2)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002219 {
2220 phosphor::logging::log<phosphor::logging::level::ERR>(
2221 "Invalid parameter received");
George Liu2f454992025-07-02 16:43:57 +08002222 return ipmi::ccParmOutOfRange;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002223 }
2224
2225 if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) ==
2226 oemData[KEY_Q_DRIVE_INFO].end())
2227 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2228
2229 ss << std::hex;
2230 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
2231
2232 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) ==
Bruce Hungb445feb2025-07-17 17:36:25 +08002233 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].end())
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002234 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2235
2236 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find(
Bruce Hungb445feb2025-07-17 17:36:25 +08002237 driveInfoKey[req->paramSel]) ==
2238 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].end())
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002239 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2240
2241 str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
Bruce Hungb445feb2025-07-17 17:36:25 +08002242 [driveInfoKey[req->paramSel]];
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002243 *data_len = strToBytes(str, res);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002244
George Liu2f454992025-07-02 16:43:57 +08002245 return ipmi::ccSuccess;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002246}
2247
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302248/* Helper function for sending DCMI commands to ME/BIC and
2249 * getting response back
2250 */
Patrick Williams1caf0482025-02-01 08:21:34 -05002251ipmi::RspType<std::vector<uint8_t>> sendDCMICmd(
2252 [[maybe_unused]] ipmi::Context::ptr ctx, [[maybe_unused]] uint8_t cmd,
2253 std::vector<uint8_t>& cmdData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002254{
2255 std::vector<uint8_t> respData;
2256
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302257#if BIC_ENABLED
2258
2259 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
2260
2261 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, cmdData, respData))
2262 {
2263 return ipmi::responseUnspecifiedError();
2264 }
2265
2266#else
2267
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002268 /* Add group id as first byte to request for ME command */
2269 cmdData.insert(cmdData.begin(), groupDCMI);
2270
2271 if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData))
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302272 {
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002273 return ipmi::responseUnspecifiedError();
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302274 }
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002275
2276 /* Remove group id as first byte as it will be added by IPMID */
2277 respData.erase(respData.begin());
2278
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302279#endif
2280
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002281 return ipmi::responseSuccess(std::move(respData));
2282}
2283
2284/* DCMI Command handellers. */
2285
Patrick Williams010dee02024-08-16 15:19:44 -04002286ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerReading(
2287 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002288{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302289 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerReading, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002290}
2291
Patrick Williams010dee02024-08-16 15:19:44 -04002292ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIGetPowerLimit(
2293 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002294{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302295 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002296}
2297
Patrick Williams010dee02024-08-16 15:19:44 -04002298ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMISetPowerLimit(
2299 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002300{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302301 return sendDCMICmd(ctx, ipmi::dcmi::cmdSetPowerLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002302}
2303
Patrick Williams010dee02024-08-16 15:19:44 -04002304ipmi::RspType<std::vector<uint8_t>> ipmiOemDCMIApplyPowerLimit(
2305 ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002306{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302307 return sendDCMICmd(ctx, ipmi::dcmi::cmdActDeactivatePwrLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002308}
2309
Cosmo Chou99d42b62024-08-15 10:42:47 +08002310// Https Boot related functions
Patrick Williams010dee02024-08-16 15:19:44 -04002311ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsData(
2312 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou99d42b62024-08-15 10:42:47 +08002313{
2314 if (reqData.size() < sizeof(HttpsDataReq))
2315 return ipmi::responseReqDataLenInvalid();
2316
2317 const auto* pReq = reinterpret_cast<const HttpsDataReq*>(reqData.data());
2318 std::error_code ec;
2319 auto fileSize = std::filesystem::file_size(certPath, ec);
2320 if (ec)
2321 return ipmi::responseUnspecifiedError();
2322
2323 if (pReq->offset >= fileSize)
2324 return ipmi::responseInvalidFieldRequest();
2325
2326 std::ifstream file(certPath, std::ios::binary);
2327 if (!file)
2328 return ipmi::responseUnspecifiedError();
2329
2330 auto readLen = std::min<uint16_t>(pReq->length, fileSize - pReq->offset);
2331 std::vector<uint8_t> resData(readLen + 1);
2332 resData[0] = readLen;
2333 file.seekg(pReq->offset);
2334 file.read(reinterpret_cast<char*>(resData.data() + 1), readLen);
2335
2336 return ipmi::responseSuccess(resData);
2337}
2338
Patrick Williams010dee02024-08-16 15:19:44 -04002339ipmi::RspType<std::vector<uint8_t>> ipmiOemGetHttpsAttr(
2340 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou99d42b62024-08-15 10:42:47 +08002341{
2342 if (reqData.size() < sizeof(HttpsBootAttr))
2343 return ipmi::responseReqDataLenInvalid();
2344
2345 std::vector<uint8_t> resData;
2346
2347 switch (static_cast<HttpsBootAttr>(reqData[0]))
2348 {
2349 case HttpsBootAttr::certSize:
2350 {
2351 std::error_code ec;
2352 auto fileSize = std::filesystem::file_size(certPath, ec);
2353 if (ec || fileSize > std::numeric_limits<uint16_t>::max())
2354 return ipmi::responseUnspecifiedError();
2355
2356 uint16_t size = static_cast<uint16_t>(fileSize);
2357 resData.resize(sizeof(uint16_t));
2358 std::memcpy(resData.data(), &size, sizeof(uint16_t));
2359 break;
2360 }
2361 case HttpsBootAttr::certCrc:
2362 {
2363 std::ifstream file(certPath, std::ios::binary);
2364 if (!file)
2365 return ipmi::responseUnspecifiedError();
2366
2367 boost::crc_32_type result;
2368 char data[1024];
2369 while (file.read(data, sizeof(data)))
2370 result.process_bytes(data, file.gcount());
2371 if (file.gcount() > 0)
2372 result.process_bytes(data, file.gcount());
2373
2374 uint32_t crc = result.checksum();
2375 resData.resize(sizeof(uint32_t));
2376 std::memcpy(resData.data(), &crc, sizeof(uint32_t));
2377 break;
2378 }
2379 default:
2380 return ipmi::responseInvalidFieldRequest();
2381 }
2382
2383 return ipmi::responseSuccess(resData);
2384}
2385
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002386// OEM Crashdump related functions
2387static ipmi_ret_t setDumpState(CrdState& currState, CrdState newState)
2388{
2389 switch (newState)
2390 {
2391 case CrdState::waitData:
2392 if (currState == CrdState::packing)
2393 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2394 break;
2395 case CrdState::packing:
2396 if (currState != CrdState::waitData)
2397 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2398 break;
2399 case CrdState::free:
2400 break;
2401 default:
George Liu2f454992025-07-02 16:43:57 +08002402 return ipmi::ccUnspecifiedError;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002403 }
2404 currState = newState;
2405
George Liu2f454992025-07-02 16:43:57 +08002406 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002407}
2408
2409static ipmi_ret_t handleMcaBank(const CrashDumpHdr& hdr,
2410 std::span<const uint8_t> data,
2411 CrdState& currState, std::stringstream& ss)
2412{
2413 if (data.size() < sizeof(CrdMcaBank))
George Liu2f454992025-07-02 16:43:57 +08002414 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002415
2416 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2417 if (res)
2418 return res;
2419
2420 const auto* pBank = reinterpret_cast<const CrdMcaBank*>(data.data());
2421 ss << std::format(" Bank ID : 0x{:02X}, Core ID : 0x{:02X}\n",
2422 hdr.bankHdr.bankId, hdr.bankHdr.coreId);
2423 ss << std::format(" MCA_CTRL : 0x{:016X}\n", pBank->mcaCtrl);
2424 ss << std::format(" MCA_STATUS : 0x{:016X}\n", pBank->mcaSts);
2425 ss << std::format(" MCA_ADDR : 0x{:016X}\n", pBank->mcaAddr);
2426 ss << std::format(" MCA_MISC0 : 0x{:016X}\n", pBank->mcaMisc0);
2427 ss << std::format(" MCA_CTRL_MASK : 0x{:016X}\n", pBank->mcaCtrlMask);
2428 ss << std::format(" MCA_CONFIG : 0x{:016X}\n", pBank->mcaConfig);
2429 ss << std::format(" MCA_IPID : 0x{:016X}\n", pBank->mcaIpid);
2430 ss << std::format(" MCA_SYND : 0x{:016X}\n", pBank->mcaSynd);
2431 ss << std::format(" MCA_DESTAT : 0x{:016X}\n", pBank->mcaDestat);
2432 ss << std::format(" MCA_DEADDR : 0x{:016X}\n", pBank->mcaDeaddr);
2433 ss << std::format(" MCA_MISC1 : 0x{:016X}\n", pBank->mcaMisc1);
2434 ss << "\n";
2435
George Liu2f454992025-07-02 16:43:57 +08002436 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002437}
2438
2439template <typename T>
2440static ipmi_ret_t handleVirtualBank(std::span<const uint8_t> data,
2441 CrdState& currState, std::stringstream& ss)
2442{
2443 if (data.size() < sizeof(T))
George Liu2f454992025-07-02 16:43:57 +08002444 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002445
2446 const auto* pBank = reinterpret_cast<const T*>(data.data());
2447
2448 if (data.size() < sizeof(T) + sizeof(BankCorePair) * pBank->mcaCount)
George Liu2f454992025-07-02 16:43:57 +08002449 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002450
2451 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2452 if (res)
2453 return res;
2454
2455 ss << " Virtual Bank\n";
2456 ss << std::format(" S5_RESET_STATUS : 0x{:08X}\n", pBank->s5ResetSts);
2457 ss << std::format(" PM_BREAKEVENT : 0x{:08X}\n", pBank->breakevent);
2458 if constexpr (std::is_same_v<T, CrdVirtualBankV3>)
2459 {
2460 ss << std::format(" WARMCOLDRSTSTATUS : 0x{:08X}\n", pBank->rstSts);
2461 }
2462 ss << std::format(" PROCESSOR NUMBER : 0x{:04X}\n", pBank->procNum);
2463 ss << std::format(" APIC ID : 0x{:08X}\n", pBank->apicId);
2464 ss << std::format(" EAX : 0x{:08X}\n", pBank->eax);
2465 ss << std::format(" EBX : 0x{:08X}\n", pBank->ebx);
2466 ss << std::format(" ECX : 0x{:08X}\n", pBank->ecx);
2467 ss << std::format(" EDX : 0x{:08X}\n", pBank->edx);
2468 ss << " VALID LIST : ";
2469 for (size_t i = 0; i < pBank->mcaCount; i++)
2470 {
2471 ss << std::format("(0x{:02X},0x{:02X}) ", pBank->mcaList[i].bankId,
2472 pBank->mcaList[i].coreId);
2473 }
2474 ss << "\n\n";
2475
George Liu2f454992025-07-02 16:43:57 +08002476 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002477}
2478
2479static ipmi_ret_t handleCpuWdtBank(std::span<const uint8_t> data,
2480 CrdState& currState, std::stringstream& ss)
2481{
2482 if (data.size() < sizeof(CrdCpuWdtBank))
George Liu2f454992025-07-02 16:43:57 +08002483 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002484
2485 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2486 if (res)
2487 return res;
2488
2489 const auto* pBank = reinterpret_cast<const CrdCpuWdtBank*>(data.data());
2490 for (size_t i = 0; i < ccmNum; i++)
2491 {
2492 ss << std::format(" [CCM{}]\n", i);
2493 ss << std::format(" HwAssertStsHi : 0x{:08X}\n",
2494 pBank->hwAssertStsHi[i]);
2495 ss << std::format(" HwAssertStsLo : 0x{:08X}\n",
2496 pBank->hwAssertStsLo[i]);
2497 ss << std::format(" OrigWdtAddrLogHi : 0x{:08X}\n",
2498 pBank->origWdtAddrLogHi[i]);
2499 ss << std::format(" OrigWdtAddrLogLo : 0x{:08X}\n",
2500 pBank->origWdtAddrLogLo[i]);
2501 ss << std::format(" HwAssertMskHi : 0x{:08X}\n",
2502 pBank->hwAssertMskHi[i]);
2503 ss << std::format(" HwAssertMskLo : 0x{:08X}\n",
2504 pBank->hwAssertMskLo[i]);
2505 ss << std::format(" OrigWdtAddrLogStat : 0x{:08X}\n",
2506 pBank->origWdtAddrLogStat[i]);
2507 }
2508 ss << "\n";
2509
George Liu2f454992025-07-02 16:43:57 +08002510 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002511}
2512
2513template <size_t N>
Patrick Williams1caf0482025-02-01 08:21:34 -05002514static ipmi_ret_t handleHwAssertBank(const char* name,
2515 std::span<const uint8_t> data,
2516 CrdState& currState, std::stringstream& ss)
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002517{
2518 if (data.size() < sizeof(CrdHwAssertBank<N>))
George Liu2f454992025-07-02 16:43:57 +08002519 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002520
2521 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2522 if (res)
2523 return res;
2524
2525 const CrdHwAssertBank<N>* pBank =
2526 reinterpret_cast<const CrdHwAssertBank<N>*>(data.data());
2527
2528 for (size_t i = 0; i < N; i++)
2529 {
2530 ss << std::format(" [{}{}]\n", name, i);
2531 ss << std::format(" HwAssertStsHi : 0x{:08X}\n",
2532 pBank->hwAssertStsHi[i]);
2533 ss << std::format(" HwAssertStsLo : 0x{:08X}\n",
2534 pBank->hwAssertStsLo[i]);
2535 ss << std::format(" HwAssertMskHi : 0x{:08X}\n",
2536 pBank->hwAssertMskHi[i]);
2537 ss << std::format(" HwAssertMskLo : 0x{:08X}\n",
2538 pBank->hwAssertMskLo[i]);
2539 }
2540 ss << "\n";
2541
George Liu2f454992025-07-02 16:43:57 +08002542 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002543}
2544
2545static ipmi_ret_t handlePcieAerBank(std::span<const uint8_t> data,
2546 CrdState& currState, std::stringstream& ss)
2547{
2548 if (data.size() < sizeof(CrdPcieAerBank))
George Liu2f454992025-07-02 16:43:57 +08002549 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002550
2551 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2552 if (res)
2553 return res;
2554
2555 const auto* pBank = reinterpret_cast<const CrdPcieAerBank*>(data.data());
2556 ss << std::format(" [Bus{} Dev{} Fun{}]\n", pBank->bus, pBank->dev,
2557 pBank->fun);
2558 ss << std::format(" Command : 0x{:04X}\n",
2559 pBank->cmd);
2560 ss << std::format(" Status : 0x{:04X}\n",
2561 pBank->sts);
2562 ss << std::format(" Slot : 0x{:04X}\n",
2563 pBank->slot);
2564 ss << std::format(" Secondary Bus : 0x{:02X}\n",
2565 pBank->secondBus);
2566 ss << std::format(" Vendor ID : 0x{:04X}\n",
2567 pBank->vendorId);
2568 ss << std::format(" Device ID : 0x{:04X}\n",
2569 pBank->devId);
2570 ss << std::format(" Class Code : 0x{:02X}{:04X}\n",
2571 pBank->classCodeHi, pBank->classCodeLo);
2572 ss << std::format(" Bridge: Secondary Status : 0x{:04X}\n",
2573 pBank->secondSts);
2574 ss << std::format(" Bridge: Control : 0x{:04X}\n",
2575 pBank->ctrl);
2576 ss << std::format(" Uncorrectable Error Status : 0x{:08X}\n",
2577 pBank->uncorrErrSts);
2578 ss << std::format(" Uncorrectable Error Mask : 0x{:08X}\n",
2579 pBank->uncorrErrMsk);
2580 ss << std::format(" Uncorrectable Error Severity : 0x{:08X}\n",
2581 pBank->uncorrErrSeverity);
2582 ss << std::format(" Correctable Error Status : 0x{:08X}\n",
2583 pBank->corrErrSts);
2584 ss << std::format(" Correctable Error Mask : 0x{:08X}\n",
2585 pBank->corrErrMsk);
2586 ss << std::format(" Header Log DW0 : 0x{:08X}\n",
2587 pBank->hdrLogDw0);
2588 ss << std::format(" Header Log DW1 : 0x{:08X}\n",
2589 pBank->hdrLogDw1);
2590 ss << std::format(" Header Log DW2 : 0x{:08X}\n",
2591 pBank->hdrLogDw2);
2592 ss << std::format(" Header Log DW3 : 0x{:08X}\n",
2593 pBank->hdrLogDw3);
2594 ss << std::format(" Root Error Status : 0x{:08X}\n",
2595 pBank->rootErrSts);
2596 ss << std::format(" Correctable Error Source ID : 0x{:04X}\n",
2597 pBank->corrErrSrcId);
2598 ss << std::format(" Error Source ID : 0x{:04X}\n",
2599 pBank->errSrcId);
2600 ss << std::format(" Lane Error Status : 0x{:08X}\n",
2601 pBank->laneErrSts);
2602 ss << "\n";
2603
George Liu2f454992025-07-02 16:43:57 +08002604 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002605}
2606
2607static ipmi_ret_t handleWdtRegBank(std::span<const uint8_t> data,
2608 CrdState& currState, std::stringstream& ss)
2609{
2610 if (data.size() < sizeof(CrdWdtRegBank))
George Liu2f454992025-07-02 16:43:57 +08002611 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002612
2613 const auto* pBank = reinterpret_cast<const CrdWdtRegBank*>(data.data());
2614 if (data.size() < sizeof(CrdWdtRegBank) + sizeof(uint32_t) * pBank->count)
George Liu2f454992025-07-02 16:43:57 +08002615 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002616
2617 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2618 if (res)
2619 return res;
2620
2621 ss << std::format(" [NBIO{}] {}\n", pBank->nbio, pBank->name);
2622 ss << std::format(" Address: 0x{:08X}\n", pBank->addr);
2623 ss << std::format(" Data Count: {}\n", pBank->count);
2624 ss << " Data:\n";
2625 for (size_t i = 0; i < pBank->count; i++)
2626 {
2627 ss << std::format(" {}: 0x{:08X}\n", i, pBank->data[i]);
2628 }
2629 ss << "\n";
2630
George Liu2f454992025-07-02 16:43:57 +08002631 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002632}
2633
2634static ipmi_ret_t handleCrdHdrBank(std::span<const uint8_t> data,
2635 CrdState& currState, std::stringstream& ss)
2636{
2637 if (data.size() < sizeof(CrdHdrBank))
George Liu2f454992025-07-02 16:43:57 +08002638 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002639
2640 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2641 if (res)
2642 return res;
2643
2644 const auto* pBank = reinterpret_cast<const CrdHdrBank*>(data.data());
2645 ss << " Crashdump Header\n";
2646 ss << std::format(" CPU PPIN : 0x{:016X}\n", pBank->ppin);
2647 ss << std::format(" UCODE VERSION : 0x{:08X}\n", pBank->ucodeVer);
2648 ss << std::format(" PMIO 80h : 0x{:08X}\n", pBank->pmio);
2649 ss << std::format(
2650 " BIT0 - SMN Parity/SMN Timeouts PSP/SMU Parity and ECC/SMN On-Package Link Error : {}\n",
2651 pBank->pmio & 0x1);
2652 ss << std::format(" BIT2 - PSP Parity and ECC : {}\n",
2653 (pBank->pmio & 0x4) >> 2);
2654 ss << std::format(" BIT3 - SMN Timeouts SMU : {}\n",
2655 (pBank->pmio & 0x8) >> 3);
2656 ss << std::format(" BIT4 - SMN Off-Package Link Packet Error : {}\n",
2657 (pBank->pmio & 0x10) >> 4);
2658 ss << "\n";
2659
George Liu2f454992025-07-02 16:43:57 +08002660 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002661}
2662
2663static std::string getFilename(const std::filesystem::path& dir,
2664 const std::string& prefix)
2665{
2666 std::vector<int> indices;
2667 std::regex pattern(prefix + "(\\d+)\\.txt");
2668
2669 for (const auto& entry : std::filesystem::directory_iterator(dir))
2670 {
2671 std::string filename = entry.path().filename().string();
2672 std::smatch match;
2673 if (std::regex_match(filename, match, pattern))
2674 indices.push_back(std::stoi(match[1]));
2675 }
2676
2677 std::sort(indices.rbegin(), indices.rend());
2678 while (indices.size() > 2) // keep 3 files, so remove if more than 2
2679 {
2680 std::filesystem::remove(
2681 dir / (prefix + std::to_string(indices.back()) + ".txt"));
2682 indices.pop_back();
2683 }
2684
2685 int nextIndex = indices.empty() ? 1 : indices.front() + 1;
2686 return prefix + std::to_string(nextIndex) + ".txt";
2687}
2688
2689static ipmi_ret_t handleCtrlBank(std::span<const uint8_t> data,
2690 CrdState& currState, std::stringstream& ss)
2691{
2692 if (data.empty())
George Liu2f454992025-07-02 16:43:57 +08002693 return ipmi::ccReqDataLenInvalid;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002694
2695 switch (static_cast<CrdCtrl>(data[0]))
2696 {
2697 case CrdCtrl::getState:
2698 break;
2699 case CrdCtrl::finish:
2700 {
2701 ipmi_ret_t res = setDumpState(currState, CrdState::packing);
2702 if (res)
2703 return res;
2704
2705 const std::filesystem::path dumpDir = "/var/lib/fb-ipmi-oem";
2706 std::string filename = getFilename(dumpDir, "crashdump_");
2707 std::ofstream outFile(dumpDir / filename);
2708 if (!outFile.is_open())
George Liu2f454992025-07-02 16:43:57 +08002709 return ipmi::ccUnspecifiedError;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002710
2711 auto now = std::chrono::system_clock::to_time_t(
2712 std::chrono::system_clock::now());
2713 outFile << "Crash Dump generated at: "
2714 << std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M:%S")
2715 << "\n\n";
2716 outFile << ss.str();
2717 outFile.close();
2718 ss.str("");
2719 ss.clear();
2720 setDumpState(currState, CrdState::free);
2721 break;
2722 }
2723 default:
2724 return ccInvalidParam;
2725 }
2726
George Liu2f454992025-07-02 16:43:57 +08002727 return ipmi::ccSuccess;
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002728}
2729
Patrick Williams010dee02024-08-16 15:19:44 -04002730ipmi::RspType<std::vector<uint8_t>> ipmiOemCrashdump(
2731 [[maybe_unused]] ipmi::Context::ptr ctx, std::vector<uint8_t> reqData)
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002732{
2733 static CrdState dumpState = CrdState::free;
2734 static std::stringstream ss;
2735
2736 if (reqData.size() < sizeof(CrashDumpHdr))
2737 return ipmi::responseReqDataLenInvalid();
2738
2739 const auto* pHdr = reinterpret_cast<const CrashDumpHdr*>(reqData.data());
2740 std::span<const uint8_t> bData{reqData.data() + sizeof(CrashDumpHdr),
2741 reqData.size() - sizeof(CrashDumpHdr)};
2742 ipmi_ret_t res;
2743
2744 switch (pHdr->bankHdr.bankType)
2745 {
2746 case BankType::mca:
2747 res = handleMcaBank(*pHdr, bData, dumpState, ss);
2748 break;
2749 case BankType::virt:
2750 if (pHdr->bankHdr.version >= 3)
2751 {
2752 res = handleVirtualBank<CrdVirtualBankV3>(bData, dumpState, ss);
2753 break;
2754 }
2755 res = handleVirtualBank<CrdVirtualBankV2>(bData, dumpState, ss);
2756 break;
2757 case BankType::cpuWdt:
2758 res = handleCpuWdtBank(bData, dumpState, ss);
2759 break;
2760 case BankType::tcdx:
2761 res = handleHwAssertBank<tcdxNum>("TCDX", bData, dumpState, ss);
2762 break;
2763 case BankType::cake:
2764 res = handleHwAssertBank<cakeNum>("CAKE", bData, dumpState, ss);
2765 break;
2766 case BankType::pie0:
2767 res = handleHwAssertBank<pie0Num>("PIE", bData, dumpState, ss);
2768 break;
2769 case BankType::iom:
2770 res = handleHwAssertBank<iomNum>("IOM", bData, dumpState, ss);
2771 break;
2772 case BankType::ccix:
2773 res = handleHwAssertBank<ccixNum>("CCIX", bData, dumpState, ss);
2774 break;
2775 case BankType::cs:
2776 res = handleHwAssertBank<csNum>("CS", bData, dumpState, ss);
2777 break;
2778 case BankType::pcieAer:
2779 res = handlePcieAerBank(bData, dumpState, ss);
2780 break;
2781 case BankType::wdtReg:
2782 res = handleWdtRegBank(bData, dumpState, ss);
2783 break;
2784 case BankType::ctrl:
2785 res = handleCtrlBank(bData, dumpState, ss);
George Liu2f454992025-07-02 16:43:57 +08002786 if (res == ipmi::ccSuccess &&
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002787 static_cast<CrdCtrl>(bData[0]) == CrdCtrl::getState)
2788 {
2789 return ipmi::responseSuccess(
2790 std::vector<uint8_t>{static_cast<uint8_t>(dumpState)});
2791 }
2792 break;
2793 case BankType::crdHdr:
2794 res = handleCrdHdrBank(bData, dumpState, ss);
2795 break;
2796 default:
2797 return ipmi::responseInvalidFieldRequest();
2798 }
2799
2800 return ipmi::response(res);
2801}
2802
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002803static void registerOEMFunctions(void)
2804{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002805 /* Get OEM data from json file */
2806 std::ifstream file(JSON_OEM_DATA_FILE);
2807 if (file)
Vijay Khemkafeaa9812019-08-27 15:08:08 -07002808 {
Peter Yinac597172024-11-05 16:15:50 +08002809 try
2810 {
2811 file >> oemData;
2812 }
2813 // If parsing fails, initialize oemData as an empty JSON and
2814 // overwrite the file
2815 catch (const nlohmann::json::parse_error& e)
2816 {
2817 lg2::error("Error parsing JSON file: {ERROR}", "ERROR", e);
2818 oemData = nlohmann::json::object();
2819 std::ofstream outFile(JSON_OEM_DATA_FILE, std::ofstream::trunc);
2820 outFile << oemData.dump(4); // Write empty JSON object to the file
2821 outFile.close();
2822 }
Vijay Khemkafeaa9812019-08-27 15:08:08 -07002823 file.close();
2824 }
Peter Yinac597172024-11-05 16:15:50 +08002825 else
2826 {
2827 lg2::info("Failed to open JSON file.");
2828 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002829
Peter Yinac597172024-11-05 16:15:50 +08002830 lg2::info("Registering OEM commands.");
Vijay Khemka7c0aea42020-03-05 13:31:53 -08002831
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002832 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO,
2833 NULL, ipmiOemDbgGetFrameInfo,
2834 PRIVILEGE_USER); // get debug frame info
2835 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ,
2836 CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL,
2837 ipmiOemDbgGetUpdFrames,
2838 PRIVILEGE_USER); // get debug updated frames
2839 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC,
2840 NULL, ipmiOemDbgGetPostDesc,
2841 PRIVILEGE_USER); // get debug post description
2842 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC,
2843 NULL, ipmiOemDbgGetGpioDesc,
2844 PRIVILEGE_USER); // get debug gpio description
2845 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA,
2846 NULL, ipmiOemDbgGetFrameData,
2847 PRIVILEGE_USER); // get debug frame data
2848 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL,
2849 NULL, ipmiOemDbgGetCtrlPanel,
2850 PRIVILEGE_USER); // get debug control panel
George Liu0821a2e2025-04-03 10:12:10 +08002851 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_DIMM_INFO, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002852 ipmiOemSetDimmInfo,
2853 PRIVILEGE_USER); // Set Dimm Info
George Liu0821a2e2025-04-03 10:12:10 +08002854 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_BOARD_ID, NULL,
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002855 ipmiOemGetBoardID,
2856 PRIVILEGE_USER); // Get Board ID
Bonnie Lo4ae63e72023-02-09 15:27:54 +08002857 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnOemOne,
2858 CMD_OEM_GET_80PORT_RECORD, ipmi::Privilege::User,
2859 ipmiOemGet80PortRecord); // Get 80 Port Record
George Liu0821a2e2025-04-03 10:12:10 +08002860 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_MACHINE_CONFIG_INFO,
2861 NULL, ipmiOemSetMachineCfgInfo,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002862 PRIVILEGE_USER); // Set Machine Config Info
George Liu0821a2e2025-04-03 10:12:10 +08002863 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_POST_START, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002864 ipmiOemSetPostStart,
2865 PRIVILEGE_USER); // Set POST start
George Liu0821a2e2025-04-03 10:12:10 +08002866 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_POST_END, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002867 ipmiOemSetPostEnd,
2868 PRIVILEGE_USER); // Set POST End
George Liu0821a2e2025-04-03 10:12:10 +08002869 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_PPIN_INFO, NULL,
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002870 ipmiOemSetPPINInfo,
2871 PRIVILEGE_USER); // Set PPIN Info
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05302872#if BIC_ENABLED
2873
2874 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2875 ipmi::cmdSetSystemGuid, ipmi::Privilege::User,
2876 ipmiOemSetSystemGuid);
2877#else
2878
George Liu0821a2e2025-04-03 10:12:10 +08002879 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_SYSTEM_GUID, NULL,
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07002880 ipmiOemSetSystemGuid,
2881 PRIVILEGE_USER); // Set System GUID
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05302882#endif
George Liu0821a2e2025-04-03 10:12:10 +08002883 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_ADR_TRIGGER, NULL,
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002884 ipmiOemSetAdrTrigger,
2885 PRIVILEGE_USER); // Set ADR Trigger
George Liu0821a2e2025-04-03 10:12:10 +08002886 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_BIOS_FLASH_INFO, NULL,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002887 ipmiOemSetBiosFlashInfo,
2888 PRIVILEGE_USER); // Set Bios Flash Info
George Liu0821a2e2025-04-03 10:12:10 +08002889 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_SET_PPR, NULL,
2890 ipmiOemSetPpr,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002891 PRIVILEGE_USER); // Set PPR
George Liu0821a2e2025-04-03 10:12:10 +08002892 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_PPR, NULL,
2893 ipmiOemGetPpr,
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002894 PRIVILEGE_USER); // Get PPR
Alex Wang695ef4e2025-09-19 15:40:42 +08002895 ipmiPrintAndRegister(ipmi::netFnOemOne, CMD_OEM_GET_FRU_ID, NULL,
2896 ipmiOemGetFruId,
2897 PRIVILEGE_USER); // Get FRU ID
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002898 /* FB OEM QC Commands */
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05302899 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2900 CMD_OEM_Q_SET_PROC_INFO, ipmi::Privilege::User,
2901 ipmiOemQSetProcInfo); // Set Proc Info
2902 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2903 CMD_OEM_Q_GET_PROC_INFO, ipmi::Privilege::User,
2904 ipmiOemQGetProcInfo); // Get Proc Info
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302905 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2906 ipmi::cmdSetQDimmInfo, ipmi::Privilege::User,
2907 ipmiOemQSetDimmInfo); // Set Dimm Info
2908 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2909 ipmi::cmdGetQDimmInfo, ipmi::Privilege::User,
2910 ipmiOemQGetDimmInfo); // Get Dimm Info
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002911 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL,
2912 ipmiOemQSetDriveInfo,
2913 PRIVILEGE_USER); // Set Drive Info
2914 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL,
2915 ipmiOemQGetDriveInfo,
2916 PRIVILEGE_USER); // Get Drive Info
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002917
2918 /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */
Patrick Williams010dee02024-08-16 15:19:44 -04002919 ipmi::registerGroupHandler(
2920 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerReading,
2921 ipmi::Privilege::User,
2922 ipmiOemDCMIGetPowerReading); // Get Power Reading
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002923
Patrick Williams010dee02024-08-16 15:19:44 -04002924 ipmi::registerGroupHandler(
2925 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdGetPowerLimit,
2926 ipmi::Privilege::User,
2927 ipmiOemDCMIGetPowerLimit); // Get Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002928
Patrick Williams010dee02024-08-16 15:19:44 -04002929 ipmi::registerGroupHandler(
2930 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdSetPowerLimit,
2931 ipmi::Privilege::Operator,
2932 ipmiOemDCMISetPowerLimit); // Set Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002933
Patrick Williams010dee02024-08-16 15:19:44 -04002934 ipmi::registerGroupHandler(
2935 ipmi::prioOpenBmcBase, groupDCMI, ipmi::dcmi::cmdActDeactivatePwrLimit,
2936 ipmi::Privilege::Operator,
2937 ipmiOemDCMIApplyPowerLimit); // Apply Power Limit
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002938
Jayashree-Df0cf6652020-11-30 11:03:30 +05302939 /* FB OEM BOOT ORDER COMMANDS */
2940 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2941 CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User,
2942 ipmiOemGetBootOrder); // Get Boot Order
2943
2944 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2945 CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User,
2946 ipmiOemSetBootOrder); // Set Boot Order
2947
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002948 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
Cosmo Chou99d42b62024-08-15 10:42:47 +08002949 CMD_OEM_GET_HTTPS_BOOT_DATA, ipmi::Privilege::User,
2950 ipmiOemGetHttpsData);
2951
2952 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2953 CMD_OEM_GET_HTTPS_BOOT_ATTR, ipmi::Privilege::User,
2954 ipmiOemGetHttpsAttr);
2955
2956 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002957 CMD_OEM_CRASHDUMP, ipmi::Privilege::User,
2958 ipmiOemCrashdump);
2959
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002960 return;
2961}
2962
2963} // namespace ipmi