From 85d2f13b6fc41bfc5a2e9bf66a87a7a0e05d96bb Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Fri, 14 Jan 2022 14:27:08 +0100 Subject: [PATCH] boot: Add PC speaker support Fixes: #17508 --- man/loader.conf.xml | 7 +++++++ src/boot/efi/boot.c | 15 ++++++++++++++- src/boot/efi/util.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/boot/efi/util.h | 6 ++++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/man/loader.conf.xml b/man/loader.conf.xml index 579eaddebe..844bd631fc 100644 --- a/man/loader.conf.xml +++ b/man/loader.conf.xml @@ -196,6 +196,13 @@ by using the f key. + + beep + + Beep once as soon as the boot menu is shown (default disabled). Currently, + only x86 is supported, where it uses the PC speaker. + + reboot-for-bitlocker diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index c07f629939..a128b38b9c 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -89,6 +89,7 @@ typedef struct { BOOLEAN force_menu; BOOLEAN use_saved_entry; BOOLEAN use_saved_entry_efivar; + BOOLEAN beep; INT64 console_mode; INT64 console_mode_efivar; RandomSeedMode random_seed_mode; @@ -497,6 +498,7 @@ static void print_status(Config *config, CHAR16 *loaded_image_path) { ps_bool(L" editor: %s\n", config->editor); ps_bool(L" auto-entries: %s\n", config->auto_entries); ps_bool(L" auto-firmware: %s\n", config->auto_firmware); + ps_bool(L" beep: %s\n", config->beep); ps_bool(L" reboot-for-bitlocker: %s\n", config->reboot_for_bitlocker); ps_string(L" random-seed-mode: %s\n", random_seed_modes_table[config->random_seed_mode]); @@ -588,7 +590,7 @@ static BOOLEAN menu_run( _cleanup_freepool_ CHAR16 *clearline = NULL, *status = NULL; UINT32 timeout_efivar_saved = config->timeout_sec_efivar; UINT32 timeout_remain = config->timeout_sec == TIMEOUT_MENU_FORCE ? 0 : config->timeout_sec; - BOOLEAN exit = FALSE, run = TRUE, firmware_setup = FALSE; + BOOLEAN exit = FALSE, run = TRUE, firmware_setup = FALSE, do_beep = config->beep; INT64 console_mode_initial = ST->ConOut->Mode->Mode, console_mode_efivar_saved = config->console_mode_efivar; UINTN default_efivar_saved = config->idx_default_efivar; @@ -725,6 +727,11 @@ static BOOLEAN menu_run( ST->ConOut->OutputString(ST->ConOut, clearline + 1 + x + len); } + if (do_beep) { + beep(); + do_beep = FALSE; + } + err = console_key_read(&key, timeout_remain > 0 ? 1000 * 1000 : UINT64_MAX); if (err == EFI_TIMEOUT) { timeout_remain--; @@ -1144,6 +1151,12 @@ static void config_defaults_load_from_file(Config *config, CHAR8 *content) { continue; } + if (strcmpa((CHAR8 *)"beep", key) == 0) { + err = parse_boolean(value, &config->beep); + if (EFI_ERROR(err)) + log_error_stall(L"Error parsing 'beep' config option: %a", value); + } + if (strcmpa((CHAR8 *)"reboot-for-bitlocker", key) == 0) { err = parse_boolean(value, &config->reboot_for_bitlocker); if (EFI_ERROR(err)) diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c index 177c1b3d9a..42c28badbf 100644 --- a/src/boot/efi/util.c +++ b/src/boot/efi/util.c @@ -757,3 +757,46 @@ __attribute__((noinline)) void debug_break(void) { #endif } #endif + +#if defined(__i386__) || defined(__x86_64__) +static inline UINT8 inb(UINT16 port) { + UINT8 value; + asm volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); + return value; +} + +static inline void outb(UINT16 port, UINT8 value) { + asm volatile("outb %0, %1" : : "a"(value), "Nd"(port)); +} + +void beep(void) { + enum { + PITCH = 500, + DURATION_USEC = 100 * 1000, + + PIT_FREQUENCY = 0x1234dd, + SPEAKER_CONTROL_PORT = 0x61, + SPEAKER_ON_MASK = 0x03, + TIMER_PORT_MAGIC = 0xB6, + TIMER_CONTROL_PORT = 0x43, + TIMER_CONTROL2_PORT = 0x42, + }; + + /* Set frequency. */ + UINT32 counter = PIT_FREQUENCY / PITCH; + outb(TIMER_CONTROL_PORT, TIMER_PORT_MAGIC); + outb(TIMER_CONTROL2_PORT, counter & 0xFF); + outb(TIMER_CONTROL2_PORT, (counter >> 8) & 0xFF); + + /* Turn speaker on. */ + UINT8 value = inb(SPEAKER_CONTROL_PORT); + value |= SPEAKER_ON_MASK; + outb(SPEAKER_CONTROL_PORT, value); + + BS->Stall(DURATION_USEC); + + /* Turn speaker off. */ + value &= ~SPEAKER_ON_MASK; + outb(SPEAKER_CONTROL_PORT, value); +} +#endif diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index 9e8db3e7c9..8cee20885e 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -169,3 +169,9 @@ extern UINT8 _text, _data; #else # define debug_hook(identity) #endif + +#if defined(__i386__) || defined(__x86_64__) +void beep(void); +#else +static inline void beep(void) {} +#endif -- 2.25.1