FruDevice: Parsing Multirecord UUID
Extend entity-manager's FruDevice to read UUID from FRU EEPROM
and update to dbus at MULTIRECORD_UUID.
The Record Type ID is: 0x03 (Management Access Record)
Sub-record Type is: 0x07 (System Unique ID)
Tested:
1. Get the UUID value:
busctl get-property xyz.openbmc_project.FruDevice \
/xyz/openbmc_project/FruDevice/MB \
xyz.openbmc_project.FruDevice \
MULTIRECORD_UUID
s "e74d8ad8-ed3b-11ec-ace5-34025a7001de"
Signed-off-by: Hieu Huynh <hieuh@os.amperecomputing.com>
Change-Id: I61fbea9a5d90b8d857d49444775f80761386845b
diff --git a/src/fru_utils.cpp b/src/fru_utils.cpp
index 808179f..ab3283b 100644
--- a/src/fru_utils.cpp
+++ b/src/fru_utils.cpp
@@ -21,9 +21,11 @@
#include <cstddef>
#include <cstdint>
#include <filesystem>
+#include <iomanip>
#include <iostream>
#include <numeric>
#include <set>
+#include <sstream>
#include <string>
#include <vector>
@@ -63,6 +65,32 @@
languageDependent = 0x3,
};
+enum MultiRecordType : uint8_t
+{
+ powerSupplyInfo = 0x00,
+ dcOutput = 0x01,
+ dcLoad = 0x02,
+ managementAccessRecord = 0x03,
+ baseCompatibilityRecord = 0x04,
+ extendedCompatibilityRecord = 0x05,
+ resvASFSMBusDeviceRecord = 0x06,
+ resvASFLegacyDeviceAlerts = 0x07,
+ resvASFRemoteControl = 0x08,
+ extendedDCOutput = 0x09,
+ extendedDCLoad = 0x0A
+};
+
+enum SubManagementAccessRecord : uint8_t
+{
+ systemManagementURL = 0x01,
+ systemName = 0x02,
+ systemPingAddress = 0x03,
+ componentManagementURL = 0x04,
+ componentName = 0x05,
+ componentPingAddress = 0x06,
+ systemUniqueID = 0x07
+};
+
/* Decode FRU data into a std::string, given an input iterator and end. If the
* state returned is fruDataOk, then the resulting string is the decoded FRU
* data. The input iterator is advanced past the data consumed.
@@ -256,6 +284,86 @@
return true;
}
+static void parseMultirecordUUID(
+ const std::vector<uint8_t>& device,
+ boost::container::flat_map<std::string, std::string>& result)
+{
+ constexpr size_t uuidDataLen = 16;
+ constexpr size_t multiRecordHeaderLen = 5;
+ /* UUID record data, plus one to skip past the sub-record type byte */
+ constexpr size_t uuidRecordData = multiRecordHeaderLen + 1;
+ constexpr size_t multiRecordEndOfListMask = 0x80;
+ /* The UUID {00112233-4455-6677-8899-AABBCCDDEEFF} would thus be represented
+ * as: 0x33 0x22 0x11 0x00 0x55 0x44 0x77 0x66 0x88 0x99 0xAA 0xBB 0xCC 0xDD
+ * 0xEE 0xFF
+ */
+ const std::array<uint8_t, uuidDataLen> uuidCharOrder = {
+ 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15};
+ uint32_t areaOffset =
+ device.at(getHeaderAreaFieldOffset(fruAreas::fruAreaMultirecord));
+
+ if (areaOffset == 0)
+ {
+ return;
+ }
+
+ areaOffset *= fruBlockSize;
+ std::vector<uint8_t>::const_iterator fruBytesIter = device.begin() +
+ areaOffset;
+
+ /* Verify area offset */
+ if (!verifyOffset(device, fruAreas::fruAreaMultirecord, *fruBytesIter))
+ {
+ return;
+ }
+ while (areaOffset + uuidRecordData + uuidDataLen <= device.size())
+ {
+ if ((areaOffset < device.size()) &&
+ (device[areaOffset] ==
+ (uint8_t)MultiRecordType::managementAccessRecord))
+ {
+ if ((areaOffset + multiRecordHeaderLen < device.size()) &&
+ (device[areaOffset + multiRecordHeaderLen] ==
+ (uint8_t)SubManagementAccessRecord::systemUniqueID))
+ {
+ /* Layout of UUID:
+ * source: https://www.ietf.org/rfc/rfc4122.txt
+ *
+ * UUID binary format (16 bytes):
+ * 4B-2B-2B-2B-6B (big endian)
+ *
+ * UUID string is 36 length of characters (36 bytes):
+ * 0 9 14 19 24
+ * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+ * be be be be be
+ * be means it should be converted to big endian.
+ */
+ /* Get UUID bytes to UUID string */
+ std::stringstream tmp;
+ tmp << std::hex << std::setfill('0');
+ for (size_t i = 0; i < uuidDataLen; i++)
+ {
+ tmp << std::setw(2)
+ << static_cast<uint16_t>(
+ device[areaOffset + uuidRecordData +
+ uuidCharOrder[i]]);
+ }
+ std::string uuidStr = tmp.str();
+ result["MULTIRECORD_UUID"] =
+ uuidStr.substr(0, 8) + '-' + uuidStr.substr(8, 4) + '-' +
+ uuidStr.substr(12, 4) + '-' + uuidStr.substr(16, 4) + '-' +
+ uuidStr.substr(20, 12);
+ break;
+ }
+ }
+ if ((device[areaOffset + 1] & multiRecordEndOfListMask) != 0)
+ {
+ break;
+ }
+ areaOffset = areaOffset + device[areaOffset + 2] + multiRecordHeaderLen;
+ }
+}
+
resCodes
formatIPMIFRU(const std::vector<uint8_t>& fruBytes,
boost::container::flat_map<std::string, std::string>& result)
@@ -457,6 +565,9 @@
}
}
+ /* Parsing the Multirecord UUID */
+ parseMultirecordUUID(fruBytes, result);
+
return ret;
}