[SeaBIOS] [PATCH] advanced_bootmenu: up to 35 entries (2 pages if >18), numpad support (console)

Mike Banon posted 1 patch 5 years ago
Failed in applying to current master (apply log)
[SeaBIOS] [PATCH] advanced_bootmenu: up to 35 entries (2 pages if >18), numpad support (console)
Posted by Mike Banon 5 years ago
Add support for up to 35 boot menu entries (2 pages if >18). To solve the
">10" problem currently experienced by SeaBIOS users (there are no 11, 12, etc.
keys on a keyboard - so impossible to choose the last menu entries if you got
>10 entries because of multiple hard drives / secondary payloads / floppies)
- the boot menu has been extended to the letter keys. NOTE: TPM menu has been
moved from T to M letter: it is at the end of keyboard's 3rd row of letters and
"Trusted" is adjective while "Module" is a noun; alternatively could press '-'.

Also, add support for a numpad. Small USB numpad could be really convenient for
choosing the boot entries at coreboot boards used as (maybe headless) servers.
'/' char on numpad could be used to open the boot menu or to exit it. If there
are >10 boot menu entries - the numpad console interface will be enabled: press
one or two digit keys and then ENTER to confirm your choice, or remove a digit
by pressing the '.Del' key. Also you could call TPM with '-' key at any moment,
or boot with a single key press of your fullsize keyboard.

Signed-off-by: Mike Banon <mikebdp2 at gmail.com>
(patch body is after the testing instructions below)

This "advanced_bootmenu" patch is much more useful when used together
with my "multiple_floppies" patch:
[SeaBIOS] [PATCH v2] ramdisk: search for all available floppy images
instead of one
https://mail.coreboot.org/pipermail/seabios/2018-December/012670.html

Sadly I haven't done the suggestions by Kevin (I have so many unfinished tasks)
so the "multiple_floppies" patch is also not merged yet. But you could install
both patches to your coreboot by executing this script while at ./coreboot dir:
https://pastebin.com/raw/hv9sSuMU

And here is a coreboot image for QEMU with these two patches applied and my
collection of wonderful and useful floppies added to popular the entries list:
https://github.com/mikebdp2/floparchive/blob/master/coreboot.rom?raw=true
Descriptions of the most prominent floppies could be found here:
http://dangerousprototypes.com/docs/Lenovo_G505S_hacking#Useful_floppies

Run this coreboot.rom by executing this QEMU command: (some floppies are 64-bit)
qemu-system-x86_64 -L . -m 768 -localtime -vga vmware -net nic,model=rtl8139 \
 -net user -soundhw ac97 -bios ./coreboot.rom -boot menu=on -serial stdio

Best regards,
Mike Banon


diff --git a/src/boot.c b/src/boot.c
index 9f82f3c..f94dd27 100644
--- a/src/boot.c
+++ b/src/boot.c
@@ -463,6 +463,7 @@ get_keystroke(int msec)
  * Boot menu and BCV execution
  ****************************************************************/

+#define BOOTMENU_PAGE_SIZE    18
 #define DEFAULT_BOOTMENU_WAIT 2500

 // Show IPL option menu.
@@ -478,59 +479,282 @@ interactive_bootmenu(void)
         ;

     char *bootmsg = romfile_loadfile("etc/boot-menu-message", NULL);
-    int menukey = romfile_loadint("etc/boot-menu-key", 1);
-    printf("%s", bootmsg ?: "\nPress ESC for boot menu.\n\n");
+    int menukey = romfile_loadint("etc/boot-menu-key", 1); // custom menukey
+    printf("%s", bootmsg ?: "\nPress ESC or \\ / slash for boot menu.\n\n");
     free(bootmsg);

     u32 menutime = romfile_loadint("etc/boot-menu-wait",
DEFAULT_BOOTMENU_WAIT);
     enable_bootsplash();
     int scan_code = get_keystroke(menutime);
     disable_bootsplash();
-    if (scan_code != menukey)
+    if (scan_code != menukey && // custom menukey
+        scan_code !=  1 && // ESC
+        scan_code != 43 && // '\' char on keyboard
+        scan_code != 53 && // '/' char on keyboard
+        scan_code != 98) { // '/' char on numpad
+        if (scan_code == -1)
+            printf("No key pressed.\n");
+        else
+            printf("Not a menukey pressed.\n");
         return;
+    }

     while (get_keystroke(0) >= 0)
         ;

-    printf("Select boot device:\n\n");
     wait_threads();

-    // Show menu items
+    char keyboard_keys[35] = {'1','2','3','4','5','6','7','8','9','0',
+                               'q','w','e','r','t','y','u','i','o','p',
+                                'a','s','d','f','g','h','j','k','l',
+                                 'z','x','c','v','b','n'}; /* m = TPM */
+    int numpad_scancodes[10] = { 82, 79, 80, 81, 75, 76, 77, 71, 72, 73 };
+    int numpi = 0; // Key index:  0,  1,  2,  3,  4,  5,  6,  7,  8,  9.
+    int digits = 0; // Numerical length of a current choice number.
+    int decode = 0; // Decode the current choice number into a letter?
+    int entry_id = 0;
+    char desc[77];
+
+    printf("Select boot device");
+
+    // Show menu items after counting them and determining a number of pages.
+    // Only 35 boot menu items (36 if to count a TPM) are supported currently.
+
     int maxmenu = 0;
     struct bootentry_s *pos;
-    hlist_for_each_entry(pos, &BootList, node) {
-        char desc[77];
+    hlist_for_each_entry(pos, &BootList, node)
         maxmenu++;
-        printf("%d. %s\n", maxmenu
+
+    if (maxmenu > 10) {
+        if (maxmenu > 35)
+            maxmenu = 35;
+        if (maxmenu > BOOTMENU_PAGE_SIZE)
+            printf(" - page 1 :");
+        else
+            printf(":          ");
+        printf(" // press ENTER after your numpad input");
+        if (maxmenu > BOOTMENU_PAGE_SIZE)
+            printf(" - if any -\n                            "
+                   " // - or to switch between the pages...\n");
+        else
+            printf(" (if any)\n\n");
+    } else {
+        printf(":\n\n");
+    }
+
+    hlist_for_each_entry(pos, &BootList, node) {
+        if (entry_id == BOOTMENU_PAGE_SIZE) // Show only the first page.
+            break;
+        printf("%c. %s\n", keyboard_keys[entry_id]
                , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
+        entry_id++;
     }
+    int tpm_cshm = 0;
     if (tpm_can_show_menu()) {
-        printf("\nt. TPM Configuration\n");
+        tpm_cshm = 1;
+        printf("\nm-. TPM Configuration");
     }
-
-    // Get key press.  If the menu key is ESC, do not restart boot unless
-    // 1.5 seconds have passed.  Otherwise users (trained by years of
-    // repeatedly hitting keys to enter the BIOS) will end up hitting ESC
-    // multiple times and immediately booting the primary boot device.
-    int esc_accepted_time = irqtimer_calc(menukey == 1 ? 1500 : 0);
+    printf("\n> ");
+
+    // Do not restart boot on menukey press, unless DEFAULT_BOOTMENU_WAIT msecs
+    // have passed. Otherwise users (trained by years of repeatedly
hitting keys
+    // to enter the BIOS) will end up hitting menukey multiple times and
+    // immediately booting the primary boot device.
+    int esc_accepted_time = irqtimer_calc(DEFAULT_BOOTMENU_WAIT);
+    int choice = 0, kb_choice = 0;
+    int page_num = 1;
+    int enter = 0;
+    int backspace = 0;
+    int tpm_show_menu = 0;
     for (;;) {
         scan_code = get_keystroke(1000);
-        if (scan_code == 1 && !irqtimer_check(esc_accepted_time))
-            continue;
-        if (tpm_can_show_menu() && scan_code == 20 /* t */) {
+        if (scan_code == menukey || // custom menukey
+            scan_code ==  1 || // ESC
+            scan_code == 43 || // '\' char on keyboard
+            scan_code == 53 || // '/' char on keyboard
+            scan_code == 98) { // '/' char on numpad
+            if (!irqtimer_check(esc_accepted_time))
+                continue;
+            if (digits == 2) // Remove the decoded "(*)"
+                printf("   \b\b\b");
+            /* Remove the existing input before printing a message. */
+            for (; digits > 0; digits--)
+                printf("\b \b");
+            printf("Menukey pressed.\n");
+            return;
+        }
+        kb_choice = 0;
+        /* 4 rows of keyboard_keys: 1 row with numbers, 3 rows with letters.
+           Use any of them to select a boot device (except the TPM
'm-' keys) */
+        // 1st range: 1-9 and 0 (10) keys <==> 2-11 scan codes <==>
1-10 choice
+        if (scan_code >=  2 && scan_code <= 11) kb_choice = scan_code -  1;
+        // 2nd range: Q-P row of letters <==> 16-25 scan codes <==>
11-20 choice
+        if (scan_code >= 16 && scan_code <= 25) kb_choice = scan_code -  5;
+        // 3rd range: A-L row of letters <==> 30-38 scan codes <==>
21-29 choice
+        if (scan_code >= 30 && scan_code <= 38) kb_choice = scan_code -  9;
+        // 4th range: Z-N row of letters <==> 44-49 scan codes <==>
30-35 choice
+        if (scan_code >= 44 && scan_code <= 49) kb_choice = scan_code - 14;
+        // ENTER: (28) on keyboard, (96) on numpad.
+        if (scan_code == 28 || scan_code == 96)
+            enter = 1;
+        // BCKSPC: '<-'(14) and 'Delete'(111) on keyboard, '.Del'(83)
on numpad.
+        if (scan_code == 14 || scan_code == 111 || scan_code == 83)
+            backspace = 1;
+        // TPM keys: 'm'(50) and '-'(12) chars on keyboard, '-'(74) on numpad.
+        if ((scan_code == 50 || scan_code == 12 || scan_code == 74)
&& tpm_cshm)
+            tpm_show_menu = 1;
+
+        if (kb_choice != 0 || tpm_show_menu) {
+            if (kb_choice > maxmenu) {
+                if (!tpm_show_menu)
+                    continue;
+            } else {
+                choice = kb_choice;
+            }
+            if (digits == 2) // Remove the decoded "(*)"
+                printf("   \b\b\b");
+            /* Remove the existing input before printing a choice. */
+            for (; digits > 0; digits--)
+                printf("\b \b");
+            if (!tpm_show_menu) {
+                // Choice is any of the detected boot devices ==> lets boot!
+                break;
+            }
+        } else {
+            // Internal/USB Numpad console interface.
+            if (digits < 9) {
+                for (numpi = 0; numpi < 10; numpi++) {
+                    if (scan_code == numpad_scancodes[numpi]) {
+                        if (maxmenu <= 10) { // Console interface is
not needed.
+                            if ((numpi != 0 && numpi <= maxmenu) ||
+                                (numpi == 0 && 10 <= maxmenu)) { // 10(0)
+                                choice = numpi;
+                                enter = 1; // Fake ENTER to boot this
entry now.
+                            } else { // If no such an entry, don't try to boot.
+                                break;
+                            }
+                        } else {
+                            if (digits == 2) {
+                                printf("   \b\b\b"); // Remove the
decoded "(*)"
+                                if (choice == 0) {
+                                    printf("\b\b  \b\b"); // Remove "10".
+                                    digits = 0;
+                                }
+                            }
+                            choice = 10 * choice + numpi;
+                        }
+                        if (choice > 0) {
+                            printf("%d", numpi); // Print the entered digit.
+                            digits++;
+                        } else {
+                            if (10 <= maxmenu)
+                                printf("10(0)\b\b\b");
+                            else
+                                printf("10(?)\b\b\b");
+                            digits = 2;
+                        }
+                        if (choice > 9 && digits == 2) // Decode into a letter.
+                            decode = 1;
+                        break;
+                    }
+                }
+            }
+            if (backspace && digits > 0) {
+                backspace = 0;
+                choice = choice / 10;
+                if (digits == 2) {
+                    printf("   \b\b\b"); // Remove the decoded "(*)"
+                    // 0 turned into 10: one more Backspace is needed
to remove.
+                    if (choice == 0) {
+                        printf("\b \b");
+                        digits--;
+                    }
+                }
+                printf("\b \b"); // Remove the last entered digit.
+                digits--;
+                if (choice > 9 && digits == 2) // Decode into a letter.
+                    decode = 1;
+            }
+            if (decode) { // Decode the current choice number into a letter.
+                decode = 0;
+                if (choice <= maxmenu) {
+                    printf("(%c)", keyboard_keys[choice-1]);
+                } else {
+                    if (tpm_cshm && choice == 36)
+                        printf("(m)"); // For TPM.
+                    else
+                        printf("(?)"); // No matching letter found.
+                    }
+                printf("\b\b\b"); // Move a cursor before the "(*)"
+            }
+        }
+
+        if (enter) {
+            enter = 0;
+            if (choice == 0) {
+                if (digits == 2) { // for 0 that turned into 10
+                    if (10 <= maxmenu)
+                        break;
+                    else
+                        continue;
+                }
+                // If there are two pages - switch between them.
+                if (maxmenu > BOOTMENU_PAGE_SIZE) {
+                    entry_id = 0;
+                    page_num = 3 - page_num; // 3 - 1 = 2; 3 - 2 = 1.
+                    printf("\n\nSelect boot device - page %d :"
+                           " // press ENTER after your numpad input"
+                           " - if any -\n                            "
+                           " // - or to switch between the pages...\n",
+                           page_num);
+                    hlist_for_each_entry(pos, &BootList, node) {
+                        if ((page_num == 1 && entry_id ==
BOOTMENU_PAGE_SIZE) ||
+                            (page_num == 2 && entry_id == 35))
+                            break;
+                        if (page_num == 1 || entry_id >= BOOTMENU_PAGE_SIZE)
+                            printf("%c. %s\n", keyboard_keys[entry_id],
+                             strtcpy(desc, pos->description,
ARRAY_SIZE(desc)));
+                        entry_id++;
+                    }
+                    if (tpm_cshm)
+                        printf("\nm-. TPM Configuration");
+                    printf("\n> ");
+                }
+            } else {
+                if (choice > maxmenu) {
+                    if (tpm_cshm && choice == 36)
+                        tpm_show_menu = 1;
+                } else {
+                    // Choice is any of the detected boot devices ==>
lets boot!
+                    break;
+                }
+            }
+        }
+
+        if (tpm_show_menu) {
+            tpm_show_menu = 0;
+            choice = 0;
+            if (digits == 0)
+                printf("TPM key pressed.");
+            else
+                digits = 0;
             printf("\n");
             tpm_menu();
+            printf("> ");
         }
-        if (scan_code >= 1 && scan_code <= maxmenu+1)
-            break;
+    }
+
+    if (choice == 0) // 10(0)
+        choice = 10;
+
+    if (digits == 0 && choice < 36) {
+        printf("%c", keyboard_keys[choice-1]);
+        if (choice > 9) // Decode into a number.
+            printf("(%d)", choice);
     }
     printf("\n");
-    if (scan_code == 0x01)
-        // ESC
-        return;

     // Find entry and make top priority.
-    int choice = scan_code - 1;
     hlist_for_each_entry(pos, &BootList, node) {
         if (! --choice)
             break;
diff --git a/src/config.h b/src/config.h
index 93c8dbc..f85cc14 100644
--- a/src/config.h
+++ b/src/config.h
@@ -19,7 +19,7 @@
 // Space to reserve in high-memory for tables
 #define BUILD_MAX_HIGHTABLE (256*1024)
 // Largest supported externaly facing drive id
-#define BUILD_MAX_EXTDRIVE 16
+#define BUILD_MAX_EXTDRIVE 36
 // Number of bytes the smbios may be and still live in the f-segment
 #define BUILD_MAX_SMBIOS_FSEG     600
 // Maximum number of bytes the mptable may be and still be copied to f-segment
_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org
[SeaBIOS] Re: [PATCH] advanced_bootmenu: up to 35 entries (2 pages if >18), numpad support (console)
Posted by Paul Menzel 4 years ago
Dear Mike,


Am 10.04.19 um 15:08 schrieb Mike Banon:
> Add support for up to 35 boot menu entries (2 pages if >18). To solve the
> ">10" problem currently experienced by SeaBIOS users (there are no 11, 12, etc.
> keys on a keyboard - so impossible to choose the last menu entries if you got
>> 10 entries because of multiple hard drives / secondary payloads / floppies)
> - the boot menu has been extended to the letter keys. NOTE: TPM menu has been
> moved from T to M letter: it is at the end of keyboard's 3rd row of letters and
> "Trusted" is adjective while "Module" is a noun; alternatively could press '-'.

Could you please rebase this. With Gerd’s commit 18d237b4 (bootmenu: add 
support for more than 9 entries), 34(?) entries are currently supported. 
(No idea, why 0 is left out for example.)

> Also, add support for a numpad. Small USB numpad could be really convenient for
> choosing the boot entries at coreboot boards used as (maybe headless) servers.
> '/' char on numpad could be used to open the boot menu or to exit it. If there
> are >10 boot menu entries - the numpad console interface will be enabled: press
> one or two digit keys and then ENTER to confirm your choice, or remove a digit
> by pressing the '.Del' key. Also you could call TPM with '-' key at any moment,
> or boot with a single key press of your fullsize keyboard.

Could you split this out, and please send separately?

> Signed-off-by: Mike Banon <mikebdp2 at gmail.com>
> (patch body is after the testing instructions below)

It’d be great if you sent your patches with `git send-email`.

[…]


Kind regards,

Paul
_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org
[SeaBIOS] Re: [PATCH] advanced_bootmenu: up to 35 entries (2 pages if >18), numpad support (console)
Posted by Mike Banon 4 years ago
Hi there Paul,

Sorry for a late reply and thanks for your message, wish you a happy
time and good health.

>
>> Add support for up to 35 boot menu entries (2 pages if >18). To solve the
>> ">10" problem currently experienced by SeaBIOS users (there are no 11, 12, etc.
>> keys on a keyboard - so impossible to choose the last menu entries if you got
>>> 10 entries because of multiple hard drives / secondary payloads / floppies)
>> - the boot menu has been extended to the letter keys. NOTE: TPM menu has been
>> moved from T to M letter: it is at the end of keyboard's 3rd row of letters and
>> "Trusted" is adjective while "Module" is a noun; alternatively could press '-'.
>
> Could you please rebase this. With Gerd’s commit 18d237b4 (bootmenu:
> add support for more than 9 entries), 34(?) entries are currently supported.
> (No idea, why 0 is left out for example.)

This " advanced_bootmenu.patch " has been already rebased in a
coreboot change 32351 ( [1] ) and it still applies to a SeaBIOS
master. This rebase was a bit lazy to be honest, but it still works
thanks to boot.c not getting any significant changes for a long time
since 18d237b4.

Despite I love SeaBIOS so much, maybe because SeaBIOS isn't on Gerrit
(or other reasons?) - it's so hard to get anything merged there, much
harder than to coreboot or flashrom. I wonder why my
"advanced_bootmenu" patch hasn't been even reviewed in its' original
form despite multiple resubmissions. Although I was happy to see a
Gerd's spinoff accepted in a commit 18d237b4 since it's better than
nothing - however, it couldn't boot a large menu entry in a single
letter keypress (only numbers are supported there), so I keep using my
original version.

Maybe I'll try sending the patches to SeaBIOS again when the
optimistic mood comes... However, seeing that even a patch which fixes
booting USB drives with a write protect switch enabled ( [2] ) has
been rejected - despite it solves a real "broken hardware" problem -
sadly it's more likely that a pile of "unofficial SeaBIOS patches" in
change 32351 will keep growing. If you know any other good patches
which also haven't been accepted to SeaBIOS, please let me know and
I'll include them to 32351.

[1] https://review.coreboot.org/c/coreboot/+/32351
[2] https://mail.coreboot.org/hyperkitty/list/seabios@seabios.org/thread/FPQEYFMJN4LZNONJS5MLDGBI4CTEUGR3/
_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org