Implement get/set platform serial port parameters command
This command is used for BIOS to set/get host serial host configuration.
Tested:
set config:
ipmitool raw 0x32 0x90 1 0
get config:
ipmitool raw 0x32 0x90 0
Change-Id: I97feebbfd88033a186e19e6f53ab92a240902603
Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
diff --git a/include/oemcommands.hpp b/include/oemcommands.hpp
index 01dca7d..a348db2 100644
--- a/include/oemcommands.hpp
+++ b/include/oemcommands.hpp
@@ -32,6 +32,11 @@
cmdGetLEDStatus = 0xB0,
};
+enum class IPMINetfnIntelOEMPlatformCmd
+{
+ cmdCfgHostSerialPortSpeed = 0x90,
+};
+
enum class IPMIIntelOEMReturnCodes
{
ipmiCCPayloadActive = 0x80,
@@ -75,6 +80,9 @@
static constexpr ipmi_netfn_t netfnIntcOEMGeneral =
NETFUN_NONE; // Netfun_none. In our platform, we use it as "intel oem
// general". The code is 0x30
+
+// Intel OEM Platform code is 0x32
+static constexpr ipmi_netfn_t netfnIntcOEMPlatform = NETFUN_OEM;
static constexpr const uint8_t maxBIOSIDLength = 0xFF;
static constexpr const uint8_t maxCPUNum = 4;
static constexpr const char* biosObjPath = "/xyz/openbmc_project/bios";
@@ -115,6 +123,20 @@
"/xyz/openbmc_project/control/shutdown_policy_config";
static constexpr const char* oemShutdownPolicyObjPathProp = "Policy";
+static constexpr const char* fwGetEnvCmd = "/sbin/fw_printenv";
+static constexpr const char* fwSetEnvCmd = "/sbin/fw_setenv";
+static constexpr const char* fwHostSerailCfgEnvName = "hostserialcfg";
+
+static constexpr const uint8_t getHostSerialCfgCmd = 0;
+static constexpr const uint8_t setHostSerialCfgCmd = 1;
+
+// parameters:
+// 0: host serial port 1 and 2 normal speed
+// 1: host serial port 1 high spend, port 2 normal speed
+// 2: host serial port 1 normal spend, port 2 high speed
+// 3: host serial port 1 and 2 high speed
+static constexpr const uint8_t HostSerialCfgParamMax = 3;
+
enum class IPMINetfnIntelOEMAppCmd
{
mdrStatus = 0x20,
@@ -242,4 +264,9 @@
uint8_t policySupport;
};
+struct CfgHostSerialReq
+{
+ uint8_t command;
+ uint8_t parameter;
+};
#pragma pack(pop)
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index 724d8e5..5791b28 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -20,6 +20,8 @@
#include <ipmid/api.h>
#include <array>
+#include <boost/process/child.hpp>
+#include <boost/process/io.hpp>
#include <commandutils.hpp>
#include <iostream>
#include <oemcommands.hpp>
@@ -573,6 +575,135 @@
return IPMI_CC_OK;
}
+ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request,
+ ipmi_response_t response,
+ ipmi_data_len_t dataLen,
+ ipmi_context_t context)
+{
+ CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
+ uint8_t* resp = reinterpret_cast<uint8_t*>(response);
+
+ if (*dataLen == 0)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "CfgHostSerial: invalid input len!",
+ phosphor::logging::entry("LEN=%d", *dataLen));
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
+ switch (req->command)
+ {
+ case getHostSerialCfgCmd:
+ {
+ if (*dataLen != 1)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "CfgHostSerial: invalid input len!");
+ *dataLen = 0;
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
+ *dataLen = 0;
+
+ boost::process::ipstream is;
+ std::vector<std::string> data;
+ std::string line;
+ boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
+ boost::process::std_out > is);
+
+ while (c1.running() && std::getline(is, line) && !line.empty())
+ {
+ data.push_back(line);
+ }
+
+ c1.wait();
+ if (c1.exit_code())
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "CfgHostSerial:: error on execute",
+ phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
+ // Using the default value
+ *resp = 0;
+ }
+ else
+ {
+ if (data.size() != 1)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "CfgHostSerial:: error on read env");
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ try
+ {
+ unsigned long tmp = std::stoul(data[0]);
+ if (tmp > std::numeric_limits<uint8_t>::max())
+ {
+ throw std::out_of_range("Out of range");
+ }
+ *resp = static_cast<uint8_t>(tmp);
+ }
+ catch (const std::invalid_argument& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "invalid config ",
+ phosphor::logging::entry("ERR=%s", e.what()));
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ catch (const std::out_of_range& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "out_of_range config ",
+ phosphor::logging::entry("ERR=%s", e.what()));
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ }
+
+ *dataLen = 1;
+ break;
+ }
+ case setHostSerialCfgCmd:
+ {
+ if (*dataLen != sizeof(CfgHostSerialReq))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "CfgHostSerial: invalid input len!");
+ *dataLen = 0;
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
+ *dataLen = 0;
+
+ if (req->parameter > HostSerialCfgParamMax)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "CfgHostSerial: invalid input!");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
+ std::to_string(req->parameter));
+
+ c1.wait();
+ if (c1.exit_code())
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "CfgHostSerial:: error on execute",
+ phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ break;
+ }
+ default:
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "CfgHostSerial: invalid input!");
+ *dataLen = 0;
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ return IPMI_CC_OK;
+}
+
static void registerOEMFunctions(void)
{
phosphor::logging::log<phosphor::logging::level::INFO>(
@@ -639,6 +770,11 @@
netfnIntcOEMGeneral,
static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
+ ipmiPrintAndRegister(
+ netfnIntcOEMPlatform,
+ static_cast<ipmi_cmd_t>(
+ IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
+ NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
return;
}