/* * Copyright (c) 2018-present Facebook. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include namespace ipmi { ipmi_ret_t getNetworkData(uint8_t lan_param, char* data); int8_t getFruData(std::string& serial, std::string& name); int8_t sysConfig(std::vector& data, size_t pos); int8_t procInfo(std::string& result, size_t pos); bool isMultiHostPlatform(); /* Declare Host Selector interface and path */ namespace selector { const std::string path = "/xyz/openbmc_project/Chassis/Buttons/HostSelector"; const std::string interface = "xyz.openbmc_project.Chassis.Buttons.HostSelector"; } // namespace selector /* Declare storage functions used here */ namespace storage { int getSensorValue(std::string&, double&); int getSensorUnit(std::string&, std::string&); int getSensorThreshold(std::string&, std::string&); } // namespace storage namespace boot { std::tuple objPath(size_t id); void setBootOrder(std::string bootObjPath, const std::vector& bootSeq, std::string hostName); void getBootOrder(std::string bootObjPath, std::vector& bootSeq, std::string hostName); } // namespace boot void getMaxHostPosition(size_t& maxPosition) { try { std::shared_ptr dbus = getSdBus(); std::string service = getService(*dbus, ipmi::selector::interface, ipmi::selector::path); Value variant = getDbusProperty(*dbus, service, ipmi::selector::path, ipmi::selector::interface, "MaxPosition"); maxPosition = std::get(variant); } catch (const std::exception& e) { lg2::error("Unable to get max host position - {MAXPOSITION}", "MAXPOSITION", maxPosition); throw e; } } void getSelectorPosition(size_t& hostPosition) { try { std::shared_ptr dbus = getSdBus(); std::string service = getService(*dbus, ipmi::selector::interface, ipmi::selector::path); Value variant = getDbusProperty(*dbus, service, ipmi::selector::path, ipmi::selector::interface, "Position"); hostPosition = std::get(variant); } catch (const std::exception& e) { lg2::error("Unable to get host position - {POSITION}", "POSITION", hostPosition); throw e; } } static int panelNum = (sizeof(panels) / sizeof(struct ctrl_panel)) - 1; /* Returns the FRU the hand-switch is switched to. If it is switched to BMC * it returns FRU_ALL. Note, if in err, it returns FRU_ALL */ static size_t plat_get_fru_sel() { size_t position; bool platform = isMultiHostPlatform(); if (platform == true) { getSelectorPosition(position); if (position == BMC_POSITION) { return FRU_ALL; } } else { /* For Tiogapass it just return 1, * can modify to support more platform */ position = 1; } return position; } // return 0 on seccuess int frame::init(size_t size) { // Reset status idx_head = idx_tail = 0; lines = 0; esc_sts = 0; pages = 1; if (buf != NULL && max_size == size) { // reinit return 0; } if (buf != NULL && max_size != size) { delete[] buf; } // Initialize Configuration title[0] = '\0'; buf = new char[size]; max_size = size; max_page = size; line_per_page = 7; line_width = 16; overwrite = 0; if (buf) return 0; else return -1; } // return 0 on seccuess int frame::append(const char* string, int indent) { const size_t buf_size = 128; char lbuf[buf_size]; char* ptr; int ret; ret = parse(lbuf, buf_size, string, indent); if (ret < 0) return ret; for (ptr = lbuf; *ptr != '\0'; ptr++) { if (isFull()) { if (overwrite) { if (buf[idx_head] == LINE_DELIMITER) lines--; idx_head = (idx_head + 1) % max_size; } else return -1; } buf[idx_tail] = *ptr; if (*ptr == LINE_DELIMITER) lines++; idx_tail = (idx_tail + 1) % max_size; } pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0); if (pages > max_page) pages = max_page; return 0; } // return 0 on seccuess int frame::insert(const char* string, int indent) { const size_t buf_size = 128; char lbuf[buf_size]; char* ptr; int ret; int i; ret = parse(lbuf, buf_size, string, indent); if (ret < 0) return ret; for (i = strlen(lbuf) - 1; i >= 0; i--) { ptr = &lbuf[i]; if (isFull()) { if (overwrite) { idx_tail = (idx_tail + max_size - 1) % max_size; if (buf[idx_tail] == LINE_DELIMITER) lines--; } else return -1; } idx_head = (idx_head + max_size - 1) % max_size; buf[idx_head] = *ptr; if (*ptr == LINE_DELIMITER) lines++; } pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0); if (pages > max_page) pages = max_page; return 0; } // return page size int frame::getPage(int page, char* page_buf, size_t page_buf_size) { int ret; uint16_t line = 0; uint16_t idx, len; if (buf == NULL) return -1; // 1-based page if (page > pages || page < 1) return -1; if (page_buf == NULL || page_buf_size == 0) return -1; ret = snprintf(page_buf, 17, "%-10s %02d/%02d", title, page, pages); len = strlen(page_buf); if (ret < 0) return -1; line = 0; idx = idx_head; while (line < ((page - 1) * line_per_page) && idx != idx_tail) { if (buf[idx] == LINE_DELIMITER) line++; idx = (idx + 1) % max_size; } while (line < ((page)*line_per_page) && idx != idx_tail) { if (buf[idx] == LINE_DELIMITER) { line++; } else { page_buf[len++] = buf[idx]; if (len == (page_buf_size - 1)) { break; } } idx = (idx + 1) % max_size; } return len; } // return 1 for frame buffer full int frame::isFull() { if (buf == NULL) return -1; if ((idx_tail + 1) % max_size == idx_head) return 1; else return 0; } // return 1 for Escape Sequence int frame::isEscSeq(char chr) { uint8_t curr_sts = esc_sts; if (esc_sts == 0 && (chr == 0x1b)) esc_sts = 1; // Escape Sequence else if (esc_sts == 1 && (chr == 0x5b)) esc_sts = 2; // Control Sequence Introducer(CSI) else if (esc_sts == 1 && (chr != 0x5b)) esc_sts = 0; else if (esc_sts == 2 && (chr >= 0x40 && chr <= 0x7e)) esc_sts = 0; if (curr_sts || esc_sts) return 1; else return 0; } // return 0 on success int frame::parse(char* lbuf, size_t buf_size, const char* input, int indent) { uint8_t pos, esc; size_t i; const char *in, *end; if (buf == NULL || input == NULL) return -1; if (indent >= line_width || indent < 0) return -1; in = input; end = in + strlen(input); pos = 0; // line position esc = 0; // escape state i = 0; // buf index while (in != end) { if (i >= buf_size) break; if (pos < indent) { // fill indent lbuf[i++] = ' '; pos++; continue; } esc = isEscSeq(*in); if (!esc && pos == line_width) { lbuf[i++] = LINE_DELIMITER; pos = 0; continue; } if (!esc) pos++; // fill input data lbuf[i++] = *(in++); } // padding while (pos <= line_width) { if (i >= buf_size) break; if (pos < line_width) lbuf[i++] = ' '; else lbuf[i++] = LINE_DELIMITER; pos++; } // full if (i >= buf_size) return -1; lbuf[i++] = '\0'; return 0; } static int chk_cri_sel_update(uint8_t* cri_sel_up) { FILE* fp; struct stat file_stat; size_t pos = plat_get_fru_sel(); static uint8_t pre_pos = 0xff; fp = fopen("/mnt/data/cri_sel", "r"); if (fp) { if ((stat("/mnt/data/cri_sel", &file_stat) == 0) && (file_stat.st_mtime != frame_sel.mtime || pre_pos != pos)) { *cri_sel_up = 1; } else { *cri_sel_up = 0; } fclose(fp); } else { if (frame_sel.buf == NULL || frame_sel.lines != 0 || pre_pos != pos) { *cri_sel_up = 1; } else { *cri_sel_up = 0; } } pre_pos = pos; return 0; } int plat_udbg_get_frame_info(uint8_t* num) { *num = 3; return 0; } int plat_udbg_get_updated_frames(uint8_t* count, uint8_t* buffer) { uint8_t cri_sel_up = 0; uint8_t info_page_up = 1; *count = 0; // info page update if (info_page_up == 1) { buffer[*count] = 1; *count += 1; } // cri sel update chk_cri_sel_update(&cri_sel_up); if (cri_sel_up == 1) { buffer[*count] = 2; *count += 1; } // cri sensor update buffer[*count] = 3; *count += 1; return 0; } int plat_udbg_get_post_desc(uint8_t index, uint8_t* next, uint8_t phase, uint8_t* end, uint8_t* length, uint8_t* buffer) { nlohmann::json postObj; std::string postCode; /* Get post description data stored in json file */ std::ifstream file(JSON_POST_DATA_FILE); if (file) { file >> postObj; file.close(); } else { phosphor::logging::log( "Post code description file not found", phosphor::logging::entry("POST_CODE_FILE=%s", JSON_POST_DATA_FILE)); return -1; } std::string phaseStr = "PhaseAny"; if (postObj.find(phaseStr) == postObj.end()) { phaseStr = "Phase" + std::to_string(phase); } if (postObj.find(phaseStr) == postObj.end()) { phosphor::logging::log( "Post code phase not available", phosphor::logging::entry("PHASE=%d", phase)); return -1; } auto phaseObj = postObj[phaseStr]; int phaseSize = phaseObj.size(); for (int i = 0; i < phaseSize; i++) { postCode = phaseObj[i][0]; if (index == stoul(postCode, nullptr, 16)) { std::string postDesc = phaseObj[i][1]; *length = postDesc.size(); memcpy(buffer, postDesc.data(), *length); buffer[*length] = '\0'; if (phaseSize != i + 1) { postCode = phaseObj[i + 1][0]; *next = stoul(postCode, nullptr, 16); *end = 0; } else { if (postObj.size() != phase) { std::string nextPhaseStr = "Phase" + std::to_string(phase + 1); postCode = postObj[nextPhaseStr][0][0]; *next = stoul(postCode, nullptr, 16); *end = 0; } else { *next = 0xff; *end = 1; } } return 0; } } phosphor::logging::log( "Post code description data not available", phosphor::logging::entry("PHASE_CODE=%d_0x%x", phase, index)); return -1; } int plat_udbg_get_gpio_desc(uint8_t index, uint8_t* next, uint8_t* level, uint8_t* def, uint8_t* length, uint8_t* buffer) { nlohmann::json gpioObj; std::string gpioPin; /* Get gpio data stored in json file */ std::ifstream file(JSON_GPIO_DATA_FILE); if (file) { file >> gpioObj; file.close(); } else { phosphor::logging::log( "GPIO pin description file not found", phosphor::logging::entry("GPIO_PIN_DETAILS_FILE=%s", JSON_GPIO_DATA_FILE)); return -1; } if (gpioObj.find(DEBUG_GPIO_KEY) == gpioObj.end()) { phosphor::logging::log( "GPIO pin details not available", phosphor::logging::entry("GPIO_JSON_KEY=%d", DEBUG_GPIO_KEY)); return -1; } auto obj = gpioObj[DEBUG_GPIO_KEY]; int objSize = obj.size(); for (int i = 0; i < objSize; i++) { if (obj[i].size() != GPIO_ARRAY_SIZE) { phosphor::logging::log( "Size of gpio array is incorrect", phosphor::logging::entry("EXPECTED_SIZE=%d", GPIO_ARRAY_SIZE)); return -1; } gpioPin = obj[i][GPIO_PIN_INDEX]; if (index == stoul(gpioPin, nullptr, 16)) { if (objSize != i + 1) { gpioPin = obj[i + 1][GPIO_PIN_INDEX]; *next = stoul(gpioPin, nullptr, 16); } else { *next = 0xff; } *level = obj[i][GPIO_LEVEL_INDEX]; *def = obj[i][GPIO_DEF_INDEX]; std::string gpioDesc = obj[i][GPIO_DESC_INDEX]; *length = gpioDesc.size(); memcpy(buffer, gpioDesc.data(), *length); buffer[*length] = '\0'; return 0; } } phosphor::logging::log( "GPIO pin description data not available", phosphor::logging::entry("GPIO_PIN=0x%x", index)); return -1; } static int udbg_get_cri_sel(uint8_t, uint8_t page, uint8_t* next, uint8_t* count, uint8_t* buffer) { if (page == 1) { // initialize and clear frame frame_sel.init(FRAME_BUFF_SIZE); frame_sel.overwrite = 1; frame_sel.max_page = 20; snprintf(frame_sel.title, 32, "Cri SEL"); static constexpr const auto depth = 0; std::vector paths; std::shared_ptr dbus = getSdBus(); auto mapperCall = dbus->new_method_call( "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper", "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths"); static constexpr std::array interface = { "xyz.openbmc_project.Logging.Entry"}; mapperCall.append("/", depth, interface); try { auto reply = dbus->call(mapperCall); reply.read(paths); } catch (sdbusplus::exception_t& e) { phosphor::logging::log(e.what()); return -1; } std::string message; // Iterate each loggings for (const auto& path : paths) { Value variant = ipmi::getDbusProperty( *dbus, "xyz.openbmc_project.Logging", path, "xyz.openbmc_project.Logging.Entry", "Severity"); // Only filter critical sel if (std::get(variant) != "xyz.openbmc_project.Logging.Entry.Level.Critical") { continue; } variant = ipmi::getDbusProperty( *dbus, "xyz.openbmc_project.Logging", path, "xyz.openbmc_project.Logging.Entry", "Message"); message = std::get(variant); frame_sel.insert(message.c_str(), 0); } } if (page > frame_sel.pages) { return -1; } int ret = frame_sel.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE); if (ret < 0) { *count = 0; return -1; } *count = (uint8_t)ret; if (page < frame_sel.pages) *next = page + 1; else *next = 0xFF; // Set the value of next to 0xFF to indicate this is the // last page return 0; } static int udbg_get_cri_sensor(uint8_t, uint8_t page, uint8_t* next, uint8_t* count, uint8_t* buffer) { int ret; double fvalue; size_t pos = plat_get_fru_sel(); if (page == 1) { // Only update frame data while getting page 1 // initialize and clear frame frame_snr.init(FRAME_BUFF_SIZE); snprintf(frame_snr.title, 32, "CriSensor"); nlohmann::json senObj; /* Get critical sensor names stored in json file */ std::ifstream file(JSON_SENSOR_NAMES_FILE); if (file) { file >> senObj; file.close(); } else { phosphor::logging::log( "Critical Sensor names file not found", phosphor::logging::entry("CRI_SENSOR_NAMES_FILE=%s", JSON_SENSOR_NAMES_FILE)); return -1; } /* Get sensors values for all critical sensors */ for (auto& j : senObj.items()) { std::string senName = j.key(); auto val = j.value(); if (senName[0] == '_') { senName = std::to_string(pos) + senName; } if (ipmi::storage::getSensorValue(senName, fvalue) == 0) { std::stringstream ss; int prec = 0; // Default value if (val.find("precision") != val.end()) prec = val["precision"]; ss << std::fixed << std::setprecision(prec) << fvalue; std::string senStr; if (val.find("short_name") != val.end()) senStr = val["short_name"]; else senStr = senName; senStr += ss.str(); /* Get unit string for sensor and append in output */ std::string unitStr; if (ipmi::storage::getSensorUnit(senName, unitStr) == 0) senStr += unitStr; std::string thresholdStr; int ret = ipmi::storage::getSensorThreshold(senName, thresholdStr); if (ret < 0) { phosphor::logging::log( "Error getting critical sensor threshold status", phosphor::logging::entry("CRI_SENSOR_NAME=%s", senName.c_str())); return -1; } if (thresholdStr.size() != 0) { senStr += ("/" + thresholdStr); std::string senStrWithBlinkAndInvertColor = ESC_ALT + senStr + ESC_RST; frame_snr.append(senStrWithBlinkAndInvertColor.c_str(), 0); } else { frame_snr.append(senStr.c_str(), 0); } } else { phosphor::logging::log( "Critical sensor not found", phosphor::logging::entry("CRI_SENSOR_NAME=%s", senName.c_str())); } } } // End of update frame if (page > frame_snr.pages) { return -1; } ret = frame_snr.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE); if (ret < 0) { *count = 0; return -1; } *count = (uint8_t)ret; if (page < frame_snr.pages) *next = page + 1; else *next = 0xFF; // Set the value of next to 0xFF to indicate this is the // last page return 0; } static int getBiosVer(std::string& ver, size_t hostPosition) { nlohmann::json appObj; std::ifstream file(JSON_APP_DATA_FILE); if (file) { file >> appObj; file.close(); std::string version_key = KEY_SYSFW_VER + std::to_string(hostPosition); if (appObj.find(version_key) != appObj.end()) { ver = appObj[version_key].get(); return 0; } } return -1; } int sendBicCmd(uint8_t netFn, uint8_t cmd, uint8_t bicAddr, std::vector& cmdData, std::vector& respData) { static constexpr uint8_t lun = 0; auto bus = getSdBus(); auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb", "sendRequest"); method.append(bicAddr, netFn, lun, cmd, cmdData); auto reply = bus->call(method); if (reply.is_method_error()) { phosphor::logging::log( "Error reading from BIC"); return -1; } IpmbMethodType resp; reply.read(resp); respData = std::move(std::get>(resp)); return 0; } int sendMeCmd(uint8_t netFn, uint8_t cmd, std::vector& cmdData, std::vector& respData) { auto bus = getSdBus(); if (DEBUG) { std::cout << "ME NetFn:cmd " << (int)netFn << ":" << (int)cmd << "\n"; std::cout << "ME req data: "; for (auto d : cmdData) { std::cout << d << " "; } std::cout << "\n"; } auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb", "sendRequest"); method.append(meAddress, netFn, lun, cmd, cmdData); auto reply = bus->call(method); if (reply.is_method_error()) { phosphor::logging::log( "Error reading from ME"); return -1; } IpmbMethodType resp; reply.read(resp); respData = std::move(std::get>(resp)); if (DEBUG) { std::cout << "ME resp data: "; for (auto d : respData) { std::cout << d << " "; } std::cout << "\n"; } return 0; } static int udbg_get_info_page(uint8_t, uint8_t page, uint8_t* next, uint8_t* count, uint8_t* buffer) { char line_buff[1000]; [[maybe_unused]] char* pres_dev = line_buff; [[maybe_unused]] size_t pos = plat_get_fru_sel(); int ret; std::string serialName = "SerialNumber"; std::string partName = "PartNumber"; std::string verDel = "VERSION="; std::string verPath = "/etc/os-release"; size_t hostPosition = 0; size_t maxPosition; if (page == 1) { // Only update frame data while getting page 1 // initialize and clear frame frame_info.init(FRAME_BUFF_SIZE); snprintf(frame_info.title, 32, "SYS_Info"); bool platform = isMultiHostPlatform(); if (platform == true) { hostPosition = plat_get_fru_sel(); } getMaxHostPosition(maxPosition); if (hostPosition == BMC_POSITION || hostInstances == "0") { frame_info.append("FRU:spb", 0); } else if (hostPosition != BMC_POSITION && hostPosition <= maxPosition) { std::string data = "FRU:slot" + std::to_string(hostPosition); frame_info.append(data.c_str(), 0); } // FRU std::string data; frame_info.append("SN:", 0); if (getFruData(data, serialName) != 0) { data = "Not Found"; } frame_info.append(data.c_str(), 1); frame_info.append("PN:", 0); if (getFruData(data, partName) != 0) { data = "Not Found"; } frame_info.append(data.c_str(), 1); // LAN getNetworkData(3, line_buff); frame_info.append("BMC_IP:", 0); frame_info.append(line_buff, 1); getNetworkData(59, line_buff); frame_info.append("BMC_IPv6:", 0); frame_info.append(line_buff, 1); // BMC ver std::ifstream file(verPath); if (file) { std::string line; while (std::getline(file, line)) { if (line.find(verDel) != std::string::npos) { std::string bmcVer = line.substr(verDel.size()); frame_info.append("BMC_FW_ver:", 0); frame_info.append(bmcVer.c_str(), 1); break; } } } if (hostPosition != BMC_POSITION) { // BIOS ver std::string biosVer; if (getBiosVer(biosVer, hostPosition) == 0) { frame_info.append("BIOS_FW_ver:", 0); frame_info.append(biosVer.c_str(), 1); } } /* TBD: Board ID needs implementation */ // Board ID // Battery - Use Escape sequence frame_info.append("Battery:", 0); frame_info.append(ESC_BAT " ", 1); // frame_info.append(&frame_info, esc_bat, 1); // MCU Version - Use Escape sequence frame_info.append("MCUbl_ver:", 0); frame_info.append(ESC_MCU_BL_VER, 1); frame_info.append("MCU_ver:", 0); frame_info.append(ESC_MCU_RUN_VER, 1); // Sys config present device if (hostPosition != BMC_POSITION) { frame_info.append("Sys Conf. info:", 0); // Dimm info std::vector data; if (sysConfig(data, pos) == 0) { for (auto& info : data) { frame_info.append(info.c_str(), 1); } } else { frame_info.append("Not Found", 1); } // Processor info std::string result; if (procInfo(result, pos) != 0) { result = "Not Found"; } frame_info.append(result.c_str(), 1); } } // End of update frame if (page > frame_info.pages) { return -1; } ret = frame_info.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE); if (ret < 0) { *count = 0; return -1; } *count = (uint8_t)ret; if (page < frame_info.pages) *next = page + 1; else *next = 0xFF; // Set the value of next to 0xFF to indicate this is the // last page return 0; } int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t* next, uint8_t* count, uint8_t* buffer) { switch (frame) { case 1: // info_page return udbg_get_info_page(frame, page, next, count, buffer); case 2: // critical SEL return udbg_get_cri_sel(frame, page, next, count, buffer); case 3: // critical Sensor return udbg_get_cri_sensor(frame, page, next, count, buffer); default: return -1; } } static uint8_t panel_main(uint8_t item) { // Update item list when select item 0 switch (item) { case 1: return panels[PANEL_BOOT_ORDER].select(0); case 2: return panels[PANEL_POWER_POLICY].select(0); default: return PANEL_MAIN; } } static uint8_t panel_boot_order(uint8_t selectedItemIndex) { static constexpr size_t sizeBootOrder = 6; static constexpr size_t bootValid = 0x80; std::vector bootSeq; ctrl_panel& bootOrderPanel = panels[PANEL_BOOT_ORDER]; size_t pos = plat_get_fru_sel(); if (pos == FRU_ALL) { bootOrderPanel.item_num = 0; return PANEL_BOOT_ORDER; } auto [bootObjPath, hostName] = ipmi::boot::objPath(pos); ipmi::boot::getBootOrder(bootObjPath, bootSeq, hostName); uint8_t& bootMode = bootSeq.front(); // One item is selected to set a new boot sequence. // The selected item become the first boot order. if (selectedItemIndex > 0 && selectedItemIndex < sizeBootOrder) { // Move the selected item to second element (the first one is boot mode) std::rotate(bootSeq.begin() + 1, bootSeq.begin() + selectedItemIndex, bootSeq.begin() + selectedItemIndex + 1); bootMode |= bootValid; try { ipmi::boot::setBootOrder(bootObjPath, bootSeq, hostName); } catch (const std::exception& e) { lg2::error("Fail to set boot order : {ERROR}", "ERROR", e); } // refresh items return bootOrderPanel.select(0); } // '*': boot flags valid, BIOS has not yet read bootOrderPanel.item_str[0] = std::string("Boot Order") + ((bootMode & bootValid) ? "*" : ""); static const std::unordered_map bootOrderMappingTable = { {0x00, " USB device"}, {0x01, " Network v4"}, {0x02, " SATA HDD"}, {0x03, " SATA-CDROM"}, {0x04, " Other"}, {0x09, " Network v6"}, }; size_t validItem = 0; for (size_t i = 1; i < sizeBootOrder; i++) { auto find = bootOrderMappingTable.find(bootSeq[i]); if (find == bootOrderMappingTable.end()) { lg2::error("Unknown boot order : {BOOTORDER}", "BOOTORDER", bootSeq[i]); break; } bootOrderPanel.item_str[i] = find->second; validItem++; } bootOrderPanel.item_num = validItem; return PANEL_BOOT_ORDER; } static uint8_t panel_power_policy(uint8_t) { /* To be cleaned */ #if 0 uint8_t buff[32] = {0}; uint8_t res_len; size_t pos = plat_get_fru_sel(); uint8_t policy; uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS, POWER_CFG_OFF}; if (pos != FRU_ALL) { if (item > 0 && item <= sizeof(pwr_policy_item_map)) { policy = pwr_policy_item_map[item - 1]; pal_set_power_restore_policy(pos, &policy, NULL); } pal_get_chassis_status(pos, NULL, buff, &res_len); policy = (((uint8_t)buff[0]) >> 5) & 0x7; snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32, "%cPower On", policy == POWER_CFG_ON ? '*' : ' '); snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32, "%cLast State", policy == POWER_CFG_LPS ? '*' : ' '); snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32, "%cPower Off", policy == POWER_CFG_OFF ? '*' : ' '); panels[PANEL_POWER_POLICY].item_num = 3; } else { panels[PANEL_POWER_POLICY].item_num = 0; } #endif return PANEL_POWER_POLICY; } ipmi_ret_t plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item, uint8_t* count, uint8_t* buffer) { if (panel > panelNum || panel < PANEL_MAIN) return IPMI_CC_PARM_OUT_OF_RANGE; // No more item; End of item list if (item > panels[panel].item_num) return IPMI_CC_PARM_OUT_OF_RANGE; switch (operation) { case 0: // Get Description break; case 1: // Select item panel = panels[panel].select(item); item = 0; break; case 2: // Back panel = panels[panel].parent; item = 0; break; default: return IPMI_CC_PARM_OUT_OF_RANGE; } buffer[0] = panel; buffer[1] = item; buffer[2] = std::size(panels[panel].item_str[item]); if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE) { std::memcpy(&buffer[3], (panels[panel].item_str[item]).c_str(), buffer[2]); } *count = buffer[2] + 3; return IPMI_CC_OK; } } // end of namespace ipmi