common/recipes-core/ipmid/files/usb-dbg.c (933 lines of code) (raw):
/*
*
* Copyright 2016-present Facebook. All Rights Reserved.
*
* This file represents platform specific implementation for storing
* SDR record entries and acts as back-end for IPMI stack
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <openbmc/pal.h>
#include <openbmc/sdr.h>
#include <openbmc/kv.h>
#include <openbmc/pal_sensors.h>
#include <openbmc/fruid.h>
#include <arpa/inet.h>
#include "usb-dbg-conf.h"
#define ESCAPE "\x1B"
#define ESC_BAT ESCAPE"B"
#define ESC_MCU_BL_VER ESCAPE"U"
#define ESC_MCU_RUN_VER ESCAPE"R"
#define ESC_ALT ESCAPE"[5;7m"
#define ESC_RST ESCAPE"[m"
#define ESC_NOR ESCAPE"[0m"
#define LINE_DELIMITER '\x1F'
#ifdef CONFIG_FBY3
#define FRAME_BUFF_SIZE 5120
#else
#define FRAME_BUFF_SIZE 4096
#endif
#define FRAME_PAGE_BUF_SIZE 256
#define MAX_UART_SEL_NAME_SIZE 16
struct frame {
char title[32];
size_t max_size;
size_t max_page;
char *buf;
uint16_t idx_head, idx_tail;
uint8_t line_per_page;
uint8_t line_width;
uint16_t lines, pages;
uint8_t esc_sts;
uint8_t overwrite;
time_t mtime;
int (*init)(struct frame *self, size_t size);
int (*append)(struct frame *self, char *string, int indent);
int (*insert)(struct frame *self, char *string, int indent);
int (*getPage)(struct frame *self, int page, char *page_buf, size_t page_buf_size);
int (*isFull)(struct frame *self);
int (*isEscSeq)(struct frame *self, char chr);
int (*parse)(struct frame *self, char *buf, size_t buf_size, char *input, int indent);
};
// return 0 on seccuess
static int frame_init (struct frame *self, size_t size) {
// Reset status
self->idx_head = self->idx_tail = 0;
self->lines = 0;
self->esc_sts = 0;
self->pages = 1;
if (self->buf != NULL && self->max_size == size) {
// reinit
return 0;
}
if (self->buf != NULL && self->max_size != size){
free(self->buf);
}
// Initialize Configuration
self->title[0] = '\0';
self->buf = malloc(size);
self->max_size = size;
self->max_page = size;
self->line_per_page = 7;
self->line_width = 16;
self->overwrite = 0;
if (self->buf)
return 0;
else
return -1;
}
static const char *find_esc(const char *buf, int blen, const char *esc, size_t elen) {
const char *ptr;
// to find the last CSI-codes
if (!(ptr = memrchr(buf, esc[0], blen)))
return NULL;
if ((blen - (ptr - buf) >= elen) && !memcmp(ptr, esc, elen))
return ptr;
return NULL;
}
// return 0 on seccuess
static int frame_append (struct frame *self, char *string, int indent)
{
const size_t buf_size = 64;
char buf[buf_size];
char *ptr;
int ret;
ret = self->parse(self, buf, buf_size, string, indent);
if (ret < 0)
return ret;
for (ptr = buf; *ptr != '\0'; ptr++) {
if (self->isFull(self)) {
if (self->overwrite) {
if (self->buf[self->idx_head] == LINE_DELIMITER)
self->lines--;
self->idx_head = (self->idx_head + 1) % self->max_size;
} else
return -1;
}
if (*ptr == LINE_DELIMITER) {
self->lines++;
// workaround when Blink CSI-codes spread 2 pages,
// add ESC_RST to the end of previous page,
// add ESC_ALT to the start of next page
if (!(self->lines % self->line_per_page)) {
const char *esc = find_esc(buf, ptr - buf, ESC_ALT, strlen(ESC_ALT));
if (esc != NULL) {
esc += strlen(ESC_ALT);
if (!find_esc(esc, ptr - esc, ESC_RST, strlen(ESC_RST))) {
char tmp[16], *ptmp;
snprintf(tmp, sizeof(tmp), ESC_RST"%c"ESC_ALT, LINE_DELIMITER);
for (ptmp = tmp; *ptmp; ptmp++) {
if (self->isFull(self)) {
if (!self->overwrite) {
return -1;
}
if (self->buf[self->idx_head] == LINE_DELIMITER)
self->lines--;
self->idx_head = (self->idx_head + 1) % self->max_size;
}
self->buf[self->idx_tail] = *ptmp;
self->idx_tail = (self->idx_tail + 1) % self->max_size;
}
continue;
}
}
}
}
self->buf[self->idx_tail] = *ptr;
self->idx_tail = (self->idx_tail + 1) % self->max_size;
}
self->pages = (self->lines / self->line_per_page) +
((self->lines % self->line_per_page)?1:0);
if (self->pages > self->max_page)
self->pages = self->max_page;
return 0;
}
// return 0 on seccuess
static int frame_insert (struct frame *self, char *string, int indent)
{
const size_t buf_size = 128;
char buf[buf_size];
char *ptr;
int ret;
int i;
ret = self->parse(self, buf, buf_size, string, indent);
if (ret < 0)
return ret;
for (i = strlen(buf) - 1; i >= 0; i--) {
ptr = &buf[i];
if (self->isFull(self)) {
if (self->overwrite) {
self->idx_tail = (self->idx_tail + self->max_size - 1) % self->max_size;
if (self->buf[self->idx_tail] == LINE_DELIMITER)
self->lines--;
} else
return -1;
}
self->idx_head = (self->idx_head + self->max_size - 1) % self->max_size;
self->buf[self->idx_head] = *ptr;
if (*ptr == LINE_DELIMITER)
self->lines++;
}
self->pages = (self->lines / self->line_per_page) +
((self->lines % self->line_per_page)?1:0);
if (self->pages > self->max_page)
self->pages = self->max_page;
return 0;
}
// return page size
static int frame_getPage (struct frame *self, int page, char *page_buf, size_t page_buf_size)
{
int ret;
uint16_t line = 0;
uint16_t idx, len;
if (self == NULL || self->buf == NULL)
return -1;
// 1-based page
if (page > self->pages || page < 1)
return -1;
if (page_buf == NULL || page_buf_size < self->line_width)
return -1;
ret = snprintf(page_buf, 17, "%-10s %02d/%02d", self->title, page, self->pages);
len = strlen(page_buf);
if (ret < 0)
return -1;
line = 0;
idx = self->idx_head;
while (line < ((page-1) * self->line_per_page) && idx != self->idx_tail) {
if (self->buf[idx] == LINE_DELIMITER)
line++;
idx = (idx + 1) % self->max_size;
}
while (line < ((page) * self->line_per_page) && idx != self->idx_tail) {
if (self->buf[idx] == LINE_DELIMITER) {
line++;
} else {
page_buf[len++] = self->buf[idx];
if (len == (page_buf_size - 1)) {
break;
}
}
idx = (idx + 1) % self->max_size;
}
return len;
}
// return 1 for frame buffer full
static int frame_isFull (struct frame *self)
{
if (self == NULL || self->buf == NULL)
return -1;
if ((self->idx_tail + 1) % self->max_size == self->idx_head)
return 1;
else
return 0;
}
// return 1 for Escape Sequence
static int frame_isEscSeq(struct frame *self, char chr) {
uint8_t curr_sts;
if (self == NULL)
return -1;
curr_sts = self->esc_sts;
if (self->esc_sts == 0 && (chr == 0x1b))
self->esc_sts = 1; // Escape Sequence
else if (self->esc_sts == 1 && (chr == 0x5b))
self->esc_sts = 2; // Control Sequence Introducer(CSI)
else if (self->esc_sts == 1 && (chr != 0x5b))
self->esc_sts = 0;
else if (self->esc_sts == 2 && (chr>=0x40 && chr <=0x7e))
self->esc_sts = 0;
if (curr_sts || self->esc_sts)
return 1;
else
return 0;
}
// return 0 on seccuess
static int frame_parse (struct frame *self, char *buf, size_t buf_size, char *input, int indent)
{
uint8_t pos, esc;
int i;
char *in, *end;
if (self == NULL || self->buf == NULL || input == NULL)
return -1;
if (indent >= self->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
buf[i++] = ' ';
pos++;
continue;
}
esc = self->isEscSeq(self, *in);
if (!esc && pos == self->line_width) {
buf[i++] = LINE_DELIMITER;
pos = 0;
continue;
}
if (!esc)
pos++;
// fill input data
buf[i++] = *(in++);
}
// padding
while (pos <= self->line_width) {
if (i >= buf_size)
break;
if (pos < self->line_width)
buf[i++] = ' ';
else
buf[i++] = LINE_DELIMITER;
pos++;
}
// full
if (i >= buf_size)
return -1;
buf[i++] = '\0';
return 0;
}
#define FRAME_DECLARE(NAME) \
struct frame NAME = {\
.buf = NULL,\
.pages = 0,\
.mtime = 0,\
.init = frame_init,\
.append = frame_append,\
.insert = frame_insert,\
.getPage = frame_getPage,\
.isFull = frame_isFull,\
.isEscSeq = frame_isEscSeq,\
.parse = frame_parse,\
};
static FRAME_DECLARE(frame_info);
static FRAME_DECLARE(frame_sel);
static FRAME_DECLARE(frame_snr);
static FRAME_DECLARE(frame_postcode);
enum ENUM_PANEL {
PANEL_MAIN = 1,
PANEL_BOOT_ORDER = 2,
PANEL_POWER_POLICY = 3,
};
struct ctrl_panel {
uint8_t parent;
uint8_t item_num;
char item_str[8][32];
uint8_t (*select)(uint8_t item);
};
static uint8_t panel_main (uint8_t item);
static uint8_t panel_boot_order (uint8_t item);
static uint8_t panel_power_policy (uint8_t item);
static struct ctrl_panel panels[] = {
{ /* dummy entry for making other to 1-based */ },
{
.parent = PANEL_MAIN,
.item_num = 2,
.item_str = {
"User Setting",
">Boot Order",
">Power Policy",
},
.select = panel_main,
},
{
.parent = PANEL_MAIN,
.item_num = 0,
.item_str = {
"Boot Order",
},
.select = panel_boot_order,
},
{
.parent = PANEL_MAIN,
.item_num = 0,
.item_str = {
"Power Policy",
},
.select = panel_power_policy,
},
};
static int panelNum = (sizeof(panels)/sizeof(struct ctrl_panel)) - 1;
extern void plat_lan_init(lan_config_t *lan);
static int
chk_cri_sel_update(uint8_t *cri_sel_up) {
FILE *fp;
struct stat file_stat;
uint8_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()
{
if (!plat_supported()) {
return -1;
}
return pal_udbg_get_frame_total_num();
}
int
plat_udbg_get_updated_frames(uint8_t *count, uint8_t *buffer) {
uint8_t cri_sel_up = 0;
uint8_t num = 0;
if (!plat_supported()) {
return -1;
}
*count = 0;
// info page update
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;
int rc = pal_udbg_get_frame_total_num();
if (rc < 0) {
return -1;
}
num = (uint8_t) rc;
if (num >= 4) {
buffer[*count] = 4;
*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) {
int target, pdesc_size;
post_phase_desc_t *post_phase;
size_t post_phase_desc_cnt, i;
post_desc_t *ptr = NULL;
post_desc_t *next_phase = NULL;
uint8_t pos = plat_get_fru_sel();
if (!plat_supported() ||
plat_get_post_phase(pos, &post_phase, &post_phase_desc_cnt)) {
return -1;
}
for (i = 0; i < post_phase_desc_cnt; i++) {
if (post_phase[i].phase == PHASE_ANY) {
ptr = post_phase[i].post_tbl;
pdesc_size = post_phase[i].post_tbl_cnt;
next_phase = NULL;
break;
}
if (post_phase[i].phase == phase) {
ptr = post_phase[i].post_tbl;
pdesc_size = post_phase[i].post_tbl_cnt;
} else if (post_phase[i].phase == phase + 1) {
next_phase = post_phase[i].post_tbl;
}
}
if (!ptr) {
return -1;
}
for (target = 0; target < pdesc_size; target++, ptr++) {
if (index == ptr->code) {
*length = strlen(ptr->desc);
memcpy(buffer, ptr->desc, *length);
buffer[*length] = '\0';
/* This is the end of this phase's post code */
if (target == pdesc_size - 1) {
/* Point to next phase if exists, else terminate */
if (next_phase != NULL) {
*next = next_phase[0].code;
*end = 0x00;
} else {
*next = 0xFF;
*end = 0x01;
}
} else {
*next = (ptr + 1)->code;
*end = 0x00;
}
return 0;
}
}
return -1;
}
int
plat_udbg_get_gpio_desc(uint8_t index, uint8_t *next, uint8_t *level, uint8_t *def,
uint8_t *count, uint8_t *buffer) {
int i = 0;
dbg_gpio_desc_t *gdesc = NULL;
size_t gdesc_count = 0;
uint8_t pos = plat_get_fru_sel();
if (!plat_supported() ||
plat_get_gdesc(pos, &gdesc, &gdesc_count)) {
return -1;
}
// If the index is 0x00: populate the next pointer with the first
if (index == 0x00) {
*next = gdesc[0].pin;
*count = 0;
return 0;
}
// Look for the index
for (i = 0; i < gdesc_count; i++) {
if (index == gdesc[i].pin) {
break;
}
}
// Check for not found
if (i == gdesc_count) {
return -1;
}
// Populate the description and next index
*level = gdesc[i].level;
*def = gdesc[i].def;
*count = strlen(gdesc[i].desc);
memcpy(buffer, gdesc[i].desc, *count);
buffer[*count] = '\0';
// Populate the next index
if (i == gdesc_count-1) { // last entry
*next = 0xFF;
} else {
*next = gdesc[i+1].pin;
}
return 0;
}
static int
udbg_get_cri_sel(uint8_t frame, uint8_t page, uint8_t *next, uint8_t *count, uint8_t *buffer) {
int len;
int ret;
char line_buff[FRAME_PAGE_BUF_SIZE], *ptr;
char *fptr;
FILE *fp;
struct stat file_stat;
uint8_t pos = plat_get_fru_sel();
static uint8_t pre_pos = FRU_ALL;
bool pos_changed = pre_pos != pos;
pre_pos = pos;
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 || pos_changed)) {
// initialize and clear frame
frame_sel.init(&frame_sel, FRAME_BUFF_SIZE);
frame_sel.overwrite = 1;
frame_sel.max_page = 20;
frame_sel.mtime = file_stat.st_mtime;
snprintf(frame_sel.title, 32, "Cri SEL");
while (fgets(line_buff, FRAME_PAGE_BUF_SIZE, fp)) {
// Remove newline
line_buff[strlen(line_buff)-1] = '\0';
ptr = line_buff;
// Find message
ptr = strstr(ptr, "local0.err");
if (ptr == NULL) {
continue;
}
// Check if FRU specific information
fptr = ptr;
fptr = strstr(fptr, ",FRU:");
if (fptr) {
if ((fptr[5]-'0') != pos) {
continue;
}
// Remove ',FRU:X' from the string.
*fptr = '\0';
}
if ((ptr = strrchr(ptr, ':')) == NULL) {
continue;
}
len = strlen(ptr);
if (len > 2) {
// to skip log string ": "
ptr += 2;
}
// Write new message
frame_sel.insert(&frame_sel, ptr, 0);
}
}
fclose(fp);
} else {
// Title only
frame_sel.init(&frame_sel, FRAME_BUFF_SIZE);
snprintf(frame_sel.title, 32, "Cri SEL");
frame_sel.mtime = 0;
}
if (page > frame_sel.pages) {
return -1;
}
ret = frame_sel.getPage(&frame_sel, 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 frame, uint8_t page, uint8_t *next, uint8_t *count, uint8_t *buffer) {
char str[64], temp_val[16], temp_thresh[8], print_format[32];
int i, ret;
float fvalue;
thresh_sensor_t thresh;
sensor_desc_t *cri_sensor = NULL;
size_t sensor_count = 0;
uint8_t pos = plat_get_fru_sel();
uint8_t fru;
if (plat_get_sensor_desc(pos, &cri_sensor, &sensor_count)) {
return -1;
}
if (page == 1) {
// Only update frame data while getting page 1
// initialize and clear frame
frame_snr.init(&frame_snr, FRAME_BUFF_SIZE);
snprintf(frame_snr.title, 32, "CriSensor");
for (i = 0; i < sensor_count; i++) {
/* Pos implies BMC (FRU_ALL) and configuration for this sensor
* wants us to use the FRU info from the pos. Skip this sensor */
if (cri_sensor[i].fru == FRU_ALL && pos == FRU_ALL) {
continue;
}
fru = cri_sensor[i].fru == FRU_ALL ? pos : cri_sensor[i].fru;
temp_thresh[0] = 0;
ret = sensor_cache_read(fru, cri_sensor[i].sensor_num, &fvalue);
if (ret < 0) {
strcpy(temp_val, "NA");
} else {
ret = sdr_get_snr_thresh(fru, cri_sensor[i].sensor_num, &thresh);
if (ret == 0) {
if ((GETBIT(thresh.flag, UNR_THRESH) == 1) && (fvalue > thresh.unr_thresh)) {
strcpy(temp_thresh, "/UNR");
} else if (((GETBIT(thresh.flag, UCR_THRESH) == 1)) && (fvalue > thresh.ucr_thresh)) {
strcpy(temp_thresh, "/UCR");
} else if (((GETBIT(thresh.flag, UNC_THRESH) == 1)) && (fvalue > thresh.unc_thresh)) {
strcpy(temp_thresh, "/UNC");
} else if (((GETBIT(thresh.flag, LNR_THRESH) == 1)) && (fvalue < thresh.lnr_thresh)) {
strcpy(temp_thresh, "/LNR");
} else if (((GETBIT(thresh.flag, LCR_THRESH) == 1)) && (fvalue < thresh.lcr_thresh)) {
strcpy(temp_thresh, "/LCR");
} else if (((GETBIT(thresh.flag, LNC_THRESH) == 1)) && (fvalue < thresh.lnc_thresh)) {
strcpy(temp_thresh, "/LNC");
}
}
snprintf(print_format, sizeof(print_format), "%%.%df%%s", (int)cri_sensor[i].disp_prec);
snprintf(temp_val, sizeof(temp_val), (const char *)print_format, fvalue, cri_sensor[i].unit);
}
if (temp_thresh[0] != 0)
snprintf(str, sizeof(str), ESC_ALT"%s%s%s"ESC_RST, cri_sensor[i].name, temp_val, temp_thresh);
else
snprintf(str, sizeof(str), ESC_NOR"%s%s"ESC_RST, cri_sensor[i].name, temp_val);
frame_snr.append(&frame_snr, str, 0);
}
} // End of update frame
if (page > frame_snr.pages) {
return -1;
}
ret = frame_snr.getPage(&frame_snr, 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;
}
int __attribute__((weak))
plat_udbg_get_uart_sel_num(uint8_t *uart_sel_num) {
return -1;
}
int __attribute__((weak))
plat_udbg_get_uart_sel_name(uint8_t uart_sel_num, char *uart_sel_name) {
return -1;
}
static int
udbg_get_info_page (uint8_t frame, uint8_t page, uint8_t *next, uint8_t *count, uint8_t *buffer) {
int ret;
char line_buff[2048], *pres_dev = line_buff, *delim = "\n";
FILE *fp;
fruid_info_t fruid;
lan_config_t lan_config = { 0 };
unsigned char zero_ip_addr[SIZE_IP_ADDR] = { 0 };
unsigned char zero_ip6_addr[SIZE_IP6_ADDR] = { 0 };
char fruid_path[256];
uint8_t pos = plat_get_fru_sel();
char uart_sel_name[MAX_UART_SEL_NAME_SIZE] = {0};
uint8_t uart_sel_num = 0;
if (page == 1) {
// Only update frame data while getting page 1
// initialize and clear frame
frame_info.init(&frame_info, FRAME_BUFF_SIZE);
snprintf(frame_info.title, 32, "SYS_Info");
pres_dev = line_buff;
if (plat_get_extra_sysinfo(pos, line_buff) == 0) {
pres_dev = strtok(pres_dev, delim);
if (pres_dev) {
do {
frame_info.append(&frame_info, pres_dev, 0);
} while ((pres_dev = strtok(NULL, delim)) != NULL);
}
}
// FRU
if (pos != FRU_ALL && pal_get_fruid_path(pos, fruid_path) == 0 &&
fruid_parse(fruid_path, &fruid) == 0) {
frame_info.append(&frame_info, "SN:", 0);
frame_info.append(&frame_info, fruid.board.serial, 1);
frame_info.append(&frame_info, "PN:", 0);
frame_info.append(&frame_info, fruid.board.part, 1);
free_fruid_info(&fruid);
}
// LAN
plat_lan_init(&lan_config);
if (memcmp(lan_config.ip_addr, zero_ip_addr, SIZE_IP_ADDR)) {
inet_ntop(AF_INET, lan_config.ip_addr, line_buff, FRAME_PAGE_BUF_SIZE);
frame_info.append(&frame_info, "BMC_IP:", 0);
frame_info.append(&frame_info, line_buff, 1);
}
if (memcmp(lan_config.ip6_addr, zero_ip6_addr, SIZE_IP6_ADDR)) {
inet_ntop(AF_INET6, lan_config.ip6_addr, line_buff, FRAME_PAGE_BUF_SIZE);
frame_info.append(&frame_info, "BMC_IPv6:", 0);
frame_info.append(&frame_info, line_buff, 1);
}
// BMC ver
fp = fopen("/etc/issue", "r");
if (fp != NULL) {
if (fgets(line_buff, sizeof(line_buff), fp)) {
char fw_ver[64];
if ((ret = sscanf(line_buff, "%*s %*s %63s", fw_ver)) == 1) {
frame_info.append(&frame_info, "BMC_FW_ver:", 0);
frame_info.append(&frame_info, fw_ver, 1);
}
}
fclose(fp);
}
// BIOS ver
if (pos != FRU_ALL && !pal_get_sysfw_ver(pos, (uint8_t *)line_buff)) {
// BIOS version response contains the length at offset 2 followed by ascii string
line_buff[3+line_buff[2]] = '\0';
frame_info.append(&frame_info, "BIOS_FW_ver:", 0);
frame_info.append(&frame_info, &line_buff[3], 1);
}
// ME status
if (pos != FRU_ALL && !plat_get_me_status(pos, line_buff)) {
frame_info.append(&frame_info, "ME_status:", 0);
frame_info.append(&frame_info, line_buff, 1);
}
// Board ID
if (!plat_get_board_id(line_buff)) {
frame_info.append(&frame_info, "Board_ID:", 0);
frame_info.append(&frame_info, line_buff, 1);
}
// Battery - Use Escape sequence
frame_info.append(&frame_info, "Battery:", 0);
frame_info.append(&frame_info, ESC_BAT" ", 1);
// MCU Version - Use Escape sequence
frame_info.append(&frame_info, "MCUbl_ver:", 0);
frame_info.append(&frame_info, ESC_MCU_BL_VER, 1);
frame_info.append(&frame_info, "MCU_ver:", 0);
frame_info.append(&frame_info, ESC_MCU_RUN_VER, 1);
// Extra FW Version
pres_dev = line_buff;
if (plat_get_etra_fw_version(pos, pres_dev) == 0) {
pres_dev = strtok(pres_dev, delim);
if (pres_dev) {
do {
frame_info.append(&frame_info, pres_dev, 0);
if ((pres_dev = strtok(NULL, delim)) != NULL) {
frame_info.append(&frame_info, pres_dev, 1);
} else {
break;
}
} while ((pres_dev = strtok(NULL, delim)) != NULL);
}
}
// Sys config present device
pres_dev = line_buff;
if (plat_get_syscfg_text(pos, pres_dev) == 0) {
pres_dev = strtok(pres_dev, delim);
if (pres_dev) {
frame_info.append(&frame_info, "Sys Conf. info:", 0);
do {
frame_info.append(&frame_info, pres_dev, 1);
} while ((pres_dev = strtok(NULL, delim)) != NULL);
}
}
// Uart selection
if (plat_udbg_get_uart_sel_num(&uart_sel_num) == 0) {
if (plat_udbg_get_uart_sel_name(uart_sel_num, uart_sel_name) == 0) {
snprintf(line_buff, sizeof(line_buff), "%u: %s", uart_sel_num, uart_sel_name);
frame_info.append(&frame_info, "UART_SEL:", 0);
frame_info.append(&frame_info, line_buff, 1);
}
}
} // End of update frame
if (page > frame_info.pages) {
return -1;
}
ret = frame_info.getPage(&frame_info, 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 __attribute__((weak))
plat_dword_postcode_buf(uint8_t fru, char *status) {
return -1;
}
static int
udbg_get_postcode (uint8_t frame, uint8_t page, uint8_t *next, uint8_t *count, uint8_t *buffer) {
int ret;
char line_buff[2048] = {0}, *pres_dev = line_buff, *delim = "\n";
if ((count == NULL) || (buffer == NULL)) {
return -1;
}
uint8_t pos = plat_get_fru_sel();
if (page == 1) {
// Only update frame data while getting page 1
// initialize and clear frame
frame_postcode.init(&frame_postcode, FRAME_BUFF_SIZE);
frame_postcode.max_page = 10;
snprintf(frame_postcode.title, 32, "POST CODE");
pres_dev = line_buff;
if (pos != FRU_ALL && plat_dword_postcode_buf(pos, line_buff) == 0) {
pres_dev = strtok(pres_dev, delim);
if (pres_dev) {
do {
frame_postcode.append(&frame_postcode, pres_dev, 0);
} while ((pres_dev = strtok(NULL, delim)) != NULL);
}
}
} // End of update frame
if (page > frame_postcode.pages) {
return -1;
}
ret = frame_postcode.getPage(&frame_postcode, page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
if (ret < 0) {
*count = 0;
return -1;
}
*count = (uint8_t)ret;
if (page < frame_postcode.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)
{
if (!plat_supported()) {
return -1;
}
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);
case 4:
return udbg_get_postcode(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 item) {
int i;
unsigned char buff[MAX_VALUE_LEN], pickup, len;
uint8_t pos = plat_get_fru_sel();
if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0) {
if (item > 0 && item < SIZE_BOOT_ORDER) {
pickup = buff[item];
while (item > 1) {
buff[item] = buff[item -1];
item--;
}
buff[item] = pickup;
buff[0] |= 0x80;
pal_set_boot_order(pos, buff, buff, &len);
// refresh items
return panels[PANEL_BOOT_ORDER].select(0);
}
// '*': boot flags valid, BIOS has not yet read
snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32,
"Boot Order%c", (buff[0] & 0x80)?'*':'\0');
for (i = 1; i < SIZE_BOOT_ORDER; i++) {
switch (buff[i]) {
case 0x0:
snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
" USB device");
break;
case 0x1:
snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
" Network v4");
break;
case (0x1 | 0x8):
snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
" Network v6");
break;
case 0x2:
snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
" SATA HDD");
break;
case 0x3:
snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
" SATA-CDROM");
break;
case 0x4:
snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
" Other");
break;
default:
panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0';
break;
}
}
// remove empty items
for (i--; (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0); i--) ;
panels[PANEL_BOOT_ORDER].item_num = i;
} else {
panels[PANEL_BOOT_ORDER].item_num = 0;
}
return PANEL_BOOT_ORDER;
}
static uint8_t panel_power_policy (uint8_t item) {
uint8_t buff[32] = {0};
uint8_t res_len;
uint8_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;
}
return PANEL_POWER_POLICY;
}
int
plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item, uint8_t *count, uint8_t *buffer)
{
if (!plat_supported()) {
return -1;
}
if (panel > panelNum || panel < PANEL_MAIN)
return CC_PARAM_OUT_OF_RANGE;
// No more item; End of item list
if (item > panels[panel].item_num)
return CC_PARAM_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 CC_PARAM_OUT_OF_RANGE;
}
buffer[0] = panel;
buffer[1] = item;
buffer[2] = strlen(panels[panel].item_str[item]);
if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE) {
memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]);
}
*count = buffer[2] + 3;
return CC_SUCCESS;
}