Enabled PFR image validation support for PFR ptfms.

Added support for validating the PFR image in ipmi firmware write
data command.

Tested:

Tested firmware update utility via KCS interface

Signed-off-by: Rajashekar Gade Reddy <raja.sekhar.reddy.gade@linux.intel.com>
Change-Id: I16d66af593dd2ab03759281d4cef8ba238c1d85a
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 546f726..218c5c6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -104,3 +104,8 @@
 target_link_libraries (zinteloemcmds ${OPENSSL_CRYPTO_LIBRARY})
 
 install (TARGETS zinteloemcmds DESTINATION lib/ipmid-providers)
+option (INTEL_PFR_ENABLED "Intel PFR Enabled" OFF)
+target_compile_definitions (
+    zinteloemcmds PRIVATE
+    $<$<BOOL:${INTEL_PFR_ENABLED}>: -DINTEL_PFR_ENABLED>
+)
diff --git a/src/firmware-update.cpp b/src/firmware-update.cpp
index 99402e8..4fdee8b 100644
--- a/src/firmware-update.cpp
+++ b/src/firmware-update.cpp
@@ -26,6 +26,13 @@
 #include <sdbusplus/timer.hpp>
 #include <sstream>
 
+#ifdef INTEL_PFR_ENABLED
+uint32_t imgLength = 0;
+uint32_t imgType = 0;
+bool block0Mapped = false;
+static constexpr uint32_t perBlock0MagicNum = 0xB6EAFD19;
+#endif
+
 static constexpr const char *secondaryFitImageStartAddr = "22480000";
 static uint8_t getActiveBootImage(void);
 static void register_netfn_firmware_functions() __attribute__((constructor));
@@ -846,6 +853,11 @@
             {
                 xfer_hash_check->clear();
             }
+#ifdef INTEL_PFR_ENABLED
+            imgLength = 0;
+            imgType = 0;
+            block0Mapped = false;
+#endif
             if (DEBUG)
                 std::cerr << "transfer start\n";
         }
@@ -1564,7 +1576,9 @@
     {
         return IPMI_CC_UNSPECIFIED_ERROR;
     }
-    if (out.tellp() > FIRMWARE_BUFFER_MAX_SIZE)
+
+    uint64_t fileDataLen = out.tellp();
+    if (fileDataLen > FIRMWARE_BUFFER_MAX_SIZE)
     {
         return IPMI_CC_INVALID_FIELD_REQUEST;
     }
@@ -1576,7 +1590,44 @@
         xfer_hash_check->hash({data, data + bytes_in});
     }
 
-    // Status code.
+#ifdef INTEL_PFR_ENABLED
+    /* PFR image block 0 - As defined in HAS */
+    struct PFRImageBlock0
+    {
+        uint32_t tag;
+        uint32_t pcLength;
+        uint32_t pcType;
+        uint32_t reserved1;
+        uint8_t hash256[32];
+        uint8_t hash384[48];
+        uint8_t reserved2[32];
+    } __attribute__((packed));
+
+    /* Get the PFR block 0 data and read the uploaded image
+     * information( Image type, length etc) */
+    if ((fileDataLen >= sizeof(PFRImageBlock0)) && (!block0Mapped))
+    {
+        struct PFRImageBlock0 block0Data = {0};
+
+        std::ifstream inFile(FIRMWARE_BUFFER_FILE,
+                             std::ios::binary | std::ios::in);
+        inFile.read(reinterpret_cast<char *>(&block0Data), sizeof(block0Data));
+        inFile.close();
+
+        uint32_t magicNum = block0Data.tag;
+
+        /* Validate the magic number */
+        if (magicNum != perBlock0MagicNum)
+        {
+            return IPMI_CC_INVALID_FIELD_REQUEST;
+        }
+        // Note:imgLength, imgType and block0Mapped are in global scope, as
+        // these are used in cascaded updates.
+        imgLength = block0Data.pcLength;
+        imgType = block0Data.pcType;
+        block0Mapped = true;
+    }
+#endif // end of INTEL_PFR_ENABLED
     return IPMI_CC_OK;
 }