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