| #pragma once |
| |
| #include "file_io_by_type.hpp" |
| |
| #include <phosphor-logging/lg2.hpp> |
| |
| #include <filesystem> |
| #include <sstream> |
| #include <string> |
| |
| PHOSPHOR_LOG2_USING; |
| |
| namespace pldm |
| { |
| namespace responder |
| { |
| |
| namespace fs = std::filesystem; |
| |
| using MarkerLIDremainingSize = uint64_t; |
| |
| /** @class LidHandler |
| * |
| * @brief Inherits and implements FileHandler. This class is used |
| * to read/write LIDs. |
| */ |
| class LidHandler : public FileHandler |
| { |
| public: |
| /** @brief LidHandler constructor |
| */ |
| LidHandler(uint32_t fileHandle, bool permSide, uint8_t lidType = 0) : |
| FileHandler(fileHandle), lidType(lidType) |
| { |
| sideToRead = permSide ? Pside : Tside; |
| isPatchDir = false; |
| std::string dir = permSide ? LID_ALTERNATE_DIR : LID_RUNNING_DIR; |
| std::stringstream stream; |
| stream << std::hex << fileHandle; |
| auto lidName = stream.str() + ".lid"; |
| std::string patchDir = permSide ? LID_ALTERNATE_PATCH_DIR |
| : LID_RUNNING_PATCH_DIR; |
| auto patch = fs::path(patchDir) / lidName; |
| if (fs::is_regular_file(patch)) |
| { |
| lidPath = patch; |
| isPatchDir = true; |
| } |
| else |
| { |
| lidPath = std::move(dir) + '/' + lidName; |
| } |
| } |
| |
| /** @brief Method to construct the LID path based on current boot side |
| * @param[in] oemPlatformHandler - OEM platform handler |
| * @return bool - true if a new path is constructed |
| */ |
| bool constructLIDPath(oem_platform::Handler* oemPlatformHandler) |
| { |
| if (oemPlatformHandler != nullptr) |
| { |
| pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = |
| dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>( |
| oemPlatformHandler); |
| std::string dir = LID_ALTERNATE_DIR; |
| if (isPatchDir) |
| { |
| dir = LID_ALTERNATE_PATCH_DIR; |
| } |
| if (oemIbmPlatformHandler->codeUpdate->fetchCurrentBootSide() == |
| sideToRead) |
| { |
| if (isPatchDir) |
| { |
| dir = LID_RUNNING_PATCH_DIR; |
| } |
| else |
| { |
| dir = LID_RUNNING_DIR; |
| } |
| } |
| else if (oemIbmPlatformHandler->codeUpdate |
| ->isCodeUpdateInProgress()) |
| { |
| return false; |
| } |
| |
| std::stringstream stream; |
| stream << std::hex << fileHandle; |
| auto lidName = stream.str() + ".lid"; |
| lidPath = std::move(dir) + '/' + lidName; |
| } |
| return true; |
| } |
| |
| virtual int writeFromMemory(uint32_t offset, uint32_t length, |
| uint64_t address, |
| oem_platform::Handler* oemPlatformHandler) |
| { |
| int rc = PLDM_SUCCESS; |
| bool codeUpdateInProgress = false; |
| if (oemPlatformHandler != nullptr) |
| { |
| pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = |
| dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>( |
| oemPlatformHandler); |
| codeUpdateInProgress = |
| oemIbmPlatformHandler->codeUpdate->isCodeUpdateInProgress(); |
| if (codeUpdateInProgress || lidType == PLDM_FILE_TYPE_LID_MARKER) |
| { |
| std::string dir = LID_STAGING_DIR; |
| std::stringstream stream; |
| stream << std::hex << fileHandle; |
| auto lidName = stream.str() + ".lid"; |
| lidPath = std::move(dir) + '/' + lidName; |
| } |
| } |
| bool fileExists = fs::exists(lidPath); |
| int flags{}; |
| if (fileExists) |
| { |
| flags = O_RDWR; |
| } |
| else |
| { |
| flags = O_WRONLY | O_CREAT | O_TRUNC | O_SYNC; |
| } |
| auto fd = open(lidPath.c_str(), flags, S_IRUSR); |
| if (fd == -1) |
| { |
| error("Could not open file for writing {LID_PATH}", "LID_PATH", |
| lidPath.c_str()); |
| return PLDM_ERROR; |
| } |
| close(fd); |
| |
| rc = transferFileData(lidPath, false, offset, length, address); |
| if (rc != PLDM_SUCCESS) |
| { |
| error("writeFileFromMemory failed with rc= {RC}", "RC", rc); |
| return rc; |
| } |
| if (lidType == PLDM_FILE_TYPE_LID_MARKER) |
| { |
| markerLIDremainingSize -= length; |
| if (markerLIDremainingSize == 0) |
| { |
| pldm::responder::oem_ibm_platform::Handler* |
| oemIbmPlatformHandler = dynamic_cast< |
| pldm::responder::oem_ibm_platform::Handler*>( |
| oemPlatformHandler); |
| auto sensorId = |
| oemIbmPlatformHandler->codeUpdate->getMarkerLidSensor(); |
| using namespace pldm::responder::oem_ibm_platform; |
| oemIbmPlatformHandler->sendStateSensorEvent( |
| sensorId, PLDM_STATE_SENSOR_STATE, 0, VALID, VALID); |
| // rc = validate api; |
| rc = PLDM_SUCCESS; |
| } |
| } |
| else if (codeUpdateInProgress) |
| { |
| rc = processCodeUpdateLid(lidPath); |
| } |
| return rc; |
| } |
| |
| virtual int readIntoMemory(uint32_t offset, uint32_t& length, |
| uint64_t address, |
| oem_platform::Handler* oemPlatformHandler) |
| { |
| if (constructLIDPath(oemPlatformHandler)) |
| { |
| return transferFileData(lidPath, true, offset, length, address); |
| } |
| return PLDM_ERROR; |
| } |
| |
| virtual int write(const char* buffer, uint32_t offset, uint32_t& length, |
| oem_platform::Handler* oemPlatformHandler) |
| { |
| int rc = PLDM_SUCCESS; |
| bool codeUpdateInProgress = false; |
| if (oemPlatformHandler != nullptr) |
| { |
| pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = |
| dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>( |
| oemPlatformHandler); |
| codeUpdateInProgress = |
| oemIbmPlatformHandler->codeUpdate->isCodeUpdateInProgress(); |
| if (codeUpdateInProgress || lidType == PLDM_FILE_TYPE_LID_MARKER) |
| { |
| std::string dir = LID_STAGING_DIR; |
| std::stringstream stream; |
| stream << std::hex << fileHandle; |
| auto lidName = stream.str() + ".lid"; |
| lidPath = std::move(dir) + '/' + lidName; |
| } |
| } |
| bool fileExists = fs::exists(lidPath); |
| int flags{}; |
| if (fileExists) |
| { |
| flags = O_RDWR; |
| size_t fileSize = fs::file_size(lidPath); |
| if (offset > fileSize) |
| { |
| error( |
| "Offset exceeds file size, OFFSET={OFFSET} FILE_SIZE={FILE_SIZE} FILE_HANDLE{FILE_HANDLE}", |
| "OFFSET", offset, "FILE_SIZE", fileSize, "FILE_HANDLE", |
| fileHandle); |
| return PLDM_DATA_OUT_OF_RANGE; |
| } |
| } |
| else |
| { |
| flags = O_WRONLY | O_CREAT | O_TRUNC | O_SYNC; |
| if (offset > 0) |
| { |
| error("Offset is non zero in a new file"); |
| return PLDM_DATA_OUT_OF_RANGE; |
| } |
| } |
| auto fd = open(lidPath.c_str(), flags, S_IRUSR); |
| if (fd == -1) |
| { |
| error("could not open file {LID_PATH}", "LID_PATH", |
| lidPath.c_str()); |
| return PLDM_ERROR; |
| } |
| rc = lseek(fd, offset, SEEK_SET); |
| if (rc == -1) |
| { |
| error("lseek failed, ERROR={ERR}, OFFSET={OFFSET}", "ERR", errno, |
| "OFFSET", offset); |
| return PLDM_ERROR; |
| } |
| rc = ::write(fd, buffer, length); |
| if (rc == -1) |
| { |
| error( |
| "file write failed, ERROR={ERR}, LENGTH={LEN}, OFFSET={OFFSET}", |
| "ERR", errno, "LEN", length, "OFFSET", offset); |
| return PLDM_ERROR; |
| } |
| else if (rc == static_cast<int>(length)) |
| { |
| rc = PLDM_SUCCESS; |
| } |
| else if (rc < static_cast<int>(length)) |
| { |
| rc = PLDM_ERROR; |
| } |
| close(fd); |
| |
| if (lidType == PLDM_FILE_TYPE_LID_MARKER) |
| { |
| markerLIDremainingSize -= length; |
| if (markerLIDremainingSize == 0) |
| { |
| pldm::responder::oem_ibm_platform::Handler* |
| oemIbmPlatformHandler = dynamic_cast< |
| pldm::responder::oem_ibm_platform::Handler*>( |
| oemPlatformHandler); |
| auto sensorId = |
| oemIbmPlatformHandler->codeUpdate->getMarkerLidSensor(); |
| using namespace pldm::responder::oem_ibm_platform; |
| oemIbmPlatformHandler->sendStateSensorEvent( |
| sensorId, PLDM_STATE_SENSOR_STATE, 0, VALID, VALID); |
| // validate api |
| rc = PLDM_SUCCESS; |
| } |
| } |
| else if (codeUpdateInProgress) |
| { |
| rc = processCodeUpdateLid(lidPath); |
| } |
| |
| return rc; |
| } |
| |
| virtual int read(uint32_t offset, uint32_t& length, Response& response, |
| oem_platform::Handler* oemPlatformHandler) |
| { |
| if (constructLIDPath(oemPlatformHandler)) |
| { |
| return readFile(lidPath, offset, length, response); |
| } |
| return PLDM_ERROR; |
| } |
| |
| virtual int fileAck(uint8_t /*fileStatus*/) |
| { |
| return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; |
| } |
| |
| virtual int newFileAvailable(uint64_t length) |
| |
| { |
| if (lidType == PLDM_FILE_TYPE_LID_MARKER) |
| { |
| markerLIDremainingSize = length; |
| return PLDM_SUCCESS; |
| } |
| return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; |
| } |
| |
| /** @brief LidHandler destructor |
| */ |
| ~LidHandler() {} |
| |
| protected: |
| std::string lidPath; |
| std::string sideToRead; |
| bool isPatchDir; |
| static inline MarkerLIDremainingSize markerLIDremainingSize; |
| uint8_t lidType; |
| }; |
| |
| } // namespace responder |
| } // namespace pldm |