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 */ 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 = permSide ? LID_ALTERNATE_PATCH_DIR 42 : 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 */ 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 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("Could not open file for writing {LID_PATH}", "LID_PATH", 133 lidPath.c_str()); 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("writeFileFromMemory failed with rc= {RC}", "RC", rc); 142 return rc; 143 } 144 if (lidType == PLDM_FILE_TYPE_LID_MARKER) 145 { 146 markerLIDremainingSize -= length; 147 if (markerLIDremainingSize == 0) 148 { 149 pldm::responder::oem_ibm_platform::Handler* 150 oemIbmPlatformHandler = dynamic_cast< 151 pldm::responder::oem_ibm_platform::Handler*>( 152 oemPlatformHandler); 153 auto sensorId = 154 oemIbmPlatformHandler->codeUpdate->getMarkerLidSensor(); 155 using namespace pldm::responder::oem_ibm_platform; 156 oemIbmPlatformHandler->sendStateSensorEvent( 157 sensorId, PLDM_STATE_SENSOR_STATE, 0, VALID, VALID); 158 // rc = validate api; 159 rc = PLDM_SUCCESS; 160 } 161 } 162 else if (codeUpdateInProgress) 163 { 164 rc = processCodeUpdateLid(lidPath); 165 } 166 return rc; 167 } 168 169 virtual int readIntoMemory(uint32_t offset, uint32_t& length, 170 uint64_t address, 171 oem_platform::Handler* oemPlatformHandler) 172 { 173 if (constructLIDPath(oemPlatformHandler)) 174 { 175 return transferFileData(lidPath, true, offset, length, address); 176 } 177 return PLDM_ERROR; 178 } 179 180 virtual int write(const char* buffer, uint32_t offset, uint32_t& length, 181 oem_platform::Handler* oemPlatformHandler) 182 { 183 int rc = PLDM_SUCCESS; 184 bool codeUpdateInProgress = false; 185 if (oemPlatformHandler != nullptr) 186 { 187 pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = 188 dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>( 189 oemPlatformHandler); 190 codeUpdateInProgress = 191 oemIbmPlatformHandler->codeUpdate->isCodeUpdateInProgress(); 192 if (codeUpdateInProgress || lidType == PLDM_FILE_TYPE_LID_MARKER) 193 { 194 std::string dir = LID_STAGING_DIR; 195 std::stringstream stream; 196 stream << std::hex << fileHandle; 197 auto lidName = stream.str() + ".lid"; 198 lidPath = std::move(dir) + '/' + lidName; 199 } 200 } 201 bool fileExists = fs::exists(lidPath); 202 int flags{}; 203 if (fileExists) 204 { 205 flags = O_RDWR; 206 size_t fileSize = fs::file_size(lidPath); 207 if (offset > fileSize) 208 { 209 error( 210 "Offset exceeds file size, OFFSET={OFFSET} FILE_SIZE={FILE_SIZE}", 211 "OFFSET", offset, "FILE_SIZE", fileSize); 212 return PLDM_DATA_OUT_OF_RANGE; 213 } 214 } 215 else 216 { 217 flags = O_WRONLY | O_CREAT | O_TRUNC | O_SYNC; 218 if (offset > 0) 219 { 220 error("Offset is non zero in a new file"); 221 return PLDM_DATA_OUT_OF_RANGE; 222 } 223 } 224 auto fd = open(lidPath.c_str(), flags, S_IRUSR); 225 if (fd == -1) 226 { 227 error("could not open file {LID_PATH}", "LID_PATH", 228 lidPath.c_str()); 229 return PLDM_ERROR; 230 } 231 rc = lseek(fd, offset, SEEK_SET); 232 if (rc == -1) 233 { 234 error("lseek failed, ERROR={ERR}, OFFSET={OFFSET}", "ERR", errno, 235 "OFFSET", offset); 236 return PLDM_ERROR; 237 } 238 rc = ::write(fd, buffer, length); 239 if (rc == -1) 240 { 241 error( 242 "file write failed, ERROR={ERR}, LENGTH={LEN}, OFFSET={OFFSET}", 243 "ERR", errno, "LEN", length, "OFFSET", offset); 244 return PLDM_ERROR; 245 } 246 else if (rc == static_cast<int>(length)) 247 { 248 rc = PLDM_SUCCESS; 249 } 250 else if (rc < static_cast<int>(length)) 251 { 252 rc = PLDM_ERROR; 253 } 254 close(fd); 255 256 if (lidType == PLDM_FILE_TYPE_LID_MARKER) 257 { 258 markerLIDremainingSize -= length; 259 if (markerLIDremainingSize == 0) 260 { 261 pldm::responder::oem_ibm_platform::Handler* 262 oemIbmPlatformHandler = dynamic_cast< 263 pldm::responder::oem_ibm_platform::Handler*>( 264 oemPlatformHandler); 265 auto sensorId = 266 oemIbmPlatformHandler->codeUpdate->getMarkerLidSensor(); 267 using namespace pldm::responder::oem_ibm_platform; 268 oemIbmPlatformHandler->sendStateSensorEvent( 269 sensorId, PLDM_STATE_SENSOR_STATE, 0, VALID, VALID); 270 // validate api 271 rc = PLDM_SUCCESS; 272 } 273 } 274 else if (codeUpdateInProgress) 275 { 276 rc = processCodeUpdateLid(lidPath); 277 } 278 279 return rc; 280 } 281 282 virtual int read(uint32_t offset, uint32_t& length, Response& response, 283 oem_platform::Handler* oemPlatformHandler) 284 { 285 if (constructLIDPath(oemPlatformHandler)) 286 { 287 return readFile(lidPath, offset, length, response); 288 } 289 return PLDM_ERROR; 290 } 291 292 virtual int fileAck(uint8_t /*fileStatus*/) 293 { 294 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 295 } 296 297 virtual int newFileAvailable(uint64_t length) 298 299 { 300 if (lidType == PLDM_FILE_TYPE_LID_MARKER) 301 { 302 markerLIDremainingSize = length; 303 return PLDM_SUCCESS; 304 } 305 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 306 } 307 308 /** @brief LidHandler destructor 309 */ 310 ~LidHandler() {} 311 312 protected: 313 std::string lidPath; 314 std::string sideToRead; 315 bool isPatchDir; 316 static inline MarkerLIDremainingSize markerLIDremainingSize; 317 uint8_t lidType; 318 }; 319 320 } // namespace responder 321 } // namespace pldm 322