diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cpu.cpp | 214 | ||||
-rw-r--r-- | src/dimm.cpp | 230 | ||||
-rw-r--r-- | src/manager.cpp | 475 | ||||
-rw-r--r-- | src/smbios-main.cpp | 96 | ||||
-rw-r--r-- | src/timer.cpp | 145 |
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, ®ionS[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, ®ionS[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 *>(®ionS[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 |