summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch
diff options
context:
space:
mode:
authorEd Tanous <ed.tanous@intel.com>2019-02-14 03:51:50 +0300
committerEd Tanous <ed.tanous@intel.com>2019-03-13 00:58:57 +0300
commita7715486507e75e4a7cee843a48067b15595defa (patch)
tree9fd209d468c42cfb6553a50e2523c1d7e1fb120a /meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch
parent9b44ea7e2de71224bce792654cab12b7a5ceaa7d (diff)
downloadopenbmc-a7715486507e75e4a7cee843a48067b15595defa.tar.xz
Initial commit of intel repository
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch322
1 files changed, 322 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch
new file mode 100644
index 000000000..4018dbffe
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch
@@ -0,0 +1,322 @@
+From cd25f43461b41b74d19cd1f93ce301df9c3bd4f2 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Fri, 21 Sep 2018 09:21:14 +0800
+Subject: [PATCH] Implement IPMI Master Write-Read command
+
+This command can be used for low-level I2C/SMBus write, read, or write-read
+accesses to the IPMB or private busses behind a management controller.
+
+The command can also be used for providing low-level access to devices
+that provide an SMBus slave interface.
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ apphandler.cpp | 236 ++++++++++++++++++++++++++++++++++++++++++++++
+ apphandler.hpp | 1 +
+ host-ipmid-whitelist.conf | 1 +
+ 3 files changed, 238 insertions(+)
+
+diff --git a/apphandler.cpp b/apphandler.cpp
+index 17aff2a..2fe79f6 100644
+--- a/apphandler.cpp
++++ b/apphandler.cpp
+@@ -8,6 +8,14 @@
+ #include "types.hpp"
+ #include "utils.hpp"
+
++#include <fcntl.h>
++#include <linux/i2c-dev.h>
++#include <linux/i2c.h>
++#include <sys/ioctl.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <unistd.h>
++
+ #include <arpa/inet.h>
+ #include <host-ipmid/ipmid-api.h>
+ #include <limits.h>
+@@ -55,6 +63,8 @@ constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID";
+ constexpr auto bmc_guid_property = "UUID";
+ constexpr auto bmc_guid_len = 16;
+
++static constexpr uint8_t maxIPMIWriteReadSize = 144;
++
+ static constexpr auto redundancyIntf =
+ "xyz.openbmc_project.Software.RedundancyPriority";
+ static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version";
+@@ -86,6 +96,34 @@ typedef struct
+ uint8_t aux[4];
+ } __attribute__((packed)) ipmi_device_id_t;
+
++typedef struct
++{
++ uint8_t busId;
++ uint8_t slaveAddr;
++ uint8_t readCount;
++} __attribute__((packed)) ipmiI2cRwReq;
++
++typedef struct
++{
++ uint8_t busId;
++ uint8_t slaveAddr;
++ std::vector<uint8_t> data;
++} ipmiMasterRwWhitelist;
++
++static std::vector<ipmiMasterRwWhitelist>& getWhiteList()
++{
++ static std::vector<ipmiMasterRwWhitelist> rwWhiteList;
++ return rwWhiteList;
++}
++
++static constexpr const char* whiteListFilename =
++ "/usr/share/ipmi-providers/master_write_read_white_list.json";
++
++static constexpr const char* filtersStr = "filters";
++static constexpr const char* busIdStr = "busId";
++static constexpr const char* slaveAddrStr = "slaveAddr";
++static constexpr const char* cmdStr = "command";
++
+ /**
+ * @brief Returns the Version info from primary s/w object
+ *
+@@ -1089,8 +1127,195 @@ writeResponse:
+ return IPMI_CC_OK;
+ }
+
++static int loadI2CWhiteList()
++{
++ nlohmann::json data = nullptr;
++ std::ifstream jsonFile(whiteListFilename);
++
++ if (!jsonFile.good())
++ {
++ log<level::WARNING>("whitelist file not found!");
++ return -1;
++ }
++
++ try
++ {
++ data = nlohmann::json::parse(jsonFile, nullptr, false);
++ }
++ catch (nlohmann::json::parse_error& e)
++ {
++ log<level::ERR>("Corrupted whitelist config file",
++ entry("MSG: %s", e.what()));
++ return -1;
++ }
++
++ try
++ {
++ unsigned int i = 0;
++ nlohmann::json filters = data[filtersStr].get<nlohmann::json>();
++ getWhiteList().resize(filters.size());
++
++ for (const auto& it : filters.items())
++ {
++ nlohmann::json filter = it.value();
++ if (filter.is_null())
++ {
++ log<level::ERR>("Incorrect filter");
++ return -1;
++ }
++
++ getWhiteList()[i].busId =
++ std::stoul(filter[busIdStr].get<std::string>(), nullptr, 16);
++
++ getWhiteList()[i].slaveAddr = std::stoul(
++ filter[slaveAddrStr].get<std::string>(), nullptr, 16);
++
++ std::string command = filter[cmdStr].get<std::string>();
++
++ log<level::DEBUG>("IPMI I2C whitelist ", entry("INDEX=%d", i),
++ entry("BUS=%d", getWhiteList()[i].busId),
++ entry("ADDR=0x%x", getWhiteList()[i].slaveAddr),
++ entry("LEN=0x%x", command.length()),
++ entry("COMMAND=[%s]", command.c_str()));
++
++ // convert data string
++ std::istringstream iss(command);
++ std::string token;
++ while (std::getline(iss, token, ' '))
++ {
++ log<level::DEBUG>("IPMI I2C command\n",
++ entry("TOKEN=%s", token.c_str()));
++ getWhiteList()[i].data.emplace_back(
++ std::stoul(token, nullptr, 16));
++ }
++ i++;
++ }
++ }
++ catch (std::exception& e)
++ {
++ log<level::ERR>("unexpected exception", entry("ERROR=%s", e.what()));
++ return -1;
++ }
++ return 0;
++}
++
++ipmi_ret_t ipmiMasterWriteRead(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
++ ipmi_request_t request, ipmi_response_t response,
++ ipmi_data_len_t data_len, ipmi_context_t context)
++{
++ bool foundInList = false;
++ int ret = 0;
++ i2c_rdwr_ioctl_data msgRdwr = {0};
++ i2c_msg i2cmsg[2] = {0};
++ ipmiI2cRwReq* reqi2c = reinterpret_cast<ipmiI2cRwReq*>(request);
++
++ if (*data_len <= sizeof(ipmiI2cRwReq))
++ {
++ log<level::ERR>("Failed in request", entry("LEN=%d", *data_len));
++ *data_len = 0;
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
++ if (reqi2c->readCount > maxIPMIWriteReadSize)
++ {
++ log<level::ERR>("Failed in request", entry("R=%d", reqi2c->readCount));
++ *data_len = 0;
++ return IPMI_CC_PARM_OUT_OF_RANGE;
++ }
++
++ uint8_t* resptr = reinterpret_cast<uint8_t*>(response);
++ uint8_t busId = (reqi2c->busId & 0xFF) >> 1;
++ // Convert the I2C address from 7-bit format
++ uint8_t i2cAddr = reqi2c->slaveAddr >> 1;
++ size_t writeCount = *data_len - sizeof(ipmiI2cRwReq);
++
++ log<level::DEBUG>(
++ "INPUT: ", entry("LEN=%d", *data_len), entry("ID=0x%x", busId),
++ entry("ADDR=0x%x", reqi2c->slaveAddr), entry("R=%d", reqi2c->readCount),
++ entry("W=%d", writeCount));
++
++ *data_len = 0;
++
++ std::vector<uint8_t> inBuf(reqi2c->readCount);
++ std::vector<uint8_t> outBuf(writeCount);
++ uint8_t* reqptr = reinterpret_cast<uint8_t*>(request);
++
++ reqptr += sizeof(ipmiI2cRwReq);
++ std::copy(reqptr, reqptr + writeCount, outBuf.begin());
++
++ log<level::DEBUG>("checking list ", entry("SIZE=%d", getWhiteList().size()));
++ // command whitelist checking
++ for (unsigned int i = 0; i < getWhiteList().size(); i++)
++ {
++ // TODO add wildchard/regex support
++ if ((busId == getWhiteList()[i].busId) &&
++ (i2cAddr == getWhiteList()[i].slaveAddr) &&
++ (outBuf == getWhiteList()[i].data))
++ {
++ log<level::DEBUG>("In whitelist");
++ foundInList = true;
++ break;
++ }
++ }
++
++ if (!foundInList)
++ {
++ log<level::ERR>("Request blocked!", entry("BUS=%d", busId),
++ entry("ADDR=0x%x", reqi2c->slaveAddr));
++ return IPMI_CC_INVALID_FIELD_REQUEST;
++ }
++
++ log<level::DEBUG>("IPMI Master WriteRead ", entry("BUS=%d", busId),
++ entry("ADDR=0x%x", reqi2c->slaveAddr),
++ entry("R=%d", reqi2c->readCount),
++ entry("W=%d", writeCount));
++
++ std::string i2cBus = "/dev/i2c-" + std::to_string(busId);
++
++ int i2cDev = ::open(i2cBus.c_str(), O_RDWR | O_CLOEXEC);
++ if (i2cDev < 0)
++ {
++ log<level::ERR>("Failed in opening i2c device",
++ entry("BUS=%s", i2cBus.c_str()));
++ return IPMI_CC_UNSPECIFIED_ERROR;
++ }
++
++ // write message
++ i2cmsg[0].addr = i2cAddr;
++ i2cmsg[0].flags = 0x00;
++ i2cmsg[0].len = writeCount;
++ i2cmsg[0].buf = outBuf.data();
++
++ // read message
++ i2cmsg[1].addr = i2cAddr;
++ i2cmsg[1].flags = I2C_M_RD;
++ i2cmsg[1].len = reqi2c->readCount;
++ i2cmsg[1].buf = inBuf.data();
++
++ msgRdwr.msgs = i2cmsg;
++ msgRdwr.nmsgs = 2;
++
++ ret = ::ioctl(i2cDev, I2C_RDWR, &msgRdwr);
++ ::close(i2cDev);
++
++ // TODO add completion code support
++ if (ret < 0)
++ {
++ log<level::ERR>("RDWR ioctl error", entry("RET=%d", ret));
++ return IPMI_CC_UNSPECIFIED_ERROR;
++ }
++
++ *data_len = msgRdwr.msgs[1].len;
++ std::copy(msgRdwr.msgs[1].buf, msgRdwr.msgs[1].buf + msgRdwr.msgs[1].len,
++ resptr);
++
++ return IPMI_CC_OK;
++}
++
+ void register_netfn_app_functions()
+ {
++ int ret = -1;
++
+ // <Get BT Interface Capabilities>
+ ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CAP_BIT, NULL,
+ ipmi_app_get_bt_capabilities, PRIVILEGE_USER);
+@@ -1145,6 +1370,17 @@ void register_netfn_app_functions()
+ ipmi_app_channel_info, PRIVILEGE_USER);
+ #endif
+
++ ret = loadI2CWhiteList();
++ log<level::DEBUG>("i2c white list is loaded", entry("RET=%d", ret),
++ entry("SIZE=%d", getWhiteList().size()));
++ if (ret == 0)
++ {
++ log<level::DEBUG>("Register Master RW command");
++ // <Master Write Read Command>
++ ipmi_register_callback(NETFUN_APP, IPMI_CMD_MASTER_WRITE_READ, NULL,
++ ipmiMasterWriteRead, PRIVILEGE_OPERATOR);
++ }
++
+ // <Get System GUID Command>
+ ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYS_GUID, NULL,
+ ipmi_app_get_sys_guid, PRIVILEGE_USER);
+diff --git a/apphandler.hpp b/apphandler.hpp
+index d4dd8e8..f9e5c59 100644
+--- a/apphandler.hpp
++++ b/apphandler.hpp
+@@ -19,6 +19,7 @@ enum ipmi_netfn_app_cmds
+ IPMI_CMD_SET_CHAN_ACCESS = 0x40,
+ IPMI_CMD_GET_CHANNEL_ACCESS = 0x41,
+ IPMI_CMD_GET_CHAN_INFO = 0x42,
++ IPMI_CMD_MASTER_WRITE_READ = 0x52,
+ IPMI_CMD_GET_CHAN_CIPHER_SUITES = 0x54,
+ IPMI_CMD_SET_SYSTEM_INFO = 0x58,
+ IPMI_CMD_GET_SYSTEM_INFO = 0x59,
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index c7eb2d8..22a2a3c 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -25,6 +25,7 @@
+ 0x06:0x36 //<App>:<Get BT Interface Capabilities>
+ 0x06:0x37 //<App>:<Get System GUID>
+ 0x06:0x42 //<App>:<Get Channel Info Command>
++0x06:0x52 //<App>:<Master Write Read Command>
+ 0x06:0x54 //<App>:<Get Channel Cipher Suites>
+ 0x0A:0x10 //<Storage>:<Get FRU Inventory Area Info>
+ 0x0A:0x11 //<Storage>:<Read FRU Data>
+--
+2.7.4
+