Attention Handler base logic

Added base logic for the attention handler application (attn) as a starting point for further refinement. Attn will handle SBE vital, system checkstop and special attention events. These events will be handled through a combination local logic and external hardware and software interfaces.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I074fb86474761bf694644c71d93ede9c45673b79
diff --git a/attn/attn_handler.cpp b/attn/attn_handler.cpp
new file mode 100644
index 0000000..cac1f84
--- /dev/null
+++ b/attn/attn_handler.cpp
@@ -0,0 +1,207 @@
+#include <libpdbg.h>
+
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/bus.hpp>
+
+#include <iomanip>
+
+using namespace phosphor::logging;
+
+namespace attn
+{
+
+/**
+ * @brief Handle SBE vital attention
+ *
+ * @return 0 = success
+ */
+int handleVital();
+
+/**
+ * @brief Handle checkstop attention
+ *
+ * @return 0 = success
+ */
+int handleCheckstop();
+
+/**
+ * @brief Handle special attention
+ *
+ * @return 0 = success
+ */
+int handleSpecial();
+
+/**
+ * @brief Notify Cronus over dbus interface
+ *
+ * @param i_proc   Processor number with Special attention
+ * @param i_core   Core number with special attention
+ * @param i_thread Thread number with special attention
+ */
+void notifyCronus(uint32_t i_proc, uint32_t i_core, uint32_t i_thread);
+
+/**
+ * @brief The main attention handler logic
+ */
+void attnHandler()
+{
+    uint32_t isr_val, isr_mask;
+    uint32_t proc;
+
+    // loop through processors looking for active attentions
+    pdbg_target* target;
+    pdbg_for_each_class_target("fsi", target)
+    {
+        if (PDBG_TARGET_ENABLED == pdbg_target_probe(target))
+        {
+            proc = pdbg_target_index(target); // get processor number
+
+            std::stringstream ss; // log message stream
+            ss << "[ATTN] checking processor " << proc << std::endl;
+            log<level::INFO>(ss.str().c_str());
+
+            // get active attentions on processor
+            if (0 != fsi_read(target, 0x1007, &isr_val))
+            {
+                std::stringstream ss; // log message stream
+                ss << "[ATTN] Error! cfam read 0x1007 FAILED" << std::endl;
+                log<level::INFO>(ss.str().c_str());
+            }
+            else
+            {
+                std::stringstream ss; // log message stream
+                ss << "[ATTN] cfam 0x1007 = 0x";
+                ss << std::hex << std::setw(8) << std::setfill('0');
+                ss << isr_val << std::endl;
+                log<level::INFO>(ss.str().c_str());
+
+                // get interrupt enabled special attentions mask
+                if (0 != fsi_read(target, 0x100d, &isr_mask))
+                {
+                    std::stringstream ss; // log message stream
+                    ss << "[ATTN] Error! cfam read 0x100d FAILED" << std::endl;
+                    log<level::INFO>(ss.str().c_str());
+                }
+                else
+                {
+                    std::stringstream ss; // log message stream
+                    ss << "[ATTN] cfam 0x100d = 0x";
+                    ss << std::hex << std::setw(8) << std::setfill('0');
+                    ss << isr_mask << std::endl;
+                    log<level::INFO>(ss.str().c_str());
+
+                    // bit 0 on "left": bit 30 = SBE vital attention
+                    if (isr_val & isr_mask & 0x00000002)
+                    {
+                        handleVital();
+                    }
+
+                    // bit 0 on "left": bit 1 = checkstop
+                    if (isr_val & isr_mask & 0x40000000)
+                    {
+                        handleCheckstop();
+                    }
+
+                    // bit 0 on "left": bit 2 = special attention
+                    if (isr_val & isr_mask & 0x20000000)
+                    {
+                        handleSpecial();
+                    }
+                } // cfam 0x100d valid
+            }     // cfam 0x1007 valid
+        }         // fsi target enabled
+    }             // next processor
+
+    return; // checked all processors
+}
+
+/**
+ * @brief Handle SBE vital attention
+ */
+int handleVital()
+{
+    int rc = 1; // vital attention handling not yet supported
+
+    std::stringstream ss; // log message stream
+    ss << "[ATTN] vital" << std::endl;
+    log<level::INFO>(ss.str().c_str());
+
+    if (0 != rc)
+    {
+        std::stringstream ss; // log message stream
+        ss << "[ATTN] vital NOT handled" << std::endl;
+        log<level::INFO>(ss.str().c_str());
+    }
+
+    return rc;
+}
+
+/**
+ * @brief Handle checkstop attention
+ */
+int handleCheckstop()
+{
+    int rc = 1; // checkstop handling not yet supported
+
+    std::stringstream ss; // log message stream
+    ss << "[ATTN] checkstop" << std::endl;
+    log<level::INFO>(ss.str().c_str());
+
+    if (0 != rc)
+    {
+        std::stringstream ss; // log message stream
+        ss << "[ATTN] checkstop NOT handled" << std::endl;
+        log<level::INFO>(ss.str().c_str());
+    }
+
+    // TODO recoverable errors?
+
+    return rc;
+}
+
+/**
+ * @brief Handle special attention
+ */
+int handleSpecial()
+{
+    int rc = 0; // special attention handling supported
+
+    std::stringstream ss; // log message stream
+
+    ss << "[ATTN] special" << std::endl;
+
+    // Currently we are only handling Cronus breakpoints
+    ss << "[ATTN] breakpoint" << std::endl;
+    log<level::INFO>(ss.str().c_str());
+
+    // Cronus will determine proc, core and thread so just notify
+    notifyCronus(0, 0, 0); // proc-0, core-0, thread-0
+
+    // TODO recoverable errors?
+
+    return rc;
+}
+
+/**
+ * @brief Notify Cronus over dbus interface
+ */
+void notifyCronus(uint32_t i_proc, uint32_t i_core, uint32_t i_thread)
+{
+    std::stringstream ss; // log message stream
+
+    // log status info
+    ss << "[ATTN] notify ";
+    ss << i_proc << ", " << i_core << ", " << i_thread << std::endl;
+    log<level::INFO>(ss.str().c_str());
+
+    // notify Cronus over dbus
+    auto bus = sdbusplus::bus::new_system();
+    auto msg = bus.new_signal("/", "org.openbmc.cronus", "Brkpt");
+
+    std::array<uint32_t, 3> params{i_proc, i_core, i_thread};
+    msg.append(params);
+
+    msg.signal_send();
+}
+
+} // namespace attn
diff --git a/attn/attn_handler.hpp b/attn/attn_handler.hpp
new file mode 100644
index 0000000..2be6b07
--- /dev/null
+++ b/attn/attn_handler.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+/**
+ * @brief The main attention handler logic
+ *
+ * Check each processor for active attentions of type SBE Vital (vital),
+ * System Checkstop (checkstop) and Special Attention (special) and handle
+ * each as follows:
+ *
+ * checkstop: TBD
+ * vital:     TBD
+ * special:   Determine if the special attention is a Breakpoint (BP),
+ *            Terminate Immediately (TI) or CoreCodeToSp (corecode). For each
+ *            special attention type, do the following:
+ *
+ *            BP:          Notify Cronus
+ *            TI:          TBD
+ *            Corecode:    TBD
+ *            Recoverable: TBD
+ */
+void attnHandler();
diff --git a/attn/attn_main.cpp b/attn/attn_main.cpp
new file mode 100644
index 0000000..dda1fc8
--- /dev/null
+++ b/attn/attn_main.cpp
@@ -0,0 +1,21 @@
+#include <libpdbg.h>
+
+#include <attn_handler.hpp>
+
+/**
+ * @brief Attention handler application main()
+ *
+ * This is the main interface to the Attention handler application, it will
+ * initialize the libgpd targets and start a gpio mointor.
+ *
+ * @return 0 = success
+ */
+int main()
+{
+    int rc = 0; // return code
+
+    // initialize pdbg targets
+    pdbg_targets_init(nullptr);
+
+    return rc;
+}
diff --git a/attn/meson.build b/attn/meson.build
new file mode 100644
index 0000000..d215067
--- /dev/null
+++ b/attn/meson.build
@@ -0,0 +1,18 @@
+# needed to find external libraries not registered with package manager
+cmplr = meson.get_compiler('cpp')
+
+# dependency to link dbus support
+sdbusplus = dependency('sdbusplus', version : '>=1.0')
+
+# dependency to link libpdbg support
+libpdbg = cmplr.find_library('pdbg')
+
+# libpdbg requires linking with "whole-archive" option
+whole_archive = declare_dependency(link_args : '-Wl,--whole-archive')
+no_whole_archive = declare_dependency(link_args : '-Wl,--no-whole-archive')
+
+executable('attn_handler',
+           'attn_main.cpp', 'attn_handler.cpp',
+           dependencies : [whole_archive, libpdbg,
+                           no_whole_archive, sdbusplus],
+           install : true)
diff --git a/meson.build b/meson.build
index b28887d..9dc0caa 100644
--- a/meson.build
+++ b/meson.build
@@ -7,6 +7,7 @@
         ])
 
 subdir('src')
+subdir('attn')
 
 build_tests = get_option('tests')