nvidia-oem: Implement GetRedfishServiceUUID

This command is used by BIOS before creating SMBIOS record
type 42. BIOS gets USBDescription information from BMC.

Note:
The implementation in this PR is for
RedfishServiceUUID.
The support for other device descriptors will be added in
upcoming PRs.

Design Document for RHI:
[1] https://gerrit.openbmc.org/c/openbmc/docs/+/79327

Redfish Host Interface specification:
[2] https://www.dmtf.org/sites/default/files/standards/documents/DSP0270_1.3.0.pdf

Tested:
Tested on gb200nvl-obmc platform:
root@gb200nvl-obmc:~# ipmitool raw 0x3c 0x34
 1b 78 70 31 20 74 e1 4e 98 13 6b 22 a7 34 7a d0

[3] root@gb200nvl-obmc:~# find / -type f -name "bmcweb_persistent_data.json" 2>/dev/null
/home/root/bmcweb_persistent_data.json
[4] /run/initramfs/rw/cow/home/root/bmcweb_persistent_data.json

Change-Id: Ibfd1b1aa654ad4f523362ca973fd2c6c6b0f18c3
Signed-off-by: Prithvi Pai <ppai@nvidia.com>
diff --git a/oem/nvidia/bootstrap-credentials-oem-cmds.cpp b/oem/nvidia/bootstrap-credentials-oem-cmds.cpp
index 0a40c65..b7d1bec 100644
--- a/oem/nvidia/bootstrap-credentials-oem-cmds.cpp
+++ b/oem/nvidia/bootstrap-credentials-oem-cmds.cpp
@@ -9,9 +9,12 @@
 #include <ipmid/api.hpp>
 #include <ipmid/types.hpp>
 #include <ipmid/utils.hpp>
+#include <nlohmann/json.hpp>
 #include <phosphor-logging/lg2.hpp>
 
+#include <array>
 #include <cstdint>
+#include <fstream>
 
 void registerBootstrapCredentialsOemCommands() __attribute__((constructor));
 
@@ -111,6 +114,75 @@
     return ipmi::responseSuccess(static_cast<uint8_t>(chNum));
 }
 
+bool getRfUuid(std::string& rfUuid)
+{
+    constexpr const char* bmcwebPersistentDataFile =
+        "/home/root/bmcweb_persistent_data.json";
+    std::ifstream f(bmcwebPersistentDataFile);
+    if (!f.is_open())
+    {
+        lg2::error("Failed to open {FILE}", "FILE", bmcwebPersistentDataFile);
+        return false;
+    }
+    auto data = nlohmann::json::parse(f, nullptr, false);
+    if (data.is_discarded())
+    {
+        lg2::error("Failed to parse {FILE}", "FILE", bmcwebPersistentDataFile);
+        return false;
+    }
+
+    if (auto it = data.find("system_uuid"); it != data.end() && it->is_string())
+    {
+        rfUuid = *it;
+        return true;
+    }
+
+    lg2::error("system_uuid missing in {FILE}", "FILE",
+               bmcwebPersistentDataFile);
+    return false;
+}
+
+ipmi::RspType<std::vector<uint8_t>> ipmiGetRedfishServiceUUID()
+{
+    std::string rfUuid;
+    bool ret = getRfUuid(rfUuid);
+    if (!ret)
+    {
+        lg2::error(
+            "ipmiGetRedfishServiceUUID: Error reading Redfish Service UUID File.");
+        return ipmi::responseResponseError();
+    }
+
+    // As per Redfish Host Interface Spec v1.3.0
+    // The Redfish UUID is 16byte and should be represented as below:
+    // Ex: {00112233-4455-6677-8899-AABBCCDDEEFF}
+    // 0x33 0x22 0x11 0x00 0x55 0x44 0x77 0x66 0x88 0x99 0xAA 0xBB 0xCC 0xDD
+    // 0xEE 0xFF
+
+    std::vector<uint8_t> resBuf;
+    std::vector<std::string> groups = ipmi::split(rfUuid, '-');
+
+    for (size_t i = 0; i < groups.size(); ++i)
+    {
+        auto group = groups[i];
+        if (i < 3)
+        {
+            std::reverse(group.begin(), group.end());
+        }
+
+        for (size_t j = 0; j < group.size(); j += 2)
+        {
+            if (i < 3)
+            {
+                std::swap(group[j], group[j + 1]);
+            }
+            resBuf.push_back(static_cast<uint8_t>(
+                std::stoi(group.substr(j, 2), nullptr, 16)));
+        }
+    }
+    return ipmi::responseSuccess(resBuf);
+}
+
 } // namespace ipmi
 
 void registerBootstrapCredentialsOemCommands()
@@ -134,4 +206,9 @@
         ipmi::prioOemBase, ipmi::groupNvidia,
         ipmi::bootstrap_credentials_oem::cmdGetIpmiChannelRfHi,
         ipmi::Privilege::Admin, ipmi::ipmiGetIpmiChannelRfHi);
+
+    ipmi::registerHandler(
+        ipmi::prioOemBase, ipmi::groupNvidia,
+        ipmi::bootstrap_credentials_oem::cmdGetRedfishServiceUUID,
+        ipmi::Privilege::Admin, ipmi::ipmiGetRedfishServiceUUID);
 }