#include #include #include #include constexpr auto sbmrBootStateIntf = "xyz.openbmc_project.State.Boot.Raw"; constexpr auto sbmrHostStateIntf = "xyz.openbmc_project.State.Boot.Progress"; constexpr auto sbmrBootProgressCodeSize = 9; constexpr auto bootProgressOem = "OEM"; constexpr auto bootProgressOsRuning = "OSRunning"; constexpr auto bootProgressOsStart = "OSStart"; constexpr auto bootProgressPciInit = "PCIInit"; constexpr auto bootProgressSystemInitComplete = "SystemInitComplete"; constexpr auto bootProgressSystemSetup = "SystemSetup"; // EFI_STATUS_CODE_TYPE constexpr auto efiProgressCode = 0x01; constexpr auto efiCodeSeverityNone = 0; // EFI_STATUS_CODE_CLASS constexpr auto efiIoBus = 0x02; constexpr auto efiSoftware = 0x03; // EFI_STATUS_CODE_SUBCLASS constexpr auto efiIoBusPci = 0x01; constexpr auto efiSoftwareDxeCore = 0x04; constexpr auto efiSoftwareDxeBsDriver = 0x05; constexpr auto efiSoftwareEfiBootService = 0x10; // EFI_STATUS_CODE_OPERATION constexpr auto efiIoBusPciResAlloc = 0x0110; constexpr auto efiSwDxeCorePcHandoffToNext = 0x0110; constexpr auto efiSwPcUserSetup = 0x0700; constexpr auto efiSwOsLoaderStart = 0x0180; constexpr auto efiSwBsPcExitBootServices = 0x1910; void registerNetfnSBMRFunctions() __attribute__((constructor)); namespace ipmi { std::string getSbmrBootProgressStage(uint8_t codeType, uint8_t codeSeverity, uint8_t codeClass, uint8_t codeSubClass, uint16_t codeOperation) { // Return OEM if code type or severity are unexpected if (codeType != efiProgressCode || codeSeverity != efiCodeSeverityNone) { return bootProgressOem; } // Code Class Software if (codeClass == efiSoftware) { if (codeSubClass == efiSoftwareDxeCore && codeOperation == efiSwDxeCorePcHandoffToNext) { return bootProgressSystemInitComplete; } else if (codeSubClass == efiSoftwareDxeBsDriver && codeOperation == efiSwPcUserSetup) { return bootProgressSystemSetup; } else if (codeSubClass == efiSoftwareDxeBsDriver && codeOperation == efiSwOsLoaderStart) { return bootProgressOsStart; } else if (codeSubClass == efiSoftwareEfiBootService && codeOperation == efiSwBsPcExitBootServices) { return bootProgressOsRuning; } } // Code Class IO Bus else if (codeClass == efiIoBus) { if (codeSubClass == efiIoBusPci && codeOperation == efiIoBusPciResAlloc) { return bootProgressPciInit; } } // Fallback to OEM if no conditions met return bootProgressOem; } bool updateBootProgressProperty(ipmi::Context::ptr& ctx, const std::string& value) { std::string bootProgress = "xyz.openbmc_project.State.Boot.Progress.ProgressStages." + value; ipmi::DbusObjectInfo sbmrHostStateObject{}; /* Get Host State Object */ boost::system::error_code ec = ipmi::getDbusObject(ctx, sbmrHostStateIntf, sbmrHostStateObject); if (ec.value()) { lg2::error("Failed to get Host State object, Error={ERROR}", "ERROR", ec.message()); return false; } /* Set Host State property */ ec = ipmi::setDbusProperty(ctx, sbmrHostStateObject.second, sbmrHostStateObject.first, sbmrHostStateIntf, "BootProgress", bootProgress); if (ec.value()) { lg2::error( "updateBootProgressProperty, can't set progerty - Error={ERROR}", "ERROR", ec.message()); return false; } return true; } bool updateBootProgressLastUpdateProperty(ipmi::Context::ptr& ctx, uint64_t timeStamp) { ipmi::DbusObjectInfo sbmrHostStateObject{}; /* Get Host State Object */ boost::system::error_code ec = ipmi::getDbusObject(ctx, sbmrHostStateIntf, sbmrHostStateObject); if (ec.value()) { lg2::error("Failed to get Host State object, Error={ERROR}", "ERROR", ec.message()); return false; } /* Set Host State property */ ec = ipmi::setDbusProperty(ctx, sbmrHostStateObject.second, sbmrHostStateObject.first, sbmrHostStateIntf, "BootProgressLastUpdate", timeStamp); if (ec.value()) { lg2::error( "updateBootProgressLastUpdateProperty, can't set property - Error={ERROR}", "ERROR", ec.message()); return false; } return true; } ipmi::RspType<> sendBootProgressCode( ipmi::Context::ptr ctx, uint8_t codeType, uint8_t codeReserved1, uint8_t codeReserved2, uint8_t codeSeverity, uint8_t codeOperation1, uint8_t codeOperation2, uint8_t codeSubClass, uint8_t codeClass, uint8_t instance) { /* Update boot progress code to Dbus property */ ipmi::DbusObjectInfo sbmrBootStateObject{}; /* Get Boot State Object */ boost::system::error_code ec = ipmi::getDbusObject(ctx, sbmrBootStateIntf, sbmrBootStateObject); if (ec.value()) { lg2::error("Failed to get Boot State object, Error={ERROR}", "ERROR", ec.message()); return ipmi::responseUnspecifiedError(); } /* Set Boot State property */ BootProgressCode bpCode( {codeType, codeReserved1, codeReserved2, codeSeverity, codeOperation1, codeOperation2, codeSubClass, codeClass, instance}, {}); ec = ipmi::setDbusProperty(ctx, sbmrBootStateObject.second, sbmrBootStateObject.first, sbmrBootStateIntf, "Value", bpCode); if (ec.value()) { lg2::error("Failed to set boot progress code, Error={ERROR}", "ERROR", ec.message()); return ipmi::responseUnspecifiedError(); } /* Update Redfish BootProgress object */ auto timeStamp = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); if (!updateBootProgressLastUpdateProperty(ctx, timeStamp)) { return ipmi::responseUnspecifiedError(); } /* Chek for BootProgressTypes */ uint16_t codeOperation = static_cast(codeOperation1) << 8 | codeOperation2; std::string stage = getSbmrBootProgressStage( codeType, codeSeverity, codeClass, codeSubClass, codeOperation); if (!updateBootProgressProperty(ctx, stage)) { return ipmi::responseUnspecifiedError(); } return ipmi::responseSuccess(); } ipmi::RspType // Instance getBootProgressCode(ipmi::Context::ptr ctx) { ipmi::DbusObjectInfo sbmrBootStateObject{}; /* Get Boot State Object */ boost::system::error_code ec = ipmi::getDbusObject(ctx, sbmrBootStateIntf, sbmrBootStateObject); if (ec.value()) { lg2::error("Failed to get Boot State object, Error={ERROR}", "ERROR", ec.message()); return ipmi::responseUnspecifiedError(); } /* Get Boot State property */ BootProgressCode value; ec = ipmi::getDbusProperty(ctx, sbmrBootStateObject.second, sbmrBootStateObject.first, sbmrBootStateIntf, "Value", value); if (ec.value()) { lg2::error("Can't get property Value, Error={ERROR}", "ERROR", ec.message()); return ipmi::responseUnspecifiedError(); } auto respBootProgressCode = std::get<0>(std::move(value)); if (respBootProgressCode.size() != sbmrBootProgressCodeSize) { return ipmi::responseUnspecifiedError(); } return ipmi::responseSuccess( respBootProgressCode[0], respBootProgressCode[1], respBootProgressCode[2], respBootProgressCode[3], respBootProgressCode[4], respBootProgressCode[5], respBootProgressCode[6], respBootProgressCode[7], respBootProgressCode[8]); } bool checkAllowedMediumType(uint8_t mediumType) { if (mediumType == static_cast(ipmi::EChannelMediumType::smbusV20) || mediumType == static_cast(ipmi::EChannelMediumType::systemInterface) || mediumType == static_cast(ipmi::EChannelMediumType::oem)) { return true; } return false; } ipmi::Cc sbmrFilterCommands(ipmi::message::Request::ptr request) { if (request->ctx->netFn != ipmi::netFnGroup || request->ctx->group != ipmi::groupSBMR) { // Skip if not group SBMR return ipmi::ccSuccess; } ipmi::ChannelInfo chInfo; if (ipmi::getChannelInfo(request->ctx->channel, chInfo) != ipmi::ccSuccess) { lg2::error("Failed to get Channel Info, channel={CHANNEL}", "CHANNEL", request->ctx->channel); return ipmi::ccUnspecifiedError; } if (request->ctx->cmd == ipmi::sbmr::cmdSendBootProgressCode && !checkAllowedMediumType(chInfo.mediumType)) { lg2::error("Error - Medium interface not supported, medium={TYPE}", "TYPE", chInfo.mediumType); return ipmi::ccCommandNotAvailable; } return ipmi::ccSuccess; } } // namespace ipmi void registerNetfnSBMRFunctions() { registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupSBMR, ipmi::sbmr::cmdSendBootProgressCode, ipmi::Privilege::Admin, ipmi::sendBootProgressCode); registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupSBMR, ipmi::sbmr::cmdGetBootProgressCode, ipmi::Privilege::User, ipmi::getBootProgressCode); ipmi::registerFilter(ipmi::prioOemBase, [](ipmi::message::Request::ptr request) { return ipmi::sbmrFilterCommands(request); }); }