support reading System Firmware Version
This commit implements reading System Firmware Version as below steps:
- Find all object path that include xyz.openbmc_project.Software.Version
interface.
- Get the Purpose property of above object paths.
- If the Purpose is Host then get the Version property.
Tested:
1. Read system firmware version
$ipmitool mc getsysinfo system_fw_version
2. The version of firmware is shown
Change-Id: I84e25572253ddc7c2a48da9f6046920e55c8ccd4
Signed-off-by: Huy Le <hule@amperecomputing.com>
Signed-off-by: Thang Tran <thuutran@amperecomputing.com>
diff --git a/apphandler.cpp b/apphandler.cpp
index 0919cfb..9bad7ff 100644
--- a/apphandler.cpp
+++ b/apphandler.cpp
@@ -48,6 +48,7 @@
constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC";
constexpr auto bmc_state_property = "CurrentBMCState";
+constexpr auto versionPurposeHostEnd = ".Host";
static constexpr auto redundancyIntf =
"xyz.openbmc_project.Software.RedundancyPriority";
@@ -1292,6 +1293,58 @@
return ipmi::responseInvalidFieldRequest();
}
+std::optional<std::string> getSysFWVersion(ipmi::Context::ptr& ctx)
+{
+ /*
+ * The System Firmware version is detected via following steps:
+ * - Get all of object paths that include
+ * "xyz.openbmc_project.Software.Version" interface.
+ * - Get the Purpose property of above object paths.
+ * - If the Purpose is Host then get the Version property.
+ */
+ ipmi::ObjectTree objectTree;
+ boost::system::error_code ec =
+ ipmi::getAllDbusObjects(ctx, softwareRoot, versionIntf, objectTree);
+ if (ec.value())
+ {
+ return std::nullopt;
+ }
+
+ for (const auto& [objPath, serviceMap] : objectTree)
+ {
+ for (const auto& [service, intfs] : serviceMap)
+ {
+ ipmi::PropertyMap props;
+ ec = ipmi::getAllDbusProperties(ctx, service, objPath, versionIntf,
+ props);
+ if (ec.value())
+ {
+ continue;
+ }
+
+ std::string purposeProp = std::string(
+ ipmi::mappedVariant<std::string>(props, "Purpose", ""));
+
+ if (!purposeProp.ends_with(versionPurposeHostEnd))
+ {
+ continue;
+ }
+
+ std::string sysFWVersion = std::string(
+ ipmi::mappedVariant<std::string>(props, "Version", ""));
+
+ if (sysFWVersion.empty())
+ {
+ return std::nullopt;
+ }
+
+ return sysFWVersion;
+ }
+ }
+
+ return std::nullopt;
+}
+
static std::unique_ptr<SysInfoParamStore> sysInfoParamStore;
static std::string sysInfoReadSystemName()
@@ -1337,9 +1390,9 @@
ipmi::RspType<uint8_t, // Parameter revision
std::optional<uint8_t>, // data1 / setSelector / ProgressStatus
std::optional<std::vector<uint8_t>>> // data2-17
- ipmiAppGetSystemInfo(uint7_t reserved, bool getRevision,
- uint8_t paramSelector, uint8_t setSelector,
- uint8_t BlockSelector)
+ ipmiAppGetSystemInfo(ipmi::Context::ptr ctx, uint7_t reserved,
+ bool getRevision, uint8_t paramSelector,
+ uint8_t setSelector, uint8_t BlockSelector)
{
if (reserved || (paramSelector >= invalidParamSelectorStart &&
paramSelector <= invalidParamSelectorEnd))
@@ -1373,6 +1426,17 @@
sysInfoReadSystemName);
}
+ if (paramSelector == IPMI_SYSINFO_SYSTEM_FW_VERSION)
+ {
+ auto fwVersion = getSysFWVersion(ctx);
+
+ if (fwVersion == std::nullopt)
+ {
+ return ipmi::responseUnspecifiedError();
+ }
+ sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_FW_VERSION, *fwVersion);
+ }
+
// Parameters other than Set In Progress are assumed to be strings.
std::tuple<bool, std::string> ret =
sysInfoParamStore->lookup(paramSelector);