summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNikita Kosenkov <NKosenkov@IBS.RU>2022-07-14 18:12:57 +0300
committerNikita Kosenkov <NKosenkov@IBS.RU>2022-07-14 18:12:57 +0300
commit613e5f0e6cc0c6e2a1e2774d81bc581035fd76f9 (patch)
treee93cee8a510aa29bf7783680a032346eebce1b39 /src
downloadsmbios-mdrv1-613e5f0e6cc0c6e2a1e2774d81bc581035fd76f9.tar.xz
Add smbios sources
Diffstat (limited to 'src')
-rw-r--r--src/cpu.cpp214
-rw-r--r--src/dimm.cpp230
-rw-r--r--src/manager.cpp475
-rw-r--r--src/smbios-main.cpp96
-rw-r--r--src/timer.cpp145
5 files changed, 1160 insertions, 0 deletions
diff --git a/src/cpu.cpp b/src/cpu.cpp
new file mode 100644
index 0000000..a92d9e6
--- /dev/null
+++ b/src/cpu.cpp
@@ -0,0 +1,214 @@
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "cpu.hpp"
+#include "manager.hpp"
+#include <map>
+
+namespace phosphor
+{
+namespace smbios
+{
+
+void Cpu::cpuSocket(uint8_t positionNum, uint8_t structLen, uint8_t *dataIn)
+{
+ std::string result;
+
+ result = positionToString(positionNum, structLen, dataIn);
+
+ processorSocket(result);
+}
+
+std::string Cpu::processorSocket(std::string value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Cpu::
+ processorSocket(value);
+}
+
+void Cpu::cpuType(uint8_t value)
+{
+ std::map<uint8_t, std::string>::const_iterator it =
+ cpuTypeTable.find(value);
+ if (it == cpuTypeTable.end())
+ {
+ processorType("Unknown Processor Type");
+ }
+ else
+ {
+ processorType(it->second);
+ }
+}
+
+std::string Cpu::processorType(std::string value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Cpu::
+ processorType(value);
+}
+
+void Cpu::cpuFamily(uint8_t value)
+{
+ std::map<uint8_t, std::string>::const_iterator it = familyTable.find(value);
+ if (it == familyTable.end())
+ {
+ processorFamily("Unknown Processor Family");
+ }
+ else
+ {
+ processorFamily(it->second);
+ }
+}
+
+std::string Cpu::processorFamily(std::string value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Cpu::
+ processorFamily(value);
+}
+
+void Cpu::cpuManufacturer(uint8_t positionNum, uint8_t structLen,
+ uint8_t *dataIn)
+{
+ std::string result;
+
+ result = positionToString(positionNum, structLen, dataIn);
+
+ processorManufacturer(result);
+}
+
+std::string Cpu::processorManufacturer(std::string value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Cpu::
+ processorManufacturer(value);
+}
+
+uint32_t Cpu::processorId(uint32_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Cpu::
+ processorId(value);
+}
+
+void Cpu::cpuVersion(uint8_t positionNum, uint8_t structLen, uint8_t *dataIn)
+{
+ std::string result;
+
+ result = positionToString(positionNum, structLen, dataIn);
+
+ processorVersion(result);
+}
+
+std::string Cpu::processorVersion(std::string value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Cpu::
+ processorVersion(value);
+}
+
+uint16_t Cpu::processorMaxSpeed(uint16_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Cpu::
+ processorMaxSpeed(value);
+}
+
+void Cpu::cpuCharacteristics(uint16_t value)
+{
+ std::string result = "";
+ for (uint8_t index = 0; index < (8 * sizeof(value)); index++)
+ {
+ if (value & 0x01)
+ {
+ result += characterTable[index];
+ }
+ value >>= 1;
+ }
+
+ processorCharacteristics(result);
+}
+
+std::string Cpu::processorCharacteristics(std::string value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Cpu::
+ processorCharacteristics(value);
+}
+
+uint16_t Cpu::processorCoreCount(uint16_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Cpu::
+ processorCoreCount(value);
+}
+
+uint16_t Cpu::processorThreadCount(uint16_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Cpu::
+ processorThreadCount(value);
+}
+
+static constexpr uint8_t maxOldVersionCount = 0xff;
+void Cpu::processorInfoUpdate(void)
+{
+ uint8_t *dataIn = regionS[0].regionData;
+
+ dataIn = smbiosTypePtr(dataIn, processorsType);
+ if (dataIn == nullptr)
+ {
+ return;
+ }
+
+ for (uint8_t index = 0; index < cpuNum; index++)
+ {
+ dataIn = smbiosNextPtr(dataIn);
+ if (dataIn == nullptr)
+ {
+ return;
+ }
+ dataIn = smbiosTypePtr(dataIn, processorsType);
+ if (dataIn == nullptr)
+ {
+ return;
+ }
+ }
+
+ auto cpuInfo = reinterpret_cast<struct ProcessorInfo *>(dataIn);
+
+ cpuSocket(cpuInfo->socketDesignation, cpuInfo->length,
+ dataIn); // offset 4h
+ cpuType(cpuInfo->processorType); // offset 5h
+ cpuFamily(cpuInfo->family); // offset 6h
+ cpuManufacturer(cpuInfo->manufacturer, cpuInfo->length,
+ dataIn); // offset 7h
+ processorId(cpuInfo->id); // offset 8h
+ cpuVersion(cpuInfo->version, cpuInfo->length, dataIn); // offset 10h
+ processorMaxSpeed(cpuInfo->maxSpeed); // offset 14h
+ if (cpuInfo->coreCount < maxOldVersionCount) // offset 23h or 2Ah
+ {
+ processorCoreCount((uint16_t)cpuInfo->coreCount);
+ }
+ else
+ {
+ processorCoreCount(cpuInfo->coreCount2);
+ }
+
+ if (cpuInfo->threadCount < maxOldVersionCount) // offset 25h or 2Eh)
+ {
+ processorThreadCount((uint16_t)cpuInfo->threadCount);
+ }
+ else
+ {
+ processorThreadCount(cpuInfo->threadCount2);
+ }
+
+ cpuCharacteristics(cpuInfo->characteristics); // offset 26h
+}
+
+} // namespace smbios
+} // namespace phosphor
diff --git a/src/dimm.cpp b/src/dimm.cpp
new file mode 100644
index 0000000..346c701
--- /dev/null
+++ b/src/dimm.cpp
@@ -0,0 +1,230 @@
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "dimm.hpp"
+#include "manager.hpp"
+
+namespace phosphor
+{
+namespace smbios
+{
+
+using DeviceType =
+ sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::DeviceType;
+
+static constexpr uint16_t maxOldDimmSize = 0x7fff;
+void Dimm::memoryInfoUpdate(void)
+{
+ uint8_t *dataIn = regionS[0].regionData;
+
+ dataIn = smbiosTypePtr(dataIn, memoryDeviceType);
+ if (dataIn == nullptr)
+ {
+ return;
+ }
+
+ for (uint8_t index = 0; index < dimmNum; index++)
+ {
+ dataIn = smbiosNextPtr(dataIn);
+ if (dataIn == nullptr)
+ {
+ return;
+ }
+ dataIn = smbiosTypePtr(dataIn, memoryDeviceType);
+ if (dataIn == nullptr)
+ {
+ return;
+ }
+ }
+
+ auto memoryInfo = reinterpret_cast<struct MemoryInfo *>(dataIn);
+
+ memoryDataWidth(memoryInfo->dataWidth);
+
+ if (memoryInfo->size == maxOldDimmSize)
+ {
+ dimmSizeExt(memoryInfo->extendedSize);
+ }
+ else
+ {
+ dimmSize(memoryInfo->size);
+ }
+
+ dimmDeviceLocator(memoryInfo->deviceLocator, memoryInfo->length, dataIn);
+ dimmType(memoryInfo->memoryType);
+ dimmTypeDetail(memoryInfo->typeDetail);
+ maxMemorySpeedInMhz(memoryInfo->speed);
+ dimmManufacturer(memoryInfo->manufacturer, memoryInfo->length, dataIn);
+ dimmSerialNum(memoryInfo->serialNum, memoryInfo->length, dataIn);
+ dimmPartNum(memoryInfo->partNum, memoryInfo->length, dataIn);
+ memoryAttributes(memoryInfo->attributes);
+ memoryConfiguredSpeedInMhz(memoryInfo->confClockSpeed);
+
+ return;
+}
+
+uint16_t Dimm::memoryDataWidth(uint16_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
+ memoryDataWidth(value);
+}
+
+static constexpr uint16_t baseNewVersionDimmSize = 0x8000;
+static constexpr uint16_t dimmSizeUnit = 1024;
+void Dimm::dimmSize(uint16_t size)
+{
+ uint32_t result = size & maxOldDimmSize;
+ if (0 == (size & baseNewVersionDimmSize))
+ {
+ result = result * dimmSizeUnit;
+ }
+ memorySizeInKB(result);
+}
+
+void Dimm::dimmSizeExt(uint32_t size)
+{
+ size = size * dimmSizeUnit;
+ memorySizeInKB(size);
+}
+
+uint32_t Dimm::memorySizeInKB(uint32_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
+ memorySizeInKB(value);
+}
+
+void Dimm::dimmDeviceLocator(uint8_t positionNum, uint8_t structLen,
+ uint8_t *dataIn)
+{
+ std::string result;
+
+ result = positionToString(positionNum, structLen, dataIn);
+
+ memoryDeviceLocator(result);
+}
+
+std::string Dimm::memoryDeviceLocator(std::string value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
+ memoryDeviceLocator(value);
+}
+
+void Dimm::dimmType(uint8_t type)
+{
+ std::map<uint8_t, DeviceType>::const_iterator it = dimmTypeTable.find(type);
+ if (it == dimmTypeTable.end())
+ {
+ memoryType(DeviceType::Unknown);
+ }
+ else
+ {
+ memoryType(it->second);
+ }
+}
+
+DeviceType Dimm::memoryType(DeviceType value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
+ memoryType(value);
+}
+
+void Dimm::dimmTypeDetail(uint16_t detail)
+{
+ std::string result;
+ for (uint8_t index = 0; index < (8 * sizeof(detail)); index++)
+ {
+ if (detail & 0x01)
+ {
+ result += detailTable[index];
+ }
+ detail >>= 1;
+ }
+ memoryTypeDetail(result);
+}
+
+std::string Dimm::memoryTypeDetail(std::string value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
+ memoryTypeDetail(value);
+}
+
+uint16_t Dimm::maxMemorySpeedInMhz(uint16_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
+ maxMemorySpeedInMhz(value);
+}
+
+void Dimm::dimmManufacturer(uint8_t positionNum, uint8_t structLen,
+ uint8_t *dataIn)
+{
+ std::string result;
+
+ result = positionToString(positionNum, structLen, dataIn);
+
+ manufacturer(result);
+}
+
+std::string Dimm::manufacturer(std::string value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Decorator::server::
+ Asset::manufacturer(value);
+}
+
+void Dimm::dimmSerialNum(uint8_t positionNum, uint8_t structLen,
+ uint8_t *dataIn)
+{
+ std::string result;
+
+ result = positionToString(positionNum, structLen, dataIn);
+
+ serialNumber(result);
+}
+
+std::string Dimm::serialNumber(std::string value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Decorator::server::
+ Asset::serialNumber(value);
+}
+
+void Dimm::dimmPartNum(uint8_t positionNum, uint8_t structLen, uint8_t *dataIn)
+{
+ std::string result;
+
+ result = positionToString(positionNum, structLen, dataIn);
+
+ partNumber(result);
+}
+
+std::string Dimm::partNumber(std::string value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Decorator::server::
+ Asset::partNumber(value);
+}
+
+uint8_t Dimm::memoryAttributes(uint8_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
+ memoryAttributes(value);
+}
+
+uint16_t Dimm::memoryConfiguredSpeedInMhz(uint16_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
+ memoryConfiguredSpeedInMhz(value);
+}
+
+} // namespace smbios
+} // namespace phosphor
diff --git a/src/manager.cpp b/src/manager.cpp
new file mode 100644
index 0000000..c3bdf4a
--- /dev/null
+++ b/src/manager.cpp
@@ -0,0 +1,475 @@
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "manager.hpp"
+#include <algorithm>
+#include <sdbusplus/exception.hpp>
+#include "xyz/openbmc_project/Smbios/MDR_V1/error.hpp"
+#include <smbios.hpp>
+#include <string>
+#include <phosphor-logging/elog-errors.hpp>
+#include <fstream>
+
+namespace phosphor
+{
+namespace smbios
+{
+
+void MDR_V1::regionUpdateTimeout(uint8_t u8Data)
+{
+ uint8_t regionId = u8Data;
+ if ((regionId == 0) || (regionId >= maxMdrIndex))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "timeout callback failure - region Id invalid");
+ return;
+ }
+ regionId--;
+
+ // TODO: Create a SEL Log
+
+ // unlock the region
+ if (regionS[regionId].state.lockPolicy != regionLockUnlocked)
+ {
+ regionS[regionId].state.valid = false;
+ regionUpdateCounter(&(regionS[regionId].state.updateCount));
+ regionS[regionId].sessionId = 0xFF;
+ regionS[regionId].state.lockPolicy = regionLockUnlocked;
+ regionS[regionId].state.regionUsed = 0;
+ } // If locked
+}
+
+std::vector<uint8_t> MDR_V1::regionStatus(uint8_t regionId)
+{
+ uint8_t *state;
+ std::vector<uint8_t> result;
+ if (regionId >= maxRegion)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "region status error - invalid regionId");
+ throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V1::Error::
+ InvalidParameter();
+ return result;
+ }
+ state = &(regionS[regionId].state.mdrVersion);
+
+ for (int index = 0; index < sizeof(struct MDRState); index++)
+ {
+ result.push_back(state[index]);
+ }
+
+ return result;
+}
+
+static constexpr int msb = 0x8000;
+static constexpr uint32_t polynomial = 0x1070;
+uint8_t MDR_V1::calcCRC8(const uint8_t regionId)
+{
+ uint8_t crc = 0;
+
+ for (int count = 0; count < regionS[regionId].state.regionUsed; count++)
+ {
+ int data = ((crc ^ regionS[regionId].regionData[count]) << 8);
+ for (int index = 0; index < 8; index++)
+ {
+ if (data & msb)
+ {
+ data = (data ^ (polynomial << 3));
+ }
+ data <<= 1;
+ }
+ crc = (data >> 8);
+ }
+
+ return crc;
+}
+
+uint8_t MDR_V1::getTotalDimmSlot()
+{
+ uint8_t *dataIn = regionS[0].regionData;
+ uint8_t num = 0;
+
+ if (dataIn == nullptr)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "get dimm total slot failed - no region data");
+ return 0;
+ }
+
+ int limit = 0xff;
+ while (limit > 0)
+ {
+ dataIn = smbiosTypePtr(dataIn, memoryDeviceType);
+ if (dataIn == nullptr)
+ {
+ break;
+ }
+ num++;
+ dataIn = smbiosNextPtr(dataIn);
+ if (dataIn == nullptr)
+ {
+ break;
+ }
+ limit--;
+ }
+
+ return num;
+}
+
+constexpr int limitEntryLen = 0xff;
+uint8_t MDR_V1::getTotalCpuSlot()
+{
+ uint8_t *dataIn = regionS[0].regionData;
+ uint8_t num = 0;
+
+ if (dataIn == nullptr)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "get cpu total slot failed - no region data");
+ return 0;
+ }
+
+ int limit = limitEntryLen;
+ while (limit > 0)
+ {
+ dataIn = smbiosTypePtr(dataIn, processorsType);
+ if (dataIn == nullptr)
+ {
+ break;
+ }
+ num++;
+ dataIn = smbiosNextPtr(dataIn);
+ if (dataIn == nullptr)
+ {
+ break;
+ }
+ limit--;
+ }
+
+ return num;
+}
+
+void MDR_V1::systemInfoUpdate()
+{
+ uint8_t num = 0;
+ std::string path;
+
+ num = getTotalDimmSlot();
+
+ // Clear all dimm cpu interface first
+ std::vector<std::unique_ptr<Dimm>>().swap(dimms);
+ std::vector<std::unique_ptr<Cpu>>().swap(cpus);
+
+ for (int index = 0; index < num; index++)
+ {
+ path = dimmPath + std::to_string(index);
+ dimms.emplace_back(std::make_unique<phosphor::smbios::Dimm>(
+ bus, path, index, &regionS[0]));
+ }
+
+ num = 0;
+ num = getTotalCpuSlot();
+
+ for (int index = 0; index < num; index++)
+ {
+ path = cpuPath + std::to_string(index);
+ cpus.emplace_back(std::make_unique<phosphor::smbios::Cpu>(
+ bus, path, index, &regionS[0]));
+ }
+}
+
+bool MDR_V1::readDataFromFlash(uint8_t *data, const char *file)
+{
+ std::ifstream filePtr(file, std::ios_base::binary);
+ if (!filePtr.good())
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Read data from flash error - Open MDRV1 table file failure");
+ return false;
+ }
+ filePtr.clear();
+ filePtr.seekg(0, std::ios_base::beg);
+ ManagedDataRegion *pRegionS = (ManagedDataRegion *)data;
+ filePtr.read(reinterpret_cast<char *>(&(pRegionS->state)),
+ sizeof(MDRState));
+ filePtr.read(reinterpret_cast<char *>(pRegionS->regionData),
+ (pRegionS->state.regionLength < smbiosTableStorageSize
+ ? pRegionS->state.regionLength
+ : smbiosTableStorageSize));
+ return true;
+}
+
+bool MDR_V1::storeDataToFlash(uint8_t *data, const char *file)
+{
+ std::ofstream filePtr(file, std::ios_base::binary);
+ if (!filePtr.good())
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Write data from flash error - Open MDRV1 table file failure");
+ return false;
+ }
+
+ filePtr.clear();
+ filePtr.seekp(0, std::ios_base::beg);
+ ManagedDataRegion *pRegionS = (ManagedDataRegion *)data;
+
+ filePtr.write(reinterpret_cast<char *>(&(pRegionS->state)),
+ sizeof(MDRState));
+ filePtr.write(reinterpret_cast<char *>(pRegionS->regionData),
+ pRegionS->state.regionLength);
+
+ return true;
+}
+
+void MDR_V1::regionComplete(uint8_t regionId)
+{
+ uint8_t tempRegionId = 0;
+ uint8_t tempUpdateCount = 0;
+
+ if (regionId >= maxRegion)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "region complete failed - invalid regionId");
+ throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V1::Error::
+ InvalidParameter();
+ return;
+ }
+
+ regionS[regionId].state.valid = true;
+ regionS[regionId].state.lockPolicy = regionLockUnlocked;
+ regionS[regionId].sessionId = 0;
+ regionS[regionId].state.crc8 = calcCRC8(regionId);
+ tempRegionId = regionS[regionId].state.regionId;
+ tempUpdateCount = regionS[regionId].state.updateCount;
+
+ lockPolicy(regionS[regionId].state.lockPolicy);
+ sessionId(regionS[regionId].sessionId);
+
+ timers[regionId]->setEnabled<std::false_type>();
+
+ // TODO: Create a SEL Log
+ systemInfoUpdate(); // Update CPU and DIMM information
+
+ // If BMC try to restore region data from BMC flash
+ // no need to store the data to flash again.
+ if (restoreRegion)
+ {
+ restoreRegion = false;
+ return;
+ }
+
+ if (access(smbiosPath, F_OK) == -1)
+ {
+ if (0 != mkdir(smbiosPath, S_IRWXU))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "create folder failed for writting smbios file");
+ return;
+ }
+ }
+ if (!storeDataToFlash(reinterpret_cast<uint8_t *>(&regionS[regionId]),
+ regionS[regionId].flashName))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Store data to flash failed");
+ throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V1::Error::IOError();
+ }
+}
+
+std::vector<uint8_t> MDR_V1::regionRead(uint8_t regionId, uint8_t length,
+ uint16_t offset)
+{
+ std::vector<uint8_t> result;
+
+ if (regionId >= maxRegion)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "region read failed - invalid regionId");
+ throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V1::Error::
+ InvalidParameter();
+ return result;
+ }
+ if (regionS[regionId].state.regionUsed < offset + length)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "region read failed - invalid offset/length");
+ throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V1::Error::
+ InvalidParameter();
+ return result;
+ }
+
+ result.push_back(length);
+ result.push_back(regionS[regionId].state.updateCount);
+ for (uint16_t index = 0; index < length; index++)
+ {
+ result.push_back(regionS[regionId].regionData[index + offset]);
+ }
+ return result;
+}
+
+std::string MDR_V1::regionWrite(std::vector<uint8_t> wData)
+{
+ uint8_t regionId = wData[0];
+ if (regionId >= maxRegion)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "region write failed - invalid regionId");
+ throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V1::Error::
+ InvalidParameter();
+ return "failed";
+ }
+ uint8_t length = wData[1];
+ uint16_t offset = wData[3] << 8 | (wData[2]);
+ uint8_t *dest;
+ std::vector<uint8_t>::iterator iter;
+ std::chrono::microseconds usec =
+ std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::milliseconds(regionS[regionId].msTimeout));
+
+ dest = &(regionS[regionId].regionData[offset]);
+
+ iter = wData.begin();
+ iter += 4;
+ std::copy(iter, wData.end(), dest);
+ regionS[regionId].state.regionUsed = std::max(
+ regionS[regionId].state.regionUsed, (uint16_t)(offset + length));
+ regionUsed(regionS[regionId].state.regionUsed);
+ timers[regionId]->start(usec);
+ timers[regionId]->setEnabled<std::true_type>();
+
+ return "Success";
+}
+
+uint32_t MDR_V1::getOsRunningTime(void)
+{
+ int s32Result;
+ struct timespec sTime;
+
+ s32Result = clock_gettime(CLOCK_MONOTONIC, &sTime);
+ if (s32Result != 0)
+ {
+ return 0;
+ }
+
+ return (sTime.tv_sec);
+}
+
+uint8_t MDR_V1::genMdrSessionId(void)
+{
+ uint32_t now = 0;
+ uint8_t id = 0;
+
+ do
+ {
+ now = getOsRunningTime();
+ id = (uint8_t)(now ^ (now >> 8) ^ (now >> 16) ^ (now >> 24));
+ } while ((id == 0x00) || (id == 0xFF));
+
+ return id;
+}
+
+void MDR_V1::regionUpdateCounter(uint8_t *count)
+{
+ if (count != nullptr)
+ {
+ if (++(*count) == 0)
+ {
+ (*count)++;
+ }
+ }
+}
+
+uint8_t MDR_V1::regionLock(uint8_t u8SessionId, uint8_t regionId,
+ uint8_t u8LockPolicy, uint16_t msTimeout)
+{
+ uint8_t reqSession;
+
+ if (regionId >= maxRegion)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "region lock failed - invalid regionId");
+ throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V1::Error::
+ InvalidParameter();
+ return 0;
+ }
+
+ if (u8LockPolicy != regionLockUnlocked)
+ {
+ reqSession = genMdrSessionId();
+ }
+ else
+ {
+ reqSession = 0;
+ }
+
+ regionS[regionId].state.valid = false;
+ regionUpdateCounter(&(regionS[regionId].state.updateCount));
+ regionS[regionId].sessionId = reqSession;
+ regionS[regionId].state.lockPolicy = u8LockPolicy;
+ regionS[regionId].state.regionUsed = 0;
+ regionS[regionId].msTimeout = msTimeout;
+ regionUsed(regionS[regionId].state.regionUsed);
+ lockPolicy(regionS[regionId].state.lockPolicy);
+ sessionId(regionS[regionId].sessionId);
+
+ if (regionS[regionId].msTimeout != 0)
+ {
+ auto usec = std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::milliseconds(1000));
+ timers[regionId]->start(usec);
+ timers[regionId]->setEnabled<std::true_type>();
+ }
+
+ return regionS[regionId].sessionId;
+}
+
+uint8_t MDR_V1::regionId(uint8_t value)
+{
+ globalRegionId = value;
+
+ sdbusplus::xyz::openbmc_project::Smbios::server::MDR_V1::lockPolicy(
+ regionS[value].state.lockPolicy);
+
+ sdbusplus::xyz::openbmc_project::Smbios::server::MDR_V1::regionUsed(
+ regionS[value].state.regionUsed);
+
+ sdbusplus::xyz::openbmc_project::Smbios::server::MDR_V1::sessionId(
+ regionS[value].sessionId);
+
+ return sdbusplus::xyz::openbmc_project::Smbios::server::MDR_V1::regionId(
+ value);
+}
+
+uint8_t MDR_V1::lockPolicy(uint8_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Smbios::server::MDR_V1::lockPolicy(
+ value);
+}
+
+uint16_t MDR_V1::regionUsed(uint16_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Smbios::server::MDR_V1::regionUsed(
+ value);
+}
+
+uint8_t MDR_V1::sessionId(uint8_t value)
+{
+ return sdbusplus::xyz::openbmc_project::Smbios::server::MDR_V1::sessionId(
+ value);
+}
+
+} // namespace smbios
+} // namespace phosphor
diff --git a/src/smbios-main.cpp b/src/smbios-main.cpp
new file mode 100644
index 0000000..532163c
--- /dev/null
+++ b/src/smbios-main.cpp
@@ -0,0 +1,96 @@
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "manager.hpp"
+#include "smbios.hpp"
+#include <systemd/sd-event.h>
+#include <phosphor-logging/elog.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+
+uint8_t mdrSmBiosData[mdrSmbiosSize];
+uint8_t mdrAcpiTable[mdrAcpiTableSize];
+uint8_t mdrMemoryMapping[mdrMemMappingSize];
+uint8_t mdrSCSIBoot[mdrScsiBootSize];
+uint8_t mdrNvmeData[mdrNvmeSize];
+
+struct ManagedDataRegion regionS[] = {
+ // SMBIOS table - matching the regionID order
+ {mdrType1File,
+ mdrSmBiosData,
+ 0,
+ {mdrVersion, mdrSmbios, false, 0, regionLockUnlocked, mdrSmbiosSize, 0, 0},
+ 0},
+
+ // ACPI tables - matching the regionID order
+ {mdrAcpiFile,
+ mdrAcpiTable,
+ 0,
+ {mdrVersion, mdrAcpi, false, 0, regionLockUnlocked, 0, mdrAcpiTableSize,
+ 0},
+ 0},
+
+ // Memory Mapping table - matching the regionID order
+ {mdrMemMapFile,
+ mdrMemoryMapping,
+ 0,
+ {mdrVersion, mdrMemMap, false, 0, regionLockUnlocked, mdrMemMappingSize, 0,
+ 0},
+ 0},
+
+ {mdrScsiBootFile,
+ mdrSCSIBoot,
+ 0,
+ {mdrVersion, mdrScsiBoot, false, 0, regionLockUnlocked, mdrScsiBootSize, 0,
+ 0},
+ 0},
+
+ // NVMe table - matching the regionID order
+ {mdrNvmeFile,
+ mdrNvmeData,
+ 0,
+ {mdrVersion, mdrNvme, false, 0, regionLockUnlocked, mdrNvmeSize, 0, 0},
+ 0},
+};
+
+int main(void)
+{
+ sd_event *events = nullptr;
+ sd_event_default(&events);
+
+ sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
+ sdbusplus::server::manager::manager objManager(bus, "/xyz/openbmc_project");
+ phosphor::watchdog::EventPtr eventP{events,
+ phosphor::watchdog::EventDeleter()};
+ bus.attach_event(events, SD_EVENT_PRIORITY_NORMAL);
+ bus.request_name("xyz.openbmc_project.Smbios.MDR_V1");
+
+ phosphor::smbios::MDR_V1 mdrV1(bus, phosphor::smbios::mdrV1Path, regionS,
+ eventP);
+
+ while (true)
+ {
+ int r = sd_event_run(events, (uint64_t)-1);
+ if (r < 0)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failure processing request",
+ phosphor::logging::entry("errno=0x%X", -r));
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/timer.cpp b/src/timer.cpp
new file mode 100644
index 0000000..46fa022
--- /dev/null
+++ b/src/timer.cpp
@@ -0,0 +1,145 @@
+/**
+ * Copyright © 2017 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "timer.hpp"
+#include <systemd/sd-event.h>
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/elog.hpp>
+#include <phosphor-logging/log.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+#include <chrono>
+namespace phosphor
+{
+namespace watchdog
+{
+
+// For throwing exception
+using namespace phosphor::logging;
+using InternalFailure =
+ sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
+
+// Initializes the timer object
+void Timer::initialize()
+{
+ // This can not be called more than once.
+ if (eventSource.get())
+ {
+ log<level::ERR>("Timer already initialized");
+ elog<InternalFailure>();
+ }
+
+ // Add infinite expiration time
+ decltype(eventSource.get()) sourcePtr = nullptr;
+ auto r = sd_event_add_time(event.get(), &sourcePtr,
+ CLOCK_MONOTONIC, // Time base
+ UINT64_MAX, // Expire time - way long time
+ 0, // Use default event accuracy
+ timeoutHandler, // Callback handler on timeout
+ this); // User data
+ eventSource.reset(sourcePtr);
+
+ if (r < 0)
+ {
+ log<level::ERR>("Timer initialization failed");
+ elog<InternalFailure>();
+ }
+
+ // Disable the timer for now
+ setEnabled<std::false_type>();
+}
+
+// callback handler on timeout
+int Timer::timeoutHandler(sd_event_source* eventSource, uint64_t usec,
+ void* userData)
+{
+ using namespace phosphor::logging;
+
+ auto timer = static_cast<Timer*>(userData);
+ timer->expire = true;
+
+ // Call an optional callback function
+ if (timer->userCallBack)
+ {
+ timer->userCallBack(timer->regionId);
+ }
+ return 0;
+}
+
+// Gets the time from steady_clock
+std::chrono::microseconds Timer::getCurrentTime()
+{
+ using namespace std::chrono;
+ auto usec = steady_clock::now().time_since_epoch();
+ return duration_cast<microseconds>(usec);
+}
+
+// Sets the expiration time and arms the timer
+void Timer::start(std::chrono::microseconds usec)
+{
+ using namespace std::chrono;
+
+ // Get the current MONOTONIC time and add the delta
+ auto expireTime = getCurrentTime() + usec;
+
+ // Set the time
+ auto r = sd_event_source_set_time(eventSource.get(), expireTime.count());
+ if (r < 0)
+ {
+ log<level::ERR>(
+ "Error setting the expiration time",
+ entry("MSEC=%llu", duration_cast<milliseconds>(usec).count()));
+ elog<InternalFailure>();
+ }
+}
+
+// Returns current timer enablement type
+int Timer::getEnabled() const
+{
+ int enabled{};
+ auto r = sd_event_source_get_enabled(eventSource.get(), &enabled);
+ if (r < 0)
+ {
+ log<level::ERR>("Error geting current timer type enablement state");
+ elog<InternalFailure>();
+ }
+ return enabled;
+}
+
+// Enables / disables the timer
+void Timer::setEnabled(int type)
+{
+ auto r = sd_event_source_set_enabled(eventSource.get(), type);
+ if (r < 0)
+ {
+ log<level::ERR>("Error setting the timer type", entry("TYPE=%d", type));
+ elog<InternalFailure>();
+ }
+}
+
+// Returns time remaining before expiration
+std::chrono::microseconds Timer::getRemaining() const
+{
+ uint64_t next = 0;
+ auto r = sd_event_source_get_time(eventSource.get(), &next);
+ if (r < 0)
+ {
+ log<level::ERR>("Error fetching remaining time to expire");
+ elog<InternalFailure>();
+ }
+ return std::chrono::microseconds(next);
+}
+
+} // namespace watchdog
+} // namespace phosphor