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 } // 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 = 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 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 = 72 getService(*dbus, ipmi::selector::interface, 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 = 511 "Phase" + 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 int len; 610 int ret; 611 char line_buff[FRAME_PAGE_BUF_SIZE]; 612 const char* ptr; 613 FILE* fp; 614 struct stat file_stat; 615 size_t pos = plat_get_fru_sel(); 616 static uint8_t pre_pos = FRU_ALL; 617 bool pos_changed = pre_pos != pos; 618 619 pre_pos = pos; 620 621 /* Revisit this */ 622 fp = fopen("/mnt/data/cri_sel", "r"); 623 if (fp) 624 { 625 if ((stat("/mnt/data/cri_sel", &file_stat) == 0) && 626 (file_stat.st_mtime != frame_sel.mtime || pos_changed)) 627 { 628 // initialize and clear frame 629 frame_sel.init(FRAME_BUFF_SIZE); 630 frame_sel.overwrite = 1; 631 frame_sel.max_page = 20; 632 frame_sel.mtime = file_stat.st_mtime; 633 snprintf(frame_sel.title, 32, "Cri SEL"); 634 635 while (fgets(line_buff, FRAME_PAGE_BUF_SIZE, fp)) 636 { 637 // Remove newline 638 line_buff[strlen(line_buff) - 1] = '\0'; 639 ptr = line_buff; 640 // Find message 641 ptr = strstr(ptr, "local0.err"); 642 if (ptr == NULL) 643 { 644 continue; 645 } 646 647 if ((ptr = strrchr(ptr, ':')) == NULL) 648 { 649 continue; 650 } 651 len = strlen(ptr); 652 if (len > 2) 653 { 654 // to skip log string ": " 655 ptr += 2; 656 } 657 // Write new message 658 frame_sel.insert(ptr, 0); 659 } 660 } 661 fclose(fp); 662 } 663 else 664 { 665 // Title only 666 frame_sel.init(FRAME_BUFF_SIZE); 667 snprintf(frame_sel.title, 32, "Cri SEL"); 668 frame_sel.mtime = 0; 669 } 670 671 if (page > frame_sel.pages) 672 { 673 return -1; 674 } 675 676 ret = frame_sel.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE); 677 if (ret < 0) 678 { 679 *count = 0; 680 return -1; 681 } 682 *count = (uint8_t)ret; 683 684 if (page < frame_sel.pages) 685 *next = page + 1; 686 else 687 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the 688 // last page 689 690 return 0; 691 } 692 693 static int udbg_get_cri_sensor(uint8_t, uint8_t page, uint8_t* next, 694 uint8_t* count, uint8_t* buffer) 695 { 696 int ret; 697 double fvalue; 698 size_t pos = plat_get_fru_sel(); 699 700 if (page == 1) 701 { 702 // Only update frame data while getting page 1 703 704 // initialize and clear frame 705 frame_snr.init(FRAME_BUFF_SIZE); 706 snprintf(frame_snr.title, 32, "CriSensor"); 707 708 nlohmann::json senObj; 709 710 /* Get critical sensor names stored in json file */ 711 std::ifstream file(JSON_SENSOR_NAMES_FILE); 712 if (file) 713 { 714 file >> senObj; 715 file.close(); 716 } 717 else 718 { 719 phosphor::logging::log<phosphor::logging::level::ERR>( 720 "Critical Sensor names file not found", 721 phosphor::logging::entry("CRI_SENSOR_NAMES_FILE=%s", 722 JSON_SENSOR_NAMES_FILE)); 723 return -1; 724 } 725 726 /* Get sensors values for all critical sensors */ 727 for (auto& j : senObj.items()) 728 { 729 std::string senName = j.key(); 730 auto val = j.value(); 731 732 if (senName[0] == '_') 733 { 734 senName = std::to_string(pos) + senName; 735 } 736 737 if (ipmi::storage::getSensorValue(senName, fvalue) == 0) 738 { 739 std::stringstream ss; 740 int prec = 0; // Default value 741 742 if (val.find("precision") != val.end()) 743 prec = val["precision"]; 744 745 ss << std::fixed << std::setprecision(prec) << fvalue; 746 747 std::string senStr; 748 if (val.find("short_name") != val.end()) 749 senStr = val["short_name"]; 750 else 751 senStr = senName; 752 753 senStr += ss.str(); 754 755 /* Get unit string for sensor and append in output */ 756 std::string unitStr; 757 if (ipmi::storage::getSensorUnit(senName, unitStr) == 0) 758 senStr += unitStr; 759 760 std::string thresholdStr; 761 int ret = 762 ipmi::storage::getSensorThreshold(senName, thresholdStr); 763 if (ret < 0) 764 { 765 phosphor::logging::log<phosphor::logging::level::ERR>( 766 "Error getting critical sensor threshold status", 767 phosphor::logging::entry("CRI_SENSOR_NAME=%s", 768 senName.c_str())); 769 return -1; 770 } 771 if (thresholdStr.size() != 0) 772 { 773 senStr += ("/" + thresholdStr); 774 std::string senStrWithBlinkAndInvertColor = 775 ESC_ALT + senStr + ESC_RST; 776 frame_snr.append(senStrWithBlinkAndInvertColor.c_str(), 0); 777 } 778 else 779 { 780 frame_snr.append(senStr.c_str(), 0); 781 } 782 } 783 else 784 { 785 phosphor::logging::log<phosphor::logging::level::INFO>( 786 "Critical sensor not found", 787 phosphor::logging::entry("CRI_SENSOR_NAME=%s", 788 senName.c_str())); 789 } 790 } 791 792 } // End of update frame 793 794 if (page > frame_snr.pages) 795 { 796 return -1; 797 } 798 799 ret = frame_snr.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE); 800 if (ret < 0) 801 { 802 *count = 0; 803 return -1; 804 } 805 *count = (uint8_t)ret; 806 807 if (page < frame_snr.pages) 808 *next = page + 1; 809 else 810 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the 811 // last page 812 813 return 0; 814 } 815 816 static int getBiosVer(std::string& ver, size_t hostPosition) 817 { 818 nlohmann::json appObj; 819 820 std::ifstream file(JSON_APP_DATA_FILE); 821 if (file) 822 { 823 file >> appObj; 824 file.close(); 825 std::string version_key = KEY_SYSFW_VER + std::to_string(hostPosition); 826 827 if (appObj.find(version_key) != appObj.end()) 828 { 829 ver = appObj[version_key].get<std::string>(); 830 return 0; 831 } 832 } 833 834 return -1; 835 } 836 837 int sendBicCmd(uint8_t netFn, uint8_t cmd, uint8_t bicAddr, 838 std::vector<uint8_t>& cmdData, std::vector<uint8_t>& respData) 839 { 840 static constexpr uint8_t lun = 0; 841 842 auto bus = getSdBus(); 843 844 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", 845 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", 846 "org.openbmc.Ipmb", "sendRequest"); 847 method.append(bicAddr, netFn, lun, cmd, cmdData); 848 849 auto reply = bus->call(method); 850 if (reply.is_method_error()) 851 { 852 phosphor::logging::log<phosphor::logging::level::ERR>( 853 "Error reading from BIC"); 854 return -1; 855 } 856 857 IpmbMethodType resp; 858 reply.read(resp); 859 860 respData = 861 std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp)); 862 863 return 0; 864 } 865 866 int sendMeCmd(uint8_t netFn, uint8_t cmd, std::vector<uint8_t>& cmdData, 867 std::vector<uint8_t>& respData) 868 { 869 auto bus = getSdBus(); 870 871 if (DEBUG) 872 { 873 std::cout << "ME NetFn:cmd " << (int)netFn << ":" << (int)cmd << "\n"; 874 std::cout << "ME req data: "; 875 for (auto d : cmdData) 876 { 877 std::cout << d << " "; 878 } 879 std::cout << "\n"; 880 } 881 882 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", 883 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", 884 "org.openbmc.Ipmb", "sendRequest"); 885 method.append(meAddress, netFn, lun, cmd, cmdData); 886 887 auto reply = bus->call(method); 888 if (reply.is_method_error()) 889 { 890 phosphor::logging::log<phosphor::logging::level::ERR>( 891 "Error reading from ME"); 892 return -1; 893 } 894 895 IpmbMethodType resp; 896 reply.read(resp); 897 898 respData = 899 std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp)); 900 901 if (DEBUG) 902 { 903 std::cout << "ME resp data: "; 904 for (auto d : respData) 905 { 906 std::cout << d << " "; 907 } 908 std::cout << "\n"; 909 } 910 911 return 0; 912 } 913 914 #ifdef ME_SUPPORT 915 static int getMeStatus(std::string& status, size_t pos) 916 { 917 uint8_t cmd = 0x01; // Get Device id command 918 uint8_t netFn = 0x06; // Netfn for APP 919 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 920 std::vector<uint8_t> cmdData; 921 922 uint8_t meAddr = meAddress; 923 bool platform = isMultiHostPlatform(); 924 if (platform == true) 925 { 926 meAddr = ((pos - 1) << 2); 927 } 928 929 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", 930 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", 931 "org.openbmc.Ipmb", "sendRequest"); 932 method.append(meAddr, netFn, lun, cmd, cmdData); 933 934 auto reply = bus->call(method); 935 if (reply.is_method_error()) 936 { 937 std::cerr << "Error reading from ME\n"; 938 return -1; 939 } 940 941 IpmbMethodType resp; 942 reply.read(resp); 943 944 std::vector<uint8_t> data; 945 data = std::get<5>(resp); 946 947 if (DEBUG) 948 { 949 std::cout << "ME Get ID: "; 950 for (size_t d : data) 951 { 952 std::cout << d << " "; 953 } 954 std::cout << "\n"; 955 } 956 957 if (data[2] & 0x80) 958 status = "recovery mode"; 959 else 960 status = "operation mode"; 961 962 return 0; 963 } 964 #endif 965 966 static int udbg_get_info_page(uint8_t, uint8_t page, uint8_t* next, 967 uint8_t* count, uint8_t* buffer) 968 { 969 char line_buff[1000]; 970 [[maybe_unused]] char* pres_dev = line_buff; 971 [[maybe_unused]] size_t pos = plat_get_fru_sel(); 972 int ret; 973 std::string serialName = "SerialNumber"; 974 std::string partName = "PartNumber"; 975 std::string verDel = "VERSION="; 976 std::string verPath = "/etc/os-release"; 977 size_t hostPosition; 978 size_t maxPosition; 979 980 if (page == 1) 981 { 982 // Only update frame data while getting page 1 983 984 // initialize and clear frame 985 frame_info.init(FRAME_BUFF_SIZE); 986 snprintf(frame_info.title, 32, "SYS_Info"); 987 988 bool platform = isMultiHostPlatform(); 989 if (platform == true) 990 { 991 hostPosition = plat_get_fru_sel(); 992 } 993 994 getMaxHostPosition(maxPosition); 995 if (hostPosition == BMC_POSITION || hostInstances == "0") 996 { 997 frame_info.append("FRU:spb", 0); 998 } 999 else if (hostPosition != BMC_POSITION && hostPosition <= maxPosition) 1000 { 1001 std::string data = "FRU:slot" + std::to_string(hostPosition); 1002 frame_info.append(data.c_str(), 0); 1003 } 1004 1005 // FRU 1006 std::string data; 1007 frame_info.append("SN:", 0); 1008 if (getFruData(data, serialName) != 0) 1009 { 1010 data = "Not Found"; 1011 } 1012 frame_info.append(data.c_str(), 1); 1013 frame_info.append("PN:", 0); 1014 if (getFruData(data, partName) != 0) 1015 { 1016 data = "Not Found"; 1017 } 1018 frame_info.append(data.c_str(), 1); 1019 1020 // LAN 1021 getNetworkData(3, line_buff); 1022 frame_info.append("BMC_IP:", 0); 1023 frame_info.append(line_buff, 1); 1024 getNetworkData(59, line_buff); 1025 frame_info.append("BMC_IPv6:", 0); 1026 frame_info.append(line_buff, 1); 1027 1028 // BMC ver 1029 std::ifstream file(verPath); 1030 if (file) 1031 { 1032 std::string line; 1033 while (std::getline(file, line)) 1034 { 1035 if (line.find(verDel) != std::string::npos) 1036 { 1037 std::string bmcVer = line.substr(verDel.size()); 1038 frame_info.append("BMC_FW_ver:", 0); 1039 frame_info.append(bmcVer.c_str(), 1); 1040 break; 1041 } 1042 } 1043 } 1044 1045 if (hostPosition != BMC_POSITION) 1046 { 1047 // BIOS ver 1048 std::string biosVer; 1049 if (getBiosVer(biosVer, hostPosition) == 0) 1050 { 1051 frame_info.append("BIOS_FW_ver:", 0); 1052 frame_info.append(biosVer.c_str(), 1); 1053 } 1054 1055 #ifdef ME_SUPPORT 1056 // ME status 1057 std::string meStatus; 1058 if (getMeStatus(meStatus, pos) != 0) 1059 { 1060 phosphor::logging::log<phosphor::logging::level::WARNING>( 1061 "Reading ME status failed"); 1062 meStatus = "unknown"; 1063 } 1064 frame_info.append("ME_status:", 0); 1065 frame_info.append(meStatus.c_str(), 1); 1066 #endif 1067 } 1068 1069 /* TBD: Board ID needs implementation */ 1070 // Board ID 1071 1072 // Battery - Use Escape sequence 1073 frame_info.append("Battery:", 0); 1074 frame_info.append(ESC_BAT " ", 1); 1075 // frame_info.append(&frame_info, esc_bat, 1); 1076 1077 // MCU Version - Use Escape sequence 1078 frame_info.append("MCUbl_ver:", 0); 1079 frame_info.append(ESC_MCU_BL_VER, 1); 1080 frame_info.append("MCU_ver:", 0); 1081 frame_info.append(ESC_MCU_RUN_VER, 1); 1082 1083 // Sys config present device 1084 if (hostPosition != BMC_POSITION) 1085 { 1086 frame_info.append("Sys Conf. info:", 0); 1087 1088 // Dimm info 1089 std::vector<std::string> data; 1090 if (sysConfig(data, pos) == 0) 1091 { 1092 for (auto& info : data) 1093 { 1094 frame_info.append(info.c_str(), 1); 1095 } 1096 } 1097 else 1098 { 1099 frame_info.append("Not Found", 1); 1100 } 1101 1102 // Processor info 1103 std::string result; 1104 if (procInfo(result, pos) != 0) 1105 { 1106 result = "Not Found"; 1107 } 1108 frame_info.append(result.c_str(), 1); 1109 } 1110 1111 } // End of update frame 1112 1113 if (page > frame_info.pages) 1114 { 1115 return -1; 1116 } 1117 1118 ret = frame_info.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE); 1119 if (ret < 0) 1120 { 1121 *count = 0; 1122 return -1; 1123 } 1124 *count = (uint8_t)ret; 1125 1126 if (page < frame_info.pages) 1127 *next = page + 1; 1128 else 1129 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the 1130 // last page 1131 1132 return 0; 1133 } 1134 1135 int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t* next, 1136 uint8_t* count, uint8_t* buffer) 1137 { 1138 switch (frame) 1139 { 1140 case 1: // info_page 1141 return udbg_get_info_page(frame, page, next, count, buffer); 1142 case 2: // critical SEL 1143 return udbg_get_cri_sel(frame, page, next, count, buffer); 1144 case 3: // critical Sensor 1145 return udbg_get_cri_sensor(frame, page, next, count, buffer); 1146 default: 1147 return -1; 1148 } 1149 } 1150 1151 static uint8_t panel_main(uint8_t item) 1152 { 1153 // Update item list when select item 0 1154 switch (item) 1155 { 1156 case 1: 1157 return panels[PANEL_BOOT_ORDER].select(0); 1158 case 2: 1159 return panels[PANEL_POWER_POLICY].select(0); 1160 default: 1161 return PANEL_MAIN; 1162 } 1163 } 1164 1165 static uint8_t panel_boot_order(uint8_t) 1166 { 1167 /* To be implemented */ 1168 #if 0 1169 int i; 1170 unsigned char buff[MAX_VALUE_LEN], pickup, len; 1171 size_t pos = plat_get_fru_sel(); 1172 if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0) 1173 { 1174 if (item > 0 && item < SIZE_BOOT_ORDER) 1175 { 1176 pickup = buff[item]; 1177 while (item > 1) 1178 { 1179 buff[item] = buff[item - 1]; 1180 item--; 1181 } 1182 buff[item] = pickup; 1183 buff[0] |= 0x80; 1184 pal_set_boot_order(pos, buff, buff, &len); 1185 1186 // refresh items 1187 return panels[PANEL_BOOT_ORDER].select(0); 1188 } 1189 1190 // '*': boot flags valid, BIOS has not yet read 1191 snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32, "Boot Order%c", 1192 (buff[0] & 0x80) ? '*' : '\0'); 1193 1194 for (i = 1; i < SIZE_BOOT_ORDER; i++) 1195 { 1196 switch (buff[i]) 1197 { 1198 case 0x0: 1199 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1200 " USB device"); 1201 break; 1202 case 0x1: 1203 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1204 " Network v4"); 1205 break; 1206 case (0x1 | 0x8): 1207 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1208 " Network v6"); 1209 break; 1210 case 0x2: 1211 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1212 " SATA HDD"); 1213 break; 1214 case 0x3: 1215 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1216 " SATA-CDROM"); 1217 break; 1218 case 0x4: 1219 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32, 1220 " Other"); 1221 break; 1222 default: 1223 panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0'; 1224 break; 1225 } 1226 } 1227 1228 // remove empty items 1229 for (i--; 1230 (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0); 1231 i--) 1232 ; 1233 1234 panels[PANEL_BOOT_ORDER].item_num = i; 1235 } 1236 else 1237 { 1238 panels[PANEL_BOOT_ORDER].item_num = 0; 1239 } 1240 #endif 1241 return PANEL_BOOT_ORDER; 1242 } 1243 1244 static uint8_t panel_power_policy(uint8_t) 1245 { 1246 /* To be cleaned */ 1247 #if 0 1248 uint8_t buff[32] = {0}; 1249 uint8_t res_len; 1250 size_t pos = plat_get_fru_sel(); 1251 uint8_t policy; 1252 uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS, 1253 POWER_CFG_OFF}; 1254 1255 if (pos != FRU_ALL) 1256 { 1257 if (item > 0 && item <= sizeof(pwr_policy_item_map)) 1258 { 1259 policy = pwr_policy_item_map[item - 1]; 1260 pal_set_power_restore_policy(pos, &policy, NULL); 1261 } 1262 pal_get_chassis_status(pos, NULL, buff, &res_len); 1263 policy = (((uint8_t)buff[0]) >> 5) & 0x7; 1264 snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32, "%cPower On", 1265 policy == POWER_CFG_ON ? '*' : ' '); 1266 snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32, "%cLast State", 1267 policy == POWER_CFG_LPS ? '*' : ' '); 1268 snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32, "%cPower Off", 1269 policy == POWER_CFG_OFF ? '*' : ' '); 1270 panels[PANEL_POWER_POLICY].item_num = 3; 1271 } 1272 else 1273 { 1274 panels[PANEL_POWER_POLICY].item_num = 0; 1275 } 1276 #endif 1277 return PANEL_POWER_POLICY; 1278 } 1279 1280 int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item, 1281 uint8_t* count, uint8_t* buffer) 1282 { 1283 if (panel > panelNum || panel < PANEL_MAIN) 1284 return IPMI_CC_PARM_OUT_OF_RANGE; 1285 1286 // No more item; End of item list 1287 if (item > panels[panel].item_num) 1288 return IPMI_CC_PARM_OUT_OF_RANGE; 1289 1290 switch (operation) 1291 { 1292 case 0: // Get Description 1293 break; 1294 case 1: // Select item 1295 panel = panels[panel].select(item); 1296 item = 0; 1297 break; 1298 case 2: // Back 1299 panel = panels[panel].parent; 1300 item = 0; 1301 break; 1302 default: 1303 return IPMI_CC_PARM_OUT_OF_RANGE; 1304 } 1305 1306 buffer[0] = panel; 1307 buffer[1] = item; 1308 buffer[2] = strlen(panels[panel].item_str[item]); 1309 if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE) 1310 { 1311 memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]); 1312 } 1313 *count = buffer[2] + 3; 1314 return IPMI_CC_OK; 1315 } 1316 1317 } // end of namespace ipmi 1318