F11 and F12 are trapped by some terminal emulators, and sgabios does not always recognize function keys very well.
Real-world machines often provide replacements for function keys for use on the serial console: ESC+1...ESC+0 for F1...F10, ESC+SHIFT+1 and ESC+SHIFT+2 for F11...F12. Accept all of them, which can be useful in case the user has set boot-menu-key.
The behavior is disabled if ESC is configured to trigger the menu. Chromebooks use this configuration.
Signed-off-by: Paolo Bonzini pbonzini@redhat.com
--- v1->v2: disable new behavior if ESC triggers the boot menu [Kevin] --- src/boot.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-)
diff --git a/src/boot.c b/src/boot.c index f23e9e1..0572ff1 100644 --- a/src/boot.c +++ b/src/boot.c @@ -422,7 +422,21 @@ get_raw_keystroke(void) memset(&br, 0, sizeof(br)); br.flags = F_IF; call16_int(0x16, &br); - return br.ah; + return br.ax; +} + +// Read a keystroke - waiting up to 'msec' milliseconds. +static int +get_keystroke_ascii(int msec) +{ + u32 end = irqtimer_calc(msec); + for (;;) { + if (check_for_keystroke()) + return get_raw_keystroke() & 255; + if (irqtimer_check(end)) + return -1; + yield_toirq(); + } }
// Read a keystroke - waiting up to 'msec' milliseconds. @@ -432,7 +446,7 @@ get_keystroke(int msec) u32 end = irqtimer_calc(msec); for (;;) { if (check_for_keystroke()) - return get_raw_keystroke(); + return get_raw_keystroke() >> 8; if (irqtimer_check(end)) return -1; yield_toirq(); @@ -446,6 +460,35 @@ get_keystroke(int msec)
#define DEFAULT_BOOTMENU_WAIT 2500
+static int +get_bootmenu_keystroke(bool esc_sequence) +{ + u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT); + int scan_code = get_keystroke(menutime); + if (esc_sequence && scan_code == 0x01) { + while (get_keystroke(0) >= 0) + ; + int ascii = get_keystroke_ascii(menutime * 2); + switch (ascii) { + case '1' ... '9': + scan_code = 0x3a + ascii - '0'; + break; + case '0': + scan_code = 0x3a + 10; + break; + case '!': + scan_code = 0x85; + break; + case '@': + scan_code = 0x86; + break; + default: + break; + } + } + return scan_code; +} + // Show IPL option menu. void interactive_bootmenu(void) @@ -460,12 +503,11 @@ interactive_bootmenu(void)
char *bootmsg = romfile_loadfile("etc/boot-menu-message", NULL); int menukey = romfile_loadint("etc/boot-menu-key", 0x86); - printf("%s", bootmsg ?: "\nPress F12 for boot menu.\n\n"); + printf("%s", bootmsg ?: "\nPress ESC+@ or F12 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); + int scan_code = get_bootmenu_keystroke(menukey != 1); disable_bootsplash(); if (scan_code != menukey) return;