Add Hostboot scratch registers to PEL

Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
Change-Id: I8f095b49ec204e6e33afc0ab300beeab5d3759a9
diff --git a/analyzer/create_pel.cpp b/analyzer/create_pel.cpp
index f1c245f..adc2264 100644
--- a/analyzer/create_pel.cpp
+++ b/analyzer/create_pel.cpp
@@ -25,9 +25,10 @@
 
 enum FfdcSubType_t : uint8_t
 {
-    FFDC_SIGNATURES    = 0x01,
-    FFDC_REGISTER_DUMP = 0x02,
-    FFDC_CALLOUT_FFDC  = 0x03,
+    FFDC_SIGNATURES      = 0x01,
+    FFDC_REGISTER_DUMP   = 0x02,
+    FFDC_CALLOUT_FFDC    = 0x03,
+    FFDC_HB_SCRATCH_REGS = 0x04,
 
     // For the callout section, the value of '0xCA' is required per the
     // phosphor-logging openpower-pel extention spec.
@@ -224,6 +225,57 @@
 
 //------------------------------------------------------------------------------
 
+void __captureHostbootScratchRegisters(
+    std::vector<util::FFDCFile>& io_userDataFiles)
+{
+    // Get the Hostboot scratch registers from the primary processor.
+
+    uint32_t cfamAddr  = 0x283C;
+    uint32_t cfamValue = 0;
+
+    uint64_t scomAddr  = 0x4602F489;
+    uint64_t scomValue = 0;
+
+    auto priProc = util::pdbg::getPrimaryProcessor();
+    if (nullptr == priProc)
+    {
+        trace::err("Unable to get primary processor");
+    }
+    else
+    {
+        if (0 != util::pdbg::getCfam(priProc, cfamAddr, cfamValue))
+        {
+            cfamValue = 0; // just in case
+        }
+
+        if (0 != util::pdbg::getScom(priProc, scomAddr, scomValue))
+        {
+            scomValue = 0; // just in case
+        }
+    }
+
+    // Create a new entry for this user data section.
+    io_userDataFiles.emplace_back(util::FFDCFormat::Custom,
+                                  FFDC_HB_SCRATCH_REGS, FFDC_VERSION1);
+
+    // Create a streamer for easy writing to the FFDC file.
+    auto path = io_userDataFiles.back().getPath();
+    util::BinFileWriter stream{path};
+
+    // Add the data (CFAM addr/val, then SCOM addr/val).
+    stream << cfamAddr << cfamValue << scomAddr << scomValue;
+
+    // If the stream failed for any reason, remove the FFDC file.
+    if (!stream.good())
+    {
+        trace::err("Unable to write register dump FFDC file: %s",
+                   path.string().c_str());
+        io_userDataFiles.pop_back();
+    }
+}
+
+//------------------------------------------------------------------------------
+
 std::string __getMessageRegistry(bool i_isCheckstop)
 {
     // For now, there are only two choices:
@@ -279,6 +331,9 @@
     // Add the list of callouts to the PEL.
     __addCalloutList(i_servData, userDataFiles);
 
+    // Add the Hostboot scratch register to the PEL.
+    __captureHostbootScratchRegisters(userDataFiles);
+
     // Add the callout FFDC to the PEL.
     __addCalloutFFDC(i_servData, userDataFiles);
 
diff --git a/util/pdbg.cpp b/util/pdbg.cpp
index fb36a8e..d4170a7 100644
--- a/util/pdbg.cpp
+++ b/util/pdbg.cpp
@@ -107,6 +107,27 @@
 
 //------------------------------------------------------------------------------
 
+int getScom(pdbg_target* i_trgt, uint64_t i_addr, uint64_t& o_val)
+{
+    // Only processor targets are supported.
+    // TODO: Will need to add OCMB support later.
+    assert(TYPE_PROC == getTrgtType(i_trgt));
+
+    auto pibTrgt = util::pdbg::getPibTrgt(i_trgt);
+
+    int rc = pib_read(pibTrgt, i_addr, &o_val);
+
+    if (0 != rc)
+    {
+        trace::err("pib_read failure: target=%s addr=0x%0" PRIx64,
+                   util::pdbg::getPath(pibTrgt), i_addr);
+    }
+
+    return rc;
+}
+
+//------------------------------------------------------------------------------
+
 int getCfam(pdbg_target* i_trgt, uint32_t i_addr, uint32_t& o_val)
 {
     // Only processor targets are supported.
@@ -118,7 +139,7 @@
 
     if (0 != rc)
     {
-        trace::err("fsi_read failure: trgt=%s addr=0x%08x",
+        trace::err("fsi_read failure: target=%s addr=0x%08x",
                    util::pdbg::getPath(fsiTrgt), i_addr);
     }
 
@@ -230,6 +251,16 @@
 
 //------------------------------------------------------------------------------
 
+pdbg_target* getPrimaryProcessor()
+{
+    // TODO: For at least P10, the primary processor (the one connected directly
+    //       to the BMC), will always be PROC 0. We will need to update this
+    //       later if we ever support an alternate primary processor.
+    return getTrgt("/proc0");
+}
+
+//------------------------------------------------------------------------------
+
 bool queryHardwareAnalysisSupported()
 {
     // Hardware analysis is only supported on P10 systems and up.
diff --git a/util/pdbg.hpp b/util/pdbg.hpp
index 2fabcf3..6c604ac 100644
--- a/util/pdbg.hpp
+++ b/util/pdbg.hpp
@@ -67,6 +67,16 @@
 pdbg_target* getFsiTrgt(pdbg_target* i_procTrgt);
 
 /**
+ * @brief  Reads a SCOM register.
+ * @param  i_trgt Given target.
+ * @param  i_addr Given address.
+ * @param  o_val  The returned value of the register.
+ * @return 0 if successful, non-0 otherwise.
+ * @note   Will assert the given target is a proc target.
+ */
+int getScom(pdbg_target* i_trgt, uint64_t i_addr, uint64_t& o_val);
+
+/**
  * @brief  Reads a CFAM FSI register.
  * @param  i_trgt Given target.
  * @param  i_addr Given address.
@@ -83,6 +93,11 @@
 void getActiveChips(std::vector<libhei::Chip>& o_chips);
 
 /**
+ * @return The primary processor (i.e. the processor connected to the BMC).
+ */
+pdbg_target* getPrimaryProcessor();
+
+/**
  * @return True, if hardware analysis is supported on this system. False,
  *         otherwise.
  * @note   Support for hardware analysis from the BMC started with P10 systems