OEM command SendFwUpdateStatus
It is used by BIOS/ME to report firmware update status.
Orignal implement uses OEM SEL. In openbmc, OEM SEL is no longer
supported. We use redfish visiable logging instead.
Tested:
1.ipmitool xxx raw 0x30 0x44 0x0 0x10 0x1 0x2 0x30 0x31 0x32 0x33
2. check 'journal -ef -overbose'
expect message with tag 'REDFISH_MESSAGE_ID' is observed
3. check redfish interface
/redfish/v1/Systems/system/LogServices/EventLog/Entries/
expect entries match what we create
Change-Id: I8746e9250bcfb4d8c4a905a1ccaedcc7efab2f51
Signed-off-by: Jia, chunhui <chunhui.jia@linux.intel.com>
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/include/oemcommands.hpp b/include/oemcommands.hpp
index cd51038..3255da1 100644
--- a/include/oemcommands.hpp
+++ b/include/oemcommands.hpp
@@ -22,6 +22,7 @@
cmdGetOEMDeviceInfo = 0x27,
cmdGetAICSlotFRUIDSlotPosRecords = 0x31,
cmdSetSystemGUID = 0x41,
+ cmdSendEmbeddedFWUpdStatus = 0x44,
cmdSetPowerRestoreDelay = 0x54,
cmdGetPowerRestoreDelay = 0x55,
cmdSetShutdownPolicy = 0x60,
@@ -143,6 +144,12 @@
// 3: host serial port 1 and 2 high speed
static constexpr const uint8_t HostSerialCfgParamMax = 3;
+static constexpr const uint8_t selEvtTargetMask = 0xF0;
+static constexpr const uint8_t selEvtTargetShift = 4;
+
+static constexpr const uint8_t targetInstanceMask = 0x0E;
+static constexpr const uint8_t targetInstanceShift = 1;
+
enum class IPMINetfnIntelOEMAppCmd
{
mdrStatus = 0x20,
@@ -172,6 +179,14 @@
sdrVer,
};
+enum class FWUpdateTarget : uint8_t
+{
+ targetBMC = 0x0,
+ targetBIOS = 0x1,
+ targetME = 0x2,
+ targetOEMEWS = 0x4,
+};
+
#pragma pack(push, 1)
struct GUIDData
{
@@ -308,4 +323,4 @@
pwmOffset = 0x2,
maxPwm = 0x3,
cfm = 0x4
-};
\ No newline at end of file
+};
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index dfd4985..2f46f13 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -18,6 +18,7 @@
#include "xyz/openbmc_project/Led/Physical/server.hpp"
#include <ipmid/api.h>
+#include <systemd/sd-journal.h>
#include <array>
#include <boost/container/flat_map.hpp>
@@ -25,6 +26,8 @@
#include <boost/process/io.hpp>
#include <commandutils.hpp>
#include <iostream>
+#include <ipmid/api.hpp>
+#include <ipmid/registration.hpp>
#include <ipmid/utils.hpp>
#include <oemcommands.hpp>
#include <phosphor-logging/log.hpp>
@@ -306,6 +309,103 @@
return IPMI_CC_OK;
}
+static uint8_t bcdToDec(uint8_t val)
+{
+ return ((val / 16 * 10) + (val % 16));
+}
+
+// Allows an update utility or system BIOS to send the status of an embedded
+// firmware update attempt to the BMC. After received, BMC will create a logging
+// record.
+ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
+ uint8_t majorRevision,
+ uint8_t minorRevision,
+ uint32_t auxInfo)
+{
+ std::string firmware;
+ target = (target & selEvtTargetMask) >> selEvtTargetShift;
+
+ /* make sure the status is 0, 1, or 2 as per the spec */
+ if (status > 2)
+ {
+ return ipmi::response(ipmi::ccInvalidFieldRequest);
+ }
+ /*orignal OEM command is to record OEM SEL.
+ But openbmc does not support OEM SEL, so we redirect it to redfish event
+ logging. */
+ std::string buildInfo;
+ std::string action;
+ switch (FWUpdateTarget(target))
+ {
+ case FWUpdateTarget::targetBMC:
+ firmware = "BMC";
+ buildInfo = " major: " + std::to_string(majorRevision) +
+ " minor: " +
+ std::to_string(bcdToDec(minorRevision)) + // BCD encoded
+ " BuildID: " + std::to_string(auxInfo);
+ buildInfo += std::to_string(auxInfo);
+ break;
+ case FWUpdateTarget::targetBIOS:
+ firmware = "BIOS";
+ buildInfo =
+ " major: " +
+ std::to_string(bcdToDec(majorRevision)) + // BCD encoded
+ " minor: " +
+ std::to_string(bcdToDec(minorRevision)) + // BCD encoded
+ " ReleaseNumber: " + // ASCII encoded
+ std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
+ std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
+ std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
+ std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
+ break;
+ case FWUpdateTarget::targetME:
+ firmware = "ME";
+ buildInfo =
+ " major: " + std::to_string(majorRevision) + " minor1: " +
+ std::to_string(bcdToDec(minorRevision)) + // BCD encoded
+ " minor2: " +
+ std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
+ " build1: " +
+ std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
+ " build2: " +
+ std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
+ break;
+ case FWUpdateTarget::targetOEMEWS:
+ firmware = "EWS";
+ buildInfo = " major: " + std::to_string(majorRevision) +
+ " minor: " +
+ std::to_string(bcdToDec(minorRevision)) + // BCD encoded
+ " BuildID: " + std::to_string(auxInfo);
+ break;
+ }
+
+ switch (status)
+ {
+ case 0x0:
+ action = "update started";
+ break;
+ case 0x1:
+ action = "update completed successfully";
+ break;
+ case 0x2:
+ action = "update failure";
+ break;
+ default:
+ action = "unknown";
+ break;
+ }
+
+ std::string message(
+ "[firmware update] " + firmware + " instance: " +
+ std::to_string((target & targetInstanceMask) >> targetInstanceShift) +
+ " status: <" + action + ">" + buildInfo);
+ static constexpr const char* redfishMsgId = "FirmwareUpdate";
+
+ sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
+ "REDFISH_MESSAGE_ID=%s", redfishMsgId, NULL);
+ return ipmi::responseSuccess();
+}
+
ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request,
ipmi_response_t response,
@@ -1132,6 +1232,13 @@
static_cast<ipmi_cmd_t>(
IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
+
+ ipmi::registerHandler(
+ ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
+ static_cast<ipmi::Cmd>(
+ IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus),
+ ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
+
ipmiPrintAndRegister(
netfnIntcOEMGeneral,
static_cast<ipmi_cmd_t>(