Support Clear Message Flags command

This is common IPMI command, but Ampere doesn't support all features in
this command. So we implement this command in Ampere OEM repository.
Ampere's Altra platform only supports clear watchdog pre-timeout interrupt flag.

Signed-off-by: Dung Cao <dung@os.amperecomputing.com>
Change-Id: Ib2996258ac45e71c2d2ae67358d6fc2ba771578d
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..e8be967
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,104 @@
+cmake_minimum_required (VERSION 3.5 FATAL_ERROR)
+
+cmake_policy (SET CMP0054 NEW)
+
+option (YOCTO "Use YOCTO depedencies system" OFF)
+include (ExternalProject)
+set (CMAKE_CXX_STANDARD 17)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+set (CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
+
+option (USING_ENTITY_MANAGER_DECORATORS
+        "Enable using EM decorators to map FRUs to entity IDs" ON)
+
+set (
+    CMAKE_CXX_FLAGS
+    "${CMAKE_CXX_FLAGS} \
+    -Werror \
+    -Wtype-limits \
+    -Wnull-dereference \
+"
+)
+
+project (ampere-ipmi-oem CXX)
+
+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)
+add_definitions (-DBOOST_COROUTINES_NO_DEPRECATION_WARNING)
+add_definitions (-Wno-psabi)
+
+if (NOT YOCTO) # headers that can't be built without yocto
+    include_directories (SYSTEM non-yocto)
+
+    configure_file (CMakeLists.txt.in 3rdparty/CMakeLists.txt)
+    execute_process (COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
+                     WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/3rdparty)
+    execute_process (COMMAND ${CMAKE_COMMAND} --build .
+                     WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/3rdparty)
+
+    set (CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}/prefix ${CMAKE_PREFIX_PATH})
+    include_directories (SYSTEM ${CMAKE_BINARY_DIR}/prefix/include)
+    link_directories (${CMAKE_BINARY_DIR}/prefix/lib)
+
+    include_directories (SYSTEM ${CMAKE_BINARY_DIR}/sdbusplus-src)
+    link_directories (${CMAKE_BINARY_DIR}/sdbusplus-src/.libs)
+    include_directories (SYSTEM ${CMAKE_BINARY_DIR}/phosphor-logging-src)
+    link_directories (${CMAKE_BINARY_DIR}/phosphor-logging-src/.libs)
+    include_directories (SYSTEM ${CMAKE_BINARY_DIR}/phosphor-ipmi-host/include)
+    include_directories (SYSTEM ${CMAKE_BINARY_DIR}/ipmid/user_channel)
+    include_directories (SYSTEM ${CMAKE_BINARY_DIR}) # link_directories  (${CMAK
+                                                     # E_BINARY_DIR}/sdbusplus-
+                                                     # src/.libs)
+endif ()
+
+if (YOCTO)
+    find_package (PkgConfig REQUIRED)
+    pkg_check_modules (LOGGING phosphor-logging REQUIRED)
+    include_directories (SYSTEM ${LOGGING_INCLUDE_DIRS})
+    link_directories (${LOGGING_LIBRARY_DIRS})
+
+    pkg_check_modules (LIBIPMID libipmid REQUIRED)
+    include_directories (SYSTEM ${LIBIPMID_INCLUDE_DIRS})
+    link_directories (${LIBIPMID_LIBRARY_DIRS})
+
+endif ()
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+#
+# import OpenSSL (crypto)
+find_package (OpenSSL REQUIRED)
+include_directories (SYSTEM ${OPENSSL_INCLUDE_DIR})
+
+include_directories (SYSTEM ${CMAKE_BINARY_DIR})
+
+add_library (zampoemcmds
+             SHARED
+             src/bridgingcommands.cpp)
+
+set_target_properties (zampoemcmds PROPERTIES VERSION "0.1.0")
+set_target_properties (zampoemcmds PROPERTIES SOVERSION "0")
+target_link_libraries (zampoemcmds stdc++fs)
+target_link_libraries (zampoemcmds ipmid)
+target_link_libraries (zampoemcmds sdbusplus)
+target_link_libraries (zampoemcmds phosphor_logging)
+target_link_libraries (zampoemcmds -luserlayer)
+target_link_libraries (zampoemcmds -lchannellayer)
+target_link_libraries (zampoemcmds ${OPENSSL_CRYPTO_LIBRARY})
+target_link_libraries (zampoemcmds gpiodcxx)
+
+install (TARGETS zampoemcmds DESTINATION lib/ipmid-providers)
+
+target_compile_definitions (
+    zampoemcmds PRIVATE
+    $<$<BOOL:${INTEL_PFR_ENABLED}>: -DINTEL_PFR_ENABLED>
+    $<$<BOOL:${BMC_VALIDATION_UNSECURE_FEATURE}>:
+    -DBMC_VALIDATION_UNSECURE_FEATURE>
+    $<$<BOOL:${MDR_V1_SUPPORT}>: -DMDR_V1_SUPPORT>
+    $<$<BOOL:${USING_ENTITY_MANAGER_DECORATORS}>:
+    -DUSING_ENTITY_MANAGER_DECORATORS>
+)
diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in
new file mode 100644
index 0000000..f50f74d
--- /dev/null
+++ b/CMakeLists.txt.in
@@ -0,0 +1,31 @@
+cmake_minimum_required (VERSION 3.5)
+
+include (ExternalProject)
+
+file (MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/prefix)
+file (MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/prefix/include)
+
+# requires apt install autoconf-archive and autoconf
+
+externalproject_add (
+    host-ipmid PREFIX ${CMAKE_BINARY_DIR}/phosphor-host-ipmid GIT_REPOSITORY
+    https://github.com/openbmc/phosphor-host-ipmid SOURCE_DIR
+    ${CMAKE_BINARY_DIR}/phosphor-ipmi-host-src BINARY_DIR
+    ${CMAKE_BINARY_DIR}/phosphor-ipmi-host-build CONFIGURE_COMMAND cd
+    ${CMAKE_BINARY_DIR}/phosphor-ipmi-host-src && export
+    PYTHONPATH=${CMAKE_BINARY_DIR}/prefix/lib/python2.7/site-packages:$ENV{PYTHONPATH}
+    && export PATH=${CMAKE_BINARY_DIR}/prefix/bin:$ENV{PATH} && export
+    PKG_CONFIG_PATH=${CMAKE_BINARY_DIR}/prefix/lib/pkgconfig && ./bootstrap.sh
+    && ./configure --prefix=${CMAKE_BINARY_DIR}/prefix
+    CPPFLAGS=-I${CMAKE_BINARY_DIR}/prefix/include/
+    CXXFLAGS=-Wno-error=unused-result LDFLAGS=-L${CMAKE_BINARY_DIR}/prefix/lib/
+    BUILD_COMMAND cd ${CMAKE_BINARY_DIR}/phosphor-ipmi-host-src && export
+    PYTHONPATH=${CMAKE_BINARY_DIR}/prefix/lib/python2.7/site-packages:$ENV{PYTHONPATH}
+    && export PATH=${CMAKE_BINARY_DIR}/prefix/bin:$ENV{PATH} && export
+    PKG_CONFIG_PATH=${CMAKE_BINARY_DIR}/prefix/lib/pkgconfig && make -j
+    verbose=1 INSTALL_COMMAND cd ${CMAKE_BINARY_DIR}/phosphor-ipmi-host-src &&
+    make install && mkdir -p
+    "${CMAKE_BINARY_DIR}/prefix/include/ipmid" && cp include/ipmid/api.h
+    "${CMAKE_BINARY_DIR}/prefix/include/ipmid/" LOG_DOWNLOAD ON
+)
+
diff --git a/cmake-format.json b/cmake-format.json
new file mode 100644
index 0000000..4a68fb7
--- /dev/null
+++ b/cmake-format.json
@@ -0,0 +1,13 @@
+{
+  "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
+}
+
diff --git a/include/bridgingcommands.hpp b/include/bridgingcommands.hpp
new file mode 100644
index 0000000..0a247bd
--- /dev/null
+++ b/include/bridgingcommands.hpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018-2021 Ampere Computing LLC
+ *
+ * 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 <ipmid/api.hpp>
+#include <sdbusplus/message.hpp>
+#include <sdbusplus/server/interface.hpp>
+
+struct IpmbResponse
+{
+    uint8_t address;
+    uint8_t netFn;
+    uint8_t rqLun;
+    uint8_t rsSA;
+    uint8_t seq;
+    uint8_t rsLun;
+    uint8_t cmd;
+    uint8_t completionCode;
+    std::vector<uint8_t> data;
+
+    IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA,
+                 uint8_t seq, uint8_t rsLun, uint8_t cmd,
+                 uint8_t completionCode, std::vector<uint8_t>& inputData);
+
+    void ipmbToi2cConstruct(uint8_t* buffer, size_t* bufferLength);
+};
+
+/** @class Bridging
+ *
+ *  @brief Implement commands to support IPMI bridging.
+ */
+class Bridging
+{
+  public:
+    Bridging() = default;
+    std::size_t getResponseQueueSize();
+
+    void clearResponseQueue();
+    void insertMessageInQueue(IpmbResponse msg);
+    IpmbResponse getMessageFromQueue();
+    void eraseMessageFromQueue();
+
+  private:
+    std::vector<IpmbResponse> responseQueue;
+};
diff --git a/src/bridgingcommands.cpp b/src/bridgingcommands.cpp
new file mode 100644
index 0000000..13fda3f
--- /dev/null
+++ b/src/bridgingcommands.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2018-2021 Ampere Computing LLC
+ *
+ * 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 <bridgingcommands.hpp>
+#include <ipmid/api.hpp>
+#include <ipmid/utils.hpp>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/bus/match.hpp>
+#include <sdbusplus/message.hpp>
+#include <user_channel/channel_layer.hpp>
+
+#include <bitset>
+#include <cstring>
+#include <vector>
+
+static Bridging bridging;
+static bool eventMessageBufferFlag = false;
+
+void Bridging::clearResponseQueue()
+{
+    responseQueue.clear();
+}
+
+void Bridging::insertMessageInQueue(IpmbResponse msg)
+{
+    responseQueue.insert(responseQueue.end(), std::move(msg));
+}
+
+void Bridging::eraseMessageFromQueue()
+{
+    responseQueue.erase(responseQueue.begin());
+}
+
+IpmbResponse Bridging::getMessageFromQueue()
+{
+    return responseQueue.front();
+}
+
+std::size_t Bridging::getResponseQueueSize()
+{
+    return responseQueue.size();
+}
+
+/** @brief This command is used to flush unread data from the receive
+ *   message queue
+ *  @param receiveMessage  - clear receive message queue
+ *  @param eventMsgBufFull - clear event message buffer full
+ *  @param reserved2       - reserved bit
+ *  @param watchdogTimeout - clear watchdog pre-timeout interrupt flag
+ *  @param reserved1       - reserved bit
+ *  @param oem0            - clear OEM 0 data
+ *  @param oem1            - clear OEM 1 data
+ *  @param oem2            - clear OEM 2 data
+
+ *  @return IPMI completion code on success
+ */
+ipmi::RspType<> ipmiAppClearMessageFlags(ipmi::Context::ptr ctx,
+                                         bool receiveMessage,
+                                         bool eventMsgBufFull, bool reserved2,
+                                         bool watchdogTimeout, bool reserved1,
+                                         bool oem0, bool oem1, bool oem2)
+{
+    ipmi::ChannelInfo chInfo;
+
+    try
+    {
+        getChannelInfo(ctx->channel, chInfo);
+    }
+    catch (sdbusplus::exception_t& e)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "ipmiAppClearMessageFlags: Failed to get Channel Info",
+            phosphor::logging::entry("MSG: %s", e.description()));
+        return ipmi::responseUnspecifiedError();
+    }
+    if (chInfo.mediumType !=
+        static_cast<uint8_t>(ipmi::EChannelMediumType::smbusV20))
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "ipmiAppClearMessageFlags: Error - supported only in SSIF "
+            "interface");
+        return ipmi::responseCommandNotAvailable();
+    }
+
+    if (reserved1 || reserved2)
+    {
+        return ipmi::responseInvalidFieldRequest();
+    }
+
+    if (receiveMessage)
+    {
+        bridging.clearResponseQueue();
+    }
+
+    if (eventMessageBufferFlag != true && eventMsgBufFull == true)
+    {
+        eventMessageBufferFlag = true;
+    }
+
+    // As phosphor-watchdog has not supported PreTimeoutInterruptFlags yet,
+    // so do nothing on clear watchdog pre-timeout interrupt flags.
+
+    return ipmi::responseSuccess();
+}
+
+void registerBridingFunctions() __attribute__((constructor));
+void registerBridingFunctions()
+{
+    // <Clear Message Flags Command>
+    ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
+                          ipmi::app::cmdClearMessageFlags,
+                          ipmi::Privilege::User, ipmiAppClearMessageFlags);
+
+    return;
+}