| /* |
| // Copyright (c) 2019 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 "mdrv2.hpp" |
| |
| #include <sys/mman.h> |
| |
| #include <fstream> |
| #include <phosphor-logging/elog-errors.hpp> |
| #include <sdbusplus/exception.hpp> |
| #include <xyz/openbmc_project/Smbios/MDR_V2/error.hpp> |
| |
| namespace phosphor |
| { |
| namespace smbios |
| { |
| |
| std::vector<uint8_t> MDR_V2::getDirectoryInformation(uint8_t dirIndex) |
| { |
| std::vector<uint8_t> responseDir; |
| if (dirIndex > smbiosDir.dirEntries) |
| { |
| responseDir.push_back(0); |
| throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error:: |
| InvalidParameter(); |
| } |
| responseDir.push_back(mdr2Version); |
| responseDir.push_back(smbiosDir.dirVersion); |
| uint8_t returnedEntries = smbiosDir.dirEntries - dirIndex; |
| responseDir.push_back(returnedEntries); |
| if ((dirIndex + returnedEntries) >= smbiosDir.dirEntries) |
| { |
| responseDir.push_back(0); |
| } |
| else |
| { |
| responseDir.push_back(smbiosDir.dirEntries - dirIndex - |
| returnedEntries); |
| } |
| for (uint8_t index = dirIndex; index < smbiosDir.dirEntries; index++) |
| { |
| for (uint8_t indexId = 0; indexId < sizeof(DataIdStruct); indexId++) |
| { |
| responseDir.push_back( |
| smbiosDir.dir[index].common.id.dataInfo[indexId]); |
| } |
| } |
| |
| return responseDir; |
| } |
| |
| bool MDR_V2::smbiosIsAvailForUpdate(uint8_t index) |
| { |
| bool ret = false; |
| if (index > maxDirEntries) |
| { |
| return ret; |
| } |
| |
| switch (smbiosDir.dir[index].stage) |
| { |
| case MDR2SMBIOSStatusEnum::mdr2Updating: |
| ret = false; |
| break; |
| |
| case MDR2SMBIOSStatusEnum::mdr2Init: |
| // This *looks* like there should be a break statement here, |
| // as the effects of the previous statement are a noop given |
| // the following code that this falls through to. |
| // We've elected not to change it, though, since it's been |
| // this way since the old generation, and it would affect |
| // the way the code functions. |
| // If it ain't broke, don't fix it. |
| |
| case MDR2SMBIOSStatusEnum::mdr2Loaded: |
| case MDR2SMBIOSStatusEnum::mdr2Updated: |
| if (smbiosDir.dir[index].lock == MDR2DirLockEnum::mdr2DirLock) |
| { |
| ret = false; |
| } |
| else |
| { |
| ret = true; |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| return ret; |
| } |
| |
| std::vector<uint8_t> MDR_V2::getDataOffer() |
| { |
| std::vector<uint8_t> offer(sizeof(DataIdStruct)); |
| if (smbiosIsAvailForUpdate(0)) |
| { |
| std::copy(smbiosDir.dir[0].common.id.dataInfo, |
| &smbiosDir.dir[0].common.id.dataInfo[16], offer.data()); |
| } |
| else |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "smbios is not ready for update"); |
| throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error:: |
| UpdateInProgress(); |
| } |
| return offer; |
| } |
| |
| inline uint8_t MDR_V2::smbiosValidFlag(uint8_t index) |
| { |
| FlagStatus ret = FlagStatus::flagIsInvalid; |
| MDR2SMBIOSStatusEnum stage = smbiosDir.dir[index].stage; |
| MDR2DirLockEnum lock = smbiosDir.dir[index].lock; |
| |
| switch (stage) |
| { |
| case MDR2SMBIOSStatusEnum::mdr2Loaded: |
| case MDR2SMBIOSStatusEnum::mdr2Updated: |
| if (lock == MDR2DirLockEnum::mdr2DirLock) |
| { |
| ret = FlagStatus::flagIsLocked; // locked |
| } |
| else |
| { |
| ret = FlagStatus::flagIsValid; // valid |
| } |
| break; |
| |
| case MDR2SMBIOSStatusEnum::mdr2Updating: |
| case MDR2SMBIOSStatusEnum::mdr2Init: |
| ret = FlagStatus::flagIsInvalid; // invalid |
| break; |
| |
| default: |
| break; |
| } |
| |
| return static_cast<uint8_t>(ret); |
| } |
| |
| std::vector<uint8_t> MDR_V2::getDataInformation(uint8_t idIndex) |
| { |
| std::vector<uint8_t> responseInfo; |
| responseInfo.push_back(mdr2Version); |
| |
| if (idIndex >= maxDirEntries) |
| { |
| throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error:: |
| InvalidParameter(); |
| } |
| |
| for (uint8_t index = 0; index < sizeof(DataIdStruct); index++) |
| { |
| responseInfo.push_back( |
| smbiosDir.dir[idIndex].common.id.dataInfo[index]); |
| } |
| responseInfo.push_back(smbiosValidFlag(idIndex)); |
| responseInfo.push_back(smbiosDir.dir[idIndex].common.size); |
| responseInfo.push_back(smbiosDir.dir[idIndex].common.dataVersion); |
| responseInfo.push_back(smbiosDir.dir[idIndex].common.timestamp); |
| |
| return responseInfo; |
| } |
| |
| bool MDR_V2::sendDirectoryInformation(uint8_t dirVersion, uint8_t dirIndex, |
| uint8_t returnedEntries, |
| uint8_t remainingEntries, |
| std::vector<uint8_t> dirEntry) |
| { |
| bool teminate = false; |
| if ((dirIndex >= maxDirEntries) || (returnedEntries < 1)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Send Dir info failed - input parameter invalid"); |
| throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error:: |
| InvalidParameter(); |
| } |
| if (dirEntry.size() < sizeof(Mdr2DirEntry)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Directory size invalid"); |
| throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error:: |
| InvalidParameter(); |
| } |
| if (dirVersion == smbiosDir.dirVersion) |
| { |
| teminate = true; |
| } |
| else |
| { |
| if (remainingEntries > 0) |
| { |
| teminate = false; |
| } |
| else |
| { |
| teminate = true; |
| smbiosDir.dirVersion = dirVersion; |
| } |
| uint8_t idIndex = dirIndex; |
| |
| uint8_t* pData = dirEntry.data(); |
| if (pData == nullptr) |
| { |
| return false; |
| } |
| for (uint8_t index = 0; index < returnedEntries; index++) |
| { |
| auto data = reinterpret_cast<const Mdr2DirEntry*>(pData); |
| smbiosDir.dir[idIndex + index].common.dataVersion = |
| data->dataVersion; |
| std::copy(data->id.dataInfo, |
| data->id.dataInfo + sizeof(DataIdStruct), |
| smbiosDir.dir[idIndex + index].common.id.dataInfo); |
| smbiosDir.dir[idIndex + index].common.dataSetSize = data->size; |
| smbiosDir.dir[idIndex + index].common.timestamp = data->timestamp; |
| pData += sizeof(returnedEntries); |
| } |
| } |
| return teminate; |
| } |
| |
| bool MDR_V2::sendDataInformation(uint8_t idIndex, uint8_t flag, |
| uint32_t dataLen, uint32_t dataVer, |
| uint32_t timeStamp) |
| { |
| if (idIndex >= maxDirEntries) |
| { |
| throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error:: |
| InvalidParameter(); |
| } |
| int entryChanged = 0; |
| if (smbiosDir.dir[idIndex].common.dataSetSize != dataLen) |
| { |
| entryChanged++; |
| smbiosDir.dir[idIndex].common.dataSetSize = dataLen; |
| } |
| |
| if (smbiosDir.dir[idIndex].common.dataVersion != dataVer) |
| { |
| entryChanged++; |
| smbiosDir.dir[idIndex].common.dataVersion = dataVer; |
| } |
| |
| if (smbiosDir.dir[idIndex].common.timestamp != timeStamp) |
| { |
| entryChanged++; |
| smbiosDir.dir[idIndex].common.timestamp = timeStamp; |
| } |
| if (entryChanged == 0) |
| { |
| return false; |
| } |
| return true; |
| } |
| |
| int MDR_V2::findIdIndex(std::vector<uint8_t> dataInfo) |
| { |
| if (dataInfo.size() != sizeof(DataIdStruct)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Length of dataInfo invalid"); |
| throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error:: |
| InvalidParameter(); |
| } |
| std::array<uint8_t, 16> arrayDataInfo; |
| |
| std::copy(dataInfo.begin(), dataInfo.end(), arrayDataInfo.begin()); |
| |
| for (int index = 0; index < smbiosDir.dirEntries; index++) |
| { |
| int info = 0; |
| for (; info < arrayDataInfo.size(); info++) |
| { |
| if (arrayDataInfo[info] != |
| smbiosDir.dir[index].common.id.dataInfo[info]) |
| { |
| break; |
| } |
| } |
| if (info == arrayDataInfo.size()) |
| { |
| return index; |
| } |
| } |
| throw sdbusplus::xyz::openbmc_project::Smbios::MDR_V2::Error::InvalidId(); |
| } |
| |
| uint8_t MDR_V2::directoryEntries(uint8_t value) |
| { |
| value = smbiosDir.dirEntries; |
| return sdbusplus::xyz::openbmc_project::Smbios::server::MDR_V2:: |
| directoryEntries(value); |
| } |
| |
| bool MDR_V2::agentSynchronizeData() |
| { |
| } |
| |
| std::vector<uint32_t> MDR_V2::synchronizeDirectoryCommonData(uint8_t idIndex, |
| uint32_t size) |
| { |
| } |
| |
| } // namespace smbios |
| } // namespace phosphor |