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