1 #pragma once 2 3 #include "file_io_by_type.hpp" 4 5 #include <phosphor-logging/lg2.hpp> 6 7 #include <filesystem> 8 #include <sstream> 9 #include <string> 10 11 PHOSPHOR_LOG2_USING; 12 13 namespace pldm 14 { 15 namespace responder 16 { 17 18 namespace fs = std::filesystem; 19 20 using MarkerLIDremainingSize = uint64_t; 21 22 /** @class LidHandler 23 * 24 * @brief Inherits and implements FileHandler. This class is used 25 * to read/write LIDs. 26 */ 27 class LidHandler : public FileHandler 28 { 29 public: 30 /** @brief LidHandler constructor 31 */ LidHandler(uint32_t fileHandle,bool permSide,uint8_t lidType=0)32 LidHandler(uint32_t fileHandle, bool permSide, uint8_t lidType = 0) : 33 FileHandler(fileHandle), lidType(lidType) 34 { 35 sideToRead = permSide ? Pside : Tside; 36 isPatchDir = false; 37 std::string dir = permSide ? LID_ALTERNATE_DIR : LID_RUNNING_DIR; 38 std::stringstream stream; 39 stream << std::hex << fileHandle; 40 auto lidName = stream.str() + ".lid"; 41 std::string patchDir = 42 permSide ? LID_ALTERNATE_PATCH_DIR : LID_RUNNING_PATCH_DIR; 43 auto patch = fs::path(patchDir) / lidName; 44 if (fs::is_regular_file(patch)) 45 { 46 lidPath = patch; 47 isPatchDir = true; 48 } 49 else 50 { 51 lidPath = std::move(dir) + '/' + lidName; 52 } 53 } 54 55 /** @brief Method to construct the LID path based on current boot side 56 * @param[in] oemPlatformHandler - OEM platform handler 57 * @return bool - true if a new path is constructed 58 */ constructLIDPath(oem_platform::Handler * oemPlatformHandler)59 bool constructLIDPath(oem_platform::Handler* oemPlatformHandler) 60 { 61 if (oemPlatformHandler != nullptr) 62 { 63 pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = 64 dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>( 65 oemPlatformHandler); 66 std::string dir = LID_ALTERNATE_DIR; 67 if (isPatchDir) 68 { 69 dir = LID_ALTERNATE_PATCH_DIR; 70 } 71 if (oemIbmPlatformHandler->codeUpdate->fetchCurrentBootSide() == 72 sideToRead) 73 { 74 if (isPatchDir) 75 { 76 dir = LID_RUNNING_PATCH_DIR; 77 } 78 else 79 { 80 dir = LID_RUNNING_DIR; 81 } 82 } 83 else if (oemIbmPlatformHandler->codeUpdate 84 ->isCodeUpdateInProgress()) 85 { 86 return false; 87 } 88 89 std::stringstream stream; 90 stream << std::hex << fileHandle; 91 auto lidName = stream.str() + ".lid"; 92 lidPath = std::move(dir) + '/' + lidName; 93 } 94 return true; 95 } 96 writeFromMemory(uint32_t offset,uint32_t length,uint64_t address,oem_platform::Handler * oemPlatformHandler)97 virtual int writeFromMemory(uint32_t offset, uint32_t length, 98 uint64_t address, 99 oem_platform::Handler* oemPlatformHandler) 100 { 101 int rc = PLDM_SUCCESS; 102 bool codeUpdateInProgress = false; 103 if (oemPlatformHandler != nullptr) 104 { 105 pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = 106 dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>( 107 oemPlatformHandler); 108 codeUpdateInProgress = 109 oemIbmPlatformHandler->codeUpdate->isCodeUpdateInProgress(); 110 if (codeUpdateInProgress || lidType == PLDM_FILE_TYPE_LID_MARKER) 111 { 112 std::string dir = LID_STAGING_DIR; 113 std::stringstream stream; 114 stream << std::hex << fileHandle; 115 auto lidName = stream.str() + ".lid"; 116 lidPath = std::move(dir) + '/' + lidName; 117 } 118 } 119 bool fileExists = fs::exists(lidPath); 120 int flags{}; 121 if (fileExists) 122 { 123 flags = O_RDWR; 124 } 125 else 126 { 127 flags = O_WRONLY | O_CREAT | O_TRUNC | O_SYNC; 128 } 129 auto fd = open(lidPath.c_str(), flags, S_IRUSR); 130 if (fd == -1) 131 { 132 error("Failed to open file '{LID_PATH}' for writing", "LID_PATH", 133 lidPath); 134 return PLDM_ERROR; 135 } 136 close(fd); 137 138 rc = transferFileData(lidPath, false, offset, length, address); 139 if (rc != PLDM_SUCCESS) 140 { 141 error("Failed to write file from memory with response code '{RC}'", 142 "RC", rc); 143 return rc; 144 } 145 if (lidType == PLDM_FILE_TYPE_LID_MARKER) 146 { 147 markerLIDremainingSize -= length; 148 if (markerLIDremainingSize == 0) 149 { 150 pldm::responder::oem_ibm_platform::Handler* 151 oemIbmPlatformHandler = dynamic_cast< 152 pldm::responder::oem_ibm_platform::Handler*>( 153 oemPlatformHandler); 154 auto sensorId = 155 oemIbmPlatformHandler->codeUpdate->getMarkerLidSensor(); 156 using namespace pldm::responder::oem_ibm_platform; 157 oemIbmPlatformHandler->sendStateSensorEvent( 158 sensorId, PLDM_STATE_SENSOR_STATE, 0, VALID, VALID); 159 // rc = validate api; 160 rc = PLDM_SUCCESS; 161 } 162 } 163 else if (codeUpdateInProgress) 164 { 165 rc = processCodeUpdateLid(lidPath); 166 } 167 return rc; 168 } 169 readIntoMemory(uint32_t offset,uint32_t length,uint64_t address,oem_platform::Handler * oemPlatformHandler)170 virtual int readIntoMemory(uint32_t offset, uint32_t length, 171 uint64_t address, 172 oem_platform::Handler* oemPlatformHandler) 173 { 174 if (constructLIDPath(oemPlatformHandler)) 175 { 176 return transferFileData(lidPath, true, offset, length, address); 177 } 178 return PLDM_ERROR; 179 } 180 write(const char * buffer,uint32_t offset,uint32_t & length,oem_platform::Handler * oemPlatformHandler)181 virtual int write(const char* buffer, uint32_t offset, uint32_t& length, 182 oem_platform::Handler* oemPlatformHandler) 183 { 184 int rc = PLDM_SUCCESS; 185 bool codeUpdateInProgress = false; 186 if (oemPlatformHandler != nullptr) 187 { 188 pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = 189 dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>( 190 oemPlatformHandler); 191 codeUpdateInProgress = 192 oemIbmPlatformHandler->codeUpdate->isCodeUpdateInProgress(); 193 if (codeUpdateInProgress || lidType == PLDM_FILE_TYPE_LID_MARKER) 194 { 195 std::string dir = LID_STAGING_DIR; 196 std::stringstream stream; 197 stream << std::hex << fileHandle; 198 auto lidName = stream.str() + ".lid"; 199 lidPath = std::move(dir) + '/' + lidName; 200 } 201 } 202 bool fileExists = fs::exists(lidPath); 203 int flags{}; 204 if (fileExists) 205 { 206 flags = O_RDWR; 207 size_t fileSize = fs::file_size(lidPath); 208 if (offset > fileSize) 209 { 210 error( 211 "Offset '{OFFSET}' exceeds file size '{SIZE}' and file handle '{FILE_HANDLE}'", 212 "OFFSET", offset, "SIZE", fileSize, "FILE_HANDLE", 213 fileHandle); 214 return PLDM_DATA_OUT_OF_RANGE; 215 } 216 } 217 else 218 { 219 flags = O_WRONLY | O_CREAT | O_TRUNC | O_SYNC; 220 if (offset > 0) 221 { 222 error("Offset '{OFFSET}' is non zero in a new file '{PATH}'", 223 "OFFSET", offset, "PATH", lidPath); 224 return PLDM_DATA_OUT_OF_RANGE; 225 } 226 } 227 auto fd = open(lidPath.c_str(), flags, S_IRUSR); 228 if (fd == -1) 229 { 230 error("Failed to open file '{LID_PATH}'", "LID_PATH", lidPath); 231 return PLDM_ERROR; 232 } 233 rc = lseek(fd, offset, SEEK_SET); 234 if (rc == -1) 235 { 236 error( 237 "Failed to lseek at offset '{OFFSET}', error number - {ERROR_NUM}", 238 "ERROR_NUM", errno, "OFFSET", offset); 239 return PLDM_ERROR; 240 } 241 rc = ::write(fd, buffer, length); 242 if (rc == -1) 243 { 244 error( 245 "Failed to do file write of length '{LENGTH}' at offset '{OFFSET}', error number - {ERROR_NUM}", 246 "LENGTH", length, "OFFSET", offset, "ERROR_NUM", errno); 247 return PLDM_ERROR; 248 } 249 else if (rc == static_cast<int>(length)) 250 { 251 rc = PLDM_SUCCESS; 252 } 253 else if (rc < static_cast<int>(length)) 254 { 255 rc = PLDM_ERROR; 256 } 257 close(fd); 258 259 if (lidType == PLDM_FILE_TYPE_LID_MARKER) 260 { 261 markerLIDremainingSize -= length; 262 if (markerLIDremainingSize == 0) 263 { 264 pldm::responder::oem_ibm_platform::Handler* 265 oemIbmPlatformHandler = dynamic_cast< 266 pldm::responder::oem_ibm_platform::Handler*>( 267 oemPlatformHandler); 268 auto sensorId = 269 oemIbmPlatformHandler->codeUpdate->getMarkerLidSensor(); 270 using namespace pldm::responder::oem_ibm_platform; 271 oemIbmPlatformHandler->sendStateSensorEvent( 272 sensorId, PLDM_STATE_SENSOR_STATE, 0, VALID, VALID); 273 // validate api 274 rc = PLDM_SUCCESS; 275 } 276 } 277 else if (codeUpdateInProgress) 278 { 279 rc = processCodeUpdateLid(lidPath); 280 } 281 282 return rc; 283 } 284 read(uint32_t offset,uint32_t & length,Response & response,oem_platform::Handler * oemPlatformHandler)285 virtual int read(uint32_t offset, uint32_t& length, Response& response, 286 oem_platform::Handler* oemPlatformHandler) 287 { 288 if (constructLIDPath(oemPlatformHandler)) 289 { 290 return readFile(lidPath, offset, length, response); 291 } 292 return PLDM_ERROR; 293 } 294 fileAck(uint8_t)295 virtual int fileAck(uint8_t /*fileStatus*/) 296 { 297 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 298 } 299 newFileAvailable(uint64_t length)300 virtual int newFileAvailable(uint64_t length) 301 302 { 303 if (lidType == PLDM_FILE_TYPE_LID_MARKER) 304 { 305 markerLIDremainingSize = length; 306 return PLDM_SUCCESS; 307 } 308 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 309 } 310 311 /** @brief LidHandler destructor 312 */ ~LidHandler()313 ~LidHandler() {} 314 315 protected: 316 std::string lidPath; 317 std::string sideToRead; 318 bool isPatchDir; 319 static inline MarkerLIDremainingSize markerLIDremainingSize; 320 uint8_t lidType; 321 }; 322 323 } // namespace responder 324 } // namespace pldm 325