Override Set Boot option command
Safe boot mode is not supported in INTEL platforms, so, it's needed
to override the Set Boot Options IPMI command in INTEL OEM command
by removing the safe mode item.
Tested:
ipmitool raw 0x00 0x08 0x05 0x80 0x0c
return 0xcc to indicate Invalid data field in request.
Change-Id: I9539c2e0ead3edb97799f63a5c1d4109c2ef3754
Signed-off-by: Chen Yugang <yugang.chen@linux.intel.com>
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index 0a152b0..d360b2b 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -2930,9 +2930,7 @@
{ipmiDefault, Source::Sources::Default}};
std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
- {0x03, Mode::Modes::Safe},
- {0x06, Mode::Modes::Setup},
- {ipmiDefault, Mode::Modes::Regular}};
+ {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
{Source::Sources::Network, 0x01},
@@ -2942,9 +2940,7 @@
{Source::Sources::Default, ipmiDefault}};
std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
- {Mode::Modes::Safe, 0x03},
- {Mode::Modes::Setup, 0x06},
- {Mode::Modes::Regular, ipmiDefault}};
+ {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
static constexpr auto bootSourceIntf =
@@ -3156,6 +3152,126 @@
return ipmi::responseSuccess();
}
+ipmi::RspType<> ipmiOemSetBootOptions(uint8_t bootFlag, uint8_t bootParam,
+ std::optional<uint8_t> bootOption)
+{
+ bool oneTimeEnabled = false;
+ uint8_t bootOptionValue = 0;
+ static constexpr const uint8_t shiftBits = 2;
+
+ if (bootFlag ==
+ static_cast<uint8_t>(boot_options::BootOptionParameter::setInProgress))
+ {
+ if (bootOption)
+ {
+ return ipmi::responseReqDataLenInvalid();
+ }
+
+ if (boot_options::transferStatus == boot_options::setInProgress)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "boot option set in progress!");
+ return ipmi::responseResponseError();
+ }
+
+ boot_options::transferStatus = bootParam;
+ return ipmi::responseSuccess();
+ }
+
+ if (bootFlag !=
+ static_cast<uint8_t>(boot_options::BootOptionParameter::bootFlags))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Unsupported parameter");
+ return ipmi::responseResponseError();
+ }
+
+ if (!bootOption)
+ {
+ return ipmi::responseReqDataLenInvalid();
+ }
+ bootOptionValue =
+ (bootOption.value() & boot_options::bootSourceMask) >> shiftBits;
+
+ try
+ {
+ bool permanent =
+ (bootParam & boot_options::setParmBootFlagsPermanent) ==
+ boot_options::setParmBootFlagsPermanent;
+ auto bootMode = boot_options::Mode::Modes::Regular;
+ auto bootSource = boot_options::Source::Sources::Default;
+
+ // read one time Enabled property
+ std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
+ std::string service = getService(*dbus, boot_options::enabledIntf,
+ boot_options::oneTimePath);
+ Value variant = getDbusProperty(
+ *dbus, service, boot_options::oneTimePath,
+ boot_options::enabledIntf, boot_options::oneTimeBootEnableProp);
+ oneTimeEnabled = std::get_if<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, boot_options::oneTimePath,
+ boot_options::enabledIntf,
+ boot_options::oneTimeBootEnableProp, !permanent);
+ }
+
+ // set BootSource and BootMode properties
+ // according to oneTimeEnable or persistent
+ auto bootObjPath = boot_options::oneTimePath;
+ if (oneTimeEnabled == false)
+ {
+ bootObjPath = boot_options::persistentObjPath;
+ }
+
+ auto modeItr = boot_options::modeIpmiToDbus.find(bootOptionValue);
+ auto sourceItr = boot_options::sourceIpmiToDbus.find(bootOptionValue);
+
+ if (boot_options::sourceIpmiToDbus.end() != sourceItr)
+ {
+ bootSource = sourceItr->second;
+ }
+
+ if (boot_options::modeIpmiToDbus.end() != modeItr)
+ {
+ bootMode = modeItr->second;
+ }
+
+ if ((boot_options::modeIpmiToDbus.end() == modeItr) &&
+ (boot_options::sourceIpmiToDbus.end() == sourceItr))
+ {
+ // return error if boot option is not supported
+ return ipmi::responseInvalidFieldRequest();
+ }
+ service = getService(*dbus, boot_options::bootModeIntf, bootObjPath);
+ setDbusProperty(*dbus, service, bootObjPath, boot_options::bootModeIntf,
+ boot_options::bootModeProp,
+ convertForMessage(bootMode));
+
+ service = getService(*dbus, boot_options::bootSourceIntf, bootObjPath);
+ setDbusProperty(
+ *dbus, service, bootObjPath, boot_options::bootSourceIntf,
+ boot_options::bootSourceProp, convertForMessage(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>(
@@ -3365,6 +3481,10 @@
ipmi::prioOemBase, netfnIntcOEMGeneral,
static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetDimmOffset),
ipmi::Privilege::Operator, ipmiOEMGetDimmOffset);
+
+ ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
+ ipmi::chassis::cmdSetSystemBootOptions,
+ ipmi::Privilege::Operator, ipmiOemSetBootOptions);
}
} // namespace ipmi