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