mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-11 07:24:46 +00:00

Coreboot provides the CMOS layout in the tables it passes to U-Boot. Use that to build an editor for the CMOS settings. Signed-off-by: Simon Glass <sjg@chromium.org>
245 lines
5.5 KiB
C
245 lines
5.5 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Building an expo from an FDT description
|
|
*
|
|
* Copyright 2022 Google LLC
|
|
* Written by Simon Glass <sjg@chromium.org>
|
|
*/
|
|
|
|
#define LOG_CATEGORY LOGC_EXPO
|
|
|
|
#include <cedit.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <expo.h>
|
|
#include <log.h>
|
|
#include <malloc.h>
|
|
#include <vsprintf.h>
|
|
#include <asm/cb_sysinfo.h>
|
|
|
|
/**
|
|
* struct build_info - Information to use when building
|
|
*/
|
|
struct build_info {
|
|
const struct cb_cmos_option_table *tab;
|
|
struct cedit_priv *priv;
|
|
};
|
|
|
|
/**
|
|
* convert_to_title() - Convert text to 'title' format and allocate a string
|
|
*
|
|
* Converts "this_is_a_test" to "This is a test" so it looks better
|
|
*
|
|
* @text: Text to convert
|
|
* Return: Allocated string, or NULL if out of memory
|
|
*/
|
|
static char *convert_to_title(const char *text)
|
|
{
|
|
int len = strlen(text);
|
|
char *buf, *s;
|
|
|
|
buf = malloc(len + 1);
|
|
if (!buf)
|
|
return NULL;
|
|
|
|
for (s = buf; *text; s++, text++) {
|
|
if (s == buf)
|
|
*s = toupper(*text);
|
|
else if (*text == '_')
|
|
*s = ' ';
|
|
else
|
|
*s = *text;
|
|
}
|
|
*s = '\0';
|
|
|
|
return buf;
|
|
}
|
|
|
|
/**
|
|
* menu_build() - Build a menu and add it to a scene
|
|
*
|
|
* See doc/developer/expo.rst for a description of the format
|
|
*
|
|
* @info: Build information
|
|
* @entry: CMOS entry to build a menu for
|
|
* @scn: Scene to add the menu to
|
|
* @objp: Returns the object pointer
|
|
* Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
|
|
* error, -ENOENT if there is a references to a non-existent string
|
|
*/
|
|
static int menu_build(struct build_info *info,
|
|
const struct cb_cmos_entries *entry, struct scene *scn,
|
|
struct scene_obj **objp)
|
|
{
|
|
struct scene_obj_menu *menu;
|
|
const void *ptr, *end;
|
|
uint menu_id;
|
|
char *title;
|
|
int ret, i;
|
|
|
|
ret = scene_menu(scn, entry->name, 0, &menu);
|
|
if (ret < 0)
|
|
return log_msg_ret("men", ret);
|
|
menu_id = ret;
|
|
|
|
title = convert_to_title(entry->name);
|
|
if (!title)
|
|
return log_msg_ret("con", -ENOMEM);
|
|
|
|
/* Set the title */
|
|
ret = scene_txt_str(scn, "title", 0, 0, title, NULL);
|
|
if (ret < 0)
|
|
return log_msg_ret("tit", ret);
|
|
menu->title_id = ret;
|
|
|
|
end = (void *)info->tab + info->tab->size;
|
|
for (ptr = (void *)info->tab + info->tab->header_length, i = 0;
|
|
ptr < end; i++) {
|
|
const struct cb_cmos_enums *enums = ptr;
|
|
struct scene_menitem *item;
|
|
uint label;
|
|
|
|
ptr += enums->size;
|
|
if (enums->tag != CB_TAG_OPTION_ENUM ||
|
|
enums->config_id != entry->config_id)
|
|
continue;
|
|
|
|
ret = scene_txt_str(scn, enums->text, 0, 0, enums->text, NULL);
|
|
if (ret < 0)
|
|
return log_msg_ret("tit", ret);
|
|
label = ret;
|
|
|
|
ret = scene_menuitem(scn, menu_id, simple_xtoa(i), 0, 0, label,
|
|
0, 0, 0, &item);
|
|
if (ret < 0)
|
|
return log_msg_ret("mi", ret);
|
|
item->value = enums->value;
|
|
}
|
|
*objp = &menu->obj;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* scene_build() - Build a scene and all its objects
|
|
*
|
|
* See doc/developer/expo.rst for a description of the format
|
|
*
|
|
* @info: Build information
|
|
* @scn: Scene to add the object to
|
|
* Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
|
|
* error, -ENOENT if there is a references to a non-existent string
|
|
*/
|
|
static int scene_build(struct build_info *info, struct expo *exp)
|
|
{
|
|
struct scene_obj_menu *menu;
|
|
const void *ptr, *end;
|
|
struct scene_obj *obj;
|
|
struct scene *scn;
|
|
uint label, menu_id;
|
|
int ret;
|
|
|
|
ret = scene_new(exp, "cmos", 0, &scn);
|
|
if (ret < 0)
|
|
return log_msg_ret("scn", ret);
|
|
|
|
ret = scene_txt_str(scn, "title", 0, 0, "CMOS RAM settings", NULL);
|
|
if (ret < 0)
|
|
return log_msg_ret("add", ret);
|
|
scn->title_id = ret;
|
|
|
|
ret = scene_txt_str(scn, "prompt", 0, 0,
|
|
"UP and DOWN to choose, ENTER to select", NULL);
|
|
if (ret < 0)
|
|
return log_msg_ret("add", ret);
|
|
|
|
end = (void *)info->tab + info->tab->size;
|
|
for (ptr = (void *)info->tab + info->tab->header_length; ptr < end;) {
|
|
const struct cb_cmos_entries *entry;
|
|
const struct cb_record *rec = ptr;
|
|
|
|
entry = ptr;
|
|
ptr += rec->size;
|
|
if (rec->tag != CB_TAG_OPTION)
|
|
continue;
|
|
switch (entry->config) {
|
|
case 'e':
|
|
ret = menu_build(info, entry, scn, &obj);
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
if (ret < 0)
|
|
return log_msg_ret("add", ret);
|
|
|
|
obj->start_bit = entry->bit;
|
|
obj->bit_length = entry->length;
|
|
}
|
|
|
|
ret = scene_menu(scn, "save", EXPOID_SAVE, &menu);
|
|
if (ret < 0)
|
|
return log_msg_ret("men", ret);
|
|
menu_id = ret;
|
|
|
|
ret = scene_txt_str(scn, "save", 0, 0, "Save and exit", NULL);
|
|
if (ret < 0)
|
|
return log_msg_ret("sav", ret);
|
|
label = ret;
|
|
ret = scene_menuitem(scn, menu_id, "save", 0, 0, label,
|
|
0, 0, 0, NULL);
|
|
if (ret < 0)
|
|
return log_msg_ret("mi", ret);
|
|
|
|
ret = scene_menu(scn, "nosave", EXPOID_DISCARD, &menu);
|
|
if (ret < 0)
|
|
return log_msg_ret("men", ret);
|
|
menu_id = ret;
|
|
|
|
ret = scene_txt_str(scn, "nosave", 0, 0, "Exit without saving", NULL);
|
|
if (ret < 0)
|
|
return log_msg_ret("nos", ret);
|
|
label = ret;
|
|
ret = scene_menuitem(scn, menu_id, "exit", 0, 0, label,
|
|
0, 0, 0, NULL);
|
|
if (ret < 0)
|
|
return log_msg_ret("mi", ret);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int build_it(struct build_info *info, struct expo **expp)
|
|
{
|
|
struct expo *exp;
|
|
int ret;
|
|
|
|
ret = expo_new("coreboot", NULL, &exp);
|
|
if (ret)
|
|
return log_msg_ret("exp", ret);
|
|
expo_set_dynamic_start(exp, EXPOID_BASE_ID);
|
|
|
|
ret = scene_build(info, exp);
|
|
if (ret < 0)
|
|
return log_msg_ret("scn", ret);
|
|
|
|
*expp = exp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int cb_expo_build(struct expo **expp)
|
|
{
|
|
struct build_info info;
|
|
struct expo *exp;
|
|
int ret;
|
|
|
|
info.tab = lib_sysinfo.option_table;
|
|
if (!info.tab)
|
|
return log_msg_ret("tab", -ENOENT);
|
|
|
|
ret = build_it(&info, &exp);
|
|
if (ret)
|
|
return log_msg_ret("bui", ret);
|
|
*expp = exp;
|
|
|
|
return 0;
|
|
}
|