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