diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor')
109 files changed, 10110 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb new file mode 100644 index 000000000..1bf81d953 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb @@ -0,0 +1,25 @@ + +SUMMARY = "Beep code manager service" +DESCRIPTION = "The beep code manager service will provide a method for beep code" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://beepcode_mgr.cpp \ + " +PV = "0.1" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +S = "${WORKDIR}" + +SYSTEMD_SERVICE_${PN} = "beepcode-mgr.service" + +inherit cmake +inherit obmc-phosphor-systemd + +DEPENDS += " \ + sdbusplus \ + phosphor-logging \ + boost \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format new file mode 100644 index 000000000..dd2770837 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format @@ -0,0 +1,98 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt new file mode 100644 index 000000000..472257279 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required (VERSION 3.5 FATAL_ERROR) +project (beepcode-mgr CXX) +set (CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD_REQUIRED ON) +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti") + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +# boost support +find_package (Boost REQUIRED) +# pkg_check_modules(Boost boost REQUIRED) +include_directories (${Boost_INCLUDE_DIRS}) +add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY) +add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED) +add_definitions (-DBOOST_ALL_NO_LIB) +add_definitions (-DBOOST_NO_RTTI) +add_definitions (-DBOOST_NO_TYPEID) +add_definitions (-DBOOST_ASIO_DISABLE_THREADS) + +# import sdbusplus +find_package (PkgConfig REQUIRED) +pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED) +include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS}) +link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS}) + +# import phosphor-logging +find_package (PkgConfig REQUIRED) +pkg_check_modules (LOGGING phosphor-logging REQUIRED) +include_directories (${LOGGING_INCLUDE_DIRS}) +link_directories (${LOGGING_LIBRARY_DIRS}) + +add_executable (beepcode-mgr beepcode_mgr.cpp) + +target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES} + phosphor_logging) + +install (TARGETS beepcode-mgr DESTINATION bin) diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service new file mode 100644 index 000000000..8099e2541 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service @@ -0,0 +1,12 @@ +[Unit] +Description=Beep code manager + +[Service] +Restart=always +RestartSec=2 +ExecStart=/usr/bin/beepcode-mgr +StartLimitInterval=0 +Type=simple + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp new file mode 100644 index 000000000..2940610da --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp @@ -0,0 +1,325 @@ +/* Copyright 2019 Intel + * + * 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. + */ + +#include <fcntl.h> +#include <linux/input.h> + +#include <boost/date_time/posix_time/posix_time.hpp> +#include <chrono> +#include <iostream> +#include <phosphor-logging/log.hpp> +#include <sdbusplus/asio/object_server.hpp> + +static constexpr uint32_t defaultBeepFrequence = 2000; +static constexpr uint32_t defaultBeepDurationMs = 300; +// Duration between two beeps +static constexpr uint32_t defaultInterBeepDurationMs = 300; +// Duration between two 4-bit digitals +static constexpr uint32_t defaultInterDigitBeepDurationMs = 800; +// Duration between two patterns +static constexpr uint32_t defaultPostBeepDurationMs = 1000; + +static constexpr uint8_t offBeepState = 0; +static constexpr uint8_t onBeepState = 1; +// finish 1 bit beep +static constexpr uint8_t interBeepState = 2; +// finish 4 bits beep +static constexpr uint8_t interDigitBeepState = 3; +// finish all bits beep +static constexpr uint8_t postBeepState = 4; + +static const std::vector<uint32_t> beepDelayTable = { + 0, defaultBeepDurationMs, defaultInterBeepDurationMs, + defaultInterDigitBeepDurationMs, defaultPostBeepDurationMs}; + +static constexpr uint32_t bpBitCount = 4; +static constexpr uint32_t bpShiftCount = 32; +static constexpr uint32_t bpMask = 0xf0000000; + +// beep code priority +static constexpr uint8_t beepOff = 0; +static constexpr uint8_t beepVRWatchdogTimeout = 1; +static constexpr uint8_t beepPSUFailure = 2; +static constexpr uint8_t beepCPUMIssing = 3; +static constexpr uint8_t beepCPUCatError = 4; +static constexpr uint8_t beepCPUErr2 = 5; +static constexpr uint8_t beepVoltageMismatch = 6; +static constexpr uint8_t beepCPUConfigError = 7; +static constexpr uint8_t beepPowerFail = 8; +static constexpr uint8_t beepPowerGoodTimeOut = 9; +static constexpr uint8_t beepMax = 10; + +// priority, abbrev name map +static const std::map<uint8_t, std::string> beepCodeNameList = { + {beepVRWatchdogTimeout, "VRWatchdogTimeout"}, + {beepPSUFailure, "PSUFailure"}, + {beepCPUMIssing, "CPUMissing"}, + {beepCPUCatError, "CPUCatError"}, + {beepCPUErr2, "CPUErr2"}, + {beepVoltageMismatch, "VoltageMismatch"}, + {beepCPUConfigError, "CPUConfigError"}, + {beepPowerFail, "PowerFail"}, + {beepPowerGoodTimeOut, "PowerGoodTimeOut"}, +}; + +// priority, code pattern map +static const std::map<uint8_t, std::string> beepCodePatternList = { + {beepVRWatchdogTimeout, "1-5-1-2"}, {beepPSUFailure, "1-5-1-4"}, + {beepCPUMIssing, "1-5-2-1"}, {beepCPUCatError, "1-5-2-2"}, + {beepCPUErr2, "1-5-2-3"}, {beepVoltageMismatch, "1-5-2-4"}, + {beepCPUConfigError, "1-5-2-5"}, {beepPowerFail, "1-5-4-2"}, + {beepPowerGoodTimeOut, "1-5-4-4"}, +}; + +static const std::vector<uint32_t> beepCodeTable = { + 0, 0x1512, 0x1514, 0x1521, 0x1522, 0x1523, 0x1524, 0x1525, 0x1542, 0x1544}; + +static constexpr char bpDevName[] = "/dev/input/event0"; +static constexpr char bpBusName[] = "xyz.openbmc_project.BeepCode"; +static constexpr char bpObjName[] = "/xyz/openbmc_project/BeepCode"; +static constexpr char bpIntfName[] = "xyz.openbmc_project.BeepCode"; +static constexpr char bpMethodName[] = "Beep"; + +static std::shared_ptr<sdbusplus::asio::dbus_interface> bpIface; +static boost::asio::io_service io; +static auto conn = std::make_shared<sdbusplus::asio::connection>(io); + +class Beeper +{ + public: + Beeper(boost::asio::io_service& io) + { + timer = std::make_unique<boost::asio::steady_timer>(io); + fdBeepDev = -1; + currentCount = 0; + currentBeepCode = 0; + currentMask = bpMask; + currentShift = bpShiftCount; + currentState = offBeepState; + timerRunning = false; + } + + ~Beeper() + { + } + + void beep(const uint8_t& beepPriority) + { + if (timerRunning) + { + pendingList.push_back(beepPriority); + pendingList.sort(std::greater<uint8_t>()); + return; + } + + performBeep(beepPriority); + } + + private: + void performBeep(const uint8_t& beepPriority) + { + currentBeepCode = beepCodeTable[beepPriority]; + currentCount = 0; + currentMask = bpMask; + currentShift = bpShiftCount; + getCurrentCount(); + startBeep(defaultBeepFrequence); + currentState = onBeepState; + currentCount--; + timerRunning = true; + startBeepTimer(); + } + + void startBeepTimer() + { + timer->expires_after( + std::chrono::milliseconds(beepDelayTable[currentState])); + timer->async_wait([this](const boost::system::error_code& ec) { + // timer timeout + switch (currentState) + { + case onBeepState: + stopBeep(); + if (currentCount == 0) + { + // finished the current 4-bit + if (currentBeepCode == 0) + { + // finished all bits + currentState = postBeepState; + } + else + { + // start next 4-bit + currentState = interDigitBeepState; + getCurrentCount(); + currentCount--; + } + } + else + { + // still in 4-bit processing + currentCount--; + currentState = interBeepState; + } + startBeepTimer(); + break; + + case interBeepState: + case interDigitBeepState: + startBeep(defaultBeepFrequence); + currentState = onBeepState; + startBeepTimer(); + break; + case postBeepState: + if (pendingList.size() != 0) + { + // continue the next new beepcode + uint8_t beepPriority = pendingList.front(); + pendingList.pop_front(); + performBeep(beepPriority); + } + else + { + timerRunning = false; + } + break; + + default: + std::cerr << "Incorrect beepState: " + << static_cast<unsigned int>(currentState) + << std::endl; + break; + } + }); + } + + void startBeep(uint32_t freq) + { + if (fdBeepDev != -1) + { + std::cerr << "beep device is opening already!" << std::endl; + ::close(fdBeepDev); + fdBeepDev = -1; + } + + if ((fdBeepDev = ::open(bpDevName, O_RDWR | O_CLOEXEC)) < 0) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Failed to open input device"); + return; + } + + struct input_event event; + event.type = EV_SND; + event.code = SND_TONE; + event.value = freq; + + if (::write(fdBeepDev, &event, sizeof(struct input_event)) != + sizeof(struct input_event)) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Failed to write a tone sound event"); + ::close(fdBeepDev); + fdBeepDev = -1; + return; + } + return; + } + + void stopBeep() + { + if (fdBeepDev == -1) + { + std::cerr << "beep device is closed!" << std::endl; + return; + } + + ::close(fdBeepDev); + fdBeepDev = -1; + } + + // Split the beep code based on bpBitCount, for example 0x1544, + // currentCount=1, 5, 4, 4 + void getCurrentCount() + { + while (currentCount == 0) + { + currentCount = currentMask & currentBeepCode; + currentShift -= bpBitCount; + currentCount >>= currentShift; + currentBeepCode = currentBeepCode & ~currentMask; + currentMask >>= bpBitCount; + if (currentMask == 0) + { + break; + } + } + } + + int fdBeepDev; + bool timerRunning; + uint32_t currentCount; + uint32_t currentBeepCode; + uint32_t currentMask; + uint32_t currentShift; + uint8_t currentState; + std::unique_ptr<boost::asio::steady_timer> timer; + std::list<uint8_t> pendingList; +}; + +static Beeper beeper(io); + +// dbus method +static void beep(const uint8_t& beepPriority) +{ + if ((beepPriority >= beepMax) || (beepPriority == beepOff)) + { + std::cerr << "Incorrect input: " + << static_cast<unsigned int>(beepPriority) << std::endl; + return; + } + + // Log into redfish event log + sd_journal_send("MESSAGE=BeepCode: Priority=%d", beepPriority, + "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", + "OpenBMC.0.1.BeepCode", "REDFISH_MESSAGE_ARGS=%d", + beepPriority, NULL); + + beeper.beep(beepPriority); + + return; +} + +int main(int argc, char** argv) +{ + phosphor::logging::log<phosphor::logging::level::INFO>( + "Starting BeepCode service"); + + conn->request_name(bpBusName); + sdbusplus::asio::object_server server = + sdbusplus::asio::object_server(conn); + bpIface = server.add_interface(bpObjName, bpIntfName); + + bpIface->register_property("BeepCodeNameList", beepCodeNameList, + sdbusplus::asio::PropertyPermission::readOnly); + bpIface->register_property("BeepCodePatternList", beepCodePatternList, + sdbusplus::asio::PropertyPermission::readOnly); + bpIface->register_method(bpMethodName, beep); + bpIface->initialize(); + + io.run(); + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json new file mode 100644 index 000000000..583c255a3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json @@ -0,0 +1,12 @@ +{ + "enum_char": ".", + "line_ending": "unix", + "bullet_char": "*", + "max_subargs_per_line": 99, + "command_case": "lower", + "tab_size": 4, + "line_width": 80, + "separate_fn_name_with_space": true, + "dangle_parens": true, + "separate_ctrl_name_with_space": true +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend new file mode 100644 index 000000000..7819c90f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend @@ -0,0 +1,8 @@ +# this is here just to bump faster than upstream +SRC_URI = "git://github.com/openbmc/entity-manager.git" +SRCREV = "978fcadadc8320ff5356ed1a5dc25e3284e3745f" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +EXTRA_OECMAKE = "-DYOCTO=1 -DUSE_OVERLAYS=0" + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch new file mode 100644 index 000000000..7568f8ce9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch @@ -0,0 +1,120 @@ +From a30a09f58b9ebfb267c0b9cce9ae25994ea025ca Mon Sep 17 00:00:00 2001 +From: cyang29 <cheng.c.yang@intel.com> +Date: Tue, 17 Jul 2018 16:04:58 +0800 +Subject: [PATCH] Add DBUS interface of CPU and Memory's properties Feature + Support: SMBIOS service interface. CPU DIMM information redfish + interface. Base on smbios spec DSP0134_3.0.0 + +Signed-off-by: cyang29 <cheng.c.yang@intel.com> +--- + .../Inventory/Item/Cpu.interface.yaml | 41 +++++++++++++++++++ + .../Inventory/Item/Dimm.interface.yaml | 46 +++++++++++++++++++++- + 2 files changed, 86 insertions(+), 1 deletion(-) + +diff --git a/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml b/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml +index ab29cf3..313eada 100644 +--- a/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml ++++ b/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml +@@ -1,4 +1,45 @@ + description: > + Implement to provide CPU attributes. ++properties: ++ - name: ProcessorSocket ++ type: string ++ description: > ++ Processor Socket on MotherBoard ++ - name: ProcessorType ++ type: string ++ description: > ++ Processor Type of CPU ++ - name: ProcessorFamily ++ type: string ++ description: > ++ Processor Family of CPU ++ - name: ProcessorManufacturer ++ type: string ++ description: > ++ Processor Manufacturer of CPU ++ - name: ProcessorId ++ type: uint32 ++ description: > ++ Processor ID of CPU ++ - name: ProcessorVersion ++ type: string ++ description: > ++ Processor Version of CPU ++ - name: ProcessorMaxSpeed ++ type: uint16 ++ description: > ++ Max Speed CPU Can Support ++ - name: ProcessorCharacteristics ++ type: string ++ description: > ++ The Characteristics CPU Has ++ - name: ProcessorCoreCount ++ type: uint16 ++ description: > ++ The Count of Core in CPU ++ - name: ProcessorThreadCount ++ type: uint16 ++ description: > ++ The Count of Thread CPU Can Support + + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 +diff --git a/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml b/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml +index d85326d..b750320 100644 +--- a/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml ++++ b/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml +@@ -1,4 +1,48 @@ + description: > + Implement to provide DIMM attributes. +- ++properties: ++ - name: MemoryDataWidth ++ type: uint16 ++ description: > ++ Data width of Memory. ++ - name: MemorySizeInKB ++ type: uint32 ++ description: > ++ Memory size of DIMM in Kilobyte. ++ - name: MemoryDeviceLocator ++ type: string ++ description: > ++ Socket on base board where Memory located. ++ - name: MemoryType ++ type: string ++ description: > ++ Type of memory. ++ - name: MemoryTypeDetail ++ type: string ++ description: > ++ Additional detail on Memory. ++ - name: MemorySpeed ++ type: uint16 ++ description: > ++ The maximun capable speed of Memory. ++ - name: MemoryManufacturer ++ type: string ++ description: > ++ Manufacturer of memory. ++ - name: MemorySerialNum ++ type: string ++ description: > ++ Memory Serial Number. ++ - name: MemoryPartNum ++ type: string ++ description: > ++ Memory Part Number. ++ - name: MemoryAttributes ++ type: byte ++ description: > ++ Rank attributes of Memory. ++ - name: MemoryConfClockSpeed ++ type: uint16 ++ description: > ++ Configured clock speed to Memory. + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch new file mode 100644 index 000000000..c87b2d89d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch @@ -0,0 +1,32 @@ +From 49debd0955b672d591f35e74119b288bd6df2992 Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Tue, 24 Jul 2018 11:40:49 +0800 +Subject: [PATCH] [ipmi] set BIOS id + +change#2 +add new dbus interface for BIOS attributes + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + xyz/openbmc_project/Inventory/Item/Bios.interface.yaml | 9 +++++++++ + 1 file changed, 9 insertions(+) + create mode 100644 xyz/openbmc_project/Inventory/Item/Bios.interface.yaml + +diff --git a/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml b/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml +new file mode 100644 +index 0000000..d7a6b95 +--- /dev/null ++++ b/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml +@@ -0,0 +1,9 @@ ++description: > ++ Implement to provide BIOS attributes. ++properties: ++ - name: BiosId ++ type: string ++ description: > ++ BIOS ID (version) string ++ ++# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch new file mode 100644 index 000000000..2c9344306 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch @@ -0,0 +1,34 @@ +From 631deef0ca88a77283741edeae8078d2185f414c Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Fri, 10 Aug 2018 16:23:13 +0800 +Subject: [PATCH] Increase the default watchdog timeout value + +The default timeout for poweron is 30 seconds, +but currently the host power on needs 120+ seconds +due to unimplemented ipmi commands for BIOS. + +Increase the value as a workaround, +to avoid the watchdog timeout during power on. +Will adjust this value in the future + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + xyz/openbmc_project/State/Watchdog.interface.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml +index f76dbf2..402e1a8 100644 +--- a/xyz/openbmc_project/State/Watchdog.interface.yaml ++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml +@@ -37,7 +37,7 @@ properties: + type: uint64 + description: > + Time interval to arm the watchdog, in milli-second. +- default: 30000 ++ default: 600000 + - name: TimeRemaining + type: uint64 + description: > +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch new file mode 100644 index 000000000..9052435ca --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch @@ -0,0 +1,34 @@ +From eeac4cf4528994aeb213d549daf4c033ac9d3bbc Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Fri, 24 Aug 2018 17:55:35 +0800 +Subject: [PATCH] Add RestoreDelay interface for power restore delay + +Which provide one property "PowerRestoreDelay" + +Change-Id: I4e6d3e45948b1e288301b4aa52cc08cace4f1bc2 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + .../Control/Power/RestoreDelay.interface.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + create mode 100644 xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml + +diff --git a/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml b/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml +new file mode 100644 +index 0000000..55ee80a +--- /dev/null ++++ b/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml +@@ -0,0 +1,11 @@ ++description: > ++ Implement to specify power transition behavior on a BMC reset. ++ The implementation based on restore policy and set a delay time ++ for power restore. ++ ++properties: ++ - name: PowerRestoreDelay ++ type: uint16 ++ description: > ++ The delay time for power restore. ++ Power Restore Delay is NOT applied on power policy is "Always Off" +-- +2.17.0 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch new file mode 100644 index 000000000..9471c7ab2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch @@ -0,0 +1,86 @@ +From 7260c24b201759f3a5168eebfee215072c13e641 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Thu, 30 Aug 2018 16:22:43 +0800 +Subject: [PATCH] Add ErrConfig.yaml interface for processor error + configuration. + +Which provide 3 properties: + ResetCfg + type: byte + description: > + Reset Configuration + [0]: CATERR Reset Enabled + 0b: Disabled + 1b: Enabled + [1]: ERR2 Reset Enabled + 0b: Disabled + 1b: Enabled + [7:2]: Reserved + ResetErrorOccurrenceCounts + type: byte + description: > + Reset Error Occurrence Counts + [0]: Reset CPU Error Counts + 0b: Keep CPU Error Counts + 1b: Reset all CPU Error Counts to zero + [7:1]: Reserved + CATERRStatus + type: array[byte] + description: > + For all CPUs including the non-legacy socket CPU + CPU CATERR (Core Error) occurrence + [5:0]: Error Occurrence Count + [7:6]: CPU Status + 00b: Disabled + 01b: Enabled + 11b: Not Present + +Change-Id: Ibc5a7a5e15c998e56c04e23b1043d99243a91171 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + .../Processor/ErrConfig.interface.yaml | 33 +++++++++++++++++++ + 1 file changed, 33 insertions(+) + create mode 100644 xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml + +diff --git a/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml b/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml +new file mode 100644 +index 0000000..2304263 +--- /dev/null ++++ b/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml +@@ -0,0 +1,33 @@ ++description: > ++ This defines processor error configuration. ++properties: ++ - name: ResetCfg ++ type: byte ++ description: > ++ Reset Configuration ++ [0]: CATERR Reset Enabled ++ 0b: Disabled ++ 1b: Enabled ++ [1]: ERR2 Reset Enabled ++ 0b: Disabled ++ 1b: Enabled ++ [7:2]: Reserved ++ ++ - name: ResetErrorOccurrenceCounts ++ type: byte ++ description: > ++ Reset Error Occurrence Counts ++ [0]: Reset CPU Error Counts ++ 0b: Keep CPU Error Counts ++ 1b: Reset all CPU Error Counts to zero ++ [7:1]: Reserved ++ - name: CATERRStatus ++ type: array[byte] ++ description: > ++ For all CPUs including the non-legacy socket CPU ++ CPU CATERR (Core Error) occurrence ++ [5:0]: Error Occurrence Count ++ [7:6]: CPU Status ++ 00b: Disabled ++ 01b: Enabled ++ 11b: Not Present +-- +2.17.0 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch new file mode 100644 index 000000000..576bae81a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch @@ -0,0 +1,227 @@ +From 9490574667485cd407193ff9f0d6a96f8c2c87d3 Mon Sep 17 00:00:00 2001 +From: cyang29 <cheng.c.yang@intel.com> +Date: Wed, 12 Sep 2018 00:27:23 +0800 +Subject: [PATCH] Add DBUS interface of SMBIOS MDR V2 + +Support: + SMBIOS MDR V2 service interface. + SMBIOS MDR V2 IPMI Command + SMBIOS MDR V2 Redfish interface. +Base on SMBIOS spec DSP0134_3.0.0 and Managed Data Region +Specification Revision 4 +--- + xyz/openbmc_project/Smbios/MDR_V2.errors.yaml | 9 + + xyz/openbmc_project/Smbios/MDR_V2.interface.yaml | 158 +++++++++++++++++++++++ + xyz/openbmc_project/Smbios/README.md | 21 +++ + 3 files changed, 188 insertions(+) + create mode 100644 xyz/openbmc_project/Smbios/MDR_V2.errors.yaml + create mode 100644 xyz/openbmc_project/Smbios/MDR_V2.interface.yaml + create mode 100644 xyz/openbmc_project/Smbios/README.md + +diff --git a/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml b/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml +new file mode 100644 +index 0000000..88bd6db +--- /dev/null ++++ b/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml +@@ -0,0 +1,9 @@ ++- name: InvalidParameter ++ description: > ++ An invalid parameter is attempted. ++- name: UpdateInProgress ++ description: > ++ Update is in progress. ++- name: InvalidId ++ description: > ++ An invalid Id is attempted. +diff --git a/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml b/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml +new file mode 100644 +index 0000000..f97700a +--- /dev/null ++++ b/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml +@@ -0,0 +1,158 @@ ++description: > ++ SMBIOS MDR V2 service ++methods: ++ - name: GetDirectoryInformation ++ description: > ++ Get the directory with directory index. ++ parameters: ++ - name: dirIndex ++ type: byte ++ description: > ++ Directory index of SMBIOS. ++ returns: ++ - name: dir ++ type: array[byte] ++ description: > ++ Directory of agent. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: GetDataInformation ++ description: > ++ Get the data info with id index and data set ID. ++ parameters: ++ - name: idIndex ++ type: byte ++ description: > ++ Index of SMBIOS directory. ++ returns: ++ - name: dataInfo ++ type: array[byte] ++ description: > ++ Data information of SMBIOS. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: SendDirectoryInformation ++ description: > ++ Send directory information to SMBIOS directory. ++ parameters: ++ - name: dirVersion ++ type: byte ++ description: > ++ A counter which increments each time directory updated. ++ - name: dirIndex ++ type: byte ++ description: > ++ Directory index of SMBIOS. ++ - name: returnedEntries ++ type: byte ++ description: > ++ Indicates number of directory entries. ++ - name: remainingEntries ++ type: byte ++ description: > ++ Remaining entries which are higher than index in this transfer. ++ - name: dirEntry ++ type: array[byte] ++ description: > ++ Data set ID of SMBIOS table. ++ returns: ++ - name: status ++ type: boolean ++ description: > ++ Need to continue directory transmisson or not. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: GetDataOffer ++ description: > ++ Get data set ID. ++ returns: ++ - name: offer ++ type: array[byte] ++ description: > ++ Data set ID. ++ errors: ++ - self.Error.UpdateInProgress ++ ++ - name: SendDataInformation ++ description: > ++ Send data information with directory index. ++ parameters: ++ - name: idIndex ++ type: byte ++ description: > ++ Index of SMBIOS directory. ++ - name: flag ++ type: byte ++ description: > ++ Valid flag to set dir entry status. ++ - name: dataLen ++ type: uint32 ++ description: > ++ The length of the data in bytes. ++ - name: dataVer ++ type: uint32 ++ description: > ++ The version number of this data. ++ - name: timeStamp ++ type: uint32 ++ description: > ++ Timestamp determinded by the agent. ++ returns: ++ - name: status ++ type: boolean ++ description: > ++ Whether data changes. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: FindIdIndex ++ description: > ++ Find id index by data info. ++ parameters: ++ - name: dataInfo ++ type: array[byte] ++ description: > ++ Data info of data entry. ++ returns: ++ - name: idIndex ++ type: int32 ++ description: > ++ Id index of data entry. ++ errors: ++ - self.Error.InvalidId ++ ++ - name: AgentSynchronizeData ++ description: > ++ Synchronize SMBIOS data from file. ++ returns: ++ - name: status ++ type: boolean ++ description: > ++ Whether synchronization succeed or not. ++ ++ - name: SynchronizeDirectoryCommonData ++ description: > ++ Synchronize directory common data. ++ parameters: ++ - name: idIndex ++ type: byte ++ description: > ++ Index of SMBIOS directory. ++ - name: size ++ type: uint32 ++ description: > ++ Size of data that BIOS prepare to transfer. ++ returns: ++ - name: commonData ++ type: array[uint32] ++ description: > ++ Directory common data includes data size, version and timestamp. ++ ++properties: ++ - name: DirectoryEntries ++ type: byte ++ description: > ++ Numbers of directory entries. +diff --git a/xyz/openbmc_project/Smbios/README.md b/xyz/openbmc_project/Smbios/README.md +new file mode 100644 +index 0000000..415ac52 +--- /dev/null ++++ b/xyz/openbmc_project/Smbios/README.md +@@ -0,0 +1,22 @@ ++# SMBIOS MDR V2 ++ ++## Overview ++SMBIOS MDR V2 service exposes D-Bus methods for SMBIOS Version 2 operations. ++ ++### SMBIOS MDR V2 Interface ++SMBIOS MDR V2 interface `xyz.openbmc_project.Smbios.MDR_V2` provides following ++methods. ++#### methods ++* GetDirectoryInformation - Get the directory with directory index. ++* GetDataInformation - Get the data information with id index and data set ID. ++* SendDirectoryInformation - Send directory information to SMBIOS directory. ++* GetDataOffer - Get data set ID. ++* SendDataInformation - Send data information with directory index. ++* FindIdIndex - Find id index by data info. ++* SynchronizeDirectoryCommonData - Synchronize directory common data before ++SMBIOS data start to transfer. ++* AgentSynchronizeData - Synchronize SMBIOS data from file after data transfer ++complete. ++ ++#### properties ++* DirEntries - Numbers of directory entries. Default: 0 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch new file mode 100644 index 000000000..68d2c92b7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch @@ -0,0 +1,76 @@ +From 2820ca36ab21c52341cdbde477756f960eaeb68b Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Wed, 13 Mar 2019 11:19:07 +0800 +Subject: [PATCH] Create dbus interface for SOL commands + +Create dbus properties for Set/Get SOL config parameter command. +Some platforms need to call Set/Get SOL config parameter command +through KCS, and since sol manager in net-ipmid cannot be accessed +by commands in host-ipmid, need to create a dbus interface in +phospher-settings to transfer properties from host-ipmid to +net-ipmid. + +TestedBy: +With the related code change in net-ipmid, busctl introspect +xyz.openbmc_project.Ipmi.SOL /xyz/openbmc_project/SOL +can show all the properties needed. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + xyz/openbmc_project/Ipmi/SOL.interface.yaml | 44 ++++++++++++++++++++++++++ + 1 file changed, 44 insertions(+) + create mode 100644 xyz/openbmc_project/Ipmi/SOL.interface.yaml + +diff --git a/xyz/openbmc_project/Ipmi/SOL.interface.yaml b/xyz/openbmc_project/Ipmi/SOL.interface.yaml +new file mode 100644 +index 0000000..94db59f +--- /dev/null ++++ b/xyz/openbmc_project/Ipmi/SOL.interface.yaml +@@ -0,0 +1,44 @@ ++description: > ++ SOL properties use for Get/Set SOL config parameter command in host-ipmid ++ sending config to SOL process in net-ipmid. ++ Since some platforms need to access Get/Set SOL config parameter command ++ through KCS, and current sol manager is implemented in net-ipmid and ++ cannot be accessed by host-ipmid, add a dbus interface for host-ipmid ++ command to transfer properties to net-ipmid. ++ This interface will be implemented in phosphor-settings. ++properties: ++ - name: Progress ++ type: byte ++ description: > ++ Set In Progress property, indicate when any parameters are being ++ updated. ++ - name: Enable ++ type: boolean ++ description: > ++ SOL Enable property, this controls whether the SOL payload type ++ can be activated. ++ - name: Authentication ++ type: byte ++ description: > ++ If SOL enable Force Payload Encryption and Authenticaton. ++ And the minimun operating privilege level SOL required. ++ - name: AccumulateIntervalMS ++ type: byte ++ description: > ++ Character Accumulate Interval in 5ms increments. ++ BMC will wait this time before transmitting a packet. ++ - name: Threshold ++ type: byte ++ description: > ++ BMC will automatically send an SOL character data packet containing ++ this number of characters as soon as this number of characters ++ (or greater) has been accepted from the baseboard serial controller. ++ - name: RetryCount ++ type: byte ++ description: > ++ Packet will be dropped if no ACK/NACK received by time retries ++ expire. ++ - name: RetryIntervalMS ++ type: byte ++ description: > ++ Retry Interval in 10ms increments. +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0022-Add-chassis-power-cycle-and-reset-to-Chassis-State.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0022-Add-chassis-power-cycle-and-reset-to-Chassis-State.patch new file mode 100644 index 000000000..181d12428 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0022-Add-chassis-power-cycle-and-reset-to-Chassis-State.patch @@ -0,0 +1,40 @@ +From b55c6847b18fdee5a72d601b871d73085481e4d9 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Mon, 3 Jun 2019 16:31:29 -0700 +Subject: [PATCH] Add chassis power-cycle and reset to Chassis State + +This adds chassis PowerCycle and Reset as possible Transition +values for the Chassis State. These are to support chassis +power cycle and a chassis reset button, respectively. + +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + xyz/openbmc_project/State/Chassis.interface.yaml | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/xyz/openbmc_project/State/Chassis.interface.yaml b/xyz/openbmc_project/State/Chassis.interface.yaml +index 4ae6274..470a3a2 100644 +--- a/xyz/openbmc_project/State/Chassis.interface.yaml ++++ b/xyz/openbmc_project/State/Chassis.interface.yaml +@@ -31,10 +31,17 @@ enumerations: + values: + - name: 'Off' + description: > +- Chassis power should be off ++ Chassis power should be off + - name: 'On' + description: > + Chassis power should be on ++ - name: 'PowerCycle' ++ description: > ++ Chassis power should be cycled ++ - name: 'Reset' ++ description: > ++ Chassis should be reset ++ + + - name: PowerState + description: > +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch new file mode 100644 index 000000000..67fa59090 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch @@ -0,0 +1,57 @@ +From 6e9a19c43acac7d4254910906329d98d7b59085a Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Fri, 24 May 2019 14:55:10 +0800 +Subject: [PATCH] Add the pre-timeout interrupt defined in IPMI spec + +The IPMI watchdog pre-timeout interrupt is used to set the different +pre-timeout interrupt source. Add them as a dbus property, +IPMI set/get watchdog commands will use it. + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + xyz/openbmc_project/State/Watchdog.interface.yaml | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml +index 2fc47d8..6dfa9b9 100644 +--- a/xyz/openbmc_project/State/Watchdog.interface.yaml ++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml +@@ -33,6 +33,11 @@ properties: + description: > + The action the watchdog should perform when it expires. + default: 'HardReset' ++ - name: PreTimeoutInterrupt ++ type: enum[self.PreTimeoutInterruptAction] ++ description: > ++ The BMC generates the selected interrupt before the timer expires. ++ default: 'None' + - name: Interval + type: uint64 + description: > +@@ -73,6 +78,23 @@ enumerations: + description: > + Perform a power cycle of the system. + ++ - name: PreTimeoutInterruptAction ++ description: > ++ The type of PreTimeout Interrupt. ++ values: ++ - name: 'None' ++ description: > ++ Do nothing. ++ - name: 'SMI' ++ description: > ++ SMI. ++ - name: 'NMI' ++ description: > ++ NMI / Diagnostic Interrupt. ++ - name: 'MI' ++ description: > ++ Messaging Interrupt. ++ + - name: TimerUse + description: > + The type of timer use. +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch new file mode 100644 index 000000000..d7e66abd2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch @@ -0,0 +1,39 @@ +From b7c487750c05dcc081219ccdd4ef539beef6aa30 Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Mon, 29 Jul 2019 10:51:12 +0800 +Subject: [PATCH] Add PreInterruptFlag properity in DBUS. + +PreTimeoutInterruptOccurFlag in DBUS would be set 'true' +when watchdog pre-timeout interrupt occurred. + +Tested: +Enable command(raw 0x06 0x31) that get message flag +can set right bit about watchdog, +need record PreTimeoutInterruptOccurFlag +at xyz.openbmmc_project.State.Watchdog when watchdog +pre-timeout interrupt occurred. + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + xyz/openbmc_project/State/Watchdog.interface.yaml | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml +index bf4cca0..6579368 100644 +--- a/xyz/openbmc_project/State/Watchdog.interface.yaml ++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml +@@ -59,6 +59,11 @@ properties: + description: > + The timer user at the time of expiration. + default: 'Reserved' ++ - name: PreTimeoutInterruptOccurFlag ++ type: boolean ++ description: > ++ PreTimeoutInterruptOccurFlag that preTimeoutInterrupt action occurred. ++ default: false + + enumerations: + - name: Action +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend new file mode 100644 index 000000000..c306e5afc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend @@ -0,0 +1,16 @@ +# todo Johnathan, undo nobranch once phosphor-networking is working +SRC_URI = "git://github.com/openbmc/phosphor-dbus-interfaces.git;nobranch=1" +SRCREV = "9cb4a711cff999b373cf98b44cc18b9001c1395a" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch \ + file://0007-ipmi-set-BIOS-id.patch \ + file://0010-Increase-the-default-watchdog-timeout-value.patch \ + file://0012-Add-RestoreDelay-interface-for-power-restore-delay.patch \ + file://0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch \ + file://0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch \ + file://0022-Add-chassis-power-cycle-and-reset-to-Chassis-State.patch \ + file://0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch \ + file://0025-Add-PreInterruptFlag-properity-in-DBUS.patch \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service new file mode 100644 index 000000000..9af9af254 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service @@ -0,0 +1,20 @@ +[Unit] +Description=Phosphor DBus Service Discovery Manager +Before=obmc-mapper.target +After=dbus.socket + +[Service] +Restart=always +Type=dbus +ExecStart=/usr/bin/env mapperx \ + --service-namespaces="xyz. com. org." \ + --interface-namespaces="org. com. xyz." \ + --service-blacklists="org.freedesktop.systemd1" +SyslogIdentifier=phosphor-mapper +BusName={BUSNAME} +TimeoutStartSec=300 +RestartSec=5 +EnvironmentFile={envfiledir}/obmc/mapper + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend new file mode 100644 index 000000000..72d991c7e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend @@ -0,0 +1 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service new file mode 100644 index 000000000..0e80b554a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service @@ -0,0 +1,14 @@ +[Unit] +Description=Phosphor-Pid-Control Margin-based Fan Control Daemon +After=xyz.openbmc_project.EntityManager.service +After=xyz.openbmc_project.ObjectMapper.service + +[Service] +Restart=always +ExecStart={bindir}/swampd +RestartSec=5 +StartLimitInterval=0 +Type=simple + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend new file mode 100644 index 000000000..842d89f03 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend @@ -0,0 +1,10 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +inherit obmc-phosphor-systemd +SYSTEMD_SERVICE_${PN} = "phosphor-pid-control.service" +EXTRA_OECONF = "--enable-configure-dbus=yes" + +SRC_URI = "git://github.com/openbmc/phosphor-pid-control.git" +SRCREV = "6b9f59991b7f694866c98775b4179ae97c5e69a8" + +FILES_${PN} = "${bindir}/swampd ${bindir}/setsensor" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch new file mode 100644 index 000000000..2a4c7e9b6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch @@ -0,0 +1,44 @@ +From b6b3051c8078267153712ed8cf514373924fd07a Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Mon, 16 Jul 2018 19:15:04 -0700 +Subject: [PATCH 2/6] Redfish firmware activation -- Modified flash.cpp to + call to customized flash service + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Change-Id: I81c3185e9c4c2ee907feeb53620faa22723c04d4 +--- + ubi/flash.cpp | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/ubi/flash.cpp b/ubi/flash.cpp +index ffa9348..5af2a17 100644 +--- a/ubi/flash.cpp ++++ b/ubi/flash.cpp +@@ -15,10 +15,13 @@ void Activation::flashWrite() + { + auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); +- method.append("obmc-flash-bmc-ubirw.service", "replace"); ++ std::string rwServiceFile = ++ "obmc-flash-bmc-ubirw@" + versionId + ".service"; ++ method.append(rwServiceFile, "replace"); + bus.call_noreply(method); + +- auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; ++ std::string roServiceFile = ++ "obmc-flash-bmc-ubiro@" + versionId + ".service"; + method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); + method.append(roServiceFile, "replace"); +@@ -37,7 +40,7 @@ void Activation::onStateChanges(sdbusplus::message::message& msg) + // Read the msg and populate each variable + msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult); + +- auto rwServiceFile = "obmc-flash-bmc-ubirw.service"; ++ auto rwServiceFile = "obmc-flash-bmc-ubirw@" + versionId + ".service"; + auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; + auto ubootVarsServiceFile = + "obmc-flash-bmc-updateubootvars@" + versionId + ".service"; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch new file mode 100644 index 000000000..3fc3907ba --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch @@ -0,0 +1,41 @@ +From 1b00440d0c8fabfa2e3eda984a21c0f004ca2150 Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Fri, 26 Oct 2018 11:54:05 -0700 +Subject: [PATCH 4/6] Changed the condition of software version service + watching deamon + + Originally it watches only files that are "written" into /tmp/images directory. +This change modified the condition to also watch files that are "moved" into this directory. + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Change-Id: I3e9cf1ffc3f5350d4649d32d3d3837991322a65b +--- + watch.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/watch.cpp b/watch.cpp +index e46b8aa..eee1bc3 100644 +--- a/watch.cpp ++++ b/watch.cpp +@@ -45,7 +45,7 @@ Watch::Watch(sd_event* loop, std::function<int(std::string&)> imageCallback) : + std::strerror(error)); + } + +- wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE); ++ wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE | IN_MOVED_TO); + if (-1 == wd) + { + auto error = errno; +@@ -96,7 +96,8 @@ int Watch::callback(sd_event_source* s, int fd, uint32_t revents, + while (offset < bytes) + { + auto event = reinterpret_cast<inotify_event*>(&buffer[offset]); +- if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR)) ++ if ((event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO)) && ++ !(event->mask & IN_ISDIR)) + { + auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name; + auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch new file mode 100644 index 000000000..aa5d900e0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch @@ -0,0 +1,188 @@ +From 7f29c255dd2af7fa6d38b02ad63a8b8940fbce84 Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Mon, 10 Dec 2018 10:36:44 -0800 +Subject: [PATCH 5/6] Modified firmware activation to launch fwupd.sh through + non-ubi fs code path to match more closely to the upstream design - + Added option FWUPD_SCRIPT to saperate intel customized code - Adopted + ActivationProgress from ubi fs activation code mainly for progress indicator + for ipmi update + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Change-Id: Id805deea75b21fab86f6bb6edbf50ddb3be42564 +--- + activation.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ + configure.ac | 7 +++++++ + static/flash.cpp | 41 +++++++++++++++++++++++++++++++++++++++-- + ubi/flash.cpp | 9 +++------ + 4 files changed, 93 insertions(+), 8 deletions(-) + +diff --git a/activation.cpp b/activation.cpp +index f918221..f2923ae 100644 +--- a/activation.cpp ++++ b/activation.cpp +@@ -163,6 +163,50 @@ auto Activation::activation(Activations value) -> Activations + softwareServer::Activation::Activations::Active); + } + } ++#elif defined(FWUPD_SCRIPT) ++ if (!activationProgress) ++ { ++ // Enable systemd signals ++ Activation::subscribeToSystemdSignals(); ++ parent.freeSpace(*this); ++ ++ activationProgress = ++ std::make_unique<ActivationProgress>(bus, path); ++ ++#ifdef WANT_SIGNATURE_VERIFY ++ fs::path uploadDir(IMG_UPLOAD_DIR); ++ if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH)) ++ { ++ onVerifyFailed(); ++ // Stop the activation process, if fieldMode is enabled. ++ if (parent.control::FieldMode::fieldModeEnabled()) ++ { ++ return softwareServer::Activation::activation( ++ softwareServer::Activation::Activations::Failed); ++ } ++ } ++#endif ++ flashWrite(); ++ activationProgress->progress(10); ++ } ++ else if (activationProgress->progress() == 100) ++ { ++ log<level::ERR>("[Jennifer] progress == 100..."); ++ if (!redundancyPriority) ++ { ++ redundancyPriority = ++ std::make_unique<RedundancyPriority>(bus, path, *this, 0); ++ } ++ ++ // Remove version object from image manager ++ Activation::deleteImageManagerObject(); ++ ++ // Create active association ++ parent.createActiveAssociation(path); ++ ++ return softwareServer::Activation::activation( ++ softwareServer::Activation::Activations::Active); ++ } + #else // !UBIFS_LAYOUT + + #ifdef WANT_SIGNATURE_VERIFY +diff --git a/configure.ac b/configure.ac +index 2da97ad..720e704 100755 +--- a/configure.ac ++++ b/configure.ac +@@ -184,6 +184,13 @@ AS_IF([test "x$enable_ubifs_layout" == "xyes"], \ + [AC_DEFINE([UBIFS_LAYOUT],[],[Enable ubifs support.])]) + AM_CONDITIONAL([UBIFS_LAYOUT], [test "x$enable_ubifs_layout" == "xyes"]) + ++# setup fwupd script support ++AC_ARG_ENABLE([fwupd_script], ++ AS_HELP_STRING([--enable-fwupd_script], [Enable fwupd script support.])) ++AS_IF([test "x$enable_fwupd_script" == "xyes"], \ ++ [AC_DEFINE([FWUPD_SCRIPT],[],[Enable fwupd script support.])]) ++AM_CONDITIONAL([FWUPD_SCRIPT], [test "x$enable_fwupd_script" == "xyes"]) ++ + # Check for header files. + AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd development package required])]) + AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])]) +diff --git a/static/flash.cpp b/static/flash.cpp +index 82c2393..1bf29d5 100644 +--- a/static/flash.cpp ++++ b/static/flash.cpp +@@ -20,9 +20,11 @@ namespace updater + { + + namespace fs = std::experimental::filesystem; ++namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server; + + void Activation::flashWrite() + { ++#ifndef FWUPD_SCRIPT + // For static layout code update, just put images in /run/initramfs. + // It expects user to trigger a reboot and an updater script will program + // the image to flash during reboot. +@@ -33,11 +35,46 @@ void Activation::flashWrite() + fs::copy_file(uploadDir / versionId / bmcImage, toPath / bmcImage, + fs::copy_options::overwrite_existing); + } ++ ++#else ++ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, ++ SYSTEMD_INTERFACE, "StartUnit"); ++ method.append("fwupd@" + versionId + ".service", "replace"); ++ bus.call_noreply(method); ++#endif + } + +-void Activation::onStateChanges(sdbusplus::message::message& /*msg*/) ++void Activation::onStateChanges(sdbusplus::message::message& msg) + { +- // Empty ++#ifndef FWUPD_SCRIPT ++ uint32_t newStateID{}; ++ sdbusplus::message::object_path newStateObjPath; ++ std::string newStateUnit{}; ++ std::string newStateResult{}; ++ ++ msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult); ++ ++ auto rwServiceFile = "fwupdw@" + versionId + ".service"; ++ ++ if (newStateUnit == rwServiceFile && newStateResult == "done") ++ { ++ activationProgress->progress(100); ++ } ++ ++ if (newStateUnit == rwServiceFile) ++ { ++ if (newStateResult == "failed" || newStateResult == "dependency") ++ { ++ Activation::activation( ++ softwareServer::Activation::Activations::Failed); ++ } ++ else ++ { ++ Activation::activation( ++ softwareServer::Activation::Activations::Activating); ++ } ++ } ++#endif + } + + } // namespace updater +diff --git a/ubi/flash.cpp b/ubi/flash.cpp +index 5af2a17..ffa9348 100644 +--- a/ubi/flash.cpp ++++ b/ubi/flash.cpp +@@ -15,13 +15,10 @@ void Activation::flashWrite() + { + auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); +- std::string rwServiceFile = +- "obmc-flash-bmc-ubirw@" + versionId + ".service"; +- method.append(rwServiceFile, "replace"); ++ method.append("obmc-flash-bmc-ubirw.service", "replace"); + bus.call_noreply(method); + +- std::string roServiceFile = +- "obmc-flash-bmc-ubiro@" + versionId + ".service"; ++ auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; + method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); + method.append(roServiceFile, "replace"); +@@ -40,7 +37,7 @@ void Activation::onStateChanges(sdbusplus::message::message& msg) + // Read the msg and populate each variable + msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult); + +- auto rwServiceFile = "obmc-flash-bmc-ubirw@" + versionId + ".service"; ++ auto rwServiceFile = "obmc-flash-bmc-ubirw.service"; + auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; + auto ubootVarsServiceFile = + "obmc-flash-bmc-updateubootvars@" + versionId + ".service"; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch new file mode 100644 index 000000000..2d2ac2673 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch @@ -0,0 +1,44 @@ +From 9b3c44e9fb3d907c0152f14b967e23ab964c0e0b Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Thu, 14 Feb 2019 14:54:45 -0800 +Subject: [PATCH 6/6] Modify the ID of software image updater object on DBus to + allow force update onto same version image + +In the original design of image update, it does not allow the same version of image to be flashed onto itself. +But this blocks validation tests and in most of the cases we don't prevent user from doing such update. + +This patch appends a random number after the version ID hash string to unblock such limitation. + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Change-Id: I16aba4804ae1bc2e8784320f91c0419fb8b23c35 +--- + image_manager.cpp | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/image_manager.cpp b/image_manager.cpp +index 5b2ff49..e3d26e3 100644 +--- a/image_manager.cpp ++++ b/image_manager.cpp +@@ -9,6 +9,7 @@ + #include <stdlib.h> + #include <sys/stat.h> + #include <sys/wait.h> ++#include <time.h> + #include <unistd.h> + + #include <algorithm> +@@ -129,6 +130,11 @@ int Manager::processImage(const std::string& tarFilePath) + // Compute id + auto id = Version::getId(version); + ++ // Append a random number after the original version hash ++ // This will allow forcing image update onto the same version ++ srand(time(NULL)); ++ id = id + "_" + std::to_string(rand()); ++ + fs::path imageDirPath = std::string{IMG_UPLOAD_DIR}; + imageDirPath /= id; + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch new file mode 100644 index 000000000..34d5b6e67 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch @@ -0,0 +1,435 @@ +From 030f918b90ea45104bccf68082c2d634c6694238 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Tue, 13 Aug 2019 22:43:12 +0530 +Subject: [PATCH] PFR images support in phosphor-software-manager + +This commit adds support for handling the PFR images +upload and processing. + +Testing: +tested PFR image uploads and updates + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + Makefile.am | 18 +++- + activation.cpp | 2 +- + configure.ac | 7 ++ + item_updater.cpp | 6 +- + pfr_image_manager.cpp | 217 ++++++++++++++++++++++++++++++++++++++++++ + pfr_image_manager.hpp | 75 +++++++++++++++ + 6 files changed, 320 insertions(+), 5 deletions(-) + create mode 100644 pfr_image_manager.cpp + create mode 100644 pfr_image_manager.hpp + +diff --git a/Makefile.am b/Makefile.am +index 6c3ec16..59ebecc 100755 +--- a/Makefile.am ++++ b/Makefile.am +@@ -6,13 +6,20 @@ noinst_HEADERS = \ + watch.hpp \ + version.hpp \ + images.hpp \ +- image_manager.hpp \ + item_updater.hpp \ + activation.hpp \ + flash.hpp \ + item_updater_helper.hpp \ + utils.hpp + ++if PFR_UPDATE ++noinst_HEADERS += \ ++ pfr_image_manager.hpp ++else ++noinst_HEADERS += \ ++ image_manager.hpp ++endif ++ + bin_PROGRAMS = \ + phosphor-version-software-manager \ + phosphor-download-manager \ +@@ -24,8 +31,15 @@ dist_bin_SCRIPTS = \ + phosphor_version_software_manager_SOURCES = \ + image_manager_main.cpp \ + watch.cpp \ +- version.cpp \ ++ version.cpp ++ ++if PFR_UPDATE ++phosphor_version_software_manager_SOURCES += \ ++ pfr_image_manager.cpp ++else ++phosphor_version_software_manager_SOURCES += \ + image_manager.cpp ++endif + + BUILT_SOURCES = \ + xyz/openbmc_project/Software/Image/error.cpp \ +diff --git a/activation.cpp b/activation.cpp +index cea1e50..7ff4196 100644 +--- a/activation.cpp ++++ b/activation.cpp +@@ -197,7 +197,7 @@ auto Activation::activation(Activations value) -> Activations + } + else if (activationProgress->progress() == 100) + { +- log<level::ERR>("[Jennifer] progress == 100..."); ++ log<level::INFO>("progress == 100..."); + if (!redundancyPriority) + { + redundancyPriority = +diff --git a/configure.ac b/configure.ac +index 720e704..e527682 100755 +--- a/configure.ac ++++ b/configure.ac +@@ -191,6 +191,13 @@ AS_IF([test "x$enable_fwupd_script" == "xyes"], \ + [AC_DEFINE([FWUPD_SCRIPT],[],[Enable fwupd script support.])]) + AM_CONDITIONAL([FWUPD_SCRIPT], [test "x$enable_fwupd_script" == "xyes"]) + ++# setup pfr image update support ++AC_ARG_ENABLE([pfr_update], ++ AS_HELP_STRING([--enable-pfr_update], [Enable pfr image update support.])) ++AS_IF([test "x$enable_pfr_update" == "xyes"], \ ++ [AC_DEFINE([PFR_UPDATE],[],[Enable pfr image update support.])]) ++AM_CONDITIONAL([PFR_UPDATE], [test "x$enable_pfr_update" == "xyes"]) ++ + # Check for header files. + AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd development package required])]) + AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])]) +diff --git a/item_updater.cpp b/item_updater.cpp +index 21fb6e0..fd76a7f 100644 +--- a/item_updater.cpp ++++ b/item_updater.cpp +@@ -64,7 +64,8 @@ void ItemUpdater::createActivation(sdbusplus::message::message& msg) + auto value = SVersion::convertVersionPurposeFromString( + variant_ns::get<std::string>(property.second)); + if (value == VersionPurpose::BMC || +- value == VersionPurpose::System) ++ value == VersionPurpose::Host || ++ value == VersionPurpose::Other) + { + purpose = value; + } +@@ -356,6 +357,7 @@ void ItemUpdater::deleteAll() + ItemUpdater::ActivationStatus + ItemUpdater::validateSquashFSImage(const std::string& filePath) + { ++#ifndef PFR_UPDATE + bool invalid = false; + + for (auto& bmcImage : bmcImages) +@@ -375,7 +377,7 @@ ItemUpdater::ActivationStatus + { + return ItemUpdater::ActivationStatus::invalid; + } +- ++#endif + return ItemUpdater::ActivationStatus::ready; + } + +diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp +new file mode 100644 +index 0000000..242a6ca +--- /dev/null ++++ b/pfr_image_manager.cpp +@@ -0,0 +1,217 @@ ++#include "config.h" ++ ++#include "pfr_image_manager.hpp" ++ ++#include "version.hpp" ++#include "watch.hpp" ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <sys/stat.h> ++#include <sys/wait.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <algorithm> ++#include <cstring> ++#include <elog-errors.hpp> ++#include <filesystem> ++#include <fstream> ++#include <iomanip> ++#include <sstream> ++#include <string> ++#include <xyz/openbmc_project/Software/Image/error.hpp> ++ ++namespace phosphor ++{ ++namespace software ++{ ++namespace manager ++{ ++ ++using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error; ++namespace Software = phosphor::logging::xyz::openbmc_project::Software; ++ ++static constexpr const uint32_t pfmPos = 2054; ++ ++static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType, ++ std::string& version) ++{ ++ struct pfrImgBlock0 block0Data; ++ uint8_t verData[2]; ++ ++ if (std::filesystem::exists(imgPath)) ++ { ++ try ++ { ++ std::ifstream imgFile(imgPath, std::ios::binary | std::ios::in); ++ ++ if (!imgFile.good()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Image file read failed"); ++ return -1; ++ } ++ ++ imgFile.read(reinterpret_cast<char*>(&block0Data), ++ sizeof(block0Data)); ++ imgType = block0Data.pcType[0]; ++ imgFile.seekg(pfmPos, ++ std::ios::beg); // Version is at 0x806 in the PFM ++ imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData)); ++ imgFile.close(); ++ version = ++ std::to_string(verData[0]) + "." + std::to_string(verData[1]); ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "PFR image", ++ phosphor::logging::entry("PCType=%d", block0Data.pcType[0]), ++ phosphor::logging::entry("VERSION=%s", version.c_str())); ++ } ++ catch (std::exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++int Manager::processImage(const std::string& imgFilePath) ++{ ++ std::filesystem::path imgPath(imgFilePath); ++ ++ if (!std::filesystem::exists(imgPath)) ++ return -1; ++ ++ uint8_t imgType; ++ int retry = 3; ++ std::string ver; ++ std::string purposeString; ++ ++ if (0 != getPFRImgInfo(imgFilePath, imgType, ver)) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error reading uploaded image type and version"); ++ return -1; ++ } ++ ++ if (ver.empty()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Empty version from image file"); ++ return -1; ++ } ++ ++ if (imgType == pfrBMCUpdateCap) ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"; ++ } ++ else if (imgType == pfrPCHUpdateCap) ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Host"; ++ } ++ else if (imgType == pfrCPLDUpdateCap) ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Other"; ++ } ++ else ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Unknown"; ++ ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unknown image type"); ++ return -1; ++ } ++ ++ sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose ++ purpose = Version::VersionPurpose::Unknown; ++ try ++ { ++ purpose = Version::convertVersionPurposeFromString(purposeString); ++ } ++ catch (const sdbusplus::exception::InvalidEnumString& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error: Failed to convert purpose to enum." ++ " Setting to Unknown."); ++ } ++ ++ // Compute id ++ std::string id = Version::getId(ver); ++ ++ // Append a random number after the original version hash ++ // This will allow forcing image update onto the same version ++ // with 3 retries on random number generation. ++ do ++ { ++ srand(time(NULL)); ++ id = id + "_" + std::to_string(rand()); ++ } while ((versions.find(id) != versions.end()) && retry--); ++ ++ if (versions.find(id) != versions.end()) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Software Object with the same version already exists, exiting " ++ "the update", ++ phosphor::logging::entry("VERSION_ID=%s", id.c_str())); ++ ++ return -1; ++ } ++ ++ std::filesystem::path imageDirPath(IMG_UPLOAD_DIR); ++ imageDirPath /= id; ++ ++ std::filesystem::create_directory(imageDirPath); ++ ++ std::filesystem::path newFileName = imageDirPath / "image-runtime"; ++ std::filesystem::rename(imgFilePath, newFileName); ++ ++ // Create Version object ++ std::string objPath = std::string{SOFTWARE_OBJPATH} + '/' + id; ++ ++ auto versionPtr = std::make_unique<Version>( ++ bus, objPath, ver, purpose, imageDirPath.string(), ++ std::bind(&Manager::erase, this, std::placeholders::_1)); ++ versionPtr->deleteObject = ++ std::make_unique<phosphor::software::manager::Delete>(bus, objPath, ++ *versionPtr); ++ versions.insert(std::make_pair(id, std::move(versionPtr))); ++ ++ return 0; ++} ++ ++void Manager::erase(std::string entryId) ++{ ++ auto it = versions.find(entryId); ++ if (it == versions.end()) ++ { ++ return; ++ } ++ ++ if (it->second->isFunctional()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ ("Error: Version " + entryId + ++ " is currently running on the BMC." ++ " Unable to remove.") ++ .c_str()); ++ return; ++ } ++ ++ // Delete image dir ++ std::filesystem::path imageDirPath = (*(it->second)).path(); ++ if (std::filesystem::exists(imageDirPath)) ++ { ++ std::filesystem::remove_all(imageDirPath); ++ } ++ this->versions.erase(entryId); ++} ++ ++} // namespace manager ++} // namespace software ++} // namespace phosphor +diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp +new file mode 100644 +index 0000000..c6ee6a4 +--- /dev/null ++++ b/pfr_image_manager.hpp +@@ -0,0 +1,75 @@ ++#pragma once ++#include "version.hpp" ++ ++#include <sdbusplus/server.hpp> ++ ++namespace phosphor ++{ ++namespace software ++{ ++namespace manager ++{ ++ ++enum pfrImgPCType { ++ pfrCPLDUpdateCap = 0x00, ++ pfrPCHPFM = 0x01, ++ pfrPCHUpdateCap = 0x02, ++ pfrBMCPFM = 0x03, ++ pfrBMCUpdateCap = 0x04 ++}; ++ ++/* PFR image block 0 - As defined in HAS */ ++struct pfrImgBlock0 { ++ uint8_t tag[4]; ++ uint8_t pcLength[4]; ++ uint8_t pcType[4]; ++ uint8_t reserved1[4]; ++ uint8_t hash256[32]; ++ uint8_t hash384[48]; ++ uint8_t reserved2[32]; ++}__attribute__((packed)); ++ ++/** @class Manager ++ * @brief Contains a map of Version dbus objects. ++ * @details The software image manager class that contains the Version dbus ++ * objects and their version ids. ++ */ ++class Manager ++{ ++ public: ++ /** @brief Constructs Manager Class ++ * ++ * @param[in] bus - The Dbus bus object ++ */ ++ Manager(sdbusplus::bus::bus& bus) : bus(bus){}; ++ ++ /** ++ * @brief Verify the image and provide the image to updater. ++ * Create and populate the version and file path interfaces. ++ * ++ * @param[in] uploaded image. ++ * @param[out] result - 0 if successful. ++ */ ++ int processImage(const std::string& imageFilePath); ++ ++ /** ++ * @brief Erase specified entry d-bus object ++ * and deletes the image file. ++ * ++ * @param[in] entryId - unique identifier of the entry ++ */ ++ void erase(std::string entryId); ++ ++ private: ++ /** @brief Persistent map of Version dbus objects and their ++ * version id */ ++ std::map<std::string, std::unique_ptr<Version>> versions; ++ ++ /** @brief Persistent sdbusplus DBus bus connection. */ ++ sdbusplus::bus::bus& bus; ++ ++}; ++ ++} // namespace manager ++} // namespace software ++} // namespace phosphor +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service new file mode 100644 index 000000000..d51fee312 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service @@ -0,0 +1,8 @@ +[Unit]
+Description=Flash BMC with fwupd script : %I
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/usr/bin/fwupd.sh file:////tmp/images/%i/image-runtime
+SyslogIdentifier=fwupd
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend new file mode 100644 index 000000000..90da32ac2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend @@ -0,0 +1,14 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +EXTRA_OECONF += "--enable-fwupd_script" + +SYSTEMD_SERVICE_${PN}-updater += "fwupd@.service" + +EXTRA_OECONF += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '--enable-pfr_update', '', d)}" + +SRC_URI += "file://0002-Redfish-firmware-activation.patch \ + file://0004-Changed-the-condition-of-software-version-service-wa.patch \ + file://0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch \ + file://0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch \ + " + +SRC_URI += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'file://0007-PFR-images-support.patch', '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb new file mode 100644 index 000000000..53cec437d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb @@ -0,0 +1,30 @@ +SUMMARY = "Default Fru" +DESCRIPTION = "Builds a default FRU file at runtime based on board ID" + +inherit systemd +inherit cmake + +SYSTEMD_SERVICE_${PN} = "SetBaseboardFru.service" + +S = "${WORKDIR}" +SRC_URI = "file://checkFru.sh \ + file://SetBaseboardFru.service \ + file://mkfru.cpp \ + file://CMakeLists.txt \ + " + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "\ + file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658 \ + file://mkfru.cpp;beginline=2;endline=14;md5=c451359f18a13ee69602afce1588c01a \ + " + +RDEPENDS_${PN} = "bash" + +do_install_append() { + install -d ${D}${bindir} + install -m 0755 ${S}/checkFru.sh ${D}/${bindir}/checkFru.sh + + install -d ${D}${base_libdir}/systemd/system + install -m 0644 ${S}/SetBaseboardFru.service ${D}${base_libdir}/systemd/system +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt new file mode 100644 index 000000000..a8e633644 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(mkfru CXX) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +add_executable(mkfru mkfru.cpp) +install(TARGETS mkfru DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service new file mode 100644 index 000000000..d8c2a75ac --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service @@ -0,0 +1,9 @@ +[Unit] +Description=Check for FRU presence + +[Service] +ExecStart=/usr/bin/checkFru.sh +Type=oneshot + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh new file mode 100755 index 000000000..908e4b51e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# this script checks the gpio id and loads the correct baseboard fru +FRUPATH="/etc/fru" +fruFile="$FRUPATH/baseboard.fru.bin" +if [ -f $fruFile ]; then + exit 0 +fi + +read_id() { + local idx=0 + local result=0 + local value=0 + for ((idx=0; idx<6; idx++)) + do + typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N")) + value=$((value << idx)) + result=$((result | value)) + done + echo $result +} + +BOARD_ID=$(read_id) +if grep -q 'CPU part\s*: 0xb76' /proc/cpuinfo; then + # AST2500 + case $BOARD_ID in + 12) NAME="D50TNP1SB";; + 40) NAME="CooperCity";; + 45) NAME="WilsonCity";; + 60) NAME="M50CYP2SB2U";; + 62) NAME="WilsonPoint";; + *) NAME="S2600WFT";; + esac +fi + +if [ -z "$NAME" ]; then + NAME="Unknown" +fi + +cd /tmp +mkdir -p $FRUPATH +mkfru $NAME +mv $NAME.fru.bin $fruFile + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp new file mode 100644 index 000000000..afadbd324 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp @@ -0,0 +1,219 @@ +/* +// Copyright (c) 2019 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. +// +// Abstract: default FRU generation +// +*/ + +#include <fstream> +#include <iostream> +#include <iterator> +#include <numeric> +#include <string> +#include <vector> + +constexpr uint8_t fillChar = '.'; +constexpr uint8_t eof = 0xc1; +const std::string intel = "Intel Corporation"; + +// round up to nearest block size (power of 2) +constexpr size_t blockRound(size_t len, size_t blk) +{ + return ((len) + (((blk) - ((len) & ((blk)-1))) & ((blk)-1))); +} + +uint8_t mklen(uint8_t len) +{ + return static_cast<uint8_t>((0x3 << 6) | len); +} + +struct FruEntry +{ + static constexpr size_t fruBlockSize = 8; // type, length, checksum + static constexpr size_t fixedBytes = 3; // type, length, checksum + FruEntry() = delete; + FruEntry(const std::vector<uint8_t>& contents) + { + constexpr size_t verOffset = 0; + constexpr size_t lenOffset = 1; + value.resize(blockRound(fixedBytes + contents.size(), fruBlockSize)); + value[verOffset] = 1; + value[lenOffset] = blocks(); + std::copy(contents.begin(), contents.end(), value.begin() + 2); + addChecksum(); + } + + void addChecksum() + { + int sum = std::accumulate(value.begin(), value.end(), 0); + value.back() = static_cast<uint8_t>(256 - sum & 0xff); + } + + uint8_t blocks() const + { + return static_cast<uint8_t>(value.size() / 8); + } + + std::vector<uint8_t> value; +}; + +size_t fillDots(std::vector<uint8_t>::iterator start, size_t count) +{ + *start++ = mklen(count); // prefix with (0xc0 | count) + auto end = start + count++; + std::fill(start, end, '.'); + return count; +} + +size_t fillStr(std::vector<uint8_t>::iterator start, const std::string& str) +{ + size_t count = str.size(); + *start++ = mklen(count++); // prefix with (0xc0 | count) + std::copy(str.begin(), str.end(), start); + return count; +} + +std::vector<uint8_t> genChassisContents() +{ + constexpr size_t pnSize = 18; + constexpr size_t snSize = 18; + constexpr size_t amSize = 31; + constexpr size_t headerSize = 1; + constexpr size_t contentSize = headerSize + 1 + pnSize + 1 + snSize + 1 + + amSize + 1 + amSize + sizeof(eof); + std::vector<uint8_t> data(contentSize); + size_t offset = 0; + // chassis type (main server chassis) + data[offset++] = 0x17; + // chassis part number + offset += fillDots(data.begin() + offset, pnSize); + // chassis serial number + offset += fillDots(data.begin() + offset, snSize); + // info am1 + offset += fillDots(data.begin() + offset, amSize); + // info am2 + offset += fillDots(data.begin() + offset, amSize); + data[offset] = eof; + + return data; +} + +std::vector<uint8_t> genBoardContents(const std::string& name) +{ + constexpr size_t headerSize = 4; + constexpr size_t snSize = 12; + constexpr size_t pnSize = 10; + const std::string version = "FRU Ver 0.01"; + size_t contentSize = headerSize + 1 + name.size() + 1 + intel.size() + 1 + + snSize + 1 + pnSize + 1 + version.size() + sizeof(eof); + std::vector<uint8_t> data(contentSize); + size_t offset = 0; + // chassis type (main server chassis) + data[offset++] = 0; // language code + data[offset++] = 0; // mfg date/time + data[offset++] = 0; // mfg date/time + data[offset++] = 0; // mfg date/time + // manufacturer name + offset += fillStr(data.begin() + offset, intel); + // product name + offset += fillStr(data.begin() + offset, name); + // board sn + offset += fillDots(data.begin() + offset, snSize); + // board pn + offset += fillDots(data.begin() + offset, pnSize); + // fru version string + offset += fillStr(data.begin() + offset, version); + data[offset] = eof; + + return data; +} + +std::vector<uint8_t> genProductContents(const std::string& name) +{ + constexpr size_t headerSize = 1; + constexpr size_t pnSize = 10; + constexpr size_t pvSize = 20; + constexpr size_t snSize = 12; + constexpr size_t atSize = 20; + constexpr size_t idSize = 0; + const std::string version = "FRU Ver 0.01"; + size_t contentSize = headerSize + 1 + intel.size() + 1 + name.size() + 1 + + pnSize + 1 + pvSize + 1 + snSize + 1 + atSize + 1 + + idSize + sizeof(eof); + std::vector<uint8_t> data(contentSize); + size_t offset = 0; + // chassis type (main server chassis) + data[offset++] = 0; // language code + // manufacturer name + offset += fillStr(data.begin() + offset, intel); + // product name + offset += fillStr(data.begin() + offset, name); + // product part number + offset += fillDots(data.begin() + offset, pnSize); + // product version + offset += fillDots(data.begin() + offset, pvSize); + // product serial number + offset += fillDots(data.begin() + offset, snSize); + // product asset tag + offset += fillDots(data.begin() + offset, atSize); + // empty fru file id + offset += fillDots(data.begin() + offset, idSize); + data[offset] = eof; + + return data; +} + +int createFru(const std::string& name) +{ + std::vector<uint8_t> internal{1, 0, 0, 0, 0, 0, 0, 1}; // fixed data + FruEntry chassis(genChassisContents()); + FruEntry board(genBoardContents(name)); + FruEntry product(genProductContents(name)); + uint8_t offset = 1; // room for header's offset + FruEntry header({ + offset += 1, // internal size + offset += chassis.blocks(), + offset += board.blocks(), + }); + std::string filename = name + ".fru.bin"; + std::ofstream output(filename); + std::ostream_iterator<uint8_t> outputIter(output); + std::copy(header.value.begin(), header.value.end(), outputIter); + std::copy(internal.begin(), internal.end(), outputIter); + std::copy(chassis.value.begin(), chassis.value.end(), outputIter); + std::copy(board.value.begin(), board.value.end(), outputIter); + std::copy(product.value.begin(), product.value.end(), outputIter); + constexpr size_t minFruSize = 0x1ff; + size_t fruSize = header.value.size() + internal.size() + + chassis.value.size() + board.value.size() + + product.value.size(); + if (fruSize < minFruSize) + { + std::vector<uint8_t> padding(minFruSize - fruSize); + std::copy(padding.begin(), padding.end(), outputIter); + } + output.close(); + return 0; +} + +int main(int argc, const char* argv[]) +{ + if (argc != 2) + { + std::cerr << "Usage: " << argv[0] << " <'Product Name'>\n"; + return 1; + } + return createFru(argv[1]); +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend new file mode 100644 index 000000000..5326680f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend @@ -0,0 +1,6 @@ +SYSTEMD_LINK_${PN}_remove += "../op-start-host@.service:obmc-host-startmin@0.target.requires/op-start-host@0.service" +SYSTEMD_LINK_${PN}_remove += "../op-init-pnor@.service:obmc-host-startmin@0.target.requires/op-init-pnor@0.service" + +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires" +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires/op-start-host@0.service" +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires/op-init-pnor@0.service"
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket new file mode 100644 index 000000000..8782e4dd3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket @@ -0,0 +1,9 @@ +[Unit] +Description=BMC Webserver socket + +[Socket] +ListenStream=443 +ReusePort=true + +[Install] +WantedBy=sockets.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend new file mode 100644 index 000000000..5a2e55497 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend @@ -0,0 +1,20 @@ +SRC_URI = "git://github.com/openbmc/bmcweb.git" +SRCREV = "c80fee55c3663e5ac620a4d11378799c91867b76" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +# add a user called bmcweb for the server to assume +# bmcweb is part of group shadow for non-root pam authentication +USERADD_PARAM_${PN} = "-r -s /usr/sbin/nologin -d /home/bmcweb -m -G shadow bmcweb" + +GROUPADD_PARAM_${PN} = "web; redfish " + +# Enable CPU Log and Raw PECI support +EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_CPU_LOG=ON" +EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_RAW_PECI=ON" + +# Enable Redfish BMC Journal support +EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_BMC_JOURNAL=ON" + +# Enable PFR support +EXTRA_OECMAKE += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-DBMCWEB_ENABLE_REDFISH_PFR_FEATURE=ON', '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend new file mode 100644 index 000000000..616fb9a75 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend @@ -0,0 +1,21 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += " file://dev_id.json \ + file://channel_access.json \ + file://channel_config.json \ + file://master_write_read_white_list.json \ + " + +FILES_${PN} += " \ + ${datadir}/ipmi-providers/channel_access.json \ + ${datadir}/ipmi-providers/channel_config.json \ + ${datadir}/ipmi-providers/master_write_read_white_list.json \ + " + +do_install_append() { + install -m 0644 -D ${WORKDIR}/channel_access.json \ + ${D}${datadir}/ipmi-providers/channel_access.json + install -m 0644 -D ${WORKDIR}/channel_config.json \ + ${D}${datadir}/ipmi-providers/channel_config.json + install -m 0644 -D ${WORKDIR}/master_write_read_white_list.json \ + ${D}${datadir}/ipmi-providers/master_write_read_white_list.json +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json new file mode 100644 index 000000000..299483121 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json @@ -0,0 +1,23 @@ +{ + "1" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + }, + "2" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + }, + "3" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + } +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json new file mode 100644 index 000000000..dc9c2ce20 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json @@ -0,0 +1,178 @@ +{ + "0" : { + "name" : "IPMB", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "1" : { + "name" : "eth1", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "lan-802.3", + "protocol_type" : "ipmb-1.0", + "session_supported" : "multi-session", + "is_ipmi" : true + } + }, + "2" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "3" : { + "name" : "eth0", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "lan-802.3", + "protocol_type" : "ipmb-1.0", + "session_supported" : "multi-session", + "is_ipmi" : true + } + }, + "4" : { + "name" : "RESERVED", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "5" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "6" : { + "name" : "SMLINK", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "7" : { + "name" : "ipmi_kcs4", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "system-interface", + "protocol_type" : "kcs", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "8" : { + "name" : "INTRABMC", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "oem", + "protocol_type" : "oem", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "9" : { + "name" : "SIPMB", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "10" : { + "name" : "PCIE", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "11" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "12" : { + "name" : "INTERNAL", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "13" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "14" : { + "name" : "SELF", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "unknown", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "15" : { + "name" : "ipmi_kcs3", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "system-interface", + "protocol_type" : "kcs", + "session_supported" : "session-less", + "is_ipmi" : true + } + } +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json new file mode 100644 index 000000000..e561569d9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json @@ -0,0 +1,2 @@ +{"id": 35, "revision": 0, "addn_dev_support": 191, + "manuf_id": 343, "prod_id": 123, "aux": 0} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json new file mode 100644 index 000000000..6fc46f452 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json @@ -0,0 +1,76 @@ +{ + "filters": [ + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x01", + "slaveAddr": "0x4d", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x01", + "slaveAddr": "0x57", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x02", + "slaveAddr": "0x40", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x02", + "slaveAddr": "0x49", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x02", + "slaveAddr": "0x51", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x03", + "slaveAddr": "0x44", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x03", + "slaveAddr": "0x68", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x06", + "slaveAddr": "0x40", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x07", + "slaveAddr": "0x51", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + } + ] +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend new file mode 100644 index 000000000..2d892ad1a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend @@ -0,0 +1,8 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += " file://config.yaml" + +#override source file before it is used for final FRU file (merged from multiple sources) +do_install() { + cp ${WORKDIR}/config.yaml ${config_datadir}/ +} + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml new file mode 100644 index 000000000..e9b7a621e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml @@ -0,0 +1,31 @@ +# A YAML similar to this example would have to be generated, for eg with MRW +# inputs and system configuration, to depict IPMI Fru information. +# +# This file maps IPMI properties to phosphor dbus inventory properties +# +# This YAML could help generate C++ code. +# Format of the YAML: +# Fruid: +# Associated Fru paths +# d-bus Interfaces +# d-bus Properties +# IPMI Fru mapping +0: + /system/board/WFP_Baseboard: + entityID: 23 + entityInstance: 1 + interfaces: + xyz.openbmc_project.Inventory.Item: + name: + IPMIFruProperty: Product Name + IPMIFruSection: Product + xyz.openbmc_project.Inventory.Decorator.Asset: + Manufacturer: + IPMIFruProperty: Manufacturer + IPMIFruSection: Product + PartNumber: + IPMIFruProperty: Part Number + IPMIFruSection: Product + SerialNumber: + IPMIFruProperty: Serial Number + IPMIFruSection: Product diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch new file mode 100644 index 000000000..c862a306a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch @@ -0,0 +1,877 @@ +From c20bc8eb6a08d177d951012eb91b37398b15d81d Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Tue, 27 Nov 2018 11:01:15 -0800 +Subject: [PATCH] IPv6 Network changes + +Allow IPv6 IPMI set/get commands + +Signed-off-by: David Cobbley <david.j.cobbley@linux.intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> + +Change-Id: If5528d3b7294c5f8c17db5919439235d0fad0446 +--- + include/ipmid/types.hpp | 9 + + include/ipmid/utils.hpp | 1 + + transporthandler.cpp | 654 +++++++++++++++++++++++++++++++++++++++- + transporthandler.hpp | 50 +++ + 4 files changed, 713 insertions(+), 1 deletion(-) + +Index: phosphor-host-ipmid.clean/include/ipmid/types.hpp +=================================================================== +--- phosphor-host-ipmid.clean.orig/include/ipmid/types.hpp ++++ phosphor-host-ipmid.clean/include/ipmid/types.hpp +@@ -224,6 +224,7 @@ constexpr auto ADDR_TYPE_FORMAT = "%hhx" + + constexpr auto IPV4_ADDRESS_SIZE_BYTE = 4; + constexpr auto IPV6_ADDRESS_SIZE_BYTE = 16; ++constexpr auto IPV6_ADDRESS_STATUS_SIZE = 22; + + constexpr auto DEFAULT_MAC_ADDRESS = "00:00:00:00:00:00"; + constexpr auto DEFAULT_ADDRESS = "0.0.0.0"; +@@ -235,6 +236,7 @@ constexpr auto BITS_32 = 32; + constexpr auto MASK_32_BIT = 0xFFFFFFFF; + constexpr auto VLAN_ID_MASK = 0x00000FFF; + constexpr auto VLAN_ENABLE_MASK = 0x8000; ++constexpr auto IPV6_DUID_SIZE = 18; + + enum class IPOrigin : uint8_t + { +@@ -243,5 +245,12 @@ enum class IPOrigin : uint8_t + DHCP = 2, + }; + ++enum class AddressingEnables : uint8_t ++{ ++ IPv4Only = 0, ++ IPv6Only = 1, ++ IPv4AndIPv6 = 2, ++}; ++ + } // namespace network + } // namespace ipmi +Index: phosphor-host-ipmid.clean/include/ipmid/utils.hpp +=================================================================== +--- phosphor-host-ipmid.clean.orig/include/ipmid/utils.hpp ++++ phosphor-host-ipmid.clean/include/ipmid/utils.hpp +@@ -256,6 +256,7 @@ namespace network + constexpr auto ROOT = "/xyz/openbmc_project/network"; + constexpr auto SERVICE = "xyz.openbmc_project.Network"; + constexpr auto IP_TYPE = "ipv4"; ++constexpr auto IPV6_TYPE = "ipv6"; + constexpr auto IPV4_PREFIX = "169.254"; + constexpr auto IPV6_PREFIX = "fe80"; + constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP"; +Index: phosphor-host-ipmid.clean/transporthandler.cpp +=================================================================== +--- phosphor-host-ipmid.clean.orig/transporthandler.cpp ++++ phosphor-host-ipmid.clean/transporthandler.cpp +@@ -29,6 +29,12 @@ std::unique_ptr<phosphor::Timer> network + + const int SIZE_MAC = 18; // xx:xx:xx:xx:xx:xx + constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4"; ++constexpr auto ipv6Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv6"; ++ ++static const std::array<std::string, 3> ipAddressEnablesType = { ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4Only", ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv6Only", ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4AndIPv6"}; + + std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig; + +@@ -445,6 +451,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + { + case LanParam::IP: + { ++ if (reqLen != lanParamIPSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + std::snprintf(ipaddr, INET_ADDRSTRLEN, + ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], + reqptr->data[1], reqptr->data[2], reqptr->data[3]); +@@ -455,6 +466,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + + case LanParam::IPSRC: + { ++ if (reqLen != lanParamIPSrcSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + uint8_t ipsrc{}; + std::memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE); + channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc); +@@ -463,6 +479,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + + case LanParam::MAC: + { ++ if (reqLen != lanParamMACSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + char mac[SIZE_MAC]; + + std::snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT, +@@ -483,6 +504,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + + case LanParam::SUBNET: + { ++ if (reqLen != lanParamSubnetSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + std::snprintf(netmask, INET_ADDRSTRLEN, + ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], + reqptr->data[1], reqptr->data[2], reqptr->data[3]); +@@ -492,6 +518,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + + case LanParam::GATEWAY: + { ++ if (reqLen != lanParamGatewaySize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + std::snprintf(gateway, INET_ADDRSTRLEN, + ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], + reqptr->data[1], reqptr->data[2], reqptr->data[3]); +@@ -522,6 +553,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + + case LanParam::INPROGRESS: + { ++ if (reqLen != lanParamInProgressSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + if (reqptr->data[0] == SET_COMPLETE) + { + channelConf->lan_set_in_progress = SET_COMPLETE; +@@ -540,6 +576,122 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n + } + break; + ++ case LanParam::IPV6_AND_IPV4_ENABLES: ++ { ++ if (reqLen != lanParamIPv6AndIPv4EnablesSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6AddressingEnables = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ADDRESSES: ++ { ++ if (reqLen != lanParamIPv6StaticAddressesSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6AddressSource = ++ reqptr->data[1] & 0x81; // Looking at bit 0 and bit 7 ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, &reqptr->data[2], tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6Addr.assign(tmpIPV6); ++ channelConf->ipv6Prefix = reqptr->data[19]; ++ break; ++ } ++ ++ case LanParam::IPV6_ROUTER_ADDRESS_CONF_CTRL: ++ { ++ if (reqLen != lanParamIPv6RouterAddressConfCtrlSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6RouterAddressConfigControl = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_IP_ADDR: ++ { ++ if (reqLen != lanParamIPv6StaticRouter1IPAddrSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6GatewayAddr.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_LEN: ++ { ++ if (reqLen != lanParamIPv6StaticRouter1PrefixLenSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6GatewayPrefixLength = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_VAL: ++ { ++ if (reqLen != lanParamIPv6StaticRouter1PrefixValSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6GatewayPrefixValue.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_IP_ADDR: ++ { ++ if (reqLen != lanParamIPv6StaticRouter2IPAddrSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6BackupGatewayAddr.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_LEN: ++ { ++ if (reqLen != lanParamIPv6StaticRouter2PrefixLenSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6BackupGatewayPrefixLength = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_VAL: ++ { ++ if (reqLen != lanParamIPv6StaticRouter2PrefixValSize) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6BackupGatewayPrefixValue.assign(tmpIPV6); ++ break; ++ } ++ + default: + { + rc = IPMI_CC_PARM_NOT_SUPPORTED; +@@ -568,6 +720,7 @@ ipmi_ret_t ipmi_transport_get_lan(ipmi_n + ipmi_ret_t rc = IPMI_CC_OK; + *data_len = 0; + const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0 ++ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; + + get_lan_t* reqptr = (get_lan_t*)request; + // channel number is the lower nibble +@@ -713,6 +866,476 @@ ipmi_ret_t ipmi_transport_get_lan(ipmi_n + static_cast<uint8_t>(cipherList.size()); + break; + } ++ case LanParam::IPV6_AND_IPV4_SUPPORTED: ++ { ++ uint8_t addressSupport = ++ 0x1; // Allow both IPv4 & IPv6 simultaneously ++ std::array<uint8_t, 2> buf = {current_revision, addressSupport}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_AND_IPV4_ENABLES: ++ { ++ // If DHCP, check if you have an ipv6 and ipv4 address. If static ++ // return not supported ++ ++ // 00h check if conf DHCP == ipv4 or off ++ // 01h check if conf DHCP == ipv6 ++ // 02h check if DHCP == true ++ ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ std::string networkInterfacePath; ++ uint8_t ipVAddressEnables = 0; ++ ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ ipmi::ObjectTree ancestorMap; ++ // if the system has an ip object,then ++ // get the IP object. ++ auto ipObject = ++ ipmi::getDbusObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ // Get the parent interface of the IP object. ++ try ++ { ++ ipmi::InterfaceList interfaces; ++ interfaces.emplace_back( ++ ipmi::network::ETHERNET_INTERFACE); ++ ++ ancestorMap = ipmi::getAllAncestors( ++ bus, ipObject.first, std::move(interfaces)); ++ } ++ catch (InternalFailure& e) ++ { ++ // if unable to get the parent interface ++ // then commit the error and return. ++ log<level::ERR>( ++ "Unable to get the parent interface", ++ entry("PATH=%s", ipObject.first.c_str()), ++ entry("INTERFACE=%s", ++ ipmi::network::ETHERNET_INTERFACE)); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ // for an ip object there would be single parent ++ // interface. ++ networkInterfacePath = ancestorMap.begin()->first; ++ } ++ catch (InternalFailure& e) ++ { ++ // if there is no ip configured on the system,then ++ // get the network interface object. ++ auto networkInterfaceObject = ipmi::getDbusObject( ++ bus, ipmi::network::ETHERNET_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ networkInterfacePath = networkInterfaceObject.first; ++ } ++ ++ ipmi::Value ipEnablesProp = ipmi::getDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfacePath, ++ ipmi::network::ETHERNET_INTERFACE, "IPAddressEnables"); ++ std::string ipEnables = std::get<std::string>(ipEnablesProp); ++ ++ // check if on off ipv4 ipv6, etc. ++ bool found = false; ++ for (uint8_t ii = 0; ii < ipAddressEnablesType.size(); ii++) ++ { ++ if (ipEnables == ipAddressEnablesType[ii]) ++ { ++ ipVAddressEnables = ii; ++ found = true; ++ break; ++ } ++ } ++ if (!found) ++ { ++ return IPMI_CC_PARM_NOT_SUPPORTED; ++ } ++ } ++ else ++ { ++ ipVAddressEnables = channelConf->ipv6AddressingEnables; ++ } ++ ++ std::array<uint8_t, 2> buf = {current_revision, ipVAddressEnables}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATUS: ++ { ++ // Number of IPV6 addresses that are supported ++ constexpr std::array<uint8_t, 3> statusData = {1, 1, 3}; ++ ++ std::array<uint8_t, 4> buf = {current_revision, statusData[0], ++ statusData[1], statusData[2]}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ADDRESSES: ++ { ++ // Only return set selector 0 ++ uint8_t ipv6SetSelector = 0; ++ std::string ipaddress; ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ uint8_t ipv6AddressSource = 0; ++ uint8_t prefixLength = 0; ++ uint8_t status = 0; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ auto ipObjectInfo = ++ ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ auto properties = ipmi::getAllDbusProperties( ++ bus, ipObjectInfo.second, ipObjectInfo.first, ++ ipmi::network::IP_INTERFACE); ++ ++ if (std::get<std::string>(properties["Origin"]) == ++ "xyz.openbmc_project.Network.IP.AddressOrigin.Static") ++ { ++ ipaddress = ++ std::get<std::string>(properties["Address"]); ++ ipv6AddressSource = 0x81; // Looking at bit 0 and bit 7 ++ prefixLength = ++ std::get<uint8_t>(properties["PrefixLength"]); ++ status = 0; ++ } ++ } ++ // ignore the exception, as it is a valid condition that ++ // the system is not configured with any IP. ++ catch (InternalFailure& e) ++ { ++ // nothing to do. ++ } ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ ipv6AddressSource = channelConf->ipv6AddressSource; ++ ipaddress = channelConf->ipv6Addr.c_str(); ++ prefixLength = channelConf->ipv6Prefix; ++ status = 1; ++ } ++ ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_STATUS_SIZE> buf = { ++ current_revision, ipv6SetSelector, ipv6AddressSource}; ++ inet_pton(AF_INET6, ipaddress.c_str(), ++ reinterpret_cast<void*>(&buf[3])); ++ buf[20] = prefixLength; ++ buf[21] = status; ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_STATIC_DUID_STORAGE_LENGTH: ++ { ++ // DHCP unique identified ++ // Only 1 read-only 16-byte Block needed ++ uint8_t duidLength = 1; ++ std::array<uint8_t, 2> buf = {current_revision, duidLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_STATIC_DUIDS: ++ { ++ std::string macAddress; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ auto macObjectInfo = ++ ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, macObjectInfo.second, macObjectInfo.first, ++ ipmi::network::MAC_INTERFACE, "MACAddress"); ++ ++ macAddress = std::get<std::string>(variant); ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ macAddress = channelConf->macAddress; ++ } ++ ++ std::array<uint8_t, ++ ipmi::network::IPV6_DUID_SIZE + sizeof(current_revision)> ++ buf; ++ buf = {current_revision, ++ reqptr->parameter_set, ++ reqptr->parameter_block, ++ DUID_LEN, ++ 0, // Filler byte ++ DUID_LL_TYPE, ++ 0, // Filler byte ++ DUIC_ETH_HW_TYPE}; ++ sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, ++ (&buf[8]), (&buf[9]), (&buf[10]), (&buf[11]), (&buf[12]), ++ (&buf[13])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DYNAMIC_ADDRESSES: ++ { ++ std::string ipaddress; ++ uint8_t ipv6AddressSource = 0; ++ uint8_t prefixLength = 0; ++ uint8_t status = 0; ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ auto ipObjectInfo = ++ ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ auto properties = ipmi::getAllDbusProperties( ++ bus, ipObjectInfo.second, ipObjectInfo.first, ++ ipmi::network::IP_INTERFACE); ++ ++ if (std::get<std::string>(properties["Origin"]) == ++ "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") ++ { ++ ipaddress = ++ std::get<std::string>(properties["Address"]); ++ ipv6AddressSource = 0x81; // Looking at bit 0 and bit 7 ++ prefixLength = ++ std::get<uint8_t>(properties["PrefixLength"]); ++ status = 0; ++ } ++ else ++ { ++ status = 1; ++ } ++ } ++ // ignore the exception, as it is a valid condition that ++ // the system is not configured with any IP. ++ catch (InternalFailure& e) ++ { ++ // nothing to do. ++ } ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ ipaddress = channelConf->ipv6Addr; ++ ipv6AddressSource = channelConf->ipv6AddressSource; ++ prefixLength = channelConf->ipv6Prefix; ++ status = channelConf->ipv6AddressStatus; ++ } ++ ++ uint8_t ipv6SetSelector = 0; ++ std::array<uint8_t, 22> buf = {current_revision, ipv6SetSelector, ++ ipv6AddressSource}; ++ inet_pton(AF_INET6, ipaddress.c_str(), ++ reinterpret_cast<void*>(&buf[3])); ++ buf[20] = prefixLength; ++ buf[21] = status; ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_DYNAMIC_DUID_STOR_LEN: ++ { ++ uint8_t duidLength = 0; ++ // Only 1 read-only 16-byte Block needed ++ duidLength = 1; ++ ++ std::array<uint8_t, 2> buf = {current_revision, duidLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_DYNAMIC_DUIDS: ++ { ++ std::string macAddress; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ auto macObjectInfo = ++ ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, macObjectInfo.second, macObjectInfo.first, ++ ipmi::network::MAC_INTERFACE, "MACAddress"); ++ ++ macAddress = std::get<std::string>(variant); ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ macAddress = channelConf->macAddress; ++ } ++ ++ std::array<uint8_t, ++ ipmi::network::IPV6_DUID_SIZE + sizeof(current_revision)> ++ buf; ++ buf = {current_revision, ++ reqptr->parameter_set, ++ reqptr->parameter_block, ++ DUID_LEN, ++ 0, // Filler byte ++ DUID_LL_TYPE, ++ 0, // Filler byte ++ DUIC_ETH_HW_TYPE}; ++ ++ sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, ++ (&buf[8]), (&buf[9]), (&buf[10]), (&buf[11]), (&buf[12]), ++ (&buf[13])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_ROUTER_ADDRESS_CONF_CTRL: ++ { ++ // Determine if automated router discovery occurs when static ++ // addresses are used for the bmc ++ ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ std::string networkInterfacePath; ++ uint8_t dynamicRA; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ ++ try ++ { ++ ipmi::ObjectTree ancestorMap; ++ // if the system is having ip object,then ++ // get the IP object. ++ auto ipObject = ++ ipmi::getDbusObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ // Get the parent interface of the IP object. ++ try ++ { ++ ipmi::InterfaceList interfaces; ++ interfaces.emplace_back( ++ ipmi::network::ETHERNET_INTERFACE); ++ ++ ancestorMap = ipmi::getAllAncestors( ++ bus, ipObject.first, std::move(interfaces)); ++ } ++ catch (InternalFailure& e) ++ { ++ // if unable to get the parent interface ++ // then commit the error and return. ++ log<level::ERR>( ++ "Unable to get the parent interface", ++ entry("PATH=%s", ipObject.first.c_str()), ++ entry("INTERFACE=%s", ++ ipmi::network::ETHERNET_INTERFACE)); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ // for an ip object there would be single parent ++ // interface. ++ networkInterfacePath = ancestorMap.begin()->first; ++ } ++ catch (InternalFailure& e) ++ { ++ // if there is no ip configured on the system,then ++ // get the network interface object. ++ auto networkInterfaceObject = ipmi::getDbusObject( ++ bus, ipmi::network::ETHERNET_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ networkInterfacePath = networkInterfaceObject.first; ++ } ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfacePath, ++ ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA"); ++ dynamicRA = std::get<bool>(variant); ++ } ++ else ++ { ++ dynamicRA = channelConf->ipv6RouterAddressConfigControl; ++ } ++ ++ std::array<uint8_t, 2> buf = {current_revision, dynamicRA}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_IP_ADDR: ++ { ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision}; ++ inet_pton(AF_INET6, channelConf->ipv6GatewayAddr.c_str(), ++ reinterpret_cast<void*>(&buf[1])); ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_LEN: ++ { ++ std::array<uint8_t, 2> buf = {current_revision, ++ channelConf->ipv6GatewayPrefixLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_VAL: ++ { ++ constexpr uint8_t setSelector = 0; ++ std::array<uint8_t, sizeof(setSelector) + ++ ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision, setSelector}; ++ ++ inet_pton(AF_INET6, channelConf->ipv6GatewayPrefixValue.c_str(), ++ reinterpret_cast<void*>(&buf[2])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_IP_ADDR: ++ { ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision}; ++ inet_pton(AF_INET6, channelConf->ipv6BackupGatewayAddr.c_str(), ++ reinterpret_cast<void*>(&buf[1])); ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_LEN: ++ { ++ std::array<uint8_t, 2> buf = { ++ current_revision, channelConf->ipv6BackupGatewayPrefixLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_VAL: ++ { ++ ++ constexpr uint8_t setSelector = 0; ++ std::array<uint8_t, sizeof(setSelector) + ++ ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision, setSelector}; ++ inet_pton(AF_INET6, ++ channelConf->ipv6BackupGatewayPrefixValue.c_str(), ++ reinterpret_cast<void*>(&buf[2])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } + default: + log<level::ERR>("Unsupported parameter", + entry("PARAMETER=0x%x", reqptr->parameter)); +@@ -957,6 +1580,16 @@ void applyChanges(int channel) + ipaddress, prefix); + } + ++ if (!channelConf->ipv6Addr.empty() && ++ channelConf->ipv6AddressSource == ++ 0x80) // Check if IPv6 static addresses are enabled ++ { ++ ipmi::network::createIP(bus, ipmi::network::SERVICE, ++ networkInterfacePath, ipv6Protocol, ++ channelConf->ipv6Addr, ++ channelConf->ipv6Prefix); ++ } ++ + if (!gateway.empty()) + { + ipmi::setDbusProperty(bus, systemObject.second, +@@ -964,7 +1597,24 @@ void applyChanges(int channel) + ipmi::network::SYSTEMCONFIG_INTERFACE, + "DefaultGateway", std::string(gateway)); + } ++ else if (!channelConf->ipv6GatewayAddr.empty()) ++ { ++ ipmi::setDbusProperty( ++ bus, systemObject.second, systemObject.first, ++ ipmi::network::SYSTEMCONFIG_INTERFACE, "DefaultGateway", ++ std::string(channelConf->ipv6GatewayAddr)); ++ } + } ++ // set IPAddress Enables ++ ipmi::setDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfaceObject.first, ++ ipmi::network::ETHERNET_INTERFACE, "IPAddressEnables", ++ ipAddressEnablesType[channelConf->ipv6AddressingEnables]); ++ ++ ipmi::setDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfaceObject.first, ++ ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA", ++ (bool)channelConf->ipv6RouterAddressConfigControl); + } + catch (sdbusplus::exception::exception& e) + { +Index: phosphor-host-ipmid.clean/transporthandler.hpp +=================================================================== +--- phosphor-host-ipmid.clean.orig/transporthandler.hpp ++++ phosphor-host-ipmid.clean/transporthandler.hpp +@@ -79,8 +79,27 @@ enum class LanParam : uint8_t + IPV6_NEIGHBOR_TIMING_CONFIGURATION = 80, + }; + ++constexpr uint8_t DUID_LEN = 10; ++constexpr uint8_t DUID_LL_TYPE = 3; ++constexpr uint8_t DUIC_ETH_HW_TYPE = 1; ++ + // Data length of parameters + constexpr size_t lanParamVLANSize = 4; ++constexpr size_t lanParamInProgressSize = 3; ++constexpr size_t lanParamIPSize = 6; ++constexpr size_t lanParamIPSrcSize = 3; ++constexpr size_t lanParamMACSize = 8; ++constexpr size_t lanParamSubnetSize = 6; ++constexpr size_t lanParamGatewaySize = 6; ++constexpr size_t lanParamIPv6AndIPv4EnablesSize = 3; ++constexpr size_t lanParamIPv6StaticAddressesSize = 23; ++constexpr size_t lanParamIPv6RouterAddressConfCtrlSize = 3; ++constexpr size_t lanParamIPv6StaticRouter1IPAddrSize = 18; ++constexpr size_t lanParamIPv6StaticRouter1PrefixLenSize = 3; ++constexpr size_t lanParamIPv6StaticRouter1PrefixValSize = 19; ++constexpr size_t lanParamIPv6StaticRouter2IPAddrSize = 18; ++constexpr size_t lanParamIPv6StaticRouter2PrefixLenSize = 3; ++constexpr size_t lanParamIPv6StaticRouter2PrefixValSize = 19; + constexpr uint8_t SET_COMPLETE = 0; + constexpr uint8_t SET_IN_PROGRESS = 1; + constexpr uint8_t SET_COMMIT_WRITE = 2; // Optional +@@ -103,6 +122,20 @@ struct ChannelConfig_t + uint8_t lan_set_in_progress = SET_COMPLETE; + bool flush = false; + ++ // IPV6 parameters ++ uint8_t ipv6AddressSource = 0x0; ++ uint8_t ipv6AddressingEnables = 0x2; ++ std::string ipv6Addr; ++ uint8_t ipv6Prefix = 32; ++ uint8_t ipv6AddressStatus = 0x0; ++ uint8_t ipv6RouterAddressConfigControl = 0x0; ++ std::string ipv6GatewayAddr; ++ std::string ipv6BackupGatewayAddr; ++ uint8_t ipv6GatewayPrefixLength; ++ std::string ipv6GatewayPrefixValue; ++ uint8_t ipv6BackupGatewayPrefixLength = 0x0; ++ std::string ipv6BackupGatewayPrefixValue; ++ + void clear() + { + ipaddr.clear(); +@@ -113,6 +146,20 @@ struct ChannelConfig_t + ipsrc = ipmi::network::IPOrigin::UNSPECIFIED; + lan_set_in_progress = SET_COMPLETE; + flush = false; ++ ++ // IPv6 ++ ipv6Addr.clear(); ++ ipv6GatewayAddr.clear(); ++ ipv6BackupGatewayAddr.clear(); ++ ipv6AddressingEnables = 0x2; ++ ipv6AddressSource = 0x0; ++ ipv6Prefix = 32; ++ ipv6AddressStatus = 0x0; ++ ipv6RouterAddressConfigControl = 0x0; ++ ipv6GatewayPrefixLength = 0x0; ++ ipv6GatewayPrefixValue.clear(); ++ ipv6BackupGatewayPrefixLength = 0x0; ++ ipv6BackupGatewayPrefixValue.clear(); + } + }; + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch new file mode 100644 index 000000000..efee7cc26 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch @@ -0,0 +1,36 @@ +commit 72e6573f36fd3b9ce018e71b07bc1be63275d1f8 +Author: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri Jun 21 12:27:20 2019 -0700 + + Fix 'Get System GUID' to use settings UUID + + The upstream Get System GUID command looks first for a BMC interface + and then assumes that the UUID interface is next to that. But that is + not the case on Intel systems where the system GUID is found in the + settings daemon. + + Change-Id: I924bd05e0a546f2b30288c1faf72157296ab6579 + Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> + +diff --git a/apphandler.cpp b/apphandler.cpp +index 280d0db..25af6bb 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -799,8 +799,6 @@ auto ipmiAppGetBtCapabilities() + + auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>> + { +- static constexpr auto bmcInterface = +- "xyz.openbmc_project.Inventory.Item.Bmc"; + static constexpr auto uuidInterface = "xyz.openbmc_project.Common.UUID"; + static constexpr auto uuidProperty = "UUID"; + +@@ -809,7 +807,7 @@ auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>> + { + // Get the Inventory object implementing BMC interface + auto busPtr = getSdBus(); +- auto objectInfo = ipmi::getDbusObject(*busPtr, bmcInterface); ++ auto objectInfo = ipmi::getDbusObject(*busPtr, uuidInterface); + + // Read UUID property value from bmcObject + // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch new file mode 100644 index 000000000..396d2e949 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch @@ -0,0 +1,22 @@ +From ad7276f3aedb6f5aed315db57406c98f2bf71a09 Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Tue, 24 Jul 2018 13:21:52 +0800 +Subject: [PATCH] [ipmi] add set bios id to whitelist + +Add "SetBIOSId" and "GetDeviceInfo" 2 OEM commands into whitelist + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + host-ipmid-whitelist.conf | 2 ++ + 1 file changed, 2 insertions(+) + +Index: phosphor-host-ipmid/host-ipmid-whitelist.conf +=================================================================== +--- phosphor-host-ipmid.orig/host-ipmid-whitelist.conf ++++ phosphor-host-ipmid/host-ipmid-whitelist.conf +@@ -47,3 +47,5 @@ + 0x2C:0x06 //<Group Extension>:<Get Asset Tag> + 0x2C:0x07 //<Group Extension>:<Get Sensor Info> + 0x2C:0x10 //<Group Extension>:<Get Temperature Readings> ++0x30:0x26 //<OEM>:<Set BIOS ID> ++0x30:0x27 //<OEM>:<Get Device Info> diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch new file mode 100644 index 000000000..fdaa91085 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch @@ -0,0 +1,25 @@ +From cf466ba2c66a95825ae0014d7c378ad63b050d2f Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Wed, 15 Aug 2018 14:50:04 +0800 +Subject: [PATCH] [ipmi] add oem command "get AIC FRU" to whitelist + +Intel BIOS requires this oem command to get addon card FRU info. +Add to whitelist to unblock. + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + host-ipmid-whitelist.conf | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index db54a49..49746a2 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -43,3 +43,4 @@ + 0x30:0x41 //<OEM>:<Set System GUID> + 0x30:0x26 //<OEM>:<Set BIOS ID> + 0x30:0x27 //<OEM>:<Get Device Info> ++0x30:0x31 //<OEM>:<Get AIC card FRU> +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch new file mode 100644 index 000000000..b800632cc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch @@ -0,0 +1,15 @@ +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 22a2a3c..5d71698 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -49,3 +49,10 @@ + 0x30:0x26 //<OEM>:<Set BIOS ID> + 0x30:0x27 //<OEM>:<Get Device Info> + 0x30:0x31 //<OEM>:<Get AIC card FRU> ++0x30:0x54 //<OEM>:<Set Power Restore Delay> ++0x30:0x55 //<OEM>:<Get Power Restore Delay> ++0x30:0x9A //<OEM>:<Get Processor Error Config> ++0x30:0x9B //<OEM>:<Set Processor Error Config> ++0x30:0xB0 //<OEM>:<Get LED Status> ++0x30:0xE9 //<OEM>:<Get BIOS Post Codes> ++ diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch new file mode 100644 index 000000000..903ae96a7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch @@ -0,0 +1,80 @@ +From ad93a6e17310d92ef07b8d367b23c93793562d0f Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@linux.intel.com> +Date: Wed, 23 Jan 2019 17:02:40 +0800 +Subject: [PATCH] Fix keep looping issue when entering OS + +Sometimes when entering OS, OS will keep continuously sending ipmi command +"READ EVENT MESSAGE BUFFER" to BMC. This issue is caused by incorrect KCS +status. If restart the host immediately while OS is still running, SMS_ATN +will be set, after that KCS come into an incorrect status, and then KCS +communction between BMC and OS crash. To make KCS go back to correct status +and fix the issue, clear SMS_ATN after every time power cycle happen. + +Unit Test: + After entered OS, force reset system, after enter OS again, OS can start +normally without keep sending READ EVENT MESSAGE BUFFER command. + After power on system, enter EFI SHELL, check cmdtool.efi can work +correctly through KCS channel. +--- + host-cmd-manager.cpp | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/host-cmd-manager.cpp b/host-cmd-manager.cpp +index f3aba7f..465eb81 100644 +--- a/host-cmd-manager.cpp ++++ b/host-cmd-manager.cpp +@@ -26,6 +26,8 @@ constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; + constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0"; + constexpr auto HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host"; + constexpr auto HOST_TRANS_PROP = "RequestedHostTransition"; ++constexpr const char* IPMI_PATH = "/xyz/openbmc_project/Ipmi/Channel/ipmi_kcs3"; ++constexpr const char* IPMI_INTERFACE = "xyz.openbmc_project.Ipmi.Channel.SMS"; + + // For throwing exceptions + using namespace phosphor::logging; +@@ -106,6 +108,20 @@ void Manager::clearQueue() + // `false` indicating Failure + std::get<CallBack>(command)(ipmiCmdData, false); + } ++ ++ auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH); ++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH, ++ IPMI_INTERFACE, "clearAttention"); ++ ++ try ++ { ++ auto reply = this->bus.call(method); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ log<level::ERR>("Error in clearing SMS attention"); ++ elog<InternalFailure>(); ++ } + } + + // Called for alerting the host +@@ -115,9 +131,6 @@ void Manager::checkQueueAndAlertHost() + { + log<level::DEBUG>("Asserting SMS Attention"); + +- std::string IPMI_PATH("/org/openbmc/HostIpmi/1"); +- std::string IPMI_INTERFACE("org.openbmc.HostIpmi"); +- + auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH); + + // Start the timer for this transaction +@@ -131,9 +144,8 @@ void Manager::checkQueueAndAlertHost() + return; + } + +- auto method = +- this->bus.new_method_call(host.c_str(), IPMI_PATH.c_str(), +- IPMI_INTERFACE.c_str(), "setAttention"); ++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH, ++ IPMI_INTERFACE, "setAttention"); + auto reply = this->bus.call(method); + + if (reply.is_method_error()) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch new file mode 100644 index 000000000..bf6f672cf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch @@ -0,0 +1,37 @@ +From 5d0c9d2217dbe369daffb8a92d7b5e7d7d34d566 Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Sat, 2 Mar 2019 20:08:32 +0530 +Subject: [PATCH] Fix: User commands require channel layer lib + +As channel layer is separated out from user layer lib, it +has to be manually included in libusercommands, as user +command handlers use channel layer API's + +Tested-by: +1. Made sure that libusercommands are loaded on it's own +without any undefined symbol error. +2. ipmitool user list 1 works on host interface + +Change-Id: I6652ad248e01afc1349e3a9612754dbdb84b96ad +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + Makefile.am | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index bb7bdbf..4e9101e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -120,7 +120,8 @@ libipmi20_la_CXXFLAGS = $(COMMON_CXX) + providers_LTLIBRARIES += libusercmds.la + libusercmds_la_LIBADD = \ + libipmid/libipmid.la \ +- user_channel/libuserlayer.la ++ user_channel/libuserlayer.la \ ++ user_channel/libchannellayer.la + libusercmds_la_SOURCES = \ + user_channel/usercommands.cpp + libusercmds_la_LDFLAGS = \ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch new file mode 100644 index 000000000..3a77887a0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch @@ -0,0 +1,102 @@ +From 949db3a985719335d3df77db368eb2b296756749 Mon Sep 17 00:00:00 2001 +From: "Jia, chunhui" <chunhui.jia@linux.intel.com> +Date: Tue, 19 Mar 2019 16:09:06 +0800 +Subject: [PATCH] add SetInProgress to get/set boot option cmd + +It is required by BIOS. BIOS will check setinprogress first. +If this flag is not supported, BIOS will bypass all boot +option flow. + +Change-Id: Ibb0501ea5bc36c4f1f72339efef03724dd4e613f +Signed-off-by: Jia, chunhui <chunhui.jia@linux.intel.com> +--- + chassishandler.cpp | 26 +++++++++++++++++++++++++- + chassishandler.hpp | 3 +++ + 2 files changed, 28 insertions(+), 1 deletion(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 6d14d1b..553afa8 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -1351,6 +1351,10 @@ static ipmi_ret_t setBootMode(const Mode::Modes& mode) + return IPMI_CC_OK; + } + ++static constexpr uint8_t setComplete = 0x0; ++static constexpr uint8_t setInProgress = 0x1; ++static uint8_t transferStatus = setComplete; ++ + 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, +@@ -1365,11 +1369,21 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + get_sys_boot_options_t* reqptr = (get_sys_boot_options_t*)request; + IpmiValue bootOption = ipmiDefault; + ++ if (reqptr->parameter == ++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS)) ++ { ++ *data_len = ++ static_cast<uint8_t>(BootOptionResponseSize::SET_IN_PROGRESS); ++ resp->version = SET_PARM_VERSION; ++ resp->parm = static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS); ++ resp->data[0] = transferStatus; ++ return IPMI_CC_OK; ++ } ++ + std::memset(resp, 0, sizeof(*resp)); + resp->version = SET_PARM_VERSION; + resp->parm = 5; + resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME; +- + /* + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. +@@ -1505,6 +1519,16 @@ 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; + ++ if (reqptr->parameter == ++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS)) ++ { ++ if (transferStatus == setInProgress) { ++ return IPMI_CC_FAIL_SET_IN_PROGRESS; ++ } ++ transferStatus = reqptr->data[0]; ++ return IPMI_CC_OK; ++ } ++ + /* 000101 + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. +diff --git a/chassishandler.hpp b/chassishandler.hpp +index 2c42b11..6a24507 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -28,6 +28,7 @@ enum ipmi_chassis_return_codes + { + IPMI_OK = 0x0, + IPMI_CC_PARM_NOT_SUPPORTED = 0x80, ++ IPMI_CC_FAIL_SET_IN_PROGRESS = 0x81, + }; + + // Generic completion codes, +@@ -49,6 +50,7 @@ enum ipmi_chassis_control_cmds : uint8_t + }; + enum class BootOptionParameter : size_t + { ++ SET_IN_PROGRESS = 0x0, + BOOT_INFO = 0x4, + BOOT_FLAGS = 0x5, + OPAL_NETWORK_SETTINGS = 0x61 +@@ -56,6 +58,7 @@ enum class BootOptionParameter : size_t + + enum class BootOptionResponseSize : size_t + { ++ SET_IN_PROGRESS = 3, + BOOT_FLAGS = 5, + OPAL_NETWORK_SETTINGS = 50 + }; +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch new file mode 100644 index 000000000..f091b31fa --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch @@ -0,0 +1,31 @@ +From 3c69c94eed1a0c6eecfd53e739fade6596c6f3e5 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Thu, 12 Sep 2019 17:37:05 +0800 +Subject: [PATCH] Add timer use/actions support + +Based on IPMI spec, add timer use/actions support, +and add input data checking + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + app/watchdog.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/app/watchdog.cpp b/app/watchdog.cpp +index c4e594d..18e7e3a 100644 +--- a/app/watchdog.cpp ++++ b/app/watchdog.cpp +@@ -251,8 +251,8 @@ ipmi::RspType<> ipmiSetWatchdogTimer( + return ipmi::responseInvalidFieldRequest(); + } + +- timerLogFlags = static_cast<uint8_t>(dontLog); +- timerActions &= static_cast<uint8_t>(timeoutAction) | ++ timerLogFlags = (static_cast<uint8_t>(dontLog)) << 7; ++ timerActions = static_cast<uint8_t>(timeoutAction) | + static_cast<uint8_t>(preTimeoutInterrupt) << 4; + + try +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch new file mode 100644 index 000000000..2dad2fc16 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch @@ -0,0 +1,383 @@ +From 27b94aa1df83abad63cbba69525273194b14ab9c Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Wed, 16 Oct 2019 14:24:20 +0800 +Subject: [PATCH] Move Set SOL config parameter to host-ipmid + +Move Set SOL config parameter command from net-ipmid to host-ipmid, +so that BIOS in Intel platform can enable or disable SOL through KCS. +Get SOL config parameter command will be moved later. + +Tested by: +With the related change in phospher-ipmi-net and phospher-dbus-interface, +Run commands: +ipmitool raw 0x0c 0x21 0x0e 0x00 0x01 +ipmitool raw 0x0c 0x21 0x0e 0x01 0x00 +ipmitool raw 0x0c 0x21 0x0e 0x02 0x03 +ipmitool raw 0x0c 0x21 0x0e 0x03 0x5 0x03 +ipmitool raw 0x0c 0x21 0x0e 0x04 0x5 0x03 +All these commands have correct response and all dbus interface for +sol command change to same value in above commands. +After reboot BMC, "Progress" property in dbus interface change back +to 0 and other properties will not reset to default value. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + host-ipmid-whitelist.conf | 1 + + transporthandler.cpp | 322 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 323 insertions(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index e8df7c7..f030ef4 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -41,6 +41,7 @@ + 0x0A:0x48 //<Storage>:<Get SEL Time> + 0x0A:0x49 //<Storage>:<Set SEL Time> + 0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters> ++0x0C:0x21 //<Transport>:<Set SOL Configuration Parameters> + 0x2C:0x00 //<Group Extension>:<Group Extension Command> + 0x2C:0x01 //<Group Extension>:<Get DCMI Capabilities> + 0x2C:0x02 //<Group Extension>:<Get Power Reading> +diff --git a/transporthandler.cpp b/transporthandler.cpp +index e88eb63..4a42e7b 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -1168,8 +1168,323 @@ RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly, + } // namespace transport + } // namespace ipmi + ++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL"; ++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/"; ++ + void register_netfn_transport_functions() __attribute__((constructor)); + ++static std::string ++ getSOLService(std::shared_ptr<sdbusplus::asio::connection> dbus, ++ const std::string& solPathWitheEthName) ++{ ++ static std::string solService{}; ++ if (solService.empty()) ++ { ++ try ++ { ++ solService = ++ ipmi::getService(*dbus, solInterface, solPathWitheEthName); ++ } ++ catch (const sdbusplus::exception::SdBusError& e) ++ { ++ solService.clear(); ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error: get SOL service failed"); ++ return solService; ++ } ++ } ++ return solService; ++} ++ ++static int setSOLParameter(const std::string& property, ++ const ipmi::Value& value, const uint8_t& channelNum) ++{ ++ auto dbus = getSdBus(); ++ ++ std::string ethdevice = ipmi::getChannelName(channelNum); ++ ++ std::string solPathWitheEthName = std::string(solPath) + ethdevice; ++ ++ std::string service = getSOLService(dbus, solPathWitheEthName); ++ if (service.empty()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get SOL service failed"); ++ return -1; ++ } ++ try ++ { ++ ipmi::setDbusProperty(*dbus, service, solPathWitheEthName, solInterface, ++ property, value); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error setting sol parameter"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int getSOLParameter(const std::string& property, ipmi::Value& value, ++ const uint8_t& channelNum) ++{ ++ auto dbus = getSdBus(); ++ ++ std::string ethdevice = ipmi::getChannelName(channelNum); ++ ++ std::string solPathWitheEthName = std::string(solPath) + ethdevice; ++ ++ std::string service = getSOLService(dbus, solPathWitheEthName); ++ if (service.empty()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get SOL service failed"); ++ return -1; ++ } ++ try ++ { ++ value = ipmi::getDbusProperty(*dbus, service, solPathWitheEthName, ++ solInterface, property); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error getting sol parameter"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++void initializeSOLInProgress() ++{ ++ ipmi::ChannelInfo chInfo; ++ for (int chNum = 0; chNum < ipmi::maxIpmiChannels; chNum++) ++ { ++ if (!ipmi::isValidChannel(static_cast<uint8_t>(chNum))) ++ { ++ continue; ++ } ++ ipmi_ret_t compCode = ++ ipmi::getChannelInfo(static_cast<uint8_t>(chNum), chInfo); ++ if (compCode != IPMI_CC_OK || ++ chInfo.mediumType != ++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032)) ++ { ++ continue; ++ } ++ if (setSOLParameter("Progress", static_cast<uint8_t>(0), chNum) < 0) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error initialize sol progress"); ++ } ++ } ++} ++ ++static const constexpr uint8_t encryptMask = 0x80; ++static const constexpr uint8_t encryptShift = 7; ++static const constexpr uint8_t authMask = 0x40; ++static const constexpr uint8_t authShift = 6; ++static const constexpr uint8_t privilegeMask = 0xf; ++ ++namespace ipmi ++{ ++constexpr Cc ccParmNotSupported = 0x80; ++constexpr Cc ccSetInProgressActive = 0x81; ++constexpr Cc ccSystemInfoParameterSetReadOnly = 0x82; ++ ++static inline auto responseParmNotSupported() ++{ ++ return response(ccParmNotSupported); ++} ++static inline auto responseSetInProgressActive() ++{ ++ return response(ccSetInProgressActive); ++} ++static inline auto responseSystemInfoParameterSetReadOnly() ++{ ++ return response(ccSystemInfoParameterSetReadOnly); ++} ++ ++} // namespace ipmi ++ ++namespace sol ++{ ++enum class Parameter ++{ ++ progress, //!< Set In Progress. ++ enable, //!< SOL Enable. ++ authentication, //!< SOL Authentication. ++ accumulate, //!< Character Accumulate Interval & Send Threshold. ++ retry, //!< SOL Retry. ++ nvbitrate, //!< SOL non-volatile bit rate. ++ vbitrate, //!< SOL volatile bit rate. ++ channel, //!< SOL payload channel. ++ port, //!< SOL payload port. ++}; ++ ++enum class Privilege : uint8_t ++{ ++ highestPriv, ++ callbackPriv, ++ userPriv, ++ operatorPriv, ++ adminPriv, ++ oemPriv, ++}; ++ ++} // namespace sol ++ ++constexpr uint8_t progressMask = 0x03; ++constexpr uint8_t enableMask = 0x01; ++constexpr uint8_t retryMask = 0x07; ++ ++ipmi::RspType<> setSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, ++ uint4_t reserved, uint8_t paramSelector, ++ uint8_t configParamData1, ++ std::optional<uint8_t> configParamData2) ++{ ++ ipmi::ChannelInfo chInfo; ++ uint8_t channelNum = ipmi::convertCurrentChannelNum( ++ static_cast<uint8_t>(chNum), ctx->channel); ++ if (reserved != 0 || ++ (!ipmi::isValidChannel(static_cast<uint8_t>(channelNum)))) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ ipmi_ret_t compCode = ++ ipmi::getChannelInfo(static_cast<uint8_t>(channelNum), chInfo); ++ if (compCode != IPMI_CC_OK || ++ chInfo.mediumType != ++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032)) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ switch (static_cast<sol::Parameter>(paramSelector)) ++ { ++ case sol::Parameter::progress: ++ { ++ if (configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ uint8_t progress = configParamData1 & progressMask; ++ ipmi::Value currentProgress = 0; ++ if (getSOLParameter("Progress", currentProgress, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ if ((std::get<uint8_t>(currentProgress) == 1) && (progress == 1)) ++ { ++ return ipmi::responseSetInProgressActive(); ++ } ++ ++ if (setSOLParameter("Progress", progress, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ break; ++ } ++ case sol::Parameter::enable: ++ { ++ if (configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ bool enable = configParamData1 & enableMask; ++ if (setSOLParameter("Enable", enable, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ break; ++ } ++ case sol::Parameter::authentication: ++ { ++ if (configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ uint8_t encrypt = (configParamData1 & encryptMask) >> encryptShift; ++ uint8_t auth = (configParamData1 & authMask) >> authShift; ++ uint8_t privilege = configParamData1 & privilegeMask; ++ // For security considering encryption and authentication must be ++ // true. ++ if (!encrypt || !auth) ++ { ++ return ipmi::responseSystemInfoParameterSetReadOnly(); ++ } ++ else if (privilege < ++ static_cast<uint8_t>(sol::Privilege::userPriv) || ++ privilege > static_cast<uint8_t>(sol::Privilege::oemPriv)) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ if (setSOLParameter("Privilege", privilege, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ break; ++ } ++ case sol::Parameter::accumulate: ++ { ++ if (!configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ if (*configParamData2 == 0) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ if (setSOLParameter("AccumulateIntervalMS", configParamData1, ++ channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ if (setSOLParameter("Threshold", *configParamData2, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ break; ++ } ++ case sol::Parameter::retry: ++ { ++ if (!configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ if ((setSOLParameter( ++ "RetryCount", ++ static_cast<uint8_t>(configParamData1 & retryMask), ++ channelNum) < 0) || ++ (setSOLParameter("RetryIntervalMS", *configParamData2, ++ channelNum) < 0)) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ break; ++ } ++ case sol::Parameter::port: ++ { ++ return ipmi::responseSystemInfoParameterSetReadOnly(); ++ } ++ case sol::Parameter::nvbitrate: ++ case sol::Parameter::vbitrate: ++ case sol::Parameter::channel: ++ default: ++ return ipmi::responseParmNotSupported(); ++ } ++ ++ return ipmi::responseSuccess(); ++} ++ + void register_netfn_transport_functions() + { + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, +@@ -1178,4 +1493,11 @@ void register_netfn_transport_functions() + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, + ipmi::transport::cmdGetLanConfigParameters, + ipmi::Privilege::Admin, ipmi::transport::getLan); ++ ++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, ++ ipmi::transport::cmdSetSolConfigParameters, ++ ipmi::Privilege::Admin, setSOLConfParams); ++ ++ // Initialize dbus property progress to 0 every time sol manager restart. ++ initializeSOLInProgress(); + } +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch new file mode 100644 index 000000000..01a3e49b8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch @@ -0,0 +1,260 @@ +From e8ad148601fc3b45fac9092fdd45c537433e662f Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Thu, 11 Jul 2019 00:32:58 +0800 +Subject: [PATCH] Move Get SOL config parameter to host-ipmid + +Move Get SOL config parameter command from net-ipmid to host-ipmid. + +Tested: +Run command ipmitool sol info 1 +Set in progress : set-complete +Enabled : true +Force Encryption : false +Force Authentication : false +Privilege Level : ADMINISTRATOR +Character Accumulate Level (ms) : 60 +Character Send Threshold : 96 +Retry Count : 6 +Retry Interval (ms) : 200 +Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting +Non-Volatile Bit Rate (kbps) : 115.2 +Payload Channel : 1 (0x01) +Payload Port : 623 + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + host-ipmid-whitelist.conf | 1 + + transporthandler.cpp | 191 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 192 insertions(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 44c2181..0fcac4e 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -41,6 +41,7 @@ + 0x0A:0x49 //<Storage>:<Set SEL Time> + 0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters> + 0x0C:0x21 //<Transport>:<Set SOL Configuration Parameters> ++0x0C:0x22 //<Transport>:<Get SOL Configuration Parameters> + 0x2C:0x00 //<Group Extension>:<Group Extension Command> + 0x2C:0x01 //<Group Extension>:<Get DCMI Capabilities> + 0x2C:0x02 //<Group Extension>:<Get Power Reading> +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 25062ae..9ba2868 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -1719,6 +1719,28 @@ static int getSOLParameter(const std::string& property, ipmi::Value& value, + return 0; + } + ++constexpr const char* consoleInterface = "xyz.openbmc_project.console"; ++constexpr const char* consolePath = "/xyz/openbmc_project/console"; ++static int getSOLBaudRate(ipmi::Value& value) ++{ ++ auto dbus = getSdBus(); ++ ++ try ++ { ++ value = ++ ipmi::getDbusProperty(*dbus, "xyz.openbmc_project.console", ++ consolePath, consoleInterface, "baudrate"); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error getting sol baud rate"); ++ return -1; ++ } ++ ++ return 0; ++} ++ + void initializeSOLInProgress() + { + ipmi::ChannelInfo chInfo; +@@ -1913,6 +1935,171 @@ ipmi::RspType<> setSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, + return ipmi::responseSuccess(); + } + ++static const constexpr uint8_t retryCountMask = 0x07; ++static constexpr uint16_t ipmiStdPort = 623; ++static constexpr uint8_t solParameterRevision = 0x11; ++ipmi::RspType<uint8_t, std::optional<uint8_t>, std::optional<uint8_t>> ++ getSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, uint3_t reserved, ++ bool getParamRev, uint8_t paramSelector, ++ uint8_t setSelector, uint8_t blockSelector) ++{ ++ ipmi::ChannelInfo chInfo; ++ uint8_t channelNum = ipmi::convertCurrentChannelNum( ++ static_cast<uint8_t>(chNum), ctx->channel); ++ if (reserved != 0 || ++ (!ipmi::isValidChannel(static_cast<uint8_t>(channelNum))) || ++ (ipmi::EChannelSessSupported::none == ++ ipmi::getChannelSessionSupport(static_cast<uint8_t>(channelNum)))) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ipmi_ret_t compCode = ++ ipmi::getChannelInfo(static_cast<uint8_t>(channelNum), chInfo); ++ if (compCode != IPMI_CC_OK || ++ chInfo.mediumType != ++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032)) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ if (getParamRev) ++ { ++ return ipmi::responseSuccess(solParameterRevision, std::nullopt, ++ std::nullopt); ++ } ++ ++ ipmi::Value value; ++ switch (static_cast<sol::Parameter>(paramSelector)) ++ { ++ case sol::Parameter::progress: ++ { ++ if (getSOLParameter("Progress", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess( ++ solParameterRevision, std::get<uint8_t>(value), std::nullopt); ++ } ++ case sol::Parameter::enable: ++ { ++ if (getSOLParameter("Enable", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess( ++ solParameterRevision, ++ static_cast<uint8_t>(std::get<bool>(value)), std::nullopt); ++ } ++ case sol::Parameter::authentication: ++ { ++ uint8_t authentication = 0; ++ if (getSOLParameter("Privilege", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ authentication = (std::get<uint8_t>(value) & 0x0f); ++ ++ if (getSOLParameter("ForceAuthentication", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ authentication |= ++ (static_cast<uint8_t>(std::get<bool>(value)) << 6); ++ ++ if (getSOLParameter("ForceEncryption", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ authentication |= ++ (static_cast<uint8_t>(std::get<bool>(value)) << 7); ++ return ipmi::responseSuccess(solParameterRevision, authentication, ++ std::nullopt); ++ } ++ case sol::Parameter::accumulate: ++ { ++ if (getSOLParameter("AccumulateIntervalMS", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ ipmi::Value value1; ++ if (getSOLParameter("Threshold", value1, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess(solParameterRevision, ++ std::get<uint8_t>(value), ++ std::get<uint8_t>(value1)); ++ } ++ case sol::Parameter::retry: ++ { ++ if (getSOLParameter("RetryCount", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ ipmi::Value value1; ++ if (getSOLParameter("RetryIntervalMS", value1, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess( ++ solParameterRevision, std::get<uint8_t>(value) & retryCountMask, ++ std::get<uint8_t>(value1)); ++ } ++ case sol::Parameter::channel: ++ { ++ return ipmi::responseSuccess(solParameterRevision, channelNum, ++ std::nullopt); ++ } ++ case sol::Parameter::port: ++ { ++ uint16_t port = htole16(ipmiStdPort); ++ auto buffer = reinterpret_cast<const uint8_t*>(&port); ++ return ipmi::responseSuccess(solParameterRevision, buffer[0], ++ buffer[1]); ++ } ++ case sol::Parameter::nvbitrate: ++ { ++ if (getSOLBaudRate(value) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ uint8_t bitRate = 0; ++ uint32_t* pBaudRate = std::get_if<uint32_t>(&value); ++ if (!pBaudRate) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Failed to get valid baud rate from D-Bus interface"); ++ } ++ switch (*pBaudRate) ++ { ++ case 9600: ++ bitRate = 0x06; ++ break; ++ case 19200: ++ bitRate = 0x07; ++ break; ++ case 38400: ++ bitRate = 0x08; ++ break; ++ case 57600: ++ bitRate = 0x09; ++ break; ++ case 115200: ++ bitRate = 0x0a; ++ break; ++ default: ++ break; ++ } ++ return ipmi::responseSuccess(solParameterRevision, bitRate, ++ std::nullopt); ++ } ++ default: ++ return ipmi::responseParmNotSupported(); ++ } ++} ++ + void register_netfn_transport_functions() + { + // As this timer is only for transport handler +@@ -1934,6 +2121,10 @@ void register_netfn_transport_functions() + ipmi::transport::cmdSetSolConfigParameters, + ipmi::Privilege::Admin, setSOLConfParams); + ++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, ++ ipmi::transport::cmdGetSolConfigParameters, ++ ipmi::Privilege::User, getSOLConfParams); ++ + // Initialize dbus property progress to 0 every time sol manager restart. + initializeSOLInProgress(); + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch new file mode 100644 index 000000000..f29111758 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch @@ -0,0 +1,289 @@ +From 00fb92edcb4229eeb5b46c4eb206ba7d70e241fc Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Mon, 3 Jun 2019 17:01:47 -0700 +Subject: [PATCH] Update IPMI Chassis Control command + +This change updates the IPMI Chassis Control command to use the new +chassis state transitions. This allows each chassis control action +to more closely follow the behavior defined in the IPMI spec. + +Tested: +Ran each IPMI chassis control command to confirm the expected +behavior: +ipmitool power on: system is powered-on +ipmitool power off: system is forced off +ipmitool power cycle: system is forced off then powered-on +ipmitool power reset: system is hard reset +ipmitool power soft: soft power-off requested from system software + +Change-Id: Ic9fba3ca4abd9a758eb88f1e6ee09f7ca64ff80a +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + chassishandler.cpp | 206 ++++++++++++++--------------------------------------- + 1 file changed, 52 insertions(+), 154 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 88bf84b..ad564e2 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -31,6 +31,7 @@ + #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp> + #include <xyz/openbmc_project/Control/Boot/Source/server.hpp> + #include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp> ++#include <xyz/openbmc_project/State/Chassis/server.hpp> + #include <xyz/openbmc_project/State/Host/server.hpp> + #include <xyz/openbmc_project/State/PowerOnHours/server.hpp> + +@@ -712,59 +713,63 @@ ipmi_ret_t ipmi_set_chassis_cap(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + //------------------------------------------ + // Calls into Host State Manager Dbus object + //------------------------------------------ +-int initiate_state_transition(State::Host::Transition transition) ++int initiateHostStateTransition(State::Host::Transition transition) + { + // OpenBMC Host State Manager dbus framework +- constexpr auto HOST_STATE_MANAGER_ROOT = "/xyz/openbmc_project/state/host0"; +- constexpr auto HOST_STATE_MANAGER_IFACE = "xyz.openbmc_project.State.Host"; +- constexpr auto DBUS_PROPERTY_IFACE = "org.freedesktop.DBus.Properties"; +- constexpr auto PROPERTY = "RequestedHostTransition"; ++ constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0"; ++ constexpr auto hostStateIntf = "xyz.openbmc_project.State.Host"; + +- // sd_bus error +- int rc = 0; +- char* busname = NULL; ++ auto service = ipmi::getService(*getSdBus(), hostStateIntf, hostStatePath); + +- // SD Bus error report mechanism. +- sd_bus_error bus_error = SD_BUS_ERROR_NULL; ++ // Convert to string equivalent of the passed in transition enum. ++ auto request = State::convertForMessage(transition); + +- // Gets a hook onto either a SYSTEM or SESSION bus +- sd_bus* bus_type = ipmid_get_sd_bus_connection(); +- rc = mapper_get_service(bus_type, HOST_STATE_MANAGER_ROOT, &busname); +- if (rc < 0) ++ try ++ { ++ ipmi::setDbusProperty(*getSdBus(), service, hostStatePath, ++ hostStateIntf, "RequestedHostTransition", ++ request); ++ } ++ catch (std::exception& e) + { + log<level::ERR>( +- "Failed to get bus name", +- entry("ERRNO=0x%X, OBJPATH=%s", -rc, HOST_STATE_MANAGER_ROOT)); +- return rc; ++ "Failed to initiate transition", ++ entry("EXCEPTION=%s, REQUEST=%s", e.what(), request.c_str())); ++ return -1; + } ++ return 0; ++} ++ ++//------------------------------------------ ++// Calls into Chassis State Manager Dbus object ++//------------------------------------------ ++int initiateChassisStateTransition(State::Chassis::Transition transition) ++{ ++ // OpenBMC Chassis State Manager dbus framework ++ constexpr auto chassisStatePath = "/xyz/openbmc_project/state/chassis0"; ++ constexpr auto chassisStateIntf = "xyz.openbmc_project.State.Chassis"; ++ ++ auto service = ++ ipmi::getService(*getSdBus(), chassisStateIntf, chassisStatePath); + + // Convert to string equivalent of the passed in transition enum. + auto request = State::convertForMessage(transition); + +- rc = sd_bus_call_method(bus_type, // On the system bus +- busname, // Service to contact +- HOST_STATE_MANAGER_ROOT, // Object path +- DBUS_PROPERTY_IFACE, // Interface name +- "Set", // Method to be called +- &bus_error, // object to return error +- nullptr, // Response buffer if any +- "ssv", // Takes 3 arguments +- HOST_STATE_MANAGER_IFACE, PROPERTY, "s", +- request.c_str()); +- if (rc < 0) ++ try + { +- log<level::ERR>("Failed to initiate transition", +- entry("ERRNO=0x%X, REQUEST=%s", -rc, request.c_str())); ++ ipmi::setDbusProperty(*getSdBus(), service, chassisStatePath, ++ chassisStateIntf, "RequestedPowerTransition", ++ request); + } +- else ++ catch (std::exception& e) + { +- log<level::INFO>("Transition request initiated successfully"); ++ log<level::ERR>( ++ "Failed to initiate transition", ++ entry("EXCEPTION=%s, REQUEST=%s", e.what(), request.c_str())); ++ return -1; + } + +- sd_bus_error_free(&bus_error); +- free(busname); +- +- return rc; ++ return 0; + } + + namespace power_policy +@@ -1033,76 +1038,6 @@ ipmi::RspType<bool, // Power is on + diagButtonDisableAllow, sleepButtonDisableAllow); + } + +-//------------------------------------------------------------- +-// Send a command to SoftPowerOff application to stop any timer +-//------------------------------------------------------------- +-int stop_soft_off_timer() +-{ +- constexpr auto iface = "org.freedesktop.DBus.Properties"; +- constexpr auto soft_off_iface = "xyz.openbmc_project.Ipmi.Internal." +- "SoftPowerOff"; +- +- constexpr auto property = "ResponseReceived"; +- constexpr auto value = "xyz.openbmc_project.Ipmi.Internal." +- "SoftPowerOff.HostResponse.HostShutdown"; +- +- // Get the system bus where most system services are provided. +- auto bus = ipmid_get_sd_bus_connection(); +- +- // Get the service name +- // TODO openbmc/openbmc#1661 - Mapper refactor +- // +- // See openbmc/openbmc#1743 for some details but high level summary is that +- // for now the code will directly call the soft off interface due to a +- // race condition with mapper usage +- // +- // char *busname = nullptr; +- // auto r = mapper_get_service(bus, SOFTOFF_OBJPATH, &busname); +- // if (r < 0) +- //{ +- // fprintf(stderr, "Failed to get %s bus name: %s\n", +- // SOFTOFF_OBJPATH, -r); +- // return r; +- //} +- +- // No error object or reply expected. +- int rc = sd_bus_call_method(bus, SOFTOFF_BUSNAME, SOFTOFF_OBJPATH, iface, +- "Set", nullptr, nullptr, "ssv", soft_off_iface, +- property, "s", value); +- if (rc < 0) +- { +- log<level::ERR>("Failed to set property in SoftPowerOff object", +- entry("ERRNO=0x%X", -rc)); +- } +- +- // TODO openbmc/openbmc#1661 - Mapper refactor +- // free(busname); +- return rc; +-} +- +-//---------------------------------------------------------------------- +-// Create file to indicate there is no need for softoff notification to host +-//---------------------------------------------------------------------- +-void indicate_no_softoff_needed() +-{ +- fs::path path{HOST_INBAND_REQUEST_DIR}; +- if (!fs::is_directory(path)) +- { +- fs::create_directory(path); +- } +- +- // Add the host instance (default 0 for now) to the file name +- std::string file{HOST_INBAND_REQUEST_FILE}; +- auto size = std::snprintf(nullptr, 0, file.c_str(), 0); +- size++; // null +- std::unique_ptr<char[]> buf(new char[size]); +- std::snprintf(buf.get(), size, file.c_str(), 0); +- +- // Append file name to directory and create it +- path /= buf.get(); +- std::ofstream(path.c_str()); +-} +- + /** @brief Implementation of chassis control command + * + * @param - chassisControl command byte +@@ -1115,61 +1050,24 @@ ipmi::RspType<> ipmiChassisControl(uint8_t chassisControl) + switch (chassisControl) + { + case CMD_POWER_ON: +- rc = initiate_state_transition(State::Host::Transition::On); ++ rc = initiateHostStateTransition(State::Host::Transition::On); + break; + case CMD_POWER_OFF: +- // This path would be hit in 2 conditions. +- // 1: When user asks for power off using ipmi chassis command 0x04 +- // 2: Host asking for power off post shutting down. +- +- // If it's a host requested power off, then need to nudge Softoff +- // application that it needs to stop the watchdog timer if running. +- // If it is a user requested power off, then this is not really +- // needed. But then we need to differentiate between user and host +- // calling this same command +- +- // For now, we are going ahead with trying to nudge the soft off and +- // interpret the failure to do so as a non softoff case +- rc = stop_soft_off_timer(); +- +- // Only request the Off transition if the soft power off +- // application is not running +- if (rc < 0) +- { +- // First create a file to indicate to the soft off application +- // that it should not run. Not doing this will result in State +- // manager doing a default soft power off when asked for power +- // off. +- indicate_no_softoff_needed(); +- +- // Now request the shutdown +- rc = initiate_state_transition(State::Host::Transition::Off); +- } +- else +- { +- log<level::INFO>("Soft off is running, so let shutdown target " +- "stop the host"); +- } ++ rc = ++ initiateChassisStateTransition(State::Chassis::Transition::Off); + break; +- + case CMD_HARD_RESET: ++ rc = initiateChassisStateTransition( ++ State::Chassis::Transition::Reset); ++ break; + case CMD_POWER_CYCLE: +- // SPEC has a section that says certain implementations can trigger +- // PowerOn if power is Off when a command to power cycle is +- // requested +- +- // First create a file to indicate to the soft off application +- // that it should not run since this is a direct user initiated +- // power reboot request (i.e. a reboot request that is not +- // originating via a soft power off SMS request) +- indicate_no_softoff_needed(); +- +- rc = initiate_state_transition(State::Host::Transition::Reboot); ++ rc = initiateChassisStateTransition( ++ State::Chassis::Transition::PowerCycle); + break; +- + case CMD_SOFT_OFF_VIA_OVER_TEMP: +- // Request Host State Manager to do a soft power off +- rc = initiate_state_transition(State::Host::Transition::Off); ++ rc = initiateHostStateTransition(State::Host::Transition::Off); ++ break; ++ case CMD_PULSE_DIAGNOSTIC_INTR: + break; + + default: +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch new file mode 100644 index 000000000..aac0850ea --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch @@ -0,0 +1,140 @@ +From d9c89943d7b0aa00ee99b7c11278ac272a47a790 Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Tue, 28 May 2019 17:11:17 +0800 +Subject: [PATCH] Save the pre-timeout interrupt in dbus property + +Get the watchdog pre-timeout interrupt value from ipmi watchdog set command, +and store it into dbus property. + +Tested: +Config IPMI watchdog: BIOS FRB2 Power Cycle after 1 seconds: +ipmitool raw 0x06 0x24 0x01 0x13 0x0 0x2 0xa 0x00 +Start watchdog: +Ipmitool mc watchdog reset +Check the watchdog pre-timeout interrupt in below: +https://BMCIP/redfish/v1/Systems/system/LogServices/EventLog/Entries + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + app/watchdog.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ + app/watchdog_service.cpp | 6 ++++++ + app/watchdog_service.hpp | 9 +++++++++ + 3 files changed, 62 insertions(+) + +diff --git a/app/watchdog.cpp b/app/watchdog.cpp +index 2ffaae3..e9b7a9c 100644 +--- a/app/watchdog.cpp ++++ b/app/watchdog.cpp +@@ -81,6 +81,7 @@ ipmi::RspType<> ipmiAppResetWatchdogTimer() + + static constexpr uint8_t wd_dont_stop = 0x1 << 6; + static constexpr uint8_t wd_timeout_action_mask = 0x3; ++static constexpr uint8_t wdPreTimeoutInterruptMask = 0x3; + + static constexpr uint8_t wdTimerUseMask = 0x7; + static constexpr uint8_t wdTimerUseResTimer1 = 0x0; +@@ -130,6 +131,45 @@ WatchdogService::Action ipmiActionToWdAction(IpmiAction ipmi_action) + } + } + ++enum class IpmiPreTimeoutInterrupt : uint8_t ++{ ++ None = 0x0, ++ SMI = 0x1, ++ NMI = 0x2, ++ MI = 0x3, ++}; ++/** @brief Converts an IPMI Watchdog PreTimeoutInterrupt to DBUS defined action ++ * @param[in] ipmi_action The IPMI Watchdog PreTimeoutInterrupt ++ * @return The Watchdog PreTimeoutInterrupt that the ipmi_action maps to ++ */ ++WatchdogService::PreTimeoutInterruptAction ipmiPreTimeoutInterruptToWdAction( ++ IpmiPreTimeoutInterrupt ipmiPreTimeOutInterrupt) ++{ ++ switch (ipmiPreTimeOutInterrupt) ++ { ++ case IpmiPreTimeoutInterrupt::None: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::None; ++ } ++ case IpmiPreTimeoutInterrupt::SMI: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::SMI; ++ } ++ case IpmiPreTimeoutInterrupt::NMI: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::NMI; ++ } ++ case IpmiPreTimeoutInterrupt::MI: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::MI; ++ } ++ default: ++ { ++ throw std::domain_error("IPMI PreTimeoutInterrupt is invalid"); ++ } ++ } ++} ++ + enum class IpmiTimerUse : uint8_t + { + Reserved = 0x0, +@@ -257,6 +297,13 @@ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + // Mark as initialized so that future resets behave correctly + wd_service.setInitialized(true); + ++ // pretimeOutAction ++ const auto ipmiPreTimeoutInterrupt = ++ static_cast<IpmiPreTimeoutInterrupt>(wdPreTimeoutInterruptMask & ++ (static_cast<uint8_t>(preTimeoutInterrupt))); ++ wd_service.setPreTimeoutInterrupt( ++ ipmiPreTimeoutInterruptToWdAction(ipmiPreTimeoutInterrupt)); ++ + lastCallSuccessful = true; + return IPMI_CC_OK; + } +diff --git a/app/watchdog_service.cpp b/app/watchdog_service.cpp +index 77663b4..0c4ea28 100644 +--- a/app/watchdog_service.cpp ++++ b/app/watchdog_service.cpp +@@ -203,3 +203,9 @@ void WatchdogService::setTimeRemaining(uint64_t timeRemaining) + { + setProperty("TimeRemaining", timeRemaining); + } ++ ++void WatchdogService::setPreTimeoutInterrupt( ++ PreTimeoutInterruptAction preTimeoutInterrupt) ++{ ++ setProperty("PreTimeoutInterrupt", convertForMessage(preTimeoutInterrupt)); ++} +\ No newline at end of file +diff --git a/app/watchdog_service.hpp b/app/watchdog_service.hpp +index ed64a3c..b550f37 100644 +--- a/app/watchdog_service.hpp ++++ b/app/watchdog_service.hpp +@@ -15,6 +15,8 @@ class WatchdogService + + using Action = + sdbusplus::xyz::openbmc_project::State::server::Watchdog::Action; ++ using PreTimeoutInterruptAction = sdbusplus::xyz::openbmc_project::State:: ++ server::Watchdog::PreTimeoutInterruptAction; + using TimerUse = + sdbusplus::xyz::openbmc_project::State::server::Watchdog::TimerUse; + +@@ -99,6 +101,13 @@ class WatchdogService + */ + void setTimeRemaining(uint64_t timeRemaining); + ++ /** @brief Sets the value of the PreTimeoutInterrupt property on the host ++ * watchdog ++ * ++ * @param[in] PreTimeoutInterrupt - The new PreTimeoutInterrupt value ++ */ ++ void setPreTimeoutInterrupt(PreTimeoutInterruptAction preTimeoutInterrupt); ++ + private: + /** @brief sdbusplus handle */ + sdbusplus::bus::bus bus; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Enable-watchdog-to-save-useflag-after-host-power-off.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Enable-watchdog-to-save-useflag-after-host-power-off.patch new file mode 100644 index 000000000..4ee28bb5c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Enable-watchdog-to-save-useflag-after-host-power-off.patch @@ -0,0 +1,66 @@ +From e7b86ade7db1e9ae86ea39a957bead9090f4ccbf Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Thu, 12 Sep 2019 13:18:42 +0800 +Subject: [PATCH] Enable watchdog to save useflag after host power off + +Get the right useflag after host power off. + +Tested: +Set a watchdog (Timer action is none and Time Use is BIOS FRB2) +ipmitool raw 0x06 0x24 0x01 0x00 0x00 0x00 0x40 0x00 +Get watchdog +ipmitool mc watchdog get +Start watchdog +ipmitool mc watchdog reset +Get watchdog +ipmitool mc watchdog get +After timer is stop, set a watchdog again +(Timer action is none and Time Use is BIOS/POST) +ipmitool raw 0x06 0x24 0x02 0x00 0x00 0x00 0x40 0x00 +Start watchdog and wait until timer is stop, +Get watchdog +ipmitool mc watchdog get +Timer Expiration Flags should be 0x06(BIOS FRB2, BIOS/POST) +Power down the Host +Ipmitool chassis power off +Check the Timer Expiration Flags(User Flags) +ipmitool mc watchdog get +Timer Expiration Flags should be 0x06(BIOS FRB2, BIOS/POST) + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + app/watchdog.cpp | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/app/watchdog.cpp b/app/watchdog.cpp +index 4650d89..1562f5e 100644 +--- a/app/watchdog.cpp ++++ b/app/watchdog.cpp +@@ -435,23 +435,21 @@ ipmi::RspType<uint8_t, // timerUse + wdTimerUseToIpmiTimerUse(wd_prop.expiredTimerUse)); + } + ++ expireFlags = timerUseExpirationFlags; + if (wd_prop.enabled) + { + timerUse |= wd_running; + presentCountdown = htole16(wd_prop.timeRemaining / 100); +- expireFlags = 0; + } + else + { + if (wd_prop.expiredTimerUse == WatchdogService::TimerUse::Reserved) + { + presentCountdown = initialCountdown; +- expireFlags = 0; + } + else + { + presentCountdown = 0; +- expireFlags = timerUseExpirationFlags; + } + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Update-provisioning-mode-filter-logic.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Update-provisioning-mode-filter-logic.patch new file mode 100644 index 000000000..57a31c991 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Update-provisioning-mode-filter-logic.patch @@ -0,0 +1,286 @@ +From 3279300bb9afd1f169b35b7830d7f054045ab35f Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Tue, 18 Jun 2019 19:42:30 +0530 +Subject: [PATCH] Update provisioning mode filter logic + +Updated provisioning mode filtering logic support. Based on the +RestrictionMode property, Host (system) interface commands will be +filtered as per the allowed list in ProvisionedHostWhitelist once +POST complete is achieved. No commands will be allowed in +ProvisionedHostDisabled after POST complete and in all other cases +filterning logic will not be applied. + +Tested +1. Verified the filtering logic through EFI shell and made sure +filtering logic is applied when RestrictionMode is in +ProvisionedHostWhitelist mode +2. Verified no filtering logic is applied in normal modes +3. Made sure BIOS is able to execute commands, which are not in +whitelist (Note: New whitelist conf is under review). + +Change-Id: I7a14e827d70e2d8d6975e600a0fd00e2a790bc22 +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + whitelist-filter.cpp | 155 ++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 122 insertions(+), 33 deletions(-) + +diff --git a/whitelist-filter.cpp b/whitelist-filter.cpp +index 9f1e7c8..2c56087 100644 +--- a/whitelist-filter.cpp ++++ b/whitelist-filter.cpp +@@ -25,6 +25,7 @@ namespace + */ + class WhitelistFilter + { ++ + public: + WhitelistFilter(); + ~WhitelistFilter() = default; +@@ -35,17 +36,26 @@ class WhitelistFilter + + private: + void postInit(); +- void cacheRestrictedMode(); ++ void cacheRestrictedAndPostCompleteMode(); + void handleRestrictedModeChange(sdbusplus::message::message& m); ++ void handlePostCompleteChange(sdbusplus::message::message& m); + ipmi::Cc filterMessage(ipmi::message::Request::ptr request); + +- bool restrictedMode = true; ++ sdbusplus::xyz::openbmc_project::Control::Security::server:: ++ RestrictionMode::Modes restrictionMode = ++ sdbusplus::xyz::openbmc_project::Control::Security::server:: ++ RestrictionMode::Modes::ProvisionedHostWhitelist; ++ bool postCompleted = false; + std::shared_ptr<sdbusplus::asio::connection> bus; + std::unique_ptr<settings::Objects> objects; ++ std::unique_ptr<settings::Objects> postCompleteObj; + std::unique_ptr<sdbusplus::bus::match::match> modeChangeMatch; ++ std::unique_ptr<sdbusplus::bus::match::match> postCompleteMatch; + + static constexpr const char restrictionModeIntf[] = + "xyz.openbmc_project.Control.Security.RestrictionMode"; ++ static constexpr const char* systemOsStatusIntf = ++ "xyz.openbmc_project.State.OperatingSystem.Status"; + }; + + WhitelistFilter::WhitelistFilter() +@@ -63,16 +73,22 @@ WhitelistFilter::WhitelistFilter() + post_work([this]() { postInit(); }); + } + +-void WhitelistFilter::cacheRestrictedMode() ++void WhitelistFilter::cacheRestrictedAndPostCompleteMode() + { + using namespace sdbusplus::xyz::openbmc_project::Control::Security::server; + std::string restrictionModeSetting; + std::string restrictionModeService; ++ std::string systemOsStatusPath; ++ std::string systemOsStatusService; + try + { + restrictionModeSetting = objects->map.at(restrictionModeIntf).at(0); + restrictionModeService = + objects->service(restrictionModeSetting, restrictionModeIntf); ++ ++ systemOsStatusPath = postCompleteObj->map.at(systemOsStatusIntf).at(0); ++ systemOsStatusService = ++ postCompleteObj->service(systemOsStatusPath, systemOsStatusIntf); + } + catch (const std::out_of_range& e) + { +@@ -80,26 +96,50 @@ void WhitelistFilter::cacheRestrictedMode() + "Could not look up restriction mode interface from cache"); + return; + } ++ + bus->async_method_call( + [this](boost::system::error_code ec, ipmi::Value v) { + if (ec) + { + log<level::ERR>("Error in RestrictionMode Get"); + // Fail-safe to true. +- restrictedMode = true; ++ restrictionMode = ++ RestrictionMode::Modes::ProvisionedHostWhitelist; + return; + } + auto mode = std::get<std::string>(v); +- auto restrictionMode = +- RestrictionMode::convertModesFromString(mode); +- restrictedMode = +- (restrictionMode == RestrictionMode::Modes::Whitelist); +- log<level::INFO>((restrictedMode ? "Set restrictedMode = true" +- : "Set restrictedMode = false")); ++ restrictionMode = RestrictionMode::convertModesFromString(mode); ++ log<level::INFO>( ++ "Read restriction mode", ++ entry("VALUE=%d", static_cast<int>(restrictionMode))); + }, + restrictionModeService, restrictionModeSetting, + "org.freedesktop.DBus.Properties", "Get", restrictionModeIntf, + "RestrictionMode"); ++ ++ bus->async_method_call( ++ [this](boost::system::error_code ec, const ipmi::Value& v) { ++ if (ec) ++ { ++ log<level::ERR>("Error in OperatingSystemState Get"); ++ postCompleted = true; ++ return; ++ } ++ auto value = std::get<std::string>(v); ++ if (value == "Standby") ++ { ++ postCompleted = true; ++ } ++ else ++ { ++ postCompleted = false; ++ } ++ log<level::INFO>("Read POST complete value", ++ entry("VALUE=%d", postCompleted)); ++ }, ++ systemOsStatusService, systemOsStatusPath, ++ "org.freedesktop.DBus.Properties", "Get", systemOsStatusIntf, ++ "OperatingSystemState"); + } + + void WhitelistFilter::handleRestrictedModeChange(sdbusplus::message::message& m) +@@ -112,23 +152,44 @@ void WhitelistFilter::handleRestrictedModeChange(sdbusplus::message::message& m) + { + if (property.first == "RestrictionMode") + { +- RestrictionMode::Modes restrictionMode = +- RestrictionMode::convertModesFromString( +- std::get<std::string>(property.second)); +- restrictedMode = +- (restrictionMode == RestrictionMode::Modes::Whitelist); +- log<level::INFO>((restrictedMode +- ? "Updated restrictedMode = true" +- : "Updated restrictedMode = false")); ++ restrictionMode = RestrictionMode::convertModesFromString( ++ std::get<std::string>(property.second)); ++ log<level::INFO>( ++ "Updated restriction mode", ++ entry("VALUE=%d", static_cast<int>(restrictionMode))); ++ } ++ } ++} ++void WhitelistFilter::handlePostCompleteChange(sdbusplus::message::message& m) ++{ ++ std::string intf; ++ std::vector<std::pair<std::string, ipmi::Value>> propertyList; ++ m.read(intf, propertyList); ++ for (const auto& property : propertyList) ++ { ++ if (property.first == "OperatingSystemState") ++ { ++ std::string value = std::get<std::string>(property.second); ++ if (value == "Standby") ++ { ++ postCompleted = true; ++ } ++ else ++ { ++ postCompleted = false; ++ } ++ log<level::INFO>(postCompleted ? "Updated to POST Complete" ++ : "Updated to !POST Complete"); + } + } + } +- + void WhitelistFilter::postInit() + { + objects = std::make_unique<settings::Objects>( + *bus, std::vector<settings::Interface>({restrictionModeIntf})); +- if (!objects) ++ postCompleteObj = std::make_unique<settings::Objects>( ++ *bus, std::vector<settings::Interface>({systemOsStatusIntf})); ++ if (!objects || !postCompleteObj) + { + log<level::ERR>( + "Failed to create settings object; defaulting to restricted mode"); +@@ -136,37 +197,65 @@ void WhitelistFilter::postInit() + } + + // Initialize restricted mode +- cacheRestrictedMode(); ++ cacheRestrictedAndPostCompleteMode(); + // Wait for changes on Restricted mode +- std::string filterStr; ++ std::string filterStrModeChange; ++ std::string filterStrPostComplete; + try + { +- filterStr = sdbusplus::bus::match::rules::propertiesChanged( ++ filterStrModeChange = sdbusplus::bus::match::rules::propertiesChanged( + objects->map.at(restrictionModeIntf).at(0), restrictionModeIntf); ++ filterStrPostComplete = sdbusplus::bus::match::rules::propertiesChanged( ++ postCompleteObj->map.at(systemOsStatusIntf).at(0), ++ systemOsStatusIntf); + } + catch (const std::out_of_range& e) + { +- log<level::ERR>("Failed to determine restriction mode filter string"); ++ log<level::ERR>("Failed to determine restriction mode / POST complete " ++ "filter string"); + return; + } + modeChangeMatch = std::make_unique<sdbusplus::bus::match::match>( +- *bus, filterStr, [this](sdbusplus::message::message& m) { ++ *bus, filterStrModeChange, [this](sdbusplus::message::message& m) { + handleRestrictedModeChange(m); + }); ++ postCompleteMatch = std::make_unique<sdbusplus::bus::match::match>( ++ *bus, filterStrPostComplete, [this](sdbusplus::message::message& m) { ++ handlePostCompleteChange(m); ++ }); + } + + ipmi::Cc WhitelistFilter::filterMessage(ipmi::message::Request::ptr request) + { +- if (request->ctx->channel == ipmi::channelSystemIface && restrictedMode) ++ using namespace sdbusplus::xyz::openbmc_project::Control::Security::server; ++ ++ if (request->ctx->channel == ipmi::channelSystemIface && ++ (restrictionMode != RestrictionMode::Modes::None && ++ restrictionMode != RestrictionMode::Modes::Provisioning)) + { +- if (!std::binary_search( +- whitelist.cbegin(), whitelist.cend(), +- std::make_pair(request->ctx->netFn, request->ctx->cmd))) ++ if (!postCompleted) + { +- log<level::ERR>("Net function not whitelisted", +- entry("NETFN=0x%X", int(request->ctx->netFn)), +- entry("CMD=0x%X", int(request->ctx->cmd))); +- return ipmi::ccInsufficientPrivilege; ++ // Allow all commands, till POST is not completed ++ return ipmi::ccSuccess; ++ } ++ switch (restrictionMode) ++ { ++ case RestrictionMode::Modes::ProvisionedHostWhitelist: ++ { ++ if (!std::binary_search( ++ whitelist.cbegin(), whitelist.cend(), ++ std::make_pair(request->ctx->netFn, request->ctx->cmd))) ++ { ++ log<level::ERR>( ++ "Net function not whitelisted", ++ entry("NETFN=0x%X", int(request->ctx->netFn)), ++ entry("CMD=0x%X", int(request->ctx->cmd))); ++ return ipmi::ccInsufficientPrivilege; ++ } ++ break; ++ } ++ default: // for whitelist, blacklist & HostDisabled ++ return ipmi::ccInsufficientPrivilege; + } + } + return ipmi::ccSuccess; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/host-ipmid-whitelist.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/host-ipmid-whitelist.conf new file mode 100644 index 000000000..f3218d8d8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/host-ipmid-whitelist.conf @@ -0,0 +1,196 @@ +#<NetFn>:<Command> +#IPMI whitelist command list version 9b +0x00:0x00 //<Chassis>:<Get Chassis Capabiliti> +0x00:0x01 //<Chassis>:<Get Chassis Status> +0x00:0x04 //<Chassis>:<Chassis Identify> +0x00:0x07 //<Chassis>:<Get System Restart Cause> +0x00:0x09 //<Chassis>:<Get System Boot Options> +0x00:0x0A //<Chassis>:<Set Front Panel Enables> +0x00:0x0F //<Chassis>:<Get POH Counter> +0x04:0x01 //<Sensor/Event>:<Get Event Receiver> +0x04:0x02 //<Sensor/Event>:<SEL Platform event> +0x04:0x10 //<Sensor/Event>:<PEF Get Capabilities> +0x04:0x13 //<Sensor/Event>:<PEF Get Configuration Parameters> +0x04:0x15 //<Sensor/Event>:<PEF Get Processed EventID> +0x04:0x20 //<Sensor/Event>:<Get Device SDR Info> +0x04:0x21 //<Sensor/Event>:<Get Device SDR> +0x04:0x23 //<Sensor/Event>:<Get Sensor Reading Factors> +0x04:0x25 //<Sensor/Event>:<Get Sensor Hysteresis> +0x04:0x27 //<Sensor/Event>:<Get Sensor Threshold> +0x04:0x29 //<Sensor/Event>:<Get SensorEvent Enable> +0x04:0x2B //<Sensor/Event>:<Get SensorEvent Status> +0x04:0x2D //<Sensor/Event>:<Get SensorReading> +0x04:0x2F //<Sensor/Event>:<Get Sensor Type> +0x06:0x01 //<App>:<Get Device ID> +0x06:0x04 //<App>:<Get Self Test> +0x06:0x06 //<App>:<Set ACPI Power State> +0x06:0x07 //<App>:<Get ACPI Power State> +0x06:0x08 //<App>:<Get Device GUID> +0x06:0x22 //<App>:<Reset Watchdog Timer> +0x06:0x24 //<App>:<Set Watchdog Timer> +0x06:0x25 //<App>:<Get Watchdog Timer> +0x06:0x2F //<App>:<Get BMC Global Enables> +0x06:0x30 //<App>:<Clear Message Flags> +0x06:0x31 //<App>:<Get Message Flags> +0x06:0x33 //<App>:<Get Message> +0x06:0x35 //<App>:<Read Event Message Buffer> +0x06:0x37 //<App>:<Get System GUID> +0x06:0x38 //<App>:<Get Channel Authentication Capability> +0x06:0x39 //<App>:<Get Session Challenge> +0x06:0x3D //<App>:<Get Channel Session Info> +0x06:0x3F //<App>:<Get Authentication Code> +0x06:0x41 //<App>:<Get Channel Access> +0x06:0x42 //<App>:<Get Channel Info> +0x06:0x44 //<App>:<Get User Access> +0x06:0x46 //<App>:<Get User Name> +0x06:0x4A //<App>:<Get Payload Activation Status> +0x06:0x4B //<App>:<Get Payload Instance Info> +0x06:0x4D //<App>:<Get User Payload Access> +0x06:0x4E //<App>:<Get Channel Payload Support> +0x06:0x4F //<App>:<Get Channel Payload Version> +0x06:0x50 //<App>:<Get Channel OEM Payload Info> +0x06:0x54 //<App>:<Get Channel Cipher Suites> +0x06:0x57 //<App>:<Get System Interface Capabilities> +0x08:0x20 //<Firmware>:<Get Version Information> +0x08:0x21 //<Firmware>:<Security Version Information> +0x08:0x22 //<Firmware>:<Firmware Update Channel Information> +0x08:0x23 //<Firmware>:<BMC Execution Context> +0x08:0x24 //<Firmware>:<Get Boot Certificate Info> +0x08:0x25 //<Firmware>:<Get Boot Certificate Data> +0x08:0x26 //<Firmware>:<Firmware Random Number Update> +0x08:0x27 //<Firmware>:<Set Firmware Update Mode> +0x08:0x28 //<Firmware>:<Exit Firmware Update Mode> +0x08:0x29 //<Firmware>:<Firmware Update Control> +0x08:0x2A //<Firmware>:<Get Firmware Update Status> +0x08:0x2B //<Firmware>:<Set Firmware Update Options> +0x08:0x2C //<Firmware>:<Write Firmware Image> +0x08:0x2D //<Firmware>:<Get Firmware Update Status Code Message> +0x08:0xE0 //<Firmware>:<Get Firmware Update Error Code Message> +0x0A:0x10 //<Storage>:<Get FRU Inventory Area Info> +0x0A:0x11 //<Storage>:<Read FRU Data> +0x0A:0x20 //<Storage>:<Get SDR Repository Info> +0x0A:0x21 //<Storage>:<Get SDR Alloc Info> +0x0A:0x23 //<Storage>:<Get SDR> +0x0A:0x28 //<Storage>:<SEL Get Time> +0x0A:0x40 //<Storage>:<Get SEL Info> +0x0A:0x41 //<Storage>:<Get SEL Alloc Info> +0x0A:0x43 //<Storage>:<Get SEL Entry> +0x0A:0x48 //<Storage>:<Get SEL Time> +0x0A:0x5A //<Storage>:<Get SEL Auxiliary Log Status> +0x0A:0x5C //<Storage>:<Get SEL Time UTC Offset> +0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters> +0x0C:0x04 //<Transport>:<Get IPUDPRMCP Statistics> +0x0C:0x11 //<Transport>:<Get Serial Modem Configuration> +0x0C:0x22 //<Transport>:<Get SOL Configuration Parameters> +0x2C:0x1F //<Group Extension>:<Get CPU PECI Package Config Data> +0x2C:0x20 //<Group Extension>:<Get MDR Data Region Status> +0x2C:0x21 //<Group Extension>:<Get MDR Region Update Complete> +0x2C:0x22 //<Group Extension>:<Read MDR Region> +0x2C:0x23 //<Group Extension>:<Write MDR Region> +0x2C:0x24 //<Group Extension>:<Get MDR Region Lock> +0x2C:0x25 //<Group Extension>:<Get System Mode> +0x2C:0x29 //<Group Extension>:<Get TPM Configuration> +0x2C:0x37 //<Group Extension>:<Read PCIe Cable EEPROM Data> +0x30:0x04 //<Intel General Application>:<Get NW Switch MIB> +0x30:0x05 //<Intel General Application>:<Get PDB FW Version> +0x30:0x09 //<Intel General Application>:<Get BMC Config> +0x30:0x14 //<Intel General Application>:<Get SM Signal> +0x30:0x19 //<Intel General Application>:<Read LAN Channel Port Value> +0x30:0x1A //<Intel General Application>:<Get NIC Info> +0x30:0x1B //<Intel General Application>:<Get LAN Available> +0x30:0x1D //<Intel General Application>:<Get Master MAC> +0x30:0x1F //<Intel General Application>:<Get Secure Mode> +0x30:0x20 //<Intel General Application>:<OEM Get SEL info> +0x30:0x21 //<Intel General Application>:<OEM Get SEL Allocation Info> +0x30:0x22 //<Intel General Application>:<OEM Platform Event Message> +0x30:0x23 //<Intel General Application>:<OEM Get SEL Entry> +0x30:0x26 //<Intel General Application>:<Set BIOS ID> +0x30:0x27 //<Intel General Application>:<Get OEM Device Information> +0x30:0x2E //<Intel General Application>:<Get Cold Redundancy Configuration> +0x30:0x30 //<Intel General Application>:<Get Sensor Severity> +0x30:0x31 //<Intel General Application>:<Get AIC Slot FRU ID SLOT POS Records> +0x30:0x33 //<Intel General Application>:<Get Controller Status> +0x30:0x38 //<Intel General Application>:<Get Satellite Firmware update status> +0x30:0x39 //<Intel General Application>:<HSBP Get Owner> +0x30:0x3C //<Intel General Application>:<Get AIC MAC> +0x30:0x41 //<Intel General Application>:<Set System GUID> +0x30:0x43 //<Intel General Application>:<Get BMC Reset Disables> +0x30:0x44 //<Intel General Application>:<Send Embedded Firmware Update Status> +0x30:0x47 //<Intel General Application>:<HSBP Get Version> +0x30:0x55 //<Intel General Application>:<Get Power Restore Delay> +0x30:0x58 //<Intel General Application>:<Get DIMM Fault Status> +0x30:0x62 //<Intel General Application>:<Get Shutdown Policy> +0x30:0x63 //<Intel General Application>:<Get Node Slot Presence> +0x30:0x65 //<Intel General Application>:<Get HDD Drive Fault LED State> +0x30:0x66 //<Intel General Application>:<Get Buffer Size> +0x30:0x71 //<Intel General Application>:<Get Advanced Support> +0x30:0x73 //<Intel General Application>:<Get EFI Payload> +0x30:0x74 //<Intel General Application>:<Get RMM Status> +0x30:0x75 //<Intel General Application>:<Get Voltage Name> +0x30:0x80 //<Intel General Application>:<HSBP Get Register From Memory> +0x30:0x81 //<Intel General Application>:<Get Power State> +0x30:0x82 //<Intel General Application>:<Get ACPI Config> +0x30:0x85 //<Intel General Application>:<Get SF PWM> +0x30:0x8A //<Intel General Application>:<Get Fan Control Configuration> +0x30:0x8B //<Intel General Application>:<Auto Fan Detect> +0x30:0x8D //<Intel General Application>:<Get fan speed offset> +0x30:0x8F //<Intel General Application>:<Get DIMM offset> +0x30:0x91 //<Intel General Application>:<Get FSC Parameter> +0x30:0x92 //<Intel General Application>:<Get Chassis Identifier> +0x30:0x93 //<Intel General Application>:<Read Base Board Product ID> +0x30:0x94 //<Intel General Application>:<Get BMC Revision ID> +0x30:0x95 //<Intel General Application>:<Get Is AP CPU> +0x30:0x9A //<Intel General Application>:<Get Processor Error Configuration and Status> +0x30:0x9D //<Intel General Application>:<Get Fan PWM Limit> +0x30:0xB0 //<Intel General Application>:<Get LED Status> +0x30:0xB2 //<Intel General Application>:<Get BMC Service Status> +0x30:0xB3 //<Intel General Application>:<Get BMC Security Control Mode> +0x30:0xBB //<Intel General Application>:<Get CPLD Revision ID> +0x30:0xC2 //<Intel General Application>:<Get OEM Extended Sys Info> +0x30:0xC6 //<Intel General Application>:<Get Partition Config> +0x30:0xC7 //<Intel General Application>:<Get Zone Information> +0x30:0xC9 //<Intel General Application>:<Get Configuration Status> +0x30:0xCA //<Intel General Application>:<Get Fabric Information> +0x30:0xCB //<Intel General Application>:<Get EndPoints Information> +0x30:0xCC //<Intel General Application>:<Get Switches Information> +0x30:0xCD //<Intel General Application>:<Get Switch Collection Information> +0x30:0xD0 //<Intel General Application>:<Get NVMe Drive Data> +0x30:0xD1 //<Intel General Application>:<HSBP Statistics> +0x30:0xD4 //<Intel General Application>:<Get BIOS Capsule (OOB Update)> +0x30:0xE2 //<Intel General Application>:<OEM Get Reading> +0x30:0xE5 //<Intel General Application>:<Get NMI Source> +0x30:0xE8 //<Intel General Application>:<Get PCIe SMBus Slot Card Info> +0x30:0xE9 //<Intel General Application>:<Get BIOS POST CODE> +0x30:0xF9 //<Intel General Application>:<Get POST Progress Codes> +0x30:0xFD //<Intel General Application>:<Get Riser Presence> +0x32:0x60 //<Intel OEM Platform>:<Get PM Bus Information> +0x32:0x63 //<Intel OEM Platform>:<Get Tach Information> +0x32:0x8D //<Intel OEM Platform>:<Get SSD Power> +0x3E:0x02 //<Intel Managed Data Region>:<BMC Data Region Update Event Message> +0x3E:0x20 //<Intel Managed Data Region>:<BMC Region Status> +0x3E:0x21 //<Intel Managed Data Region>:<BMC Region Update Complete> +0x3E:0x22 //<Intel Managed Data Region>:<MDR Event> +0x3E:0x23 //<Intel Managed Data Region>:<BMC Region Read> +0x3E:0x24 //<Intel Managed Data Region>:<BMC Region Write> +0x3E:0x25 //<Intel Managed Data Region>:<BMC Region Lock> +0x3E:0x28 //<Intel Managed Data Region>:<Get DIMM information> +0x3E:0x30 //<Intel Managed Data Region>:<MDR2 Status> +0x3E:0x31 //<Intel Managed Data Region>:<MDR2 GET Direction> +0x3E:0x32 //<Intel Managed Data Region>:<MDR2 Get Data Set Info> +0x3E:0x33 //<Intel Managed Data Region>:<MDR2 Lock Data> +0x3E:0x34 //<Intel Managed Data Region>:<MDR2 Unlock Data> +0x3E:0x35 //<Intel Managed Data Region>:<MDR2 Dget Data Block> +0x3E:0x38 //<Intel Managed Data Region>:<MDR2 Send Direction> +0x3E:0x39 //<Intel Managed Data Region>:<MDR2 Data Info Offer> +0x3E:0x3A //<Intel Managed Data Region>:<MDR2 Data Info> +0x3E:0x3B //<Intel Managed Data Region>:<MDR2 Data Start> +0x3E:0x3C //<Intel Managed Data Region>:<MDR2 Data Done> +0x3E:0x3D //<Intel Managed Data Region>:<MDR2 Data Block> +0x3E:0x41 //<Intel Managed Data Region>:<Enter Platform Debug Log file transfer mode> +0x3E:0x42 //<Intel Managed Data Region>:<Read Platform Debug Log file> +0x3E:0x43 //<Intel Managed Data Region>:<Status of the Platform Debug Log file transfer mode> +0x3E:0x44 //<Intel Managed Data Region>:<Exit Platform Debug Log file transfer mode> +0x3E:0x50 //<Intel Managed Data Region>:<Node IPMB slave address> +0x3E:0x51 //<Intel Managed Data Region>:<Slot IPMB> +0x3E:0x52 //<Intel Managed Data Region>:<Slot I2C Master Write Read> +0x3E:0x75 //<Intel Managed Data Region>:<Get Remote Log IP> diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service new file mode 100644 index 000000000..b09bbf890 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service @@ -0,0 +1,28 @@ +[Unit] +Description=Phosphor Inband IPMI +# TODO openbmc/openbmc#2059 - The wants/after below should be based on providers +Wants=mapper-wait@-xyz-openbmc_project-control-host0-boot.service +After=mapper-wait@-xyz-openbmc_project-control-host0-boot.service +Wants=mapper-wait@-xyz-openbmc_project-control-host0-boot-one_time.service +After=mapper-wait@-xyz-openbmc_project-control-host0-boot-one_time.service +Wants=mapper-wait@-xyz-openbmc_project-control-host0-power_restore_policy.service +After=mapper-wait@-xyz-openbmc_project-control-host0-power_restore_policy.service +Wants=mapper-wait@-xyz-openbmc_project-control-security-restriction_mode.service +After=mapper-wait@-xyz-openbmc_project-control-security-restriction_mode.service +Wants=mapper-wait@-xyz-openbmc_project-state-os.service +After=mapper-wait@-xyz-openbmc_project-state-os.service +Wants=clear-once.service +After=clear-once.service + +[Service] +Restart=always +RestartSec=5 +StartLimitBurst=10 +ExecStart=/usr/bin/env ipmid +SyslogIdentifier=ipmid +RuntimeDirectory = ipmi +RuntimeDirectoryPreserve = yes +StateDirectory = ipmi + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend new file mode 100644 index 000000000..a50d5fd7f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend @@ -0,0 +1,45 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +#todo yong unpin this +SRC_URI = "git://github.com/openbmc/phosphor-host-ipmid;nobranch=1" +SRCREV = "c514d874e4ce3ed1f747cfcb4bab5990393c55e8" + +SRC_URI += "file://phosphor-ipmi-host.service \ + file://host-ipmid-whitelist.conf \ + file://0010-fix-get-system-GUID-ipmi-command.patch \ + file://0013-ipmi-add-set-bios-id-to-whitelist.patch \ + file://0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch \ + file://0050-enable-6-oem-commands.patch \ + file://0053-Fix-keep-looping-issue-when-entering-OS.patch \ + file://0056-add-SetInProgress-to-get-set-boot-option-cmd.patch \ + file://0057-Add-timer-use-actions-support.patch \ + file://0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch \ + file://0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch \ + file://0062-Update-IPMI-Chassis-Control-command.patch \ + file://0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch \ + file://0064-Enable-watchdog-to-save-useflag-after-host-power-off.patch \ + file://0064-Update-provisioning-mode-filter-logic.patch \ + " + +EXTRA_OECONF_append = " --disable-i2c-whitelist-check" + +RDEPENDS_${PN}_remove = "clear-once" + +# remove the softpoweroff service since we do not need it +SYSTEMD_SERVICE_${PN}_remove += " \ + xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service" + +SYSTEMD_LINK_${PN}_remove += " \ + ../xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service:obmc-host-shutdown@0.target.requires/xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service \ + " +FILES_${PN}_remove = " \ + ${systemd_unitdir}/system/obmc-host-shutdown@0.target.requires/ \ + ${systemd_unitdir}/system/obmc-host-shutdown@0.target.requires/xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service \ + " +do_configure_append(){ + cp -f ${WORKDIR}/host-ipmid-whitelist.conf ${S} +} + +do_install_append(){ + rm -f ${D}/${bindir}/phosphor-softpoweroff +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend new file mode 100644 index 000000000..f33be5760 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend @@ -0,0 +1,2 @@ +SRC_URI = "git://github.com/openbmc/ipmbbridge.git" +SRCREV = "bbfd00abdbc6d2f7c0389eae91cc055a1d4fe0c3" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules new file mode 100644 index 000000000..0a64b58db --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules @@ -0,0 +1,2 @@ +KERNEL=="ipmi-kcs3", SYMLINK+="ipmi_kcs3" +KERNEL=="ipmi-kcs4", SYMLINK+="ipmi_kcs4" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend new file mode 100644 index 000000000..140d1b302 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend @@ -0,0 +1,21 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +#SYSTEMD_SUBSTITUTIONS_remove = "KCS_DEVICE:${KCS_DEVICE}:${DBUS_SERVICE_${PN}}" + +# Default kcs device is ipmi-kcs3; this is SMS. +# Add SMM kcs device instance + +# Replace the '-' to '_', since Dbus object/interface names do not allow '-'. +KCS_DEVICE = "ipmi_kcs3" +SMM_DEVICE = "ipmi_kcs4" +SYSTEMD_SERVICE_${PN}_append = " ${PN}@${SMM_DEVICE}.service " + +SRC_URI = "git://github.com/openbmc/kcsbridge.git" +SRCREV = "2cdc49585235a6557c9cbb6c8b75c064fc02681a" + +SRC_URI += "file://99-ipmi-kcs.rules" + +do_install_append() { + install -d ${D}${base_libdir}/udev/rules.d + install -m 0644 ${WORKDIR}/99-ipmi-kcs.rules ${D}${base_libdir}/udev/rules.d/ +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch new file mode 100644 index 000000000..867b3aba6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch @@ -0,0 +1,40 @@ +From 0fd38eb0a155cb11ff5a5452087f68c46d12111b Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Thu, 28 Mar 2019 18:10:40 +0800 +Subject: [PATCH] Change Authentication Parameter + +Seprate D-bus interface Authentication to forceAuthentication, +forceEncryption, Privilege according to the related change in +sol-dbus-interface. + +Tested By: +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0x03 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0xc2 +The parameters has been changed to the request data in above command. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + sol/sol_manager.cpp | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp +index de36723..0bd837e 100644 +--- a/sol/sol_manager.cpp ++++ b/sol/sol_manager.cpp +@@ -195,8 +195,12 @@ void Manager::updateSOLParameter() + + enable = std::get<bool>(properties["Enable"]); + ++ forceEncrypt = std::get<bool>(properties["ForceEncryption"]); ++ ++ forceAuth = std::get<bool>(properties["ForceAuthentication"]); ++ + solMinPrivilege = static_cast<session::Privilege>( +- std::get<uint8_t>(properties["Authentication"])); ++ std::get<uint8_t>(properties["Privilege"])); + + accumulateInterval = + std::get<uint8_t>((properties["AccumulateIntervalMS"])) * +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch new file mode 100644 index 000000000..0ad625a1f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch @@ -0,0 +1,39 @@ +From 6fc55bb689272d34ff6616cdd4b24367ea39c749 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Mon, 2 Jul 2018 15:51:52 +0800 +Subject: [PATCH] Modify dbus namespace of chassis control for guid.cpp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Switch chassis control service namespace for guid.cpp from “org” to “xyz”, +to compatible with new intel-chassis services + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + command/guid.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +Index: phosphor-net-ipmid.clean/command/guid.cpp +=================================================================== +--- phosphor-net-ipmid.clean.orig/command/guid.cpp ++++ phosphor-net-ipmid.clean/command/guid.cpp +@@ -21,7 +21,8 @@ namespace command + + std::unique_ptr<sdbusplus::bus::match_t> matchPtr(nullptr); + +-static constexpr auto guidObjPath = "/org/openbmc/control/chassis0"; ++static constexpr auto guidObjPath = ++ "/xyz/openbmc_project/Chassis/Control/Chassis0"; + static constexpr auto propInterface = "org.freedesktop.DBus.Properties"; + + Guid getSystemGUID() +@@ -31,7 +32,7 @@ Guid getSystemGUID() + Guid guid = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}; + +- constexpr auto chassisIntf = "org.openbmc.control.Chassis"; ++ constexpr auto chassisIntf = "xyz.openbmc_project.Chassis.Control.Chassis"; + + sd_bus_message* reply = nullptr; + sd_bus_error error = SD_BUS_ERROR_NULL; diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch new file mode 100644 index 000000000..dc7f7357c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch @@ -0,0 +1,319 @@ +From 97c21a556702a0d65096b30c07ef23f15cb6a7d9 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Wed, 3 Jul 2019 07:39:47 +0800 +Subject: [PATCH] Add dbus interface for sol commands + +Add dbus interface for sol config parameters so that after move set/get +sol config parameter command from net-ipmid to host-ipmid, the command +can send config parameters to net-ipmid sol service through the dbus +interface. + +Tested by: +busctl introspect xyz.openbmc_project.Settings /xyz/openbmc_project +/network/host0/sol can show correct dbus properties of sol parameters. +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x00 0x01 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x01 0x00 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0x83 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x03 0x5 0x03 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x04 0x5 0x03 +all these commands can change the dbus properties as the value in +above commands. +Before and after run these commands, ipmitool -I lanplus -H x -U x +-P x sol activate can start sol session correctly. +After reboot BMC, "Progress" property in dbus interface change back +to 0 and other properties will not reset to default value. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + command/payload_cmds.cpp | 3 ++ + command/sol_cmds.cpp | 84 ------------------------------- + sol/sol_manager.cpp | 125 +++++++++++++++++++++++++++++++++++++++++++++++ + sol/sol_manager.hpp | 1 + + sol_module.cpp | 6 --- + 5 files changed, 129 insertions(+), 90 deletions(-) + +diff --git a/command/payload_cmds.cpp b/command/payload_cmds.cpp +index c32a510..17167a7 100644 +--- a/command/payload_cmds.cpp ++++ b/command/payload_cmds.cpp +@@ -34,6 +34,9 @@ std::vector<uint8_t> activatePayload(const std::vector<uint8_t>& inPayload, + return outPayload; + } + ++ std::get<sol::Manager&>(singletonPool) ++ .updateSOLParameter(ipmi::convertCurrentChannelNum( ++ ipmi::currentChNum, getInterfaceIndex())); + if (!std::get<sol::Manager&>(singletonPool).enable) + { + response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; +diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp +index a8fa410..804b5ea 100644 +--- a/command/sol_cmds.cpp ++++ b/command/sol_cmds.cpp +@@ -65,90 +65,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID) + outPayload); + } + +-std::vector<uint8_t> setConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler) +-{ +- std::vector<uint8_t> outPayload(sizeof(SetConfParamsResponse)); +- auto request = +- reinterpret_cast<const SetConfParamsRequest*>(inPayload.data()); +- auto response = reinterpret_cast<SetConfParamsResponse*>(outPayload.data()); +- response->completionCode = IPMI_CC_OK; +- +- switch (static_cast<Parameter>(request->paramSelector)) +- { +- case Parameter::PROGRESS: +- { +- uint8_t progress = request->value & progressMask; +- std::get<sol::Manager&>(singletonPool).progress = progress; +- break; +- } +- case Parameter::ENABLE: +- { +- bool enable = request->value & enableMask; +- std::get<sol::Manager&>(singletonPool).enable = enable; +- break; +- } +- case Parameter::AUTHENTICATION: +- { +- if (!request->auth.auth || !request->auth.encrypt) +- { +- response->completionCode = ipmiCCWriteReadParameter; +- } +- else if (request->auth.privilege < +- static_cast<uint8_t>(session::Privilege::USER) || +- request->auth.privilege > +- static_cast<uint8_t>(session::Privilege::OEM)) +- { +- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; +- } +- else +- { +- std::get<sol::Manager&>(singletonPool).solMinPrivilege = +- static_cast<session::Privilege>(request->auth.privilege); +- } +- break; +- } +- case Parameter::ACCUMULATE: +- { +- using namespace std::chrono_literals; +- +- if (request->acc.threshold == 0) +- { +- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; +- break; +- } +- +- std::get<sol::Manager&>(singletonPool).accumulateInterval = +- request->acc.interval * sol::accIntervalFactor * 1ms; +- std::get<sol::Manager&>(singletonPool).sendThreshold = +- request->acc.threshold; +- break; +- } +- case Parameter::RETRY: +- { +- using namespace std::chrono_literals; +- +- std::get<sol::Manager&>(singletonPool).retryCount = +- request->retry.count; +- std::get<sol::Manager&>(singletonPool).retryInterval = +- request->retry.interval * sol::retryIntervalFactor * 1ms; +- break; +- } +- case Parameter::PORT: +- { +- response->completionCode = ipmiCCWriteReadParameter; +- break; +- } +- case Parameter::NVBITRATE: +- case Parameter::VBITRATE: +- case Parameter::CHANNEL: +- default: +- response->completionCode = ipmiCCParamNotSupported; +- } +- +- return outPayload; +-} +- + std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload, + const message::Handler& handler) + { +diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp +index 2046fe4..eedd28a 100644 +--- a/sol/sol_manager.cpp ++++ b/sol/sol_manager.cpp +@@ -12,7 +12,13 @@ + #include <boost/asio/write.hpp> + #include <chrono> + #include <cmath> ++#include <ipmid/utils.hpp> + #include <phosphor-logging/log.hpp> ++#include <sdbusplus/message/types.hpp> ++ ++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL"; ++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/"; ++constexpr const char* PROP_INTF = "org.freedesktop.DBus.Properties"; + + namespace sol + { +@@ -93,6 +99,125 @@ void Manager::stopHostConsole() + } + } + ++std::string getService(sdbusplus::bus::bus& bus, const std::string& intf, ++ const std::string& path) ++{ ++ auto mapperCall = ++ bus.new_method_call("xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject"); ++ ++ mapperCall.append(path); ++ mapperCall.append(std::vector<std::string>({intf})); ++ ++ std::map<std::string, std::vector<std::string>> mapperResponse; ++ ++ try ++ { ++ auto mapperResponseMsg = bus.call(mapperCall); ++ mapperResponseMsg.read(mapperResponse); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ throw std::runtime_error("ERROR in mapper call"); ++ } ++ ++ if (mapperResponse.begin() == mapperResponse.end()) ++ { ++ throw std::runtime_error("ERROR in reading the mapper response"); ++ } ++ ++ return mapperResponse.begin()->first; ++} ++ ++ipmi::PropertyMap getAllDbusProperties(sdbusplus::bus::bus& bus, ++ const std::string& service, ++ const std::string& objPath, ++ const std::string& interface) ++{ ++ ipmi::PropertyMap properties; ++ ++ sdbusplus::message::message method = bus.new_method_call( ++ service.c_str(), objPath.c_str(), PROP_INTF, "GetAll"); ++ ++ method.append(interface); ++ ++ try ++ { ++ sdbusplus::message::message reply = bus.call(method); ++ reply.read(properties); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Failed to get all properties", ++ phosphor::logging::entry("PATH=%s", objPath.c_str()), ++ phosphor::logging::entry("INTERFACE=%s", interface.c_str())); ++ throw std::runtime_error("ERROR in reading proerties"); ++ } ++ ++ return properties; ++} ++ ++void Manager::updateSOLParameter(uint8_t channelNum) ++{ ++ std::variant<uint8_t, bool> value; ++ sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); ++ static std::string solService{}; ++ ipmi::PropertyMap properties; ++ std::string ethdevice = ipmi::getChannelName(channelNum); ++ std::string solPathWitheEthName = solPath + ethdevice; ++ if (solService.empty()) ++ { ++ try ++ { ++ solService = getService(dbus, solInterface, solPathWitheEthName); ++ } ++ catch (const std::runtime_error& e) ++ { ++ solService.clear(); ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error: get SOL service failed"); ++ return; ++ } ++ } ++ try ++ { ++ properties = getAllDbusProperties(dbus, solService, solPathWitheEthName, ++ solInterface); ++ } ++ catch (const std::runtime_error&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error setting sol parameter"); ++ return; ++ } ++ ++ progress = std::get<uint8_t>(properties["Progress"]); ++ ++ enable = std::get<bool>(properties["Enable"]); ++ ++ forceEncrypt = std::get<bool>(properties["ForceEncryption"]); ++ ++ forceAuth = std::get<bool>(properties["ForceAuthentication"]); ++ ++ solMinPrivilege = static_cast<session::Privilege>( ++ std::get<uint8_t>(properties["Privilege"])); ++ ++ accumulateInterval = ++ std::get<uint8_t>((properties["AccumulateIntervalMS"])) * ++ sol::accIntervalFactor * 1ms; ++ ++ sendThreshold = std::get<uint8_t>(properties["Threshold"]); ++ ++ retryCount = std::get<uint8_t>(properties["RetryCount"]); ++ ++ retryInterval = std::get<uint8_t>(properties["RetryIntervalMS"]) * ++ sol::retryIntervalFactor * 1ms; ++ ++ return; ++} ++ + void Manager::startPayloadInstance(uint8_t payloadInstance, + session::SessionID sessionID) + { +diff --git a/sol/sol_manager.hpp b/sol/sol_manager.hpp +index 5d96890..00da9fb 100644 +--- a/sol/sol_manager.hpp ++++ b/sol/sol_manager.hpp +@@ -248,6 +248,7 @@ class Manager + * @return 0 on success and errno on failure. + */ + int writeConsoleSocket(const std::vector<uint8_t>& input) const; ++ void updateSOLParameter(uint8_t channelNum); + + private: + SOLPayloadMap payloadMap; +diff --git a/sol_module.cpp b/sol_module.cpp +index 8200e74..2b1fb46 100644 +--- a/sol_module.cpp ++++ b/sol_module.cpp +@@ -42,12 +42,6 @@ void registerCommands() + &getPayloadInfo, + session::Privilege::USER, + false}, +- // Set SOL Configuration Parameters +- {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | +- static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x21}, +- &setConfParams, +- session::Privilege::ADMIN, +- false}, + // Get SOL Configuration Parameters + {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | + static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x22}, +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch new file mode 100644 index 000000000..da173704b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch @@ -0,0 +1,336 @@ +From a36f181163974b2da0a954fc97a89fb2cdbd7287 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Tue, 30 Apr 2019 05:35:31 +0800 +Subject: [PATCH] Remove Get SOL Config Command from Netipmid + +Since Get SOL Config Parameter command already exists in host-ipmid, and +can be shared to net channel, remove this command from net-ipmid. + +Tested: +Run ipmitool -I lanplus -H xxx -U root -P 0penBmc sol info, the command +returns the same result as ipmitool sol info as below. +Info: SOL parameter 'Nonvolatile Bitrate (5)' not supported +Info: SOL parameter 'Volatile Bitrate (6)' not supported +Info: SOL parameter 'Payload Channel (7)' not supported - defaulting to 0x0e +Set in progress : set-complete +Enabled : true +Force Encryption : true +Force Authentication : true +Privilege Level : USER +Character Accumulate Level (ms) : 100 +Character Send Threshold : 1 +Retry Count : 3 +Retry Interval (ms) : 100 +Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting +Non-Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting +Payload Channel : 14 (0x0e) +Payload Port : 623 + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + command/sol_cmds.cpp | 91 ---------------------------- + command/sol_cmds.hpp | 168 --------------------------------------------------- + sol_module.cpp | 6 -- + 3 files changed, 265 deletions(-) + +diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp +index 804b5ea..8b2d041 100644 +--- a/command/sol_cmds.cpp ++++ b/command/sol_cmds.cpp +@@ -65,97 +65,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID) + outPayload); + } + +-std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler) +-{ +- std::vector<uint8_t> outPayload(sizeof(GetConfParamsResponse)); +- auto request = +- reinterpret_cast<const GetConfParamsRequest*>(inPayload.data()); +- auto response = reinterpret_cast<GetConfParamsResponse*>(outPayload.data()); +- response->completionCode = IPMI_CC_OK; +- response->paramRev = parameterRevision; +- +- if (request->getParamRev) +- { +- return outPayload; +- } +- +- switch (static_cast<Parameter>(request->paramSelector)) +- { +- case Parameter::PROGRESS: +- { +- outPayload.push_back( +- std::get<sol::Manager&>(singletonPool).progress); +- break; +- } +- case Parameter::ENABLE: +- { +- outPayload.push_back(std::get<sol::Manager&>(singletonPool).enable); +- break; +- } +- case Parameter::AUTHENTICATION: +- { +- Auth value{0}; +- +- value.encrypt = std::get<sol::Manager&>(singletonPool).forceEncrypt; +- value.auth = std::get<sol::Manager&>(singletonPool).forceAuth; +- value.privilege = static_cast<uint8_t>( +- std::get<sol::Manager&>(singletonPool).solMinPrivilege); +- auto buffer = reinterpret_cast<const uint8_t*>(&value); +- +- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::ACCUMULATE: +- { +- Accumulate value{0}; +- +- value.interval = std::get<sol::Manager&>(singletonPool) +- .accumulateInterval.count() / +- sol::accIntervalFactor; +- value.threshold = +- std::get<sol::Manager&>(singletonPool).sendThreshold; +- auto buffer = reinterpret_cast<const uint8_t*>(&value); +- +- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::RETRY: +- { +- Retry value{0}; +- +- value.count = std::get<sol::Manager&>(singletonPool).retryCount; +- value.interval = +- std::get<sol::Manager&>(singletonPool).retryInterval.count() / +- sol::retryIntervalFactor; +- auto buffer = reinterpret_cast<const uint8_t*>(&value); +- +- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::PORT: +- { +- auto port = endian::to_ipmi<uint16_t>(IPMI_STD_PORT); +- auto buffer = reinterpret_cast<const uint8_t*>(&port); +- +- std::copy_n(buffer, sizeof(port), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::CHANNEL: +- { +- outPayload.push_back( +- std::get<sol::Manager&>(singletonPool).channel); +- break; +- } +- case Parameter::NVBITRATE: +- case Parameter::VBITRATE: +- default: +- response->completionCode = ipmiCCParamNotSupported; +- } +- +- return outPayload; +-} +- + } // namespace command + + } // namespace sol +diff --git a/command/sol_cmds.hpp b/command/sol_cmds.hpp +index 182b73e..10cbf25 100644 +--- a/command/sol_cmds.hpp ++++ b/command/sol_cmds.hpp +@@ -62,174 +62,6 @@ struct ActivatingRequest + */ + void activating(uint8_t payloadInstance, uint32_t sessionID); + +-/** @enum Parameter +- * +- * SOL parameters are volatile, they are initialized by the SOL manager. +- * They can be read using Get SOL configuration parameters command and updated +- * using Set SOL configuration parameters command. +- */ +-enum class Parameter +-{ +- PROGRESS, //!< Set In Progress. +- ENABLE, //!< SOL Enable. +- AUTHENTICATION, //!< SOL Authentication. +- ACCUMULATE, //!< Character Accumulate Interval & Send Threshold. +- RETRY, //!< SOL Retry. +- NVBITRATE, //!< SOL non-volatile bit rate. +- VBITRATE, //!< SOL volatile bit rate. +- CHANNEL, //!< SOL payload channel. +- PORT, //!< SOL payload port. +-}; +- +-constexpr uint8_t progressMask = 0x03; +-constexpr uint8_t enableMask = 0x01; +- +-/** @struct Auth +- * +- * SOL authentication parameter. +- */ +-struct Auth +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t privilege : 4; //!< SOL privilege level. +- uint8_t reserved : 2; //!< Reserved. +- uint8_t auth : 1; //!< Force SOL payload Authentication. +- uint8_t encrypt : 1; //!< Force SOL payload encryption. +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t encrypt : 1; //!< Force SOL payload encryption. +- uint8_t auth : 1; //!< Force SOL payload Authentication. +- uint8_t reserved : 2; //!< Reserved. +- uint8_t privilege : 4; //!< SOL privilege level. +-#endif +-} __attribute__((packed)); +- +-/** @struct Accumulate +- * +- * Character accumulate interval & Character send threshold. +- */ +-struct Accumulate +-{ +- uint8_t interval; //!< Character accumulate interval. +- uint8_t threshold; //!< Character send threshold. +-} __attribute__((packed)); +- +-constexpr uint8_t retryCountMask = 0x07; +- +-/** @struct Retry +- * +- * SOL retry count and interval. +- */ +-struct Retry +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t count : 3; //!< SOL retry count. +- uint8_t reserved : 5; //!< Reserved. +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t reserved : 5; //!< Reserved. +- uint8_t count : 3; //!< SOL retry count. +-#endif +- +- uint8_t interval; //!< SOL retry interval. +-} __attribute__((packed)); +- +-constexpr uint8_t ipmiCCParamNotSupported = 0x80; +-constexpr uint8_t ipmiCCInvalidSetInProgress = 0x81; +-constexpr uint8_t ipmiCCWriteReadParameter = 0x82; +-constexpr uint8_t ipmiCCReadWriteParameter = 0x83; +-constexpr uint8_t parameterRevision = 0x11; +- +-/** @struct SetConfParamsRequest +- * +- * IPMI payload for Set SOL configuration parameters command request. +- */ +-struct SetConfParamsRequest +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t channelNumber : 4; //!< Channel number. +- uint8_t reserved : 4; //!< Reserved. +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t reserved : 4; //!< Reserved. +- uint8_t channelNumber : 4; //!< Channel number. +-#endif +- +- uint8_t paramSelector; //!< Parameter selector. +- union +- { +- uint8_t value; //!< Represents one byte SOL parameters. +- struct Accumulate acc; //!< Character accumulate values. +- struct Retry retry; //!< Retry values. +- struct Auth auth; //!< Authentication parameters. +- }; +-} __attribute__((packed)); +- +-/** @struct SetConfParamsResponse +- * +- * IPMI payload for Set SOL configuration parameters command response. +- */ +-struct SetConfParamsResponse +-{ +- uint8_t completionCode; //!< Completion code. +-} __attribute__((packed)); +- +-/** @brief Set SOL configuration parameters command. +- * +- * @param[in] inPayload - Request data for the command. +- * @param[in] handler - Reference to the message handler. +- * +- * @return Response data for the command. +- */ +-std::vector<uint8_t> setConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler); +- +-/** @struct GetConfParamsRequest +- * +- * IPMI payload for Get SOL configuration parameters command request. +- */ +-struct GetConfParamsRequest +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t channelNum : 4; //!< Channel number. +- uint8_t reserved : 3; //!< Reserved. +- uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision +- uint8_t reserved : 3; //!< Reserved. +- uint8_t channelNum : 4; //!< Channel number. +-#endif +- +- uint8_t paramSelector; //!< Parameter selector. +- uint8_t setSelector; //!< Set selector. +- uint8_t blockSelector; //!< Block selector. +-} __attribute__((packed)); +- +-/** @struct GetConfParamsResponse +- * +- * IPMI payload for Get SOL configuration parameters command response. +- */ +-struct GetConfParamsResponse +-{ +- uint8_t completionCode; //!< Completion code. +- uint8_t paramRev; //!< Parameter revision. +-} __attribute__((packed)); +- +-/** @brief Get SOL configuration parameters command. +- * +- * @param[in] inPayload - Request data for the command. +- * @param[in] handler - Reference to the message handler. +- * +- * @return Response data for the command. +- */ +-std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler); +- + } // namespace command + + } // namespace sol +diff --git a/sol_module.cpp b/sol_module.cpp +index 2b1fb46..6da82c0 100644 +--- a/sol_module.cpp ++++ b/sol_module.cpp +@@ -42,12 +42,6 @@ void registerCommands() + &getPayloadInfo, + session::Privilege::USER, + false}, +- // Get SOL Configuration Parameters +- {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | +- static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x22}, +- &getConfParams, +- session::Privilege::USER, +- false}, + }; + + for (const auto& iter : commands) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend new file mode 100644 index 000000000..7f7d89105 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend @@ -0,0 +1,26 @@ +inherit useradd + +# TODO: This should be removed, once up-stream bump up +# issue is resolved +SRC_URI += "git://github.com/openbmc/phosphor-net-ipmid" +SRCREV = "dafe36444fa438030fdf27089b0e94d8d88411dc" + +USERADD_PACKAGES = "${PN}" +# add a group called ipmi +GROUPADD_PARAM_${PN} = "ipmi " + +# Default rmcpp iface is eth0; channel 1 +# Add channel 2 instance (eth1) +RMCPP_EXTRA = "eth1" +SYSTEMD_SERVICE_${PN} += " \ + ${PN}@${RMCPP_EXTRA}.service \ + ${PN}@${RMCPP_EXTRA}.socket \ + " + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += " file://0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch \ + file://0009-Add-dbus-interface-for-sol-commands.patch \ + file://0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch \ + " + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend new file mode 100644 index 000000000..72d991c7e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend @@ -0,0 +1 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb new file mode 100644 index 000000000..fd0a6562b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb @@ -0,0 +1,19 @@ +SUMMARY = "Node Manager Proxy" +DESCRIPTION = "The Node Manager Proxy provides a simple interface for communicating \ +with Management Engine via IPMB" + +SRC_URI = "git://git@github.com/Intel-BMC/node-manager;protocol=ssh" +SRCREV = "cceeff9cd35aa548cba039b8ad47c20c5870fa27" +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SYSTEMD_SERVICE_${PN} = "node-manager-proxy.service" + +DEPENDS = "sdbusplus \ + phosphor-logging \ + boost" + +S = "${WORKDIR}/git/" +inherit cmake systemd diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb new file mode 100644 index 000000000..dd48df0c6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb @@ -0,0 +1,21 @@ +SUMMARY = "Phosphor LED Group Management for Intel" +PR = "r1" + +inherit native +inherit obmc-phosphor-utils + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +PROVIDES += "virtual/phosphor-led-manager-config-native" + +SRC_URI += "file://led.yaml" +S = "${WORKDIR}" + +# Overwrite the example led layout yaml file prior +# to building the phosphor-led-manager package +do_install() { + SRC=${S} + DEST=${D}${datadir}/phosphor-led-manager + install -D ${SRC}/led.yaml ${DEST}/led.yaml +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml new file mode 100644 index 000000000..533df68a4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml @@ -0,0 +1,48 @@ +bmc_booted: + +power_on: + +status_ok: + status_green: + Action: 'On' + status_amber: + Action: 'Off' + +status_degraded: + status_green: + Action: 'Blink' + DutyOn: 50 + Period: 1000 + status_amber: + Action: 'Off' + +status_non_critical: + status_green: + Action: 'Off' + status_amber: + Action: 'Blink' + DutyOn: 50 + Period: 1000 + +status_critical: + status_green: + Action: 'Off' + status_amber: + Action: 'On' + +enclosure_identify: + identify: + Action: 'On' + +enclosure_identify_blink: + identify: + Action: 'Blink' + +cpu0_fault: + cpu0fault: + Action: 'On' + +cpu1_fault: + cpu1fault: + Action: 'On' + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-manager/multi-node-manager.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-manager/multi-node-manager.bb new file mode 100644 index 000000000..177f5c98f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-manager/multi-node-manager.bb @@ -0,0 +1,15 @@ +SUMMARY = "Multi node manager" +DESCRIPTION = "Daemon to handle chassis level shared resources on multi-node platform" + +SRC_URI = "git://git@github.com/Intel-BMC/multi-node-manager.git;protocol=ssh" +SRCREV = "34d959285a3ca12c4bfefa4040d82d571c78843b" + +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SYSTEMD_SERVICE_${PN} = "multi-node-manager.service" + +DEPENDS = "boost sdbusplus phosphor-logging i2c-tools" +inherit cmake systemd diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb new file mode 100644 index 000000000..66530e01d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb @@ -0,0 +1,18 @@ +SUMMARY = "Phosphor U-Boot environment manager" +DESCRIPTION = "Daemon to read or write U-Boot environment variables" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/phosphor-u-boot-env-mgr" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" + +SRCREV = "30110fe5b18999bddc5721dc5611f542f6feeabd" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.U_Boot.Environment.Manager.service" + +DEPENDS = "boost sdbusplus phosphor-logging" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend new file mode 100644 index 000000000..dc22b3c95 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend @@ -0,0 +1,3 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI = "file://init"
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init new file mode 100755 index 000000000..1ea94ed3a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init @@ -0,0 +1,243 @@ +#!/bin/sh + +# Copyright 2017-2019 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. +# +# +# provide a couple of places in the RO root filesystem +# that can be made RW with an overlayfs + +log() { + [ -c /dev/kmsg ] && echo "init: $@" > /dev/kmsg + echo "init: $@" +} + +# start with /proc and /tmp mounted +[ -e /proc/mounts ] || mount -t proc proc /proc +# FIXME: add size limits to /tmp +grep -q /tmp /proc/mounts || mount -t tmpfs -o rw,nosuid,nodev tmp /tmp +grep -q /sys /proc/mounts || mount -t sysfs -o rw,nosuid,nodev,noexec sys /sys + +# fix up /srv to be RW +mkdir -p /tmp/srv +mount --bind /tmp/srv /srv + +if grep -q debug-init /proc/cmdline; then + exec > /tmp/init.log 2>&1 + set -x + env +else + # silent bob + exec >/dev/null 2>&1 +fi + +# list of things that need to be rw at boot +NV_OVERLAYS="/etc /var /home" + +# place to mount the real ubifs backing store +RWFS_MNT=/tmp/.rwfs + +if grep -q "$RWFS_MNT" /proc/mounts; then + # quit - we have already run + exit 0 +fi +mkdir -p "$RWFS_MNT" + +mtd_by_name() { + local name="$1" + local mtd="/dev/$(grep "$name" /proc/mtd | cut -d : -f 1)" + echo "$mtd" +} + +mtdnum_by_name() { + local name="$1" + local mtdnum="$(grep "$name" /proc/mtd | cut -c 4)" + echo "$mtdnum" +} + +NV_MTD=rwfs +NV_MTD_DEV="$(mtd_by_name ${NV_MTD})" +NV_MTD_NUM="$(mtdnum_by_name ${NV_MTD})" + +nvrw() { + local p="$1" + # Clear the work dir doing overlay mount + rm -rf "${RWFS_MNT}${p}.work" + mkdir -p "${RWFS_MNT}${p}" "${RWFS_MNT}${p}.work" + local mname=$(echo "rwnv${p}" | sed 's,/,,g') + local opts="lowerdir=${p},upperdir=${RWFS_MNT}${p},workdir=${RWFS_MNT}${p}.work,sync" + mount -t overlay -o "$opts" "$mname" "$p" +} + +targeted_clean() { + log "restore-defaults: targeted_clean" + # Do not delete FRU info, ssh/ssl certs, or machine-id + ( + cd "${RWFS_MNT}/etc" + find . ! -regex '.*\(/ssl\|/dropbear\|/machine-id\(_bkup\)\?\|/fru\).*' -exec rm -rf {} + + ) + # nothing should be in the workdir, but clear it just in case + rm -rf "${RWFS_MNT}/etc.work" + + # clean everything out of /home + rm -rf "${RWFS_MNT}/home" "${RWFS_MNT}/home.work" + + # clean everything out of /var + rm -rf "${RWFS_MNT}/var" "${RWFS_MNT}/var.work" + + echo "Files remaining: $(find $RWFS_MNT/)" + sync +} + +full_clean() { + log "restore-defaults: full_clean" + local OVL='' + for OVL in $NV_OVERLAYS; do + rm -rf "${RWFS_MNT}${OVL}" "${RWFS_MNT}${OVL}.work" + done + sync +} +# attach a UBI device to the MTD device +prepare_ubi_volume() { + local nv_num="$1" + local mtd="/dev/mtd${nv_num}" + local ubi="/dev/ubi${nv_num}" + if [ ! -e $ubi ]; then + if ! ubiattach -m "$nv_num" -d "$nv_num"; then + # the attach failed, so format the MTD device and try again + log "Warning! Failed to attach $ubi to $mtd." + log "UBI-formatting $mtd to attach again. Data on this device will be lost." + ubiformat -y "$mtd" + ubiattach -m "$nv_num" -d "$nv_num" + fi + fi + + # make a UBI volume on the UBI device + local vol="${ubi}_0" + if [ ! -e $vol ]; then + ubimkvol "$ubi" -N "$mtd" -m + fi +} + +reformat_ubi_volume() { + local nv_num="$1" + local mnt="$2" + local mtd="/dev/mtd${nv_num}" + local ubi="/dev/ubi${nv_num}" + local mtd="/dev/mtd${nv_num}" + local vol="${ubi}_0" + # unmount the volume to reformat it + umount -f "$mnt" + ubidetach -m $nv_num + ubiformat -y "$mtd" + prepare_ubi_volume $nv_num + # remount the UBIFS on the UBI volume + mount -t ubifs -o sync "$vol" "$mnt" + if [ $? -ne 0 ]; then + log "Failed to mount reformatted NV volume; system unstable" + fi +} + +clear_ubenv() { + log "Clearing U-Boot environment" + flash_erase /dev/mtd/u-boot-env 0 0 +} + +# mount a UBIFS on the UBI volume +prepare_ubi_volume $NV_MTD_NUM +mount -t ubifs -o sync "/dev/ubi${NV_MTD_NUM}_0" "$RWFS_MNT" +if [ $? -ne 0 ]; then + log "Failed to mount NV volume; attempting recovery" + reformat_ubi_volume $NV_MTD_NUM $RWFS_MNT +fi + +# check for full factory reset: if so, ubiformat $NV_MTD_DEV +RESTORE_FLAG=$RWFS_MNT/.restore_op +restore_op=$(cat $RESTORE_FLAG) # read from NV +restore_op=${restore_op:-0} # set default value 0 +restore_op=$((restore_op & 3)) # mask off 2 bits +if [ $restore_op -eq 1 ]; then + targeted_clean +elif [ $restore_op -eq 2 ]; then + full_clean + clear_ubenv +elif [ $restore_op -eq 3 ]; then + log "restore-defaults: reformat" + reformat_ubi_volume $NV_MTD_NUM $RWFS_MNT + clear_ubenv +fi +rm -f $RESTORE_FLAG + +for FS in $NV_OVERLAYS; do + nvrw "$FS" +done + +# at first boot, fix up /var/volatile/{log,tmp} to be RW (due to yocto nonsense) +if [ -L /var/log ]; then + # remove symlink /var/log -> volatile/log; make /var/log non-volatile + rm /var/log + mkdir -p /var/log + # remove symlink /var/tmp -> volatile/tmp; symlink to /tmp/var + rm /var/tmp + ln -s /tmp/var /var/tmp +fi +mkdir -p /tmp/var + +# work around bug where /etc/machine-id will be mounted with a temporary file +# if rootfs is read-only and the file is empty +MACHINE_ID=/etc/machine-id +generate_machine_id() { + systemd-machine-id-setup + cp -pf "$MACHINE_ID" "${MACHINE_ID}_bkup" +} + +if [ ! -s "$MACHINE_ID" ]; then + # work around - Bug: Overlay fs fails for machine-id due to + # origin mismatch. Clean it up, from overlay fs before re-creating + # the same. + if [ -e "$RWFS_MNT$MACHINE_ID" ]; then + umount "/etc" + rm -f "$RWFS_MNT$MACHINE_ID" + nvrw "/etc" + # Restore the machine-id from backup, else generate it. + if [ -s "${MACHINE_ID}_bkup" ]; then + cp -pf "${MACHINE_ID}_bkup" "${MACHINE_ID}" + else + generate_machine_id + fi + log "Remounted /etc for machine-id origin mismatch" + else + generate_machine_id + fi +fi + +# mount persistent NV filesystem, where immortal settings live +SOFS_MNT=/var/sofs +if ! grep -q sofs /proc/mounts; then + mkdir -p $SOFS_MNT + SOFS_MTD=sofs + SOFS_MTD_NUM="$(mtdnum_by_name ${SOFS_MTD})" + + # mount a UBIFS on the UBI volume + prepare_ubi_volume $SOFS_MTD_NUM + mount -t ubifs -o sync "/dev/ubi${SOFS_MTD_NUM}_0" "$SOFS_MNT" + if [ $? -ne 0 ]; then + log "Failed to mount SOFS volume; attempting recovery" + reformat_ubi_volume $SOFS_MTD_NUM $SOFS_MNT + fi +fi + +log "Finished mounting non-volatile overlays" + +exec /lib/systemd/systemd diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb new file mode 100644 index 000000000..7ceff1798 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb @@ -0,0 +1,18 @@ +SUMMARY = "Provision mode daemon - RestrictionMode" +DESCRIPTION = "Daemon allows to configure RestrictionMode property" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/prov-mode-mgr" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" + +SRCREV = "30110fe5b18999bddc5721dc5611f542f6feeabd" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.RestrictionMode.Manager.service" + +DEPENDS = "boost sdbusplus phosphor-logging" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend new file mode 100644 index 000000000..ad14d1d65 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend @@ -0,0 +1,7 @@ +# Enable downstream autobump +SRC_URI = "git://github.com/openbmc/phosphor-sel-logger.git" +SRCREV = "6afe9560852c6431c43c8e79a28e2b7cb498e355" + +# Enable threshold monitoring +EXTRA_OECMAKE += "-DSEL_LOGGER_MONITOR_THRESHOLD_EVENTS=ON" +EXTRA_OECMAKE += "-DREDFISH_LOG_MONITOR_PULSE_EVENTS=ON" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service new file mode 100644 index 000000000..b8c3554ae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service @@ -0,0 +1,10 @@ +[Unit] +Description= BMC Self-Test + +[Service] +Restart=always +ExecStart=/usr/bin/env selftest +SyslogIdentifier=selftest + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb new file mode 100644 index 000000000..da1d74207 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb @@ -0,0 +1,38 @@ +SUMMARY = "BMC Self Test service" +DESCRIPTION = "BMC Self Test service for subsystem diagnosis failure info" + +SRC_URI = "git://git@github.com/Intel-BMC/intel-self-test;protocol=ssh" + +PV = "1.0+git${SRCPV}" +SRCREV = "d039998ad2c55aeae4191af30e15bbd3032508c1" + +S = "${WORKDIR}/git" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=fa818a259cbed7ce8bc2a22d35a464fc" + +inherit cmake +inherit obmc-phosphor-dbus-service +inherit obmc-phosphor-systemd +inherit pkgconfig pythonnative + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.selftest.service" + +DEPENDS += " \ + autoconf-archive-native \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + " + +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + phosphor-dbus-interfaces \ + " + +EXTRA_OECMAKE = " -DENABLE_GTEST=OFF -DCMAKE_SKIP_RPATH=ON" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend new file mode 100644 index 000000000..ce487dd0d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend @@ -0,0 +1,7 @@ +SRCREV = "432d1edf7ac86f69558273307a59e4b1cf86b8a6" +SRC_URI = "git://github.com/openbmc/dbus-sensors.git" + +DEPENDS_append = " libgpiod" + +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb new file mode 100644 index 000000000..c23d86a38 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb @@ -0,0 +1,20 @@ +SUMMARY = "Settings" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "30110fe5b18999bddc5721dc5611f542f6feeabd" +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SYSTEMD_SERVICE_${PN} = "settings.service" + +DEPENDS = "boost \ + nlohmann-json \ + sdbusplus" + +S = "${WORKDIR}/git/settings" +inherit cmake systemd + +EXTRA_OECMAKE = "-DYOCTO=1" + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb new file mode 100644 index 000000000..eb8f6ac34 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb @@ -0,0 +1,28 @@ +SUMMARY = "Special mode manager daemon to handle manufacturing modes" +DESCRIPTION = "Daemon exposes the manufacturing mode property" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/special-mode-mgr" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "30110fe5b18999bddc5721dc5611f542f6feeabd" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "specialmodemgr.service" + +DEPENDS += " \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + boost \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb new file mode 100644 index 000000000..12619a88e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb @@ -0,0 +1,28 @@ +SUMMARY = "Service configuration manager daemon to control service properties" +DESCRIPTION = "Daemon controls service properies like port, channels, state etc.." + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/srvcfg-manager" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "30110fe5b18999bddc5721dc5611f542f6feeabd" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "srvcfg-manager.service" + +DEPENDS += " \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + boost \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch new file mode 100644 index 000000000..56bb8d1c3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch @@ -0,0 +1,499 @@ +From 7d78e70735e1bce51ef34cfe128be68758de3447 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Tue, 19 Feb 2019 15:00:11 +0800 +Subject: [PATCH] Implement post code manager + +Implement method and properties defined in PostCode.interface.yaml +under phosphor-dbus-interfaces/xyz/openbmc_project/State/Boot +1. Method: std::vector<uint64_t> PostCode::getPostCodes(uint16_t index) +2. Properties: CurrentBootCycleIndex/MaxBootCycleNum + +Test-By: + Every cycle post codes is saved in "/var/lib/phosphor-post-code-manager" + "1" file is saved all post codes for cycle 1 + "2" file is saved all post codes for cycle 2 + "CurrentBootCycleIndex" file is saved the current boot cycle number. + root@wolfpass:/var/lib/phosphor-post-code-manager# ls + 1 2 CurrentBootCycleIndex + +Change-Id: Ia89b9121983261fef5573092d890beb84626ceeb +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + CMakeLists.txt | 45 ++++++ + MAINTAINERS | 45 ++++++ + inc/post_code.hpp | 152 ++++++++++++++++++ + ...penbmc_project.State.Boot.PostCode.service | 11 ++ + src/main.cpp | 61 +++++++ + src/post_code.cpp | 109 +++++++++++++ + 6 files changed, 423 insertions(+) + create mode 100644 CMakeLists.txt + create mode 100644 MAINTAINERS + create mode 100644 inc/post_code.hpp + create mode 100644 service_files/xyz.openbmc_project.State.Boot.PostCode.service + create mode 100644 src/main.cpp + create mode 100644 src/post_code.cpp + +diff --git a/CMakeLists.txt b/CMakeLists.txt +new file mode 100644 +index 0000000..594d839 +--- /dev/null ++++ b/CMakeLists.txt +@@ -0,0 +1,45 @@ ++cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) ++project(post-code-manager CXX) ++set(CMAKE_CXX_STANDARD 17) ++set(CMAKE_CXX_STANDARD_REQUIRED ON) ++ ++set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) ++include(GNUInstallDirs) ++include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc) ++include_directories(${CMAKE_CURRENT_BINARY_DIR}) ++ ++set(DBUS_OBJECT_NAME "xyz/openbmc_project/State/Boot/PostCode") ++set(DBUS_INTF_NAME "xyz.openbmc_project.State.Boot.PostCode") ++ ++add_definitions(-DDBUS_OBJECT_NAME="/${DBUS_OBJECT_NAME}") ++add_definitions(-DDBUS_INTF_NAME="${DBUS_INTF_NAME}") ++set(SRC_FILES src/post_code.cpp ++ src/main.cpp ) ++set ( SERVICE_FILES ++ service_files/xyz.openbmc_project.State.Boot.PostCode.service ) ++ ++# import sdbusplus ++find_package(PkgConfig REQUIRED) ++pkg_check_modules(SDBUSPLUSPLUS sdbusplus REQUIRED) ++include_directories(${SDBUSPLUSPLUS_INCLUDE_DIRS}) ++link_directories(${SDBUSPLUSPLUS_LIBRARY_DIRS}) ++find_program(SDBUSPLUSPLUS sdbus++) ++ ++# import phosphor-logging ++find_package(PkgConfig REQUIRED) ++pkg_check_modules(LOGGING phosphor-logging REQUIRED) ++include_directories(${LOGGING_INCLUDE_DIRS}) ++link_directories(${LOGGING_LIBRARY_DIRS}) ++ ++# phosphor-dbus-interfaces ++find_package(PkgConfig REQUIRED) ++pkg_check_modules(DBUSINTERFACE phosphor-dbus-interfaces REQUIRED) ++include_directories(${DBUSINTERFACE_INCLUDE_DIRS}) ++link_directories(${DBUSINTERFACE_LIBRARY_DIRS}) ++ ++add_executable(${PROJECT_NAME} ${SRC_FILES}) ++target_link_libraries(${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES} ) ++target_link_libraries(${PROJECT_NAME} "${SDBUSPLUSPLUS_LIBRARIES} -lstdc++fs -lphosphor_dbus") ++ ++install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) ++install (FILES ${SERVICE_FILES} DESTINATION /lib/systemd/system/) +\ No newline at end of file +diff --git a/MAINTAINERS b/MAINTAINERS +new file mode 100644 +index 0000000..de6cc54 +--- /dev/null ++++ b/MAINTAINERS +@@ -0,0 +1,45 @@ ++How to use this list: ++ Find the most specific section entry (described below) that matches where ++ your change lives and add the reviewers (R) and maintainers (M) as ++ reviewers. You can use the same method to track down who knows a particular ++ code base best. ++ ++ Your change/query may span multiple entries; that is okay. ++ ++ If you do not find an entry that describes your request at all, someone ++ forgot to update this list; please at least file an issue or send an email ++ to a maintainer, but preferably you should just update this document. ++ ++Description of section entries: ++ ++ Section entries are structured according to the following scheme: ++ ++ X: NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!> ++ X: ... ++ . ++ . ++ . ++ ++ Where REPO_NAME is the name of the repository within the OpenBMC GitHub ++ organization; FILE_PATH is a file path within the repository, possibly with ++ wildcards; X is a tag of one of the following types: ++ ++ M: Denotes maintainer; has fields NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!>; ++ if omitted from an entry, assume one of the maintainers from the ++ MAINTAINERS entry. ++ R: Denotes reviewer; has fields NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!>; ++ these people are to be added as reviewers for a change matching the repo ++ path. ++ F: Denotes forked from an external repository; has fields URL. ++ ++ Line comments are to be denoted "# SOME COMMENT" (typical shell style ++ comment); it is important to follow the correct syntax and semantics as we ++ may want to use automated tools with this file in the future. ++ ++ A change cannot be added to an OpenBMC repository without a MAINTAINER's ++ approval; thus, a MAINTAINER should always be listed as a reviewer. ++ ++START OF MAINTAINERS LIST ++------------------------- ++ ++M: Kuiying Wang <kuiying.wang@intel.com> <kuiyingw> +\ No newline at end of file +diff --git a/inc/post_code.hpp b/inc/post_code.hpp +new file mode 100644 +index 0000000..84c8b3e +--- /dev/null ++++ b/inc/post_code.hpp +@@ -0,0 +1,152 @@ ++/* ++// Copyright (c) 2019 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 <fcntl.h> ++#include <unistd.h> ++#include <cereal/cereal.hpp> ++#include <experimental/filesystem> ++#include <cereal/access.hpp> ++#include <cereal/archives/json.hpp> ++#include <iostream> ++#include <fstream> ++#include <cereal/types/vector.hpp> ++ ++#include <xyz/openbmc_project/State/Boot/PostCode/server.hpp> ++#include <xyz/openbmc_project/Common/error.hpp> ++#include <phosphor-logging/elog-errors.hpp> ++#include <xyz/openbmc_project/State/Host/server.hpp> ++ ++#define MaxPostCodeCycles 100 ++ ++const static constexpr char *PostCodePath = ++ "/xyz/openbmc_project/state/boot/raw"; ++const static constexpr char *PropertiesIntf = ++ "org.freedesktop.DBus.Properties"; ++const static constexpr char *PostCodeListPath = ++ "/var/lib/phosphor-post-code-manager/"; ++const static constexpr char *CurrentBootCycleIndexName = ++ "CurrentBootCycleIndex"; ++const static constexpr char *HostStatePath = ++ "/xyz/openbmc_project/state/host0"; ++ ++ ++struct EventDeleter ++{ ++ void operator()(sd_event *event) const ++ { ++ event = sd_event_unref(event); ++ } ++}; ++using EventPtr = std::unique_ptr<sd_event, EventDeleter>; ++namespace fs = std::experimental::filesystem; ++namespace StateServer = sdbusplus::xyz::openbmc_project::State::server; ++ ++using post_code = ++ sdbusplus::xyz::openbmc_project::State::Boot::server::PostCode; ++ ++struct PostCode : sdbusplus::server::object_t<post_code> ++{ ++ PostCode(sdbusplus::bus::bus& bus, const char* path, ++ EventPtr &event) : ++ sdbusplus::server::object_t<post_code>(bus, path), ++ bus(bus), ++ propertiesChangedSignalRaw( ++ bus, ++ sdbusplus::bus::match::rules::type::signal() + ++ sdbusplus::bus::match::rules::member("PropertiesChanged") + ++ sdbusplus::bus::match::rules::path(PostCodePath) + ++ sdbusplus::bus::match::rules::interface(PropertiesIntf), ++ [this](sdbusplus::message::message &msg) { ++ std::string objectName; ++ std::map<std::string, sdbusplus::message::variant<uint64_t>> msgData; ++ msg.read(objectName, msgData); ++ // Check if it was the Value property that changed. ++ auto valPropMap = msgData.find("Value"); ++ { ++ if (valPropMap != msgData.end()) ++ { ++ this->savePostCodes(sdbusplus::message::variant_ns::get<uint64_t>(valPropMap->second)); ++ } ++ } ++ }), ++ propertiesChangedSignalCurrentHostState( ++ bus, ++ sdbusplus::bus::match::rules::type::signal() + ++ sdbusplus::bus::match::rules::member("PropertiesChanged") + ++ sdbusplus::bus::match::rules::path(HostStatePath) + ++ sdbusplus::bus::match::rules::interface(PropertiesIntf), ++ [this](sdbusplus::message::message &msg) { ++ std::string objectName; ++ std::map<std::string, sdbusplus::message::variant<std::string>> msgData; ++ msg.read(objectName, msgData); ++ // Check if it was the Value property that changed. ++ auto valPropMap = msgData.find("CurrentHostState"); ++ { ++ if (valPropMap != msgData.end()) ++ { ++ StateServer::Host::HostState currentHostState = ++ StateServer::Host::convertHostStateFromString( ++ sdbusplus::message::variant_ns::get<std::string>(valPropMap->second)); ++ if (currentHostState == StateServer::Host::HostState::Off) ++ { ++ if (this->currentBootCycleIndex() >= this->maxBootCycleNum()) ++ { ++ this->currentBootCycleIndex(1); ++ } else{ ++ this->currentBootCycleIndex(this->currentBootCycleIndex() + 1); ++ } ++ this->postCodes.clear(); ++ } ++ } ++ } ++ }) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "PostCode is created"); ++ auto dir = fs::path(PostCodeListPath); ++ fs::create_directories(dir); ++ strPostCodeListPath = PostCodeListPath; ++ strCurrentBootCycleIndexName = CurrentBootCycleIndexName; ++ uint16_t index = 0; ++ deserialize(fs::path(strPostCodeListPath + strCurrentBootCycleIndexName), index); ++ currentBootCycleIndex(index); ++ maxBootCycleNum(MaxPostCodeCycles); ++ if (currentBootCycleIndex() >= maxBootCycleNum()) ++ { ++ currentBootCycleIndex(1); ++ } else{ ++ currentBootCycleIndex(currentBootCycleIndex() + 1); ++ } ++ } ++ ~PostCode() ++ { ++ ++ } ++ ++ std::vector<uint64_t> getPostCodes(uint16_t index) override; ++ ++ private: ++ sdbusplus::bus::bus& bus; ++ std::vector<uint64_t> postCodes; ++ std::string strPostCodeListPath; ++ std::string strCurrentBootCycleIndexName; ++ void savePostCodes(uint64_t code); ++ sdbusplus::bus::match_t propertiesChangedSignalRaw; ++ sdbusplus::bus::match_t propertiesChangedSignalCurrentHostState; ++ fs::path serialize(const std::string& path); ++ bool deserialize(const fs::path& path, uint16_t& index); ++ bool deserializePostCodes(const fs::path& path, std::vector<uint64_t> &codes); ++}; +diff --git a/service_files/xyz.openbmc_project.State.Boot.PostCode.service b/service_files/xyz.openbmc_project.State.Boot.PostCode.service +new file mode 100644 +index 0000000..67bc43f +--- /dev/null ++++ b/service_files/xyz.openbmc_project.State.Boot.PostCode.service +@@ -0,0 +1,11 @@ ++[Unit] ++Description=Post code manager ++ ++[Service] ++ExecStart=/usr/bin/env post-code-manager ++SyslogIdentifier=post-code-manager ++Type=dbus ++BusName=xyz.openbmc_project.State.Boot.PostCode ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/src/main.cpp b/src/main.cpp +new file mode 100644 +index 0000000..4a74b29 +--- /dev/null ++++ b/src/main.cpp +@@ -0,0 +1,61 @@ ++/* ++// Copyright (c) 2019 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. ++*/ ++#include "post_code.hpp" ++ ++int main(int argc, char* argv[]) ++{ ++ int ret = 0; ++ ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Start post code manager service..."); ++ ++ sd_event* event = nullptr; ++ ret = sd_event_default(&event); ++ if (ret < 0) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error creating a default sd_event handler"); ++ return ret; ++ } ++ EventPtr eventP{event}; ++ event = nullptr; ++ ++ sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); ++ sdbusplus::server::manager_t m{bus, DBUS_OBJECT_NAME}; ++ ++ bus.request_name(DBUS_INTF_NAME); ++ ++ PostCode postCode{bus, DBUS_OBJECT_NAME, eventP}; ++ ++ try ++ { ++ bus.attach_event(eventP.get(), SD_EVENT_PRIORITY_NORMAL); ++ ret = sd_event_loop(eventP.get()); ++ if (ret < 0) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error occurred during the sd_event_loop", ++ phosphor::logging::entry("RET=%d", ret)); ++ } ++ } ++ catch (std::exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return -1; ++ } ++ return 0; ++ ++} +diff --git a/src/post_code.cpp b/src/post_code.cpp +new file mode 100644 +index 0000000..983eeee +--- /dev/null ++++ b/src/post_code.cpp +@@ -0,0 +1,109 @@ ++/* ++// Copyright (c) 2019 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. ++*/ ++#include "post_code.hpp" ++std::vector<uint64_t> PostCode::getPostCodes(uint16_t index) ++{ ++ std::vector<uint64_t> codes; ++ ++ if (currentBootCycleIndex() == index) ++ return postCodes; ++ deserializePostCodes(fs::path(strPostCodeListPath + std::to_string(index)), codes); ++ return codes; ++} ++void PostCode::savePostCodes(uint64_t code) ++{ ++ postCodes.push_back(code); ++ serialize(fs::path(PostCodeListPath)); ++ return; ++} ++ ++fs::path PostCode::serialize(const std::string& path) ++{ ++ try ++ { ++ uint16_t index = currentBootCycleIndex(); ++ fs::path fullPath(path + strCurrentBootCycleIndexName); ++ std::ofstream os(fullPath.c_str(), std::ios::binary); ++ cereal::JSONOutputArchive oarchive(os); ++ oarchive(index); ++ std::ofstream osPostCodes((path + std::to_string(currentBootCycleIndex())).c_str(), std::ios::binary); ++ cereal::JSONOutputArchive oarchivePostCodes(osPostCodes); ++ oarchivePostCodes(postCodes); ++ } ++ catch (cereal::Exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return ""; ++ } ++ catch (const fs::filesystem_error& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return ""; ++ } ++ return path; ++} ++ ++bool PostCode::deserialize(const fs::path& path, uint16_t& index) ++{ ++ try ++ { ++ if (fs::exists(path)) ++ { ++ std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); ++ cereal::JSONInputArchive iarchive(is); ++ iarchive(index); ++ return true; ++ } ++ return false; ++ } ++ catch (cereal::Exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return false; ++ } ++ catch (const fs::filesystem_error& e) ++ { ++ return false; ++ } ++ ++ return false; ++} ++ ++bool PostCode::deserializePostCodes(const fs::path& path, std::vector<uint64_t> &codes) ++{ ++ try ++ { ++ if (fs::exists(path)) ++ { ++ std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); ++ cereal::JSONInputArchive iarchive(is); ++ iarchive(codes); ++ return true; ++ } ++ return false; ++ } ++ catch (cereal::Exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return false; ++ } ++ catch (const fs::filesystem_error& e) ++ { ++ return false; ++ } ++ ++ return false; ++} +-- +2.19.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb new file mode 100644 index 000000000..8f2ead18a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb @@ -0,0 +1,34 @@ +SUMMARY = "Phosphor post code manager" +DESCRIPTION = "Post Code Manager" + +SRC_URI = "git://github.com/openbmc/phosphor-post-code-manager.git" +SRCREV = "7f50dcaa6feb66cf5307b8a0e4742a36a50eed29" + +S = "${WORKDIR}/git" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327" + +inherit cmake pkgconfig systemd + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.State.Boot.PostCode.service" + +DEPENDS += " \ + autoconf-archive-native \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + phosphor-logging \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-dbus-interfaces \ + phosphor-logging \ + " +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += "file://0001-Implement-post-code-manager.patch" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb new file mode 100644 index 000000000..7e69f41c5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb @@ -0,0 +1,19 @@ +SUMMARY = "Callback Manager" +DESCRIPTION = "D-Bus daemon that registers matches that trigger method calls" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground;protocol=ssh" + +inherit cmake systemd +DEPENDS = "boost sdbusplus" + +PV = "0.1+git${SRCPV}" +SRCREV = "30110fe5b18999bddc5721dc5611f542f6feeabd" + +S = "${WORKDIR}/git/callback-manager" + +SYSTEMD_SERVICE_${PN} += "callback-manager.service" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENCE;md5=7becf906c8f8d03c237bad13bc3dac53" + +EXTRA_OECMAKE = "-DYOCTO=1" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch new file mode 100644 index 000000000..0af64698a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch @@ -0,0 +1,1645 @@ +From a519a128b9a44b1798419bf3a653d58e266c60fb Mon Sep 17 00:00:00 2001 +From: Radivoje Jovanovic <radivoje.jovanovic@intel.com> +Date: Mon, 2 Jul 2018 19:23:25 -0700 +Subject: [PATCH] Added suport for multiple user manager services + +Support added for SSSD service implementation + +Signed-off-by: Alberto Salazar Perez <alberto.salazar.perez@intel.com> +Signed-off-by: Radivoje Jovanovic <radivoje.jovanovic@intel.com> +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + Makefile.am | 5 +- + mainapp.cpp | 89 ++++++- + user_mgr.cpp | 290 ++------------------- + user_mgr.hpp | 9 +- + user_service.cpp | 781 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + user_service.hpp | 233 +++++++++++++++++ + 6 files changed, 1139 insertions(+), 268 deletions(-) + create mode 100644 user_service.cpp + create mode 100644 user_service.hpp + +diff --git a/Makefile.am b/Makefile.am +index 7c7271e..58916b0 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1,11 +1,12 @@ + bin_PROGRAMS = phosphor-user-manager + +-noinst_HEADERS = user_mgr.hpp users.hpp ++noinst_HEADERS = user_mgr.hpp users.hpp user_service.hpp + + phosphor_user_manager_SOURCES = \ + mainapp.cpp \ + user_mgr.cpp \ +- users.cpp ++ users.cpp \ ++ user_service.cpp + + phosphor_user_manager_LDFLAGS = $(SDBUSPLUS_LIBS) \ + $(PHOSPHOR_DBUS_INTERFACES_LIBS) \ +diff --git a/mainapp.cpp b/mainapp.cpp +index c9da030..03c406a 100644 +--- a/mainapp.cpp ++++ b/mainapp.cpp +@@ -14,18 +14,105 @@ + * limitations under the License. + */ + #include <string> ++#include <iostream> ++#include <getopt.h> + #include "user_mgr.hpp" ++#include "user_service.hpp" + #include "config.h" + + // D-Bus root for user manager + constexpr auto USER_MANAGER_ROOT = "/xyz/openbmc_project/user"; + ++void printUsage() ++{ ++ std::string usage = ++ R"(Usage: ++ phosphor-user-manager [OPTIONS] ++ ++Backend DBUS service for OpenBMC User Management. ++If no OPTIONS are specified, shadow file will be used. ++ ++Options: ++ -s, --service={shadow|sssd} ++ Specify the authentication service to use: ++ 'shadow' will use the /etc/shadow file. ++ 'sssd' will use the sssd service domains. ++ -h, --help Displays this help message. ++)"; ++ std::cerr << usage; ++} ++ ++void parseArgs(int argc, char** argv, ++ phosphor::user::UserService::ServiceType& srvc) ++{ ++ const std::string shortOpts{"s:h"}; ++ const struct option longOpts[] = {{"service", 1, nullptr, 's'}, ++ {"help", 0, nullptr, 'h'}, ++ {nullptr, 0, nullptr, 0}}; ++ ++ while (true) ++ { ++ const auto opt = ++ getopt_long(argc, argv, shortOpts.c_str(), longOpts, nullptr); ++ ++ if (opt == -1) ++ { ++ if (srvc == phosphor::user::UserService::ServiceType::none) ++ { ++ srvc = phosphor::user::UserService::ServiceType::shadow; ++ } ++ break; ++ } ++ ++ switch (opt) ++ { ++ case 's': ++ { ++ std::string srvcStr{optarg}; ++ if (!srvcStr.compare("shadow")) ++ { ++ srvc = phosphor::user::UserService::ServiceType::shadow; ++ } ++ else if (!srvcStr.compare("sssd")) ++ { ++ srvc = phosphor::user::UserService::ServiceType::sssd; ++ } ++ else ++ { ++ std::cerr << "Error. '" << srvcStr << "' is not a valid" ++ << " authentication service." << std::endl; ++ printUsage(); ++ exit(1); ++ } ++ } ++ break; ++ ++ case 'h': ++ { ++ printUsage(); ++ exit(0); ++ } ++ ++ default: ++ { ++ printUsage(); ++ exit(1); ++ } ++ } ++ } ++} ++ + int main(int argc, char** argv) + { ++ // Check command line options. Exit if error. ++ phosphor::user::UserService::ServiceType srvc = ++ phosphor::user::UserService::ServiceType::none; ++ parseArgs(argc, argv, srvc); ++ + auto bus = sdbusplus::bus::new_default(); + sdbusplus::server::manager::manager objManager(bus, USER_MANAGER_ROOT); + +- phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT); ++ phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT, srvc); + + // Claim the bus now + bus.request_name(USER_MANAGER_BUSNAME); +diff --git a/user_mgr.cpp b/user_mgr.cpp +index 17146e6..db6e7d5 100644 +--- a/user_mgr.cpp ++++ b/user_mgr.cpp +@@ -14,26 +14,20 @@ + // limitations under the License. + */ + +-#include <shadow.h> +-#include <unistd.h> +-#include <sys/types.h> +-#include <sys/wait.h> ++#include <cstdio> ++ + #include <fstream> + #include <grp.h> + #include <pwd.h> + #include <regex> +-#include <algorithm> +-#include <numeric> +-#include <boost/process/child.hpp> +-#include <boost/process/io.hpp> + #include <boost/algorithm/string/split.hpp> + #include <xyz/openbmc_project/Common/error.hpp> + #include <xyz/openbmc_project/User/Common/error.hpp> + #include <phosphor-logging/log.hpp> + #include <phosphor-logging/elog.hpp> + #include <phosphor-logging/elog-errors.hpp> ++#include <stdexcept> + #include "shadowlock.hpp" +-#include "file.hpp" + #include "user_mgr.hpp" + #include "users.hpp" + #include "config.h" +@@ -43,12 +37,10 @@ namespace phosphor + namespace user + { + +-static constexpr const char *passwdFileName = "/etc/passwd"; + static constexpr size_t ipmiMaxUsers = 15; + static constexpr size_t ipmiMaxUserNameLen = 16; + static constexpr size_t systemMaxUserNameLen = 30; + static constexpr size_t maxSystemUsers = 30; +-static constexpr const char *grpSsh = "ssh"; + static constexpr uint8_t minPasswdLength = 8; + static constexpr int success = 0; + static constexpr int failure = -1; +@@ -94,79 +86,6 @@ using NoResource = + + using Argument = xyz::openbmc_project::Common::InvalidArgument; + +-template <typename... ArgTypes> +-static std::vector<std::string> executeCmd(const char *path, +- ArgTypes &&... tArgs) +-{ +- std::vector<std::string> stdOutput; +- boost::process::ipstream stdOutStream; +- boost::process::child execProg(path, const_cast<char *>(tArgs)..., +- boost::process::std_out > stdOutStream); +- std::string stdOutLine; +- +- while (stdOutStream && std::getline(stdOutStream, stdOutLine) && +- !stdOutLine.empty()) +- { +- stdOutput.emplace_back(stdOutLine); +- } +- +- execProg.wait(); +- +- int retCode = execProg.exit_code(); +- if (retCode) +- { +- log<level::ERR>("Command execution failed", entry("PATH=%d", path), +- entry("RETURN_CODE:%d", retCode)); +- elog<InternalFailure>(); +- } +- +- return stdOutput; +-} +- +-static std::string getCSVFromVector(std::vector<std::string> vec) +-{ +- switch (vec.size()) +- { +- case 0: +- { +- return ""; +- } +- break; +- +- case 1: +- { +- return std::string{vec[0]}; +- } +- break; +- +- default: +- { +- return std::accumulate( +- std::next(vec.begin()), vec.end(), vec[0], +- [](std::string a, std::string b) { return a + ',' + b; }); +- } +- } +-} +- +-static bool removeStringFromCSV(std::string &csvStr, const std::string &delStr) +-{ +- std::string::size_type delStrPos = csvStr.find(delStr); +- if (delStrPos != std::string::npos) +- { +- // need to also delete the comma char +- if (delStrPos == 0) +- { +- csvStr.erase(delStrPos, delStr.size() + 1); +- } +- else +- { +- csvStr.erase(delStrPos - 1, delStr.size() + 1); +- } +- return true; +- } +- return false; +-} +- + bool UserMgr::isUserExist(const std::string &userName) + { + if (userName.empty()) +@@ -293,39 +212,14 @@ void UserMgr::createUser(std::string userName, + { + throwForInvalidPrivilege(priv); + throwForInvalidGroups(groupNames); +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserExists(userName); + throwForUserNameConstraints(userName, groupNames); + throwForMaxGrpUserCount(groupNames); + +- std::string groups = getCSVFromVector(groupNames); +- bool sshRequested = removeStringFromCSV(groups, grpSsh); +- +- // treat privilege as a group - This is to avoid using different file to +- // store the same. +- if (!priv.empty()) +- { +- if (groups.size() != 0) +- { +- groups += ","; +- } +- groups += priv; +- } +- try +- { +- executeCmd("/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(), +- "-m", "-N", "-s", +- (sshRequested ? "/bin/sh" : "/bin/nologin"), "-e", +- (enabled ? "" : "1970-01-02")); +- } +- catch (const InternalFailure &e) +- { +- log<level::ERR>("Unable to create new user"); +- elog<InternalFailure>(); +- } ++ // Tell the User Service to create a new user with the info provided. ++ userSrvc->createUser(userName, groupNames, priv, enabled); + +- // Add the users object before sending out the signal ++ // Add the users to the local list before sending out the signal + std::string userObj = std::string(usersObjPath) + "/" + userName; + std::sort(groupNames.begin(), groupNames.end()); + usersList.emplace( +@@ -339,19 +233,11 @@ void UserMgr::createUser(std::string userName, + + void UserMgr::deleteUser(std::string userName) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); +- try +- { +- executeCmd("/usr/sbin/userdel", userName.c_str(), "-r"); +- } +- catch (const InternalFailure &e) +- { +- log<level::ERR>("User delete failed", +- entry("USER_NAME=%s", userName.c_str())); +- elog<InternalFailure>(); +- } ++ ++ // Tell the User Service to delete user ++ userSrvc->deleteUser(userName); ++ // Then delete user from local list + + usersList.erase(userName); + +@@ -362,24 +248,13 @@ void UserMgr::deleteUser(std::string userName) + + void UserMgr::renameUser(std::string userName, std::string newUserName) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); + throwForUserExists(newUserName); + throwForUserNameConstraints(newUserName, + usersList[userName].get()->userGroups()); +- try +- { +- std::string newHomeDir = "/home/" + newUserName; +- executeCmd("/usr/sbin/usermod", "-l", newUserName.c_str(), +- userName.c_str(), "-d", newHomeDir.c_str(), "-m"); +- } +- catch (const InternalFailure &e) +- { +- log<level::ERR>("User rename failed", +- entry("USER_NAME=%s", userName.c_str())); +- elog<InternalFailure>(); +- } ++ // Call The User Service to rename user on the system ++ userSrvc->renameUser(userName, newUserName); ++ // Update local list to reflect the name change + const auto &user = usersList[userName]; + std::string priv = user.get()->userPrivilege(); + std::vector<std::string> groupNames = user.get()->userGroups(); +@@ -403,8 +278,6 @@ void UserMgr::updateGroupsAndPriv(const std::string &userName, + { + throwForInvalidPrivilege(priv); + throwForInvalidGroups(groupNames); +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); + const std::vector<std::string> &oldGroupNames = + usersList[userName].get()->userGroups(); +@@ -420,29 +293,8 @@ void UserMgr::updateGroupsAndPriv(const std::string &userName, + throwForMaxGrpUserCount(groupNames); + } + +- std::string groups = getCSVFromVector(groupNames); +- bool sshRequested = removeStringFromCSV(groups, grpSsh); +- +- // treat privilege as a group - This is to avoid using different file to +- // store the same. +- if (!priv.empty()) +- { +- if (groups.size() != 0) +- { +- groups += ","; +- } +- groups += priv; +- } +- try +- { +- executeCmd("/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(), +- "-s", (sshRequested ? "/bin/sh" : "/bin/nologin")); +- } +- catch (const InternalFailure &e) +- { +- log<level::ERR>("Unable to modify user privilege / groups"); +- elog<InternalFailure>(); +- } ++ // Call The User Service to update user groups and priv on the system ++ userSrvc->updateGroupsAndPriv(userName, groupNames, priv); + + log<level::INFO>("User groups / privilege updated successfully", + entry("USER_NAME=%s", userName.c_str())); +@@ -638,19 +490,9 @@ int UserMgr::setPamModuleArgValue(const std::string &moduleName, + + void UserMgr::userEnable(const std::string &userName, bool enabled) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); +- try +- { +- executeCmd("/usr/sbin/usermod", userName.c_str(), "-e", +- (enabled ? "" : "1970-01-02")); +- } +- catch (const InternalFailure &e) +- { +- log<level::ERR>("Unable to modify user enabled state"); +- elog<InternalFailure>(); +- } ++ // Call The User Service to update user groups and priv on the system ++ userSrvc->updateUserStatus(userName, enabled); + + log<level::INFO>("User enabled/disabled state updated successfully", + entry("USER_NAME=%s", userName.c_str()), +@@ -728,49 +570,8 @@ bool UserMgr::userLockedForFailedAttempt(const std::string &userName, + + UserSSHLists UserMgr::getUserAndSshGrpList() + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); +- +- std::vector<std::string> userList; +- std::vector<std::string> sshUsersList; +- struct passwd pw, *pwp = nullptr; +- std::array<char, 1024> buffer{}; +- +- phosphor::user::File passwd(passwdFileName, "r"); +- if ((passwd)() == NULL) +- { +- log<level::ERR>("Error opening the passwd file"); +- elog<InternalFailure>(); +- } +- +- while (true) +- { +- auto r = fgetpwent_r((passwd)(), &pw, buffer.data(), buffer.max_size(), +- &pwp); +- if ((r != 0) || (pwp == NULL)) +- { +- // Any error, break the loop. +- break; +- } +- // Add all users whose UID >= 1000 and < 65534 +- // and special UID 0. +- if ((pwp->pw_uid == 0) || +- ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))) +- { +- std::string userName(pwp->pw_name); +- userList.emplace_back(userName); +- +- // ssh doesn't have separate group. Check login shell entry to +- // get all users list which are member of ssh group. +- std::string loginShell(pwp->pw_shell); +- if (loginShell == "/bin/sh") +- { +- sshUsersList.emplace_back(userName); +- } +- } +- } +- endpwent(); +- return std::make_pair(std::move(userList), std::move(sshUsersList)); ++ // Call The User Service to get the User and SSUsers lists ++ return std::move(userSrvc->getUserAndSshGrpList()); + } + + size_t UserMgr::getIpmiUsersCount() +@@ -781,49 +582,14 @@ size_t UserMgr::getIpmiUsersCount() + + bool UserMgr::isUserEnabled(const std::string &userName) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); +- std::array<char, 4096> buffer{}; +- struct spwd spwd; +- struct spwd *resultPtr = nullptr; +- int status = getspnam_r(userName.c_str(), &spwd, buffer.data(), +- buffer.max_size(), &resultPtr); +- if (!status && (&spwd == resultPtr)) +- { +- if (resultPtr->sp_expire >= 0) +- { +- return false; // user locked out +- } +- return true; +- } +- return false; // assume user is disabled for any error. ++ // Call The User Service to verify if user is enabled ++ return userSrvc->isUserEnabled(userName); + } + + std::vector<std::string> UserMgr::getUsersInGroup(const std::string &groupName) + { +- std::vector<std::string> usersInGroup; +- // Should be more than enough to get the pwd structure. +- std::array<char, 4096> buffer{}; +- struct group grp; +- struct group *resultPtr = nullptr; +- +- int status = getgrnam_r(groupName.c_str(), &grp, buffer.data(), +- buffer.max_size(), &resultPtr); +- +- if (!status && (&grp == resultPtr)) +- { +- for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem)) +- { +- usersInGroup.emplace_back(*(grp.gr_mem)); +- } +- } +- else +- { +- log<level::ERR>("Group not found", +- entry("GROUP=%s", groupName.c_str())); +- // Don't throw error, just return empty userList - fallback +- } +- return usersInGroup; ++ // Call The User Service to get the users that belong to a group ++ return std::move(userSrvc->getUsersInGroup(groupName)); + } + + DbusUserObj UserMgr::getPrivilegeMapperObject(void) +@@ -1052,11 +818,9 @@ void UserMgr::initUserObjects(void) + { + // All user management lock has to be based on /etc/shadow + phosphor::user::shadow::Lock lock(); +- std::vector<std::string> userNameList; +- std::vector<std::string> sshGrpUsersList; + UserSSHLists userSSHLists = getUserAndSshGrpList(); +- userNameList = std::move(userSSHLists.first); +- sshGrpUsersList = std::move(userSSHLists.second); ++ std::vector<std::string> userNameList = std::move(userSSHLists.first); ++ std::vector<std::string> sshGrpUsersList = std::move(userSSHLists.second); + + if (!userNameList.empty()) + { +@@ -1111,7 +875,8 @@ void UserMgr::initUserObjects(void) + } + } + +-UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path) : ++UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path, ++ UserService::ServiceType srvc) : + Ifaces(bus, path, true), bus(bus), path(path) + { + UserMgrIface::allPrivileges(privMgr); +@@ -1220,6 +985,7 @@ UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path) : + } + AccountPolicyIface::accountUnlockTimeout(value32); + } ++ userSrvc = std::make_unique<UserService>(srvc, groupsMgr, privMgr); + initUserObjects(); + + // emit the signal +diff --git a/user_mgr.hpp b/user_mgr.hpp +index b25e9f2..c24733b 100644 +--- a/user_mgr.hpp ++++ b/user_mgr.hpp +@@ -21,6 +21,7 @@ + #include <unordered_map> + #include <variant> + #include "users.hpp" ++#include "user_service.hpp" + + namespace phosphor + { +@@ -28,8 +29,6 @@ namespace user + { + + using UserMgrIface = sdbusplus::xyz::openbmc_project::User::server::Manager; +-using UserSSHLists = +- std::pair<std::vector<std::string>, std::vector<std::string>>; + using AccountPolicyIface = + sdbusplus::xyz::openbmc_project::User::server::AccountPolicy; + +@@ -76,8 +75,10 @@ class UserMgr : public Ifaces + * + * @param[in] bus - sdbusplus handler + * @param[in] path - D-Bus path ++ * @param[in] srvc - User service to be used + */ +- UserMgr(sdbusplus::bus::bus &bus, const char *path); ++ UserMgr(sdbusplus::bus::bus &bus, const char *path, ++ UserService::ServiceType srvc); + + /** @brief create user method. + * This method creates a new user as requested +@@ -186,6 +187,8 @@ class UserMgr : public Ifaces + /** @brief object path */ + const std::string path; + ++ /** @brief user service to be used */ ++ std::unique_ptr<UserService> userSrvc; + /** @brief privilege manager container */ + std::vector<std::string> privMgr = {"priv-admin", "priv-operator", + "priv-user", "priv-callback"}; +diff --git a/user_service.cpp b/user_service.cpp +new file mode 100644 +index 0000000..9bb602c +--- /dev/null ++++ b/user_service.cpp +@@ -0,0 +1,781 @@ ++/* ++// Copyright (c) 2018 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. ++*/ ++ ++#include <grp.h> ++#include <pwd.h> ++#include <numeric> ++#include <boost/process/child.hpp> ++#include <boost/process/io.hpp> ++#include <boost/algorithm/string/split.hpp> ++#include "shadowlock.hpp" ++#include "file.hpp" ++#include "user_service.hpp" ++ ++/* anonymous namespace for User Service interface implementations. ++// Each class inside this namespace implements a special service ++// to be used for the User Manager class. This can be extended to use ++// other user management services and it should be as simple as ++// adding a new class which inherits from phosphor::user::UserServiceInterface ++*/ ++ ++namespace ++{ ++ ++std::string getCSVFromVector(std::vector<std::string> vec) ++{ ++ switch (vec.size()) ++ { ++ case 0: ++ { ++ return ""; ++ } ++ break; ++ ++ case 1: ++ { ++ return std::string{vec[0]}; ++ } ++ break; ++ ++ default: ++ { ++ return std::accumulate( ++ std::next(vec.begin()), vec.end(), vec[0], ++ [](std::string a, std::string b) { return a + ',' + b; }); ++ } ++ } ++} ++ ++bool removeStringFromCSV(std::string &csvStr, const std::string &delStr) ++{ ++ std::string::size_type delStrPos = csvStr.find(delStr); ++ if (delStrPos != std::string::npos) ++ { ++ // need to also delete the comma char ++ if (delStrPos == 0) ++ { ++ csvStr.erase(delStrPos, delStr.size() + 1); ++ } ++ else ++ { ++ csvStr.erase(delStrPos - 1, delStr.size() + 1); ++ } ++ return true; ++ } ++ return false; ++} ++ ++class ShadowService : public phosphor::user::UserServiceInterface ++{ ++ public: ++ ShadowService() = default; ++ ++ ~ShadowService() = default; ++ ++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::vector<std::string> userList; ++ std::vector<std::string> sshUsersList; ++ ++ struct passwd pw, *pwp = nullptr; ++ std::array<char, 1024> buffer{}; ++ ++ phosphor::user::File passwd(passwdFileName, "r"); ++ if ((passwd)() == NULL) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error opening the passwd file"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ while (true) ++ { ++ auto r = fgetpwent_r((passwd)(), &pw, buffer.data(), ++ buffer.max_size(), &pwp); ++ if ((r != 0) || (pwp == NULL)) ++ { ++ // Any error, break the loop. ++ break; ++ } ++ // Add all users whose UID >= 1000 and < 65534 ++ // and special UID 0. ++ if ((pwp->pw_uid == 0) || ++ ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))) ++ { ++ std::string userName(pwp->pw_name); ++ userList.emplace_back(userName); ++ ++ // ssh doesn't have separate group. Check login shell entry to ++ // get all users list which are member of ssh group. ++ std::string loginShell(pwp->pw_shell); ++ if (loginShell == "/bin/sh") ++ { ++ sshUsersList.emplace_back(userName); ++ } ++ } ++ } ++ endpwent(); ++ return std::make_pair(std::move(userList), std::move(sshUsersList)); ++ } ++ ++ std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const override ++ { ++ std::vector<std::string> usersInGroup; ++ // Should be more than enough to get the pwd structure. ++ std::array<char, 4096> buffer{}; ++ struct group grp; ++ struct group *grpPtr = &grp; ++ struct group *resultPtr; ++ ++ int status = getgrnam_r(groupName.c_str(), grpPtr, buffer.data(), ++ buffer.max_size(), &resultPtr); ++ ++ if (!status && (grpPtr == resultPtr)) ++ { ++ for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem)) ++ { ++ usersInGroup.emplace_back(*(grp.gr_mem)); ++ } ++ } ++ else ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Group not found", ++ phosphor::logging::entry("GROUP=%s", groupName.c_str())); ++ // Don't throw error, just return empty usersInGroup - fallback ++ } ++ return usersInGroup; ++ } ++ ++ void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups.append(","); ++ } ++ groups.append(priv); ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(), ++ "-m", "-N", "-s", (sshRequested ? "/bin/sh" : "/bin/nologin"), ++ "-e", (enabled ? "" : "1970-01-02")); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create new user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void renameUser(const std::string &userName, ++ const std::string &newUserName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ try ++ { ++ std::string newHomeDir = "/home/" + newUserName; ++ phosphor::user::executeCmd("/usr/sbin/usermod", "-l", ++ newUserName.c_str(), userName.c_str(), ++ "-d", newHomeDir.c_str(), "-m"); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "User rename failed", ++ phosphor::logging::entry("USER_NAME=%s", userName.c_str())); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void deleteUser(const std::string &userName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/userdel", userName.c_str(), ++ "-r"); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "User delete failed", ++ phosphor::logging::entry("USER_NAME=%s", userName.c_str())); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same. ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(), ++ "-s", (sshRequested ? "/bin/sh" : "/bin/nologin")); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to modify user privilege / groups"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateUserStatus(const std::string &userName, ++ const bool &enabled) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/usermod", userName.c_str(), ++ "-e", (enabled ? "" : "1970-01-02")); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to modify user enabled state"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ bool isUserEnabled(const std::string &userName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ std::array<char, 4096> buffer{}; ++ struct spwd spwd; ++ struct spwd *resultPtr = nullptr; ++ int status = getspnam_r(userName.c_str(), &spwd, buffer.data(), ++ buffer.max_size(), &resultPtr); ++ if (!status && (&spwd == resultPtr)) ++ { ++ if (resultPtr->sp_expire >= 0) ++ { ++ return false; // user locked out ++ } ++ return true; ++ } ++ return false; // assume user is disabled for any error. ++ } ++ ++ std::vector<std::string> ++ getUserGroups(const std::string &userName) const override ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "ShadowService::getUserGroups not implemented!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ return std::vector<std::string>(); ++ } ++ ++ void createGroup(const std::string &groupName) const override ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "ShadowService::createGroup not implemented!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ private: ++ static constexpr const char *passwdFileName = "/etc/passwd"; ++}; ++ ++class SSSDService : public phosphor::user::UserServiceInterface ++{ ++ public: ++ SSSDService(const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++ { ++ ++ createGroup(lockedGrp); ++ for (const auto &g : groups) ++ { ++ createGroup(g); ++ } ++ for (const auto &p : privs) ++ { ++ createGroup(p); ++ } ++ } ++ ++ ~SSSDService() = default; ++ ++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override ++ { ++ std::vector<std::string> users; ++ std::vector<std::string> sshGroup; ++ std::vector<std::string> exeOutput; ++ ++ try ++ { ++ exeOutput = phosphor::user::executeCmd("/usr/bin/getent", "-s", ++ "sss", "passwd"); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get users information " ++ "from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ for (const auto &userLine : exeOutput) ++ { ++ std::vector<std::string> userInfo; ++ boost::algorithm::split(userInfo, userLine, ++ boost::algorithm::is_any_of(":")); ++ // At this point userInfo is a vector containing the passwd ++ // info for the user, so we know the correct positions: ++ // 0: User name. ++ // 1: Encrypted password. ++ // 2: User ID number (UID) ++ // 3: User's group ID number (GID) ++ // 4: Full name of the user (GECOS) ++ // 5: User home directory. ++ // 6: Login shell. ++ users.emplace_back(userInfo[0]); ++ ++ // ssh doesn't have separate group. Check login shell entry to ++ // get all users list which are member of ssh group. ++ if (userInfo[6] == "/bin/sh") ++ { ++ sshGroup.emplace_back(userInfo[0]); ++ } ++ } ++ ++ return std::make_pair(std::move(users), std::move(sshGroup)); ++ } ++ ++ std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const override ++ { ++ std::vector<std::string> userList; ++ std::vector<std::string> exeOutput; ++ ++ try ++ { ++ exeOutput = phosphor::user::executeCmd("/usr/sbin/sss_groupshow", ++ groupName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get group users from sssd service"); ++ // Don't throw error, just return empty usersInGroup - return ++ return userList; ++ } ++ // exeOutput should have 5 entries ++ // 0: Group ++ // 1: GID number ++ // 2: Member users ++ // 3: Is a member of ++ // 4: Member groups ++ exeOutput[2].erase( ++ exeOutput[2].begin(), ++ std::find(exeOutput[2].begin(), exeOutput[2].end(), ':')); ++ boost::algorithm::trim_left(exeOutput[2]); ++ boost::algorithm::split(userList, exeOutput[2], ++ boost::algorithm::is_any_of(",")); ++ return userList; ++ } ++ ++ void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const override ++ { ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/sss_useradd", "-m", "-G", groups.c_str(), "-s", ++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create new user in sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ // Sometimes the SSSD service needs some time to actually ++ // reflect the changes to the local DB to the NSS service, ++ // that is why we have this sleep here ... ++ std::this_thread::sleep_for(std::chrono::seconds(1)); ++ // update user status (locked/unlocked) ++ updateUserStatus(userName, enabled); ++ } ++ ++ void renameUser(const std::string &userName, ++ const std::string &newUserName) const override ++ { ++ std::vector<std::string> exeOutput; ++ // Local Domain for sssd doesn't have a rename feature ++ // so we need to first create a new user and then delete ++ // the old one. ++ // The only issue with this is that the password for the ++ // user will have to be reseted since it is a new user being created. ++ ++ // Get original user groups ++ std::vector<std::string> groups = getUserGroups(userName); ++ // Check if it has a "ssh" group by looking for the shell login ++ try ++ { ++ exeOutput = phosphor::user::executeCmd( ++ "/usr/bin/getent", "-s", "sss", "passwd", userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get information for user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ if (exeOutput[0].find("/bin/sh")) ++ { ++ groups.emplace_back(phosphor::user::grpSsh); ++ } ++ // Call create user with the new user names and previous groups ++ // Priv is already part of the groups so that can be empty. ++ createUser(newUserName, groups, "", isUserEnabled(userName)); ++ ++ // Now delete original user ++ deleteUser(userName); ++ } ++ ++ void deleteUser(const std::string &userName) const override ++ { ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_userdel", "-r", ++ userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to delete user from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const override ++ { ++ // local domain sssd do not allow to update all list of groups, ++ // so we will remove all groups first (except for the user one) ++ // and then all all the ones that were passed ++ std::string oldGroups = getCSVFromVector(getUserGroups(userName)); ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/sss_usermod", "-r", oldGroups.c_str(), "-a", ++ groups.c_str(), "-s", ++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to update user groups and " ++ "priv from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateUserStatus(const std::string &userName, ++ const bool &enabled) const override ++ { ++ std::string enabledStr; ++ std::string lockedStr; ++ if (isUserEnabled(userName) == enabled) ++ { ++ return; ++ } ++ if (enabled) ++ { ++ enabledStr = "-r"; ++ lockedStr = "-U"; ++ } ++ else ++ { ++ enabledStr = "-a"; ++ lockedStr = "-L"; ++ } ++ try ++ { ++ // We will add a special locked group to identify the users ++ // that have been locked out of the system. ++ // TODO: sss_usermod is not locking user accounts for the ++ // LOCAL domain, need to find the correct PAM configuration ++ // to actually lockout users for SSSD. ++ // As a workaround we are using the pam module pam_listfile.so ++ // to lockout all users that belong to the locked group. ++ phosphor::user::executeCmd("/usr/sbin/sss_usermod", ++ enabledStr.c_str(), lockedGrp.c_str(), ++ lockedStr.c_str(), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to update user status from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ bool isUserEnabled(const std::string &userName) const override ++ { ++ std::vector<std::string> userGrps = getUserGroups(userName); ++ return std::find(userGrps.begin(), userGrps.end(), lockedGrp) == ++ userGrps.end(); ++ } ++ ++ std::vector<std::string> ++ getUserGroups(const std::string &userName) const override ++ { ++ std::vector<std::string> exeOutput; ++ try ++ { ++ exeOutput = ++ phosphor::user::executeCmd("/usr/bin/groups", userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get groups for user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ std::vector<std::string> groups; ++ boost::algorithm::split(groups, exeOutput[0], ++ boost::algorithm::is_any_of(" ")); ++ // Delete group that equals user name if it exists ++ auto userNameGroup = std::find(groups.begin(), groups.end(), userName); ++ if (userNameGroup != groups.end()) ++ { ++ groups.erase(userNameGroup); ++ } ++ return groups; ++ } ++ ++ void createGroup(const std::string &groupName) const override ++ { ++ try ++ { ++ if (!groupExists(groupName)) ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_groupadd", ++ groupName.c_str()); ++ } ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create group"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ private: ++ static const std::string lockedGrp; ++ ++ bool groupExists(const std::string &groupName) const ++ { ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_groupshow", ++ groupName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ return false; ++ } ++ return true; ++ } ++}; ++ ++const std::string SSSDService::lockedGrp = "sssd_locked"; ++} // anonymous namespace ++ ++namespace phosphor ++{ ++namespace user ++{ ++ ++UserService::UserService(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++{ ++ setServiceImpl(srvcType, groups, privs); ++} ++ ++void UserService::updateServiceType(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++{ ++ usrSrvcImpl.reset(); ++ setServiceImpl(srvcType, groups, privs); ++} ++ ++void UserService::setServiceImpl(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++{ ++ switch (srvcType) ++ { ++ case ServiceType::shadow: ++ { ++ usrSrvcImpl = std::make_unique<ShadowService>(); ++ } ++ break; ++ ++ case ServiceType::sssd: ++ { ++ usrSrvcImpl = std::make_unique<SSSDService>(groups, privs); ++ } ++ break; ++ ++ case ServiceType::none: ++ default: ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Invalid service type initialization!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ break; ++ } ++} ++ ++UserService::~UserService() ++{ ++} ++ ++phosphor::user::UserSSHLists UserService::getUserAndSshGrpList() const ++{ ++ return usrSrvcImpl->getUserAndSshGrpList(); ++} ++ ++std::vector<std::string> ++ UserService::getUsersInGroup(const std::string &groupName) const ++{ ++ return usrSrvcImpl->getUsersInGroup(groupName); ++} ++ ++void UserService::createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const ++{ ++ usrSrvcImpl->createUser(userName, groupNames, priv, enabled); ++} ++ ++void UserService::renameUser(const std::string &userName, ++ const std::string &newUserName) const ++{ ++ usrSrvcImpl->renameUser(userName, newUserName); ++} ++ ++void UserService::deleteUser(const std::string &userName) const ++{ ++ usrSrvcImpl->deleteUser(userName); ++} ++ ++void UserService::updateGroupsAndPriv( ++ const std::string &userName, const std::vector<std::string> &groupNames, ++ const std::string &priv) const ++{ ++ usrSrvcImpl->updateGroupsAndPriv(userName, groupNames, priv); ++} ++ ++void UserService::updateUserStatus(const std::string &userName, ++ const bool &enabled) const ++{ ++ usrSrvcImpl->updateUserStatus(userName, enabled); ++} ++ ++bool UserService::isUserEnabled(const std::string &userName) const ++{ ++ return usrSrvcImpl->isUserEnabled(userName); ++} ++ ++std::vector<std::string> ++ UserService::getUserGroups(const std::string &userName) const ++{ ++ return usrSrvcImpl->getUserGroups(userName); ++} ++ ++} // namespace user ++} // namespace phosphor +diff --git a/user_service.hpp b/user_service.hpp +new file mode 100644 +index 0000000..97a049b +--- /dev/null ++++ b/user_service.hpp +@@ -0,0 +1,233 @@ ++/* ++// Copyright (c) 2018 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 <xyz/openbmc_project/Common/error.hpp> ++#include <xyz/openbmc_project/User/Common/error.hpp> ++#include <phosphor-logging/log.hpp> ++#include <phosphor-logging/elog.hpp> ++#include <boost/process/child.hpp> ++#include <boost/process/io.hpp> ++ ++namespace phosphor ++{ ++namespace user ++{ ++ ++using UserSSHLists = ++ std::pair<std::vector<std::string>, std::vector<std::string>>; ++using InternalFailure = ++ sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; ++using InsufficientPermission = ++ sdbusplus::xyz::openbmc_project::Common::Error::InsufficientPermission; ++ ++const std::string grpSsh = "ssh"; ++ ++template <typename... ArgTypes> ++std::vector<std::string> executeCmd(const char *path, ArgTypes &&... tArgs) ++{ ++ std::vector<std::string> stdOutput; ++ boost::process::ipstream stdOutStream; ++ boost::process::child execProg(path, const_cast<char *>(tArgs)..., ++ boost::process::std_out > stdOutStream); ++ std::string stdOutLine; ++ ++ while (stdOutStream && std::getline(stdOutStream, stdOutLine) && ++ !stdOutLine.empty()) ++ { ++ stdOutput.emplace_back(stdOutLine); ++ } ++ ++ execProg.wait(); ++ ++ int retCode = execProg.exit_code(); ++ if (retCode) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Command execution failed", ++ phosphor::logging::entry("PATH=%d", path), ++ phosphor::logging::entry("RETURN_CODE:%d", retCode)); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ return stdOutput; ++} ++ ++/** @class UserServiceInterface ++ * @brief Interface class for methods provided by the implemmentations ++ * of the user service. Provides the same methods as the UserService ++ * class. ++ */ ++class UserServiceInterface ++{ ++ public: ++ UserServiceInterface() = default; ++ virtual ~UserServiceInterface() = default; ++ virtual UserSSHLists getUserAndSshGrpList() const = 0; ++ virtual std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const = 0; ++ virtual void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, ++ const bool &enabled) const = 0; ++ virtual void renameUser(const std::string &userName, ++ const std::string &newUserName) const = 0; ++ virtual void deleteUser(const std::string &userName) const = 0; ++ virtual void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const = 0; ++ virtual void updateUserStatus(const std::string &userName, ++ const bool &enabled) const = 0; ++ virtual bool isUserEnabled(const std::string &userName) const = 0; ++ virtual std::vector<std::string> ++ getUserGroups(const std::string &userName) const = 0; ++ virtual void createGroup(const std::string &groupName) const = 0; ++}; ++ ++/** @class UserService ++ * @brief Responsible for managing the user service for the user manager. ++ * This service is the one responsible to actually change the user information ++ * of the application. It can support sevaral services, currently the ones ++ * supported are: ++ * ++ * 1) Shadow: Which uses the /etc/shadow file for updating the users ++ * 2) SSSD: Which uses the sssd service for a LOCAL domain only right now. ++ */ ++class UserService ++{ ++ public: ++ UserService() = delete; ++ UserService(const UserService &) = delete; ++ UserService &operator=(const UserService &) = delete; ++ UserService(UserService &&) = delete; ++ UserService &operator=(UserService &&) = delete; ++ ++ // Service Types implemented. None is used to validate. ++ enum class ServiceType ++ { ++ none, ++ shadow, ++ sssd ++ }; ++ ++ UserService(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs); ++ ~UserService(); ++ ++ /** @brief update the current Service type of the instance. ++ * This function is used to update in real time the service ++ * being used for the user management without restarting the ++ * whole service. ++ * ++ * @param[in] srvcType ++ * @param[in] groups ++ * @param[in] privs ++ */ ++ void updateServiceType(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs); ++ ++ /** @brief get user list and SSH group members list ++ * This method gets the list of users from the service. ++ * If the userlist reference is empty, all the users will be added ++ * and DBus notified about them. If the list is not empty, the function ++ * will only update list adding the missing ones to it. It will not remove ++ * any extra users on the list that are not part of the service! ++ * ++ */ ++ UserSSHLists getUserAndSshGrpList() const; ++ ++ /** @brief Get users in group. ++ * This method creates a new user as requested ++ * ++ * @param[in] groupName - Name of the group which has to be queried ++ */ ++ std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const; ++ ++ /** @brief create user method. ++ * This method creates a new user as requested ++ * ++ * @param[in] userName - Name of the user which has to be created ++ * @param[in] groupNames - Group names list, to which user has to be added. ++ * @param[in] priv - Privilege of the user. ++ * @param[in] enabled - State of the user enabled / disabled. ++ */ ++ void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const; ++ ++ /** @brief rename user method. ++ * This method renames the user as requested ++ * ++ * @param[in] userName - current name of the user ++ * @param[in] userName - user name to which it has to be renamed. ++ */ ++ void renameUser(const std::string &userName, ++ const std::string &newUserName) const; ++ ++ /** @brief delete user method. ++ * This method deletes the user as requested ++ * ++ * @param[in] userName - Name of the user which has to be deleted ++ */ ++ void deleteUser(const std::string &userName) const; ++ ++ /** @brief Updates user Groups and Privilege. ++ * ++ * @param[in] userName - Name of the user which has to be modified ++ * @param[in] groupNames - Group names list for user. ++ * @param[in] priv - Privilege of the user. ++ */ ++ void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const; ++ ++ /** @brief Updates user status ++ * If enabled = false: User will be disabled ++ * If enabled = true : User will be enabled ++ * ++ * @param[in] userName - Name of the user ++ * @param[in] enabled - Status of the user: enabled / disabled? ++ */ ++ void updateUserStatus(const std::string &userName, ++ const bool &enabled) const; ++ ++ /** @brief Verify if user is enabled or not ++ * If enabled returns true ++ * If not enabled returns false ++ * ++ * @param[in] userName - Name of the user ++ */ ++ bool isUserEnabled(const std::string &userName) const; ++ ++ /** @brief Get the list of groups a user belongs to ++ * ++ * @param[in] userName - Name of the user ++ */ ++ std::vector<std::string> getUserGroups(const std::string &userName) const; ++ ++ private: ++ // User service implementation. ++ void setServiceImpl(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs); ++ std::unique_ptr<UserServiceInterface> usrSrvcImpl; ++}; ++ ++} // namespace user ++} // namespace phosphor +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend new file mode 100644 index 000000000..327be045d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend @@ -0,0 +1,9 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +#SRC_URI = "git://github.com/openbmc/phosphor-user-manager;nobranch=1" +SRCREV = "1af1223304dbf7aaecd5f238227abee95cce8b39" + + +SRC_URI += " \ + file://0005-Added-suport-for-multiple-user-manager-services.patch \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb new file mode 100644 index 000000000..9f7be9434 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb @@ -0,0 +1,21 @@ +SUMMARY = "Virtual Media Service" +DESCRIPTION = "Virtual Media Service" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "30110fe5b18999bddc5721dc5611f542f6feeabd" + +S = "${WORKDIR}/git/virtual-media/" +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.VirtualMedia.service" + +DEPENDS = "udev boost nlohmann-json systemd sdbusplus" + +inherit cmake systemd + +EXTRA_OECMAKE += "-DYOCTO_DEPENDENCIES=ON" + +FULL_OPTIMIZATION = "-Os -pipe -flto -fno-rtti" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb new file mode 100644 index 000000000..ebd795e83 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb @@ -0,0 +1,35 @@ + +SUMMARY = "FRB2 timer service" +DESCRIPTION = "The FRB2 timer service will monitor the mailbox register 0\ +and start a watchdog for FRB2 if the data is 1(BIOS will write this value)" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://frb2-watchdog.cpp \ + " +PV = "0.1" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +S = "${WORKDIR}" + +inherit cmake +inherit pkgconfig pythonnative + +DEPENDS += " \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + boost \ + " + +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + phosphor-dbus-interfaces \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format new file mode 100644 index 000000000..dd2770837 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format @@ -0,0 +1,98 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt new file mode 100644 index 000000000..bd5567d31 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required (VERSION 3.5 FATAL_ERROR) +project (frb2-watchdog CXX) +set (CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD_REQUIRED ON) +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti") + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +# boost support +find_package (Boost REQUIRED) +# pkg_check_modules(Boost boost REQUIRED) +include_directories (${Boost_INCLUDE_DIRS}) +add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY) +add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED) +add_definitions (-DBOOST_ALL_NO_LIB) +add_definitions (-DBOOST_NO_RTTI) +add_definitions (-DBOOST_NO_TYPEID) +add_definitions (-DBOOST_ASIO_DISABLE_THREADS) + +# import libsystemd +find_package (PkgConfig REQUIRED) +pkg_check_modules (SYSTEMD libsystemd REQUIRED) +include_directories (${SYSTEMD_INCLUDE_DIRS}) +link_directories (${SYSTEMD_LIBRARY_DIRS}) + +# import sdbusplus +find_package (PkgConfig REQUIRED) +pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED) +include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS}) +link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS}) + +# import phosphor-logging +find_package (PkgConfig REQUIRED) +pkg_check_modules (LOGGING phosphor-logging REQUIRED) +include_directories (${LOGGING_INCLUDE_DIRS}) +link_directories (${LOGGING_LIBRARY_DIRS}) + +# import phosphor-dbus-interfaces +find_package (PkgConfig REQUIRED) +pkg_check_modules (DBUSINTERFACE phosphor-dbus-interfaces REQUIRED) +include_directories (${DBUSINTERFACE_INCLUDE_DIRS}) +link_directories (${DBUSINTERFACE_LIBRARY_DIRS}) + +add_executable (frb2-watchdog frb2-watchdog.cpp) + +target_link_libraries (${PROJECT_NAME} systemd) +target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES} + phosphor_logging) +install (TARGETS frb2-watchdog DESTINATION bin) diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json new file mode 100644 index 000000000..583c255a3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json @@ -0,0 +1,12 @@ +{ + "enum_char": ".", + "line_ending": "unix", + "bullet_char": "*", + "max_subargs_per_line": 99, + "command_case": "lower", + "tab_size": 4, + "line_width": 80, + "separate_fn_name_with_space": true, + "dangle_parens": true, + "separate_ctrl_name_with_space": true +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp new file mode 100644 index 000000000..5356e95db --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp @@ -0,0 +1,258 @@ +/* Copyright 2018 Intel + * + * 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. + */ + +#include <fcntl.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <boost/container/flat_set.hpp> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <iostream> +#include <memory> +#include <optional> +#include <phosphor-logging/log.hpp> +#include <sdbusplus/asio/object_server.hpp> +#include <sdbusplus/bus.hpp> +#include <sdbusplus/bus/match.hpp> +#include <sdbusplus/message.hpp> +#include <sdbusplus/timer.hpp> +#include <vector> +#include <xyz/openbmc_project/State/Watchdog/server.hpp> + +void handleResponse(const boost::system::error_code &err, + std::size_t bytes_transferred); + +static int mailboxDevFd = -1; + +static boost::asio::io_service io; +static auto conn = std::make_shared<sdbusplus::asio::connection>(io); +boost::asio::ip::tcp::socket mailBoxDevSocket(io); +boost::asio::deadline_timer pollTimer(io); +boost::asio::posix::stream_descriptor inputDevice(io); + +// mailbox registre data[0:0] for FRB2 enable bit +boost::asio::streambuf readBuf(1); +std::string dataRead; + +// FRB2 watchdog timeout is 6 minutes +static constexpr unsigned int frb2TimerIntervalMs = 360 * 1000; + +// mailbox device polling time interval is 2 seconds +static constexpr unsigned int pollMs = 2000; + +static constexpr unsigned int frb2Started = 1; +static constexpr unsigned int frb2Stopped = 0; + +// FRB2 status +static uint8_t frb2Status = frb2Stopped; + +static constexpr const char *mailboxDevName = "/dev/aspeed-mbox"; + +static constexpr const char frb2Bus[] = "xyz.openbmc_project.FRB2"; +static constexpr const char frb2Obj[] = "/xyz/openbmc_project/FRB2"; +static constexpr const char frb2Intf[] = "xyz.openbmc_project.FRB2"; + +static constexpr char powerBus[] = "xyz.openbmc_project.Chassis.Control.Power"; +static constexpr char powerPath[] = + "/xyz/openbmc_project/Chassis/Control/Power0"; +static constexpr char powerIntf[] = "xyz.openbmc_project.Chassis.Control.Power"; + +static constexpr char wdBus[] = "xyz.openbmc_project.Watchdog"; +static constexpr char wdPath[] = "/xyz/openbmc_project/watchdog/host0"; +static constexpr char wdIntf[] = "xyz.openbmc_project.State.Watchdog"; +static constexpr char propIntf[] = "org.freedesktop.DBus.Properties"; + +typedef boost::asio::buffers_iterator<boost::asio::const_buffers_1> iterator; + +// check if FRB2 bit is 0x1 +std::pair<iterator, bool> matchFRB2(iterator begin, iterator end) +{ + unsigned char ch = 0; + iterator i = begin; + + while (i != end) + { + ch = static_cast<unsigned char>(*i); + if (ch & 0x1) + { + return std::make_pair(i, true); + } + i++; + } + + return std::make_pair(i, false); +} + +static void startRead() +{ + boost::asio::async_read_until(inputDevice, readBuf, matchFRB2, + [&](const boost::system::error_code &ec, + std::size_t bytes_transferred) { + handleResponse(ec, bytes_transferred); + }); +} + +template <typename T> void setProperty(const std::string &key, const T &val) +{ + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "setProperty", phosphor::logging::entry("KEY=%s", key.c_str())); + + try + { + conn->async_method_call( + [](const boost::system::error_code &err) { + if (err) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "async_method_call error!", + phosphor::logging::entry( + "ERROR=%s", + boost::system::system_error(err).what())); + } + }, + wdBus, wdPath, propIntf, "Set", wdIntf, key, + sdbusplus::message::variant_ns::variant<T>(val)); + } + catch (sdbusplus::exception::SdBusError &e) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Dbus error!", phosphor::logging::entry("ERROR=%s", e.what())); + } +} +void handleResponse(const boost::system::error_code &err, + std::size_t bytes_transferred) +{ + std::istream responseStream(&readBuf); + std::string response; + int n = 0; + uint64_t interval = frb2TimerIntervalMs; + + std::getline(responseStream, response); + responseStream.clear(); + + if (err == boost::system::errc::bad_file_descriptor) + { + + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "bad file descriptor"); + return; // we're being destroyed + } + + if (!err) + { + // FRB2 is set by BIOS + if (frb2Stopped == frb2Status) + { + // start FRB2 watchdog + frb2Status = frb2Started; + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "FRB2 enable, start FRB2 watchdog"); + setProperty( + "ExpireAction", + std::string( + "xyz.openbmc_project.State.Watchdog.Action.HardReset")); + setProperty("Interval", interval); + setProperty("TimeRemaining", interval); + setProperty("Initialized", true); + setProperty("Enabled", true); + } + } + else if (err == boost::asio::error::misc_errors::not_found) + { + // FRB2 is clear, stop FRB2 watchdog if it is started + if (frb2Started == frb2Status) + { + frb2Status = frb2Stopped; + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "FRB2 is unset, stop FRB2 watchdog"); + setProperty("Enabled", false); + } + } + else + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "handleResponse error!", + phosphor::logging::entry("ERROR=%s", + boost::system::system_error(err).what())); + } + + pollTimer.expires_from_now(boost::posix_time::milliseconds(pollMs)); + pollTimer.async_wait( + [](const boost::system::error_code &ec) { startRead(); }); +} + +int main(int argc, char **argv) +{ + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "Monitor FRB2 signal"); + + sdbusplus::bus::match_t biosPostSignal( + static_cast<sdbusplus::bus::bus &>(*conn), + sdbusplus::bus::match::rules::type::signal() + + sdbusplus::bus::match::rules::member("PostCompleted") + + sdbusplus::bus::match::rules::path(powerPath) + + sdbusplus::bus::match::rules::interface(powerIntf), + [](sdbusplus::message::message &msg) { + uint8_t value = 0; + ssize_t rc = 0; + phosphor::logging::log<phosphor::logging::level::INFO>( + "BIOS post completed signal"); + // stop FRB2 and clean mailbox + value = 0; + rc = ::pwrite(mailboxDevFd, &value, 1, 0); + if (rc != 1) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "mailbox write error!"); + } + setProperty("Enabled", false); + frb2Status = frb2Stopped; + return; + }); + + conn->request_name(frb2Bus); + + auto server = sdbusplus::asio::object_server(conn); + + std::shared_ptr<sdbusplus::asio::dbus_interface> frb2Iface = + server.add_interface(frb2Obj, frb2Intf); + + frb2Iface->register_property("frb2Status", frb2Status); + + frb2Iface->initialize(); + + mailboxDevFd = ::open(mailboxDevName, O_RDWR | O_CLOEXEC); + if (mailboxDevFd < 0) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "mailbox device open fail!"); + return -1; + } + + inputDevice.assign(mailboxDevFd); + + startRead(); + + io.run(); + + ::close(mailboxDevFd); + + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch new file mode 100644 index 000000000..736431e9e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch @@ -0,0 +1,316 @@ +From a65701eabcf205203d6363d54730a6a497c0e6fc Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Mon, 17 Jun 2019 12:00:58 -0700 +Subject: [PATCH] Customize phosphor-watchdog for Intel platforms + +This patch adds various changes to phosphor-watchdog that are +required for compatibility with Intel platforms. + + 1. Add Redfish messages for watchdog timeout and pre-interrupt + 2. Use dbus properties for power control insted of service files + 3. Use host status to enable/disable watchdog + 4. Set preTimeoutInterruptOccurFlag + +Signed-off-by: James Feist <james.feist@linux.intel.com> +Signed-off-by: Ren Yu <yux.ren@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + watchdog.cpp | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- + watchdog.hpp | 23 ++++++- + 2 files changed, 206 insertions(+), 10 deletions(-) + +diff --git a/watchdog.cpp b/watchdog.cpp +index 9090760..68b4246 100644 +--- a/watchdog.cpp ++++ b/watchdog.cpp +@@ -1,11 +1,14 @@ + #include "watchdog.hpp" + ++#include <systemd/sd-journal.h> ++ + #include <algorithm> + #include <chrono> + #include <phosphor-logging/elog.hpp> + #include <phosphor-logging/log.hpp> + #include <sdbusplus/exception.hpp> + #include <xyz/openbmc_project/Common/error.hpp> ++#include <xyz/openbmc_project/State/Host/server.hpp> + + namespace phosphor + { +@@ -18,10 +21,69 @@ using namespace phosphor::logging; + using sdbusplus::exception::SdBusError; + using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; + +-// systemd service to kick start a target. +-constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; +-constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1"; +-constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; ++const static constexpr char* currentHostState = "CurrentHostState"; ++const static constexpr char* hostStatusOff = ++ "xyz.openbmc_project.State.Host.HostState.Off"; ++ ++const static constexpr char* actionDescription = " due to Watchdog timeout"; ++const static constexpr char* hardResetDescription = "Hard Reset - System reset"; ++const static constexpr char* powerOffDescription = ++ "Power Down - System power down"; ++const static constexpr char* powerCycleDescription = ++ "Power Cycle - System power cycle"; ++const static constexpr char* timerExpiredDescription = "Timer expired"; ++ ++const static constexpr char* preInterruptActionNone = ++ "xyz.openbmc_project.State.Watchdog.PreTimeoutInterruptAction.None"; ++ ++const static constexpr char* preInterruptDescriptionSMI = "SMI"; ++const static constexpr char* preInterruptDescriptionNMI = "NMI"; ++const static constexpr char* preInterruptDescriptionMI = "Messaging Interrupt"; ++ ++const static constexpr char* reservedDescription = "Reserved"; ++ ++const static constexpr char* timerUseDescriptionBIOSFRB2 = "BIOS FRB2"; ++const static constexpr char* timerUseDescriptionBIOSPOST = "BIOS/POST"; ++const static constexpr char* timerUseDescriptionOSLoad = "OSLoad"; ++const static constexpr char* timerUseDescriptionSMSOS = "SMS/OS"; ++const static constexpr char* timerUseDescriptionOEM = "OEM"; ++ ++namespace restart ++{ ++static constexpr const char* busName = ++ "xyz.openbmc_project.Control.Host.RestartCause"; ++static constexpr const char* path = ++ "/xyz/openbmc_project/control/host0/restart_cause"; ++static constexpr const char* interface = ++ "xyz.openbmc_project.Control.Host.RestartCause"; ++static constexpr const char* property = "RequestedRestartCause"; ++} // namespace restart ++ ++// chassis state manager service ++namespace chassis ++{ ++static constexpr const char* busName = "xyz.openbmc_project.State.Chassis"; ++static constexpr const char* path = "/xyz/openbmc_project/state/chassis0"; ++static constexpr const char* interface = "xyz.openbmc_project.State.Chassis"; ++static constexpr const char* request = "RequestedPowerTransition"; ++} // namespace chassis ++ ++void Watchdog::powerStateChangedHandler( ++ const std::map<std::string, std::variant<std::string>>& props) ++{ ++ const auto iter = props.find(currentHostState); ++ if (iter != props.end()) ++ { ++ const std::string* powerState = std::get_if<std::string>(&iter->second); ++ if (powerState && (*powerState == hostStatusOff)) ++ { ++ if (timerEnabled()) ++ { ++ enabled(false); ++ } ++ } ++ } ++} + + void Watchdog::resetTimeRemaining(bool enableWatchdog) + { +@@ -102,13 +164,102 @@ uint64_t Watchdog::interval(uint64_t value) + // Optional callback function on timer expiration + void Watchdog::timeOutHandler() + { ++ PreTimeoutInterruptAction preTimeoutInterruptAction = preTimeoutInterrupt(); ++ std::string preInterruptActionMessageArgs{}; ++ + Action action = expireAction(); ++ std::string actionMessageArgs{}; ++ ++ expiredTimerUse(currentTimerUse()); ++ ++ TimerUse timeUser = expiredTimerUse(); ++ std::string timeUserMessage{}; ++ + if (!this->enabled()) + { + action = fallback->action; + } + +- expiredTimerUse(currentTimerUse()); ++ switch (timeUser) ++ { ++ case Watchdog::TimerUse::BIOSFRB2: ++ timeUserMessage = timerUseDescriptionBIOSFRB2; ++ break; ++ case Watchdog::TimerUse::BIOSPOST: ++ timeUserMessage = timerUseDescriptionBIOSPOST; ++ break; ++ case Watchdog::TimerUse::OSLoad: ++ timeUserMessage = timerUseDescriptionOSLoad; ++ break; ++ case Watchdog::TimerUse::SMSOS: ++ timeUserMessage = timerUseDescriptionSMSOS; ++ break; ++ case Watchdog::TimerUse::OEM: ++ timeUserMessage = timerUseDescriptionOEM; ++ break; ++ default: ++ timeUserMessage = reservedDescription; ++ break; ++ } ++ ++ switch (action) ++ { ++ case Watchdog::Action::HardReset: ++ actionMessageArgs = std::string(hardResetDescription) + ++ std::string(actionDescription); ++ break; ++ case Watchdog::Action::PowerOff: ++ actionMessageArgs = std::string(powerOffDescription) + ++ std::string(actionDescription); ++ break; ++ case Watchdog::Action::PowerCycle: ++ actionMessageArgs = std::string(powerCycleDescription) + ++ std::string(actionDescription); ++ break; ++ case Watchdog::Action::None: ++ actionMessageArgs = timerExpiredDescription; ++ break; ++ default: ++ actionMessageArgs = reservedDescription; ++ break; ++ } ++ ++ // Log into redfish event log ++ sd_journal_send("MESSAGE=IPMIWatchdog: Timed out ACTION=%s", ++ convertForMessage(action).c_str(), "PRIORITY=%i", LOG_INFO, ++ "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.IPMIWatchdog", ++ "REDFISH_MESSAGE_ARGS=%s. timer use: %s", ++ actionMessageArgs.c_str(), timeUserMessage.c_str(), NULL); ++ ++ switch (preTimeoutInterruptAction) ++ { ++ case Watchdog::PreTimeoutInterruptAction::SMI: ++ preInterruptActionMessageArgs = preInterruptDescriptionSMI; ++ break; ++ case Watchdog::PreTimeoutInterruptAction::NMI: ++ preInterruptActionMessageArgs = preInterruptDescriptionNMI; ++ break; ++ case Watchdog::PreTimeoutInterruptAction::MI: ++ preInterruptActionMessageArgs = preInterruptDescriptionMI; ++ break; ++ default: ++ preInterruptActionMessageArgs = reservedDescription; ++ break; ++ } ++ ++ if (preInterruptActionNone != convertForMessage(preTimeoutInterruptAction)) ++ { ++ preTimeoutInterruptOccurFlag(true); ++ ++ sd_journal_send("MESSAGE=IPMIWatchdog: Pre Timed out Interrupt=%s", ++ convertForMessage(preTimeoutInterruptAction).c_str(), ++ "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", ++ "OpenBMC.0.1.IPMIWatchdog", ++ "REDFISH_MESSAGE_ARGS=Timer interrupt - %s due to " ++ "Watchdog timeout. timer use: %s", ++ preInterruptActionMessageArgs.c_str(), ++ timeUserMessage.c_str(), NULL); ++ } + + auto target = actionTargetMap.find(action); + if (target == actionTargetMap.end()) +@@ -128,10 +279,11 @@ void Watchdog::timeOutHandler() + + try + { +- auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT, +- SYSTEMD_INTERFACE, "StartUnit"); +- method.append(target->second); +- method.append("replace"); ++ auto method = ++ bus.new_method_call(chassis::busName, chassis::path, ++ "org.freedesktop.DBus.Properties", "Set"); ++ method.append(chassis::interface, chassis::request, ++ std::variant<std::string>(target->second)); + + bus.call_noreply(method); + } +@@ -142,6 +294,29 @@ void Watchdog::timeOutHandler() + entry("ERROR=%s", e.what())); + commit<InternalFailure>(); + } ++ ++ // set restart cause for watchdog HardReset & PowerCycle actions ++ if ((action == Watchdog::Action::HardReset) || ++ (action == Watchdog::Action::PowerCycle)) ++ { ++ try ++ { ++ auto method = bus.new_method_call( ++ restart::busName, restart::path, ++ "org.freedesktop.DBus.Properties", "Set"); ++ method.append( ++ restart::interface, restart::property, ++ std::variant<std::string>("xyz.openbmc_project.State.Host." ++ "RestartCause.WatchdogTimer")); ++ bus.call(method); ++ } ++ catch (sdbusplus::exception_t& e) ++ { ++ log<level::ERR>("Failed to set HostRestartCause property", ++ entry("ERROR=%s", e.what())); ++ commit<InternalFailure>(); ++ } ++ } + } + + tryFallbackOrDisable(); +diff --git a/watchdog.hpp b/watchdog.hpp +index 7de9bb3..b004b7a 100644 +--- a/watchdog.hpp ++++ b/watchdog.hpp +@@ -68,7 +68,18 @@ class Watchdog : public WatchdogInherits + WatchdogInherits(bus, objPath), + bus(bus), actionTargetMap(std::move(actionTargetMap)), + fallback(std::move(fallback)), minInterval(minInterval), +- timer(event, std::bind(&Watchdog::timeOutHandler, this)) ++ timer(event, std::bind(&Watchdog::timeOutHandler, this)), ++ powerStateChangedSignal( ++ bus, ++ sdbusplus::bus::match::rules::propertiesChanged( ++ "/xyz/openbmc_project/state/host0", ++ "xyz.openbmc_project.State.Host"), ++ [this](sdbusplus::message::message& msg) { ++ std::string objectName; ++ std::map<std::string, std::variant<std::string>> props; ++ msg.read(objectName, props); ++ powerStateChangedHandler(props); ++ }) + { + // We set the watchdog interval with the default value. + interval(interval()); +@@ -77,6 +88,12 @@ class Watchdog : public WatchdogInherits + tryFallbackOrDisable(); + } + ++ /** @brief Disable watchdog when power status change meet ++ * the specific requirement ++ */ ++ void powerStateChangedHandler( ++ const std::map<std::string, std::variant<std::string>>& props); ++ + /** @brief Resets the TimeRemaining to the configured Interval + * Optionally enables the watchdog. + * +@@ -165,6 +182,10 @@ class Watchdog : public WatchdogInherits + /** @brief Contained timer object */ + sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer; + ++ /** @brief Optional Callback handler when power status change meet ++ * the specific requirement */ ++ sdbusplus::bus::match_t powerStateChangedSignal; ++ + /** @brief Optional Callback handler on timer expirartion */ + void timeOutHandler(); + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service new file mode 100644 index 000000000..5ef1a4179 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service @@ -0,0 +1,16 @@ +[Unit] +Description=Phosphor Watchdog + +[Service] +ExecStart=/usr/bin/env phosphor-watchdog --continue --service=xyz.openbmc_project.Watchdog \ + --path=/xyz/openbmc_project/watchdog/host0 \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.HardReset=xyz.openbmc_project.State.Chassis.Transition.Reset \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerOff=xyz.openbmc_project.State.Chassis.Transition.Off \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerCycle=xyz.openbmc_project.State.Chassis.Transition.PowerCycle + +SyslogIdentifier=phosphor-watchdog +BusName =xyz.openbmc_project.Watchdog +Type=dbus + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend new file mode 100644 index 000000000..f0b8e8f23 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend @@ -0,0 +1,9 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +SRCREV = "c35135d32f9cb84b62de7b72eee3a2e87b4b3d4d" +SRC_URI += "file://0001-Customize-phosphor-watchdog-for-Intel-platforms.patch \ + " + +# Remove the override to keep service running after DC cycle +SYSTEMD_OVERRIDE_${PN}_remove = "poweron.conf:phosphor-watchdog@poweron.service.d/poweron.conf" +SYSTEMD_SERVICE_${PN} = "phosphor-watchdog.service" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb new file mode 100644 index 000000000..45c2c5364 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb @@ -0,0 +1,24 @@ +SUMMARY = "System watchdog" +DESCRIPTION = "BMC hardware watchdog service that is used to reset BMC \ + when unrecoverable events occurs" + +inherit allarch +inherit obmc-phosphor-systemd + +RDEPENDS_${PN} = "bash" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SYSTEMD_SERVICE_${PN} += "system-watchdog.service" +SYSTEMD_ENVIRONMENT_FILE_${PN} += "obmc/system-watchdog/system-watchdog.conf" + +SYSTEMD_SERVICE_${PN} += "watchdog-reset.service" +SYSTEMD_SERVICE_${PN} += "watchdog-clear-failures.service" +SYSTEMD_SERVICE_${PN} += "watchdog-clear-failures.timer" +SRC_URI += "file://watchdog-reset.sh" + +do_install_append(){ + install -d ${D}${bindir} + install -m 0755 ${WORKDIR}/watchdog-reset.sh ${D}${bindir} +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf new file mode 100644 index 000000000..defe830a1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf @@ -0,0 +1,3 @@ +TIMEOUT=60 +INTERVAL=10 +DEVICE=/dev/watchdog1 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service new file mode 100644 index 000000000..1564fda20 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service @@ -0,0 +1,11 @@ +[Unit] +Description=BMC Hardware Watchdog Daemon + +[Service] +EnvironmentFile=/etc/default/obmc/system-watchdog/system-watchdog.conf +ExecStart=/sbin/watchdog -T ${{TIMEOUT}} -t ${{INTERVAL}} -F ${{DEVICE}} +KillSignal=SIGKILL + +[Install] +WantedBy=basic.target + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.service new file mode 100644 index 000000000..801f4ed27 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.service @@ -0,0 +1,10 @@ +[Unit] +Description=Reset BMC Hardware Watchdog Failure Count + +[Service] +ExecStart=busctl call xyz.openbmc_project.U_Boot.Environment.Manager \ + /xyz/openbmc_project/u_boot/environment/mgr \ + xyz.openbmc_project.U_Boot.Environment.Manager \ + Write ss bootfailures 0 +Type=oneshot + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.timer b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.timer new file mode 100644 index 000000000..1abac4326 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.timer @@ -0,0 +1,8 @@ +[Unit] +Description=Starts the clear watchdog serivce after 30 minutes + +[Timer] +OnBootSec=30min + +[Install] +WantedBy=timers.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.service new file mode 100644 index 000000000..6a5ffb4ba --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.service @@ -0,0 +1,7 @@ +[Unit] +Description=Reset BMC Using Hardware Watchdog + +[Service] +ExecStart=/usr/bin/watchdog-reset.sh +Type=oneshot + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.sh new file mode 100644 index 000000000..b3afd73d3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +if /sbin/fw_printenv bootfailures -n | grep -q 3; then + exit 0 # passed boot limit, user started again on purpose +fi + +echo "Watchdog Failure Limit Reached, Failed Processes:" > /dev/kmsg +systemctl --failed --no-pager | grep failed > /dev/kmsg +echo "Log as follows:" > /dev/kmsg +journalctl -r -n 100 | while read line; do echo $line > /dev/kmsg; done + +systemctl stop system-watchdog.service +/sbin/watchdog -T 0 -F /dev/watchdog1 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend new file mode 100644 index 000000000..7133892e9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend @@ -0,0 +1,2 @@ +SRC_URI = "git://git@github.com/Intel-BMC/phosphor-webui;protocol=ssh;branch=intel" +SRCREV = "2e0bc44e0c5552395f10e95f66a0874f14403ceb" |