dcmihandler: Fix Get DCMI Capabilities command

Get DCMI Capabilities (Discover) command returned
wrong values for parameters exceeding 1 byte length.
Also added the check for SEL entries number range
per DCMI specification.

Tested: the condition for value limit check works properly.

Change-Id: Iee0d75594067630bb6094d05533c87e3ad82807e
Signed-off-by: Kirill Pakhomov <k.pakhomov@yadro.com>
diff --git a/dcmihandler.cpp b/dcmihandler.cpp
index e858416..cb14005 100644
--- a/dcmihandler.cpp
+++ b/dcmihandler.cpp
@@ -784,16 +784,23 @@
         // If the data is beyond first byte boundary, insert in a
         // 16bit pattern for example number of SEL entries are represented
         // in 12bits.
-        if ((cap.length + cap.position) > 8)
+        if ((cap.length + cap.position) > dcmi::gByteBitSize)
         {
-            // Read the value corresponding to capability name and assign to
-            // 16bit bitset.
-            std::bitset<16> val(data.value(cap.name.c_str(), 0));
+            uint16_t val = data.value(cap.name.c_str(), 0);
+            // According to DCMI spec v1.5, max number of SEL entries is
+            // 4096, but bit 12b of DCMI capabilities Mandatory Platform
+            // Attributes field is reserved and therefore we can use only
+            // the provided 12 bits with maximum value of 4095.
+            // We're playing safe here by applying the mask
+            // to ensure that provided value will fit into 12 bits.
+            if (cap.length > dcmi::gByteBitSize)
+            {
+                val &= dcmi::gMaxSELEntriesMask;
+            }
             val <<= cap.position;
-            reinterpret_cast<uint16_t*>(
-                responseData
-                    ->data)[(cap.bytePosition - 1) / sizeof(uint16_t)] |=
-                val.to_ulong();
+            responseData->data[cap.bytePosition - 1] |=
+                static_cast<uint8_t>(val);
+            responseData->data[cap.bytePosition] |= val >> dcmi::gByteBitSize;
         }
         else
         {
diff --git a/dcmihandler.hpp b/dcmihandler.hpp
index 8b16e3d..a188c25 100644
--- a/dcmihandler.hpp
+++ b/dcmihandler.hpp
@@ -58,6 +58,8 @@
     "/usr/share/ipmi-providers/dcmi_cap.json";
 static constexpr auto gDCMIPowerMgmtCapability = "PowerManagement";
 static constexpr auto gDCMIPowerMgmtSupported = 0x1;
+static constexpr auto gMaxSELEntriesMask = 0xFFF;
+static constexpr auto gByteBitSize = 8;
 
 namespace assettag
 {