summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apphandler.cpp264
-rw-r--r--apphandler.hpp1
-rw-r--r--host-ipmid-whitelist.conf2
3 files changed, 266 insertions, 1 deletions
diff --git a/apphandler.cpp b/apphandler.cpp
index ac06f50..370e0c3 100644
--- a/apphandler.cpp
+++ b/apphandler.cpp
@@ -29,6 +29,7 @@
#include <tuple>
#include <vector>
#include <xyz/openbmc_project/Common/error.hpp>
+#include <xyz/openbmc_project/Control/Power/ACPIPowerState/server.hpp>
#include <xyz/openbmc_project/Software/Activation/server.hpp>
#include <xyz/openbmc_project/Software/Version/server.hpp>
#include <xyz/openbmc_project/State/BMC/server.hpp>
@@ -179,16 +180,273 @@ bool getCurrentBmcState()
variant_ns::get<std::string>(variant)) == BMC::BMCState::Ready;
}
+namespace acpi_state
+{
+using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
+
+const static constexpr char* acpiObjPath =
+ "/xyz/openbmc_project/control/host0/acpi_power_state";
+const static constexpr char* acpiInterface =
+ "xyz.openbmc_project.Control.Power.ACPIPowerState";
+const static constexpr char* sysACPIProp = "SysACPIStatus";
+const static constexpr char* devACPIProp = "DevACPIStatus";
+
+enum class PowerStateType : uint8_t
+{
+ sysPowerState = 0x00,
+ devPowerState = 0x01,
+};
+
+// Defined in 20.6 of ipmi doc
+enum class PowerState : uint8_t
+{
+ s0G0D0 = 0x00,
+ s1D1 = 0x01,
+ s2D2 = 0x02,
+ s3D3 = 0x03,
+ s4 = 0x04,
+ s5G2 = 0x05,
+ s4S5 = 0x06,
+ g3 = 0x07,
+ sleep = 0x08,
+ g1Sleep = 0x09,
+ override = 0x0a,
+ legacyOn = 0x20,
+ legacyOff = 0x21,
+ unknown = 0x2a,
+ noChange = 0x7f,
+};
+
+static constexpr uint8_t stateChanged = 0x80;
+
+struct ACPIState
+{
+ uint8_t sysACPIState;
+ uint8_t devACPIState;
+} __attribute__((packed));
+
+std::map<ACPIPowerState::ACPI, PowerState> dbusToIPMI = {
+ {ACPIPowerState::ACPI::S0_G0_D0, PowerState::s0G0D0},
+ {ACPIPowerState::ACPI::S1_D1, PowerState::s1D1},
+ {ACPIPowerState::ACPI::S2_D2, PowerState::s2D2},
+ {ACPIPowerState::ACPI::S3_D3, PowerState::s3D3},
+ {ACPIPowerState::ACPI::S4, PowerState::s4},
+ {ACPIPowerState::ACPI::S5_G2, PowerState::s5G2},
+ {ACPIPowerState::ACPI::S4_S5, PowerState::s4S5},
+ {ACPIPowerState::ACPI::G3, PowerState::g3},
+ {ACPIPowerState::ACPI::SLEEP, PowerState::sleep},
+ {ACPIPowerState::ACPI::G1_SLEEP, PowerState::g1Sleep},
+ {ACPIPowerState::ACPI::OVERRIDE, PowerState::override},
+ {ACPIPowerState::ACPI::LEGACY_ON, PowerState::legacyOn},
+ {ACPIPowerState::ACPI::LEGACY_OFF, PowerState::legacyOff},
+ {ACPIPowerState::ACPI::Unknown, PowerState::unknown}};
+
+bool isValidACPIState(acpi_state::PowerStateType type, uint8_t state)
+{
+ if (type == acpi_state::PowerStateType::sysPowerState)
+ {
+ if ((state <= static_cast<uint8_t>(acpi_state::PowerState::override)) ||
+ (state == static_cast<uint8_t>(acpi_state::PowerState::legacyOn)) ||
+ (state ==
+ static_cast<uint8_t>(acpi_state::PowerState::legacyOff)) ||
+ (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
+ (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (type == acpi_state::PowerStateType::devPowerState)
+ {
+ if ((state <= static_cast<uint8_t>(acpi_state::PowerState::s3D3)) ||
+ (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
+ (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ return false;
+}
+} // namespace acpi_state
+
ipmi_ret_t ipmi_app_set_acpi_power_state(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)
{
+ auto s = static_cast<uint8_t>(acpi_state::PowerState::unknown);
ipmi_ret_t rc = IPMI_CC_OK;
+
+ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+
+ auto value = acpi_state::ACPIPowerState::ACPI::Unknown;
+
+ auto* req = reinterpret_cast<acpi_state::ACPIState*>(request);
+
+ if (*data_len != sizeof(acpi_state::ACPIState))
+ {
+ log<level::ERR>("set_acpi invalid len");
+ *data_len = 0;
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
*data_len = 0;
- log<level::DEBUG>("IPMI SET ACPI STATE Ignoring for now\n");
+ if (req->sysACPIState & acpi_state::stateChanged)
+ {
+ // set system power state
+ s = req->sysACPIState & ~acpi_state::stateChanged;
+
+ if (!acpi_state::isValidACPIState(
+ acpi_state::PowerStateType::sysPowerState, s))
+ {
+ log<level::ERR>("set_acpi_power sys invalid input",
+ entry("S=%x", s));
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ // valid input
+ if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
+ {
+ log<level::DEBUG>("No change for system power state");
+ }
+ else
+ {
+ auto found = std::find_if(
+ acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
+ [&s](const auto& iter) {
+ return (static_cast<uint8_t>(iter.second) == s);
+ });
+
+ value = found->first;
+
+ try
+ {
+ auto acpiObject =
+ ipmi::getDbusObject(bus, acpi_state::acpiInterface);
+ ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
+ acpi_state::acpiInterface,
+ acpi_state::sysACPIProp,
+ convertForMessage(value));
+ }
+ catch (const InternalFailure& e)
+ {
+ log<level::ERR>("Failed in set ACPI system property",
+ entry("EXCEPTION=%s", e.what()));
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ }
+ }
+ else
+ {
+ log<level::DEBUG>("Do not change system power state");
+ }
+
+ if (req->devACPIState & acpi_state::stateChanged)
+ {
+ // set device power state
+ s = req->devACPIState & ~acpi_state::stateChanged;
+ if (!acpi_state::isValidACPIState(
+ acpi_state::PowerStateType::devPowerState, s))
+ {
+ log<level::ERR>("set_acpi_power dev invalid input",
+ entry("S=%x", s));
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ // valid input
+ if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
+ {
+ log<level::DEBUG>("No change for device power state");
+ }
+ else
+ {
+ auto found = std::find_if(
+ acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
+ [&s](const auto& iter) {
+ return (static_cast<uint8_t>(iter.second) == s);
+ });
+
+ value = found->first;
+
+ try
+ {
+ auto acpiObject =
+ ipmi::getDbusObject(bus, acpi_state::acpiInterface);
+ ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
+ acpi_state::acpiInterface,
+ acpi_state::devACPIProp,
+ convertForMessage(value));
+ }
+ catch (const InternalFailure& e)
+ {
+ log<level::ERR>("Failed in set ACPI device property",
+ entry("EXCEPTION=%s", e.what()));
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ }
+ }
+ else
+ {
+ log<level::DEBUG>("Do not change device power state");
+ }
+
+ return rc;
+}
+
+ipmi_ret_t ipmi_app_get_acpi_power_state(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)
+{
+ ipmi_ret_t rc = IPMI_CC_OK;
+
+ auto* res = reinterpret_cast<acpi_state::ACPIState*>(response);
+
+ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+
+ *data_len = 0;
+
+ try
+ {
+ auto acpiObject = ipmi::getDbusObject(bus, acpi_state::acpiInterface);
+
+ auto sysACPIVal = ipmi::getDbusProperty(
+ bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
+ acpi_state::sysACPIProp);
+ auto sysACPI = acpi_state::ACPIPowerState::convertACPIFromString(
+ sysACPIVal.get<std::string>());
+ res->sysACPIState =
+ static_cast<uint8_t>(acpi_state::dbusToIPMI.at(sysACPI));
+
+ auto devACPIVal = ipmi::getDbusProperty(
+ bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
+ acpi_state::devACPIProp);
+ auto devACPI = acpi_state::ACPIPowerState::convertACPIFromString(
+ devACPIVal.get<std::string>());
+ res->devACPIState =
+ static_cast<uint8_t>(acpi_state::dbusToIPMI.at(devACPI));
+
+ *data_len = sizeof(acpi_state::ACPIState);
+ }
+ catch (const InternalFailure& e)
+ {
+ log<level::ERR>("Failed in get ACPI property");
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
return rc;
}
@@ -860,6 +1118,10 @@ void register_netfn_app_functions()
ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_ACPI, NULL,
ipmi_app_set_acpi_power_state, PRIVILEGE_ADMIN);
+ // <Get ACPI Power State>
+ ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_ACPI, NULL,
+ ipmi_app_get_acpi_power_state, PRIVILEGE_ADMIN);
+
// <Get Channel Access>
ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL,
ipmi_get_channel_access, PRIVILEGE_USER);
diff --git a/apphandler.hpp b/apphandler.hpp
index 3d377fb..d4dd8e8 100644
--- a/apphandler.hpp
+++ b/apphandler.hpp
@@ -9,6 +9,7 @@ enum ipmi_netfn_app_cmds
IPMI_CMD_GET_DEVICE_ID = 0x01,
IPMI_CMD_GET_SELF_TEST_RESULTS = 0x04,
IPMI_CMD_SET_ACPI = 0x06,
+ IPMI_CMD_GET_ACPI = 0x07,
IPMI_CMD_GET_DEVICE_GUID = 0x08,
IPMI_CMD_RESET_WD = 0x22,
IPMI_CMD_SET_WD = 0x24,
diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
index 2c37ac9..9dff10a 100644
--- a/host-ipmid-whitelist.conf
+++ b/host-ipmid-whitelist.conf
@@ -11,6 +11,8 @@
0x04:0x30 //<Sensor/Event>:<Set Sensor Reading and Event Status>
0x06:0x01 //<App>:<Get Device ID>
0x06:0x04 //<App>:<Get Self Test Results>
+0x06:0x06 //<App>:<Set ACPI Power State>
+0x06:0x07 //<App>:<Get ACPI Power State>
0x06:0x08 //<App>:<Get Device GUID>
0x06:0x22 //<App>:<Reset Watchdog Timer>
0x06:0x24 //<App>:<Set Watchdog Timer>
OpenPOWER on IntegriCloud