UBOOT_CUSTOMIZE_CONFIG := \
--disable TOOLS_KWBIMAGE \
--disable TOOLS_LIBCRYPTO \
- --disable TOOLS_MKEFICAPSULE
+ --disable TOOLS_MKEFICAPSULE \
+ --enable SERIAL_RX_BUFFER
ifdef CONFIG_TARGET_mediatek
UBOOT_MAKE_FLAGS += $(UBOOT_IMAGE:.fip=.bin)
--- /dev/null
+From 72b4ba8417d33516b8489bac3c90dbbbf781a3d2 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 29 Oct 2024 17:47:10 +0800
+Subject: [PATCH 1/3] menu: fix the logic checking whether ESC key is pressed
+
+It's observed that the bootmenu on a serial console sometimes
+incorrectly quitted with superfluous characters filled to command
+line input:
+
+> *** U-Boot Boot Menu ***
+>
+> 1. Startup system (Default)
+> 2. Upgrade firmware
+> 3. Upgrade ATF BL2
+> 4. Upgrade ATF FIP
+> 5. Load image
+> 0. U-Boot console
+>
+>
+> Press UP/DOWN to move, ENTER to select, ESC to quit
+>MT7988> [B
+
+Analysis shows it was caused by the wrong logic of bootmenu_loop:
+
+At first the bootmenu_loop received the first ESC char correctly.
+
+However, during the second call to bootmenu_loop, there's no data
+in the UART Rx FIFO. Due to the low baudrate, the second char of
+the down array key sequence hasn't be fully received.
+
+But bootmenu_loop just did a mdelay(10), and then treated it as a
+single ESC key press event. It didn't even try tstc() again after
+the 10ms timeout.
+
+This patch fixes this issue by letting bootmenu_loop check tstc()
+twice.
+
+Tested-By: E Shattow <lucent@gmail.com>
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ common/menu.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/common/menu.c
++++ b/common/menu.c
+@@ -525,14 +525,15 @@ enum bootmenu_key bootmenu_loop(struct b
+ struct cli_ch_state *cch)
+ {
+ enum bootmenu_key key;
+- int c;
++ int c, errchar = 0;
+
+ c = cli_ch_process(cch, 0);
+ if (!c) {
+ while (!c && !tstc()) {
+ schedule();
+ mdelay(10);
+- c = cli_ch_process(cch, -ETIMEDOUT);
++ c = cli_ch_process(cch, errchar);
++ errchar = -ETIMEDOUT;
+ }
+ if (!c) {
+ c = getchar();
--- /dev/null
+From f1cbdd3330f0055dfbff0ef7d86276c4cc3cff2a Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 29 Oct 2024 17:47:16 +0800
+Subject: [PATCH 2/3] menu: add support to check if menu needs to be reprinted
+
+This patch adds a new callback named need_reprint for menu.
+The need_reprint will be called before printing the menu. If the
+callback exists and returns FALSE, menu printing will be canceled.
+
+This is very useful if the menu was not changed. It can save time
+for serial-based menu to handle more input data.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ boot/pxe_utils.c | 2 +-
+ cmd/bootmenu.c | 2 +-
+ cmd/eficonfig.c | 2 +-
+ common/menu.c | 11 +++++++++++
+ include/menu.h | 1 +
+ 5 files changed, 15 insertions(+), 3 deletions(-)
+
+--- a/boot/pxe_utils.c
++++ b/boot/pxe_utils.c
+@@ -1449,7 +1449,7 @@ static struct menu *pxe_menu_to_menu(str
+ * Create a menu and add items for all the labels.
+ */
+ m = menu_create(cfg->title, DIV_ROUND_UP(cfg->timeout, 10),
+- cfg->prompt, NULL, label_print, NULL, NULL);
++ cfg->prompt, NULL, label_print, NULL, NULL, NULL);
+ if (!m)
+ return NULL;
+
+--- a/cmd/bootmenu.c
++++ b/cmd/bootmenu.c
+@@ -506,7 +506,7 @@ static enum bootmenu_ret bootmenu_show(i
+
+ menu = menu_create(NULL, bootmenu->delay, 1, menu_display_statusline,
+ bootmenu_print_entry, bootmenu_choice_entry,
+- bootmenu);
++ NULL, bootmenu);
+ if (!menu) {
+ bootmenu_destroy(bootmenu);
+ return BOOTMENU_RET_FAIL;
+--- a/cmd/eficonfig.c
++++ b/cmd/eficonfig.c
+@@ -443,7 +443,7 @@ efi_status_t eficonfig_process_common(st
+ efi_menu->menu_desc = menu_desc;
+
+ menu = menu_create(NULL, 0, 1, display_statusline, item_data_print,
+- item_choice, efi_menu);
++ item_choice, NULL, efi_menu);
+ if (!menu)
+ return EFI_INVALID_PARAMETER;
+
+--- a/common/menu.c
++++ b/common/menu.c
+@@ -43,6 +43,7 @@ struct menu {
+ void (*display_statusline)(struct menu *);
+ void (*item_data_print)(void *);
+ char *(*item_choice)(void *);
++ bool (*need_reprint)(void *);
+ void *item_choice_data;
+ struct list_head items;
+ int item_cnt;
+@@ -117,6 +118,11 @@ static inline void *menu_item_destroy(st
+ */
+ static inline void menu_display(struct menu *m)
+ {
++ if (m->need_reprint) {
++ if (!m->need_reprint(m->item_choice_data))
++ return;
++ }
++
+ if (m->title) {
+ puts(m->title);
+ putc('\n');
+@@ -362,6 +368,9 @@ int menu_item_add(struct menu *m, char *
+ * item. Returns a key string corresponding to the chosen item or NULL if
+ * no item has been selected.
+ *
++ * need_reprint - If not NULL, will be called before printing the menu.
++ * Returning FALSE means the menu does not need reprint.
++ *
+ * item_choice_data - Will be passed as the argument to the item_choice function
+ *
+ * Returns a pointer to the menu if successful, or NULL if there is
+@@ -371,6 +380,7 @@ struct menu *menu_create(char *title, in
+ void (*display_statusline)(struct menu *),
+ void (*item_data_print)(void *),
+ char *(*item_choice)(void *),
++ bool (*need_reprint)(void *),
+ void *item_choice_data)
+ {
+ struct menu *m;
+@@ -386,6 +396,7 @@ struct menu *menu_create(char *title, in
+ m->display_statusline = display_statusline;
+ m->item_data_print = item_data_print;
+ m->item_choice = item_choice;
++ m->need_reprint = need_reprint;
+ m->item_choice_data = item_choice_data;
+ m->item_cnt = 0;
+
+--- a/include/menu.h
++++ b/include/menu.h
+@@ -13,6 +13,7 @@ struct menu *menu_create(char *title, in
+ void (*display_statusline)(struct menu *),
+ void (*item_data_print)(void *),
+ char *(*item_choice)(void *),
++ bool (*need_reprint)(void *),
+ void *item_choice_data);
+ int menu_default_set(struct menu *m, char *item_key);
+ int menu_get_choice(struct menu *m, void **choice);
--- /dev/null
+From 702752cfae954648d6133bdff19283343b3339ef Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Tue, 29 Oct 2024 17:47:22 +0800
+Subject: [PATCH 3/3] bootmenu: add reprint check
+
+Record the last active menu item and check if it equals to the
+current selected item before reprint.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ cmd/bootmenu.c | 16 +++++++++++++++-
+ include/menu.h | 1 +
+ 2 files changed, 16 insertions(+), 1 deletion(-)
+
+--- a/cmd/bootmenu.c
++++ b/cmd/bootmenu.c
+@@ -103,11 +103,13 @@ static char *bootmenu_choice_entry(void
+
+ switch (key) {
+ case BKEY_UP:
++ menu->last_active = menu->active;
+ if (menu->active > 0)
+ --menu->active;
+ /* no menu key selected, regenerate menu */
+ return NULL;
+ case BKEY_DOWN:
++ menu->last_active = menu->active;
+ if (menu->active < menu->count - 1)
+ ++menu->active;
+ /* no menu key selected, regenerate menu */
+@@ -133,6 +135,17 @@ static char *bootmenu_choice_entry(void
+ return NULL;
+ }
+
++static bool bootmenu_need_reprint(void *data)
++{
++ struct bootmenu_data *menu = data;
++ bool need_reprint;
++
++ need_reprint = menu->last_active != menu->active;
++ menu->last_active = menu->active;
++
++ return need_reprint;
++}
++
+ static void bootmenu_destroy(struct bootmenu_data *menu)
+ {
+ struct bootmenu_entry *iter = menu->first;
+@@ -332,6 +345,7 @@ static struct bootmenu_data *bootmenu_cr
+
+ menu->delay = delay;
+ menu->active = 0;
++ menu->last_active = -1;
+ menu->first = NULL;
+
+ default_str = env_get("bootmenu_default");
+@@ -506,7 +520,7 @@ static enum bootmenu_ret bootmenu_show(i
+
+ menu = menu_create(NULL, bootmenu->delay, 1, menu_display_statusline,
+ bootmenu_print_entry, bootmenu_choice_entry,
+- NULL, bootmenu);
++ bootmenu_need_reprint, bootmenu);
+ if (!menu) {
+ bootmenu_destroy(bootmenu);
+ return BOOTMENU_RET_FAIL;
+--- a/include/menu.h
++++ b/include/menu.h
+@@ -40,6 +40,7 @@ int menu_show(int bootdelay);
+ struct bootmenu_data {
+ int delay; /* delay for autoboot */
+ int active; /* active menu entry */
++ int last_active; /* last active menu entry */
+ int count; /* total count of menu entries */
+ struct bootmenu_entry *first; /* first menu entry */
+ };
}
switch (key) {
-@@ -112,6 +113,12 @@ static char *bootmenu_choice_entry(void
+@@ -114,6 +115,12 @@ static char *bootmenu_choice_entry(void
++menu->active;
/* no menu key selected, regenerate menu */
return NULL;
case BKEY_SELECT:
iter = menu->first;
for (i = 0; i < menu->active; ++i)
-@@ -169,6 +176,9 @@ static int prepare_bootmenu_entry(struct
+@@ -182,6 +189,9 @@ static int prepare_bootmenu_entry(struct
unsigned short int i = *index;
struct bootmenu_entry *entry = NULL;
struct bootmenu_entry *iter = *current;
while ((option = bootmenu_getoption(i))) {
-@@ -183,11 +193,24 @@ static int prepare_bootmenu_entry(struct
+@@ -196,11 +206,24 @@ static int prepare_bootmenu_entry(struct
if (!entry)
return -ENOMEM;
entry->command = strdup(sep + 1);
if (!entry->command) {
-@@ -333,6 +356,7 @@ static struct bootmenu_data *bootmenu_cr
- menu->delay = delay;
+@@ -347,6 +370,7 @@ static struct bootmenu_data *bootmenu_cr
menu->active = 0;
+ menu->last_active = -1;
menu->first = NULL;
+ menu->last_choiced = false;
default_str = env_get("bootmenu_default");
if (default_str)
-@@ -368,9 +392,9 @@ static struct bootmenu_data *bootmenu_cr
+@@ -382,9 +406,9 @@ static struct bootmenu_data *bootmenu_cr
/* Add Quit entry if exiting bootmenu is disabled */
if (!IS_ENABLED(CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE))
free(entry);
--- a/common/menu.c
+++ b/common/menu.c
-@@ -48,6 +48,33 @@ struct menu {
+@@ -49,6 +49,33 @@ struct menu {
int item_cnt;
};
/*
* An iterator function for menu items. callback will be called for each item
* in m, with m, a pointer to the item, and extra being passed to callback. If
-@@ -426,7 +453,7 @@ int menu_destroy(struct menu *m)
+@@ -437,7 +464,7 @@ int menu_destroy(struct menu *m)
}
enum bootmenu_key bootmenu_autoboot_loop(struct bootmenu_data *menu,
{
enum bootmenu_key key = BKEY_NONE;
int i, c;
-@@ -461,6 +488,19 @@ enum bootmenu_key bootmenu_autoboot_loop
+@@ -472,6 +499,19 @@ enum bootmenu_key bootmenu_autoboot_loop
break;
default:
key = BKEY_NONE;
break;
}
break;
-@@ -481,7 +521,8 @@ enum bootmenu_key bootmenu_autoboot_loop
+@@ -492,7 +532,8 @@ enum bootmenu_key bootmenu_autoboot_loop
return key;
}
{
enum bootmenu_key key;
-@@ -513,6 +554,20 @@ enum bootmenu_key bootmenu_conv_key(int
+@@ -524,6 +565,20 @@ enum bootmenu_key bootmenu_conv_key(int
case ' ':
key = BKEY_SPACE;
break;
default:
key = BKEY_NONE;
break;
-@@ -522,11 +577,16 @@ enum bootmenu_key bootmenu_conv_key(int
+@@ -533,11 +588,17 @@ enum bootmenu_key bootmenu_conv_key(int
}
enum bootmenu_key bootmenu_loop(struct bootmenu_data *menu,
- struct cli_ch_state *cch)
-+ struct cli_ch_state *cch, int *choice)
++ struct cli_ch_state *cch,
++ int *choice)
{
enum bootmenu_key key;
- int c;
+ int c, errchar = 0;
+ if (menu->last_choiced) {
+ menu->last_choiced = false;
c = cli_ch_process(cch, 0);
if (!c) {
while (!c && !tstc()) {
-@@ -540,7 +600,7 @@ enum bootmenu_key bootmenu_loop(struct b
+@@ -552,7 +613,7 @@ enum bootmenu_key bootmenu_loop(struct b
}
}
struct cli_ch_state;
struct menu;
-@@ -19,6 +21,8 @@ int menu_get_choice(struct menu *m, void
+@@ -20,6 +22,8 @@ int menu_get_choice(struct menu *m, void
int menu_item_add(struct menu *m, char *item_key, void *item_data);
int menu_destroy(struct menu *m);
int menu_default_choice(struct menu *m, void **choice);
/**
* menu_show() Show a boot menu
-@@ -41,6 +45,7 @@ struct bootmenu_data {
- int active; /* active menu entry */
+@@ -43,6 +47,7 @@ struct bootmenu_data {
+ int last_active; /* last active menu entry */
int count; /* total count of menu entries */
struct bootmenu_entry *first; /* first menu entry */
+ bool last_choiced;
};
/** enum bootmenu_key - keys that can be returned by the bootmenu */
-@@ -51,6 +56,7 @@ enum bootmenu_key {
+@@ -53,6 +58,7 @@ enum bootmenu_key {
BKEY_SELECT,
BKEY_QUIT,
BKEY_SAVE,
/* 'extra' keys, which are used by menus but not cedit */
BKEY_PLUS,
-@@ -81,7 +87,7 @@ enum bootmenu_key {
+@@ -83,7 +89,7 @@ enum bootmenu_key {
* anything else: KEY_NONE
*/
enum bootmenu_key bootmenu_autoboot_loop(struct bootmenu_data *menu,
/**
* bootmenu_loop() - handle waiting for a keypress when autoboot is disabled
-@@ -107,7 +113,7 @@ enum bootmenu_key bootmenu_autoboot_loop
+@@ -109,7 +115,7 @@ enum bootmenu_key bootmenu_autoboot_loop
* Space: BKEY_SPACE
*/
enum bootmenu_key bootmenu_loop(struct bootmenu_data *menu,
/**
* bootmenu_conv_key() - Convert a U-Boot keypress into a menu key
-@@ -115,6 +121,7 @@ enum bootmenu_key bootmenu_loop(struct b
+@@ -117,6 +123,7 @@ enum bootmenu_key bootmenu_loop(struct b
* @ichar: Keypress to convert (ASCII, including control characters)
* Returns: Menu key that corresponds to @ichar, or BKEY_NONE if none
*/
--- a/cmd/bootmenu.c
+++ b/cmd/bootmenu.c
-@@ -451,7 +451,11 @@ static void menu_display_statusline(stru
+@@ -465,7 +465,11 @@ static void menu_display_statusline(stru
printf(ANSI_CURSOR_POSITION, 1, 1);
puts(ANSI_CLEAR_LINE);
printf(ANSI_CURSOR_POSITION, 2, 3);
puts(ANSI_CLEAR_LINE_TO_END);
printf(ANSI_CURSOR_POSITION, 3, 1);
puts(ANSI_CLEAR_LINE);
-@@ -536,6 +540,7 @@ static enum bootmenu_ret bootmenu_show(i
+@@ -550,6 +554,7 @@ static enum bootmenu_ret bootmenu_show(i
return BOOTMENU_RET_FAIL;
}
goto cleanup;
--- a/include/menu.h
+++ b/include/menu.h
-@@ -45,6 +45,7 @@ struct bootmenu_data {
- int active; /* active menu entry */
+@@ -47,6 +47,7 @@ struct bootmenu_data {
+ int last_active; /* last active menu entry */
int count; /* total count of menu entries */
struct bootmenu_entry *first; /* first menu entry */
+ char *mtitle; /* custom menu title */