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