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