1 /* 2 * Copyright (c) 2018-present Facebook. All Rights Reserved. 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 <commandutils.hpp> 18 #include <usb-dbg.hpp> 19 20 namespace ipmi 21 { 22 23 ipmi_ret_t getNetworkData(uint8_t lan_param, char* data); 24 int8_t getFruData(std::string& serial, std::string& name); 25 int8_t sysConfig(std::vector<std::string>& data, size_t pos); 26 int8_t procInfo(std::string& result, size_t pos); 27 28 bool isMultiHostPlatform(); 29 30 /* Declare Host Selector interface and path */ 31 namespace selector 32 { 33 const std::string path = "/xyz/openbmc_project/Chassis/Buttons/HostSelector"; 34 const std::string interface = 35 "xyz.openbmc_project.Chassis.Buttons.HostSelector"; 36 } // namespace selector 37 38 /* Declare storage functions used here */ 39 namespace storage 40 { 41 int getSensorValue(std::string&, double&); 42 int getSensorUnit(std::string&, std::string&); 43 int getSensorThreshold(std::string&, std::string&); 44 } // namespace storage 45 46 void getMaxHostPosition(size_t& maxPosition) 47 { 48 try 49 { 50 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 51 std::string service = getService(*dbus, ipmi::selector::interface, 52 ipmi::selector::path); 53 Value variant = getDbusProperty(*dbus, service, ipmi::selector::path, 54 ipmi::selector::interface, 55 "MaxPosition"); 56 maxPosition = std::get<size_t>(variant); 57 } 58 catch (const std::exception& e) 59 { 60 lg2::error("Unable to get max host position - {MAXPOSITION}", 61 "MAXPOSITION", maxPosition); 62 throw e; 63 } 64 } 65 66 void getSelectorPosition(size_t& hostPosition) 67 { 68 try 69 { 70 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 71 std::string service = getService(*dbus, ipmi::selector::interface, 72 ipmi::selector::path); 73 Value variant = getDbusProperty(*dbus, service, ipmi::selector::path, 74 ipmi::selector::interface, "Position"); 75 hostPosition = std::get<size_t>(variant); 76 } 77 catch (const std::exception& e) 78 { 79 lg2::error("Unable to get host position - {POSITION}", "POSITION", 80 hostPosition); 81 throw e; 82 } 83 } 84 85 static int panelNum = (sizeof(panels) / sizeof(struct ctrl_panel)) - 1; 86 87 /* Returns the FRU the hand-switch is switched to. If it is switched to BMC 88 * it returns FRU_ALL. Note, if in err, it returns FRU_ALL */ 89 static size_t plat_get_fru_sel() 90 { 91 size_t position; 92 bool platform = isMultiHostPlatform(); 93 if (platform == true) 94 { 95 getSelectorPosition(position); 96 if (position == BMC_POSITION) 97 { 98 return FRU_ALL; 99 } 100 } 101 else 102 { 103 /* For Tiogapass it just return 1, 104 * can modify to support more platform */ 105 position = 1; 106 } 107 return position; 108 } 109 110 // return 0 on seccuess 111 int frame::init(size_t size) 112 { 113 // Reset status 114 idx_head = idx_tail = 0; 115 lines = 0; 116 esc_sts = 0; 117 pages = 1; 118 119 if (buf != NULL && max_size == size) 120 { 121 // reinit 122 return 0; 123 } 124 125 if (buf != NULL && max_size != size) 126 { 127 delete[] buf; 128 } 129 // Initialize Configuration 130 title[0] = '\0'; 131 buf = new char[size]; 132 max_size = size; 133 max_page = size; 134 line_per_page = 7; 135 line_width = 16; 136 overwrite = 0; 137 138 if (buf) 139 return 0; 140 else 141 return -1; 142 } 143 144 // return 0 on seccuess 145 int frame::append(const char* string, int indent) 146 { 147 const size_t buf_size = 128; 148 char lbuf[buf_size]; 149 char* ptr; 150 int ret; 151 152 ret = parse(lbuf, buf_size, string, indent); 153 154 if (ret < 0) 155 return ret; 156 157 for (ptr = lbuf; *ptr != '\0'; ptr++) 158 { 159 if (isFull()) 160 { 161 if (overwrite) 162 { 163 if (buf[idx_head] == LINE_DELIMITER) 164 lines--; 165 idx_head = (idx_head + 1) % max_size; 166 } 167 else 168 return -1; 169 } 170 171 buf[idx_tail] = *ptr; 172 if (*ptr == LINE_DELIMITER) 173 lines++; 174 175 idx_tail = (idx_tail + 1) % max_size; 176 } 177 178 pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0); 179 180 if (pages > max_page) 181 pages = max_page; 182 183 return 0; 184 } 185 186 // return 0 on seccuess 187 int frame::insert(const char* string, int indent) 188 { 189 const size_t buf_size = 128; 190 char lbuf[buf_size]; 191 char* ptr; 192 int ret; 193 int i; 194 195 ret = parse(lbuf, buf_size, string, indent); 196 197 if (ret < 0) 198 return ret; 199 200 for (i = strlen(lbuf) - 1; i >= 0; i--) 201 { 202 ptr = &lbuf[i]; 203 if (isFull()) 204 { 205 if (overwrite) 206 { 207 idx_tail = (idx_tail + max_size - 1) % max_size; 208 if (buf[idx_tail] == LINE_DELIMITER) 209 lines--; 210 } 211 else 212 return -1; 213 } 214 215 idx_head = (idx_head + max_size - 1) % max_size; 216 217 buf[idx_head] = *ptr; 218 if (*ptr == LINE_DELIMITER) 219 lines++; 220 } 221 222 pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0); 223 224 if (pages > max_page) 225 pages = max_page; 226 227 return 0; 228 } 229 230 // return page size 231 int frame::getPage(int page, char* page_buf, size_t page_buf_size) 232 { 233 int ret; 234 uint16_t line = 0; 235 uint16_t idx, len; 236 237 if (buf == NULL) 238 return -1; 239 240 // 1-based page 241 if (page > pages || page < 1) 242 return -1; 243 244 if (page_buf == NULL || page_buf_size == 0) 245 return -1; 246 247 ret = snprintf(page_buf, 17, "%-10s %02d/%02d", title, page, pages); 248 len = strlen(page_buf); 249 if (ret < 0) 250 return -1; 251 252 line = 0; 253 idx = idx_head; 254 while (line < ((page - 1) * line_per_page) && idx != idx_tail) 255 { 256 if (buf[idx] == LINE_DELIMITER) 257 line++; 258 idx = (idx + 1) % max_size; 259 } 260 261 while (line < ((page)*line_per_page) && idx != idx_tail) 262 { 263 if (buf[idx] == LINE_DELIMITER) 264 { 265 line++; 266 } 267 else 268 { 269 page_buf[len++] = buf[idx]; 270 if (len == (page_buf_size - 1)) 271 { 272 break; 273 } 274 } 275 idx = (idx + 1) % max_size; 276 } 277 278 return len; 279 } 280 281 // return 1 for frame buffer full 282 int frame::isFull() 283 { 284 if (buf == NULL) 285 return -1; 286 287 if ((idx_tail + 1) % max_size == idx_head) 288 return 1; 289 else 290 return 0; 291 } 292 293 // return 1 for Escape Sequence 294 int frame::isEscSeq(char chr) 295 { 296 uint8_t curr_sts = esc_sts; 297 298 if (esc_sts == 0 && (chr == 0x1b)) 299 esc_sts = 1; // Escape Sequence 300 else if (esc_sts == 1 && (chr == 0x5b)) 301 esc_sts = 2; // Control Sequence Introducer(CSI) 302 else if (esc_sts == 1 && (chr != 0x5b)) 303 esc_sts = 0; 304 else if (esc_sts == 2 && (chr >= 0x40 && chr <= 0x7e)) 305 esc_sts = 0; 306 307 if (curr_sts || esc_sts) 308 return 1; 309 else 310 return 0; 311 } 312 313 // return 0 on success 314 int frame::parse(char* lbuf, size_t buf_size, const char* input, int indent) 315 { 316 uint8_t pos, esc; 317 size_t i; 318 const char *in, *end; 319 320 if (buf == NULL || input == NULL) 321 return -1; 322 323 if (indent >= line_width || indent < 0) 324 return -1; 325 326 in = input; 327 end = in + strlen(input); 328 pos = 0; // line position 329 esc = 0; // escape state 330 i = 0; // buf index 331 while (in != end) 332 { 333 if (i >= buf_size) 334 break; 335 336 if (pos < indent) 337 { 338 // fill indent 339 lbuf[i++] = ' '; 340 pos++; 341 continue; 342 } 343 344 esc = isEscSeq(*in); 345 346 if (!esc && pos == line_width) 347 { 348 lbuf[i++] = LINE_DELIMITER; 349 pos = 0; 350 continue; 351 } 352 353 if (!esc) 354 pos++; 355 356 // fill input data 357 lbuf[i++] = *(in++); 358 } 359 360 // padding 361 while (pos <= line_width) 362 { 363 if (i >= buf_size) 364 break; 365 if (pos < line_width) 366 lbuf[i++] = ' '; 367 else 368 lbuf[i++] = LINE_DELIMITER; 369 pos++; 370 } 371 372 // full 373 if (i >= buf_size) 374 return -1; 375 376 lbuf[i++] = '\0'; 377 378 return 0; 379 } 380 381 static int chk_cri_sel_update(uint8_t* cri_sel_up) 382 { 383 FILE* fp; 384 struct stat file_stat; 385 size_t pos = plat_get_fru_sel(); 386 static uint8_t pre_pos = 0xff; 387 388 fp = fopen("/mnt/data/cri_sel", "r"); 389 if (fp) 390 { 391 if ((stat("/mnt/data/cri_sel", &file_stat) == 0) && 392 (file_stat.st_mtime != frame_sel.mtime || pre_pos != pos)) 393 { 394 *cri_sel_up = 1; 395 } 396 else 397 { 398 *cri_sel_up = 0; 399 } 400 fclose(fp); 401 } 402 else 403 { 404 if (frame_sel.buf == NULL || frame_sel.lines != 0 || pre_pos != pos) 405 { 406 *cri_sel_up = 1; 407 } 408 else 409 { 410 *cri_sel_up = 0; 411 } 412 } 413 pre_pos = pos; 414 return 0; 415 } 416 417 int plat_udbg_get_frame_info(uint8_t* num) 418 { 419 *num = 3; 420 return 0; 421 } 422 423 int plat_udbg_get_updated_frames(uint8_t* count, uint8_t* buffer) 424 { 425 uint8_t cri_sel_up = 0; 426 uint8_t info_page_up = 1; 427 428 *count = 0; 429 430 // info page update 431 if (info_page_up == 1) 432 { 433 buffer[*count] = 1; 434 *count += 1; 435 } 436 437 // cri sel update 438 chk_cri_sel_update(&cri_sel_up); 439 if (cri_sel_up == 1) 440 { 441 buffer[*count] = 2; 442 *count += 1; 443 } 444 445 // cri sensor update 446 buffer[*count] = 3; 447 *count += 1; 448 449 return 0; 450 } 451 452 int plat_udbg_get_post_desc(uint8_t index, uint8_t* next, uint8_t phase, 453 uint8_t* end, uint8_t* length, uint8_t* buffer) 454 { 455 nlohmann::json postObj; 456 std::string postCode; 457 458 /* Get post description data stored in json file */ 459 std::ifstream file(JSON_POST_DATA_FILE); 460 if (file) 461 { 462 file >> postObj; 463 file.close(); 464 } 465 else 466 { 467 phosphor::logging::log<phosphor::logging::level::ERR>( 468 "Post code description file not found", 469 phosphor::logging::entry("POST_CODE_FILE=%s", JSON_POST_DATA_FILE)); 470 return -1; 471 } 472 473 std::string phaseStr = "PhaseAny"; 474 if (postObj.find(phaseStr) == postObj.end()) 475 { 476 phaseStr = "Phase" + std::to_string(phase); 477 } 478 479 if (postObj.find(phaseStr) == postObj.end()) 480 { 481 phosphor::logging::log<phosphor::logging::level::ERR>( 482 "Post code phase not available", 483 phosphor::logging::entry("PHASE=%d", phase)); 484 return -1; 485 } 486 487 auto phaseObj = postObj[phaseStr]; 488 int phaseSize = phaseObj.size(); 489 490 for (int i = 0; i < phaseSize; i++) 491 { 492 postCode = phaseObj[i][0]; 493 if (index == stoul(postCode, nullptr, 16)) 494 { 495 std::string postDesc = phaseObj[i][1]; 496 *length = postDesc.size(); 497 memcpy(buffer, postDesc.data(), *length); 498 buffer[*length] = '\0'; 499 500 if (phaseSize != i + 1) 501 { 502 postCode = phaseObj[i + 1][0]; 503 *next = stoul(postCode, nullptr, 16); 504 *end = 0; 505 } 506 else 507 { 508 if (postObj.size() != phase) 509 { 510 std::string nextPhaseStr = "Phase" + 511 std::to_string(phase + 1); 512 postCode = postObj[nextPhaseStr][0][0]; 513 *next = stoul(postCode, nullptr, 16); 514 *end = 0; 515 } 516 else 517 { 518 *next = 0xff; 519 *end = 1; 520 } 521 } 522 523 return 0; 524 } 525 } 526 527 phosphor::logging::log<phosphor::logging::level::ERR>( 528 "Post code description data not available", 529 phosphor::logging::entry("PHASE_CODE=%d_0x%x", phase, index)); 530 return -1; 531 } 532 533 int plat_udbg_get_gpio_desc(uint8_t index, uint8_t* next, uint8_t* level, 534 uint8_t* def, uint8_t* length, uint8_t* buffer) 535 { 536 nlohmann::json gpioObj; 537 std::string gpioPin; 538 539 /* Get gpio data stored in json file */ 540 std::ifstream file(JSON_GPIO_DATA_FILE); 541 if (file) 542 { 543 file >> gpioObj; 544 file.close(); 545 } 546 else 547 { 548 phosphor::logging::log<phosphor::logging::level::ERR>( 549 "GPIO pin description file not found", 550 phosphor::logging::entry("GPIO_PIN_DETAILS_FILE=%s", 551 JSON_GPIO_DATA_FILE)); 552 return -1; 553 } 554 555 if (gpioObj.find(DEBUG_GPIO_KEY) == gpioObj.end()) 556 { 557 phosphor::logging::log<phosphor::logging::level::ERR>( 558 "GPIO pin details not available", 559 phosphor::logging::entry("GPIO_JSON_KEY=%d", DEBUG_GPIO_KEY)); 560 return -1; 561 } 562 563 auto obj = gpioObj[DEBUG_GPIO_KEY]; 564 int objSize = obj.size(); 565 566 for (int i = 0; i < objSize; i++) 567 { 568 if (obj[i].size() != GPIO_ARRAY_SIZE) 569 { 570 phosphor::logging::log<phosphor::logging::level::ERR>( 571 "Size of gpio array is incorrect", 572 phosphor::logging::entry("EXPECTED_SIZE=%d", GPIO_ARRAY_SIZE)); 573 return -1; 574 } 575 576 gpioPin = obj[i][GPIO_PIN_INDEX]; 577 if (index == stoul(gpioPin, nullptr, 16)) 578 { 579 if (objSize != i + 1) 580 { 581 gpioPin = obj[i + 1][GPIO_PIN_INDEX]; 582 *next = stoul(gpioPin, nullptr, 16); 583 } 584 else 585 { 586 *next = 0xff; 587 } 588 589 *level = obj[i][GPIO_LEVEL_INDEX]; 590 *def = obj[i][GPIO_DEF_INDEX]; 591 std::string gpioDesc = obj[i][GPIO_DESC_INDEX]; 592 *length = gpioDesc.size(); 593 memcpy(buffer, gpioDesc.data(), *length); 594 buffer[*length] = '\0'; 595 596 return 0; 597 } 598 } 599 600 phosphor::logging::log<phosphor::logging::level::ERR>( 601 "GPIO pin description data not available", 602 phosphor::logging::entry("GPIO_PIN=0x%x", index)); 603 return -1; 604 } 605 606 static int udbg_get_cri_sel(uint8_t, uint8_t page, uint8_t* next, 607 uint8_t* count, uint8_t* buffer) 608 { 609 if (page == 1) 610 { 611 // initialize and clear frame 612 frame_sel.init(FRAME_BUFF_SIZE); 613 frame_sel.overwrite = 1; 614 frame_sel.max_page = 20; 615 snprintf(frame_sel.title, 32, "Cri SEL"); 616 617 static constexpr const auto depth = 0; 618 std::vector<std::string> paths; 619 620 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 621 622 auto mapperCall = dbus->new_method_call( 623 "xyz.openbmc_project.ObjectMapper", 624 "/xyz/openbmc_project/object_mapper", 625 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths"); 626 static constexpr std::array<const char*, 1> interface = { 627 "xyz.openbmc_project.Logging.Entry"}; 628 mapperCall.append("/", depth, interface); 629 630 try 631 { 632 auto reply = dbus->call(mapperCall); 633 reply.read(paths); 634 } 635 catch (sdbusplus::exception_t& e) 636 { 637 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 638 return -1; 639 } 640 641 std::string message; 642 643 // Iterate each loggings 644 for (const auto& path : paths) 645 { 646 Value variant = ipmi::getDbusProperty( 647 *dbus, "xyz.openbmc_project.Logging", path, 648 "xyz.openbmc_project.Logging.Entry", "Severity"); 649 650 // Only filter critial sel 651 if (std::get<std::string>(variant) != 652 "xyz.openbmc_project.Logging.Entry.Level.Critical") 653 { 654 continue; 655 } 656 657 variant = ipmi::getDbusProperty( 658 *dbus, "xyz.openbmc_project.Logging", path, 659 "xyz.openbmc_project.Logging.Entry", "Message"); 660 message = std::get<std::string>(variant); 661 662 frame_sel.insert(message.c_str(), 0); 663 } 664 } 665 if (page > frame_sel.pages) 666 { 667 return -1; 668 } 669 int ret = frame_sel.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE); 670 if (ret < 0) 671 { 672 *count = 0; 673 return -1; 674 } 675 *count = (uint8_t)ret; 676 677 if (page < frame_sel.pages) 678 *next = page + 1; 679 else 680 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the 681 // last page 682 683 return 0; 684 } 685 686 static int udbg_get_cri_sensor(uint8_t, uint8_t page, uint8_t* next, 687 uint8_t* count, uint8_t* buffer) 688 { 689 int ret; 690 double fvalue; 691 size_t pos = plat_get_fru_sel(); 692 693 if (page == 1) 694 { 695 // Only update frame data while getting page 1 696 697 // initialize and clear frame 698 frame_snr.init(FRAME_BUFF_SIZE); 699 snprintf(frame_snr.title, 32, "CriSensor"); 700 701 nlohmann::json senObj; 702 703 /* Get critical sensor names stored in json file */ 704 std::ifstream file(JSON_SENSOR_NAMES_FILE); 705 if (file) 706 { 707 file >> senObj; 708 file.close(); 709 } 710 else 711 { 712 phosphor::logging::log<phosphor::logging::level::ERR>( 713 "Critical Sensor names file not found", 714 phosphor::logging::entry("CRI_SENSOR_NAMES_FILE=%s", 715 JSON_SENSOR_NAMES_FILE)); 716 return -1; 717 } 718 719 /* Get sensors values for all critical sensors */ 720 for (auto& j : senObj.items()) 721 { 722 std::string senName = j.key(); 723 auto val = j.value(); 724 725 if (senName[0] == '_') 726 { 727 senName = std::to_string(pos) + senName; 728 } 729 730 if (ipmi::storage::getSensorValue(senName, fvalue) == 0) 731 { 732 std::stringstream ss; 733 int prec = 0; // Default value 734 735 if (val.find("precision") != val.end()) 736 prec = val["precision"]; 737 738 ss << std::fixed << std::setprecision(prec) << fvalue; 739 740 std::string senStr; 741 if (val.find("short_name") != val.end()) 742 senStr = val["short_name"]; 743 else 744 senStr = senName; 745 746 senStr += ss.str(); 747 748 /* Get unit string for sensor and append in output */ 749 std::string unitStr; 750 if (ipmi::storage::getSensorUnit(senName, unitStr) == 0) 751 senStr += unitStr; 752 753 std::string thresholdStr; 754 int ret = ipmi::storage::getSensorThreshold(senName, 755 thresholdStr); 756 if (ret < 0) 757 { 758 phosphor::logging::log<phosphor::logging::level::ERR>( 759 "Error getting critical sensor threshold status", 760 phosphor::logging::entry("CRI_SENSOR_NAME=%s", 761 senName.c_str())); 762 return -1; 763 } 764 if (thresholdStr.size() != 0) 765 { 766 senStr += ("/" + thresholdStr); 767 std::string senStrWithBlinkAndInvertColor = 768 ESC_ALT + senStr + ESC_RST; 769 frame_snr.append(senStrWithBlinkAndInvertColor.c_str(), 0); 770 } 771 else 772 { 773 frame_snr.append(senStr.c_str(), 0); 774 } 775 } 776 else 777 { 778 phosphor::logging::log<phosphor::logging::level::INFO>( 779 "Critical sensor not found", 780 phosphor::logging::entry("CRI_SENSOR_NAME=%s", 781 senName.c_str())); 782 } 783 } 784 785 } // End of update frame 786 787 if (page > frame_snr.pages) 788 { 789 return -1; 790 } 791 792 ret = frame_snr.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE); 793 if (ret < 0) 794 { 795 *count = 0; 796 return -1; 797 } 798 *count = (uint8_t)ret; 799 800 if (page < frame_snr.pages) 801 *next = page + 1; 802 else 803 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the 804 // last page 805 806 return 0; 807 } 808 809 static int getBiosVer(std::string& ver, size_t hostPosition) 810 { 811 nlohmann::json appObj; 812 813 std::ifstream file(JSON_APP_DATA_FILE); 814 if (file) 815 { 816 file >> appObj; 817 file.close(); 818 std::string version_key = KEY_SYSFW_VER + std::to_string(hostPosition); 819 820 if (appObj.find(version_key) != appObj.end()) 821 { 822 ver = appObj[version_key].get<std::string>(); 823 return 0; 824 } 825 } 826 827 return -1; 828 } 829 830 int sendBicCmd(uint8_t netFn, uint8_t cmd, uint8_t bicAddr, 831 std::vector<uint8_t>& cmdData, std::vector<uint8_t>& respData) 832 { 833 static constexpr uint8_t lun = 0; 834 835 auto bus = getSdBus(); 836 837 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", 838 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", 839 "org.openbmc.Ipmb", "sendRequest"); 840 method.append(bicAddr, netFn, lun, cmd, cmdData); 841 842 auto reply = bus->call(method); 843 if (reply.is_method_error()) 844 { 845 phosphor::logging::log<phosphor::logging::level::ERR>( 846 "Error reading from BIC"); 847 return -1; 848 } 849 850 IpmbMethodType resp; 851 reply.read(resp); 852 853 respData = 854 std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp)); 855 856 return 0; 857 } 858 859 int sendMeCmd(uint8_t netFn, uint8_t cmd, std::vector<uint8_t>& cmdData, 860 std::vector<uint8_t>& respData) 861 { 862 auto bus = getSdBus(); 863 864 if (DEBUG) 865 { 866 std::cout << "ME NetFn:cmd " << (int)netFn << ":" << (int)cmd << "\n"; 867 std::cout << "ME req data: "; 868 for (auto d : cmdData) 869 { 870 std::cout << d << " "; 871 } 872 std::cout << "\n"; 873 } 874 875 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", 876 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", 877 "org.openbmc.Ipmb", "sendRequest"); 878 method.append(meAddress, netFn, lun, cmd, cmdData); 879 880 auto reply = bus->call(method); 881 if (reply.is_method_error()) 882 { 883 phosphor::logging::log<phosphor::logging::level::ERR>( 884 "Error reading from ME"); 885 return -1; 886 } 887 888 IpmbMethodType resp; 889 reply.read(resp); 890 891 respData = 892 std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp)); 893 894 if (DEBUG) 895 { 896 std::cout << "ME resp data: "; 897 for (auto d : respData) 898 { 899 std::cout << d << " "; 900 } 901 std::cout << "\n"; 902 } 903 904 return 0; 905 } 906 907 #ifdef ME_SUPPORT 908 static int getMeStatus(std::string& status, size_t pos) 909 { 910 uint8_t cmd = 0x01; // Get Device id command 911 uint8_t netFn = 0x06; // Netfn for APP 912 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 913 std::vector<uint8_t> cmdData; 914 915 uint8_t meAddr = meAddress; 916 bool platform = isMultiHostPlatform(); 917 if (platform == true) 918 { 919 meAddr = ((pos - 1) << 2); 920 } 921 922 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", 923 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", 924 "org.openbmc.Ipmb", "sendRequest"); 925 method.append(meAddr, netFn, lun, cmd, cmdData); 926 927 auto reply = bus->call(method); 928 if (reply.is_method_error()) 929 { 930 std::cerr << "Error reading from ME\n"; 931 return -1; 932 } 933 934 IpmbMethodType resp; 935 reply.read(resp); 936 937 std::vector<uint8_t> data; 938 data = std::get<5>(resp); 939 940 if (DEBUG) 941 { 942 std::cout << "ME Get ID: "; 943 for (size_t d : data) 944 { 945 std::cout << d << " "; 946 } 947 std::cout << "\n"; 948 } 949 950 if (data[2] & 0x80) 951 status = "recovery mode"; 952 else 953 status = "operation mode"; 954 955 return 0; 956 } 957 #endif 958 959 static int udbg_get_info_page(uint8_t, uint8_t page, uint8_t* next, 960 uint8_t* count, uint8_t* buffer) 961 { 962 char line_buff[1000]; 963 [[maybe_unused]] char* pres_dev = line_buff; 964 [[maybe_unused]] size_t pos = plat_get_fru_sel(); 965 int ret; 966 std::string serialName = "SerialNumber"; 967 std::string partName = "PartNumber"; 968 std::string verDel = "VERSION="; 969 std::string verPath = "/etc/os-release"; 970 size_t hostPosition; 971 size_t maxPosition; 972 973 if (page == 1) 974 { 975 // Only update frame data while getting page 1 976 977 // initialize and clear frame 978 frame_info.init(FRAME_BUFF_SIZE); 979 snprintf(frame_info.title, 32, "SYS_Info"); 980 981 bool platform = isMultiHostPlatform(); 982 if (platform == true) 983 { 984 hostPosition = plat_get_fru_sel(); 985 } 986 987 getMaxHostPosition(maxPosition); 988 if (hostPosition == BMC_POSITION || hostInstances == "0") 989 { 990 frame_info.append("FRU:spb", 0); 991 } 992 else if (hostPosition != BMC_POSITION && hostPosition <= maxPosition) 993 { 994 std::string data = "FRU:slot" + std::to_string(hostPosition); 995 frame_info.append(data.c_str(), 0); 996 } 997 998 // FRU 999 std::string data; 1000 frame_info.append("SN:", 0); 1001 if (getFruData(data, serialName) != 0) 1002 { 1003 data = "Not Found"; 1004 } 1005 frame_info.append(data.c_str(), 1); 1006 frame_info.append("PN:", 0); 1007 if (getFruData(data, partName) != 0) 1008 { 1009 data = "Not Found"; 1010 } 1011 frame_info.append(data.c_str(), 1); 1012 1013 // LAN 1014 getNetworkData(3, line_buff); 1015 frame_info.append("BMC_IP:", 0); 1016 frame_info.append(line_buff, 1); 1017 getNetworkData(59, line_buff); 1018 frame_info.append("BMC_IPv6:", 0); 1019 frame_info.append(line_buff, 1); 1020 1021 // BMC ver 1022 std::ifstream file(verPath); 1023 if (file) 1024 { 1025 std::string line; 1026 while (std::getline(file, line)) 1027 { 1028 if (line.find(verDel) != std::string::npos) 1029 { 1030 std::string bmcVer = line.substr(verDel.size()); 1031 frame_info.append("BMC_FW_ver:", 0); 1032 frame_info.append(bmcVer.c_str(), 1); 1033 break; 1034 } 1035 } 1036 } 1037 1038 if (hostPosition != BMC_POSITION) 1039 { 1040 // BIOS ver 1041 std::string biosVer; 1042 if (getBiosVer(biosVer, hostPosition) == 0) 1043 { 1044 frame_info.append("BIOS_FW_ver:", 0); 1045 frame_info.append(biosVer.c_str(), 1); 1046 } 1047 1048 #ifdef ME_SUPPORT 1049 // ME status 1050 std::string meStatus; 1051 if (getMeStatus(meStatus, pos) != 0) 1052 { 1053 phosphor::logging::log<phosphor::logging::level::WARNING>( 1054 "Reading ME status failed"); 1055 meStatus = "unknown"; 1056 } 1057 frame_info.append("ME_status:", 0); 1058 frame_info.append(meStatus.c_str(), 1); 1059 #endif 1060 } 1061 1062 /* TBD: Board ID needs implementation */ 1063 // Board ID 1064 1065 // Battery - Use Escape sequence 1066 frame_info.append("Battery:", 0); 1067 frame_info.append(ESC_BAT " ", 1); 1068 // frame_info.append(&frame_info, esc_bat, 1); 1069 1070 // MCU Version - Use Escape sequence 1071 frame_info.append("MCUbl_ver:", 0); 1072 frame_info.append(ESC_MCU_BL_VER, 1); 1073 frame_info.append("MCU_ver:", 0); 1074 frame_info.append(ESC_MCU_RUN_VER, 1); 1075 1076 // Sys config present device 1077 if (hostPosition != BMC_POSITION) 1078 { 1079 frame_info.append("Sys Conf. info:", 0); 1080 1081 // Dimm info 1082 std::vector<std::string> data; 1083 if (sysConfig(data, pos) == 0) 1084 { 1085 for (auto& info : data) 1086 { 1087 frame_info.append(info.c_str(), 1); 1088 } 1089 } 1090 else 1091 { 1092 frame_info.append("Not Found", 1); 1093 } 1094 1095 // Processor info 1096 std::string result; 1097 if (procInfo(result, pos) != 0) 1098 { 1099 result = "Not Found"; 1100 } 1101 frame_info.append(result.c_str(), 1); 1102 } 1103 1104 } // End of update frame 1105 1106 if (page > frame_info.pages) 1107 { 1108 return -1; 1109 } 1110 1111 ret = frame_info.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE); 1112 if (ret < 0) 1113 { 1114 *count = 0; 1115 return -1; 1116 } 1117 *count = (uint8_t)ret; 1118 1119 if (page < frame_info.pages) 1120 *next = page + 1; 1121 else 1122 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the 1123 // last page 1124 1125 return 0; 1126 } 1127 1128 int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t* next, 1129 uint8_t* count, uint8_t* buffer) 1130 { 1131 switch (frame) 1132 { 1133 case 1: // info_page 1134 return udbg_get_info_page(frame, page, next, count, buffer); 1135 case 2: // critical SEL 1136 return udbg_get_cri_sel(frame, page, next, count, buffer); 1137 case 3: // critical Sensor 1138 return udbg_get_cri_sensor(frame, page, next, count, buffer); 1139 default: 1140 return -1; 1141 } 1142 } 1143 1144 static uint8_t panel_main(uint8_t item) 1145 { 1146 // Update item list when select item 0 1147 switch (item) 1148 { 1149 case 1: 1150 return panels[PANEL_BOOT_ORDER].select(0); 1151 case 2: 1152 return panels[PANEL_POWER_POLICY].select(0); 1153 default: 1154 return PANEL_MAIN; 1155 } 1156 } 1157 1158 static uint8_t panel_boot_order(uint8_t) 1159 { 1160 /* To be implemented */ 1161 #if 0 1162 int i; 1163 unsigned char buff[MAX_VALUE_LEN], pickup, len; 1164 size_t pos = plat_get_fru_sel(); 1165 if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0) 1166 { 1167 if (item > 0 && item < SIZE_BOOT_ORDER) 1168 { 1169 pickup = buff[item]; 1170 while (item > 1) 1171 { 1172 buff[item] = buff[item - 1]; 1173 item--; 1174 } 1175 buff[item] = pickup; 1176 buff[0] |= 0x80; 1177 pal_set_boot_order(pos, buff, buff, &len); 1178 1179 // refresh items 1180 return panels[PANEL_BOOT_ORDER].select(0); 1181 } 1182 1183 // '*': boot flags valid, BIOS has not yet read 1184 snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32, "Boot Order%c", 1185 (buff[0] & 0x80) ? '*' : '\0'); 1186 1187 for (i = 1; i < SIZE_BOOT_ORDER; i++) 1188 { 1189 switch (buff[i]) 1190 { 1191 case 0x0: 1192 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1193 " USB device"); 1194 break; 1195 case 0x1: 1196 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1197 " Network v4"); 1198 break; 1199 case (0x1 | 0x8): 1200 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1201 " Network v6"); 1202 break; 1203 case 0x2: 1204 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1205 " SATA HDD"); 1206 break; 1207 case 0x3: 1208 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1209 " SATA-CDROM"); 1210 break; 1211 case 0x4: 1212 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1213 " Other"); 1214 break; 1215 default: 1216 panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0'; 1217 break; 1218 } 1219 } 1220 1221 // remove empty items 1222 for (i--; 1223 (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0); 1224 i--) 1225 ; 1226 1227 panels[PANEL_BOOT_ORDER].item_num = i; 1228 } 1229 else 1230 { 1231 panels[PANEL_BOOT_ORDER].item_num = 0; 1232 } 1233 #endif 1234 return PANEL_BOOT_ORDER; 1235 } 1236 1237 static uint8_t panel_power_policy(uint8_t) 1238 { 1239 /* To be cleaned */ 1240 #if 0 1241 uint8_t buff[32] = {0}; 1242 uint8_t res_len; 1243 size_t pos = plat_get_fru_sel(); 1244 uint8_t policy; 1245 uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS, 1246 POWER_CFG_OFF}; 1247 1248 if (pos != FRU_ALL) 1249 { 1250 if (item > 0 && item <= sizeof(pwr_policy_item_map)) 1251 { 1252 policy = pwr_policy_item_map[item - 1]; 1253 pal_set_power_restore_policy(pos, &policy, NULL); 1254 } 1255 pal_get_chassis_status(pos, NULL, buff, &res_len); 1256 policy = (((uint8_t)buff[0]) >> 5) & 0x7; 1257 snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32, "%cPower On", 1258 policy == POWER_CFG_ON ? '*' : ' '); 1259 snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32, "%cLast State", 1260 policy == POWER_CFG_LPS ? '*' : ' '); 1261 snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32, "%cPower Off", 1262 policy == POWER_CFG_OFF ? '*' : ' '); 1263 panels[PANEL_POWER_POLICY].item_num = 3; 1264 } 1265 else 1266 { 1267 panels[PANEL_POWER_POLICY].item_num = 0; 1268 } 1269 #endif 1270 return PANEL_POWER_POLICY; 1271 } 1272 1273 int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item, 1274 uint8_t* count, uint8_t* buffer) 1275 { 1276 if (panel > panelNum || panel < PANEL_MAIN) 1277 return IPMI_CC_PARM_OUT_OF_RANGE; 1278 1279 // No more item; End of item list 1280 if (item > panels[panel].item_num) 1281 return IPMI_CC_PARM_OUT_OF_RANGE; 1282 1283 switch (operation) 1284 { 1285 case 0: // Get Description 1286 break; 1287 case 1: // Select item 1288 panel = panels[panel].select(item); 1289 item = 0; 1290 break; 1291 case 2: // Back 1292 panel = panels[panel].parent; 1293 item = 0; 1294 break; 1295 default: 1296 return IPMI_CC_PARM_OUT_OF_RANGE; 1297 } 1298 1299 buffer[0] = panel; 1300 buffer[1] = item; 1301 buffer[2] = strlen(panels[panel].item_str[item]); 1302 if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE) 1303 { 1304 memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]); 1305 } 1306 *count = buffer[2] + 3; 1307 return IPMI_CC_OK; 1308 } 1309 1310 } // end of namespace ipmi 1311