Add set/get Http boot option OEM commands
Set/get Http boot option is used to add a new boot item in reserved bits,
which set to 1101b in data 2nd[5:2] of boot flags parameter.
tested:
it's tested in system for IPMI OEM command and BIOS
- get/set http boot option,
set: ipmitool raw 0x30 0xEA 0x05 0x80 0x34
get: ipmitool raw 0x30 0xEB 0x05 0x00 0x00
Change-Id: Ie2927c924e233023b1644ce2e62e06003d55e0f2
Signed-off-by: Chen,Yugang <yugang.chen@linux.intel.com>
diff --git a/include/oemcommands.hpp b/include/oemcommands.hpp
index 9020498..95fc991 100644
--- a/include/oemcommands.hpp
+++ b/include/oemcommands.hpp
@@ -54,6 +54,8 @@
cmdGetBmcServiceStatus = 0xB2,
cmdMtmKeepAlive = 0xB5,
cmdGetNmiStatus = 0xE5,
+ cmdSetEfiBootOptions = 0xEA,
+ cmdGetEfiBootOptions = 0xEB,
cmdSetNmiStatus = 0xED,
};
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index 214f536..0b7c4ef 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -38,6 +38,8 @@
#include <string>
#include <variant>
#include <vector>
+#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
+#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
namespace ipmi
@@ -2762,6 +2764,247 @@
return ipmi::responseSuccess(resp);
}
+namespace boot_options
+{
+
+using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
+using IpmiValue = uint8_t;
+constexpr auto ipmiDefault = 0;
+
+std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
+ {0x01, Source::Sources::Network},
+ {0x02, Source::Sources::Disk},
+ {0x05, Source::Sources::ExternalMedia},
+ {0x0f, Source::Sources::RemovableMedia},
+ {ipmiDefault, Source::Sources::Default}};
+
+std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
+ {0x03, Mode::Modes::Safe},
+ {0x06, Mode::Modes::Setup},
+ {ipmiDefault, Mode::Modes::Regular}};
+
+std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
+ {Source::Sources::Network, 0x01},
+ {Source::Sources::Disk, 0x02},
+ {Source::Sources::ExternalMedia, 0x05},
+ {Source::Sources::RemovableMedia, 0x0f},
+ {Source::Sources::Default, ipmiDefault}};
+
+std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
+ {Mode::Modes::Safe, 0x03},
+ {Mode::Modes::Setup, 0x06},
+ {Mode::Modes::Regular, ipmiDefault}};
+
+static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
+static constexpr auto bootSourceIntf =
+ "xyz.openbmc_project.Control.Boot.Source";
+static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
+static constexpr auto persistentObjPath =
+ "/xyz/openbmc_project/control/host0/boot";
+static constexpr auto oneTimePath =
+ "/xyz/openbmc_project/control/host0/boot/one_time";
+static constexpr auto bootSourceProp = "BootSource";
+static constexpr auto bootModeProp = "BootMode";
+static constexpr auto oneTimeBootEnableProp = "Enabled";
+static constexpr auto httpBootMode =
+ "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
+
+enum class BootOptionParameter : size_t
+{
+ setInProgress = 0x0,
+ bootFlags = 0x5,
+};
+static constexpr uint8_t setComplete = 0x0;
+static constexpr uint8_t setInProgress = 0x1;
+static uint8_t transferStatus = setComplete;
+static constexpr uint8_t setParmVersion = 0x01;
+static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
+static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
+static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
+static constexpr uint8_t httpBoot = 0xd;
+static constexpr uint8_t bootSourceMask = 0x3c;
+
+} // namespace boot_options
+
+ipmi::RspType<uint8_t, // version
+ uint8_t, // param
+ uint8_t, // data0, dependent on parameter
+ std::optional<uint8_t> // data1, dependent on parameter
+ >
+ ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
+{
+ using namespace boot_options;
+ uint8_t bootOption = 0;
+
+ if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
+ {
+ return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
+ std::nullopt);
+ }
+
+ if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Unsupported parameter");
+ return ipmi::responseResponseError();
+ }
+
+ try
+ {
+ auto oneTimeEnabled = false;
+ // read one time Enabled property
+ std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
+ std::string service = getService(*dbus, enabledIntf, oneTimePath);
+ Value variant = getDbusProperty(*dbus, service, oneTimePath,
+ enabledIntf, oneTimeBootEnableProp);
+ oneTimeEnabled = std::get<bool>(variant);
+
+ // get BootSource and BootMode properties
+ // according to oneTimeEnable
+ auto bootObjPath = oneTimePath;
+ if (oneTimeEnabled == false)
+ {
+ bootObjPath = persistentObjPath;
+ }
+
+ service = getService(*dbus, bootModeIntf, bootObjPath);
+ variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
+ bootModeProp);
+
+ auto bootMode =
+ Mode::convertModesFromString(std::get<std::string>(variant));
+
+ service = getService(*dbus, bootSourceIntf, bootObjPath);
+ variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
+ bootSourceProp);
+
+ if (std::get<std::string>(variant) == httpBootMode)
+ {
+ bootOption = httpBoot;
+ }
+ else
+ {
+ auto bootSource = Source::convertSourcesFromString(
+ std::get<std::string>(variant));
+ bootOption = sourceDbusToIpmi.at(bootSource);
+ if (Source::Sources::Default == bootSource)
+ {
+ bootOption = modeDbusToIpmi.at(bootMode);
+ }
+ }
+
+ uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
+ : setParmBootFlagsValidPermanent;
+ bootOption <<= 2; // shift for responseconstexpr
+ return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
+ bootOption);
+ }
+ catch (sdbusplus::exception_t& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
+ return ipmi::responseResponseError();
+ }
+}
+
+ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
+ std::optional<uint8_t> bootOption)
+{
+ using namespace boot_options;
+ auto oneTimeEnabled = false;
+
+ if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
+ {
+ if (bootOption)
+ {
+ return ipmi::responseReqDataLenInvalid();
+ }
+
+ if (transferStatus == setInProgress)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "boot option set in progress!");
+ return ipmi::responseResponseError();
+ }
+
+ transferStatus = bootParam;
+ return ipmi::responseSuccess();
+ }
+
+ if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Unsupported parameter");
+ return ipmi::responseResponseError();
+ }
+
+ if (!bootOption)
+ {
+ return ipmi::responseReqDataLenInvalid();
+ }
+
+ if (((bootOption.value() & bootSourceMask) >> 2) !=
+ httpBoot) // not http boot, exit
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "wrong boot option parameter!");
+ return ipmi::responseParmOutOfRange();
+ }
+
+ try
+ {
+ bool permanent = (bootParam & setParmBootFlagsPermanent) ==
+ setParmBootFlagsPermanent;
+
+ // read one time Enabled property
+ std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
+ std::string service = getService(*dbus, enabledIntf, oneTimePath);
+ Value variant = getDbusProperty(*dbus, service, oneTimePath,
+ enabledIntf, oneTimeBootEnableProp);
+ oneTimeEnabled = std::get<bool>(variant);
+
+ /*
+ * Check if the current boot setting is onetime or permanent, if the
+ * request in the command is otherwise, then set the "Enabled"
+ * property in one_time object path to 'True' to indicate onetime
+ * and 'False' to indicate permanent.
+ *
+ * Once the onetime/permanent setting is applied, then the bootMode
+ * and bootSource is updated for the corresponding object.
+ */
+ if (permanent == oneTimeEnabled)
+ {
+ setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
+ oneTimeBootEnableProp, !permanent);
+ }
+
+ // set BootSource and BootMode properties
+ // according to oneTimeEnable or persistent
+ auto bootObjPath = oneTimePath;
+ if (oneTimeEnabled == false)
+ {
+ bootObjPath = persistentObjPath;
+ }
+ std::string bootMode =
+ "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
+ std::string bootSource = httpBootMode;
+
+ service = getService(*dbus, bootModeIntf, bootObjPath);
+ setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
+ bootMode);
+
+ service = getService(*dbus, bootSourceIntf, bootObjPath);
+ setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
+ bootSourceProp, bootSource);
+ }
+ catch (sdbusplus::exception_t& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
+ return ipmi::responseResponseError();
+ }
+
+ return ipmi::responseSuccess();
+}
+
static void registerOEMFunctions(void)
{
phosphor::logging::log<phosphor::logging::level::INFO>(
@@ -2910,6 +3153,18 @@
static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetNmiStatus),
ipmi::Privilege::Operator, ipmiOEMSetNmiSource);
+ ipmi::registerHandler(
+ ipmi::prioOemBase, netfnIntcOEMGeneral,
+ static_cast<ipmi::Cmd>(
+ IPMINetfnIntelOEMGeneralCmd::cmdGetEfiBootOptions),
+ ipmi::Privilege::User, ipmiOemGetEfiBootOptions);
+
+ ipmi::registerHandler(
+ ipmi::prioOemBase, netfnIntcOEMGeneral,
+ static_cast<ipmi::Cmd>(
+ IPMINetfnIntelOEMGeneralCmd::cmdSetEfiBootOptions),
+ ipmi::Privilege::Operator, ipmiOemSetEfiBootOptions);
+
ipmiPrintAndRegister(
netfnIntcOEMGeneral,
static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),