diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig')
7 files changed, 2277 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch new file mode 100644 index 000000000..409a2af3f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0001-Define-Redfish-interface-Registries-Bios.patch @@ -0,0 +1,874 @@ +From 8b21bce7fa0974c454e4bed539be0475738ee21e Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Fri, 4 Sep 2020 19:24:25 +0800 +Subject: [PATCH] Define Redfish interface "/Registries/Bios" and enable + Attributes property + +1. Define Redfish interface "/Registries/Bios" for BIOS Attribute Registry + RBC Daemon provide method to get BIOS attribute registry. +2. Eanble Attributes property for BIOS resource +3. Define Redfish interface "/Systems/system/Bios/Settings" for BIOS +settings +4. RBC daemon is at +https://gerrit.openbmc-project.xyz/#/c/openbmc/bios-settings-mgr/+/35563/ +5. IPMI command implementation is at +https://gerrit.openbmc-project.xyz/#/c/openbmc/intel-ipmi-oem/+/30827/ +6. Property design is at +https://github.com/openbmc/phosphor-dbus-interfaces/tree/master/xyz/openbmc_project/BIOSConfig +7. Design doc is at +https://github.com/openbmc/docs/blob/master/designs/remote-bios-configuration.md +8. There will be 95 test cases for this feature in the validation team. + +Tested: + +1. Use postman (Redfish tool) could get all the attributes in bios +resouce, get bios settings, get bios attribute +registry. +https://IP_ADDR/redfish/v1/Systems/system/Bios +{ + "@Redfish.Settings": { + "@odata.type": "#Settings.v1_3_0.Settings", + "SettingsObject": { + "@odata.id": "/redfish/v1/Systems/system/Bios/Settings" + } + }, + "@odata.id": "/redfish/v1/Systems/system/Bios", + "@odata.type": "#Bios.v1_1_0.Bios", + "Actions": { + "#Bios.ChangePassword": { + "target": "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword" + }, + "#Bios.ResetBios": { + "target": "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios" + } + }, + "AttributeRegistry": "BiosAttributeRegistry", + "Attributes": { + "attr0": "current value" + }, + "Description": "BIOS Configuration Service", + "Id": "BIOS", + "Links": { + "ActiveSoftwareImage": { + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bios_active" + }, + "SoftwareImages": [ + { + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bios_active" + } + ], + "SoftwareImages@odata.count": 1 + }, + "Name": "BIOS Configuration" +} + +Redfish interface: https://BMCIP/redfish/v1/Registries/BiosAttributeRegistry +{ + "@odata.id": "/redfish/v1/Registries/BiosAttributeRegistry", + "@odata.type": "#MessageRegistryFile.v1_1_0.MessageRegistryFile", + "Description": "BiosAttributeRegistry Message Registry File Location", + "Id": "BiosAttributeRegistry", + "Languages": [ + "en" + ], + "Languages@odata.count": 1, + "Location": [ + { + "Language": "en", + "Uri": "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry" + } + ], + "Location@odata.count": 1, + "Name": "BiosAttributeRegistry Message Registry File", + "Registry": "BiosAttributeRegistry.1.0.0" +} + +Redfish interface: https://BMCIP/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry +{ + "@odata.id": "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry", + "@odata.type": "#AttributeRegistry.v1_3_2.AttributeRegistry", + "Id": "BiosAttributeRegistry", + "Language": "en", + "Name": "Bios Attribute Registry", + "OwningEntity": "OpenBMC", + "RegistryEntries": { + "Attributes": [ + { + "AttributeName": "attr0", + "CurrentValue": "current value", + "DefaultValue": "default value", + "DisplayName": "display name for attr0", + "HelpText": "description for attr0", + "MenuPath": "./menu/path/for/attr0", + "ReadOnly": false, + "Type": "String", + "Value": [] + } + ] + }, + "RegistryVersion": "1.0.0" +} + +https://BMC_IPADDR/redfish/v1/Systems/system/Bios/Settings +{ + "@odata.id": "/redfish/v1/Systems/system/Bios/Settings", + "@odata.type": "#Bios.v1_1_0.Bios", + "AttributeRegistry": "BiosAttributeRegistry", + "Attributes": { + "QuietBoot": "0x0" + }, + "Id": "BiosSettingsV1", + "Name": "Bios Settings Version 1" +} + +2. Passed Validator check for bios resource and bios attribute registry +*** /redfish/v1/Systems/system/Bios +INFO - Type (#Bios.v1_1_0.Bios), GET SUCCESS (time: 1.57377) +INFO - PASS +*** /redfish/v1/Registries/BiosAttributeRegistry +INFO - Type (#MessageRegistryFile.v1_1_0.MessageRegistryFile), GET SUCCESS (time: 0.075438) +INFO - PASS +INFO - +*** /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry +INFO - Type (#AttributeRegistry.v1_3_2.AttributeRegistry), GET SUCCESS (time: 0.075751) +INFO - PASS + +@odata.id /redfish/v1/Systems/system/Bios odata Exists PASS +@odata.type #Settings.v1_3_0.Settings odata Exists PASS +Links [JSON Object] Bios.v1_1_0.Links Yes complex +Links.ActiveSoftwareImage Link: /redfish/v1/UpdateService/FirmwareInventory/bios_active link to: SoftwareInventory Yes PASS +Links.SoftwareImages Array (size: 1) array of: SoftwareInventory Yes ... +Links.SoftwareImages[0] Link: /redfish/v1/UpdateService/FirmwareInventory/bios_active SoftwareInventory Yes PASS +Links.Oem - Resource.Oem No Optional +SoftwareImages@odata.count 1 odata Exists PASS +AttributeRegistry BiosAttributeRegistry string Yes PASS +Actions [JSON Object] Bios.v1_0_0.Actions Yes complex +Actions.#Bios.ResetBios Action - Yes PASS +Actions.#Bios.ChangePassword Action - Yes PASS +Attributes [JSON Object] Bios.v1_0_0.Attributes Yes complex +Attributes.attr0 current value primitive Yes PASS +Id BIOS string Yes PASS +Description BIOS Configuration Service string Yes PASS +Name BIOS Configuration string Yes PASS +Oem - Resource.Oem No Optional +@Redfish.Settings [JSON Object] Settings.Settings Yes complex +@Redfish.Settings.MaintenanceWindowResource - link to: ItemOrCollection No Optional +@Redfish.Settings.SupportedApplyTimes - string (enum) No Optional +@Redfish.Settings.Time - date No Optional +@Redfish.Settings.ETag - string No Optional +@Redfish.Settings.SettingsObject Link: /redfish/v1/Systems/system/Bios/Settings link to: Item Yes PASS +@Redfish.Settings.Messages - Message No Optional + +@odata.id /redfish/v1/Registries/BiosAttributeRegistry odata Exists PASS +@odata.type #MessageRegistryFile.v1_1_0.MessageRegistryFile odata Exists PASS +Languages@odata.count 1 odata Exists PASS +Location@odata.count 1 odata Exists PASS +Actions - MessageRegistryFile.v1_1_0.Actions No Optional +Languages Array (size: 1) string Yes ... +Languages[0] en string Yes PASS +Registry BiosAttributeRegistry.1.0.0 string Yes PASS +Location Array (size: 1) array of: Location Yes ... +Location[0] [JSON Object] Location Yes complex +Location[0].Language en string Yes PASS +Location[0].Uri /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry string Yes PASS +Location[0].ArchiveUri - string No Optional +Location[0].PublicationUri - string No Optional +Location[0].ArchiveFile - string No Optional +Id BiosAttributeRegistry string Yes PASS +Description BiosAttributeRegistry Message Registry File Location string Yes PASS +Name BiosAttributeRegistry Message Registry File string Yes PASS +Oem - Resource.Oem No Optional + +@odata.id /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry odata Exists PASS +@odata.type #AttributeRegistry.v1_3_2.AttributeRegistry odata Exists PASS +Actions - AttributeRegistry.v1_1_0.Actions No Optional +Language en string Yes PASS +RegistryVersion 1.0.0 string Yes PASS +OwningEntity OpenBMC string Yes PASS +SupportedSystems - SupportedSystems No Optional +RegistryEntries [JSON Object] AttributeRegistry.v1_0_0.RegistryEntries Yes complex +RegistryEntries.Attributes Array (size: 1) array of: Attributes Yes ... +RegistryEntries.Attributes[0] [JSON Object] Attributes Yes complex +RegistryEntries.Attributes[0].Oem - Resource.Oem No Optional +RegistryEntries.Attributes[0].ResetRequired - boolean No Optional +RegistryEntries.Attributes[0].UefiDevicePath - string No Optional +RegistryEntries.Attributes[0].UefiKeywordName - string No Optional +RegistryEntries.Attributes[0].UefiNamespaceId - string No Optional +RegistryEntries.Attributes[0].AttributeName attr0 string Yes PASS +RegistryEntries.Attributes[0].Type String string (enum) Yes PASS +RegistryEntries.Attributes[0].Value Array (size: 0) array of: AttributeValue Yes ... +RegistryEntries.Attributes[0].DisplayName display name for attr0 string Yes PASS +RegistryEntries.Attributes[0].HelpText description for attr0 string Yes PASS +RegistryEntries.Attributes[0].WarningText - string No Optional +RegistryEntries.Attributes[0].CurrentValue current value primitive Yes PASS +RegistryEntries.Attributes[0].DefaultValue default value primitive Yes PASS +RegistryEntries.Attributes[0].DisplayOrder - number No Optional +RegistryEntries.Attributes[0].MenuPath ./menu/path/for/attr0 string Yes PASS +RegistryEntries.Attributes[0].ReadOnly False boolean Yes PASS +RegistryEntries.Attributes[0].WriteOnly - boolean No Optional +RegistryEntries.Attributes[0].GrayOut - boolean No Optional +RegistryEntries.Attributes[0].Hidden - boolean No Optional +RegistryEntries.Attributes[0].Immutable - boolean No Optional +RegistryEntries.Attributes[0].IsSystemUniqueProperty - boolean No Optional +RegistryEntries.Attributes[0].MaxLength - number No Optional +RegistryEntries.Attributes[0].MinLength - number No Optional +RegistryEntries.Attributes[0].ScalarIncrement - number No Optional +RegistryEntries.Attributes[0].UpperBound - number No Optional +RegistryEntries.Attributes[0].LowerBound - number No Optional +RegistryEntries.Attributes[0].ValueExpression - string No Optional +RegistryEntries.Menus - Menus No Optional +RegistryEntries.Dependencies - Dependencies No Optional +Id BiosAttributeRegistry string Yes PASS +Description - string No Optional +Name Bios Attribute Registry string Yes PASS +Oem - Resource.Oem No Optional + +Change-Id: Iecc61018c350f0b8c89df59b2864b941508b1916 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +Signed-off-by: Snehalatha Venkatesh <snehalathax.v@intel.com> +Signed-off-by: Smriti Ayushi <smriti.ayushi@intel.com> +--- + redfish-core/include/redfish.hpp | 3 + + .../include/registries/bios_registry.hpp | 40 ++ + redfish-core/lib/bios.hpp | 511 ++++++++++++++++++ + redfish-core/lib/message_registries.hpp | 10 +- + 4 files changed, 563 insertions(+), 1 deletion(-) + create mode 100644 redfish-core/include/registries/bios_registry.hpp + +diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp +index a9704d6..e4881ff 100644 +--- a/redfish-core/include/redfish.hpp ++++ b/redfish-core/include/redfish.hpp +@@ -152,7 +152,10 @@ class RedfishService + requestRoutesSystemActionsReset(app); + requestRoutesSystemResetActionInfo(app); + requestRoutesBiosService(app); ++ requestRoutesBiosSettings(app); ++ requestRoutesBiosAttributeRegistry(app); + requestRoutesBiosReset(app); ++ requestRoutesBiosChangePassword(app); + + #ifdef BMCWEB_ENABLE_VM_NBDPROXY + requestNBDVirtualMediaRoutes(app); +diff --git a/redfish-core/include/registries/bios_registry.hpp b/redfish-core/include/registries/bios_registry.hpp +new file mode 100644 +index 0000000..bcf6b73 +--- /dev/null ++++ b/redfish-core/include/registries/bios_registry.hpp +@@ -0,0 +1,40 @@ ++/* ++// Copyright (c) 2020 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++#pragma once ++#include <registries.hpp> ++ ++namespace redfish::registries::bios ++{ ++const Header header = { ++ "Copyright 2020 OpenBMC. All rights reserved.", ++ "#MessageRegistry.v1_4_0.MessageRegistry", ++ "BiosAttributeRegistry.1.0.0", ++ "Bios Attribute Registry", ++ "en", ++ "This registry defines the messages for bios attribute registry.", ++ "BiosAttributeRegistry", ++ "1.0.0", ++ "OpenBMC", ++}; ++// BiosAttributeRegistry registry is not defined in DMTF, We should use ++// OEM defined registries for this purpose. ++// Below link is wrong - We need to define OEM registries and use ++// appropriate data here. ++constexpr const char* url = ++ "https://redfish.dmtf.org/registries/BiosAttributeRegistry.1.0.0.json"; ++ ++constexpr std::array<MessageEntry, 0> registry = {}; ++} // namespace redfish::registries::bios +diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp +index d8475ae..e92e842 100644 +--- a/redfish-core/lib/bios.hpp ++++ b/redfish-core/lib/bios.hpp +@@ -3,8 +3,140 @@ + #include <app.hpp> + #include <registries/privilege_registry.hpp> + #include <utils/fw_utils.hpp> ++ + namespace redfish + { ++ ++/*baseBIOSTable ++map{attributeName,struct{attributeType,readonlyStatus,displayname, ++ description,menuPath,current,default, ++ array{struct{optionstring,optionvalue}}}} ++*/ ++using BiosBaseTableType = std::vector<std::pair< ++ std::string, ++ std::tuple< ++ std::string, bool, std::string, std::string, std::string, ++ std::variant<int64_t, std::string>, std::variant<int64_t, std::string>, ++ std::vector< ++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>>; ++using BiosBaseTableItemType = std::pair< ++ std::string, ++ std::tuple< ++ std::string, bool, std::string, std::string, std::string, ++ std::variant<int64_t, std::string>, std::variant<int64_t, std::string>, ++ std::vector< ++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>; ++using OptionsItemType = ++ std::tuple<std::string, std::variant<int64_t, std::string>>; ++ ++enum BiosBaseTableIndex ++{ ++ biosBaseAttrType = 0, ++ biosBaseReadonlyStatus, ++ biosBaseDisplayName, ++ biosBaseDescription, ++ biosBaseMenuPath, ++ biosBaseCurrValue, ++ biosBaseDefaultValue, ++ biosBaseOptions ++}; ++enum OptionsItemIndex ++{ ++ optItemType = 0, ++ optItemValue ++}; ++/* ++ The Pending attribute name and new value. ++ ex- { {"QuietBoot",Type.Integer, 0x1}, ++ { "DdrFreqLimit",Type.String,"2933"} ++ } ++*/ ++using PendingAttributesType = std::vector<std::pair< ++ std::string, std::tuple<std::string, std::variant<int64_t, std::string>>>>; ++using PendingAttributesItemType = ++ std::pair<std::string, ++ std::tuple<std::string, std::variant<int64_t, std::string>>>; ++enum PendingAttributesIndex ++{ ++ pendingAttrType = 0, ++ pendingAttrValue ++}; ++static std::string mapAttrTypeToRedfish(const std::string_view typeDbus) ++{ ++ std::string ret; ++ if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager." ++ "AttributeType.Enumeration") ++ { ++ ret = "Enumeration"; ++ } ++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig." ++ "Manager.AttributeType.String") ++ { ++ ret = "String"; ++ } ++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig." ++ "Manager.AttributeType.Password") ++ { ++ ret = "Password"; ++ } ++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig." ++ "Manager.AttributeType.Integer") ++ { ++ ret = "Integer"; ++ } ++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig." ++ "Manager.AttributeType.Boolean") ++ { ++ ret = "Boolean"; ++ } ++ else ++ { ++ ret = "UNKNOWN"; ++ } ++ ++ return ret; ++} ++static std::string mapBoundTypeToRedfish(const std::string_view typeDbus) ++{ ++ std::string ret; ++ if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.ScalarIncrement") ++ { ++ ret = "ScalarIncrement"; ++ } ++ else if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.LowerBound") ++ { ++ ret = "LowerBound"; ++ } ++ else if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.UpperBound") ++ { ++ ret = "UpperBound"; ++ } ++ else if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.MinStringLength") ++ { ++ ret = "MinStringLength"; ++ } ++ else if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.MaxStringLength") ++ { ++ ret = "MaxStringLength"; ++ } ++ else if (typeDbus == ++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.OneOf") ++ { ++ ret = "OneOf"; ++ } ++ else ++ { ++ ret = "UNKNOWN"; ++ } ++ ++ return ret; ++} ++ + /** + * BiosService class supports handle get method for bios. + */ +@@ -23,6 +155,85 @@ inline void + // Get the ActiveSoftwareImage and SoftwareImages + fw_util::populateFirmwareInformation(asyncResp, fw_util::biosPurpose, "", + true); ++ ++ asyncResp->res.jsonValue["@Redfish.Settings"] = { ++ {"@odata.type", "#Settings.v1_3_0.Settings"}, ++ {"SettingsObject", ++ {{"@odata.id", "/redfish/v1/Systems/system/Bios/Settings"}}}}; ++ asyncResp->res.jsonValue["AttributeRegistry"] = "BiosAttributeRegistry"; ++ asyncResp->res.jsonValue["Attributes"] = nlohmann::json::object(); ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec, ++ const GetObjectType& getObjectType) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " ++ << ec; ++ messages::internalError(asyncResp->res); ++ ++ return; ++ } ++ const std::string& service = getObjectType.begin()->first; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp]( ++ const boost::system::error_code ec, ++ const std::variant<BiosBaseTableType>& retBiosTable) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "getBiosAttributes DBUS error: " ++ << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ const BiosBaseTableType* baseBiosTable = ++ std::get_if<BiosBaseTableType>(&retBiosTable); ++ nlohmann::json& attributesJson = ++ asyncResp->res.jsonValue["Attributes"]; ++ if (baseBiosTable == nullptr) ++ { ++ BMCWEB_LOG_ERROR << "baseBiosTable == nullptr "; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ for (const BiosBaseTableItemType& item : *baseBiosTable) ++ { ++ const std::string& key = item.first; ++ const std::string& itemType = ++ std::get<biosBaseAttrType>(item.second); ++ std::string attrType = mapAttrTypeToRedfish(itemType); ++ if (attrType == "String") ++ { ++ const std::string* currValue = ++ std::get_if<std::string>( ++ &std::get<biosBaseCurrValue>(item.second)); ++ attributesJson.emplace( ++ key, currValue != nullptr ? *currValue : ""); ++ } ++ else if (attrType == "Integer") ++ { ++ const int64_t* currValue = std::get_if<int64_t>( ++ &std::get<biosBaseCurrValue>(item.second)); ++ attributesJson.emplace( ++ key, currValue != nullptr ? *currValue : 0); ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "Unsupported attribute type."; ++ messages::internalError(asyncResp->res); ++ } ++ } ++ }, ++ service, "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.BIOSConfig.Manager", "BaseBIOSTable"); ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject", ++ "/xyz/openbmc_project/bios_config/manager", ++ std::array<const char*, 0>()); + } + inline void requestRoutesBiosService(App& app) + { +@@ -31,6 +242,306 @@ inline void requestRoutesBiosService(App& app) + .methods(boost::beast::http::verb::get)(handleBiosServiceGet); + } + ++/** ++ * BiosSettings class supports handle GET/PATCH method for ++ * BIOS configuration pending settings. ++ */ ++inline void requestRoutesBiosSettings(App& app) ++{ ++ BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/Settings") ++ .privileges(redfish::privileges::getBios) ++ .methods(boost::beast::http::verb::get)( ++ [](const crow::Request&, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { ++ asyncResp->res.jsonValue["@odata.id"] = ++ asyncResp->res.jsonValue["@odata.id"] = ++ "/redfish/v1/Systems/system/Bios/Settings"; ++ asyncResp->res.jsonValue["@odata.type"] = "#Bios.v1_1_0.Bios"; ++ asyncResp->res.jsonValue["Name"] = "Bios Settings Version 1"; ++ asyncResp->res.jsonValue["Id"] = "BiosSettingsV1"; ++ asyncResp->res.jsonValue["AttributeRegistry"] = ++ "BiosAttributeRegistry"; ++ asyncResp->res.jsonValue["Attributes"] = {}; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec, ++ const GetObjectType& getObjectType) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR ++ << "ObjectMapper::GetObject call failed: " ++ << ec; ++ messages::internalError(asyncResp->res); ++ ++ return; ++ } ++ std::string service = getObjectType.begin()->first; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp]( ++ const boost::system::error_code ec, ++ const std::variant<PendingAttributesType>& ++ retPendingAttributes) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR ++ << "getBiosSettings DBUS error: " << ec; ++ messages::resourceNotFound( ++ asyncResp->res, "Systems/system/Bios", ++ "Settings"); ++ return; ++ } ++ const PendingAttributesType* pendingAttributes = ++ std::get_if<PendingAttributesType>( ++ &retPendingAttributes); ++ nlohmann::json& attributesJson = ++ asyncResp->res.jsonValue["Attributes"]; ++ if (pendingAttributes == nullptr) ++ { ++ BMCWEB_LOG_ERROR ++ << "pendingAttributes == nullptr "; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ for (const PendingAttributesItemType& item : ++ *pendingAttributes) ++ { ++ const std::string& key = item.first; ++ const std::string& itemType = ++ std::get<pendingAttrType>(item.second); ++ std::string attrType = ++ mapAttrTypeToRedfish(itemType); ++ if (attrType == "String") ++ { ++ const std::string* currValue = ++ std::get_if<std::string>( ++ &std::get<pendingAttrValue>( ++ item.second)); ++ attributesJson.emplace( ++ key, currValue != nullptr ++ ? *currValue ++ : ""); ++ } ++ else if (attrType == "Integer") ++ { ++ const int64_t* currValue = ++ std::get_if<int64_t>( ++ &std::get<pendingAttrValue>( ++ item.second)); ++ attributesJson.emplace( ++ key, currValue != nullptr ++ ? *currValue ++ : 0); ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR ++ << "Unsupported attribute type."; ++ messages::internalError(asyncResp->res); ++ } ++ } ++ }, ++ service, "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.BIOSConfig.Manager", ++ "PendingAttributes"); ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject", ++ "/xyz/openbmc_project/bios_config/manager", ++ std::array<const char*, 0>()); ++ }); ++} ++/** ++ * BiosAttributeRegistry class supports handle get method for BIOS attribute ++ * registry. ++ */ ++inline void requestRoutesBiosAttributeRegistry(App& app) ++{ ++ BMCWEB_ROUTE( ++ app, ++ "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry/") ++ .privileges(redfish::privileges::getBios) ++ .methods( ++ boost::beast::http::verb:: ++ get)([](const crow::Request&, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { ++ asyncResp->res.jsonValue["@odata.id"] = ++ "/redfish/v1/Registries/BiosAttributeRegistry/" ++ "BiosAttributeRegistry"; ++ asyncResp->res.jsonValue["@odata.type"] = ++ "#AttributeRegistry.v1_3_2.AttributeRegistry"; ++ asyncResp->res.jsonValue["Name"] = "Bios Attribute Registry"; ++ asyncResp->res.jsonValue["Id"] = "BiosAttributeRegistry"; ++ asyncResp->res.jsonValue["RegistryVersion"] = "1.0.0"; ++ asyncResp->res.jsonValue["Language"] = "en"; ++ asyncResp->res.jsonValue["OwningEntity"] = "OpenBMC"; ++ asyncResp->res.jsonValue["RegistryEntries"]["Attributes"] = ++ nlohmann::json::array(); ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec, ++ const GetObjectType& getObjectType) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR ++ << "ObjectMapper::GetObject call failed: " << ec; ++ messages::internalError(asyncResp->res); ++ ++ return; ++ } ++ std::string service = getObjectType.begin()->first; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec, ++ const std::variant<BiosBaseTableType>& ++ retBiosTable) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR ++ << "getBiosAttributeRegistry DBUS error: " ++ << ec; ++ messages::resourceNotFound( ++ asyncResp->res, "Registries/Bios", "Bios"); ++ return; ++ } ++ const BiosBaseTableType* baseBiosTable = ++ std::get_if<BiosBaseTableType>(&retBiosTable); ++ nlohmann::json& attributeArray = ++ asyncResp->res ++ .jsonValue["RegistryEntries"]["Attributes"]; ++ nlohmann::json optionsArray = ++ nlohmann::json::array(); ++ if (baseBiosTable == nullptr) ++ { ++ BMCWEB_LOG_ERROR << "baseBiosTable == nullptr "; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ for (const BiosBaseTableItemType& item : ++ *baseBiosTable) ++ { ++ const std::string& itemType = ++ std::get<biosBaseAttrType>(item.second); ++ std::string attrType = ++ mapAttrTypeToRedfish(itemType); ++ if (attrType == "UNKNOWN") ++ { ++ BMCWEB_LOG_ERROR << "attrType == UNKNOWN"; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ nlohmann::json attributeItem; ++ attributeItem["AttributeName"] = item.first; ++ attributeItem["Type"] = attrType; ++ attributeItem["ReadOnly"] = ++ std::get<biosBaseReadonlyStatus>( ++ item.second); ++ attributeItem["DisplayName"] = ++ std::get<biosBaseDisplayName>(item.second); ++ attributeItem["HelpText"] = ++ std::get<biosBaseDescription>(item.second); ++ attributeItem["MenuPath"] = ++ std::get<biosBaseMenuPath>(item.second); ++ ++ if (attrType == "String") ++ { ++ const std::string* currValue = ++ std::get_if<std::string>( ++ &std::get<biosBaseCurrValue>( ++ item.second)); ++ const std::string* defValue = ++ std::get_if<std::string>( ++ &std::get<biosBaseDefaultValue>( ++ item.second)); ++ attributeItem["CurrentValue"] = ++ currValue != nullptr ? *currValue : ""; ++ attributeItem["DefaultValue"] = ++ defValue != nullptr ? *defValue : ""; ++ } ++ else if (attrType == "Integer") ++ { ++ const int64_t* currValue = ++ std::get_if<int64_t>( ++ &std::get<biosBaseCurrValue>( ++ item.second)); ++ const int64_t* defValue = ++ std::get_if<int64_t>( ++ &std::get<biosBaseDefaultValue>( ++ item.second)); ++ attributeItem["CurrentValue"] = ++ currValue != nullptr ? *currValue : 0; ++ attributeItem["DefaultValue"] = ++ defValue != nullptr ? *defValue : 0; ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR ++ << "Unsupported attribute type."; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ const std::vector<OptionsItemType>& ++ optionsVector = ++ std::get<biosBaseOptions>(item.second); ++ for (const OptionsItemType& optItem : ++ optionsVector) ++ { ++ nlohmann::json optItemJson; ++ const std::string& strOptItemType = ++ std::get<optItemType>(optItem); ++ std::string optItemTypeRedfish = ++ mapBoundTypeToRedfish(strOptItemType); ++ if (optItemTypeRedfish == "UNKNOWN") ++ { ++ BMCWEB_LOG_ERROR ++ << "optItemTypeRedfish == UNKNOWN"; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ if (optItemTypeRedfish == "OneOf") ++ { ++ const std::string* currValue = ++ std::get_if<std::string>( ++ &std::get<optItemValue>( ++ optItem)); ++ optItemJson[optItemTypeRedfish] = ++ currValue != nullptr ? *currValue ++ : ""; ++ } ++ else ++ { ++ const int64_t* currValue = ++ std::get_if<int64_t>( ++ &std::get<optItemValue>( ++ optItem)); ++ optItemJson[optItemTypeRedfish] = ++ currValue != nullptr ? *currValue ++ : 0; ++ } ++ ++ optionsArray.push_back(optItemJson); ++ } ++ ++ attributeItem["Value"] = optionsArray; ++ attributeArray.push_back(attributeItem); ++ } ++ }, ++ service, "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.BIOSConfig.Manager", ++ "BaseBIOSTable"); ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject", ++ "/xyz/openbmc_project/bios_config/manager", ++ std::array<const char*, 0>()); ++ }); ++} ++ + /** + * BiosReset class supports handle POST method for Reset bios. + * The class retrieves and sends data directly to D-Bus. +diff --git a/redfish-core/lib/message_registries.hpp b/redfish-core/lib/message_registries.hpp +index c030e5a..d76f70b 100644 +--- a/redfish-core/lib/message_registries.hpp ++++ b/redfish-core/lib/message_registries.hpp +@@ -17,6 +17,7 @@ + + #include "registries.hpp" + #include "registries/base_message_registry.hpp" ++#include "registries/bios_registry.hpp" + #include "registries/openbmc_message_registry.hpp" + #include "registries/resource_event_message_registry.hpp" + #include "registries/task_event_message_registry.hpp" +@@ -128,7 +129,6 @@ inline void handleMessageRegistryGet( + const crow::Request& /*req*/, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const std::string& registry, const std::string& registryMatch) +- + { + const registries::Header* header = nullptr; + std::vector<const registries::MessageEntry*> registryEntries; +@@ -167,6 +167,14 @@ inline void handleMessageRegistryGet( + registryEntries.emplace_back(&entry); + } + } ++ else if (registry == "BiosAttributeRegistry") ++ { ++ header = ®istries::bios::header; ++ for (const registries::MessageEntry& entry : registries::bios::registry) ++ { ++ registryEntries.emplace_back(&entry); ++ } ++ } + else + { + messages::resourceNotFound( +-- +2.25.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch new file mode 100644 index 000000000..a52a1614f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0002-BaseBiosTable-Add-support-for-PATCH-operation.patch @@ -0,0 +1,148 @@ +From ffa924ef204930a5bb442bf654eac02543acfb8f Mon Sep 17 00:00:00 2001 +From: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +Date: Wed, 30 Jun 2021 15:18:46 +0000 +Subject: [PATCH 2/5] BaseBiosTable: Add support for PATCH operation + +This commit brings in support for PATCH operation of the +bios variables that updates the BaseBiosTable. + +Tested-By: +* Passed Redfish validator + +* Single Attribute: +PATCH https://${bmc}/redfish/v1/Systems/system/Bios/Settings -d +'{"data":[{"AttributeName": <attribute name>, "AttributeType": +<attribute type>, "AttributeValue": <attribute value>}]}' + +* Multiple Attributes: +PATCH https://${bmc}/redfish/v1/Systems/system/Bios/Settings -d +'{"data":[{"AttributeName": <attribute name>, "AttributeType": +<attribute type>, "AttributeValue": <attribute value>}, +{"AttributeName": <attribute name>, "AttributeType": +<attribute type>, "AttributeValue": <attribute value>}]}' + +This makes use of the "Set" of "PendingAttributes" in the +backend and that updates the BaseBiosTable. + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +Change-Id: I12e78e5ac623c264c7a3e1dd5198aca67172736d +--- + redfish-core/lib/bios.hpp | 95 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 95 insertions(+) + +diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp +index c1a5c56..14d2171 100644 +--- a/redfish-core/lib/bios.hpp ++++ b/redfish-core/lib/bios.hpp +@@ -96,6 +96,29 @@ static std::string mapAttrTypeToRedfish(const std::string_view typeDbus) + + return ret; + } ++static std::string mapRedfishToAttrType(const std::string_view type) ++{ ++ std::string ret; ++ if (type == "string") ++ { ++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String"; ++ } ++ else if (type == "int") ++ { ++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer"; ++ } ++ else if (type == "enum") ++ { ++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType." ++ "Enumeration"; ++ } ++ else ++ { ++ ret = "UNKNOWN"; ++ } ++ ++ return ret; ++} + static std::string mapBoundTypeToRedfish(const std::string_view typeDbus) + { + std::string ret; +@@ -370,6 +393,78 @@ inline void requestRoutesBiosSettings(App& app) + "/xyz/openbmc_project/bios_config/manager", + std::array<const char*, 0>()); + }); ++ ++ BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/Settings") ++ .privileges({{"ConfigureComponents"}}) ++ .methods(boost::beast::http::verb::patch)( ++ [](const crow::Request& req, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { ++ nlohmann::json inpJson; ++ ++ if (!redfish::json_util::readJsonPatch(req, asyncResp->res, "data", ++ inpJson)) ++ { ++ return; ++ } ++ ++ for (auto& attrInfo : inpJson) ++ { ++ std::optional<std::string> attrName; ++ std::optional<std::string> attrType; ++ std::optional<std::string> attrValue; ++ if (!json_util::getValueFromJsonObject( ++ attrInfo, "AttributeName", attrName)) ++ { ++ messages::propertyMissing(asyncResp->res, ++ "AttributeName"); ++ return; ++ } ++ if (!json_util::getValueFromJsonObject( ++ attrInfo, "AttributeType", attrType)) ++ { ++ messages::propertyMissing(asyncResp->res, ++ "AttributeType"); ++ return; ++ } ++ if (!json_util::getValueFromJsonObject( ++ attrInfo, "AttributeValue", attrValue)) ++ { ++ messages::propertyMissing(asyncResp->res, ++ "AttributeValue"); ++ return; ++ } ++ std::string biosAttrType = mapRedfishToAttrType(*attrType); ++ ++ if (biosAttrType == "UNKNOWN") ++ { ++ BMCWEB_LOG_ERROR << "Invalid attribute type"; ++ messages::propertyValueNotInList( ++ asyncResp->res, "AttributeType", *attrType); ++ return; ++ } ++ ++ PendingAttributesType pendingAttributes; ++ pendingAttributes.emplace_back(std::make_pair( ++ *attrName, std::make_tuple(biosAttrType, *attrValue))); ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR ++ << "doPatch resp_handler got error " << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ }, ++ "xyz.openbmc_project.BIOSConfigManager", ++ "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.BIOSConfig.Manager", ++ "PendingAttributes", ++ std::variant<PendingAttributesType>(pendingAttributes)); ++ } ++ }); + } + /** + * BiosAttributeRegistry class supports handle get method for BIOS attribute +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0003-Add-support-to-ResetBios-action.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0003-Add-support-to-ResetBios-action.patch new file mode 100644 index 000000000..5ed92cc3e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0003-Add-support-to-ResetBios-action.patch @@ -0,0 +1,53 @@ +From b7adca60dd69ac9566dc8f417065e244198fc711 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Wed, 6 Oct 2021 22:27:20 +0000 +Subject: [PATCH] Add support to ResetBios action + +Tested: + +Bios reset flag can be modified throw redfish +POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios + +Change-Id: Ic719c55705e5f634539b3dd858b60922e505a8d0 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + redfish-core/lib/bios.hpp | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp +index f5aa7b7..f613613 100644 +--- a/redfish-core/lib/bios.hpp ++++ b/redfish-core/lib/bios.hpp +@@ -648,17 +648,23 @@ inline void + handleBiosResetPost(const crow::Request&, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) + { ++ std::string resetFlag = ++ "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.FactoryDefaults"; ++ + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) + { +- BMCWEB_LOG_ERROR << "Failed to reset bios: " << ec; ++ BMCWEB_LOG_ERROR << "doPost bios reset got error " << ec; + messages::internalError(asyncResp->res); + return; + } + }, +- "org.open_power.Software.Host.Updater", "/xyz/openbmc_project/software", +- "xyz.openbmc_project.Common.FactoryReset", "Reset"); ++ "xyz.openbmc_project.BIOSConfigManager", ++ "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.BIOSConfig.Manager", "ResetBIOSSettings", ++ std::variant<std::string>(resetFlag)); + } + + inline void requestRoutesBiosReset(App& app) +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0004-Add-support-to-ChangePassword-action.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0004-Add-support-to-ChangePassword-action.patch new file mode 100644 index 000000000..de705b60b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0004-Add-support-to-ChangePassword-action.patch @@ -0,0 +1,117 @@ +From 22956921a228f6f1cbbbd3045a3cc3969732dca3 Mon Sep 17 00:00:00 2001 +From: Arun Lal K M <arun.lal@intel.com> +Date: Fri, 8 Oct 2021 20:56:00 +0000 +Subject: [PATCH] Add support to ChangePassword action + +Tested: + +Passed Redfish validator. +Bios change password: +root@intel-obmc:~# cat /var/lib/bios-settings-manager/seedData +{ +"UserPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D", +"AdminPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D", +"Seed": "123456", +"HashAlgo": "SHA384" +} +POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword +{ + "NewPassword": "12345678", + "OldPassword": "1234567890", + "PasswordName": "Administrator" +} +root@intel-obmc:~# cat /var/lib/bios-settings-manager/passwordData +{ + "CurrentPassword": "1234567890", + "IsAdminPwdChanged": 1, + "IsUserPwdChanged": 0, + "NewPassword": "2DD65D57EB60B1D92C5F3D2DC84724FCEE7BC02E57AA75E834712266ED94CAC704047B2FF7CEC1C36BED280B36BB5AC6", + "UserName": "Administrator" +} + +Signed-off-by: Arun Lal K M <arun.lal@intel.com> +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + redfish-core/lib/bios.hpp | 59 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 59 insertions(+) + +diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp +index f613613..b06a904 100644 +--- a/redfish-core/lib/bios.hpp ++++ b/redfish-core/lib/bios.hpp +@@ -175,6 +175,10 @@ inline void + asyncResp->res.jsonValue["Actions"]["#Bios.ResetBios"] = { + {"target", "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios"}}; + ++ asyncResp->res.jsonValue["Actions"]["#Bios.ChangePassword"] = { ++ {"target", "/redfish/v1/Systems/system/Bios/Actions/" ++ "Bios.ChangePassword"}}; ++ + // Get the ActiveSoftwareImage and SoftwareImages + fw_util::populateFirmwareInformation(asyncResp, fw_util::biosPurpose, "", + true); +@@ -265,6 +269,61 @@ inline void requestRoutesBiosService(App& app) + .methods(boost::beast::http::verb::get)(handleBiosServiceGet); + } + ++/** ++ * BiosChangePassword class supports handle POST method for change bios ++ * password. The class retrieves and sends data directly to D-Bus. ++ */ ++inline void requestRoutesBiosChangePassword(App& app) ++{ ++ BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/") ++ .privileges({{"ConfigureComponents"}}) ++ .methods(boost::beast::http::verb::post)( ++ [](const crow::Request& req, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { ++ std::string currentPassword, newPassword, userName; ++ if (!json_util::readJsonPatch(req, asyncResp->res, "NewPassword", ++ newPassword, "OldPassword", ++ currentPassword, "PasswordName", ++ userName)) ++ { ++ return; ++ } ++ if (currentPassword.empty()) ++ { ++ messages::actionParameterUnknown( ++ asyncResp->res, "ChangePassword", "OldPassword"); ++ return; ++ } ++ if (newPassword.empty()) ++ { ++ messages::actionParameterUnknown( ++ asyncResp->res, "ChangePassword", "NewPassword"); ++ return; ++ } ++ if (userName.empty()) ++ { ++ messages::actionParameterUnknown( ++ asyncResp->res, "ChangePassword", "PasswordName"); ++ return; ++ } ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_CRITICAL ++ << "Failed in doPost(BiosChangePassword) " ++ << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ }, ++ "xyz.openbmc_project.BIOSConfigPassword", ++ "/xyz/openbmc_project/bios_config/password", ++ "xyz.openbmc_project.BIOSConfig.Password", "ChangePassword", ++ userName, currentPassword, newPassword); ++ }); ++} ++ + /** + * BiosSettings class supports handle GET/PATCH method for + * BIOS configuration pending settings. +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch new file mode 100644 index 000000000..26393bfee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0005-Fix-remove-bios-user-pwd-change-option-via-Redfish.patch @@ -0,0 +1,46 @@ +From edc6925e8c0d9f60da1f70c524261efaf05b2710 Mon Sep 17 00:00:00 2001 +From: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +Date: Wed, 30 Jun 2021 15:42:06 +0000 +Subject: [PATCH 5/5] Fix:remove bios user pwd change option via Redfish + +BMC should not provide user bios setup password change option via +Redfish as per bios security requirements. Only Admin BIOS setup +password is supported. + +Added check for the password name action parameter and +do not allow if it has User Password value from redfish side. + +Tested: sent POST query in redfish on URI: +https://<ip>/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword +error occurs for UserPassword parameter and allows for AdminPassword. + +Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com> +Change-Id: I169cc6a4f786625d9e8b8dfe56816d52b1740f4c +--- + redfish-core/lib/bios.hpp | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp +index 0250c59..360a749 100644 +--- a/redfish-core/lib/bios.hpp ++++ b/redfish-core/lib/bios.hpp +@@ -323,6 +323,16 @@ inline void requestRoutesBiosChangePassword(App& app) + asyncResp->res, "ChangePassword", "PasswordName"); + return; + } ++ ++ // In Intel BIOS, we are not supporting user password in BIOS ++ // setup ++ if (userName == "UserPassword") ++ { ++ messages::actionParameterUnknown( ++ asyncResp->res, "ChangePassword", "PasswordName"); ++ return; ++ } ++ + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0006-Add-fix-for-broken-feature-Pending-Attributes.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0006-Add-fix-for-broken-feature-Pending-Attributes.patch new file mode 100644 index 000000000..05257bbf7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0006-Add-fix-for-broken-feature-Pending-Attributes.patch @@ -0,0 +1,963 @@ +From bedec07809e2d2ecfed9db0d9509d2380ea094b7 Mon Sep 17 00:00:00 2001 +From: Arun Lal K M <arun.lal@intel.com> +Date: Wed, 19 Jan 2022 14:44:07 +0000 +Subject: [PATCH] Add fix for broken feature 'Pending Attributes'. + +Fix is added for the following: +1) GET to 'redfish/v1/Systems/system/Bios'. +2) PATCH to 'redfish/v1/Systems/system/Bios/Settings'. +3) GET to 'redfish/v1/Systems/system/Bios/Settings'. +4) Fix for incremental duplicate values in BiosAttributeRegistry. +5) POST to '/redfish/v1/Systems/system/Bios/Actions + /Bios.ChangePassword/'. +6) Add support for Enumeration. +7) Support DMTF standard of displaying "Value" in BIOS attribute registries. + +Tested: +By giving PATCH to 'redfish/v1/Systems/system/Bios/Settings' +PATCH command raw data: +{ + "data":{ + "AmpPrefetchEnable": "0x1", + "Ce2LmLoggingEn": "0x1", + "DfxEadrDebugLogs": "0x2", + "PsfUrEnable": "0x1", + "ATS": "0x0" + } +} + +Response: +{ + "@Message.ExtendedInfo": [ + { + "@odata.type": "#Message.v1_1_1.Message", + "Message": "Successfully Completed Request", + "MessageArgs": [], + "MessageId": "Base.1.8.1.Success", + "MessageSeverity": "OK", + "Resolution": "None" + } + ] +} + +By giving GET to 'redfish/v1/Systems/system/Bios' +Response: +{ + "@Redfish.Settings": { + "@odata.type": "#Settings.v1_3_0.Settings", + "SettingsObject": { + "@odata.id": + "/redfish/v1/Systems/system/Bios/Settings" + } + }, + "@odata.id": "/redfish/v1/Systems/system/Bios", + "@odata.type": "#Bios.v1_1_0.Bios", + "Actions": { + "#Bios.ChangePassword": { + "target": + "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword" + }, + "#Bios.ResetBios": { + "target": + "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios" + } + }, + "AttributeRegistry": "BiosAttributeRegistry", + "Attributes": { + "AEPErrorInjEn": "0x00", + "ARIEnable": "0x01", + "ARIForward": "0x00", + ... + ... + ... + "txEqCalibration": "0x01", + "volMemMode": "0x00", + "wrVrefCenter": "0x01" + }, + "Description": "BIOS Configuration Service", + "Id": "BIOS", + "Links": { + "ActiveSoftwareImage": { + "@odata.id": + "/redfish/v1/UpdateService/FirmwareInventory/bios_active" + }, + "SoftwareImages": [ + { + "@odata.id": + "/redfish/v1/UpdateService/FirmwareInventory/bios_active" + } + ], + "SoftwareImages@odata.count": 1 + }, + "Name": "BIOS Configuration" +} + +By giving GET to 'redfish/v1/Systems/system/Bios/Settings' +Response: +{ + "@odata.id": "/redfish/v1/Systems/system/Bios/Settings", + "@odata.type": "#Bios.v1_1_0.Bios", + "AttributeRegistry": "BiosAttributeRegistry", + "Attributes": { + "ATS": "0x0", + "AmpPrefetchEnable": "0x1", + "Ce2LmLoggingEn": "0x1", + "DfxEadrDebugLogs": "0x2", + "PsfUrEnable": "0x1" + }, + "Id": "BiosSettingsV1", + "Name": "Bios Settings Version 1" +} + +By giving POST to '/redfish/v1/Systems/system/Bios/Actions +/Bios.ChangePassword/' +Response: Success + +By running Redfish-Service-Validator +Result: +Elapsed time: 0:09:36 +invalidPropertyValue: 108 +metadataNamespaces: 2185 +missingNamespaces: 1 +optionalAction: 9 +pass: 13772 +passAction: 22 +passGet: 541 +reflink: 1 +repeat: 47 +serviceNamespaces: 75 +skipOptional: 9276 +unverifiedComplexAdditional: 1 +warnDeprecated: 230 +warningPresent: 54 +Validation has succeeded. + +Signed-off-by: Arun Lal K M <arun.lal@intel.com> +Signed-off-by: Snehalatha Venkatesh <snehalathax.v@intel.com> +--- + redfish-core/lib/bios.hpp | 605 +++++++++++++++++++++++++------------- + 1 file changed, 394 insertions(+), 211 deletions(-) + +diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp +index bbf9460..c3192dd 100644 +--- a/redfish-core/lib/bios.hpp ++++ b/redfish-core/lib/bios.hpp +@@ -12,13 +12,15 @@ map{attributeName,struct{attributeType,readonlyStatus,displayname, + description,menuPath,current,default, + array{struct{optionstring,optionvalue}}}} + */ +-using BiosBaseTableType = std::vector<std::pair< ++ ++using BiosBaseTableType = boost::container::flat_map< + std::string, + std::tuple< + std::string, bool, std::string, std::string, std::string, + std::variant<int64_t, std::string>, std::variant<int64_t, std::string>, + std::vector< +- std::tuple<std::string, std::variant<int64_t, std::string>>>>>>; ++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>; ++ + using BiosBaseTableItemType = std::pair< + std::string, + std::tuple< +@@ -29,6 +31,13 @@ using BiosBaseTableItemType = std::pair< + using OptionsItemType = + std::tuple<std::string, std::variant<int64_t, std::string>>; + ++using PendingAttributesType = boost::container::flat_map< ++ std::string, std::tuple<std::string, std::variant<int64_t, std::string>>>; ++ ++using PendingAttributesItemType = ++ std::pair<std::string, ++ std::tuple<std::string, std::variant<int64_t, std::string>>>; ++ + enum BiosBaseTableIndex + { + biosBaseAttrType = 0, +@@ -45,17 +54,7 @@ enum OptionsItemIndex + optItemType = 0, + optItemValue + }; +-/* +- The Pending attribute name and new value. +- ex- { {"QuietBoot",Type.Integer, 0x1}, +- { "DdrFreqLimit",Type.String,"2933"} +- } +-*/ +-using PendingAttributesType = std::vector<std::pair< +- std::string, std::tuple<std::string, std::variant<int64_t, std::string>>>>; +-using PendingAttributesItemType = +- std::pair<std::string, +- std::tuple<std::string, std::variant<int64_t, std::string>>>; ++ + enum PendingAttributesIndex + { + pendingAttrType = 0, +@@ -64,30 +63,20 @@ enum PendingAttributesIndex + static std::string mapAttrTypeToRedfish(const std::string_view typeDbus) + { + std::string ret; +- if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager." +- "AttributeType.Enumeration") +- { +- ret = "Enumeration"; +- } +- else if (typeDbus == "xyz.openbmc_project.BIOSConfig." +- "Manager.AttributeType.String") ++ if (typeDbus == "xyz.openbmc_project.BIOSConfig." ++ "Manager.AttributeType.String") + { + ret = "String"; + } +- else if (typeDbus == "xyz.openbmc_project.BIOSConfig." +- "Manager.AttributeType.Password") +- { +- ret = "Password"; +- } + else if (typeDbus == "xyz.openbmc_project.BIOSConfig." + "Manager.AttributeType.Integer") + { + ret = "Integer"; + } + else if (typeDbus == "xyz.openbmc_project.BIOSConfig." +- "Manager.AttributeType.Boolean") ++ "Manager.AttributeType.Enumeration") + { +- ret = "Boolean"; ++ ret = "Enumeration"; + } + else + { +@@ -96,29 +85,7 @@ static std::string mapAttrTypeToRedfish(const std::string_view typeDbus) + + return ret; + } +-static std::string mapRedfishToAttrType(const std::string_view type) +-{ +- std::string ret; +- if (type == "string") +- { +- ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String"; +- } +- else if (type == "int") +- { +- ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer"; +- } +- else if (type == "enum") +- { +- ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType." +- "Enumeration"; +- } +- else +- { +- ret = "UNKNOWN"; +- } + +- return ret; +-} + static std::string mapBoundTypeToRedfish(const std::string_view typeDbus) + { + std::string ret; +@@ -201,6 +168,15 @@ inline void + + return; + } ++ ++ if (getObjectType.empty()) ++ { ++ BMCWEB_LOG_ERROR << "getObjectType is empty."; ++ messages::internalError(asyncResp->res); ++ ++ return; ++ } ++ + const std::string& service = getObjectType.begin()->first; + + crow::connections::systemBus->async_method_call( +@@ -220,7 +196,7 @@ inline void + asyncResp->res.jsonValue["Attributes"]; + if (baseBiosTable == nullptr) + { +- BMCWEB_LOG_ERROR << "baseBiosTable == nullptr "; ++ BMCWEB_LOG_ERROR << "baseBiosTable is empty"; + messages::internalError(asyncResp->res); + return; + } +@@ -230,7 +206,7 @@ inline void + const std::string& itemType = + std::get<biosBaseAttrType>(item.second); + std::string attrType = mapAttrTypeToRedfish(itemType); +- if (attrType == "String") ++ if (attrType == "String" || attrType == "Enumeration") + { + const std::string* currValue = + std::get_if<std::string>( +@@ -248,7 +224,6 @@ inline void + else + { + BMCWEB_LOG_ERROR << "Unsupported attribute type."; +- messages::internalError(asyncResp->res); + } + } + }, +@@ -275,8 +250,9 @@ inline void requestRoutesBiosService(App& app) + */ + inline void requestRoutesBiosChangePassword(App& app) + { +- BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/") +- .privileges({{"ConfigureComponents"}}) ++ BMCWEB_ROUTE(app, ++ "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword/") ++ .privileges(redfish::privileges::postBios) + .methods(boost::beast::http::verb::post)( + [](const crow::Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { +@@ -342,180 +318,303 @@ inline void requestRoutesBiosSettings(App& app) + { + BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/Settings") + .privileges(redfish::privileges::getBios) +- .methods(boost::beast::http::verb::get)( +- [](const crow::Request&, +- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { +- asyncResp->res.jsonValue["@odata.id"] = +- asyncResp->res.jsonValue["@odata.id"] = +- "/redfish/v1/Systems/system/Bios/Settings"; +- asyncResp->res.jsonValue["@odata.type"] = "#Bios.v1_1_0.Bios"; +- asyncResp->res.jsonValue["Name"] = "Bios Settings Version 1"; +- asyncResp->res.jsonValue["Id"] = "BiosSettingsV1"; +- asyncResp->res.jsonValue["AttributeRegistry"] = +- "BiosAttributeRegistry"; +- asyncResp->res.jsonValue["Attributes"] = {}; ++ .methods( ++ boost::beast::http::verb:: ++ get)([](const crow::Request&, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { ++ asyncResp->res.jsonValue["@odata.id"] = ++ "/redfish/v1/Systems/system/Bios/Settings"; ++ asyncResp->res.jsonValue["@odata.type"] = "#Bios.v1_1_0.Bios"; ++ asyncResp->res.jsonValue["Name"] = "Bios Settings Version 1"; ++ asyncResp->res.jsonValue["Id"] = "BiosSettingsV1"; ++ asyncResp->res.jsonValue["AttributeRegistry"] = ++ "BiosAttributeRegistry"; ++ asyncResp->res.jsonValue["Attributes"] = {}; + +- crow::connections::systemBus->async_method_call( +- [asyncResp](const boost::system::error_code ec, +- const GetObjectType& getObjectType) { +- if (ec) +- { +- BMCWEB_LOG_ERROR +- << "ObjectMapper::GetObject call failed: " +- << ec; +- messages::internalError(asyncResp->res); ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec, ++ const GetObjectType& getObjectType) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR ++ << "ObjectMapper::GetObject call failed: " << ec; ++ messages::internalError(asyncResp->res); + +- return; +- } +- std::string service = getObjectType.begin()->first; +- +- crow::connections::systemBus->async_method_call( +- [asyncResp]( +- const boost::system::error_code ec, +- const std::variant<PendingAttributesType>& +- retPendingAttributes) { +- if (ec) +- { +- BMCWEB_LOG_ERROR +- << "getBiosSettings DBUS error: " << ec; +- messages::resourceNotFound( +- asyncResp->res, "Systems/system/Bios", +- "Settings"); +- return; +- } +- const PendingAttributesType* pendingAttributes = +- std::get_if<PendingAttributesType>( +- &retPendingAttributes); +- nlohmann::json& attributesJson = +- asyncResp->res.jsonValue["Attributes"]; +- if (pendingAttributes == nullptr) +- { +- BMCWEB_LOG_ERROR +- << "pendingAttributes == nullptr "; +- messages::internalError(asyncResp->res); +- return; +- } +- for (const PendingAttributesItemType& item : +- *pendingAttributes) ++ return; ++ } ++ ++ if (getObjectType.empty()) ++ { ++ BMCWEB_LOG_ERROR << "getObjectType is empty."; ++ messages::internalError(asyncResp->res); ++ ++ return; ++ } ++ ++ std::string service = getObjectType.begin()->first; ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec, ++ const std::variant<PendingAttributesType>& ++ retPendingAttributes) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR ++ << "getBiosSettings DBUS error: " << ec; ++ messages::resourceNotFound( ++ asyncResp->res, "Systems/system/Bios", ++ "Settings"); ++ return; ++ } ++ ++ const PendingAttributesType* pendingAttributes = ++ std::get_if<PendingAttributesType>( ++ &retPendingAttributes); ++ nlohmann::json& attributesJson = ++ asyncResp->res.jsonValue["Attributes"]; ++ if (pendingAttributes == nullptr) ++ { ++ BMCWEB_LOG_ERROR ++ << "pendingAttributes is empty"; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ for (const PendingAttributesItemType& ++ pendingAttributesItem : *pendingAttributes) ++ { ++ const std::string& biosAttrType = ++ std::get<pendingAttrType>( ++ pendingAttributesItem.second); ++ ++ std::string itemType = ++ mapAttrTypeToRedfish(biosAttrType); ++ ++ if (itemType == "String" || ++ itemType == "Enumeration") + { +- const std::string& key = item.first; +- const std::string& itemType = +- std::get<pendingAttrType>(item.second); +- std::string attrType = +- mapAttrTypeToRedfish(itemType); +- if (attrType == "String") +- { +- const std::string* currValue = +- std::get_if<std::string>( +- &std::get<pendingAttrValue>( +- item.second)); +- attributesJson.emplace( +- key, currValue != nullptr +- ? *currValue +- : ""); +- } +- else if (attrType == "Integer") ++ const std::string* currValue = ++ std::get_if<std::string>( ++ &std::get<pendingAttrValue>( ++ pendingAttributesItem.second)); ++ ++ if (!currValue) + { +- const int64_t* currValue = +- std::get_if<int64_t>( +- &std::get<pendingAttrValue>( +- item.second)); +- attributesJson.emplace( +- key, currValue != nullptr +- ? *currValue +- : 0); ++ BMCWEB_LOG_ERROR ++ << "No string data in pending " ++ "attributes item data"; ++ messages::internalError(asyncResp->res); ++ return; + } +- else ++ ++ attributesJson.emplace( ++ pendingAttributesItem.first, ++ *currValue); ++ } ++ else if (itemType == "Integer") ++ { ++ const int64_t* currValue = ++ std::get_if<int64_t>( ++ &std::get<pendingAttrValue>( ++ pendingAttributesItem.second)); ++ ++ if (!currValue) + { + BMCWEB_LOG_ERROR +- << "Unsupported attribute type."; ++ << "No int64_t data in pending " ++ "attributes item data"; + messages::internalError(asyncResp->res); ++ return; + } ++ ++ attributesJson.emplace( ++ pendingAttributesItem.first, ++ *currValue); + } +- }, +- service, "/xyz/openbmc_project/bios_config/manager", +- "org.freedesktop.DBus.Properties", "Get", +- "xyz.openbmc_project.BIOSConfig.Manager", +- "PendingAttributes"); +- }, +- "xyz.openbmc_project.ObjectMapper", +- "/xyz/openbmc_project/object_mapper", +- "xyz.openbmc_project.ObjectMapper", "GetObject", +- "/xyz/openbmc_project/bios_config/manager", +- std::array<const char*, 0>()); +- }); ++ else ++ { ++ BMCWEB_LOG_ERROR ++ << "Unsupported attribute type."; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ } ++ }, ++ service, "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Get", ++ "xyz.openbmc_project.BIOSConfig.Manager", ++ "PendingAttributes"); ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject", ++ "/xyz/openbmc_project/bios_config/manager", ++ std::array<const char*, 0>()); ++ }); + + BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Bios/Settings") +- .privileges({{"ConfigureComponents"}}) +- .methods(boost::beast::http::verb::patch)( +- [](const crow::Request& req, +- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { +- nlohmann::json inpJson; ++ .privileges(redfish::privileges::patchBios) ++ .methods( ++ boost::beast::http::verb:: ++ patch)([](const crow::Request& req, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { ++ nlohmann::json inpJson; + +- if (!redfish::json_util::readJsonPatch(req, asyncResp->res, "data", +- inpJson)) +- { +- return; +- } ++ if (!redfish::json_util::readJsonPatch(req, asyncResp->res, "data", ++ inpJson)) ++ { ++ BMCWEB_LOG_ERROR << "No 'data' in req!"; ++ return; ++ } + +- for (auto& attrInfo : inpJson) +- { +- std::optional<std::string> attrName; +- std::optional<std::string> attrType; +- std::optional<std::string> attrValue; +- if (!json_util::getValueFromJsonObject( +- attrInfo, "AttributeName", attrName)) +- { +- messages::propertyMissing(asyncResp->res, +- "AttributeName"); +- return; +- } +- if (!json_util::getValueFromJsonObject( +- attrInfo, "AttributeType", attrType)) +- { +- messages::propertyMissing(asyncResp->res, +- "AttributeType"); +- return; +- } +- if (!json_util::getValueFromJsonObject( +- attrInfo, "AttributeValue", attrValue)) ++ if (inpJson.empty()) ++ { ++ messages::invalidObject(asyncResp->res, ++ crow::utility::urlFromPieces("data")); ++ BMCWEB_LOG_ERROR << "No input in req!"; ++ return; ++ } ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp, inpJson](const boost::system::error_code ec, ++ const GetObjectType& getObjectType) { ++ if (ec) + { +- messages::propertyMissing(asyncResp->res, +- "AttributeValue"); ++ BMCWEB_LOG_ERROR ++ << "ObjectMapper::GetObject call failed: " << ec; ++ messages::internalError(asyncResp->res); ++ + return; + } +- std::string biosAttrType = mapRedfishToAttrType(*attrType); + +- if (biosAttrType == "UNKNOWN") ++ if (getObjectType.empty()) + { +- BMCWEB_LOG_ERROR << "Invalid attribute type"; +- messages::propertyValueNotInList( +- asyncResp->res, "AttributeType", *attrType); ++ BMCWEB_LOG_ERROR << "getObjectType is empty."; ++ messages::internalError(asyncResp->res); ++ + return; + } + +- PendingAttributesType pendingAttributes; +- pendingAttributes.emplace_back(std::make_pair( +- *attrName, std::make_tuple(biosAttrType, *attrValue))); ++ std::string service = getObjectType.begin()->first; + + crow::connections::systemBus->async_method_call( +- [asyncResp](const boost::system::error_code ec) { ++ [asyncResp, ++ inpJson](const boost::system::error_code ec, ++ const std::variant<BiosBaseTableType>& ++ retBiosTable) { + if (ec) + { + BMCWEB_LOG_ERROR +- << "doPatch resp_handler got error " << ec; ++ << "getBiosAttributes DBUS error: " << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ const BiosBaseTableType* baseBiosTable = ++ std::get_if<BiosBaseTableType>(&retBiosTable); ++ ++ if (baseBiosTable == nullptr) ++ { ++ BMCWEB_LOG_ERROR << "baseBiosTable is empty."; + messages::internalError(asyncResp->res); + return; + } ++ ++ PendingAttributesType pendingAttributes{}; ++ ++ for (nlohmann::detail::iteration_proxy_value< ++ nlohmann::detail::iter_impl< ++ const nlohmann::basic_json<>>>& ++ attributes : inpJson.items()) ++ { ++ BiosBaseTableType::const_iterator knobIter = ++ baseBiosTable->find(attributes.key()); ++ if (knobIter == baseBiosTable->end()) ++ { ++ BMCWEB_LOG_ERROR << "Cannot find " ++ << attributes.key() ++ << " in baseBiosTable"; ++ messages::propertyValueNotInList( ++ asyncResp->res, attributes.key(), ++ "data"); ++ return; ++ } ++ ++ const std::string& itemType = ++ std::get<biosBaseAttrType>( ++ knobIter->second); ++ std::string attrType = ++ mapAttrTypeToRedfish(itemType); ++ ++ if (attrType == "String" || ++ attrType == "Enumeration") ++ { ++ std::string val = attributes.value(); ++ ++ pendingAttributes.emplace( ++ attributes.key(), ++ std::make_tuple(itemType, val)); ++ } ++ else if (attrType == "Integer") ++ { ++ pendingAttributes.emplace( ++ attributes.key(), ++ std::make_tuple( ++ itemType, static_cast<int64_t>( ++ attributes.value()))); ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "UNKNOWN attrType == " ++ << itemType; ++ messages::internalError(asyncResp->res); ++ ++ return; ++ } ++ } ++ ++ if (pendingAttributes.empty()) ++ { ++ BMCWEB_LOG_ERROR ++ << "pendingAttributes is empty."; ++ messages::invalidObject( ++ asyncResp->res, ++ crow::utility::urlFromPieces("data")); ++ } ++ ++ crow::connections::systemBus->async_method_call( ++ [asyncResp]( ++ const boost::system::error_code ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR ++ << "doPatch resp_handler got error " ++ << ec << "\n"; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ messages::success(asyncResp->res); ++ }, ++ "xyz.openbmc_project.BIOSConfigManager", ++ "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.BIOSConfig.Manager", ++ "PendingAttributes", ++ std::variant<PendingAttributesType>( ++ pendingAttributes)); + }, +- "xyz.openbmc_project.BIOSConfigManager", +- "/xyz/openbmc_project/bios_config/manager", +- "org.freedesktop.DBus.Properties", "Set", ++ service, "/xyz/openbmc_project/bios_config/manager", ++ "org.freedesktop.DBus.Properties", "Get", + "xyz.openbmc_project.BIOSConfig.Manager", +- "PendingAttributes", +- std::variant<PendingAttributesType>(pendingAttributes)); +- } +- }); ++ "BaseBIOSTable"); ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject", ++ "/xyz/openbmc_project/bios_config/manager", ++ std::array<const char*, 0>()); ++ }); + } + /** + * BiosAttributeRegistry class supports handle get method for BIOS attribute +@@ -555,6 +654,15 @@ inline void requestRoutesBiosAttributeRegistry(App& app) + + return; + } ++ ++ if (getObjectType.empty()) ++ { ++ BMCWEB_LOG_ERROR << "getObjectType is empty."; ++ messages::internalError(asyncResp->res); ++ ++ return; ++ } ++ + std::string service = getObjectType.begin()->first; + + crow::connections::systemBus->async_method_call( +@@ -575,8 +683,6 @@ inline void requestRoutesBiosAttributeRegistry(App& app) + nlohmann::json& attributeArray = + asyncResp->res + .jsonValue["RegistryEntries"]["Attributes"]; +- nlohmann::json optionsArray = +- nlohmann::json::array(); + if (baseBiosTable == nullptr) + { + BMCWEB_LOG_ERROR << "baseBiosTable == nullptr "; +@@ -592,10 +698,11 @@ inline void requestRoutesBiosAttributeRegistry(App& app) + mapAttrTypeToRedfish(itemType); + if (attrType == "UNKNOWN") + { +- BMCWEB_LOG_ERROR << "attrType == UNKNOWN"; +- messages::internalError(asyncResp->res); +- return; ++ BMCWEB_LOG_ERROR << "UNKNOWN attrType == " ++ << itemType; ++ continue; + } ++ + nlohmann::json attributeItem; + attributeItem["AttributeName"] = item.first; + attributeItem["Type"] = attrType; +@@ -609,16 +716,37 @@ inline void requestRoutesBiosAttributeRegistry(App& app) + attributeItem["MenuPath"] = + std::get<biosBaseMenuPath>(item.second); + +- if (attrType == "String") ++ if (attrType == "String" || ++ attrType == "Enumeration") + { + const std::string* currValue = + std::get_if<std::string>( + &std::get<biosBaseCurrValue>( + item.second)); ++ ++ if (!currValue) ++ { ++ BMCWEB_LOG_ERROR ++ << "Unable to get currValue, no " ++ "std::string data in BIOS " ++ "attributes item data"; ++ continue; ++ } ++ + const std::string* defValue = + std::get_if<std::string>( + &std::get<biosBaseDefaultValue>( + item.second)); ++ ++ if (!defValue) ++ { ++ BMCWEB_LOG_ERROR ++ << "Unable to get defValue, no " ++ "std::string data in BIOS " ++ "attributes item data"; ++ continue; ++ } ++ + attributeItem["CurrentValue"] = + currValue != nullptr ? *currValue : ""; + attributeItem["DefaultValue"] = +@@ -630,10 +758,30 @@ inline void requestRoutesBiosAttributeRegistry(App& app) + std::get_if<int64_t>( + &std::get<biosBaseCurrValue>( + item.second)); ++ ++ if (!currValue) ++ { ++ BMCWEB_LOG_ERROR ++ << "Unable to get currValue, no " ++ "int64_t data in BIOS " ++ "attributes item data"; ++ continue; ++ } ++ + const int64_t* defValue = + std::get_if<int64_t>( + &std::get<biosBaseDefaultValue>( + item.second)); ++ ++ if (!defValue) ++ { ++ BMCWEB_LOG_ERROR ++ << "Unable to get defValue, no " ++ "int64_t data in BIOS " ++ "attributes item data"; ++ continue; ++ } ++ + attributeItem["CurrentValue"] = + currValue != nullptr ? *currValue : 0; + attributeItem["DefaultValue"] = +@@ -641,12 +789,13 @@ inline void requestRoutesBiosAttributeRegistry(App& app) + } + else + { +- BMCWEB_LOG_ERROR +- << "Unsupported attribute type."; +- messages::internalError(asyncResp->res); +- return; ++ BMCWEB_LOG_ERROR << "UNKNOWN attrType == " ++ << itemType; ++ continue; + } + ++ nlohmann::json optionsArray = ++ nlohmann::json::array(); + const std::vector<OptionsItemType>& + optionsVector = + std::get<biosBaseOptions>(item.second); +@@ -661,9 +810,9 @@ inline void requestRoutesBiosAttributeRegistry(App& app) + if (optItemTypeRedfish == "UNKNOWN") + { + BMCWEB_LOG_ERROR +- << "optItemTypeRedfish == UNKNOWN"; +- messages::internalError(asyncResp->res); +- return; ++ << "UNKNOWN optItemTypeRedfish == " ++ << strOptItemType; ++ continue; + } + if (optItemTypeRedfish == "OneOf") + { +@@ -671,7 +820,21 @@ inline void requestRoutesBiosAttributeRegistry(App& app) + std::get_if<std::string>( + &std::get<optItemValue>( + optItem)); +- optItemJson[optItemTypeRedfish] = ++ ++ if (!currValue) ++ { ++ BMCWEB_LOG_ERROR ++ << "Unable to get currValue, " ++ "no " ++ "std::string data in option " ++ "item value"; ++ continue; ++ } ++ ++ optItemJson["ValueDisplayName"] = ++ currValue != nullptr ? *currValue ++ : ""; ++ optItemJson["ValueName"] = + currValue != nullptr ? *currValue + : ""; + } +@@ -681,7 +844,21 @@ inline void requestRoutesBiosAttributeRegistry(App& app) + std::get_if<int64_t>( + &std::get<optItemValue>( + optItem)); +- optItemJson[optItemTypeRedfish] = ++ ++ if (!currValue) ++ { ++ BMCWEB_LOG_ERROR ++ << "Unable to get currValue, " ++ "no " ++ "int64_t data in option " ++ "item value"; ++ continue; ++ } ++ ++ optItemJson["ValueDisplayName"] = ++ currValue != nullptr ? *currValue ++ : 0; ++ optItemJson["ValueName"] = + currValue != nullptr ? *currValue + : 0; + } +@@ -689,6 +866,12 @@ inline void requestRoutesBiosAttributeRegistry(App& app) + optionsArray.push_back(optItemJson); + } + ++ if (optionsArray.empty()) ++ { ++ BMCWEB_LOG_ERROR << "optionsArray is empty"; ++ continue; ++ } ++ + attributeItem["Value"] = optionsArray; + attributeArray.push_back(attributeItem); + } +-- +2.25.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0007-Add-BiosAttributeRegistry-node-under-Registries.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0007-Add-BiosAttributeRegistry-node-under-Registries.patch new file mode 100644 index 000000000..dbd5700be --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/biosconfig/0007-Add-BiosAttributeRegistry-node-under-Registries.patch @@ -0,0 +1,76 @@ +From dd8160fefbac27d7f2ec99bf8b54c599083bcdbd Mon Sep 17 00:00:00 2001 +From: Snehalatha Venkatesh <snehalathax.v@intel.com> +Date: Tue, 28 Dec 2021 11:05:50 +0000 +Subject: [PATCH] Add BiosAttributeRegistry node under Registries. + +/redfish/v1/Registries/ is missing node BiosAttributeRegistry +under it. Added code to fix the same. + +Tested: +1.Ran Redfish Validator and passed. +2.GET - /redfish/v1/Registries/ + +Response: +{ +"@odata.id": "/redfish/v1/Registries", +"@odata.type": "#MessageRegistryFileCollection.MessageRegistryFileCollection", +"Description": "Collection of MessageRegistryFiles", +"Members": [ +{ +"@odata.id": "/redfish/v1/Registries/Base" +}, +{ +"@odata.id": "/redfish/v1/Registries/TaskEvent" +}, +{ +"@odata.id": "/redfish/v1/Registries/ResourceEvent" +}, +{ +"@odata.id": "/redfish/v1/Registries/BiosAttributeRegistry" +}, +{ +"@odata.id": "/redfish/v1/Registries/OpenBMC" +} +], +"Members@odata.count": 5, +"Name": "MessageRegistryFile Collection" +} + +Signed-off-by: Snehalatha Venkatesh <snehalathax.v@intel.com> +--- + redfish-core/lib/message_registries.hpp | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/redfish-core/lib/message_registries.hpp b/redfish-core/lib/message_registries.hpp +index d76f70b..4ae8383 100644 +--- a/redfish-core/lib/message_registries.hpp ++++ b/redfish-core/lib/message_registries.hpp +@@ -41,11 +41,12 @@ inline void handleMessageRegistryFileCollectionGet( + {"@odata.id", "/redfish/v1/Registries"}, + {"Name", "MessageRegistryFile Collection"}, + {"Description", "Collection of MessageRegistryFiles"}, +- {"Members@odata.count", 4}, ++ {"Members@odata.count", 5}, + {"Members", + {{{"@odata.id", "/redfish/v1/Registries/Base"}}, + {{"@odata.id", "/redfish/v1/Registries/TaskEvent"}}, + {{"@odata.id", "/redfish/v1/Registries/ResourceEvent"}}, ++ {{"@odata.id", "/redfish/v1/Registries/BiosAttributeRegistry"}}, + {{"@odata.id", "/redfish/v1/Registries/OpenBMC"}}}}}; + } + +@@ -89,6 +90,11 @@ inline void handleMessageRoutesMessageRegistryFileGet( + header = ®istries::resource_event::header; + url = registries::resource_event::url; + } ++ else if (registry == "BiosAttributeRegistry") ++ { ++ header = ®istries::bios::header; ++ dmtf.clear(); ++ } + else + { + messages::resourceNotFound( +-- +2.25.1 + |