diff options
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.patch | 322 |
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 + |