chassishandler: Add support for boot type flag (Legacy/EFI)
Add support for IPMI boot type field of a
"Get System Boot Options" сommand:
[1] - BIOS boot type (for BIOS that support both legacy and EFI boots)
0b = "PC compatible" boot (legacy)
1b = Extensible Firmware Interface Boot (EFI)
For the architectures that don't implement Legacy/EFI boot type
property (for example POWER), always return EFI boot type.
Signed-off-by: Konstantin Aladyshev <aladyshev22@gmail.com>
Change-Id: Ifc052b988af86f02a7665ed0477b364c243e9f71
diff --git a/chassishandler.cpp b/chassishandler.cpp
index 4a3252a..db513ab 100644
--- a/chassishandler.cpp
+++ b/chassishandler.cpp
@@ -30,6 +30,7 @@
#include <xyz/openbmc_project/Common/error.hpp>
#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
+#include <xyz/openbmc_project/Control/Boot/Type/server.hpp>
#include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
#include <xyz/openbmc_project/State/Host/server.hpp>
#include <xyz/openbmc_project/State/PowerOnHours/server.hpp>
@@ -39,9 +40,6 @@
static ChassisIDState chassisIDState = ChassisIDState::reserved;
static constexpr uint8_t setParmVersion = 0x01;
-static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
-static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
-static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
constexpr size_t sizeVersion = 2;
constexpr size_t DEFAULT_IDENTIFY_TIME_OUT = 15;
@@ -133,6 +131,7 @@
{
constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
+constexpr auto bootTypeIntf = "xyz.openbmc_project.Control.Boot.Type";
constexpr auto bootSourceIntf = "xyz.openbmc_project.Control.Boot.Source";
constexpr auto powerRestoreIntf =
"xyz.openbmc_project.Control.Power.RestorePolicy";
@@ -148,8 +147,8 @@
if (objectsPtr == nullptr)
{
objectsPtr = std::make_unique<settings::Objects>(
- dbus, std::vector<std::string>{bootModeIntf, bootSourceIntf,
- powerRestoreIntf});
+ dbus, std::vector<std::string>{bootModeIntf, bootTypeIntf,
+ bootSourceIntf, powerRestoreIntf});
}
return *objectsPtr;
}
@@ -1587,6 +1586,9 @@
using IpmiValue = uint8_t;
constexpr auto ipmiDefault = 0;
+std::map<IpmiValue, Type::Types> typeIpmiToDbus = {{0x00, Type::Types::Legacy},
+ {0x01, Type::Types::EFI}};
+
std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
{0x01, Source::Sources::Network},
{0x02, Source::Sources::Disk},
@@ -1601,6 +1603,9 @@
{0x06, Mode::Modes::Setup},
{ipmiDefault, Mode::Modes::Regular}};
+std::map<Type::Types, IpmiValue> typeDbusToIpmi = {{Type::Types::Legacy, 0x00},
+ {Type::Types::EFI, 0x01}};
+
std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
{Source::Sources::Network, 0x01},
{Source::Sources::Disk, 0x02},
@@ -1669,6 +1674,44 @@
return ipmi::ccSuccess;
}
+/** @brief Set the property value for boot type
+ * @param[in] type - boot type value
+ * @return On failure return IPMI error.
+ */
+static ipmi::Cc setBootType(const Type::Types& type)
+{
+ using namespace chassis::internal;
+ using namespace chassis::internal::cache;
+ std::variant<std::string> property = convertForMessage(type);
+ settings::Objects& objects = getObjects();
+ std::tuple<settings::Path, settings::boot::OneTimeEnabled> bootSetting;
+ try
+ {
+ bootSetting = settings::boot::setting(objects, bootTypeIntf);
+ }
+ catch (const std::exception& e)
+ {
+ // Return immediately if BootType interface is not present.
+ // This interface is not relevant for some Host architectures
+ // (for example POWER). In this case we don't won't IPMI to
+ // return an error, but want to just skip this function.
+ return ipmi::ccSuccess;
+ }
+ const auto& bootTypeSetting = std::get<settings::Path>(bootSetting);
+ auto method = dbus.new_method_call(
+ objects.service(bootTypeSetting, bootTypeIntf).c_str(),
+ bootTypeSetting.c_str(), ipmi::PROP_INTF, "Set");
+ method.append(bootTypeIntf, "BootType", property);
+ auto reply = dbus.call(method);
+ if (reply.is_method_error())
+ {
+ log<level::ERR>("Error in BootType Set");
+ report<InternalFailure>();
+ return ipmi::ccUnspecifiedError;
+ }
+ return ipmi::ccSuccess;
+}
+
static constexpr uint8_t setComplete = 0x0;
static constexpr uint8_t setInProgress = 0x1;
static uint8_t transferStatus = setComplete;
@@ -1758,6 +1801,45 @@
auto bootSource =
Source::convertSourcesFromString(std::get<std::string>(result));
+ Type::Types bootType;
+ bool bootTypeIntfPresent = true;
+ try
+ {
+ bootSetting = settings::boot::setting(objects, bootTypeIntf);
+ }
+ catch (const std::exception& e)
+ {
+ bootTypeIntfPresent = false;
+ }
+
+ if (bootTypeIntfPresent)
+ {
+ const auto& bootTypeSetting =
+ std::get<settings::Path>(bootSetting);
+ method = dbus.new_method_call(
+ objects.service(bootTypeSetting, bootTypeIntf).c_str(),
+ bootTypeSetting.c_str(), ipmi::PROP_INTF, "Get");
+ method.append(bootTypeIntf, "BootType");
+ reply = dbus.call(method);
+ if (reply.is_method_error())
+ {
+ log<level::ERR>(
+ "ipmiChassisGetSysBootOptions: Error in BootType Get");
+ report<InternalFailure>();
+ return ipmi::responseUnspecifiedError();
+ }
+ else
+ {
+ reply.read(result);
+ bootType = Type::convertTypesFromString(
+ std::get<std::string>(result));
+ }
+ }
+ else
+ {
+ bootType = Type::Types::EFI;
+ }
+
bootSetting = settings::boot::setting(objects, bootModeIntf);
const auto& bootModeSetting = std::get<settings::Path>(bootSetting);
method = dbus.new_method_call(
@@ -1787,12 +1869,14 @@
bootOption = modeDbusToIpmi.at(bootMode);
}
- uint8_t bootOptionParam = oneTimeEnabled
- ? setParmBootFlagsValidOneTime
- : setParmBootFlagsValidPermanent;
- response.pack(bootOptionParameter, reserved1, bootOptionParam,
- uint2_t{}, uint4_t{bootOption}, uint2_t{}, uint8_t{},
- uint8_t{}, uint8_t{});
+ IpmiValue biosBootType = typeDbusToIpmi.at(bootType);
+ uint1_t permanent = oneTimeEnabled ? 0 : 1;
+ uint1_t validFlag = 1;
+
+ response.pack(bootOptionParameter, reserved1, uint5_t{},
+ uint1_t{biosBootType}, uint1_t{permanent},
+ uint1_t{validFlag}, uint2_t{}, uint4_t{bootOption},
+ uint2_t{}, uint8_t{}, uint8_t{}, uint8_t{});
return ipmi::responseSuccess(std::move(response));
}
catch (InternalFailure& e)
@@ -1938,6 +2022,8 @@
auto modeItr =
modeIpmiToDbus.find(static_cast<uint8_t>(bootDeviceSelector));
+ auto typeItr =
+ typeIpmiToDbus.find(static_cast<uint8_t>(biosBootType));
auto sourceItr =
sourceIpmiToDbus.find(static_cast<uint8_t>(bootDeviceSelector));
if (sourceIpmiToDbus.end() != sourceItr)
@@ -1958,6 +2044,18 @@
setBootMode(Mode::Modes::Regular);
}
}
+
+ if (typeIpmiToDbus.end() != typeItr)
+ {
+ rc = setBootType(typeItr->second);
+ if (rc != ipmi::ccSuccess)
+ {
+ log<level::ERR>("ipmiChassisSetSysBootOptions: Error in "
+ "setting boot type");
+ return ipmi::responseUnspecifiedError();
+ }
+ }
+
if (modeIpmiToDbus.end() != modeItr)
{
rc = setBootMode(modeItr->second);
@@ -1977,6 +2075,7 @@
}
}
if ((modeIpmiToDbus.end() == modeItr) &&
+ (typeIpmiToDbus.end() == typeItr) &&
(sourceIpmiToDbus.end() == sourceItr))
{
// return error if boot option is not supported