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) 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 if (appObj.find(KEY_SYSFW_VER) != appObj.end()) 808 { 809 ver = appObj[KEY_SYSFW_VER].get<std::string>(); 810 return 0; 811 } 812 } 813 814 return -1; 815 } 816 817 int sendBicCmd(uint8_t netFn, uint8_t cmd, uint8_t bicAddr, 818 std::vector<uint8_t>& cmdData, std::vector<uint8_t>& respData) 819 { 820 static constexpr uint8_t lun = 0; 821 822 auto bus = getSdBus(); 823 824 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", 825 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", 826 "org.openbmc.Ipmb", "sendRequest"); 827 method.append(bicAddr, netFn, lun, cmd, cmdData); 828 829 auto reply = bus->call(method); 830 if (reply.is_method_error()) 831 { 832 phosphor::logging::log<phosphor::logging::level::ERR>( 833 "Error reading from BIC"); 834 return -1; 835 } 836 837 IpmbMethodType resp; 838 reply.read(resp); 839 840 respData = 841 std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp)); 842 843 return 0; 844 } 845 846 int sendMeCmd(uint8_t netFn, uint8_t cmd, std::vector<uint8_t>& cmdData, 847 std::vector<uint8_t>& respData) 848 { 849 auto bus = getSdBus(); 850 851 if (DEBUG) 852 { 853 std::cout << "ME NetFn:cmd " << (int)netFn << ":" << (int)cmd << "\n"; 854 std::cout << "ME req data: "; 855 for (auto d : cmdData) 856 { 857 std::cout << d << " "; 858 } 859 std::cout << "\n"; 860 } 861 862 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", 863 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", 864 "org.openbmc.Ipmb", "sendRequest"); 865 method.append(meAddress, netFn, lun, cmd, cmdData); 866 867 auto reply = bus->call(method); 868 if (reply.is_method_error()) 869 { 870 phosphor::logging::log<phosphor::logging::level::ERR>( 871 "Error reading from ME"); 872 return -1; 873 } 874 875 IpmbMethodType resp; 876 reply.read(resp); 877 878 respData = 879 std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp)); 880 881 if (DEBUG) 882 { 883 std::cout << "ME resp data: "; 884 for (auto d : respData) 885 { 886 std::cout << d << " "; 887 } 888 std::cout << "\n"; 889 } 890 891 return 0; 892 } 893 894 #ifdef ME_SUPPORT 895 static int getMeStatus(std::string& status, size_t pos) 896 { 897 uint8_t cmd = 0x01; // Get Device id command 898 uint8_t netFn = 0x06; // Netfn for APP 899 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 900 std::vector<uint8_t> cmdData; 901 902 uint8_t meAddr = meAddress; 903 bool platform = isMultiHostPlatform(); 904 if (platform == true) 905 { 906 meAddr = ((pos - 1) << 2); 907 } 908 909 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", 910 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", 911 "org.openbmc.Ipmb", "sendRequest"); 912 method.append(meAddr, netFn, lun, cmd, cmdData); 913 914 auto reply = bus->call(method); 915 if (reply.is_method_error()) 916 { 917 std::cerr << "Error reading from ME\n"; 918 return -1; 919 } 920 921 IpmbMethodType resp; 922 reply.read(resp); 923 924 std::vector<uint8_t> data; 925 data = std::get<5>(resp); 926 927 if (DEBUG) 928 { 929 std::cout << "ME Get ID: "; 930 for (size_t d : data) 931 { 932 std::cout << d << " "; 933 } 934 std::cout << "\n"; 935 } 936 937 if (data[2] & 0x80) 938 status = "recovery mode"; 939 else 940 status = "operation mode"; 941 942 return 0; 943 } 944 #endif 945 946 static int udbg_get_info_page(uint8_t, uint8_t page, uint8_t* next, 947 uint8_t* count, uint8_t* buffer) 948 { 949 char line_buff[1000]; 950 [[maybe_unused]] char* pres_dev = line_buff; 951 [[maybe_unused]] size_t pos = plat_get_fru_sel(); 952 int ret; 953 std::string serialName = "SerialNumber"; 954 std::string partName = "PartNumber"; 955 std::string verDel = "VERSION="; 956 std::string verPath = "/etc/os-release"; 957 size_t hostPosition; 958 959 if (page == 1) 960 { 961 // Only update frame data while getting page 1 962 963 // initialize and clear frame 964 frame_info.init(FRAME_BUFF_SIZE); 965 snprintf(frame_info.title, 32, "SYS_Info"); 966 967 bool platform = isMultiHostPlatform(); 968 if (platform == true) 969 { 970 hostPosition = getSelectorPosition(); 971 } 972 973 if (hostPosition == BMC_POSITION || hostInstances == "0") 974 { 975 frame_info.append("FRU:spb", 0); 976 } 977 else if (hostPosition != BMC_POSITION && 978 hostPosition <= getMaxHostPosition()) 979 { 980 std::string data = "FRU:slot" + std::to_string(hostPosition); 981 frame_info.append(data.c_str(), 0); 982 } 983 984 // FRU 985 std::string data; 986 frame_info.append("SN:", 0); 987 if (getFruData(data, serialName) != 0) 988 { 989 data = "Not Found"; 990 } 991 frame_info.append(data.c_str(), 1); 992 frame_info.append("PN:", 0); 993 if (getFruData(data, partName) != 0) 994 { 995 data = "Not Found"; 996 } 997 frame_info.append(data.c_str(), 1); 998 999 // LAN 1000 getNetworkData(3, line_buff); 1001 frame_info.append("BMC_IP:", 0); 1002 frame_info.append(line_buff, 1); 1003 getNetworkData(59, line_buff); 1004 frame_info.append("BMC_IPv6:", 0); 1005 frame_info.append(line_buff, 1); 1006 1007 // BMC ver 1008 std::ifstream file(verPath); 1009 if (file) 1010 { 1011 std::string line; 1012 while (std::getline(file, line)) 1013 { 1014 if (line.find(verDel) != std::string::npos) 1015 { 1016 std::string bmcVer = line.substr(verDel.size()); 1017 frame_info.append("BMC_FW_ver:", 0); 1018 frame_info.append(bmcVer.c_str(), 1); 1019 break; 1020 } 1021 } 1022 } 1023 1024 if (hostPosition != BMC_POSITION) 1025 { 1026 // BIOS ver 1027 std::string biosVer; 1028 if (getBiosVer(biosVer) == 0) 1029 { 1030 frame_info.append("BIOS_FW_ver:", 0); 1031 frame_info.append(biosVer.c_str(), 1); 1032 } 1033 1034 #ifdef ME_SUPPORT 1035 // ME status 1036 std::string meStatus; 1037 if (getMeStatus(meStatus, pos) != 0) 1038 { 1039 phosphor::logging::log<phosphor::logging::level::WARNING>( 1040 "Reading ME status failed"); 1041 meStatus = "unknown"; 1042 } 1043 frame_info.append("ME_status:", 0); 1044 frame_info.append(meStatus.c_str(), 1); 1045 #endif 1046 } 1047 1048 /* TBD: Board ID needs implementation */ 1049 // Board ID 1050 1051 // Battery - Use Escape sequence 1052 frame_info.append("Battery:", 0); 1053 frame_info.append(ESC_BAT " ", 1); 1054 // frame_info.append(&frame_info, esc_bat, 1); 1055 1056 // MCU Version - Use Escape sequence 1057 frame_info.append("MCUbl_ver:", 0); 1058 frame_info.append(ESC_MCU_BL_VER, 1); 1059 frame_info.append("MCU_ver:", 0); 1060 frame_info.append(ESC_MCU_RUN_VER, 1); 1061 1062 // Sys config present device 1063 if (hostPosition != BMC_POSITION) 1064 { 1065 frame_info.append("Sys Conf. info:", 0); 1066 1067 // Dimm info 1068 std::vector<std::string> data; 1069 sysConfig(data, pos); 1070 for (auto& info : data) 1071 { 1072 frame_info.append(info.c_str(), 1); 1073 } 1074 1075 // Processor info 1076 std::string result; 1077 procInfo(result, pos); 1078 frame_info.append(result.c_str(), 1); 1079 } 1080 1081 } // End of update frame 1082 1083 if (page > frame_info.pages) 1084 { 1085 return -1; 1086 } 1087 1088 ret = frame_info.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE); 1089 if (ret < 0) 1090 { 1091 *count = 0; 1092 return -1; 1093 } 1094 *count = (uint8_t)ret; 1095 1096 if (page < frame_info.pages) 1097 *next = page + 1; 1098 else 1099 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the 1100 // last page 1101 1102 return 0; 1103 } 1104 1105 int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t* next, 1106 uint8_t* count, uint8_t* buffer) 1107 { 1108 switch (frame) 1109 { 1110 case 1: // info_page 1111 return udbg_get_info_page(frame, page, next, count, buffer); 1112 case 2: // critical SEL 1113 return udbg_get_cri_sel(frame, page, next, count, buffer); 1114 case 3: // critical Sensor 1115 return udbg_get_cri_sensor(frame, page, next, count, buffer); 1116 default: 1117 return -1; 1118 } 1119 } 1120 1121 static uint8_t panel_main(uint8_t item) 1122 { 1123 // Update item list when select item 0 1124 switch (item) 1125 { 1126 case 1: 1127 return panels[PANEL_BOOT_ORDER].select(0); 1128 case 2: 1129 return panels[PANEL_POWER_POLICY].select(0); 1130 default: 1131 return PANEL_MAIN; 1132 } 1133 } 1134 1135 static uint8_t panel_boot_order(uint8_t) 1136 { 1137 /* To be implemented */ 1138 #if 0 1139 int i; 1140 unsigned char buff[MAX_VALUE_LEN], pickup, len; 1141 size_t pos = plat_get_fru_sel(); 1142 if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0) 1143 { 1144 if (item > 0 && item < SIZE_BOOT_ORDER) 1145 { 1146 pickup = buff[item]; 1147 while (item > 1) 1148 { 1149 buff[item] = buff[item - 1]; 1150 item--; 1151 } 1152 buff[item] = pickup; 1153 buff[0] |= 0x80; 1154 pal_set_boot_order(pos, buff, buff, &len); 1155 1156 // refresh items 1157 return panels[PANEL_BOOT_ORDER].select(0); 1158 } 1159 1160 // '*': boot flags valid, BIOS has not yet read 1161 snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32, "Boot Order%c", 1162 (buff[0] & 0x80) ? '*' : '\0'); 1163 1164 for (i = 1; i < SIZE_BOOT_ORDER; i++) 1165 { 1166 switch (buff[i]) 1167 { 1168 case 0x0: 1169 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1170 " USB device"); 1171 break; 1172 case 0x1: 1173 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1174 " Network v4"); 1175 break; 1176 case (0x1 | 0x8): 1177 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1178 " Network v6"); 1179 break; 1180 case 0x2: 1181 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1182 " SATA HDD"); 1183 break; 1184 case 0x3: 1185 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1186 " SATA-CDROM"); 1187 break; 1188 case 0x4: 1189 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1190 " Other"); 1191 break; 1192 default: 1193 panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0'; 1194 break; 1195 } 1196 } 1197 1198 // remove empty items 1199 for (i--; 1200 (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0); 1201 i--) 1202 ; 1203 1204 panels[PANEL_BOOT_ORDER].item_num = i; 1205 } 1206 else 1207 { 1208 panels[PANEL_BOOT_ORDER].item_num = 0; 1209 } 1210 #endif 1211 return PANEL_BOOT_ORDER; 1212 } 1213 1214 static uint8_t panel_power_policy(uint8_t) 1215 { 1216 /* To be cleaned */ 1217 #if 0 1218 uint8_t buff[32] = {0}; 1219 uint8_t res_len; 1220 size_t pos = plat_get_fru_sel(); 1221 uint8_t policy; 1222 uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS, 1223 POWER_CFG_OFF}; 1224 1225 if (pos != FRU_ALL) 1226 { 1227 if (item > 0 && item <= sizeof(pwr_policy_item_map)) 1228 { 1229 policy = pwr_policy_item_map[item - 1]; 1230 pal_set_power_restore_policy(pos, &policy, NULL); 1231 } 1232 pal_get_chassis_status(pos, NULL, buff, &res_len); 1233 policy = (((uint8_t)buff[0]) >> 5) & 0x7; 1234 snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32, "%cPower On", 1235 policy == POWER_CFG_ON ? '*' : ' '); 1236 snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32, "%cLast State", 1237 policy == POWER_CFG_LPS ? '*' : ' '); 1238 snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32, "%cPower Off", 1239 policy == POWER_CFG_OFF ? '*' : ' '); 1240 panels[PANEL_POWER_POLICY].item_num = 3; 1241 } 1242 else 1243 { 1244 panels[PANEL_POWER_POLICY].item_num = 0; 1245 } 1246 #endif 1247 return PANEL_POWER_POLICY; 1248 } 1249 1250 int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item, 1251 uint8_t* count, uint8_t* buffer) 1252 { 1253 if (panel > panelNum || panel < PANEL_MAIN) 1254 return IPMI_CC_PARM_OUT_OF_RANGE; 1255 1256 // No more item; End of item list 1257 if (item > panels[panel].item_num) 1258 return IPMI_CC_PARM_OUT_OF_RANGE; 1259 1260 switch (operation) 1261 { 1262 case 0: // Get Description 1263 break; 1264 case 1: // Select item 1265 panel = panels[panel].select(item); 1266 item = 0; 1267 break; 1268 case 2: // Back 1269 panel = panels[panel].parent; 1270 item = 0; 1271 break; 1272 default: 1273 return IPMI_CC_PARM_OUT_OF_RANGE; 1274 } 1275 1276 buffer[0] = panel; 1277 buffer[1] = item; 1278 buffer[2] = strlen(panels[panel].item_str[item]); 1279 if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE) 1280 { 1281 memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]); 1282 } 1283 *count = buffer[2] + 3; 1284 return IPMI_CC_OK; 1285 } 1286 1287 } // end of namespace ipmi 1288