Expose Processor PPIN property

Some Processors may support exposing a globally unique identifier in
addition to a serial number. Redfish supports this via
ProcessorId.ProtectedIdentificationNumber property. ("Protected"
indicates it may be a sensitive value due to tracking/privacy concerns -
Intel CPUs allow the customer to mask the PPIN so it can't be exposed.)

cpuinfoapp in smbios-mdr repo is currently implementing this interface.

Tested:
- New property is shown (only for cpus with valid PPIN)
- Passed Redfish Service Validator with no errors.

Signed-off-by: Jonathan Doman <jonathan.doman@intel.com>
Change-Id: I233931ac640338e8f50f37ba4cc7298c7a0db9bf
diff --git a/redfish-core/lib/processor.hpp b/redfish-core/lib/processor.hpp
index 07a83eb..8111717 100644
--- a/redfish-core/lib/processor.hpp
+++ b/redfish-core/lib/processor.hpp
@@ -651,6 +651,38 @@
 }
 
 /**
+ * Populate the unique identifier in a Processor resource by requesting data
+ * from the given D-Bus object.
+ *
+ * @param[in,out]   aResp       Async HTTP response.
+ * @param[in]       service     D-Bus service to query.
+ * @param[in]       objPath     D-Bus object to query.
+ */
+inline void getCpuUniqueId(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
+                           const std::string& service,
+                           const std::string& objectPath)
+{
+    BMCWEB_LOG_DEBUG << "Get CPU UniqueIdentifier";
+    crow::connections::systemBus->async_method_call(
+        [aResp](boost::system::error_code ec,
+                const std::variant<std::string>& property) {
+            const std::string* id = std::get_if<std::string>(&property);
+            if (ec || id == nullptr)
+            {
+                BMCWEB_LOG_ERROR << "Failed to read cpu unique id: " << ec;
+                messages::internalError(aResp->res);
+                return;
+            }
+            aResp->res
+                .jsonValue["ProcessorId"]["ProtectedIdentificationNumber"] =
+                *id;
+        },
+        service, objectPath, "org.freedesktop.DBus.Properties", "Get",
+        "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier",
+        "UniqueIdentifier");
+}
+
+/**
  * Find the D-Bus object representing the requested Processor, and call the
  * handler with the results. If matching object is not found, add 404 error to
  * response and don't call the handler.
@@ -721,14 +753,15 @@
         "/xyz/openbmc_project/object_mapper",
         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
         "/xyz/openbmc_project/inventory", 0,
-        std::array<const char*, 7>{
+        std::array<const char*, 8>{
             "xyz.openbmc_project.Common.UUID",
             "xyz.openbmc_project.Inventory.Decorator.Asset",
             "xyz.openbmc_project.Inventory.Decorator.Revision",
             "xyz.openbmc_project.Inventory.Item.Cpu",
             "xyz.openbmc_project.Inventory.Decorator.LocationCode",
             "xyz.openbmc_project.Inventory.Item.Accelerator",
-            "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"});
+            "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
+            "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier"});
 }
 
 inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
@@ -774,6 +807,11 @@
             {
                 getProcessorUUID(aResp, serviceName, objectPath);
             }
+            else if (interface == "xyz.openbmc_project.Inventory."
+                                  "Decorator.UniqueIdentifier")
+            {
+                getCpuUniqueId(aResp, serviceName, objectPath);
+            }
         }
     }
 }