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