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