1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 17 #include <errno.h> 18 #include <fcntl.h> 19 #include <limits.h> 20 #include <sys/stat.h> 21 #include <sys/types.h> 22 #include <unistd.h> 23 24 #include <commandutils.hpp> 25 #include <cstdint> 26 #include <fstream> 27 #include <ipmid/api.hpp> 28 #include <ipmid/utils.hpp> 29 #include <oemcommands.hpp> 30 #include <phosphor-logging/log.hpp> 31 #include <sdbusplus/message/types.hpp> 32 #include <smbiosmdrv2handler.hpp> 33 #include <string> 34 #include <vector> 35 #include <xyz/openbmc_project/Common/error.hpp> 36 37 std::unique_ptr<MDRV2> mdrv2 = nullptr; 38 static constexpr const uint8_t ccOemInvalidChecksum = 0x85; 39 static constexpr size_t dataInfoSize = 16; 40 static constexpr const uint8_t ccStorageLeak = 0xC4; 41 42 static void register_netfn_smbiosmdrv2_functions() __attribute__((constructor)); 43 44 int MDRV2::agentLookup(const uint16_t &agentId) 45 { 46 int agentIndex = -1; 47 48 if (lastAgentId == agentId) 49 { 50 return lastAgentIndex; 51 } 52 53 if (agentId == smbiosAgentId) 54 { 55 return firstAgentIndex; 56 } 57 58 return agentIndex; 59 } 60 61 int MDRV2::sdplusMdrv2GetProperty(const std::string &name, 62 sdbusplus::message::variant<uint8_t> &value, 63 const std::string &service) 64 { 65 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 66 sdbusplus::message::message method = 67 bus->new_method_call(service.c_str(), mdrv2Path, dbusProperties, "Get"); 68 method.append(mdrv2Interface, name); 69 70 sdbusplus::message::message reply = bus->call(method); 71 72 try 73 { 74 sdbusplus::message::message reply = bus->call(method); 75 reply.read(value); 76 } 77 catch (sdbusplus::exception_t &e) 78 { 79 phosphor::logging::log<phosphor::logging::level::ERR>( 80 "Error get property, sdbusplus call failed", 81 phosphor::logging::entry("ERROR=%s", e.what())); 82 return -1; 83 } 84 85 return 0; 86 } 87 88 int MDRV2::syncDirCommonData(uint8_t idIndex, uint32_t size, 89 const std::string &service) 90 { 91 std::vector<uint32_t> commonData; 92 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 93 sdbusplus::message::message method = 94 bus->new_method_call(service.c_str(), mdrv2Path, mdrv2Interface, 95 "SynchronizeDirectoryCommonData"); 96 method.append(idIndex, size); 97 98 try 99 { 100 sdbusplus::message::message reply = bus->call(method); 101 reply.read(commonData); 102 } 103 catch (sdbusplus::exception_t &e) 104 { 105 phosphor::logging::log<phosphor::logging::level::ERR>( 106 "Error sync dir common data with service", 107 phosphor::logging::entry("ERROR=%s", e.what())); 108 return -1; 109 } 110 111 if (commonData.size() < syncDirCommonSize) 112 { 113 phosphor::logging::log<phosphor::logging::level::ERR>( 114 "Error sync dir common data - data length invalid"); 115 return -1; 116 } 117 smbiosDir.dir[idIndex].common.dataSetSize = commonData.at(0); 118 smbiosDir.dir[idIndex].common.dataVersion = commonData.at(1); 119 smbiosDir.dir[idIndex].common.timestamp = commonData.at(2); 120 121 return 0; 122 } 123 124 int MDRV2::findDataId(const uint8_t *dataInfo, const size_t &len, 125 const std::string &service) 126 { 127 int idIndex = -1; 128 129 if (dataInfo == nullptr) 130 { 131 phosphor::logging::log<phosphor::logging::level::ERR>( 132 "Error dataInfo, input is null point"); 133 return -1; 134 } 135 136 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 137 sdbusplus::message::message method = bus->new_method_call( 138 service.c_str(), mdrv2Path, mdrv2Interface, "FindIdIndex"); 139 std::vector<uint8_t> info; 140 info.resize(len); 141 std::copy(dataInfo, dataInfo + len, info.data()); 142 method.append(info); 143 144 try 145 { 146 sdbusplus::message::message reply = bus->call(method); 147 reply.read(idIndex); 148 } 149 catch (sdbusplus::exception_t &e) 150 { 151 phosphor::logging::log<phosphor::logging::level::ERR>( 152 "Error find id index", 153 phosphor::logging::entry("ERROR=%s", e.what()), 154 phosphor::logging::entry("SERVICE=%s", service.c_str()), 155 phosphor::logging::entry("PATH=%s", mdrv2Path)); 156 return -1; 157 } 158 159 return idIndex; 160 } 161 162 uint16_t MDRV2::getSessionHandle(Mdr2DirStruct *dir) 163 { 164 if (dir == NULL) 165 { 166 phosphor::logging::log<phosphor::logging::level::ERR>( 167 "Empty dir point"); 168 return 0; 169 } 170 dir->sessionHandle++; 171 if (dir->sessionHandle == 0) 172 { 173 dir->sessionHandle = 1; 174 } 175 176 return dir->sessionHandle; 177 } 178 179 int MDRV2::findLockHandle(const uint16_t &lockHandle) 180 { 181 int idIndex = -1; 182 183 for (int index = 0; index < smbiosDir.dirEntries; index++) 184 { 185 if (lockHandle == smbiosDir.dir[index].lockHandle) 186 { 187 return index; 188 } 189 } 190 191 return idIndex; 192 } 193 194 bool MDRV2::smbiosIsUpdating(uint8_t index) 195 { 196 if (index > maxDirEntries) 197 { 198 return false; 199 } 200 if (smbiosDir.dir[index].stage == MDR2SMBIOSStatusEnum::mdr2Updating) 201 { 202 return true; 203 } 204 205 return false; 206 } 207 208 uint32_t MDRV2::calcChecksum32(uint8_t *buf, uint32_t len) 209 { 210 uint32_t sum = 0; 211 212 if (buf == nullptr) 213 { 214 return invalidChecksum; 215 } 216 217 for (uint32_t index = 0; index < len; index++) 218 { 219 sum += buf[index]; 220 } 221 222 return sum; 223 } 224 225 /** @brief implements mdr2 agent status command 226 * @param agentId 227 * @param dirVersion 228 * 229 * @returns IPMI completion code plus response data 230 * - mdrVersion 231 * - agentVersion 232 * - dirVersion 233 * - dirEntries 234 * - dataRequest 235 */ 236 ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t> 237 mdr2AgentStatus(uint16_t agentId, uint8_t dirVersion) 238 { 239 if (mdrv2 == nullptr) 240 { 241 mdrv2 = std::make_unique<MDRV2>(); 242 } 243 244 int agentIndex = mdrv2->agentLookup(agentId); 245 if (agentIndex == -1) 246 { 247 phosphor::logging::log<phosphor::logging::level::ERR>( 248 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 249 return ipmi::responseParmOutOfRange(); 250 } 251 252 constexpr uint8_t mdrVersion = mdr2Version; 253 constexpr uint8_t agentVersion = smbiosAgentVersion; 254 uint8_t dirVersionResp = mdrv2->smbiosDir.dirVersion; 255 uint8_t dirEntries = mdrv2->smbiosDir.dirEntries; 256 uint8_t dataRequest; 257 258 if (mdrv2->smbiosDir.remoteDirVersion != dirVersion) 259 { 260 mdrv2->smbiosDir.remoteDirVersion = dirVersion; 261 dataRequest = 262 static_cast<uint8_t>(DirDataRequestEnum::dirDataRequested); 263 } 264 else 265 { 266 dataRequest = 267 static_cast<uint8_t>(DirDataRequestEnum::dirDataNotRequested); 268 } 269 270 return ipmi::responseSuccess(mdrVersion, agentVersion, dirVersionResp, 271 dirEntries, dataRequest); 272 } 273 274 /** @brief implements mdr2 get directory command 275 * @param agentId 276 * @param dirIndex 277 * @returns IPMI completion code plus response data 278 * - dataOut 279 */ 280 ipmi::RspType<std::vector<uint8_t>> mdr2GetDir(uint16_t agentId, 281 uint8_t dirIndex) 282 { 283 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 284 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 285 286 if (mdrv2 == nullptr) 287 { 288 mdrv2 = std::make_unique<MDRV2>(); 289 } 290 291 int agentIndex = mdrv2->agentLookup(agentId); 292 if (agentIndex == -1) 293 { 294 phosphor::logging::log<phosphor::logging::level::ERR>( 295 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 296 return ipmi::responseParmOutOfRange(); 297 } 298 299 std::variant<uint8_t> value = 0; 300 if (0 != mdrv2->sdplusMdrv2GetProperty("DirectoryEntries", value, service)) 301 { 302 phosphor::logging::log<phosphor::logging::level::ERR>( 303 "Error getting DirEnries"); 304 return ipmi::responseUnspecifiedError(); 305 } 306 if (dirIndex > std::get<uint8_t>(value)) 307 { 308 return ipmi::responseParmOutOfRange(); 309 } 310 311 sdbusplus::message::message method = bus->new_method_call( 312 service.c_str(), mdrv2Path, mdrv2Interface, "GetDirectoryInformation"); 313 314 method.append(dirIndex); 315 316 std::vector<uint8_t> dataOut; 317 try 318 { 319 sdbusplus::message::message reply = bus->call(method); 320 reply.read(dataOut); 321 } 322 catch (sdbusplus::exception_t &e) 323 { 324 phosphor::logging::log<phosphor::logging::level::ERR>( 325 "Error get dir", phosphor::logging::entry("ERROR=%s", e.what()), 326 phosphor::logging::entry("SERVICE=%s", service.c_str()), 327 phosphor::logging::entry("PATH=%s", mdrv2Path)); 328 return ipmi::responseResponseError(); 329 } 330 331 constexpr size_t getDirRespSize = 6; 332 if (dataOut.size() < getDirRespSize) 333 { 334 phosphor::logging::log<phosphor::logging::level::ERR>( 335 "Error get dir, response length invalid"); 336 return ipmi::responseUnspecifiedError(); 337 } 338 339 if (dataOut.size() > MAX_IPMI_BUFFER) // length + completion code should no 340 // more than MAX_IPMI_BUFFER 341 { 342 phosphor::logging::log<phosphor::logging::level::ERR>( 343 "Data length send from service is invalid"); 344 return ipmi::responseResponseError(); 345 } 346 347 return ipmi::responseSuccess(dataOut); 348 } 349 350 ipmi::RspType<bool> mdr2SendDir(uint16_t agentId, uint8_t dirVersion, 351 uint8_t dirIndex, uint8_t returnedEntries, 352 uint8_t remainingEntries, 353 std::array<uint8_t, 16> dataInfo, uint32_t size, 354 uint32_t dataSetSize, uint32_t dataVersion, 355 uint32_t timestamp) 356 { 357 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 358 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 359 360 if (mdrv2 == nullptr) 361 { 362 mdrv2 = std::make_unique<MDRV2>(); 363 } 364 365 int agentIndex = mdrv2->agentLookup(agentId); 366 if (agentIndex == -1) 367 { 368 phosphor::logging::log<phosphor::logging::level::ERR>( 369 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 370 return ipmi::responseParmOutOfRange(); 371 } 372 373 if ((dirIndex + returnedEntries) > maxDirEntries) 374 { 375 phosphor::logging::log<phosphor::logging::level::ERR>( 376 "Too many directory entries"); 377 return ipmi::response(ccStorageLeak); 378 } 379 380 sdbusplus::message::message method = bus->new_method_call( 381 service.c_str(), mdrv2Path, mdrv2Interface, "SendDirectoryInformation"); 382 method.append(dirVersion, dirIndex, returnedEntries, remainingEntries, 383 dataInfo, size, dataSetSize, dataVersion, timestamp); 384 385 bool terminate = false; 386 try 387 { 388 sdbusplus::message::message reply = bus->call(method); 389 reply.read(terminate); 390 } 391 catch (sdbusplus::exception_t &e) 392 { 393 phosphor::logging::log<phosphor::logging::level::ERR>( 394 "Error send dir", phosphor::logging::entry("ERROR=%s", e.what()), 395 phosphor::logging::entry("SERVICE=%s", service.c_str()), 396 phosphor::logging::entry("PATH=%s", mdrv2Path)); 397 return ipmi::responseResponseError(); 398 } 399 400 return ipmi::responseSuccess(terminate); 401 } 402 403 /** @brief implements mdr2 get data info command 404 * @param agentId 405 * @param dataInfo 406 * 407 * @returns IPMI completion code plus response data 408 * - response - mdrVersion, data info, validFlag, 409 * dataLength, dataVersion, timeStamp 410 */ 411 ipmi::RspType<std::vector<uint8_t>> 412 mdr2GetDataInfo(uint16_t agentId, std::vector<uint8_t> dataInfo) 413 { 414 constexpr size_t getDataInfoReqSize = 16; 415 416 if (dataInfo.size() < getDataInfoReqSize) 417 { 418 return ipmi::responseReqDataLenInvalid(); 419 } 420 421 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 422 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 423 424 if (mdrv2 == nullptr) 425 { 426 mdrv2 = std::make_unique<MDRV2>(); 427 } 428 429 int agentIndex = mdrv2->agentLookup(agentId); 430 if (agentIndex == -1) 431 { 432 phosphor::logging::log<phosphor::logging::level::ERR>( 433 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 434 return ipmi::responseParmOutOfRange(); 435 } 436 437 int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service); 438 439 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 440 { 441 phosphor::logging::log<phosphor::logging::level::ERR>( 442 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 443 return ipmi::responseParmOutOfRange(); 444 } 445 446 sdbusplus::message::message method = bus->new_method_call( 447 service.c_str(), mdrv2Path, mdrv2Interface, "GetDataInformation"); 448 449 method.append(idIndex); 450 451 std::vector<uint8_t> res; 452 try 453 { 454 sdbusplus::message::message reply = bus->call(method); 455 reply.read(res); 456 } 457 catch (sdbusplus::exception_t &e) 458 { 459 phosphor::logging::log<phosphor::logging::level::ERR>( 460 "Error get data info", 461 phosphor::logging::entry("ERROR=%s", e.what()), 462 phosphor::logging::entry("SERVICE=%s", service.c_str()), 463 phosphor::logging::entry("PATH=%s", mdrv2Path)); 464 return ipmi::responseResponseError(); 465 } 466 467 if (res.size() != sizeof(MDRiiGetDataInfoResponse)) 468 { 469 phosphor::logging::log<phosphor::logging::level::ERR>( 470 "Get data info response length not invalid"); 471 return ipmi::responseResponseError(); 472 } 473 474 return ipmi::responseSuccess(res); 475 } 476 477 /** @brief implements mdr2 data info offer command 478 * @param agentId - Offer a agent ID to get the "Data Set ID" 479 * 480 * @returns IPMI completion code plus response data 481 * - dataOut - data Set Id 482 */ 483 ipmi::RspType<std::vector<uint8_t>> mdr2DataInfoOffer(uint16_t agentId) 484 { 485 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 486 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 487 488 if (mdrv2 == nullptr) 489 { 490 mdrv2 = std::make_unique<MDRV2>(); 491 } 492 493 int agentIndex = mdrv2->agentLookup(agentId); 494 if (agentIndex == -1) 495 { 496 phosphor::logging::log<phosphor::logging::level::ERR>( 497 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 498 return ipmi::responseParmOutOfRange(); 499 } 500 501 sdbusplus::message::message method = bus->new_method_call( 502 service.c_str(), mdrv2Path, mdrv2Interface, "GetDataOffer"); 503 504 std::vector<uint8_t> dataOut; 505 try 506 { 507 sdbusplus::message::message reply = bus->call(method); 508 reply.read(dataOut); 509 } 510 catch (sdbusplus::exception_t &e) 511 { 512 phosphor::logging::log<phosphor::logging::level::ERR>( 513 "Error send data info offer", 514 phosphor::logging::entry("ERROR=%s", e.what()), 515 phosphor::logging::entry("SERVICE=%s", service.c_str()), 516 phosphor::logging::entry("PATH=%s", mdrv2Path)); 517 return ipmi::responseResponseError(); 518 } 519 520 constexpr size_t respInfoSize = 16; 521 if (dataOut.size() != respInfoSize) 522 { 523 phosphor::logging::log<phosphor::logging::level::ERR>( 524 "Error send data info offer, return length invalid"); 525 return ipmi::responseUnspecifiedError(); 526 } 527 528 return ipmi::responseSuccess(dataOut); 529 } 530 531 /** @brief implements mdr2 send data info command 532 * @param agentId 533 * @param dataInfo 534 * @param validFlag 535 * @param dataLength 536 * @param dataVersion 537 * @param timeStamp 538 * 539 * @returns IPMI completion code plus response data 540 * - bool 541 */ 542 ipmi::RspType<bool> mdr2SendDataInfo(uint16_t agentId, 543 std::array<uint8_t, dataInfoSize> dataInfo, 544 uint8_t validFlag, uint32_t dataLength, 545 uint32_t dataVersion, uint32_t timeStamp) 546 { 547 if (dataLength > smbiosTableStorageSize) 548 { 549 phosphor::logging::log<phosphor::logging::level::ERR>( 550 "Requested data length is out of SMBIOS Table storage size."); 551 return ipmi::responseParmOutOfRange(); 552 } 553 554 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 555 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 556 557 if (mdrv2 == nullptr) 558 { 559 mdrv2 = std::make_unique<MDRV2>(); 560 } 561 562 int agentIndex = mdrv2->agentLookup(agentId); 563 if (agentIndex == -1) 564 { 565 phosphor::logging::log<phosphor::logging::level::ERR>( 566 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 567 return ipmi::responseParmOutOfRange(); 568 } 569 570 int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service); 571 572 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 573 { 574 phosphor::logging::log<phosphor::logging::level::ERR>( 575 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 576 return ipmi::responseParmOutOfRange(); 577 } 578 579 sdbusplus::message::message method = bus->new_method_call( 580 service.c_str(), mdrv2Path, mdrv2Interface, "SendDataInformation"); 581 582 method.append((uint8_t)idIndex, validFlag, dataLength, dataVersion, 583 timeStamp); 584 585 bool entryChanged = true; 586 try 587 { 588 sdbusplus::message::message reply = bus->call(method); 589 reply.read(entryChanged); 590 } 591 catch (sdbusplus::exception_t &e) 592 { 593 phosphor::logging::log<phosphor::logging::level::ERR>( 594 "Error send data info", 595 phosphor::logging::entry("ERROR=%s", e.what()), 596 phosphor::logging::entry("SERVICE=%s", service.c_str()), 597 phosphor::logging::entry("PATH=%s", mdrv2Path)); 598 return ipmi::responseResponseError(); 599 } 600 601 return ipmi::responseSuccess(entryChanged); 602 } 603 604 /** 605 @brief This command is MDR related get data block command. 606 607 @param - agentId 608 @param - lockHandle 609 @param - xferOffset 610 @param - xferLength 611 612 @return on success 613 - xferLength 614 - checksum 615 - data 616 **/ 617 ipmi::RspType<uint32_t, // xferLength 618 uint32_t, // Checksum 619 std::vector<uint8_t> // data 620 > 621 mdr2GetDataBlock(uint16_t agentId, uint16_t lockHandle, uint32_t xferOffset, 622 uint32_t xferLength) 623 { 624 if (mdrv2 == nullptr) 625 { 626 mdrv2 = std::make_unique<MDRV2>(); 627 } 628 629 int agentIndex = mdrv2->agentLookup(agentId); 630 if (agentIndex == -1) 631 { 632 phosphor::logging::log<phosphor::logging::level::ERR>( 633 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 634 return ipmi::responseParmOutOfRange(); 635 } 636 637 int idIndex = mdrv2->findLockHandle(lockHandle); 638 639 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 640 { 641 phosphor::logging::log<phosphor::logging::level::ERR>( 642 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 643 return ipmi::responseParmOutOfRange(); 644 } 645 646 if (xferOffset >= mdrv2->smbiosDir.dir[idIndex].common.size) 647 { 648 phosphor::logging::log<phosphor::logging::level::ERR>( 649 "Offset is outside of range."); 650 return ipmi::responseParmOutOfRange(); 651 } 652 653 size_t outSize = (xferLength > mdrv2->smbiosDir.dir[idIndex].xferSize) 654 ? mdrv2->smbiosDir.dir[idIndex].xferSize 655 : xferLength; 656 if (outSize > UINT_MAX - xferOffset) 657 { 658 phosphor::logging::log<phosphor::logging::level::ERR>( 659 "Out size and offset are out of range"); 660 return ipmi::responseParmOutOfRange(); 661 } 662 if ((xferOffset + outSize) > mdrv2->smbiosDir.dir[idIndex].common.size) 663 { 664 outSize = mdrv2->smbiosDir.dir[idIndex].common.size - xferOffset; 665 } 666 667 uint32_t respXferLength = outSize; 668 669 if (respXferLength > xferLength) 670 { 671 phosphor::logging::log<phosphor::logging::level::ERR>( 672 "Get data block unexpected error."); 673 return ipmi::responseUnspecifiedError(); 674 } 675 676 if ((xferOffset + outSize) > 677 UINT_MAX - 678 reinterpret_cast<size_t>(mdrv2->smbiosDir.dir[idIndex].dataStorage)) 679 { 680 phosphor::logging::log<phosphor::logging::level::ERR>( 681 "Input data to calculate checksum is out of range"); 682 return ipmi::responseParmOutOfRange(); 683 } 684 685 uint32_t u32Checksum = mdrv2->calcChecksum32( 686 mdrv2->smbiosDir.dir[idIndex].dataStorage + xferOffset, outSize); 687 if (u32Checksum == invalidChecksum) 688 { 689 phosphor::logging::log<phosphor::logging::level::ERR>( 690 "Get data block failed - invalid checksum"); 691 return ipmi::response(ccOemInvalidChecksum); 692 } 693 std::vector<uint8_t> data(outSize); 694 695 std::copy(&mdrv2->smbiosDir.dir[idIndex].dataStorage[xferOffset], 696 &mdrv2->smbiosDir.dir[idIndex].dataStorage[xferOffset + outSize], 697 data.begin()); 698 699 return ipmi::responseSuccess(respXferLength, u32Checksum, data); 700 } 701 702 /** @brief implements mdr2 send data block command 703 * @param agentId 704 * @param lockHandle 705 * @param xferOffset 706 * @param xferLength 707 * @param checksum 708 * 709 * @returns IPMI completion code 710 */ 711 ipmi::RspType<> mdr2SendDataBlock(uint16_t agentId, uint16_t lockHandle, 712 uint32_t xferOffset, uint32_t xferLength, 713 uint32_t checksum) 714 { 715 716 if (mdrv2 == nullptr) 717 { 718 mdrv2 = std::make_unique<MDRV2>(); 719 } 720 721 int agentIndex = mdrv2->agentLookup(agentId); 722 if (agentIndex == -1) 723 { 724 phosphor::logging::log<phosphor::logging::level::ERR>( 725 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 726 return ipmi::responseParmOutOfRange(); 727 } 728 729 int idIndex = mdrv2->findLockHandle(lockHandle); 730 731 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 732 { 733 phosphor::logging::log<phosphor::logging::level::ERR>( 734 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 735 return ipmi::responseParmOutOfRange(); 736 } 737 738 if (mdrv2->smbiosIsUpdating(idIndex)) 739 { 740 if (xferOffset > UINT_MAX - xferLength) 741 { 742 phosphor::logging::log<phosphor::logging::level::ERR>( 743 "Offset and length are out of range"); 744 return ipmi::responseParmOutOfRange(); 745 } 746 if (((xferOffset + xferLength) > 747 mdrv2->smbiosDir.dir[idIndex].maxDataSize) || 748 ((xferOffset + xferLength) > 749 mdrv2->smbiosDir.dir[idIndex].common.dataSetSize)) 750 { 751 phosphor::logging::log<phosphor::logging::level::ERR>( 752 "Send data block Invalid offset/length"); 753 return ipmi::responseReqDataLenExceeded(); 754 } 755 if (reinterpret_cast<size_t>( 756 mdrv2->smbiosDir.dir[idIndex].dataStorage) > 757 UINT_MAX - xferOffset) 758 { 759 phosphor::logging::log<phosphor::logging::level::ERR>( 760 "Offset is out of range"); 761 return ipmi::responseParmOutOfRange(); 762 } 763 uint8_t *destAddr = 764 mdrv2->smbiosDir.dir[idIndex].dataStorage + xferOffset; 765 uint8_t *sourceAddr = reinterpret_cast<uint8_t *>(mdrv2->area->vPtr); 766 uint32_t calcChecksum = mdrv2->calcChecksum32(sourceAddr, xferLength); 767 if (calcChecksum != checksum) 768 { 769 phosphor::logging::log<phosphor::logging::level::ERR>( 770 "Send data block Invalid checksum"); 771 return ipmi::response(ccOemInvalidChecksum); 772 } 773 else 774 { 775 if (reinterpret_cast<size_t>(sourceAddr) > UINT_MAX - xferLength) 776 { 777 phosphor::logging::log<phosphor::logging::level::ERR>( 778 "Length is out of range"); 779 return ipmi::responseParmOutOfRange(); 780 } 781 std::copy(sourceAddr, sourceAddr + xferLength, destAddr); 782 } 783 } 784 else 785 { 786 phosphor::logging::log<phosphor::logging::level::ERR>( 787 "Send data block failed, other data is updating"); 788 return ipmi::responseDestinationUnavailable(); 789 } 790 791 return ipmi::responseSuccess(); 792 } 793 794 bool MDRV2::storeDatatoFlash(MDRSMBIOSHeader *mdrHdr, uint8_t *data) 795 { 796 std::ofstream smbiosFile(mdrType2File, 797 std::ios_base::binary | std::ios_base::trunc); 798 if (!smbiosFile.good()) 799 { 800 phosphor::logging::log<phosphor::logging::level::ERR>( 801 "Write data from flash error - Open MDRV2 table file failure"); 802 return false; 803 } 804 805 try 806 { 807 smbiosFile.write(reinterpret_cast<char *>(mdrHdr), 808 sizeof(MDRSMBIOSHeader)); 809 smbiosFile.write(reinterpret_cast<char *>(data), mdrHdr->dataSize); 810 } 811 catch (std::ofstream::failure &e) 812 { 813 phosphor::logging::log<phosphor::logging::level::ERR>( 814 "Write data from flash error - write data error", 815 phosphor::logging::entry("ERROR=%s", e.what())); 816 return false; 817 } 818 819 return true; 820 } 821 822 void SharedMemoryArea::Initialize(uint32_t addr, uint32_t areaSize) 823 { 824 int memDriver = 0; 825 826 // open mem driver for the system memory access 827 memDriver = open("/dev/vgasharedmem", O_RDONLY); 828 if (memDriver < 0) 829 { 830 phosphor::logging::log<phosphor::logging::level::ERR>( 831 "Cannot access mem driver"); 832 throw std::system_error(EIO, std::generic_category()); 833 } 834 835 // map the system memory 836 vPtr = mmap(NULL, // where to map to: don't mind 837 areaSize, // how many bytes ? 838 PROT_READ, // want to read and write 839 MAP_SHARED, // no copy on write 840 memDriver, // handle to /dev/mem 841 (physicalAddr & pageMask)); // hopefully the Text-buffer :-) 842 843 close(memDriver); 844 if (vPtr == MAP_FAILED) 845 { 846 phosphor::logging::log<phosphor::logging::level::ERR>( 847 "Failed to map share memory"); 848 throw std::system_error(EIO, std::generic_category()); 849 } 850 size = areaSize; 851 physicalAddr = addr; 852 } 853 854 bool MDRV2::smbiosUnlock(uint8_t index) 855 { 856 bool ret; 857 switch (smbiosDir.dir[index].stage) 858 { 859 case MDR2SMBIOSStatusEnum::mdr2Updating: 860 smbiosDir.dir[index].stage = MDR2SMBIOSStatusEnum::mdr2Updated; 861 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock; 862 863 timer->stop(); 864 smbiosDir.dir[index].lockHandle = 0; 865 ret = true; 866 break; 867 868 case MDR2SMBIOSStatusEnum::mdr2Updated: 869 case MDR2SMBIOSStatusEnum::mdr2Loaded: 870 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock; 871 872 timer->stop(); 873 874 smbiosDir.dir[index].lockHandle = 0; 875 ret = true; 876 break; 877 878 default: 879 break; 880 } 881 882 return ret; 883 } 884 885 bool MDRV2::smbiosTryLock(uint8_t flag, uint8_t index, uint16_t *session, 886 uint16_t timeout) 887 { 888 bool ret = false; 889 uint32_t u32Status = 0; 890 891 if (timeout == 0) 892 { 893 timeout = defaultTimeout; 894 } 895 std::chrono::microseconds usec(timeout * sysClock); 896 897 switch (smbiosDir.dir[index].stage) 898 { 899 case MDR2SMBIOSStatusEnum::mdr2Updating: 900 if (smbiosDir.dir[index].lock != MDR2DirLockEnum::mdr2DirLock) 901 { 902 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirLock; 903 timer->start(usec); 904 lockIndex = index; 905 906 *session = getSessionHandle(&smbiosDir); 907 smbiosDir.dir[index].lockHandle = *session; 908 ret = true; 909 } 910 break; 911 case MDR2SMBIOSStatusEnum::mdr2Init: 912 if (flag) 913 { 914 smbiosDir.dir[index].stage = MDR2SMBIOSStatusEnum::mdr2Updating; 915 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock; 916 timer->start(usec); 917 lockIndex = index; 918 919 *session = getSessionHandle(&smbiosDir); 920 smbiosDir.dir[index].lockHandle = *session; 921 ret = true; 922 } 923 break; 924 925 case MDR2SMBIOSStatusEnum::mdr2Updated: 926 case MDR2SMBIOSStatusEnum::mdr2Loaded: 927 if (smbiosDir.dir[index].lock != MDR2DirLockEnum::mdr2DirLock) 928 { 929 if (flag) 930 { 931 smbiosDir.dir[index].stage = 932 MDR2SMBIOSStatusEnum::mdr2Updating; 933 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock; 934 } 935 else 936 { 937 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirLock; 938 } 939 940 timer->start(usec); 941 lockIndex = index; 942 943 *session = getSessionHandle(&smbiosDir); 944 smbiosDir.dir[index].lockHandle = *session; 945 ret = true; 946 } 947 break; 948 949 default: 950 break; 951 } 952 return ret; 953 } 954 955 void MDRV2::timeoutHandler() 956 { 957 smbiosUnlock(lockIndex); 958 mdrv2->area.reset(nullptr); 959 } 960 961 /** @brief implements mdr2 lock data command 962 * @param agentId 963 * @param dataInfo 964 * @param timeout 965 * 966 * @returns IPMI completion code plus response data 967 * - mdr2Version 968 * - session 969 * - dataLength 970 * - xferAddress 971 * - xferLength 972 */ 973 ipmi::RspType<uint8_t, // mdr2Version 974 uint16_t, // session 975 uint32_t, // dataLength 976 uint32_t, // xferAddress 977 uint32_t // xferLength 978 > 979 mdr2LockData(uint16_t agentId, std::array<uint8_t, dataInfoSize> dataInfo, 980 uint16_t timeout) 981 { 982 if (mdrv2 == nullptr) 983 { 984 mdrv2 = std::make_unique<MDRV2>(); 985 } 986 987 int agentIndex = mdrv2->agentLookup(agentId); 988 if (agentIndex == -1) 989 { 990 phosphor::logging::log<phosphor::logging::level::ERR>( 991 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 992 return ipmi::responseParmOutOfRange(); 993 } 994 995 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 996 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 997 998 int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service); 999 1000 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 1001 { 1002 phosphor::logging::log<phosphor::logging::level::ERR>( 1003 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 1004 return ipmi::responseParmOutOfRange(); 1005 } 1006 1007 uint16_t session = 0; 1008 if (!mdrv2->smbiosTryLock(0, idIndex, &session, timeout)) 1009 { 1010 phosphor::logging::log<phosphor::logging::level::ERR>( 1011 "Lock Data failed - cannot lock idIndex"); 1012 return ipmi::responseCommandNotAvailable(); 1013 } 1014 1015 uint32_t dataLength = mdrv2->smbiosDir.dir[idIndex].common.size; 1016 uint32_t xferAddress = mdrv2->smbiosDir.dir[idIndex].xferBuff; 1017 uint32_t xferLength = mdrv2->smbiosDir.dir[idIndex].xferSize; 1018 1019 return ipmi::responseSuccess(mdr2Version, session, dataLength, xferAddress, 1020 xferLength); 1021 } 1022 1023 /** @brief implements mdr2 unlock data command 1024 * @param agentId 1025 * @param lockHandle 1026 * 1027 * @returns IPMI completion code 1028 */ 1029 ipmi::RspType<> mdr2UnlockData(uint16_t agentId, uint16_t lockHandle) 1030 { 1031 phosphor::logging::log<phosphor::logging::level::ERR>("unlock data"); 1032 1033 if (mdrv2 == nullptr) 1034 { 1035 mdrv2 = std::make_unique<MDRV2>(); 1036 } 1037 1038 int agentIndex = mdrv2->agentLookup(agentId); 1039 if (agentIndex == -1) 1040 { 1041 phosphor::logging::log<phosphor::logging::level::ERR>( 1042 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 1043 return ipmi::responseParmOutOfRange(); 1044 } 1045 1046 int idIndex = mdrv2->findLockHandle(lockHandle); 1047 1048 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 1049 { 1050 phosphor::logging::log<phosphor::logging::level::ERR>( 1051 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 1052 return ipmi::responseParmOutOfRange(); 1053 } 1054 1055 if (!mdrv2->smbiosUnlock(idIndex)) 1056 { 1057 phosphor::logging::log<phosphor::logging::level::ERR>( 1058 "Unlock Data failed - cannot unlock idIndex"); 1059 return ipmi::responseCommandNotAvailable(); 1060 } 1061 1062 return ipmi::responseSuccess(); 1063 } 1064 1065 /** 1066 @brief This command is executed after POST BIOS to get the session info. 1067 1068 @param - agentId, dataInfo, dataLength, xferAddress, xferLength, timeout. 1069 1070 @return xferStartAck and session on success. 1071 **/ 1072 ipmi::RspType<uint8_t, uint16_t> 1073 cmd_mdr2_data_start(uint16_t agentId, std::array<uint8_t, 16> dataInfo, 1074 uint32_t dataLength, uint32_t xferAddress, 1075 uint32_t xferLength, uint16_t timeout) 1076 { 1077 uint16_t session = 0; 1078 1079 if (dataLength > smbiosTableStorageSize) 1080 { 1081 phosphor::logging::log<phosphor::logging::level::ERR>( 1082 "Requested data length is out of SMBIOS Table storage size."); 1083 return ipmi::responseParmOutOfRange(); 1084 } 1085 if ((xferLength + xferAddress) > mdriiSMSize) 1086 { 1087 phosphor::logging::log<phosphor::logging::level::ERR>( 1088 "Invalid data address and size"); 1089 return ipmi::responseParmOutOfRange(); 1090 } 1091 1092 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 1093 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 1094 1095 if (mdrv2 == nullptr) 1096 { 1097 mdrv2 = std::make_unique<MDRV2>(); 1098 } 1099 1100 int agentIndex = mdrv2->agentLookup(agentId); 1101 if (agentIndex == -1) 1102 { 1103 phosphor::logging::log<phosphor::logging::level::ERR>( 1104 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 1105 return ipmi::responseParmOutOfRange(); 1106 } 1107 1108 int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service); 1109 1110 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 1111 { 1112 phosphor::logging::log<phosphor::logging::level::ERR>( 1113 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 1114 return ipmi::responseParmOutOfRange(); 1115 } 1116 1117 if (mdrv2->smbiosTryLock(1, idIndex, &session, timeout)) 1118 { 1119 try 1120 { 1121 mdrv2->area = 1122 std::make_unique<SharedMemoryArea>(xferAddress, xferLength); 1123 } 1124 catch (const std::system_error &e) 1125 { 1126 mdrv2->smbiosUnlock(idIndex); 1127 phosphor::logging::log<phosphor::logging::level::ERR>( 1128 "Unable to access share memory", 1129 phosphor::logging::entry("ERROR=%s", e.what())); 1130 return ipmi::responseUnspecifiedError(); 1131 } 1132 mdrv2->smbiosDir.dir[idIndex].common.size = dataLength; 1133 mdrv2->smbiosDir.dir[idIndex].lockHandle = session; 1134 if (-1 == 1135 mdrv2->syncDirCommonData( 1136 idIndex, mdrv2->smbiosDir.dir[idIndex].common.size, service)) 1137 { 1138 phosphor::logging::log<phosphor::logging::level::ERR>( 1139 "Unable to sync data to service"); 1140 return ipmi::responseResponseError(); 1141 } 1142 } 1143 else 1144 { 1145 phosphor::logging::log<phosphor::logging::level::ERR>( 1146 "Canot lock smbios"); 1147 return ipmi::responseUnspecifiedError(); 1148 } 1149 1150 static constexpr uint8_t xferStartAck = 1; 1151 1152 return ipmi::responseSuccess(xferStartAck, session); 1153 } 1154 1155 /** 1156 @brief This command is executed to close the session. 1157 1158 @param - agentId, lockHandle. 1159 1160 @return completion code on success. 1161 **/ 1162 ipmi::RspType<> cmd_mdr2_data_done(uint16_t agentId, uint16_t lockHandle) 1163 { 1164 1165 if (mdrv2 == nullptr) 1166 { 1167 mdrv2 = std::make_unique<MDRV2>(); 1168 } 1169 1170 int agentIndex = mdrv2->agentLookup(agentId); 1171 if (agentIndex == -1) 1172 { 1173 phosphor::logging::log<phosphor::logging::level::ERR>( 1174 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 1175 return ipmi::responseParmOutOfRange(); 1176 } 1177 1178 int idIndex = mdrv2->findLockHandle(lockHandle); 1179 1180 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 1181 { 1182 phosphor::logging::log<phosphor::logging::level::ERR>( 1183 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 1184 return ipmi::responseParmOutOfRange(); 1185 } 1186 1187 if (!mdrv2->smbiosUnlock(idIndex)) 1188 { 1189 phosphor::logging::log<phosphor::logging::level::ERR>( 1190 "Send data done failed - cannot unlock idIndex"); 1191 return ipmi::responseDestinationUnavailable(); 1192 } 1193 1194 mdrv2->area.reset(nullptr); 1195 MDRSMBIOSHeader mdr2Smbios; 1196 mdr2Smbios.mdrType = mdrTypeII; 1197 mdr2Smbios.dirVer = mdrv2->smbiosDir.dir[0].common.dataVersion; 1198 mdr2Smbios.timestamp = mdrv2->smbiosDir.dir[0].common.timestamp; 1199 mdr2Smbios.dataSize = mdrv2->smbiosDir.dir[0].common.size; 1200 1201 if (access(smbiosPath, 0) == -1) 1202 { 1203 int flag = mkdir(smbiosPath, S_IRWXU); 1204 if (flag != 0) 1205 { 1206 phosphor::logging::log<phosphor::logging::level::ERR>( 1207 "create folder failed for writting smbios file"); 1208 } 1209 } 1210 if (!mdrv2->storeDatatoFlash( 1211 &mdr2Smbios, mdrv2->smbiosDir.dir[smbiosDirIndex].dataStorage)) 1212 { 1213 phosphor::logging::log<phosphor::logging::level::ERR>( 1214 "MDR2 Store data to flash failed"); 1215 return ipmi::responseDestinationUnavailable(); 1216 } 1217 bool status = false; 1218 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 1219 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 1220 sdbusplus::message::message method = bus->new_method_call( 1221 service.c_str(), mdrv2Path, mdrv2Interface, "AgentSynchronizeData"); 1222 1223 try 1224 { 1225 sdbusplus::message::message reply = bus->call(method); 1226 reply.read(status); 1227 } 1228 catch (sdbusplus::exception_t &e) 1229 { 1230 phosphor::logging::log<phosphor::logging::level::ERR>( 1231 "Error Sync data with service", 1232 phosphor::logging::entry("ERROR=%s", e.what()), 1233 phosphor::logging::entry("SERVICE=%s", service.c_str()), 1234 phosphor::logging::entry("PATH=%s", mdrv2Path)); 1235 return ipmi::responseResponseError(); 1236 } 1237 1238 if (!status) 1239 { 1240 phosphor::logging::log<phosphor::logging::level::ERR>( 1241 "Sync data with service failure"); 1242 return ipmi::responseUnspecifiedError(); 1243 } 1244 1245 return ipmi::responseSuccess(); 1246 } 1247 1248 static void register_netfn_smbiosmdrv2_functions(void) 1249 { 1250 // MDR V2 Command 1251 // <Get MDRII Status Command> 1252 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1253 ipmi::intel::app::cmdMdrIIAgentStatus, 1254 ipmi::Privilege::Operator, mdr2AgentStatus); 1255 1256 // <Get MDRII Directory Command> 1257 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1258 ipmi::intel::app::cmdMdrIIGetDir, 1259 ipmi::Privilege::Operator, mdr2GetDir); 1260 1261 // <Send MDRII Directory Command> 1262 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1263 ipmi::intel::app::cmdMdrIISendDir, 1264 ipmi::Privilege::Operator, mdr2SendDir); 1265 1266 // <Get MDRII Data Info Command> 1267 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1268 ipmi::intel::app::cmdMdrIIGetDataInfo, 1269 ipmi::Privilege::Operator, mdr2GetDataInfo); 1270 1271 // <Send MDRII Info Offer> 1272 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1273 ipmi::intel::app::cmdMdrIISendDataInfoOffer, 1274 ipmi::Privilege::Operator, mdr2DataInfoOffer); 1275 1276 // <Send MDRII Data Info> 1277 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1278 ipmi::intel::app::cmdMdrIISendDataInfo, 1279 ipmi::Privilege::Operator, mdr2SendDataInfo); 1280 1281 // <Get MDRII Data Block Command> 1282 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1283 ipmi::intel::app::cmdMdrIIGetDataBlock, 1284 ipmi::Privilege::Operator, mdr2GetDataBlock); 1285 1286 // <Send MDRII Data Block> 1287 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1288 ipmi::intel::app::cmdMdrIISendDataBlock, 1289 ipmi::Privilege::Operator, mdr2SendDataBlock); 1290 1291 // <Lock MDRII Data Command> 1292 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1293 ipmi::intel::app::cmdMdrIILockData, 1294 ipmi::Privilege::Operator, mdr2LockData); 1295 1296 // <Unlock MDRII Data Command> 1297 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1298 ipmi::intel::app::cmdMdrIIUnlockData, 1299 ipmi::Privilege::Operator, mdr2UnlockData); 1300 1301 // <Send MDRII Data Start> 1302 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1303 ipmi::intel::app::cmdMdrIIDataStart, 1304 ipmi::Privilege::Operator, cmd_mdr2_data_start); 1305 1306 // <Send MDRII Data Done> 1307 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1308 ipmi::intel::app::cmdMdrIIDataDone, 1309 ipmi::Privilege::Operator, cmd_mdr2_data_done); 1310 } 1311