[PATCH v2 00/19] x86: expo: Add support for editing coreboot CMOS RAM settings

U-Boot provides support for editing settings with an 'expo', as well as reading and writing settings to CMOS RAM.
This series integrates expo functionality with coreboot, using the sysinfo table to get a list of settings, creating an expo with them and allowing them to be edited.
A new CI test provides coverage for some coreboot-related commands. For this to work, a number of minor tweaks are made to existing tests, so that they pass on coreboot (x86) or at least are skipped when they cannot pass. Likely most of these fixes will apply to other boards too.
It includes several other fixes and improvements: - new -m flag for 'bootflow scan' so it can display a menu automatically - Fix for video-scrolling crash with Truetype - menu items can now have individual integer values - menu items are lined up according to the width of all menu labels
Changes in v2: - Avoid using common.h - Avoid using common.h - Rebase to -next
Simon Glass (19): video: Add a dark-grey console colour video: Avoid starting a new line to close to the bottom expo: Place menu items to the right of all labels expo: Set the initial next_id to 1 expo: Use standard numbering for save and discard expo: Allow menu items to have values expo: Add a little more cedit CMOS logging expo: Support menu-item values in cedit expo: Drop unneceesary calls to expo_str() expo: Drop scene_title_set() expo: Add forward declaration for udevice to cedit x86: coreboot: Enable unit tests x86: CI: Update coreboot x86: coreboot: Add a test for cbsysinfo command x86: coreboot: Show the option table x86: coreboot: Enable support for the configuration editor x86: coreboot: Add a command to check and update CMOS RAM x86: coreboot: Allow building an expo for editing CMOS config x86: Enable RTC command by default
.azure-pipelines.yml | 2 +- .gitlab-ci.yml | 2 +- arch/sandbox/dts/cedit.dtsi | 3 + arch/x86/dts/coreboot.dts | 7 + boot/Makefile | 4 + boot/cedit.c | 191 +++++++++++++++-------- boot/expo.c | 3 + boot/expo_build.c | 36 ++--- boot/expo_build_cb.c | 245 ++++++++++++++++++++++++++++++ boot/scene.c | 61 ++++++-- boot/scene_internal.h | 30 +++- boot/scene_menu.c | 26 +++- boot/scene_textline.c | 3 +- cmd/Kconfig | 12 ++ cmd/cedit.c | 28 ++++ cmd/x86/Makefile | 1 + cmd/x86/cbcmos.c | 139 +++++++++++++++++ cmd/x86/cbsysinfo.c | 73 ++++++++- configs/coreboot64_defconfig | 2 + configs/coreboot_defconfig | 6 + doc/board/coreboot/coreboot.rst | 6 + doc/develop/cedit.rst | 9 +- doc/develop/expo.rst | 26 +++- doc/usage/cmd/cbcmos.rst | 45 ++++++ doc/usage/cmd/cbsysinfo.rst | 99 ++++++++++++ doc/usage/cmd/cedit.rst | 91 ++++++++++- doc/usage/index.rst | 1 + drivers/video/vidconsole-uclass.c | 4 +- drivers/video/video-uclass.c | 3 + include/cedit.h | 2 + include/expo.h | 51 +++++-- include/test/cedit-test.h | 30 ++-- include/video.h | 4 +- include/video_console.h | 8 + test/boot/cedit.c | 22 ++- test/boot/expo.c | 26 +++- test/boot/files/expo_ids.h | 3 +- test/boot/files/expo_layout.dts | 5 +- test/cmd/Makefile | 1 + test/cmd/coreboot.c | 119 +++++++++++++++ tools/expo.py | 33 +++- 41 files changed, 1309 insertions(+), 153 deletions(-) create mode 100644 boot/expo_build_cb.c create mode 100644 cmd/x86/cbcmos.c create mode 100644 doc/usage/cmd/cbcmos.rst create mode 100644 test/cmd/coreboot.c

This is useful for highlighting something with a black background, as is needed with cedit when using a white-on-black console. Add this as a new colour.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
boot/scene.c | 2 +- drivers/video/video-uclass.c | 3 +++ include/video.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/boot/scene.c b/boot/scene.c index d4dfb49ada1..0b37971b1ff 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -346,7 +346,7 @@ static void scene_render_background(struct scene_obj *obj, bool box_only)
/* draw a background for the object */ if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) { - fore = VID_BLACK; + fore = VID_DARK_GREY; back = VID_WHITE; } else { fore = VID_LIGHT_GRAY; diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index f743ed74c81..51fafbb2174 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -281,6 +281,9 @@ static const struct vid_rgb colours[VID_COLOUR_COUNT] = { { 0xff, 0x00, 0xff }, /* bright magenta */ { 0x00, 0xff, 0xff }, /* bright cyan */ { 0xff, 0xff, 0xff }, /* white */ + + /* an extra one for menus */ + { 0x40, 0x40, 0x40 }, /* dark gray */ };
u32 video_index_to_colour(struct video_priv *priv, enum colour_idx idx) diff --git a/include/video.h b/include/video.h index 4d8df9baaad..ae9ce03f5bf 100644 --- a/include/video.h +++ b/include/video.h @@ -179,6 +179,7 @@ enum colour_idx { VID_LIGHT_MAGENTA, VID_LIGHT_CYAN, VID_WHITE, + VID_DARK_GREY,
VID_COLOUR_COUNT };

When starting a new text line, an assumption is made that the current vertical position is a multiple of the character height. When this is not true, characters can be written after the end of the framebuffer.
This can causes crashes and strange errors from QEMU.
Adjust the scrolling check when processing a newline character, to avoid any problems.
Add some comments to make things a little clearer.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
drivers/video/vidconsole-uclass.c | 4 +++- include/video.h | 3 ++- include/video_console.h | 8 ++++++++ 3 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index a312a198524..a8d2199147d 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -94,7 +94,9 @@ static void vidconsole_newline(struct udevice *dev) priv->ycur += priv->y_charsize;
/* Check if we need to scroll the terminal */ - if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) { + if (vid_priv->rot % 2 ? + priv->ycur + priv->x_charsize > vid_priv->xsize : + priv->ycur + priv->y_charsize > vid_priv->ysize) { vidconsole_move_rows(dev, 0, rows, priv->rows - rows); for (i = 0; i < rows; i++) vidconsole_set_row(dev, priv->rows - i - 1, diff --git a/include/video.h b/include/video.h index ae9ce03f5bf..e20f1173762 100644 --- a/include/video.h +++ b/include/video.h @@ -78,7 +78,8 @@ enum video_format { * * @xsize: Number of pixel columns (e.g. 1366) * @ysize: Number of pixels rows (e.g.. 768) - * @rot: Display rotation (0=none, 1=90 degrees clockwise, etc.) + * @rot: Display rotation (0=none, 1=90 degrees clockwise, etc.). THis + * does not affect @xsize and @ysize * @bpix: Encoded bits per pixel (enum video_log2_bpp) * @format: Pixel format (enum video_format) * @vidconsole_drv_name: Driver to use for the text console, NULL to diff --git a/include/video_console.h b/include/video_console.h index bde67fa9a5a..ecbf183b3d0 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -27,6 +27,14 @@ enum { * Drivers must set up @rows, @cols, @x_charsize, @y_charsize in their probe() * method. Drivers may set up @xstart_frac if desired. * + * Note that these values relate to the rotated console, so that an 80x25 + * console which is rotated 90 degrees will have rows=80 and cols=25 + * + * The xcur_frac and ycur values refer to the unrotated coordinates, that is + * xcur_frac always advances with each character, even if its limit might be + * vid_priv->ysize instead of vid_priv->xsize if the console is rotated 90 or + * 270 degrees. + * * @sdev: stdio device, acting as an output sink * @xcur_frac: Current X position, in fractional units (VID_TO_POS(x)) * @ycur: Current Y position in pixels (0=top)

At present a fixed position is used for menu items, 200 pixels to the right of the left side of the labels. This means that a menu item with a very long label may overlap the items.
It seems better to calculate the maximum label width and then place the items to the right of all of them.
To implement this, add a new struct to containing arrangement information. Calculate it before doing the actual arrangement. Add a new style item which sets the amount of space from the right side of the labels to left side of the items.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
boot/cedit.c | 13 ++++++++--- boot/expo.c | 2 ++ boot/scene.c | 52 +++++++++++++++++++++++++++++++++++++++++-- boot/scene_internal.h | 20 +++++++++++++++-- boot/scene_menu.c | 9 +++++--- boot/scene_textline.c | 3 ++- doc/develop/expo.rst | 4 ++++ include/expo.h | 12 ++++++++++ 8 files changed, 104 insertions(+), 11 deletions(-)
diff --git a/boot/cedit.c b/boot/cedit.c index 8c654dba6dc..b5f89e945bc 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -52,10 +52,11 @@ struct cedit_iter_priv {
int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id) { + struct expo_arrange_info arr; struct scene_obj_txt *txt; struct scene_obj *obj; struct scene *scn; - int y; + int y, ret;
scn = expo_lookup_scene_id(exp, scene_id); if (!scn) @@ -69,6 +70,11 @@ int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id) if (txt) scene_obj_set_pos(scn, txt->obj.id, 200, 10);
+ memset(&arr, '\0', sizeof(arr)); + ret = scene_calc_arrange(scn, &arr); + if (ret < 0) + return log_msg_ret("arr", ret); + y = 100; list_for_each_entry(obj, &scn->obj_head, sibling) { switch (obj->type) { @@ -78,12 +84,13 @@ int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id) break; case SCENEOBJT_MENU: scene_obj_set_pos(scn, obj->id, 50, y); - scene_menu_arrange(scn, (struct scene_obj_menu *)obj); + scene_menu_arrange(scn, &arr, + (struct scene_obj_menu *)obj); y += 50; break; case SCENEOBJT_TEXTLINE: scene_obj_set_pos(scn, obj->id, 50, y); - scene_textline_arrange(scn, + scene_textline_arrange(scn, &arr, (struct scene_obj_textline *)obj); y += 50; break; diff --git a/boot/expo.c b/boot/expo.c index cadb6a0ad6e..d030820e77c 100644 --- a/boot/expo.c +++ b/boot/expo.c @@ -259,6 +259,8 @@ int expo_apply_theme(struct expo *exp, ofnode node) ofnode_read_u32(node, "font-size", &theme->font_size); ofnode_read_u32(node, "menu-inset", &theme->menu_inset); ofnode_read_u32(node, "menuitem-gap-y", &theme->menuitem_gap_y); + ofnode_read_u32(node, "menu-title-margin-x", + &theme->menu_title_margin_x);
list_for_each_entry(scn, &exp->scene_head, sibling) { ret = scene_apply_theme(scn, theme); diff --git a/boot/scene.c b/boot/scene.c index 0b37971b1ff..56569e76e9f 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -478,11 +478,59 @@ static int scene_obj_render(struct scene_obj *obj, bool text_mode) return 0; }
+int scene_calc_arrange(struct scene *scn, struct expo_arrange_info *arr) +{ + struct scene_obj *obj; + + arr->label_width = 0; + list_for_each_entry(obj, &scn->obj_head, sibling) { + uint label_id = 0; + int width; + + switch (obj->type) { + case SCENEOBJT_NONE: + case SCENEOBJT_IMAGE: + case SCENEOBJT_TEXT: + break; + case SCENEOBJT_MENU: { + struct scene_obj_menu *menu; + + menu = (struct scene_obj_menu *)obj, + label_id = menu->title_id; + break; + } + case SCENEOBJT_TEXTLINE: { + struct scene_obj_textline *tline; + + tline = (struct scene_obj_textline *)obj, + label_id = tline->label_id; + break; + } + } + + if (label_id) { + int ret; + + ret = scene_obj_get_hw(scn, label_id, &width); + if (ret < 0) + return log_msg_ret("hei", ret); + arr->label_width = max(arr->label_width, width); + } + } + + return 0; +} + int scene_arrange(struct scene *scn) { + struct expo_arrange_info arr; struct scene_obj *obj; int ret;
+ ret = scene_calc_arrange(scn, &arr); + if (ret < 0) + return log_msg_ret("arr", ret); + list_for_each_entry(obj, &scn->obj_head, sibling) { switch (obj->type) { case SCENEOBJT_NONE: @@ -493,7 +541,7 @@ int scene_arrange(struct scene *scn) struct scene_obj_menu *menu;
menu = (struct scene_obj_menu *)obj, - ret = scene_menu_arrange(scn, menu); + ret = scene_menu_arrange(scn, &arr, menu); if (ret) return log_msg_ret("arr", ret); break; @@ -502,7 +550,7 @@ int scene_arrange(struct scene *scn) struct scene_obj_textline *tline;
tline = (struct scene_obj_textline *)obj, - ret = scene_textline_arrange(scn, tline); + ret = scene_textline_arrange(scn, &arr, tline); if (ret) return log_msg_ret("arr", ret); break; diff --git a/boot/scene_internal.h b/boot/scene_internal.h index e72202c9821..be25f6a8b96 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -96,10 +96,12 @@ int scene_calc_dims(struct scene *scn, bool do_menus); * if not already done * * @scn: Scene to update + * @arr: Arrangement information * @menu: Menu to process * Returns: 0 if OK, -ve on error */ -int scene_menu_arrange(struct scene *scn, struct scene_obj_menu *menu); +int scene_menu_arrange(struct scene *scn, struct expo_arrange_info *arr, + struct scene_obj_menu *menu);
/** * scene_textline_arrange() - Set the position of things in a textline @@ -108,10 +110,12 @@ int scene_menu_arrange(struct scene *scn, struct scene_obj_menu *menu); * positioned correctly relative to the textline. * * @scn: Scene to update + * @arr: Arrangement information * @tline: textline to process * Returns: 0 if OK, -ve on error */ -int scene_textline_arrange(struct scene *scn, struct scene_obj_textline *tline); +int scene_textline_arrange(struct scene *scn, struct expo_arrange_info *arr, + struct scene_obj_textline *tline);
/** * scene_apply_theme() - Apply a theme to a scene @@ -358,4 +362,16 @@ int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline); */ int scene_textline_close(struct scene *scn, struct scene_obj_textline *tline);
+/** + * scene_calc_arrange() - Calculate sizes needed to arrange a scene + * + * Checks the size of some objects and stores this info to help with a later + * scene arrangement + * + * @scn: Scene to check + * @arr: Place to put scene-arrangement info + * Returns: 0 if OK, -ve on error + */ +int scene_calc_arrange(struct scene *scn, struct expo_arrange_info *arr); + #endif /* __SCENE_INTERNAL_H */ diff --git a/boot/scene_menu.c b/boot/scene_menu.c index 63994165efb..dbf6eacb298 100644 --- a/boot/scene_menu.c +++ b/boot/scene_menu.c @@ -169,7 +169,8 @@ int scene_menu_calc_dims(struct scene_obj_menu *menu) return 0; }
-int scene_menu_arrange(struct scene *scn, struct scene_obj_menu *menu) +int scene_menu_arrange(struct scene *scn, struct expo_arrange_info *arr, + struct scene_obj_menu *menu) { const bool open = menu->obj.flags & SCENEOF_OPEN; struct expo *exp = scn->expo; @@ -183,16 +184,18 @@ int scene_menu_arrange(struct scene *scn, struct scene_obj_menu *menu) x = menu->obj.dim.x; y = menu->obj.dim.y; if (menu->title_id) { + int width; + ret = scene_obj_set_pos(scn, menu->title_id, menu->obj.dim.x, y); if (ret < 0) return log_msg_ret("tit", ret);
- ret = scene_obj_get_hw(scn, menu->title_id, NULL); + ret = scene_obj_get_hw(scn, menu->title_id, &width); if (ret < 0) return log_msg_ret("hei", ret);
if (stack) - x += 200; + x += arr->label_width + theme->menu_title_margin_x; else y += ret * 2; } diff --git a/boot/scene_textline.c b/boot/scene_textline.c index 6ea072a1c26..576a402a688 100644 --- a/boot/scene_textline.c +++ b/boot/scene_textline.c @@ -85,7 +85,8 @@ int scene_textline_calc_dims(struct scene_obj_textline *tline) return 0; }
-int scene_textline_arrange(struct scene *scn, struct scene_obj_textline *tline) +int scene_textline_arrange(struct scene *scn, struct expo_arrange_info *arr, + struct scene_obj_textline *tline) { const bool open = tline->obj.flags & SCENEOF_OPEN; bool point; diff --git a/doc/develop/expo.rst b/doc/develop/expo.rst index c87b6ec8128..f7b636e5fc6 100644 --- a/doc/develop/expo.rst +++ b/doc/develop/expo.rst @@ -176,6 +176,10 @@ menu-inset menuitem-gap-y Number of pixels between menu items
+menu-title-margin-x + Number of pixels between right side of menu title to the left size of the + menu labels + Pop-up mode -----------
diff --git a/include/expo.h b/include/expo.h index 264745f7f01..dc3b68f68ee 100644 --- a/include/expo.h +++ b/include/expo.h @@ -59,11 +59,14 @@ struct expo_action { * @font_size: Default font size for all text * @menu_inset: Inset width (on each side and top/bottom) for menu items * @menuitem_gap_y: Gap between menu items in pixels + * @menu_title_margin_x: Gap between right side of menu title and left size of + * menu label */ struct expo_theme { u32 font_size; u32 menu_inset; u32 menuitem_gap_y; + u32 menu_title_margin_x; };
/** @@ -341,6 +344,15 @@ struct scene_obj_textline { uint pos; };
+/** + * struct expo_arrange_info - Information used when arranging a scene + * + * @label_width: Maximum width of labels in scene + */ +struct expo_arrange_info { + int label_width; +}; + /** * expo_new() - create a new expo *

If expo_set_dynamic_start() is never called, the first scene created will have an ID of 0, which is invalid. Correct this by setting a default value.
Add a test to check this.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
boot/expo.c | 1 + test/boot/expo.c | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/boot/expo.c b/boot/expo.c index d030820e77c..20ca0b9bfa0 100644 --- a/boot/expo.c +++ b/boot/expo.c @@ -30,6 +30,7 @@ int expo_new(const char *name, void *priv, struct expo **expp) exp->priv = priv; INIT_LIST_HEAD(&exp->scene_head); INIT_LIST_HEAD(&exp->str_head); + exp->next_id = 1;
*expp = exp;
diff --git a/test/boot/expo.c b/test/boot/expo.c index 714fdfa415d..8a84cbc7103 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -92,7 +92,7 @@ static int expo_base(struct unit_test_state *uts) *name = '\0'; ut_assertnonnull(exp); ut_asserteq(0, exp->scene_id); - ut_asserteq(0, exp->next_id); + ut_asserteq(1, exp->next_id);
/* Make sure the name was allocated */ ut_assertnonnull(exp->name); @@ -131,7 +131,7 @@ static int expo_scene(struct unit_test_state *uts) ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
scn = NULL; - ut_asserteq(0, exp->next_id); + ut_asserteq(1, exp->next_id); strcpy(name, SCENE_NAME1); id = scene_new(exp, name, SCENE1, &scn); *name = '\0'; @@ -168,6 +168,25 @@ static int expo_scene(struct unit_test_state *uts) } BOOTSTD_TEST(expo_scene, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+/* Check creating a scene with no ID */ +static int expo_scene_no_id(struct unit_test_state *uts) +{ + struct scene *scn; + struct expo *exp; + char name[100]; + int id; + + ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); + ut_asserteq(1, exp->next_id); + + strcpy(name, SCENE_NAME1); + id = scene_new(exp, SCENE_NAME1, 0, &scn); + ut_asserteq(1, scn->id); + + return 0; +} +BOOTSTD_TEST(expo_scene_no_id, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + /* Check creating a scene with objects */ static int expo_object(struct unit_test_state *uts) {

Set aside some expo IDs for 'save' and 'discard' buttons. This avoids needing to store the IDs for these. Adjust the documentation and expo tool for the new EXPOID_BASE_ID value.
Ignore these objects when saving and loading the cedit, since they do not contain real data.
Adjust 'cedit run' to return failure when the user exits the expo without saving. Update the test for this change as well.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
boot/cedit.c | 24 +++++++++++++++++++++--- boot/expo.c | 2 +- doc/develop/cedit.rst | 7 ++++++- doc/develop/expo.rst | 12 ++++++++---- include/expo.h | 20 ++++++++++++++++++++ include/test/cedit-test.h | 30 +++++++++++++++--------------- test/boot/cedit.c | 14 ++++++++------ test/boot/expo.c | 8 ++++---- test/boot/files/expo_ids.h | 3 +-- tools/expo.py | 33 ++++++++++++++++++++++++++++----- 10 files changed, 112 insertions(+), 41 deletions(-)
diff --git a/boot/cedit.c b/boot/cedit.c index b5f89e945bc..a53a4f28990 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -155,7 +155,7 @@ int cedit_run(struct expo *exp) struct video_priv *vid_priv; uint scene_id; struct scene *scn; - bool done; + bool done, save; int ret;
cli_ch_init(cch); @@ -165,6 +165,7 @@ int cedit_run(struct expo *exp) scene_id = ret;
done = false; + save = false; do { struct expo_action act; int ichar, key; @@ -209,6 +210,15 @@ int cedit_run(struct expo *exp) case EXPOACT_OPEN: scene_set_open(scn, act.select.id, true); cedit_arange(exp, vid_priv, scene_id); + switch (scn->highlight_id) { + case EXPOID_SAVE: + done = true; + save = true; + break; + case EXPOID_DISCARD: + done = true; + break; + } break; case EXPOACT_CLOSE: scene_set_open(scn, act.select.id, false); @@ -230,6 +240,8 @@ int cedit_run(struct expo *exp)
if (ret) return log_msg_ret("end", ret); + if (!save) + return -EACCES;
return 0; } @@ -478,6 +490,9 @@ static int h_write_settings_env(struct scene_obj *obj, void *vpriv) const char *str; int val, ret;
+ if (obj->id < EXPOID_BASE_ID) + return 0; + snprintf(var, sizeof(var), "c.%s", obj->name);
switch (obj->type) { @@ -550,6 +565,9 @@ static int h_read_settings_env(struct scene_obj *obj, void *vpriv) char var[60]; int val;
+ if (obj->id < EXPOID_BASE_ID) + return 0; + snprintf(var, sizeof(var), "c.%s", obj->name);
switch (obj->type) { @@ -645,7 +663,7 @@ static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv) int val, ret; uint i, seq;
- if (obj->type != SCENEOBJT_MENU) + if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID) return 0;
menu = (struct scene_obj_menu *)obj; @@ -735,7 +753,7 @@ static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv) int val, ret; uint i;
- if (obj->type != SCENEOBJT_MENU) + if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID) return 0;
menu = (struct scene_obj_menu *)obj; diff --git a/boot/expo.c b/boot/expo.c index 20ca0b9bfa0..2a1591cce6a 100644 --- a/boot/expo.c +++ b/boot/expo.c @@ -30,7 +30,7 @@ int expo_new(const char *name, void *priv, struct expo **expp) exp->priv = priv; INIT_LIST_HEAD(&exp->scene_head); INIT_LIST_HEAD(&exp->str_head); - exp->next_id = 1; + exp->next_id = EXPOID_BASE_ID;
*expp = exp;
diff --git a/doc/develop/cedit.rst b/doc/develop/cedit.rst index 82305b921f0..310be889240 100644 --- a/doc/develop/cedit.rst +++ b/doc/develop/cedit.rst @@ -94,7 +94,7 @@ them. Expo supports doing this with an enum, where every ID is listed in the enum::
enum { - ZERO, + ID_PROMPT = EXPOID_BASE_ID,
ID_PROMPT,
@@ -130,6 +130,11 @@ that means that something is wrong with your syntax, or perhaps you have an ID in the `.dts` file that is not mentioned in your enum. Check both files and try again.
+Note that the first ID in your file must be no less that `EXPOID_BASE_ID` since +IDs before that are reserved. The `expo.py` tool automatically obtains this +value from the `expo.h` header file, but you must set the first ID to this +enum value. +
Use the command interface ------------------------- diff --git a/doc/develop/expo.rst b/doc/develop/expo.rst index f7b636e5fc6..d8115c463c1 100644 --- a/doc/develop/expo.rst +++ b/doc/develop/expo.rst @@ -88,8 +88,13 @@ or even the IDs of objects. Programmatic creation of many items in a loop can be handled by allocating space in the enum for a maximum number of items, then adding the loop count to the enum values to obtain unique IDs.
-Where dynamic IDs are need, use expo_set_dynamic_start() to set the start value, -so that they are allocated above the starting (enum) IDs. +Some standard IDs are reserved for certain purposes. These are defined by +`enum expo_id_t` and start at 1. `EXPOID_BASE_ID` defines the first ID which +can be used for an expo. + +An ID of 0 is invalid. If this is specified in an expo call then a valid +'dynamic IDs is allocated. Use expo_set_dynamic_start() to set the start +value, so that they are allocated above the starting (enum) IDs.
All text strings are stored in a structure attached to the expo, referenced by a text ID. This makes it easier at some point to implement multiple languages or @@ -417,8 +422,7 @@ strings are provided inline in the nodes where they are used. /* this comment is parsed by the expo.py tool to insert the values below
enum { - ZERO, - ID_PROMPT, + ID_PROMPT = EXPOID_BASE_ID, ID_SCENE1, ID_SCENE1_TITLE,
diff --git a/include/expo.h b/include/expo.h index dc3b68f68ee..6c2e9437b73 100644 --- a/include/expo.h +++ b/include/expo.h @@ -15,6 +15,26 @@ struct udevice;
#include <cli.h>
+/** + * enum expo_id_t - standard expo IDs + * + * These are assumed to be in use at all times. Expos should use IDs starting + * from EXPOID_BASE_ID, + * + * @EXPOID_NONE: Not used, invalid ID 0 + * @EXPOID_SAVE: User has requested that the expo data be saved + * @EXPOID_DISCARD: User has requested that the expo data be discarded + * @EXPOID_BASE_ID: First ID which can be used for expo objects + */ +enum expo_id_t { + EXPOID_NONE, + + EXPOID_SAVE, + EXPOID_DISCARD, + + EXPOID_BASE_ID = 5, +}; + /** * enum expoact_type - types of actions reported by the expo * diff --git a/include/test/cedit-test.h b/include/test/cedit-test.h index 475ecc9c2dc..0d38a953415 100644 --- a/include/test/cedit-test.h +++ b/include/test/cedit-test.h @@ -9,24 +9,24 @@ #ifndef __cedit_test_h #define __cedit_test_h
-#define ID_PROMPT 1 -#define ID_SCENE1 2 -#define ID_SCENE1_TITLE 3 +#define ID_PROMPT 5 +#define ID_SCENE1 6 +#define ID_SCENE1_TITLE 7
-#define ID_CPU_SPEED 4 -#define ID_CPU_SPEED_TITLE 5 -#define ID_CPU_SPEED_1 6 -#define ID_CPU_SPEED_2 7 -#define ID_CPU_SPEED_3 8 +#define ID_CPU_SPEED 8 +#define ID_CPU_SPEED_TITLE 9 +#define ID_CPU_SPEED_1 10 +#define ID_CPU_SPEED_2 11 +#define ID_CPU_SPEED_3 12
-#define ID_POWER_LOSS 9 -#define ID_AC_OFF 10 -#define ID_AC_ON 11 -#define ID_AC_MEMORY 12 +#define ID_POWER_LOSS 13 +#define ID_AC_OFF 14 +#define ID_AC_ON 15 +#define ID_AC_MEMORY 16
-#define ID_MACHINE_NAME 13 -#define ID_MACHINE_NAME_EDIT 14 +#define ID_MACHINE_NAME 17 +#define ID_MACHINE_NAME_EDIT 18
-#define ID_DYNAMIC_START 15 +#define ID_DYNAMIC_START 19
#endif diff --git a/test/boot/cedit.c b/test/boot/cedit.c index aa417190486..37807f9a981 100644 --- a/test/boot/cedit.c +++ b/test/boot/cedit.c @@ -34,9 +34,11 @@ static int cedit_base(struct unit_test_state *uts) * ^N Move down to second item * ^M Select item * \e Quit + * + * cedit_run() returns -EACCESS so this command returns CMD_RET_FAILURE */ console_in_puts("\x0e\x0d\x0e\x0d\e"); - ut_assertok(run_command("cedit run", 0)); + ut_asserteq(1, run_command("cedit run", 0));
exp = cur_exp; scn = expo_lookup_scene_id(exp, exp->scene_id); @@ -152,14 +154,14 @@ static int cedit_env(struct unit_test_state *uts) strcpy(str, "my-machine");
ut_assertok(run_command("cedit write_env -v", 0)); - ut_assert_nextlinen("c.cpu-speed=7"); + ut_assert_nextlinen("c.cpu-speed=11"); ut_assert_nextlinen("c.cpu-speed-str=2.5 GHz"); - ut_assert_nextlinen("c.power-loss=10"); + ut_assert_nextlinen("c.power-loss=14"); ut_assert_nextlinen("c.power-loss-str=Always Off"); ut_assert_nextlinen("c.machine-name=my-machine"); ut_assert_console_end();
- ut_asserteq(7, env_get_ulong("c.cpu-speed", 10, 0)); + ut_asserteq(11, env_get_ulong("c.cpu-speed", 10, 0)); ut_asserteq_str("2.5 GHz", env_get("c.cpu-speed-str")); ut_asserteq_str("my-machine", env_get("c.machine-name"));
@@ -168,8 +170,8 @@ static int cedit_env(struct unit_test_state *uts) *str = '\0';
ut_assertok(run_command("cedit read_env -v", 0)); - ut_assert_nextlinen("c.cpu-speed=7"); - ut_assert_nextlinen("c.power-loss=10"); + ut_assert_nextlinen("c.cpu-speed=11"); + ut_assert_nextlinen("c.power-loss=14"); ut_assert_nextlinen("c.machine-name=my-machine"); ut_assert_console_end();
diff --git a/test/boot/expo.c b/test/boot/expo.c index 8a84cbc7103..2e8acac0731 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -92,7 +92,7 @@ static int expo_base(struct unit_test_state *uts) *name = '\0'; ut_assertnonnull(exp); ut_asserteq(0, exp->scene_id); - ut_asserteq(1, exp->next_id); + ut_asserteq(EXPOID_BASE_ID, exp->next_id);
/* Make sure the name was allocated */ ut_assertnonnull(exp->name); @@ -131,7 +131,7 @@ static int expo_scene(struct unit_test_state *uts) ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
scn = NULL; - ut_asserteq(1, exp->next_id); + ut_asserteq(EXPOID_BASE_ID, exp->next_id); strcpy(name, SCENE_NAME1); id = scene_new(exp, name, SCENE1, &scn); *name = '\0'; @@ -177,11 +177,11 @@ static int expo_scene_no_id(struct unit_test_state *uts) int id;
ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); - ut_asserteq(1, exp->next_id); + ut_asserteq(EXPOID_BASE_ID, exp->next_id);
strcpy(name, SCENE_NAME1); id = scene_new(exp, SCENE_NAME1, 0, &scn); - ut_asserteq(1, scn->id); + ut_asserteq(EXPOID_BASE_ID, scn->id);
return 0; } diff --git a/test/boot/files/expo_ids.h b/test/boot/files/expo_ids.h index a86e0d06f6b..ffb511364b1 100644 --- a/test/boot/files/expo_ids.h +++ b/test/boot/files/expo_ids.h @@ -4,8 +4,7 @@ */
enum { - ZERO, - ID_PROMPT, + ID_PROMPT = EXPOID_BASE_ID,
ID_SCENE1, ID_SCENE1_TITLE, diff --git a/tools/expo.py b/tools/expo.py index ea80c70f04e..44995f28a38 100755 --- a/tools/expo.py +++ b/tools/expo.py @@ -20,17 +20,22 @@ from u_boot_pylib import tools
# Parse: # SCENE1 = 7, +# or SCENE1 = EXPOID_BASE_ID, # or SCENE2, -RE_ENUM = re.compile(r'(\S*)(\s*= (\d))?,') +RE_ENUM = re.compile(r'(\S*)(\s*= ([0-9A-Z_]+))?,')
# Parse #define <name> "string" RE_DEF = re.compile(r'#define (\S*)\s*"(.*)"')
-def calc_ids(fname): +# Parse EXPOID_BASE_ID = 5, +RE_BASE_ID = re.compile(r'\s*EXPOID_BASE_ID\s*= (\d+),') + +def calc_ids(fname, base_id): """Figure out the value of the enums in a C file
Args: fname (str): Filename to parse + base_id (int): Base ID (value of EXPOID_BASE_ID)
Returns: OrderedDict(): @@ -55,8 +60,12 @@ def calc_ids(fname): if not line or line.startswith('/*'): continue m_enum = RE_ENUM.match(line) - if m_enum.group(3): - cur_id = int(m_enum.group(3)) + enum_name = m_enum.group(3) + if enum_name: + if enum_name == 'EXPOID_BASE_ID': + cur_id = base_id + else: + cur_id = int(enum_name) vals[m_enum.group(1)] = cur_id cur_id += 1 else: @@ -67,10 +76,24 @@ def calc_ids(fname): return vals
+def find_base_id(): + fname = 'include/expo.h' + base_id = None + with open(fname, 'r', encoding='utf-8') as inf: + for line in inf.readlines(): + m_base_id = RE_BASE_ID.match(line) + if m_base_id: + base_id = int(m_base_id.group(1)) + if base_id is None: + raise ValueError('EXPOID_BASE_ID not found in expo.h') + #print(f'EXPOID_BASE_ID={base_id}') + return base_id + def run_expo(args): """Run the expo program""" + base_id = find_base_id() fname = args.enum_fname or args.layout - ids = calc_ids(fname) + ids = calc_ids(fname, base_id) if not ids: print(f"Warning: No enum ID values found in file '{fname}'")

At present menu items are stored according to their sequence number in the menu. In some cases we may want to have holes in that sequence, or not use a sequence at all.
Add a new 'value' property for menu items. This will be used for reading and writing, if present. If there is no 'value' property, then the normal sequence number will be used instead.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
arch/sandbox/dts/cedit.dtsi | 3 +++ boot/expo_build.c | 16 ++++++++++++---- boot/scene_internal.h | 10 ++++++++++ boot/scene_menu.c | 17 +++++++++++++++++ doc/develop/expo.rst | 10 ++++++++++ include/expo.h | 2 ++ test/boot/expo.c | 1 + test/boot/files/expo_layout.dts | 3 +++ 8 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/arch/sandbox/dts/cedit.dtsi b/arch/sandbox/dts/cedit.dtsi index 9bd84e62936..facd7a49bef 100644 --- a/arch/sandbox/dts/cedit.dtsi +++ b/arch/sandbox/dts/cedit.dtsi @@ -39,6 +39,9 @@ /* IDs for the menu items */ item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2 ID_CPU_SPEED_3>; + + /* values for the menu items */ + item-value = <0 3 6>; };
power-loss { diff --git a/boot/expo_build.c b/boot/expo_build.c index 04d88a2c308..3458bf12c67 100644 --- a/boot/expo_build.c +++ b/boot/expo_build.c @@ -228,10 +228,10 @@ static void list_strings(struct build_info *info) static int menu_build(struct build_info *info, ofnode node, struct scene *scn, uint id, struct scene_obj **objp) { + const u32 *item_ids, *item_values; struct scene_obj_menu *menu; + int ret, size, i, num_items; uint title_id, menu_id; - const u32 *item_ids; - int ret, size, i; const char *name;
name = ofnode_get_name(node); @@ -255,9 +255,15 @@ static int menu_build(struct build_info *info, ofnode node, struct scene *scn, return log_msg_ret("itm", -EINVAL); if (!size || size % sizeof(u32)) return log_msg_ret("isz", -EINVAL); - size /= sizeof(u32); + num_items = size / sizeof(u32);
- for (i = 0; i < size; i++) { + item_values = ofnode_read_prop(node, "item-value", &size); + if (item_values) { + if (size != num_items * sizeof(u32)) + return log_msg_ret("vsz", -EINVAL); + } + + for (i = 0; i < num_items; i++) { struct scene_menitem *item; uint label, key, desc;
@@ -281,6 +287,8 @@ static int menu_build(struct build_info *info, ofnode node, struct scene *scn, desc, 0, 0, &item); if (ret < 0) return log_msg_ret("mi", ret); + if (item_values) + item->value = fdt32_to_cpu(item_values[i]); } *objp = &menu->obj;
diff --git a/boot/scene_internal.h b/boot/scene_internal.h index be25f6a8b96..ec9008ea593 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -281,6 +281,16 @@ struct scene_menitem *scene_menuitem_find(const struct scene_obj_menu *menu, struct scene_menitem *scene_menuitem_find_seq(const struct scene_obj_menu *menu, uint seq);
+/** + * scene_menuitem_find_val() - Find the menu item with a given value + * + * @menu: Menu to check + * @find_val: Value to look for + * Return: menu item if found, else NULL + */ +struct scene_menitem *scene_menuitem_find_val(const struct scene_obj_menu *menu, + int val); + /** * scene_bbox_union() - update bouding box with the demensions of an object * diff --git a/boot/scene_menu.c b/boot/scene_menu.c index dbf6eacb298..002821ec1f5 100644 --- a/boot/scene_menu.c +++ b/boot/scene_menu.c @@ -62,6 +62,22 @@ struct scene_menitem *scene_menuitem_find_seq(const struct scene_obj_menu *menu, return NULL; }
+struct scene_menitem *scene_menuitem_find_val(const struct scene_obj_menu *menu, + int val) +{ + struct scene_menitem *item; + uint i; + + i = 0; + list_for_each_entry(item, &menu->item_head, sibling) { + if (item->value == val) + return item; + i++; + } + + return NULL; +} + /** * update_pointers() - Update the pointer object and handle highlights * @@ -417,6 +433,7 @@ int scene_menuitem(struct scene *scn, uint menu_id, const char *name, uint id, item->desc_id = desc_id; item->preview_id = preview_id; item->flags = flags; + item->value = INT_MAX; list_add_tail(&item->sibling, &menu->item_head);
if (itemp) diff --git a/doc/develop/expo.rst b/doc/develop/expo.rst index d8115c463c1..cc7c36173db 100644 --- a/doc/develop/expo.rst +++ b/doc/develop/expo.rst @@ -361,6 +361,13 @@ item-id Specifies the ID for each menu item. These are used for checking which item has been selected.
+item-value + type: u32 list, optional + + Specifies the value for each menu item. These are used for saving and + loading. If this is omitted the value is its position in the menu (0..n-1). + Valid values are positive and negative integers INT_MIN...(INT_MAX - 1). + item-label / item-label-id type: string list / u32 list, required
@@ -474,6 +481,9 @@ strings are provided inline in the nodes where they are used. /* IDs for the menu items */ item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2 ID_CPU_SPEED_3>; + + /* values for the menu items */ + item-value = <(-1) 3 6>; };
power-loss { diff --git a/include/expo.h b/include/expo.h index 6c2e9437b73..658ff003835 100644 --- a/include/expo.h +++ b/include/expo.h @@ -330,6 +330,7 @@ enum scene_menuitem_flags_t { * @desc_id: ID of text object to use as the description text * @preview_id: ID of the preview object, or 0 if none * @flags: Flags for this item + * @value: Value for this item, or INT_MAX to use sequence * @sibling: Node to link this item to its siblings */ struct scene_menitem { @@ -340,6 +341,7 @@ struct scene_menitem { uint desc_id; uint preview_id; uint flags; + int value; struct list_head sibling; };
diff --git a/test/boot/expo.c b/test/boot/expo.c index 2e8acac0731..75f31fe6690 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -719,6 +719,7 @@ static int expo_test_build(struct unit_test_state *uts) ut_asserteq(0, item->desc_id); ut_asserteq(0, item->preview_id); ut_asserteq(0, item->flags); + ut_asserteq(0, item->value);
txt = scene_obj_find(scn, item->label_id, SCENEOBJT_NONE); ut_asserteq_str("2 GHz", expo_get_str(exp, txt->str_id)); diff --git a/test/boot/files/expo_layout.dts b/test/boot/files/expo_layout.dts index bed552288f4..ebe5adb27bb 100644 --- a/test/boot/files/expo_layout.dts +++ b/test/boot/files/expo_layout.dts @@ -39,6 +39,9 @@ item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2 ID_CPU_SPEED_3>;
+ /* values for the menu items */ + item-value = <(-1) 3 6>; + start-bit = <0x400>; bit-length = <2>; };

Add some more logging in the CMOS read/write code. Tidy up a few comments while we are here.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
boot/cedit.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/boot/cedit.c b/boot/cedit.c index a53a4f28990..cc1d5b76357 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -585,7 +585,7 @@ static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
/* * note that no validation is done here, to make sure the ID is - * valid * and actually points to a menu item + * valid and actually points to a menu item */ menu->cur_item_id = val; break; @@ -719,6 +719,7 @@ int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev, }
/* write the data to the RTC */ + log_debug("Writing CMOS\n"); first = CMOS_MAX_BYTES; last = -1; for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) { @@ -786,6 +787,7 @@ static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv) }
/* update the current item */ + log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id); mi = scene_menuitem_find_seq(menu, val); if (!mi) return log_msg_ret("seq", -ENOENT); @@ -820,7 +822,7 @@ int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev, goto done; }
- /* read the data to the RTC */ + /* indicate what bytes were read from the RTC */ first = CMOS_MAX_BYTES; last = -1; for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {

Update the cedit read/write functions to support menu items with values.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
boot/cedit.c | 148 +++++++++++++++++++++----------- boot/scene_menu.c | 2 +- doc/usage/cmd/cedit.rst | 15 +++- test/boot/cedit.c | 8 +- test/boot/files/expo_layout.dts | 4 +- 5 files changed, 117 insertions(+), 60 deletions(-)
diff --git a/boot/cedit.c b/boot/cedit.c index cc1d5b76357..7fc800940fb 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -294,11 +294,49 @@ static int get_cur_menuitem_text(const struct scene_obj_menu *menu, return 0; }
+/** + * get_cur_menuitem_val() - Get the value of a menu's current item + * + * Obtains the value of the current item in the menu. If no value, then + * enumerates the items of a menu (0, 1, 2) and returns the sequence number of + * the currently selected item. If the first item is selected, this returns 0; + * if the second, 1; etc. + * + * @menu: Menu to check + * @valp: Returns current-item value / sequence number + * Return: 0 on success, else -ve error value + */ +static int get_cur_menuitem_val(const struct scene_obj_menu *menu, int *valp) +{ + const struct scene_menitem *mi; + int seq; + + seq = 0; + list_for_each_entry(mi, &menu->item_head, sibling) { + if (mi->id == menu->cur_item_id) { + *valp = mi->value == INT_MAX ? seq : mi->value; + return 0; + } + seq++; + } + + return log_msg_ret("nf", -ENOENT); +} + +/** + * write_dt_string() - Write a string to the devicetree, expanding if needed + * + * If this fails, it tries again after expanding the devicetree a little + * + * @buf: Buffer containing the devicetree + * @name: Property name to use + * @str: String value + * Return: 0 if OK, -EFAULT if something went horribly wrong + */ static int write_dt_string(struct abuf *buf, const char *name, const char *str) { int ret, i;
- /* write the text of the current item */ ret = -EAGAIN; for (i = 0; ret && i < 2; i++) { ret = fdt_property_string(abuf_data(buf), name, str); @@ -316,6 +354,38 @@ static int write_dt_string(struct abuf *buf, const char *name, const char *str) return 0; }
+/** + * write_dt_u32() - Write an int to the devicetree, expanding if needed + * + * If this fails, it tries again after expanding the devicetree a little + * + * @buf: Buffer containing the devicetree + * @name: Property name to use + * @lva: Integer value + * Return: 0 if OK, -EFAULT if something went horribly wrong + */ +static int write_dt_u32(struct abuf *buf, const char *name, uint val) +{ + int ret, i; + + /* write the text of the current item */ + ret = -EAGAIN; + for (i = 0; ret && i < 2; i++) { + ret = fdt_property_u32(abuf_data(buf), name, val); + if (!i) { + ret = check_space(ret, buf); + if (ret) + return log_msg_ret("rs2", -ENOMEM); + } + } + + /* this should not happen */ + if (ret) + return log_msg_ret("str", -EFAULT); + + return 0; +} + static int h_write_settings(struct scene_obj *obj, void *vpriv) { struct cedit_iter_priv *priv = vpriv; @@ -340,23 +410,21 @@ static int h_write_settings(struct scene_obj *obj, void *vpriv) const struct scene_obj_menu *menu; const char *str; char name[80]; - int i; + int val;
/* write the ID of the current item */ menu = (struct scene_obj_menu *)obj; - ret = -EAGAIN; - for (i = 0; ret && i < 2; i++) { - ret = fdt_property_u32(abuf_data(buf), obj->name, - menu->cur_item_id); - if (!i) { - ret = check_space(ret, buf); - if (ret) - return log_msg_ret("res", -ENOMEM); - } - } - /* this should not happen */ + ret = write_dt_u32(buf, obj->name, menu->cur_item_id); if (ret) - return log_msg_ret("wrt", -EFAULT); + return log_msg_ret("wrt", ret); + + snprintf(name, sizeof(name), "%s-value", obj->name); + ret = get_cur_menuitem_val(menu, &val); + if (ret < 0) + return log_msg_ret("cur", ret); + ret = write_dt_u32(buf, name, val); + if (ret) + return log_msg_ret("wr2", ret);
ret = get_cur_menuitem_text(menu, &str); if (ret) @@ -522,6 +590,14 @@ static int h_write_settings_env(struct scene_obj *obj, void *vpriv) ret = env_set(name, str); if (ret) return log_msg_ret("st2", ret); + + ret = get_cur_menuitem_val(menu, &val); + if (ret < 0) + return log_msg_ret("cur", ret); + snprintf(name, sizeof(name), "c.%s-value", obj->name); + if (priv->verbose) + printf("%s=%d\n", name, val); + break; case SCENEOBJT_TEXTLINE: { const struct scene_obj_textline *tline; @@ -625,43 +701,12 @@ int cedit_read_settings_env(struct expo *exp, bool verbose) return 0; }
-/** - * get_cur_menuitem_seq() - Get the sequence number of a menu's current item - * - * Enumerates the items of a menu (0, 1, 2) and returns the sequence number of - * the currently selected item. If the first item is selected, this returns 0; - * if the second, 1; etc. - * - * @menu: Menu to check - * Return: Sequence number on success, else -ve error value - */ -static int get_cur_menuitem_seq(const struct scene_obj_menu *menu) -{ - const struct scene_menitem *mi; - int seq, found; - - seq = 0; - found = -1; - list_for_each_entry(mi, &menu->item_head, sibling) { - if (mi->id == menu->cur_item_id) { - found = seq; - break; - } - seq++; - } - - if (found == -1) - return log_msg_ret("nf", -ENOENT); - - return found; -} - static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv) { const struct scene_obj_menu *menu; struct cedit_iter_priv *priv = vpriv; int val, ret; - uint i, seq; + uint i;
if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID) return 0; @@ -669,11 +714,10 @@ static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv) menu = (struct scene_obj_menu *)obj; val = menu->cur_item_id;
- ret = get_cur_menuitem_seq(menu); + ret = get_cur_menuitem_val(menu, &val); if (ret < 0) return log_msg_ret("cur", ret); - seq = ret; - log_debug("%s: seq=%d\n", menu->obj.name, seq); + log_debug("%s: val=%d\n", menu->obj.name, val);
/* figure out where to place this item */ if (!obj->bit_length) @@ -681,11 +725,11 @@ static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv) if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS) return log_msg_ret("bit", -E2BIG);
- for (i = 0; i < obj->bit_length; i++, seq >>= 1) { + for (i = 0; i < obj->bit_length; i++, val >>= 1) { uint bitnum = obj->start_bit + i;
priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum); - if (seq & 1) + if (val & 1) priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum)); log_debug("bit %x %x %x\n", bitnum, priv->mask[CMOS_BYTE(bitnum)], @@ -788,7 +832,7 @@ static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
/* update the current item */ log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id); - mi = scene_menuitem_find_seq(menu, val); + mi = scene_menuitem_find_val(menu, val); if (!mi) return log_msg_ret("seq", -ENOENT);
diff --git a/boot/scene_menu.c b/boot/scene_menu.c index 002821ec1f5..86f5fd88804 100644 --- a/boot/scene_menu.c +++ b/boot/scene_menu.c @@ -70,7 +70,7 @@ struct scene_menitem *scene_menuitem_find_val(const struct scene_obj_menu *menu,
i = 0; list_for_each_entry(item, &menu->item_head, sibling) { - if (item->value == val) + if (item->value == INT_MAX ? val == i : item->value == val) return item; i++; } diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst index f415b48699e..0f0cc26e74b 100644 --- a/doc/usage/cmd/cedit.rst +++ b/doc/usage/cmd/cedit.rst @@ -104,8 +104,10 @@ That results in:: / { cedit-values { cpu-speed = <0x00000006>; + cpu-speed-value = <0x00000003>; cpu-speed-str = "2 GHz"; power-loss = <0x0000000a>; + power-loss-value = <0x00000000>; power-loss-str = "Always Off"; }; } @@ -115,16 +117,23 @@ That results in:: This shows settings being stored in the environment::
=> cedit write_env -v - c.cpu-speed=7 + c.cpu-speed=11 c.cpu-speed-str=2.5 GHz - c.power-loss=12 - c.power-loss-str=Memory + c.cpu-speed-value=3 + c.power-loss=14 + c.power-loss-str=Always Off + c.power-loss-value=0 + c.machine-name=my-machine + c.cpu-speed=11 + c.power-loss=14 + c.machine-name=my-machine => print ... c.cpu-speed=6 c.cpu-speed-str=2 GHz c.power-loss=10 c.power-loss-str=Always Off + c.machine-name=my-machine ...
=> cedit read_env -v diff --git a/test/boot/cedit.c b/test/boot/cedit.c index 37807f9a981..876503befe0 100644 --- a/test/boot/cedit.c +++ b/test/boot/cedit.c @@ -100,14 +100,16 @@ static int cedit_fdt(struct unit_test_state *uts)
ut_asserteq(ID_CPU_SPEED_2, ofnode_read_u32_default(node, "cpu-speed", 0)); + ut_asserteq(3, + ofnode_read_u32_default(node, "cpu-speed-value", 0)); ut_asserteq_str("2.5 GHz", ofnode_read_string(node, "cpu-speed-str")); ut_asserteq_str("my-machine", ofnode_read_string(node, "machine-name"));
- /* There should only be 5 properties */ + /* There should only be 7 properties */ for (i = 0, ofnode_first_property(node, &prop); ofprop_valid(&prop); i++, ofnode_next_property(&prop)) ; - ut_asserteq(5, i); + ut_asserteq(7, i);
ut_assert_console_end();
@@ -156,8 +158,10 @@ static int cedit_env(struct unit_test_state *uts) ut_assertok(run_command("cedit write_env -v", 0)); ut_assert_nextlinen("c.cpu-speed=11"); ut_assert_nextlinen("c.cpu-speed-str=2.5 GHz"); + ut_assert_nextlinen("c.cpu-speed-value=3"); ut_assert_nextlinen("c.power-loss=14"); ut_assert_nextlinen("c.power-loss-str=Always Off"); + ut_assert_nextlinen("c.power-loss-value=0"); ut_assert_nextlinen("c.machine-name=my-machine"); ut_assert_console_end();
diff --git a/test/boot/files/expo_layout.dts b/test/boot/files/expo_layout.dts index ebe5adb27bb..9bc1e4950b9 100644 --- a/test/boot/files/expo_layout.dts +++ b/test/boot/files/expo_layout.dts @@ -40,10 +40,10 @@ ID_CPU_SPEED_3>;
/* values for the menu items */ - item-value = <(-1) 3 6>; + item-value = <0 3 6>;
start-bit = <0x400>; - bit-length = <2>; + bit-length = <3>; };
power-loss {

The scene_txt_str() function calls expo_str() so there is no need to call it beforehand. Drop this unnecessary code.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
boot/expo_build.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-)
diff --git a/boot/expo_build.c b/boot/expo_build.c index 3458bf12c67..71aa03f2826 100644 --- a/boot/expo_build.c +++ b/boot/expo_build.c @@ -47,7 +47,6 @@ int add_txt_str(struct build_info *info, ofnode node, struct scene *scn, const char *find_name, uint obj_id) { const char *text; - uint str_id; int ret;
info->err_prop = find_name; @@ -68,12 +67,7 @@ int add_txt_str(struct build_info *info, ofnode node, struct scene *scn, return log_msg_ret("id", -EINVAL); }
- ret = expo_str(scn->expo, find_name, 0, text); - if (ret < 0) - return log_msg_ret("add", ret); - str_id = ret; - - ret = scene_txt_str(scn, find_name, obj_id, str_id, text, NULL); + ret = scene_txt_str(scn, find_name, obj_id, 0, text, NULL); if (ret < 0) return log_msg_ret("add", ret);
@@ -95,7 +89,6 @@ int add_txt_str_list(struct build_info *info, ofnode node, struct scene *scn, const char *find_name, int index, uint obj_id) { const char *text; - uint str_id; int ret;
ret = ofnode_read_string_index(node, find_name, index, &text); @@ -115,12 +108,7 @@ int add_txt_str_list(struct build_info *info, ofnode node, struct scene *scn, return log_msg_ret("id", -EINVAL); }
- ret = expo_str(scn->expo, find_name, 0, text); - if (ret < 0) - return log_msg_ret("add", ret); - str_id = ret; - - ret = scene_txt_str(scn, find_name, obj_id, str_id, text, NULL); + ret = scene_txt_str(scn, find_name, obj_id, 0, text, NULL); if (ret < 0) return log_msg_ret("add", ret);

This function is really just an assignment, so serves no useful purpose. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
boot/expo_build.c | 4 ++-- boot/scene.c | 7 ------- include/expo.h | 9 --------- test/boot/expo.c | 2 +- 4 files changed, 3 insertions(+), 19 deletions(-)
diff --git a/boot/expo_build.c b/boot/expo_build.c index 71aa03f2826..ae0ffd225b3 100644 --- a/boot/expo_build.c +++ b/boot/expo_build.c @@ -405,7 +405,7 @@ static int scene_build(struct build_info *info, ofnode scn_node, if (ret < 0) return log_msg_ret("tit", ret); title_id = ret; - scene_title_set(scn, title_id); + scn->title_id = title_id;
ret = add_txt_str(info, scn_node, scn, "prompt", 0); if (ret < 0) @@ -421,7 +421,7 @@ static int scene_build(struct build_info *info, ofnode scn_node, return 0; }
-int build_it(struct build_info *info, ofnode root, struct expo **expp) +static int build_it(struct build_info *info, ofnode root, struct expo **expp) { ofnode scenes, node; struct expo *exp; diff --git a/boot/scene.c b/boot/scene.c index 56569e76e9f..1369bcda13b 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -71,13 +71,6 @@ void scene_destroy(struct scene *scn) free(scn); }
-int scene_title_set(struct scene *scn, uint id) -{ - scn->title_id = id; - - return 0; -} - int scene_obj_count(struct scene *scn) { struct scene_obj *obj; diff --git a/include/expo.h b/include/expo.h index 658ff003835..8e834b50e4f 100644 --- a/include/expo.h +++ b/include/expo.h @@ -540,15 +540,6 @@ void scene_set_highlight_id(struct scene *scn, uint id); */ int scene_set_open(struct scene *scn, uint id, bool open);
-/** - * scene_title_set() - set the scene title - * - * @scn: Scene to update - * @title_id: Title ID to set - * Returns: 0 if OK - */ -int scene_title_set(struct scene *scn, uint title_id); - /** * scene_obj_count() - Count the number of objects in a scene * diff --git a/test/boot/expo.c b/test/boot/expo.c index 75f31fe6690..c7b8e9ba674 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -152,7 +152,7 @@ static int expo_scene(struct unit_test_state *uts) scn = NULL; id = scene_new(exp, SCENE_NAME2, 0, &scn); ut_assertnonnull(scn); - ut_assertok(scene_title_set(scn, title_id)); + scn->title_id = title_id; ut_asserteq(STR_SCENE_TITLE + 1, id); ut_asserteq(STR_SCENE_TITLE + 2, exp->next_id); ut_asserteq_ptr(exp, scn->expo);

Some files may include this header file without first including dm.h so add a forward declaration.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
include/cedit.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/cedit.h b/include/cedit.h index f43cafa5aa2..f9a4a6d9e8e 100644 --- a/include/cedit.h +++ b/include/cedit.h @@ -12,6 +12,7 @@ struct abuf; struct expo; struct scene; +struct udevice; struct video_priv;
enum {

Enable unit tests so we can run command-line tests in coreboot. Enable console recording, with enough space for the 'cbsysinfo' command. Add to the pre-relocation malloc() space to make room for this.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
configs/coreboot_defconfig | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/configs/coreboot_defconfig b/configs/coreboot_defconfig index 7d744e9962a..5433a5ae0c2 100644 --- a/configs/coreboot_defconfig +++ b/configs/coreboot_defconfig @@ -1,6 +1,7 @@ CONFIG_X86=y CONFIG_TEXT_BASE=0x1110000 CONFIG_SYS_MALLOC_LEN=0x2000000 +CONFIG_SYS_MALLOC_F_LEN=0x1000 CONFIG_NR_DRAM_BANKS=8 CONFIG_ENV_SIZE=0x1000 CONFIG_DEFAULT_DEVICE_TREE="coreboot" @@ -16,6 +17,8 @@ CONFIG_SHOW_BOOT_PROGRESS=y CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro" CONFIG_BOOTCOMMAND="bootflow scan -l; if bootflow menu; then cls; bootflow boot; fi" +CONFIG_CONSOLE_RECORD=y +CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 CONFIG_PRE_CONSOLE_BUFFER=y CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_LOG=y @@ -60,3 +63,4 @@ CONFIG_CONSOLE_SCROLL_LINES=5 CONFIG_CMD_DHRYSTONE=y # CONFIG_GZIP is not set CONFIG_SMBIOS_PARSER=y +CONFIG_UNIT_TEST=y

Update to a newer version which supports settings in CMOS RAM.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
.azure-pipelines.yml | 2 +- .gitlab-ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index b9d6aa98a0b..05efb8449ab 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -236,7 +236,7 @@ stages: cp images/spi-nor.img ${UBOOT_TRAVIS_BUILD_DIR}/; fi if [[ "${TEST_PY_BD}" == "coreboot" ]]; then - wget -O - "https://drive.google.com/uc?id=1uJ2VkUQ8czWFZmhJQ90Tp8V_zrJ6BrBH&export=..." |xz -dc >${UBOOT_TRAVIS_BUILD_DIR}/coreboot.rom; + wget -O - "https://drive.google.com/uc?id=1RWzwnrha-wsj8WgO2XHByo7vttxb62pJ&export=..." |xz -dc >${UBOOT_TRAVIS_BUILD_DIR}/coreboot.rom; wget -O - "https://drive.google.com/uc?id=149Cz-5SZXHNKpi9xg6R_5XITWohu348y&export=..." >cbfstool; chmod a+x cbfstool; ./cbfstool ${UBOOT_TRAVIS_BUILD_DIR}/coreboot.rom add-flat-binary -f ${UBOOT_TRAVIS_BUILD_DIR}/u-boot.bin -n fallback/payload -c LZMA -l 0x1110000 -e 0x1110000; diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fbf99f0322a..1402d97d805 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -71,7 +71,7 @@ stages: fi - if [[ "${TEST_PY_BD}" == "coreboot" ]]; then wget -O - - "https://drive.google.com/uc?id=1uJ2VkUQ8czWFZmhJQ90Tp8V_zrJ6BrBH&export=..." | + "https://drive.google.com/uc?id=1RWzwnrha-wsj8WgO2XHByo7vttxb62pJ&export=..." | xz -dc >${UBOOT_TRAVIS_BUILD_DIR}/coreboot.rom; wget -O - "https://drive.google.com/uc?id=149Cz-5SZXHNKpi9xg6R_5XITWohu348y&export=..." >

Add a simple test for this command, checking that coreboot has the required features.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
test/cmd/Makefile | 1 + test/cmd/coreboot.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 test/cmd/coreboot.c
diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 7e40e25b9e8..dd2c0dc28b5 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -14,6 +14,7 @@ endif obj-y += exit.o mem.o obj-$(CONFIG_CMD_ADDRMAP) += addrmap.o obj-$(CONFIG_CMD_BDI) += bdinfo.o +obj-$(CONFIG_COREBOOT_SYSINFO) += coreboot.o obj-$(CONFIG_CMD_FDT) += fdt.o obj-$(CONFIG_CONSOLE_TRUETYPE) += font.o obj-$(CONFIG_CMD_HISTORY) += history.o diff --git a/test/cmd/coreboot.c b/test/cmd/coreboot.c new file mode 100644 index 00000000000..054fe2d7950 --- /dev/null +++ b/test/cmd/coreboot.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for coreboot commands + * + * Copyright 2023 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#include <command.h> +#include <test/cmd.h> +#include <test/test.h> +#include <test/ut.h> + +/** + * test_cmd_cbsysinfo() - test the cbsysinfo command produces expected output + * + * This includes ensuring that the coreboot build has the expected options + * enabled + */ +static int test_cmd_cbsysinfo(struct unit_test_state *uts) +{ + ut_assertok(run_command("cbsysinfo", 0)); + ut_assert_nextlinen("Coreboot table at"); + + /* Make sure the linear frame buffer is enabled */ + ut_assert_skip_to_linen("Framebuffer"); + ut_assert_nextlinen(" Phys addr"); + + ut_assert_skip_to_line("Chrome OS VPD: 00000000"); + ut_assert_nextlinen("RSDP"); + ut_assert_nextlinen("Unimpl."); + ut_assert_console_end(); + + return 0; +} +CMD_TEST(test_cmd_cbsysinfo, UT_TESTF_CONSOLE_REC);

Update the cbsysinfo command to show the contents of the CMOS option table.
While we are here, add some example output for this command, along with mention of what the unimplemented tags are.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
cmd/x86/cbsysinfo.c | 73 ++++++++++++++++++++++++++- doc/usage/cmd/cbsysinfo.rst | 99 +++++++++++++++++++++++++++++++++++++ test/cmd/coreboot.c | 7 +++ 3 files changed, 178 insertions(+), 1 deletion(-)
diff --git a/cmd/x86/cbsysinfo.c b/cmd/x86/cbsysinfo.c index 84822a3e321..8c46203e1af 100644 --- a/cmd/x86/cbsysinfo.c +++ b/cmd/x86/cbsysinfo.c @@ -185,6 +185,77 @@ static const char *timestamp_name(uint32_t id) return "<unknown>"; }
+static void show_option_vals(const struct cb_cmos_option_table *tab, + uint id) +{ + const void *ptr, *end; + bool found = false; + + end = (void *)tab + tab->size; + for (ptr = (void *)tab + tab->header_length; ptr < end;) { + const struct cb_record *rec = ptr; + + switch (rec->tag) { + case CB_TAG_OPTION_ENUM: { + const struct cb_cmos_enums *enums = ptr; + + if (enums->config_id == id) { + if (!found) + printf(" "); + printf(" %d:%s", enums->value, enums->text); + found = true; + } + break; + } + break; + case CB_TAG_OPTION_DEFAULTS: + case CB_TAG_OPTION_CHECKSUM: + case CB_TAG_OPTION: + break; + default: + printf("tag %x\n", rec->tag); + break; + } + ptr += rec->size; + } +} + +static void show_option_table(const struct cb_cmos_option_table *tab) +{ + const void *ptr, *end; + + print_ptr("option_table", tab); + if (!tab->size) + return; + + printf(" Bit Len Cfg ID Name\n"); + end = (void *)tab + tab->size; + for (ptr = (void *)tab + tab->header_length; ptr < end;) { + const struct cb_record *rec = ptr; + + switch (rec->tag) { + case CB_TAG_OPTION: { + const struct cb_cmos_entries *entry = ptr; + + printf("%4x %4x %3c %3x %-20s", entry->bit, + entry->length, entry->config, entry->config_id, + entry->name); + show_option_vals(tab, entry->config_id); + printf("\n"); + break; + } + case CB_TAG_OPTION_ENUM: + case CB_TAG_OPTION_DEFAULTS: + case CB_TAG_OPTION_CHECKSUM: + break; + default: + printf("tag %x\n", rec->tag); + break; + } + ptr += rec->size; + } +} + static void show_table(struct sysinfo_t *info, bool verbose) { struct cb_serial *ser = info->serial; @@ -219,7 +290,7 @@ static void show_table(struct sysinfo_t *info, bool verbose) printf("%12d: %02x:%-8s %016llx %016llx\n", i, mr->type, get_mem_name(mr->type), mr->base, mr->size); } - print_ptr("option_table", info->option_table); + show_option_table(info->option_table);
print_hex("CMOS start", info->cmos_range_start); if (info->cmos_range_start) { diff --git a/doc/usage/cmd/cbsysinfo.rst b/doc/usage/cmd/cbsysinfo.rst index 8c03a85169d..ea6878e5423 100644 --- a/doc/usage/cmd/cbsysinfo.rst +++ b/doc/usage/cmd/cbsysinfo.rst @@ -23,3 +23,102 @@ Example ::
=> cbsysinfo + Coreboot table at 500, size 5c4, records 1d (dec 29), decoded to 000000007dce4520, forwarded to 000000007ff9a000 + + CPU KHz : 0 + Serial I/O port: 00000000 + base : 00000000 + pointer : 000000007ff9a370 + type : 1 + base : 000003f8 + baud : 0d115200 + regwidth : 1 + input_hz : 0d1843200 + PCI addr : 00000010 + Mem ranges : 7 + id: type || base || size + 0: 10:table 0000000000000000 0000000000001000 + 1: 01:ram 0000000000001000 000000000009f000 + 2: 02:reserved 00000000000a0000 0000000000060000 + 3: 01:ram 0000000000100000 000000007fe6d000 + 4: 10:table 000000007ff6d000 0000000000093000 + 5: 02:reserved 00000000fec00000 0000000000001000 + 6: 02:reserved 00000000ff800000 0000000000800000 + option_table: 000000007ff9a018 + Bit Len Cfg ID Name + 0 180 r 0 reserved_memory + 180 1 e 4 boot_option 0:Fallback 1:Normal + 184 4 h 0 reboot_counter + 190 8 r 0 reserved_century + 1b8 8 r 0 reserved_ibm_ps2_century + 1c0 1 e 1 power_on_after_fail 0:Disable 1:Enable + 1c4 4 e 6 debug_level 5:Notice 6:Info 7:Debug 8:Spew + 1d0 80 r 0 vbnv + 3f0 10 h 0 check_sum + CMOS start : 1c0 + CMOS end : 1cf + CMOS csum loc: 3f0 + VBNV start : ffffffff + VBNV size : ffffffff + CB version : 4.21-5-g7e6eae9679e3-dirty + Extra : + Build : Thu Sep 07 14:52:41 UTC 2023 + Time : 14:52:41 + Framebuffer : 000000007ff9a410 + Phys addr : fd000000 + X res : 0d800 + X res : 0d600 + Bytes / line: c80 + Bpp : 0d32 + pos/size red 16/8, green 8/8, blue 0/8, reserved 24/8 + GPIOs : 0 + id: port polarity val name + MACs : 0d10 + 0: 12:00:00:00:28:00 + 1: 00:00:00:fd:00:00 + 2: 20:03:00:00:58:02 + 3: 80:0c:00:00:20:10 + 4: 08:00:08:18:08:00 + 5: 16:00:00:00:10:00 + 6: 00:d0:fd:7f:00:00 + 7: 17:00:00:00:10:00 + 8: 00:e0:fd:7f:00:00 + 9: 37:00:00:00:10:00 + Multiboot tab: 0000000000000000 + CB header : 000000007ff9a000 + CB mainboard: 000000007ff9a344 + vendor : 0: Emulation + part_number : 10: QEMU x86 i440fx/piix4 + vboot handoff: 0000000000000000 + size : 0 + vdat addr : 0000000000000000 + size : 0 + SMBIOS : 7ff6d000 + size : 8000 + ROM MTRR : 0 + Tstamp table: 000000007ffdd000 + CBmem cons : 000000007ffde000 + Size : 1fff8 + Cursor : 3332 + MRC cache : 0000000000000000 + ACPI GNVS : 0000000000000000 + Board ID : ffffffff + RAM code : ffffffff + WiFi calib : 0000000000000000 + Ramoops buff: 0 + size : 0 + SF size : 0 + SF sector : 0 + SF erase cmd: 0 + FMAP offset : 0 + CBFS offset : 200 + CBFS size : 3ffe00 + Boot media size: 400000 + MTC start : 0 + MTC size : 0 + Chrome OS VPD: 0000000000000000 + RSDP : 000000007ff75000 + Unimpl. : 10 37 40 + => + +Note that "Unimpl." shows tags which U-Boot does not currently implement. diff --git a/test/cmd/coreboot.c b/test/cmd/coreboot.c index 054fe2d7950..1feca1e5075 100644 --- a/test/cmd/coreboot.c +++ b/test/cmd/coreboot.c @@ -22,6 +22,13 @@ static int test_cmd_cbsysinfo(struct unit_test_state *uts) ut_assertok(run_command("cbsysinfo", 0)); ut_assert_nextlinen("Coreboot table at");
+ /* Make sure CMOS options are enabled */ + ut_assert_skip_to_line( + " 1c0 1 e 1 power_on_after_fail 0:Disable 1:Enable"); + ut_assert_skip_to_line("CMOS start : 1c0"); + ut_assert_nextline(" CMOS end : 1cf"); + ut_assert_nextline(" CMOS csum loc: 3f0"); + /* Make sure the linear frame buffer is enabled */ ut_assert_skip_to_linen("Framebuffer"); ut_assert_nextlinen(" Phys addr");

Enable cedit support along with required options and a simple style.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
arch/x86/dts/coreboot.dts | 7 +++++++ configs/coreboot64_defconfig | 2 ++ configs/coreboot_defconfig | 2 ++ 3 files changed, 11 insertions(+)
diff --git a/arch/x86/dts/coreboot.dts b/arch/x86/dts/coreboot.dts index b867468e16c..39d1d325db9 100644 --- a/arch/x86/dts/coreboot.dts +++ b/arch/x86/dts/coreboot.dts @@ -54,6 +54,13 @@ menu-inset = <3>; menuitem-gap-y = <1>; }; + + cedit-theme { + font-size = <30>; + menu-inset = <3>; + menuitem-gap-y = <1>; + menu-title-margin-x = <30>; + }; };
sysinfo { diff --git a/configs/coreboot64_defconfig b/configs/coreboot64_defconfig index 8f80e0271f7..49c982ef756 100644 --- a/configs/coreboot64_defconfig +++ b/configs/coreboot64_defconfig @@ -18,6 +18,7 @@ CONFIG_SHOW_BOOT_PROGRESS=y CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro" CONFIG_BOOTCOMMAND="bootflow scan -l; if bootflow menu; then cls; bootflow boot; fi" +CONFIG_CEDIT=y CONFIG_SYS_PBSIZE=532 CONFIG_PRE_CONSOLE_BUFFER=y CONFIG_SYS_CONSOLE_INFO_QUIET=y @@ -47,6 +48,7 @@ CONFIG_TFTP_TSIZE=y CONFIG_USE_ROOTPATH=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_OFNODE_MULTI_TREE=y # CONFIG_ACPIGEN is not set CONFIG_SYS_IDE_MAXDEVICE=4 CONFIG_SYS_ATA_DATA_OFFSET=0 diff --git a/configs/coreboot_defconfig b/configs/coreboot_defconfig index 5433a5ae0c2..d4e44e00dca 100644 --- a/configs/coreboot_defconfig +++ b/configs/coreboot_defconfig @@ -17,6 +17,7 @@ CONFIG_SHOW_BOOT_PROGRESS=y CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro" CONFIG_BOOTCOMMAND="bootflow scan -l; if bootflow menu; then cls; bootflow boot; fi" +CONFIG_CEDIT=y CONFIG_CONSOLE_RECORD=y CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 CONFIG_PRE_CONSOLE_BUFFER=y @@ -44,6 +45,7 @@ CONFIG_TFTP_TSIZE=y CONFIG_USE_ROOTPATH=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_OFNODE_MULTI_TREE=y # CONFIG_ACPIGEN is not set CONFIG_SYS_IDE_MAXDEVICE=4 CONFIG_SYS_ATA_DATA_OFFSET=0

Coreboot tables provide information about the CMOS-RAM checksum. Add a command which can check and update this.
With this it is possible to adjust CMOS-RAM settings and tidy up the checksum afterwards.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Avoid using common.h
cmd/Kconfig | 11 ++++ cmd/x86/Makefile | 1 + cmd/x86/cbcmos.c | 139 +++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/cbcmos.rst | 42 ++++++++++++ doc/usage/index.rst | 1 + test/cmd/coreboot.c | 42 ++++++++++++ 6 files changed, 236 insertions(+) create mode 100644 cmd/x86/cbcmos.c create mode 100644 doc/usage/cmd/cbcmos.rst
diff --git a/cmd/Kconfig b/cmd/Kconfig index 26aeeeed03b..2386f4cf3bc 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2782,6 +2782,17 @@ config CMD_CBSYSINFO memory by coreboot before jumping to U-Boot. It can be useful for debugging the beaaviour of coreboot or U-Boot.
+config CMD_CBCMOS + bool "cbcmos" + depends on X86 + default y if SYS_COREBOOT + help + This provides information options to check the CMOS RAM checksum, + if present, as well as to update it. + + It is useful when coreboot CMOS-RAM settings must be examined or + updated. + config CMD_CYCLIC bool "cyclic - Show information about cyclic functions" depends on CYCLIC diff --git a/cmd/x86/Makefile b/cmd/x86/Makefile index 5f82204c87e..565e2077675 100644 --- a/cmd/x86/Makefile +++ b/cmd/x86/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_CMD_CBSYSINFO) += cbsysinfo.o +obj-$(CONFIG_CMD_CBCMOS) += cbcmos.o obj-y += mtrr.o obj-$(CONFIG_CMD_EXCEPTION) += exception.o obj-$(CONFIG_USE_HOB) += hob.o diff --git a/cmd/x86/cbcmos.c b/cmd/x86/cbcmos.c new file mode 100644 index 00000000000..fe5582fbf51 --- /dev/null +++ b/cmd/x86/cbcmos.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Support for booting from coreboot + * + * Copyright 2021 Google LLC + */ + +#define LOG_CATEGORY UCLASS_RTC + +#include <command.h> +#include <dm.h> +#include <rtc.h> +#include <asm/cb_sysinfo.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +const struct sysinfo_t *get_table(void) +{ + if (!gd->arch.coreboot_table) { + printf("No coreboot sysinfo table found\n"); + return NULL; + } + + return &lib_sysinfo; +} + +static int calc_sum(struct udevice *dev, uint start_bit, uint bit_count) +{ + uint start_byte = start_bit / 8; + uint byte_count = bit_count / 8; + int ret, i; + uint sum; + + log_debug("Calc sum from %x: %x bytes\n", start_byte, byte_count); + sum = 0; + for (i = 0; i < bit_count / 8; i++) { + ret = rtc_read8(dev, start_bit / 8 + i); + if (ret < 0) + return ret; + sum += ret; + } + + return (sum & 0xff) << 8 | (sum & 0xff00) >> 8; +} + +/** + * prep_cbcmos() - Prepare for a CMOS-RAM command + * + * @tab: coreboot table + * @devnum: RTC device name to use, or NULL for the first one + * @dep: Returns RTC device on success + * Return: calculated checksum for CMOS RAM or -ve on error + */ +static int prep_cbcmos(const struct sysinfo_t *tab, const char *devname, + struct udevice **devp) +{ + struct udevice *dev; + int ret; + + if (!tab) + return CMD_RET_FAILURE; + if (devname) + ret = uclass_get_device_by_name(UCLASS_RTC, devname, &dev); + else + ret = uclass_first_device_err(UCLASS_RTC, &dev); + if (ret) { + printf("Failed to get RTC device: %dE\n", ret); + return ret; + } + + ret = calc_sum(dev, tab->cmos_range_start, + tab->cmos_range_end + 1 - tab->cmos_range_start); + if (ret < 0) { + printf("Failed to read RTC device: %dE\n", ret); + return ret; + } + *devp = dev; + + return ret; +} + +static int do_cbcmos_check(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + const struct sysinfo_t *tab = get_table(); + struct udevice *dev; + u16 cur, sum; + int ret; + + ret = prep_cbcmos(tab, argv[1], &dev); + if (ret < 0) + return CMD_RET_FAILURE; + sum = ret; + + ret = rtc_read16(dev, tab->cmos_checksum_location / 8, &cur); + if (ret < 0) { + printf("Failed to read RTC device: %dE\n", ret); + return CMD_RET_FAILURE; + } + if (sum != cur) { + printf("Checksum %04x error: calculated %04x\n", cur, sum); + return CMD_RET_FAILURE; + } + + return 0; +} + +static int do_cbcmos_update(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + const struct sysinfo_t *tab = get_table(); + struct udevice *dev; + u16 sum; + int ret; + + ret = prep_cbcmos(tab, argv[1], &dev); + if (ret < 0) + return CMD_RET_FAILURE; + sum = ret; + + ret = rtc_write16(dev, tab->cmos_checksum_location / 8, sum); + if (ret < 0) { + printf("Failed to read RTC device: %dE\n", ret); + return CMD_RET_FAILURE; + } + printf("Checksum %04x written\n", sum); + + return 0; +} + +U_BOOT_LONGHELP(cbcmos, + "check - check CMOS RAM\n" + "cbcmos update - Update CMOS-RAM checksum"; +); + +U_BOOT_CMD_WITH_SUBCMDS(cbcmos, "coreboot CMOS RAM", cbcmos_help_text, + U_BOOT_SUBCMD_MKENT(check, 2, 1, do_cbcmos_check), + U_BOOT_SUBCMD_MKENT(update, 2, 1, do_cbcmos_update)); diff --git a/doc/usage/cmd/cbcmos.rst b/doc/usage/cmd/cbcmos.rst new file mode 100644 index 00000000000..156521dd02b --- /dev/null +++ b/doc/usage/cmd/cbcmos.rst @@ -0,0 +1,42 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +cbcmos +====== + +Synopis +------- + +:: + + cbcmos check [<dev>] + cbcmos update [<dev>] + + +Description +----------- + +This checks or updates the CMOS-RAM checksum value against the CMOS-RAM +contents. It is used with coreboot, which provides information about where to +find the checksum and what part of the CMOS RAM it covers. + +If `<dev>` is provided then the named real-time clock (RTC) device is used. +Otherwise the default RTC is used. + +Example +------- + +This shows checking and updating a checksum across bytes 38 and 39 of the +CMOS RAM:: + + => rtc read 38 2 + 00000038: 71 00 q. + => cbc check + => rtc write 38 66 + => rtc read 38 2 + 00000038: 66 00 f. + => cbc check + Checksum 7100 error: calculated 6600 + => cbc update + Checksum 6600 written + => cbc check + => diff --git a/doc/usage/index.rst b/doc/usage/index.rst index c171c029b80..6069c3a7eb6 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -41,6 +41,7 @@ Shell commands cmd/bootz cmd/button cmd/cat + cmd/cbcmos cmd/cbsysinfo cmd/cedit cmd/cli diff --git a/test/cmd/coreboot.c b/test/cmd/coreboot.c index 1feca1e5075..b689035db9d 100644 --- a/test/cmd/coreboot.c +++ b/test/cmd/coreboot.c @@ -7,10 +7,16 @@ */
#include <command.h> +#include <dm.h> +#include <rtc.h> #include <test/cmd.h> #include <test/test.h> #include <test/ut.h>
+enum { + CSUM_LOC = 0x3f0 / 8, +}; + /** * test_cmd_cbsysinfo() - test the cbsysinfo command produces expected output * @@ -41,3 +47,39 @@ static int test_cmd_cbsysinfo(struct unit_test_state *uts) return 0; } CMD_TEST(test_cmd_cbsysinfo, UT_TESTF_CONSOLE_REC); + +/* test cbcmos command */ +static int test_cmd_cbcmos(struct unit_test_state *uts) +{ + u16 old_csum, new_csum; + struct udevice *dev; + + /* initially the checksum should be correct */ + ut_assertok(run_command("cbcmos check", 0)); + ut_assert_console_end(); + + /* make a change to the checksum */ + ut_assertok(uclass_first_device_err(UCLASS_RTC, &dev)); + ut_assertok(rtc_read16(dev, CSUM_LOC, &old_csum)); + ut_assertok(rtc_write16(dev, CSUM_LOC, old_csum + 1)); + + /* now the command should fail */ + ut_asserteq(1, run_command("cbcmos check", 0)); + ut_assert_nextline("Checksum %04x error: calculated %04x", + old_csum + 1, old_csum); + ut_assert_console_end(); + + /* now get it to fix the checksum */ + ut_assertok(run_command("cbcmos update", 0)); + ut_assert_nextline("Checksum %04x written", old_csum); + ut_assert_console_end(); + + /* check the RTC looks right */ + ut_assertok(rtc_read16(dev, CSUM_LOC, &new_csum)); + ut_asserteq(old_csum, new_csum); + ut_assert_console_end(); + + return 0; +} +CMD_TEST(test_cmd_cbcmos, UT_TESTF_CONSOLE_REC); +

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 ---
Changes in v2: - Avoid using common.h
boot/Makefile | 4 + boot/expo_build_cb.c | 245 ++++++++++++++++++++++++++++++++ cmd/cedit.c | 28 ++++ doc/board/coreboot/coreboot.rst | 6 + doc/develop/cedit.rst | 2 +- doc/usage/cmd/cbcmos.rst | 3 + doc/usage/cmd/cedit.rst | 76 ++++++++++ include/cedit.h | 1 + include/expo.h | 8 ++ test/cmd/coreboot.c | 34 +++++ 10 files changed, 406 insertions(+), 1 deletion(-) create mode 100644 boot/expo_build_cb.c
diff --git a/boot/Makefile b/boot/Makefile index a90ebea5a86..5808023b380 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -61,6 +61,10 @@ endif obj-$(CONFIG_$(SPL_TPL_)EXPO) += expo.o scene.o expo_build.o obj-$(CONFIG_$(SPL_TPL_)EXPO) += scene_menu.o scene_textline.o
+ifdef CONFIG_COREBOOT_SYSINFO +obj-$(CONFIG_$(SPL_TPL_)EXPO) += expo_build_cb.o +endif + obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE) += vbe.o obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE_REQUEST) += vbe_request.o obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE_SIMPLE) += vbe_simple.o diff --git a/boot/expo_build_cb.c b/boot/expo_build_cb.c new file mode 100644 index 00000000000..442ad760e79 --- /dev/null +++ b/boot/expo_build_cb.c @@ -0,0 +1,245 @@ +// 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; +} diff --git a/cmd/cedit.c b/cmd/cedit.c index 6352e6369d1..1640693a106 100644 --- a/cmd/cedit.c +++ b/cmd/cedit.c @@ -68,6 +68,28 @@ static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc, return 0; }
+#ifdef CONFIG_COREBOOT_SYSINFO +static int do_cedit_cb_load(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct expo *exp; + int ret; + + if (argc > 1) + return CMD_RET_USAGE; + + ret = cb_expo_build(&exp); + if (ret) { + printf("Failed to build expo: %dE\n", ret); + return CMD_RET_FAILURE; + } + + cur_exp = exp; + + return 0; +} +#endif /* CONFIG_COREBOOT_SYSINFO */ + static int do_cedit_write_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -272,6 +294,9 @@ static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc,
U_BOOT_LONGHELP(cedit, "load <interface> <dev[:part]> <filename> - load config editor\n" +#ifdef CONFIG_COREBOOT_SYSINFO + "cb_load - load coreboot CMOS editor\n" +#endif "cedit read_fdt <i/f> <dev[:part]> <filename> - read settings\n" "cedit write_fdt <i/f> <dev[:part]> <filename> - write settings\n" "cedit read_env [-v] - read settings from env vars\n" @@ -282,6 +307,9 @@ U_BOOT_LONGHELP(cedit,
U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text, U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load), +#ifdef CONFIG_COREBOOT_SYSINFO + U_BOOT_SUBCMD_MKENT(cb_load, 5, 1, do_cedit_cb_load), +#endif U_BOOT_SUBCMD_MKENT(read_fdt, 5, 1, do_cedit_read_fdt), U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt), U_BOOT_SUBCMD_MKENT(read_env, 2, 1, do_cedit_read_env), diff --git a/doc/board/coreboot/coreboot.rst b/doc/board/coreboot/coreboot.rst index 10a251c2b64..f2c6452b5b9 100644 --- a/doc/board/coreboot/coreboot.rst +++ b/doc/board/coreboot/coreboot.rst @@ -195,3 +195,9 @@ To update the `coreboot.rom` file which is used: #. Upload the file to Google drive
#. Send a patch to change the file ID used by wget in the CI yaml files. + +Editing CMOS RAM settings +------------------------- + +U-Boot supports creating a configuration editor to edit coreboot CMOS-RAM +settings. See :ref:`cedit_cb_load`. diff --git a/doc/develop/cedit.rst b/doc/develop/cedit.rst index 310be889240..1ac55ab1219 100644 --- a/doc/develop/cedit.rst +++ b/doc/develop/cedit.rst @@ -172,4 +172,4 @@ Cedit provides several options for persistent settings:
For now, reading and writing settings is not automatic. See the :doc:`../usage/cmd/cedit` for how to do this on the command line or in a -script. +script. For x86 devices, see :ref:`cedit_cb_load`. diff --git a/doc/usage/cmd/cbcmos.rst b/doc/usage/cmd/cbcmos.rst index 156521dd02b..9395cf1cbd7 100644 --- a/doc/usage/cmd/cbcmos.rst +++ b/doc/usage/cmd/cbcmos.rst @@ -40,3 +40,6 @@ CMOS RAM:: Checksum 6600 written => cbc check => + +See also :ref:`cedit_cb_load` which shows an example that includes the +configuration editor. diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst index 0f0cc26e74b..fbad0a9b147 100644 --- a/doc/usage/cmd/cedit.rst +++ b/doc/usage/cmd/cedit.rst @@ -15,6 +15,7 @@ Synopis cedit write_env [-v] cedit read_env [-v] cedit write_cmos [-v] [dev] + cedit cb_load
Description ----------- @@ -89,6 +90,13 @@ updated. Normally the first RTC device is used to hold the data. You can specify a different device by name using the `dev` parameter.
+.. _cedit_cb_load: + +cedit cb_load +~~~~~~~~~~~~~ + +This is supported only on x86 devices booted from coreboot. It creates a new +configuration editor which can be used to edit CMOS settings.
Example ------- @@ -155,3 +163,71 @@ Here is an example with the device specified::
=> cedit write_cmos rtc@43 => + +This example shows editing coreboot CMOS-RAM settings. A script could be used +to automate this:: + + => cbsysinfo + Coreboot table at 500, size 5c4, records 1d (dec 29), decoded to 000000007dce3f40, forwarded to 000000007ff9a000 + + CPU KHz : 0 + Serial I/O port: 00000000 + base : 00000000 + pointer : 000000007ff9a370 + type : 1 + base : 000003f8 + baud : 0d115200 + regwidth : 1 + input_hz : 0d1843200 + PCI addr : 00000010 + Mem ranges : 7 + id: type || base || size + 0: 10:table 0000000000000000 0000000000001000 + 1: 01:ram 0000000000001000 000000000009f000 + 2: 02:reserved 00000000000a0000 0000000000060000 + 3: 01:ram 0000000000100000 000000007fe6d000 + 4: 10:table 000000007ff6d000 0000000000093000 + 5: 02:reserved 00000000fec00000 0000000000001000 + 6: 02:reserved 00000000ff800000 0000000000800000 + option_table: 000000007ff9a018 + Bit Len Cfg ID Name + 0 180 r 0 reserved_memory + 180 1 e 4 boot_option 0:Fallback 1:Normal + 184 4 h 0 reboot_counter + 190 8 r 0 reserved_century + 1b8 8 r 0 reserved_ibm_ps2_century + 1c0 1 e 1 power_on_after_fail 0:Disable 1:Enable + 1c4 4 e 6 debug_level 5:Notice 6:Info 7:Debug 8:Spew + 1d0 80 r 0 vbnv + 3f0 10 h 0 check_sum + CMOS start : 1c0 + CMOS end : 1cf + CMOS csum loc: 3f0 + VBNV start : ffffffff + VBNV size : ffffffff + ... + Unimpl. : 10 37 40 + +Check that the CMOS RAM checksum is correct, then create a configuration editor +and load the settings from CMOS RAM:: + + => cbcmos check + => cedit cb + => cedit read_cmos + +Now run the cedit. In this case the user selected 'save' so `cedit run` returns +success:: + + => if cedit run; then cedit write_cmos -v; fi + Write 2 bytes from offset 30 to 38 + => echo $? + 0 + +Update the checksum in CMOS RAM:: + + => cbcmos check + Checksum 6100 error: calculated 7100 + => cbcmos update + Checksum 7100 written + => cbcmos check + => diff --git a/include/cedit.h b/include/cedit.h index f9a4a6d9e8e..5b1900b5082 100644 --- a/include/cedit.h +++ b/include/cedit.h @@ -8,6 +8,7 @@ #define __CEDIT_H
#include <dm/ofnode_decl.h> +#include <linux/types.h>
struct abuf; struct expo; diff --git a/include/expo.h b/include/expo.h index 8e834b50e4f..620447acdf1 100644 --- a/include/expo.h +++ b/include/expo.h @@ -762,4 +762,12 @@ int expo_apply_theme(struct expo *exp, ofnode node); */ int expo_build(ofnode root, struct expo **expp);
+/** + * cb_expo_build() - Build an expo for coreboot CMOS RAM + * + * @expp: Returns the expo created + * Return: 0 if OK, -ve on error + */ +int cb_expo_build(struct expo **expp); + #endif /*__EXPO_H */ diff --git a/test/cmd/coreboot.c b/test/cmd/coreboot.c index b689035db9d..c34fcc49717 100644 --- a/test/cmd/coreboot.c +++ b/test/cmd/coreboot.c @@ -6,12 +6,16 @@ * Written by Simon Glass sjg@chromium.org */
+#include <cedit.h> #include <command.h> #include <dm.h> +#include <expo.h> #include <rtc.h> +#include <test/cedit-test.h> #include <test/cmd.h> #include <test/test.h> #include <test/ut.h> +#include "../../boot/scene_internal.h"
enum { CSUM_LOC = 0x3f0 / 8, @@ -83,3 +87,33 @@ static int test_cmd_cbcmos(struct unit_test_state *uts) } CMD_TEST(test_cmd_cbcmos, UT_TESTF_CONSOLE_REC);
+/* test 'cedit cb_load' command */ +static int test_cmd_cedit_cb_load(struct unit_test_state *uts) +{ + struct scene_obj_menu *menu; + struct video_priv *vid_priv; + struct scene_obj_txt *txt; + struct scene *scn; + struct expo *exp; + int scn_id; + + ut_assertok(run_command("cedit cb_load", 0)); + ut_assertok(run_command("cedit read_cmos", 0)); + ut_assert_console_end(); + + exp = cur_exp; + scn_id = cedit_prepare(exp, &vid_priv, &scn); + ut_assert(scn_id > 0); + ut_assertnonnull(scn); + + /* just do a very basic test that the first menu is present */ + menu = scene_obj_find(scn, scn->highlight_id, SCENEOBJT_NONE); + ut_assertnonnull(menu); + + txt = scene_obj_find(scn, menu->title_id, SCENEOBJT_NONE); + ut_assertnonnull(txt); + ut_asserteq_str("Boot option", expo_get_str(exp, txt->str_id)); + + return 0; +} +CMD_TEST(test_cmd_cedit_cb_load, UT_TESTF_CONSOLE_REC);

The real-time clock is needed for most X86 systems and it is useful to be able to read from it. Enable the rtc command by default.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Rebase to -next
cmd/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/cmd/Kconfig b/cmd/Kconfig index 2386f4cf3bc..8423277c542 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2193,6 +2193,7 @@ config CMD_DATE config CMD_RTC bool "rtc" depends on DM_RTC + default y if X86 help Enable the 'rtc' command for low-level access to RTC devices.

Hi Simon,
On Thu, Jan 4, 2024 at 11:11 PM Simon Glass sjg@chromium.org wrote:
U-Boot provides support for editing settings with an 'expo', as well as reading and writing settings to CMOS RAM.
This series integrates expo functionality with coreboot, using the sysinfo table to get a list of settings, creating an expo with them and allowing them to be edited.
A new CI test provides coverage for some coreboot-related commands. For this to work, a number of minor tweaks are made to existing tests, so that they pass on coreboot (x86) or at least are skipped when they cannot pass. Likely most of these fixes will apply to other boards too.
It includes several other fixes and improvements:
- new -m flag for 'bootflow scan' so it can display a menu automatically
- Fix for video-scrolling crash with Truetype
- menu items can now have individual integer values
- menu items are lined up according to the width of all menu labels
Changes in v2:
- Avoid using common.h
- Avoid using common.h
- Rebase to -next
Simon Glass (19): video: Add a dark-grey console colour video: Avoid starting a new line to close to the bottom expo: Place menu items to the right of all labels expo: Set the initial next_id to 1 expo: Use standard numbering for save and discard expo: Allow menu items to have values expo: Add a little more cedit CMOS logging expo: Support menu-item values in cedit expo: Drop unneceesary calls to expo_str() expo: Drop scene_title_set() expo: Add forward declaration for udevice to cedit x86: coreboot: Enable unit tests x86: CI: Update coreboot x86: coreboot: Add a test for cbsysinfo command x86: coreboot: Show the option table x86: coreboot: Enable support for the configuration editor x86: coreboot: Add a command to check and update CMOS RAM x86: coreboot: Allow building an expo for editing CMOS config x86: Enable RTC command by default
.azure-pipelines.yml | 2 +- .gitlab-ci.yml | 2 +- arch/sandbox/dts/cedit.dtsi | 3 + arch/x86/dts/coreboot.dts | 7 + boot/Makefile | 4 + boot/cedit.c | 191 +++++++++++++++-------- boot/expo.c | 3 + boot/expo_build.c | 36 ++--- boot/expo_build_cb.c | 245 ++++++++++++++++++++++++++++++ boot/scene.c | 61 ++++++-- boot/scene_internal.h | 30 +++- boot/scene_menu.c | 26 +++- boot/scene_textline.c | 3 +- cmd/Kconfig | 12 ++ cmd/cedit.c | 28 ++++ cmd/x86/Makefile | 1 + cmd/x86/cbcmos.c | 139 +++++++++++++++++ cmd/x86/cbsysinfo.c | 73 ++++++++- configs/coreboot64_defconfig | 2 + configs/coreboot_defconfig | 6 + doc/board/coreboot/coreboot.rst | 6 + doc/develop/cedit.rst | 9 +- doc/develop/expo.rst | 26 +++- doc/usage/cmd/cbcmos.rst | 45 ++++++ doc/usage/cmd/cbsysinfo.rst | 99 ++++++++++++ doc/usage/cmd/cedit.rst | 91 ++++++++++- doc/usage/index.rst | 1 + drivers/video/vidconsole-uclass.c | 4 +- drivers/video/video-uclass.c | 3 + include/cedit.h | 2 + include/expo.h | 51 +++++-- include/test/cedit-test.h | 30 ++-- include/video.h | 4 +- include/video_console.h | 8 + test/boot/cedit.c | 22 ++- test/boot/expo.c | 26 +++- test/boot/files/expo_ids.h | 3 +- test/boot/files/expo_layout.dts | 5 +- test/cmd/Makefile | 1 + test/cmd/coreboot.c | 119 +++++++++++++++ tools/expo.py | 33 +++- 41 files changed, 1309 insertions(+), 153 deletions(-) create mode 100644 boot/expo_build_cb.c create mode 100644 cmd/x86/cbcmos.c create mode 100644 doc/usage/cmd/cbcmos.rst create mode 100644 test/cmd/coreboot.c
I have applied all patches in the queue to u-boot-x86/master. When testing coreboot with the graphics console, I found a regression. See below:
With u-boot/master, I got: https://ibb.co/swt8ZQ5
With u-boot-x86/master, I got: https://ibb.co/5MZ76mC
As you can see, the text is crooked and misaligned. I didn't have time to locate which commit(s) is the culprit.
Would you please take a look?
Regards, Bin

Hi Bin,
On Thu, Jan 4, 2024 at 4:02 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Thu, Jan 4, 2024 at 11:11 PM Simon Glass sjg@chromium.org wrote:
U-Boot provides support for editing settings with an 'expo', as well as reading and writing settings to CMOS RAM.
This series integrates expo functionality with coreboot, using the sysinfo table to get a list of settings, creating an expo with them and allowing them to be edited.
A new CI test provides coverage for some coreboot-related commands. For this to work, a number of minor tweaks are made to existing tests, so that they pass on coreboot (x86) or at least are skipped when they cannot pass. Likely most of these fixes will apply to other boards too.
It includes several other fixes and improvements:
- new -m flag for 'bootflow scan' so it can display a menu automatically
- Fix for video-scrolling crash with Truetype
- menu items can now have individual integer values
- menu items are lined up according to the width of all menu labels
Changes in v2:
- Avoid using common.h
- Avoid using common.h
- Rebase to -next
Simon Glass (19): video: Add a dark-grey console colour video: Avoid starting a new line to close to the bottom expo: Place menu items to the right of all labels expo: Set the initial next_id to 1 expo: Use standard numbering for save and discard expo: Allow menu items to have values expo: Add a little more cedit CMOS logging expo: Support menu-item values in cedit expo: Drop unneceesary calls to expo_str() expo: Drop scene_title_set() expo: Add forward declaration for udevice to cedit x86: coreboot: Enable unit tests x86: CI: Update coreboot x86: coreboot: Add a test for cbsysinfo command x86: coreboot: Show the option table x86: coreboot: Enable support for the configuration editor x86: coreboot: Add a command to check and update CMOS RAM x86: coreboot: Allow building an expo for editing CMOS config x86: Enable RTC command by default
.azure-pipelines.yml | 2 +- .gitlab-ci.yml | 2 +- arch/sandbox/dts/cedit.dtsi | 3 + arch/x86/dts/coreboot.dts | 7 + boot/Makefile | 4 + boot/cedit.c | 191 +++++++++++++++-------- boot/expo.c | 3 + boot/expo_build.c | 36 ++--- boot/expo_build_cb.c | 245 ++++++++++++++++++++++++++++++ boot/scene.c | 61 ++++++-- boot/scene_internal.h | 30 +++- boot/scene_menu.c | 26 +++- boot/scene_textline.c | 3 +- cmd/Kconfig | 12 ++ cmd/cedit.c | 28 ++++ cmd/x86/Makefile | 1 + cmd/x86/cbcmos.c | 139 +++++++++++++++++ cmd/x86/cbsysinfo.c | 73 ++++++++- configs/coreboot64_defconfig | 2 + configs/coreboot_defconfig | 6 + doc/board/coreboot/coreboot.rst | 6 + doc/develop/cedit.rst | 9 +- doc/develop/expo.rst | 26 +++- doc/usage/cmd/cbcmos.rst | 45 ++++++ doc/usage/cmd/cbsysinfo.rst | 99 ++++++++++++ doc/usage/cmd/cedit.rst | 91 ++++++++++- doc/usage/index.rst | 1 + drivers/video/vidconsole-uclass.c | 4 +- drivers/video/video-uclass.c | 3 + include/cedit.h | 2 + include/expo.h | 51 +++++-- include/test/cedit-test.h | 30 ++-- include/video.h | 4 +- include/video_console.h | 8 + test/boot/cedit.c | 22 ++- test/boot/expo.c | 26 +++- test/boot/files/expo_ids.h | 3 +- test/boot/files/expo_layout.dts | 5 +- test/cmd/Makefile | 1 + test/cmd/coreboot.c | 119 +++++++++++++++ tools/expo.py | 33 +++- 41 files changed, 1309 insertions(+), 153 deletions(-) create mode 100644 boot/expo_build_cb.c create mode 100644 cmd/x86/cbcmos.c create mode 100644 doc/usage/cmd/cbcmos.rst create mode 100644 test/cmd/coreboot.c
I have applied all patches in the queue to u-boot-x86/master. When testing coreboot with the graphics console, I found a regression. See below:
With u-boot/master, I got: https://ibb.co/swt8ZQ5
With u-boot-x86/master, I got: https://ibb.co/5MZ76mC
As you can see, the text is crooked and misaligned. I didn't have time to locate which commit(s) is the culprit.
Would you please take a look?
Actually this is WAI since it now uses a proportional font instead of fixed width!
Regards, Simon

Hi Simon,
On Sat, Jan 6, 2024 at 4:12 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Thu, Jan 4, 2024 at 4:02 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Thu, Jan 4, 2024 at 11:11 PM Simon Glass sjg@chromium.org wrote:
U-Boot provides support for editing settings with an 'expo', as well as reading and writing settings to CMOS RAM.
This series integrates expo functionality with coreboot, using the sysinfo table to get a list of settings, creating an expo with them and allowing them to be edited.
A new CI test provides coverage for some coreboot-related commands. For this to work, a number of minor tweaks are made to existing tests, so that they pass on coreboot (x86) or at least are skipped when they cannot pass. Likely most of these fixes will apply to other boards too.
It includes several other fixes and improvements:
- new -m flag for 'bootflow scan' so it can display a menu automatically
- Fix for video-scrolling crash with Truetype
- menu items can now have individual integer values
- menu items are lined up according to the width of all menu labels
Changes in v2:
- Avoid using common.h
- Avoid using common.h
- Rebase to -next
Simon Glass (19): video: Add a dark-grey console colour video: Avoid starting a new line to close to the bottom expo: Place menu items to the right of all labels expo: Set the initial next_id to 1 expo: Use standard numbering for save and discard expo: Allow menu items to have values expo: Add a little more cedit CMOS logging expo: Support menu-item values in cedit expo: Drop unneceesary calls to expo_str() expo: Drop scene_title_set() expo: Add forward declaration for udevice to cedit x86: coreboot: Enable unit tests x86: CI: Update coreboot x86: coreboot: Add a test for cbsysinfo command x86: coreboot: Show the option table x86: coreboot: Enable support for the configuration editor x86: coreboot: Add a command to check and update CMOS RAM x86: coreboot: Allow building an expo for editing CMOS config x86: Enable RTC command by default
.azure-pipelines.yml | 2 +- .gitlab-ci.yml | 2 +- arch/sandbox/dts/cedit.dtsi | 3 + arch/x86/dts/coreboot.dts | 7 + boot/Makefile | 4 + boot/cedit.c | 191 +++++++++++++++-------- boot/expo.c | 3 + boot/expo_build.c | 36 ++--- boot/expo_build_cb.c | 245 ++++++++++++++++++++++++++++++ boot/scene.c | 61 ++++++-- boot/scene_internal.h | 30 +++- boot/scene_menu.c | 26 +++- boot/scene_textline.c | 3 +- cmd/Kconfig | 12 ++ cmd/cedit.c | 28 ++++ cmd/x86/Makefile | 1 + cmd/x86/cbcmos.c | 139 +++++++++++++++++ cmd/x86/cbsysinfo.c | 73 ++++++++- configs/coreboot64_defconfig | 2 + configs/coreboot_defconfig | 6 + doc/board/coreboot/coreboot.rst | 6 + doc/develop/cedit.rst | 9 +- doc/develop/expo.rst | 26 +++- doc/usage/cmd/cbcmos.rst | 45 ++++++ doc/usage/cmd/cbsysinfo.rst | 99 ++++++++++++ doc/usage/cmd/cedit.rst | 91 ++++++++++- doc/usage/index.rst | 1 + drivers/video/vidconsole-uclass.c | 4 +- drivers/video/video-uclass.c | 3 + include/cedit.h | 2 + include/expo.h | 51 +++++-- include/test/cedit-test.h | 30 ++-- include/video.h | 4 +- include/video_console.h | 8 + test/boot/cedit.c | 22 ++- test/boot/expo.c | 26 +++- test/boot/files/expo_ids.h | 3 +- test/boot/files/expo_layout.dts | 5 +- test/cmd/Makefile | 1 + test/cmd/coreboot.c | 119 +++++++++++++++ tools/expo.py | 33 +++- 41 files changed, 1309 insertions(+), 153 deletions(-) create mode 100644 boot/expo_build_cb.c create mode 100644 cmd/x86/cbcmos.c create mode 100644 doc/usage/cmd/cbcmos.rst create mode 100644 test/cmd/coreboot.c
I have applied all patches in the queue to u-boot-x86/master. When testing coreboot with the graphics console, I found a regression. See below:
With u-boot/master, I got: https://ibb.co/swt8ZQ5
With u-boot-x86/master, I got: https://ibb.co/5MZ76mC
As you can see, the text is crooked and misaligned. I didn't have time to locate which commit(s) is the culprit.
Would you please take a look?
Actually this is WAI since it now uses a proportional font instead of fixed width!
Since we are talking about the graphics console, and for consoles the fonts used are usually fixed width ones. What it is now looks really bad. Where do yo need proportional font?
Can we switch fonts dynamically?
Regards, Bin

Hi Bin,
On Fri, Jan 5, 2024 at 4:06 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Jan 6, 2024 at 4:12 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Thu, Jan 4, 2024 at 4:02 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Thu, Jan 4, 2024 at 11:11 PM Simon Glass sjg@chromium.org wrote:
U-Boot provides support for editing settings with an 'expo', as well as reading and writing settings to CMOS RAM.
This series integrates expo functionality with coreboot, using the sysinfo table to get a list of settings, creating an expo with them and allowing them to be edited.
A new CI test provides coverage for some coreboot-related commands. For this to work, a number of minor tweaks are made to existing tests, so that they pass on coreboot (x86) or at least are skipped when they cannot pass. Likely most of these fixes will apply to other boards too.
It includes several other fixes and improvements:
- new -m flag for 'bootflow scan' so it can display a menu automatically
- Fix for video-scrolling crash with Truetype
- menu items can now have individual integer values
- menu items are lined up according to the width of all menu labels
Changes in v2:
- Avoid using common.h
- Avoid using common.h
- Rebase to -next
Simon Glass (19): video: Add a dark-grey console colour video: Avoid starting a new line to close to the bottom expo: Place menu items to the right of all labels expo: Set the initial next_id to 1 expo: Use standard numbering for save and discard expo: Allow menu items to have values expo: Add a little more cedit CMOS logging expo: Support menu-item values in cedit expo: Drop unneceesary calls to expo_str() expo: Drop scene_title_set() expo: Add forward declaration for udevice to cedit x86: coreboot: Enable unit tests x86: CI: Update coreboot x86: coreboot: Add a test for cbsysinfo command x86: coreboot: Show the option table x86: coreboot: Enable support for the configuration editor x86: coreboot: Add a command to check and update CMOS RAM x86: coreboot: Allow building an expo for editing CMOS config x86: Enable RTC command by default
.azure-pipelines.yml | 2 +- .gitlab-ci.yml | 2 +- arch/sandbox/dts/cedit.dtsi | 3 + arch/x86/dts/coreboot.dts | 7 + boot/Makefile | 4 + boot/cedit.c | 191 +++++++++++++++-------- boot/expo.c | 3 + boot/expo_build.c | 36 ++--- boot/expo_build_cb.c | 245 ++++++++++++++++++++++++++++++ boot/scene.c | 61 ++++++-- boot/scene_internal.h | 30 +++- boot/scene_menu.c | 26 +++- boot/scene_textline.c | 3 +- cmd/Kconfig | 12 ++ cmd/cedit.c | 28 ++++ cmd/x86/Makefile | 1 + cmd/x86/cbcmos.c | 139 +++++++++++++++++ cmd/x86/cbsysinfo.c | 73 ++++++++- configs/coreboot64_defconfig | 2 + configs/coreboot_defconfig | 6 + doc/board/coreboot/coreboot.rst | 6 + doc/develop/cedit.rst | 9 +- doc/develop/expo.rst | 26 +++- doc/usage/cmd/cbcmos.rst | 45 ++++++ doc/usage/cmd/cbsysinfo.rst | 99 ++++++++++++ doc/usage/cmd/cedit.rst | 91 ++++++++++- doc/usage/index.rst | 1 + drivers/video/vidconsole-uclass.c | 4 +- drivers/video/video-uclass.c | 3 + include/cedit.h | 2 + include/expo.h | 51 +++++-- include/test/cedit-test.h | 30 ++-- include/video.h | 4 +- include/video_console.h | 8 + test/boot/cedit.c | 22 ++- test/boot/expo.c | 26 +++- test/boot/files/expo_ids.h | 3 +- test/boot/files/expo_layout.dts | 5 +- test/cmd/Makefile | 1 + test/cmd/coreboot.c | 119 +++++++++++++++ tools/expo.py | 33 +++- 41 files changed, 1309 insertions(+), 153 deletions(-) create mode 100644 boot/expo_build_cb.c create mode 100644 cmd/x86/cbcmos.c create mode 100644 doc/usage/cmd/cbcmos.rst create mode 100644 test/cmd/coreboot.c
I have applied all patches in the queue to u-boot-x86/master. When testing coreboot with the graphics console, I found a regression. See below:
With u-boot/master, I got: https://ibb.co/swt8ZQ5
With u-boot-x86/master, I got: https://ibb.co/5MZ76mC
As you can see, the text is crooked and misaligned. I didn't have time to locate which commit(s) is the culprit.
Would you please take a look?
Actually this is WAI since it now uses a proportional font instead of fixed width!
Since we are talking about the graphics console, and for consoles the fonts used are usually fixed width ones. What it is now looks really bad. Where do yo need proportional font?
Can we switch fonts dynamically?
Yes, it is possible, if multiple fonts are enabled; or we could just use a monospace one by default.
Regards, Simon

Hi Simon,
On Sat, Jan 6, 2024 at 9:38 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Fri, Jan 5, 2024 at 4:06 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Jan 6, 2024 at 4:12 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Thu, Jan 4, 2024 at 4:02 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Thu, Jan 4, 2024 at 11:11 PM Simon Glass sjg@chromium.org wrote:
U-Boot provides support for editing settings with an 'expo', as well as reading and writing settings to CMOS RAM.
This series integrates expo functionality with coreboot, using the sysinfo table to get a list of settings, creating an expo with them and allowing them to be edited.
A new CI test provides coverage for some coreboot-related commands. For this to work, a number of minor tweaks are made to existing tests, so that they pass on coreboot (x86) or at least are skipped when they cannot pass. Likely most of these fixes will apply to other boards too.
It includes several other fixes and improvements:
- new -m flag for 'bootflow scan' so it can display a menu automatically
- Fix for video-scrolling crash with Truetype
- menu items can now have individual integer values
- menu items are lined up according to the width of all menu labels
Changes in v2:
- Avoid using common.h
- Avoid using common.h
- Rebase to -next
Simon Glass (19): video: Add a dark-grey console colour video: Avoid starting a new line to close to the bottom expo: Place menu items to the right of all labels expo: Set the initial next_id to 1 expo: Use standard numbering for save and discard expo: Allow menu items to have values expo: Add a little more cedit CMOS logging expo: Support menu-item values in cedit expo: Drop unneceesary calls to expo_str() expo: Drop scene_title_set() expo: Add forward declaration for udevice to cedit x86: coreboot: Enable unit tests x86: CI: Update coreboot x86: coreboot: Add a test for cbsysinfo command x86: coreboot: Show the option table x86: coreboot: Enable support for the configuration editor x86: coreboot: Add a command to check and update CMOS RAM x86: coreboot: Allow building an expo for editing CMOS config x86: Enable RTC command by default
.azure-pipelines.yml | 2 +- .gitlab-ci.yml | 2 +- arch/sandbox/dts/cedit.dtsi | 3 + arch/x86/dts/coreboot.dts | 7 + boot/Makefile | 4 + boot/cedit.c | 191 +++++++++++++++-------- boot/expo.c | 3 + boot/expo_build.c | 36 ++--- boot/expo_build_cb.c | 245 ++++++++++++++++++++++++++++++ boot/scene.c | 61 ++++++-- boot/scene_internal.h | 30 +++- boot/scene_menu.c | 26 +++- boot/scene_textline.c | 3 +- cmd/Kconfig | 12 ++ cmd/cedit.c | 28 ++++ cmd/x86/Makefile | 1 + cmd/x86/cbcmos.c | 139 +++++++++++++++++ cmd/x86/cbsysinfo.c | 73 ++++++++- configs/coreboot64_defconfig | 2 + configs/coreboot_defconfig | 6 + doc/board/coreboot/coreboot.rst | 6 + doc/develop/cedit.rst | 9 +- doc/develop/expo.rst | 26 +++- doc/usage/cmd/cbcmos.rst | 45 ++++++ doc/usage/cmd/cbsysinfo.rst | 99 ++++++++++++ doc/usage/cmd/cedit.rst | 91 ++++++++++- doc/usage/index.rst | 1 + drivers/video/vidconsole-uclass.c | 4 +- drivers/video/video-uclass.c | 3 + include/cedit.h | 2 + include/expo.h | 51 +++++-- include/test/cedit-test.h | 30 ++-- include/video.h | 4 +- include/video_console.h | 8 + test/boot/cedit.c | 22 ++- test/boot/expo.c | 26 +++- test/boot/files/expo_ids.h | 3 +- test/boot/files/expo_layout.dts | 5 +- test/cmd/Makefile | 1 + test/cmd/coreboot.c | 119 +++++++++++++++ tools/expo.py | 33 +++- 41 files changed, 1309 insertions(+), 153 deletions(-) create mode 100644 boot/expo_build_cb.c create mode 100644 cmd/x86/cbcmos.c create mode 100644 doc/usage/cmd/cbcmos.rst create mode 100644 test/cmd/coreboot.c
I have applied all patches in the queue to u-boot-x86/master. When testing coreboot with the graphics console, I found a regression. See below:
With u-boot/master, I got: https://ibb.co/swt8ZQ5
With u-boot-x86/master, I got: https://ibb.co/5MZ76mC
As you can see, the text is crooked and misaligned. I didn't have time to locate which commit(s) is the culprit.
Would you please take a look?
Actually this is WAI since it now uses a proportional font instead of fixed width!
Since we are talking about the graphics console, and for consoles the fonts used are usually fixed width ones. What it is now looks really bad. Where do yo need proportional font?
Can we switch fonts dynamically?
Yes, it is possible, if multiple fonts are enabled; or we could just use a monospace one by default.
Would you please prepare some new patches, to keep the default console font as fixed width and select proportional font one some other place you need that?
Regards, Bin

On Thu, Jan 04, 2024 at 08:11:33AM -0700, Simon Glass wrote:
U-Boot provides support for editing settings with an 'expo', as well as reading and writing settings to CMOS RAM.
This series integrates expo functionality with coreboot, using the sysinfo table to get a list of settings, creating an expo with them and allowing them to be edited.
A new CI test provides coverage for some coreboot-related commands. For this to work, a number of minor tweaks are made to existing tests, so that they pass on coreboot (x86) or at least are skipped when they cannot pass. Likely most of these fixes will apply to other boards too.
It includes several other fixes and improvements:
- new -m flag for 'bootflow scan' so it can display a menu automatically
- Fix for video-scrolling crash with Truetype
- menu items can now have individual integer values
- menu items are lined up according to the width of all menu labels
This needs to be rebased on top of master where I suspect the biggest problem is that we need to reconfigure coreboot that we build now? All of the new tests fail: https://source.denx.de/u-boot/u-boot/-/jobs/814728 and we're just building a standard defconfig for coreboot now.
participants (3)
-
Bin Meng
-
Simon Glass
-
Tom Rini