From 13fe7b9607f68e1c002d38255f549b5bbeb7a264 Mon Sep 17 00:00:00 2001 From: Ivan Mikhaylov Date: Thu, 9 Jul 2020 15:29:04 +0300 Subject: meta-yadro: share boot initiator mailbox support Boot Initiator Mailbox should be available on all our hardware. This commit moves all required files and recipes to the meta-yadro. (From meta-yadro rev: 9ee3c28294c6a87912edbcf09b999b926634f836) Change-Id: Idc52bfb50c8f122662279a593de0ee40703ddb51 Signed-off-by: Alexander Filippov Signed-off-by: Ivan Mikhaylov Signed-off-by: Andrew Geissler --- .../Control/Boot/Mailbox.interface.yaml | 63 --- .../dbus/phosphor-dbus-interfaces_%.bbappend | 15 - ...-Add-support-for-persistent-only-settings.patch | 92 ---- ...02-Add-support-for-boot-initiator-mailbox.patch | 477 --------------------- .../ipmi/phosphor-ipmi-host_%.bbappend | 6 - .../Control/Boot/Mailbox.interface.yaml | 63 +++ .../dbus/phosphor-dbus-interfaces_%.bbappend | 15 + ...-Add-support-for-persistent-only-settings.patch | 92 ++++ ...02-Add-support-for-boot-initiator-mailbox.patch | 477 +++++++++++++++++++++ .../ipmi/phosphor-ipmi-host_%.bbappend | 6 + 10 files changed, 653 insertions(+), 653 deletions(-) delete mode 100644 meta-yadro/meta-nicole/recipes-phosphor/dbus/phosphor-dbus-interfaces/xyz/openbmc_project/Control/Boot/Mailbox.interface.yaml delete mode 100644 meta-yadro/meta-nicole/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend delete mode 100644 meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch delete mode 100644 meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Add-support-for-boot-initiator-mailbox.patch create mode 100644 meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces/xyz/openbmc_project/Control/Boot/Mailbox.interface.yaml create mode 100644 meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend create mode 100644 meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch create mode 100644 meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Add-support-for-boot-initiator-mailbox.patch create mode 100644 meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend diff --git a/meta-yadro/meta-nicole/recipes-phosphor/dbus/phosphor-dbus-interfaces/xyz/openbmc_project/Control/Boot/Mailbox.interface.yaml b/meta-yadro/meta-nicole/recipes-phosphor/dbus/phosphor-dbus-interfaces/xyz/openbmc_project/Control/Boot/Mailbox.interface.yaml deleted file mode 100644 index 839e8beca..000000000 --- a/meta-yadro/meta-nicole/recipes-phosphor/dbus/phosphor-dbus-interfaces/xyz/openbmc_project/Control/Boot/Mailbox.interface.yaml +++ /dev/null @@ -1,63 +0,0 @@ -description: > - Implement to provide the boot initiator (such as Petitboot or UEFI) - with its specific parameters. This is based on IPMI 2.0 Table 28-14 - 'Boot Option Parameters' parameter 7 'Boot initiator mailbox'. - -properties: - - name: Supported - type: boolean - flags: - - const - default: false - description: > - Specifies whether or not the mailbox is supported by the - boot initiator on this machine. - - The property is constant and is only set by the implementation - on startup. - - - name: IANAEnterpriseNumber - type: uint32 - flags: - - const - default: 0 - description: > - The 24-bit IANA Private Enterprise Number for the company or organization - that has specified the boot initiator. This is a machine-specific - constant. The implementing application is responsible for setting - this to the proper machine-specific value (0x000000..0xFFFFFF) - according to https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers. - - The property is constant and is only set by the implementation - on startup. - - - name: Data - type: array[byte] - description: > - The array of data bytes for the boot initiator to treat - in its specific way. This interface doesn't impose any - limitiations on the format or make any assumptions regarding - it. The boot initiator is responsible for parsing this array. - - The size of the array is a constant depending on the requirements - set by the boot initiator used for a particular architecture or - a machine. The implementing application is responsible for setting - the size of this array to the proper value. - - For conformance to the IPMI 2.0 specification, the size of the array - plus 3 (the size of IPMI 2.0 representation of IANA Enterprise Number) - must be a multiple of 16 with the minimum allowed size being 77 - (5 x 16-byte blocks, minus 3) if mailbox is at all Supported. - - For IPMI 2.0 this array is supposed to be split into 16-byte - blocks by the implementing service (block 0 being made of IANA PEN - plus first 13 bytes of this array). Please pay special attention - that this array does NOT include the IANA PEN needed for IPMI 2.0. - Only the actual PEN-specific data is stored here. - - When partially written to, the remaining parts of this array - must not be automatically cleared. This is per IPMI 2.0 - specification. - - Other interfaces to the boot initiator (such as MCTP) may process - this array differently. diff --git a/meta-yadro/meta-nicole/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend b/meta-yadro/meta-nicole/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend deleted file mode 100644 index 656e1514b..000000000 --- a/meta-yadro/meta-nicole/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend +++ /dev/null @@ -1,15 +0,0 @@ -FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" - -# Directory with new layer of source tree with additional files -YAML_DIR = "xyz" - -SRC_URI += "file://${YAML_DIR}" - -S = "${WORKDIR}/git" - -# Merge source tree by original project with our layer of additional files -do_add_yamls(){ - cp -r "${WORKDIR}/${YAML_DIR}" "${S}" -} - -addtask do_add_yamls after do_unpack before do_configure diff --git a/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch b/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch deleted file mode 100644 index f1e2c4ae4..000000000 --- a/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch +++ /dev/null @@ -1,92 +0,0 @@ -From aaf8a4a5b82baff679f557ed83b25af6ff2919cf Mon Sep 17 00:00:00 2001 -From: Alexander Amelkin -Date: Thu, 23 May 2019 20:39:57 +0300 -Subject: [PATCH] Add support for persistent-only settings - -Some settings such as Boot Initiator Mailbox do not support -one-time setting mode (as per IPMI 2.0 specification). - -This commit adds support for such persistent-only settings. - -Partially resolves openbmc/openbmc#3391 - -Change-Id: Iec8e2f5bddbc50d270916567effe334f10db2987 -Signed-off-by: Alexander Amelkin -Signed-off-by: Ivan Mikhaylov ---- - settings.cpp | 35 +++++++++++++++++++++++++++++++---- - 1 file changed, 31 insertions(+), 4 deletions(-) - -diff --git a/settings.cpp b/settings.cpp -index 2fa2511..6002365 100644 ---- a/settings.cpp -+++ b/settings.cpp -@@ -95,19 +95,44 @@ namespace boot - std::tuple setting(const Objects& objects, - const Interface& iface) - { -- constexpr auto bootObjCount = 2; -+ constexpr auto ambiguousOperationCount = 2; - constexpr auto oneTime = "one_time"; - constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable"; -+ bool oneTimeEnabled = false; - - const std::vector& paths = objects.map.at(iface); - auto count = paths.size(); -- if (count != bootObjCount) -+ if (!count) - { -- log("Exactly two objects expected", -+ // If there are no objects implementing the requested interface, -+ // that must be an error. -+ log("Interface objects not found", -+ entry("INTERFACE=%s", iface.c_str())); -+ elog(); -+ } -+ else if (count < ambiguousOperationCount) -+ { -+ // On the contrary, if there is just one object, that may mean -+ // that this particular interface doesn't support one-time -+ // setting mode (e.g. Boot Initiator Mailbox). -+ // That is not an error, just return the regular setting. -+ // If there's just one object, that's the only kind of setting -+ // mode this interface supports, so just return that setting path. -+ const Path& regularSetting = paths[0]; -+ return std::make_tuple(regularSetting, oneTimeEnabled); -+ } -+ else if (count > ambiguousOperationCount) -+ { -+ // Something must be wrong if there are more objects than expected -+ log("Exactly 1 or 2 interface objects are required", - entry("INTERFACE=%s", iface.c_str()), - entry("COUNT=%d", count)); - elog(); - } -+ -+ // We are here because there were exactly two objects implementing the -+ // same interface. Take those two and find out which of them is the -+ // one-time setting, consider the other the persistent setting. - size_t index = 0; - if (std::string::npos == paths[0].rfind(oneTime)) - { -@@ -116,6 +141,8 @@ std::tuple setting(const Objects& objects, - const Path& oneTimeSetting = paths[index]; - const Path& regularSetting = paths[!index]; - -+ // Now see if the one-time setting is enabled and return the path for it -+ // if so. Otherwise return the path for the persistent setting. - auto method = objects.bus.new_method_call( - objects.service(oneTimeSetting, iface).c_str(), oneTimeSetting.c_str(), - ipmi::PROP_INTF, "Get"); -@@ -131,7 +158,7 @@ std::tuple setting(const Objects& objects, - - std::variant enabled; - reply.read(enabled); -- auto oneTimeEnabled = std::get(enabled); -+ oneTimeEnabled = std::get(enabled); - const Path& setting = oneTimeEnabled ? oneTimeSetting : regularSetting; - return std::make_tuple(setting, oneTimeEnabled); - } --- -2.21.1 - diff --git a/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Add-support-for-boot-initiator-mailbox.patch b/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Add-support-for-boot-initiator-mailbox.patch deleted file mode 100644 index 922426ef4..000000000 --- a/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Add-support-for-boot-initiator-mailbox.patch +++ /dev/null @@ -1,477 +0,0 @@ -From f19ca89265616e14ba2bb16d9a5418f23157c943 Mon Sep 17 00:00:00 2001 -From: Alexander Amelkin -Date: Mon, 8 Apr 2019 17:58:42 +0300 -Subject: [PATCH] Add support for boot initiator mailbox - -Add handlers to process the chassis system option 7 -(boot initiator mailbox). The format of mailbox is -specific to the machine/bootloader. This commit only -adds generic handlers to process getting and setting -of the mailbox data regardless of the content. - -Only the IANA Enterprise number is checked in the data -block 0. Also checked are the data boundaries. - -It is expected that a machine-specific override for -phosphor-settingsd sets the supported state and -the IANA number according to the used bootloader. - -Resolves openbmc/openbmc#3391 - -Change-Id: Iccbf74c0775f20c70e8deaa7b0a8bd995ebbffea -Signed-off-by: Alexander Amelkin -Signed-off-by: Ivan Mikhaylov ---- - chassishandler.cpp | 365 ++++++++++++++++++++++++++++++++++++++++++++- - chassishandler.hpp | 2 + - 2 files changed, 362 insertions(+), 5 deletions(-) - -diff --git a/chassishandler.cpp b/chassishandler.cpp -index 0326806..538154c 100644 ---- a/chassishandler.cpp -+++ b/chassishandler.cpp -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -125,6 +126,7 @@ namespace internal - { - - constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode"; -+constexpr auto bootMboxIntf = "xyz.openbmc_project.Control.Boot.Mailbox"; - constexpr auto bootSourceIntf = "xyz.openbmc_project.Control.Boot.Source"; - constexpr auto powerRestoreIntf = - "xyz.openbmc_project.Control.Power.RestorePolicy"; -@@ -140,8 +142,8 @@ settings::Objects& getObjects() - if (objectsPtr == nullptr) - { - objectsPtr = std::make_unique( -- dbus, std::vector{bootModeIntf, bootSourceIntf, -- powerRestoreIntf}); -+ dbus, std::vector{bootMboxIntf, bootModeIntf, -+ bootSourceIntf, powerRestoreIntf}); - } - return *objectsPtr; - } -@@ -177,6 +179,20 @@ struct set_sys_boot_options_t - uint8_t data[SIZE_BOOT_OPTION]; - } __attribute__((packed)); - -+struct BootMboxBlock -+{ -+ uint8_t block; -+ union -+ { -+ struct -+ { -+ uint8_t ipmiIANAEnterprise[3]; -+ uint8_t blockZeroData[13]; -+ }; -+ uint8_t data[16]; -+ }; -+} __attribute__((packed)); -+ - int getHostNetworkData(get_sys_boot_options_response_t* respptr) - { - ipmi::PropertyMap properties; -@@ -1443,6 +1459,124 @@ static ipmi_ret_t setBootMode(const Mode::Modes& mode) - return IPMI_CC_OK; - } - -+using MboxVec = std::vector; -+ -+// Check if Boot Mailbox is supported. -+static std::optional isBootMboxSupported() -+{ -+ using namespace chassis::internal; -+ using namespace chassis::internal::cache; -+ -+ try -+ { -+ settings::Objects& objects = getObjects(); -+ auto bootMbox = settings::boot::setting(objects, bootMboxIntf); -+ const auto& bootMboxSetting = std::get(bootMbox); -+ auto method = dbus.new_method_call( -+ objects.service(bootMboxSetting, bootMboxIntf).c_str(), -+ bootMboxSetting.c_str(), ipmi::PROP_INTF, "Get"); -+ -+ method.append(bootMboxIntf, "Supported"); -+ auto reply = dbus.call(method); -+ std::variant result; -+ reply.read(result); -+ return std::get(result); -+ } -+ catch (const std::exception& e) -+ { -+ log("Error getting Boot/Mailbox/Supported", -+ entry("ERROR=%s", e.what())); -+ report(); -+ return std::nullopt; -+ } -+} -+ -+static std::optional getBootMboxIANA() -+{ -+ using namespace chassis::internal; -+ using namespace chassis::internal::cache; -+ -+ try -+ { -+ settings::Objects& objects = getObjects(); -+ auto bootMbox = settings::boot::setting(objects, bootMboxIntf); -+ const auto& bootMboxSetting = std::get(bootMbox); -+ auto method = dbus.new_method_call( -+ objects.service(bootMboxSetting, bootMboxIntf).c_str(), -+ bootMboxSetting.c_str(), ipmi::PROP_INTF, "Get"); -+ -+ method.append(bootMboxIntf, "IANAEnterpriseNumber"); -+ auto reply = dbus.call(method); -+ std::variant result; -+ reply.read(result); -+ return std::get(result); -+ } -+ catch (const std::exception& e) -+ { -+ log("Error getting Boot/Mailbox/IANAEnterpriseNumber", -+ entry("ERROR=%s", e.what())); -+ report(); -+ return std::nullopt; -+ } -+} -+ -+static std::optional getBootMbox() -+{ -+ using namespace chassis::internal; -+ using namespace chassis::internal::cache; -+ -+ try -+ { -+ settings::Objects& objects = getObjects(); -+ auto bootMbox = settings::boot::setting(objects, bootMboxIntf); -+ const auto& bootMboxSetting = std::get(bootMbox); -+ auto method = dbus.new_method_call( -+ objects.service(bootMboxSetting, bootMboxIntf).c_str(), -+ bootMboxSetting.c_str(), ipmi::PROP_INTF, "Get"); -+ -+ method.append(bootMboxIntf, "Data"); -+ auto reply = dbus.call(method); -+ std::variant result; -+ reply.read(result); -+ return std::get(result); -+ } -+ catch (const std::exception& e) -+ { -+ log("Error getting Boot/Mailbox/Data", -+ entry("ERROR=%s", e.what())); -+ report(); -+ return std::nullopt; -+ } -+} -+ -+static bool setBootMbox(MboxVec data) -+{ -+ using namespace chassis::internal; -+ using namespace chassis::internal::cache; -+ -+ try -+ { -+ settings::Objects& objects = getObjects(); -+ std::variant property(data); -+ auto bootMbox = settings::boot::setting(objects, bootMboxIntf); -+ const auto& bootMboxSetting = std::get(bootMbox); -+ auto method = dbus.new_method_call( -+ objects.service(bootMboxSetting, bootMboxIntf).c_str(), -+ bootMboxSetting.c_str(), ipmi::PROP_INTF, "Set"); -+ -+ method.append(bootMboxIntf, "Data", property); -+ dbus.call(method); -+ return true; -+ } -+ catch (const std::exception& e) -+ { -+ log("Error setting Boot/Mailbox/Data", -+ entry("ERROR=%s", e.what())); -+ report(); -+ return false; -+ } -+} -+ - ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, - ipmi_request_t request, - ipmi_response_t response, -@@ -1543,6 +1677,106 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, - return IPMI_CC_UNSPECIFIED_ERROR; - } - } -+ else if (reqptr->parameter == -+ static_cast(BootOptionParameter::BOOT_INITIATOR_MBOX)) -+ { -+ // Only allow reading the boot initiator mailbox if Mailbox is supported -+ // -+ // Algorithm: -+ // 1. Get 'Supported' property from the Control.Boot.Mailbox interface -+ // 2. If {1} is 'false', report Parameter not supported (0x80) -+ // 3. Get Block Selector from request -+ // 4. Get 'Data' vector from Control.Boot.Mailbox -+ // 5. If requested block {3} exceeds total vector size {4}, -+ // report Out of space (0xC4) -+ // 6. Return the selected block (16 bytes) from the vector -+ -+ BootMboxBlock* rspMboxData = -+ reinterpret_cast(resp->data); -+ -+ *data_len = 0; // Assume an error and no data -+ -+ resp->parm = -+ static_cast(BootOptionParameter::BOOT_INITIATOR_MBOX); -+ -+ try -+ { -+ // Check whether this option is supported -+ std::optional isSupported = isBootMboxSupported(); -+ if (!isSupported) -+ { -+ return IPMI_CC_UNSPECIFIED_ERROR; -+ } -+ -+ if (!*isSupported) -+ { -+ log("Attempt to read unsupported Boot/Mailbox"); -+ return IPMI_CC_PARM_NOT_SUPPORTED; -+ } -+ rc = IPMI_CC_OK; -+ -+ // Requested block -+ IpmiValue reqBlock = reqptr->set; // Use "set selector" -+ rspMboxData->block = reqBlock; -+ -+ // Initially assume it's block 1+ -+ uint8_t* rspBlockPtr = rspMboxData->data; -+ size_t blockDataSize = sizeof(rspMboxData->data); -+ size_t dataVecStartOffset = reqBlock * blockDataSize - -+ sizeof(rspMboxData->ipmiIANAEnterprise); -+ -+ // Adjust pointers and sizes for block 0, and fill in the IANA PEN -+ if (0 == reqBlock) -+ { -+ ipmi::message::Payload tmpPayload; -+ std::optional IANAEnterprise = getBootMboxIANA(); -+ if (!IANAEnterprise) -+ { -+ return IPMI_CC_INVALID; -+ } -+ tmpPayload.pack((uint32_t)*IANAEnterprise); -+ std::copy(tmpPayload.raw.begin(), tmpPayload.raw.end(), -+ rspMboxData->ipmiIANAEnterprise); -+ -+ rspBlockPtr = rspMboxData->blockZeroData; -+ blockDataSize = sizeof(rspMboxData->blockZeroData); -+ dataVecStartOffset = 0; -+ } -+ -+ // Get the total data size -+ std::optional dataVec = getBootMbox(); -+ if (!dataVec) -+ { -+ return IPMI_CC_INVALID; -+ } -+ -+ // Does the requested block exist? -+ if ((*dataVec).size() < dataVecStartOffset + blockDataSize) -+ { -+ size_t total_size = -+ (*dataVec).size() + sizeof(rspMboxData->ipmiIANAEnterprise); -+ size_t normalBlockSize = sizeof(rspMboxData->data); -+ log( -+ "Attempt to read unsupported block", -+ entry("REQUESTED_BLOCK=%d", reqBlock), -+ entry("MAX_BLOCK=%d", total_size / normalBlockSize)); -+ return IPMI_CC_PARM_OUT_OF_RANGE; -+ } -+ -+ // Copy the data to response from specified offset in d-bus vector -+ for (size_t i = 0; i < blockDataSize; ++i) -+ { -+ rspBlockPtr[i] = (*dataVec)[dataVecStartOffset + i]; -+ } -+ *data_len = static_cast( -+ BootOptionResponseSize::BOOT_INITIATOR_MBOX); -+ } -+ catch (InternalFailure& e) -+ { -+ report(); -+ return IPMI_CC_UNSPECIFIED_ERROR; -+ } -+ } - else if (reqptr->parameter == - static_cast(BootOptionParameter::OPAL_NETWORK_SETTINGS)) - { -@@ -1599,11 +1833,9 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, - // This IPMI command does not have any resposne data - *data_len = 0; - -- /* 000101 -+ /* - * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. -- * This is the only parameter used by petitboot. - */ -- - if (reqptr->parameter == (uint8_t)BootOptionParameter::BOOT_FLAGS) - { - IpmiValue bootOption = ((reqptr->data[1] & 0x3C) >> 2); -@@ -1697,6 +1929,129 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, - return IPMI_CC_UNSPECIFIED_ERROR; - } - } -+ else if (reqptr->parameter == -+ static_cast(BootOptionParameter::BOOT_INITIATOR_MBOX)) -+ { -+ // Only allow writing to boot initiator mailbox if: -+ // 1. Mailbox is supported -+ // 2. IANA PEN matches. -+ // -+ // Algorithm: -+ // 1. Get 'Supported' property from Control.Boot.Mailbox interface -+ // 2. If {1} is 'false', report Parameter not supported (0x80) -+ // 3. Get Block Selector from request -+ // 4. Get 'Data' array from Control.Boot.Mailbox -+ // 5. If requested block {3} exceeds total vector size {4}, -+ // report Out of range (0xC9) -+ // 6. If requsted block {3} is 0: -+ // 4.1. Get IANA PEN from request -+ // 4.2. Get 'IANAEnterpriseNumber' property from Control.Boot.Mailbox -+ // 4.3. If {4.1} doesn't match {4.2}, report 0xCC error (Invalid -+ // data field in request) -+ // 7. Overwrite the 16 bytes at offset {3}*16 with the data from request -+ // 8. Update the 'Data' array in Control.Boot.Mailbox -+ -+ BootMboxBlock* reqMboxData = -+ reinterpret_cast(reqptr->data); -+ -+ try -+ { -+ std::optional isSupported = isBootMboxSupported(); -+ if (!isSupported) -+ { -+ return IPMI_CC_UNSPECIFIED_ERROR; -+ } -+ -+ if (!*isSupported) -+ { -+ log("Attempt to read unsupported Boot/Mailbox"); -+ return IPMI_CC_PARM_NOT_SUPPORTED; -+ } -+ -+ // Requested block -+ IpmiValue reqBlock = reqMboxData->block; -+ -+ // Initially assume it's block 1+ -+ uint8_t* reqBlockPtr = reqMboxData->data; -+ size_t blockDataSize = sizeof(reqMboxData->data); -+ size_t dataVecStartOffset = reqBlock * blockDataSize - -+ sizeof(reqMboxData->ipmiIANAEnterprise); -+ -+ // Adjust pointers and sizes for block 0, and fill in the IANA PEN -+ if (0 == reqBlock) -+ { -+ uint24_t reqIANAEnterprise; -+ std::vector tmp( -+ &reqMboxData->ipmiIANAEnterprise[0], -+ &reqMboxData->ipmiIANAEnterprise[0] + -+ sizeof(reqMboxData->ipmiIANAEnterprise)); -+ ipmi::message::Payload tmpPayload( -+ std::forward>(tmp)); -+ ipmi::Cc unpackError = tmpPayload.unpack(reqIANAEnterprise); -+ if (unpackError != ipmi::ccSuccess) -+ { -+ return unpackError; -+ } -+ -+ std::optional IANAEnterprise = getBootMboxIANA(); -+ if (!IANAEnterprise) -+ { -+ return IPMI_CC_INVALID; -+ } -+ -+ if (*IANAEnterprise != reqIANAEnterprise) -+ { -+ log( -+ "Unsupported IANA Enterprise number", -+ entry("REQUESTED_IANA=%d", -+ static_cast(reqIANAEnterprise)), -+ entry("SUPPORTED_IANA=%d", -+ static_cast(*IANAEnterprise))); -+ return IPMI_CC_INVALID_FIELD_REQUEST; -+ } -+ -+ // For block 0 operate on data after IANA PEN -+ reqBlockPtr = reqMboxData->blockZeroData; -+ blockDataSize = sizeof(reqMboxData->blockZeroData); -+ dataVecStartOffset = 0; -+ } -+ -+ // Get the data vector from d-bus -+ std::optional dataVec = getBootMbox(); -+ if (!dataVec) -+ { -+ return IPMI_CC_INVALID; -+ } -+ -+ // Does the requested block exist? -+ if ((*dataVec).size() < dataVecStartOffset + blockDataSize) -+ { -+ size_t total_size = -+ (*dataVec).size() + sizeof(reqMboxData->ipmiIANAEnterprise); -+ size_t normalBlockSize = sizeof(reqMboxData->data); -+ log( -+ "Attempt to read unsupported block", -+ entry("REQUESTED_BLOCK=%d", reqBlock), -+ entry("MAX_BLOCK=%d", total_size / normalBlockSize)); -+ return IPMI_CC_PARM_OUT_OF_RANGE; -+ } -+ -+ // Copy the data from request to specified offset in d-bus vector -+ for (size_t i = 0; i < blockDataSize; ++i) -+ { -+ (*dataVec)[dataVecStartOffset + i] = reqBlockPtr[i]; -+ } -+ if (setBootMbox(*dataVec)) -+ { -+ rc = IPMI_CC_OK; -+ } -+ } -+ catch (InternalFailure& e) -+ { -+ report(); -+ return IPMI_CC_UNSPECIFIED_ERROR; -+ } -+ } - else if (reqptr->parameter == - (uint8_t)BootOptionParameter::OPAL_NETWORK_SETTINGS) - { -diff --git a/chassishandler.hpp b/chassishandler.hpp -index dcaf06c..0e738e9 100644 ---- a/chassishandler.hpp -+++ b/chassishandler.hpp -@@ -48,12 +48,14 @@ enum class BootOptionParameter : size_t - { - BOOT_INFO = 0x4, - BOOT_FLAGS = 0x5, -+ BOOT_INITIATOR_MBOX = 0x07, - OPAL_NETWORK_SETTINGS = 0x61 - }; - - enum class BootOptionResponseSize : size_t - { - BOOT_FLAGS = 5, -+ BOOT_INITIATOR_MBOX = 17, - OPAL_NETWORK_SETTINGS = 50 - }; - --- -2.21.1 - diff --git a/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend b/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend index 1503d72ac..7983e94bb 100644 --- a/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend +++ b/meta-yadro/meta-nicole/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend @@ -1,4 +1,3 @@ -FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" DEPENDS_append = " nicole-yaml-config" EXTRA_OECONF = " \ @@ -6,8 +5,3 @@ EXTRA_OECONF = " \ INVSENSOR_YAML_GEN=${STAGING_DIR_HOST}${datadir}/nicole-yaml-config/ipmi-inventory-sensors.yaml \ FRU_YAML_GEN=${STAGING_DIR_HOST}${datadir}/nicole-yaml-config/ipmi-fru-read.yaml \ " - -SRC_URI_append = "\ - file://0001-Add-support-for-persistent-only-settings.patch \ - file://0002-Add-support-for-boot-initiator-mailbox.patch \ -" diff --git a/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces/xyz/openbmc_project/Control/Boot/Mailbox.interface.yaml b/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces/xyz/openbmc_project/Control/Boot/Mailbox.interface.yaml new file mode 100644 index 000000000..839e8beca --- /dev/null +++ b/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces/xyz/openbmc_project/Control/Boot/Mailbox.interface.yaml @@ -0,0 +1,63 @@ +description: > + Implement to provide the boot initiator (such as Petitboot or UEFI) + with its specific parameters. This is based on IPMI 2.0 Table 28-14 + 'Boot Option Parameters' parameter 7 'Boot initiator mailbox'. + +properties: + - name: Supported + type: boolean + flags: + - const + default: false + description: > + Specifies whether or not the mailbox is supported by the + boot initiator on this machine. + + The property is constant and is only set by the implementation + on startup. + + - name: IANAEnterpriseNumber + type: uint32 + flags: + - const + default: 0 + description: > + The 24-bit IANA Private Enterprise Number for the company or organization + that has specified the boot initiator. This is a machine-specific + constant. The implementing application is responsible for setting + this to the proper machine-specific value (0x000000..0xFFFFFF) + according to https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers. + + The property is constant and is only set by the implementation + on startup. + + - name: Data + type: array[byte] + description: > + The array of data bytes for the boot initiator to treat + in its specific way. This interface doesn't impose any + limitiations on the format or make any assumptions regarding + it. The boot initiator is responsible for parsing this array. + + The size of the array is a constant depending on the requirements + set by the boot initiator used for a particular architecture or + a machine. The implementing application is responsible for setting + the size of this array to the proper value. + + For conformance to the IPMI 2.0 specification, the size of the array + plus 3 (the size of IPMI 2.0 representation of IANA Enterprise Number) + must be a multiple of 16 with the minimum allowed size being 77 + (5 x 16-byte blocks, minus 3) if mailbox is at all Supported. + + For IPMI 2.0 this array is supposed to be split into 16-byte + blocks by the implementing service (block 0 being made of IANA PEN + plus first 13 bytes of this array). Please pay special attention + that this array does NOT include the IANA PEN needed for IPMI 2.0. + Only the actual PEN-specific data is stored here. + + When partially written to, the remaining parts of this array + must not be automatically cleared. This is per IPMI 2.0 + specification. + + Other interfaces to the boot initiator (such as MCTP) may process + this array differently. diff --git a/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend b/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend new file mode 100644 index 000000000..656e1514b --- /dev/null +++ b/meta-yadro/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend @@ -0,0 +1,15 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +# Directory with new layer of source tree with additional files +YAML_DIR = "xyz" + +SRC_URI += "file://${YAML_DIR}" + +S = "${WORKDIR}/git" + +# Merge source tree by original project with our layer of additional files +do_add_yamls(){ + cp -r "${WORKDIR}/${YAML_DIR}" "${S}" +} + +addtask do_add_yamls after do_unpack before do_configure diff --git a/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch b/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch new file mode 100644 index 000000000..f1e2c4ae4 --- /dev/null +++ b/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Add-support-for-persistent-only-settings.patch @@ -0,0 +1,92 @@ +From aaf8a4a5b82baff679f557ed83b25af6ff2919cf Mon Sep 17 00:00:00 2001 +From: Alexander Amelkin +Date: Thu, 23 May 2019 20:39:57 +0300 +Subject: [PATCH] Add support for persistent-only settings + +Some settings such as Boot Initiator Mailbox do not support +one-time setting mode (as per IPMI 2.0 specification). + +This commit adds support for such persistent-only settings. + +Partially resolves openbmc/openbmc#3391 + +Change-Id: Iec8e2f5bddbc50d270916567effe334f10db2987 +Signed-off-by: Alexander Amelkin +Signed-off-by: Ivan Mikhaylov +--- + settings.cpp | 35 +++++++++++++++++++++++++++++++---- + 1 file changed, 31 insertions(+), 4 deletions(-) + +diff --git a/settings.cpp b/settings.cpp +index 2fa2511..6002365 100644 +--- a/settings.cpp ++++ b/settings.cpp +@@ -95,19 +95,44 @@ namespace boot + std::tuple setting(const Objects& objects, + const Interface& iface) + { +- constexpr auto bootObjCount = 2; ++ constexpr auto ambiguousOperationCount = 2; + constexpr auto oneTime = "one_time"; + constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable"; ++ bool oneTimeEnabled = false; + + const std::vector& paths = objects.map.at(iface); + auto count = paths.size(); +- if (count != bootObjCount) ++ if (!count) + { +- log("Exactly two objects expected", ++ // If there are no objects implementing the requested interface, ++ // that must be an error. ++ log("Interface objects not found", ++ entry("INTERFACE=%s", iface.c_str())); ++ elog(); ++ } ++ else if (count < ambiguousOperationCount) ++ { ++ // On the contrary, if there is just one object, that may mean ++ // that this particular interface doesn't support one-time ++ // setting mode (e.g. Boot Initiator Mailbox). ++ // That is not an error, just return the regular setting. ++ // If there's just one object, that's the only kind of setting ++ // mode this interface supports, so just return that setting path. ++ const Path& regularSetting = paths[0]; ++ return std::make_tuple(regularSetting, oneTimeEnabled); ++ } ++ else if (count > ambiguousOperationCount) ++ { ++ // Something must be wrong if there are more objects than expected ++ log("Exactly 1 or 2 interface objects are required", + entry("INTERFACE=%s", iface.c_str()), + entry("COUNT=%d", count)); + elog(); + } ++ ++ // We are here because there were exactly two objects implementing the ++ // same interface. Take those two and find out which of them is the ++ // one-time setting, consider the other the persistent setting. + size_t index = 0; + if (std::string::npos == paths[0].rfind(oneTime)) + { +@@ -116,6 +141,8 @@ std::tuple setting(const Objects& objects, + const Path& oneTimeSetting = paths[index]; + const Path& regularSetting = paths[!index]; + ++ // Now see if the one-time setting is enabled and return the path for it ++ // if so. Otherwise return the path for the persistent setting. + auto method = objects.bus.new_method_call( + objects.service(oneTimeSetting, iface).c_str(), oneTimeSetting.c_str(), + ipmi::PROP_INTF, "Get"); +@@ -131,7 +158,7 @@ std::tuple setting(const Objects& objects, + + std::variant enabled; + reply.read(enabled); +- auto oneTimeEnabled = std::get(enabled); ++ oneTimeEnabled = std::get(enabled); + const Path& setting = oneTimeEnabled ? oneTimeSetting : regularSetting; + return std::make_tuple(setting, oneTimeEnabled); + } +-- +2.21.1 + diff --git a/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Add-support-for-boot-initiator-mailbox.patch b/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Add-support-for-boot-initiator-mailbox.patch new file mode 100644 index 000000000..922426ef4 --- /dev/null +++ b/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Add-support-for-boot-initiator-mailbox.patch @@ -0,0 +1,477 @@ +From f19ca89265616e14ba2bb16d9a5418f23157c943 Mon Sep 17 00:00:00 2001 +From: Alexander Amelkin +Date: Mon, 8 Apr 2019 17:58:42 +0300 +Subject: [PATCH] Add support for boot initiator mailbox + +Add handlers to process the chassis system option 7 +(boot initiator mailbox). The format of mailbox is +specific to the machine/bootloader. This commit only +adds generic handlers to process getting and setting +of the mailbox data regardless of the content. + +Only the IANA Enterprise number is checked in the data +block 0. Also checked are the data boundaries. + +It is expected that a machine-specific override for +phosphor-settingsd sets the supported state and +the IANA number according to the used bootloader. + +Resolves openbmc/openbmc#3391 + +Change-Id: Iccbf74c0775f20c70e8deaa7b0a8bd995ebbffea +Signed-off-by: Alexander Amelkin +Signed-off-by: Ivan Mikhaylov +--- + chassishandler.cpp | 365 ++++++++++++++++++++++++++++++++++++++++++++- + chassishandler.hpp | 2 + + 2 files changed, 362 insertions(+), 5 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 0326806..538154c 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -125,6 +126,7 @@ namespace internal + { + + constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode"; ++constexpr auto bootMboxIntf = "xyz.openbmc_project.Control.Boot.Mailbox"; + constexpr auto bootSourceIntf = "xyz.openbmc_project.Control.Boot.Source"; + constexpr auto powerRestoreIntf = + "xyz.openbmc_project.Control.Power.RestorePolicy"; +@@ -140,8 +142,8 @@ settings::Objects& getObjects() + if (objectsPtr == nullptr) + { + objectsPtr = std::make_unique( +- dbus, std::vector{bootModeIntf, bootSourceIntf, +- powerRestoreIntf}); ++ dbus, std::vector{bootMboxIntf, bootModeIntf, ++ bootSourceIntf, powerRestoreIntf}); + } + return *objectsPtr; + } +@@ -177,6 +179,20 @@ struct set_sys_boot_options_t + uint8_t data[SIZE_BOOT_OPTION]; + } __attribute__((packed)); + ++struct BootMboxBlock ++{ ++ uint8_t block; ++ union ++ { ++ struct ++ { ++ uint8_t ipmiIANAEnterprise[3]; ++ uint8_t blockZeroData[13]; ++ }; ++ uint8_t data[16]; ++ }; ++} __attribute__((packed)); ++ + int getHostNetworkData(get_sys_boot_options_response_t* respptr) + { + ipmi::PropertyMap properties; +@@ -1443,6 +1459,124 @@ static ipmi_ret_t setBootMode(const Mode::Modes& mode) + return IPMI_CC_OK; + } + ++using MboxVec = std::vector; ++ ++// Check if Boot Mailbox is supported. ++static std::optional isBootMboxSupported() ++{ ++ using namespace chassis::internal; ++ using namespace chassis::internal::cache; ++ ++ try ++ { ++ settings::Objects& objects = getObjects(); ++ auto bootMbox = settings::boot::setting(objects, bootMboxIntf); ++ const auto& bootMboxSetting = std::get(bootMbox); ++ auto method = dbus.new_method_call( ++ objects.service(bootMboxSetting, bootMboxIntf).c_str(), ++ bootMboxSetting.c_str(), ipmi::PROP_INTF, "Get"); ++ ++ method.append(bootMboxIntf, "Supported"); ++ auto reply = dbus.call(method); ++ std::variant result; ++ reply.read(result); ++ return std::get(result); ++ } ++ catch (const std::exception& e) ++ { ++ log("Error getting Boot/Mailbox/Supported", ++ entry("ERROR=%s", e.what())); ++ report(); ++ return std::nullopt; ++ } ++} ++ ++static std::optional getBootMboxIANA() ++{ ++ using namespace chassis::internal; ++ using namespace chassis::internal::cache; ++ ++ try ++ { ++ settings::Objects& objects = getObjects(); ++ auto bootMbox = settings::boot::setting(objects, bootMboxIntf); ++ const auto& bootMboxSetting = std::get(bootMbox); ++ auto method = dbus.new_method_call( ++ objects.service(bootMboxSetting, bootMboxIntf).c_str(), ++ bootMboxSetting.c_str(), ipmi::PROP_INTF, "Get"); ++ ++ method.append(bootMboxIntf, "IANAEnterpriseNumber"); ++ auto reply = dbus.call(method); ++ std::variant result; ++ reply.read(result); ++ return std::get(result); ++ } ++ catch (const std::exception& e) ++ { ++ log("Error getting Boot/Mailbox/IANAEnterpriseNumber", ++ entry("ERROR=%s", e.what())); ++ report(); ++ return std::nullopt; ++ } ++} ++ ++static std::optional getBootMbox() ++{ ++ using namespace chassis::internal; ++ using namespace chassis::internal::cache; ++ ++ try ++ { ++ settings::Objects& objects = getObjects(); ++ auto bootMbox = settings::boot::setting(objects, bootMboxIntf); ++ const auto& bootMboxSetting = std::get(bootMbox); ++ auto method = dbus.new_method_call( ++ objects.service(bootMboxSetting, bootMboxIntf).c_str(), ++ bootMboxSetting.c_str(), ipmi::PROP_INTF, "Get"); ++ ++ method.append(bootMboxIntf, "Data"); ++ auto reply = dbus.call(method); ++ std::variant result; ++ reply.read(result); ++ return std::get(result); ++ } ++ catch (const std::exception& e) ++ { ++ log("Error getting Boot/Mailbox/Data", ++ entry("ERROR=%s", e.what())); ++ report(); ++ return std::nullopt; ++ } ++} ++ ++static bool setBootMbox(MboxVec data) ++{ ++ using namespace chassis::internal; ++ using namespace chassis::internal::cache; ++ ++ try ++ { ++ settings::Objects& objects = getObjects(); ++ std::variant property(data); ++ auto bootMbox = settings::boot::setting(objects, bootMboxIntf); ++ const auto& bootMboxSetting = std::get(bootMbox); ++ auto method = dbus.new_method_call( ++ objects.service(bootMboxSetting, bootMboxIntf).c_str(), ++ bootMboxSetting.c_str(), ipmi::PROP_INTF, "Set"); ++ ++ method.append(bootMboxIntf, "Data", property); ++ dbus.call(method); ++ return true; ++ } ++ catch (const std::exception& e) ++ { ++ log("Error setting Boot/Mailbox/Data", ++ entry("ERROR=%s", e.what())); ++ report(); ++ return false; ++ } ++} ++ + ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, +@@ -1543,6 +1677,106 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + return IPMI_CC_UNSPECIFIED_ERROR; + } + } ++ else if (reqptr->parameter == ++ static_cast(BootOptionParameter::BOOT_INITIATOR_MBOX)) ++ { ++ // Only allow reading the boot initiator mailbox if Mailbox is supported ++ // ++ // Algorithm: ++ // 1. Get 'Supported' property from the Control.Boot.Mailbox interface ++ // 2. If {1} is 'false', report Parameter not supported (0x80) ++ // 3. Get Block Selector from request ++ // 4. Get 'Data' vector from Control.Boot.Mailbox ++ // 5. If requested block {3} exceeds total vector size {4}, ++ // report Out of space (0xC4) ++ // 6. Return the selected block (16 bytes) from the vector ++ ++ BootMboxBlock* rspMboxData = ++ reinterpret_cast(resp->data); ++ ++ *data_len = 0; // Assume an error and no data ++ ++ resp->parm = ++ static_cast(BootOptionParameter::BOOT_INITIATOR_MBOX); ++ ++ try ++ { ++ // Check whether this option is supported ++ std::optional isSupported = isBootMboxSupported(); ++ if (!isSupported) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ ++ if (!*isSupported) ++ { ++ log("Attempt to read unsupported Boot/Mailbox"); ++ return IPMI_CC_PARM_NOT_SUPPORTED; ++ } ++ rc = IPMI_CC_OK; ++ ++ // Requested block ++ IpmiValue reqBlock = reqptr->set; // Use "set selector" ++ rspMboxData->block = reqBlock; ++ ++ // Initially assume it's block 1+ ++ uint8_t* rspBlockPtr = rspMboxData->data; ++ size_t blockDataSize = sizeof(rspMboxData->data); ++ size_t dataVecStartOffset = reqBlock * blockDataSize - ++ sizeof(rspMboxData->ipmiIANAEnterprise); ++ ++ // Adjust pointers and sizes for block 0, and fill in the IANA PEN ++ if (0 == reqBlock) ++ { ++ ipmi::message::Payload tmpPayload; ++ std::optional IANAEnterprise = getBootMboxIANA(); ++ if (!IANAEnterprise) ++ { ++ return IPMI_CC_INVALID; ++ } ++ tmpPayload.pack((uint32_t)*IANAEnterprise); ++ std::copy(tmpPayload.raw.begin(), tmpPayload.raw.end(), ++ rspMboxData->ipmiIANAEnterprise); ++ ++ rspBlockPtr = rspMboxData->blockZeroData; ++ blockDataSize = sizeof(rspMboxData->blockZeroData); ++ dataVecStartOffset = 0; ++ } ++ ++ // Get the total data size ++ std::optional dataVec = getBootMbox(); ++ if (!dataVec) ++ { ++ return IPMI_CC_INVALID; ++ } ++ ++ // Does the requested block exist? ++ if ((*dataVec).size() < dataVecStartOffset + blockDataSize) ++ { ++ size_t total_size = ++ (*dataVec).size() + sizeof(rspMboxData->ipmiIANAEnterprise); ++ size_t normalBlockSize = sizeof(rspMboxData->data); ++ log( ++ "Attempt to read unsupported block", ++ entry("REQUESTED_BLOCK=%d", reqBlock), ++ entry("MAX_BLOCK=%d", total_size / normalBlockSize)); ++ return IPMI_CC_PARM_OUT_OF_RANGE; ++ } ++ ++ // Copy the data to response from specified offset in d-bus vector ++ for (size_t i = 0; i < blockDataSize; ++i) ++ { ++ rspBlockPtr[i] = (*dataVec)[dataVecStartOffset + i]; ++ } ++ *data_len = static_cast( ++ BootOptionResponseSize::BOOT_INITIATOR_MBOX); ++ } ++ catch (InternalFailure& e) ++ { ++ report(); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ } + else if (reqptr->parameter == + static_cast(BootOptionParameter::OPAL_NETWORK_SETTINGS)) + { +@@ -1599,11 +1833,9 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + // This IPMI command does not have any resposne data + *data_len = 0; + +- /* 000101 ++ /* + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. +- * This is the only parameter used by petitboot. + */ +- + if (reqptr->parameter == (uint8_t)BootOptionParameter::BOOT_FLAGS) + { + IpmiValue bootOption = ((reqptr->data[1] & 0x3C) >> 2); +@@ -1697,6 +1929,129 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + return IPMI_CC_UNSPECIFIED_ERROR; + } + } ++ else if (reqptr->parameter == ++ static_cast(BootOptionParameter::BOOT_INITIATOR_MBOX)) ++ { ++ // Only allow writing to boot initiator mailbox if: ++ // 1. Mailbox is supported ++ // 2. IANA PEN matches. ++ // ++ // Algorithm: ++ // 1. Get 'Supported' property from Control.Boot.Mailbox interface ++ // 2. If {1} is 'false', report Parameter not supported (0x80) ++ // 3. Get Block Selector from request ++ // 4. Get 'Data' array from Control.Boot.Mailbox ++ // 5. If requested block {3} exceeds total vector size {4}, ++ // report Out of range (0xC9) ++ // 6. If requsted block {3} is 0: ++ // 4.1. Get IANA PEN from request ++ // 4.2. Get 'IANAEnterpriseNumber' property from Control.Boot.Mailbox ++ // 4.3. If {4.1} doesn't match {4.2}, report 0xCC error (Invalid ++ // data field in request) ++ // 7. Overwrite the 16 bytes at offset {3}*16 with the data from request ++ // 8. Update the 'Data' array in Control.Boot.Mailbox ++ ++ BootMboxBlock* reqMboxData = ++ reinterpret_cast(reqptr->data); ++ ++ try ++ { ++ std::optional isSupported = isBootMboxSupported(); ++ if (!isSupported) ++ { ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ ++ if (!*isSupported) ++ { ++ log("Attempt to read unsupported Boot/Mailbox"); ++ return IPMI_CC_PARM_NOT_SUPPORTED; ++ } ++ ++ // Requested block ++ IpmiValue reqBlock = reqMboxData->block; ++ ++ // Initially assume it's block 1+ ++ uint8_t* reqBlockPtr = reqMboxData->data; ++ size_t blockDataSize = sizeof(reqMboxData->data); ++ size_t dataVecStartOffset = reqBlock * blockDataSize - ++ sizeof(reqMboxData->ipmiIANAEnterprise); ++ ++ // Adjust pointers and sizes for block 0, and fill in the IANA PEN ++ if (0 == reqBlock) ++ { ++ uint24_t reqIANAEnterprise; ++ std::vector tmp( ++ &reqMboxData->ipmiIANAEnterprise[0], ++ &reqMboxData->ipmiIANAEnterprise[0] + ++ sizeof(reqMboxData->ipmiIANAEnterprise)); ++ ipmi::message::Payload tmpPayload( ++ std::forward>(tmp)); ++ ipmi::Cc unpackError = tmpPayload.unpack(reqIANAEnterprise); ++ if (unpackError != ipmi::ccSuccess) ++ { ++ return unpackError; ++ } ++ ++ std::optional IANAEnterprise = getBootMboxIANA(); ++ if (!IANAEnterprise) ++ { ++ return IPMI_CC_INVALID; ++ } ++ ++ if (*IANAEnterprise != reqIANAEnterprise) ++ { ++ log( ++ "Unsupported IANA Enterprise number", ++ entry("REQUESTED_IANA=%d", ++ static_cast(reqIANAEnterprise)), ++ entry("SUPPORTED_IANA=%d", ++ static_cast(*IANAEnterprise))); ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } ++ ++ // For block 0 operate on data after IANA PEN ++ reqBlockPtr = reqMboxData->blockZeroData; ++ blockDataSize = sizeof(reqMboxData->blockZeroData); ++ dataVecStartOffset = 0; ++ } ++ ++ // Get the data vector from d-bus ++ std::optional dataVec = getBootMbox(); ++ if (!dataVec) ++ { ++ return IPMI_CC_INVALID; ++ } ++ ++ // Does the requested block exist? ++ if ((*dataVec).size() < dataVecStartOffset + blockDataSize) ++ { ++ size_t total_size = ++ (*dataVec).size() + sizeof(reqMboxData->ipmiIANAEnterprise); ++ size_t normalBlockSize = sizeof(reqMboxData->data); ++ log( ++ "Attempt to read unsupported block", ++ entry("REQUESTED_BLOCK=%d", reqBlock), ++ entry("MAX_BLOCK=%d", total_size / normalBlockSize)); ++ return IPMI_CC_PARM_OUT_OF_RANGE; ++ } ++ ++ // Copy the data from request to specified offset in d-bus vector ++ for (size_t i = 0; i < blockDataSize; ++i) ++ { ++ (*dataVec)[dataVecStartOffset + i] = reqBlockPtr[i]; ++ } ++ if (setBootMbox(*dataVec)) ++ { ++ rc = IPMI_CC_OK; ++ } ++ } ++ catch (InternalFailure& e) ++ { ++ report(); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ } + else if (reqptr->parameter == + (uint8_t)BootOptionParameter::OPAL_NETWORK_SETTINGS) + { +diff --git a/chassishandler.hpp b/chassishandler.hpp +index dcaf06c..0e738e9 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -48,12 +48,14 @@ enum class BootOptionParameter : size_t + { + BOOT_INFO = 0x4, + BOOT_FLAGS = 0x5, ++ BOOT_INITIATOR_MBOX = 0x07, + OPAL_NETWORK_SETTINGS = 0x61 + }; + + enum class BootOptionResponseSize : size_t + { + BOOT_FLAGS = 5, ++ BOOT_INITIATOR_MBOX = 17, + OPAL_NETWORK_SETTINGS = 50 + }; + +-- +2.21.1 + diff --git a/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend b/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend new file mode 100644 index 000000000..a32658412 --- /dev/null +++ b/meta-yadro/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend @@ -0,0 +1,6 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI_append = "\ + file://0001-Add-support-for-persistent-only-settings.patch \ + file://0002-Add-support-for-boot-initiator-mailbox.patch \ +" -- cgit v1.2.3