> Date: Thu, 17 Mar 2022 11:02:00 +0000
> From: Miod Vallat <[email protected]>
>
> By default (with no override in /etc/boot.conf), the arm64 boot loader
> will attempt to boot the kernel after a 5 second timeout.
>
> On the RPi 4b here, it will indeed boot the kernel, but after about 80
> seconds.
>
> The reason for this delay is that there is logic in the boot code, while
> waiting for keystrokes, to limit the timeout check to "only once every
> 1000 times the console reports no keystroke". That logic was introduced
> almost 23 years ago to cope with some slow i386 BIOses.
>
> However, when there is no console activity, the EFI routine to check for
> a keystroke will itself wait for about 80 millisecond before returning
> failure, which in turn causes the timeout check to be performed only
> once every 80 seconds. Bummer.
>
> The following diff introduces a compile-time symbol to reduce the loop
> counter from 1000 to 10, and enables this on arm64. This results in
> accurate timeout processing, and the system correctly boots after 5
> seconds of idleness.
>
> That change might be needed on some other systems (armv7, riscv64?) as
> well.
This issue has been fixed somewhat recently in U-Boot. It only
happens if you connect a USB keyboard to the machine. With the
exception of Apple machines and possibly the Raspberry Pi, I expect
most people to use a serial console on arm64 (and armv7 and riscv64)
machines. And Apple machines will have a fixed U-Boot.
Note that this bug not only affects the timeout. It makes loading the
kernel from disk slow as well. So we probably should patch the U-Boot
version we ship and/or update to U-Boot 2022.04 when it is released in
a few weeks.
It may still be worth doing something like this, but would a middle
groun of making it loop something like a 100 times be an option?
> Index: arch/arm64/stand/efiboot/Makefile
> ===================================================================
> RCS file: /OpenBSD/src/sys/arch/arm64/stand/efiboot/Makefile,v
> retrieving revision 1.15
> diff -u -p -r1.15 Makefile
> --- arch/arm64/stand/efiboot/Makefile 14 Mar 2022 19:09:32 -0000 1.15
> +++ arch/arm64/stand/efiboot/Makefile 17 Mar 2022 10:53:34 -0000
> @@ -49,6 +49,7 @@ CPPFLAGS+= -I${EFIDIR}/include -I${EFIDI
> CPPFLAGS+= -D_STANDALONE
> CPPFLAGS+= -DSMALL -DSLOW -DNOBYFOUR -D__INTERNAL_LIBSA_CREAD
> CPPFLAGS+= -DNEEDS_HEAP_H -DMDRANDOM -DFWRANDOM
> +CPPFLAGS+= -DSLOW_CNISCHAR
> COPTS+= -Wno-attributes -Wno-format
> COPTS+= -ffreestanding -fno-stack-protector
> COPTS+= -fshort-wchar -fPIC -fno-builtin
> Index: arch/arm64/stand/efiboot/conf.c
> ===================================================================
> RCS file: /OpenBSD/src/sys/arch/arm64/stand/efiboot/conf.c,v
> retrieving revision 1.36
> diff -u -p -r1.36 conf.c
> --- arch/arm64/stand/efiboot/conf.c 14 Mar 2022 19:09:32 -0000 1.36
> +++ arch/arm64/stand/efiboot/conf.c 17 Mar 2022 10:53:34 -0000
> @@ -46,7 +46,7 @@
> #include "efipxe.h"
> #include "softraid_arm64.h"
>
> -const char version[] = "1.8";
> +const char version[] = "1.9";
> int debug = 0;
>
> struct fs_ops file_system[] = {
> Index: stand/boot/cmd.c
> ===================================================================
> RCS file: /OpenBSD/src/sys/stand/boot/cmd.c,v
> retrieving revision 1.68
> diff -u -p -r1.68 cmd.c
> --- stand/boot/cmd.c 24 Oct 2021 17:49:19 -0000 1.68
> +++ stand/boot/cmd.c 17 Mar 2022 10:53:35 -0000
> @@ -238,6 +238,18 @@ whatcmd(const struct cmd_table **ct, cha
> return q;
> }
>
> +/*
> + * If there is a timeout, we want to honour it as best as possible, but
> + * the getsecs() call might be expensive, so we don't want to check for
> + * timeout too frequently... unless cnischar() itself takes a long time
> + * to report no activity.
> + */
> +#ifdef SLOW_CNISCHAR
> +#define TIMEOUT_LOOP 10
> +#else
> +#define TIMEOUT_LOOP 1000
> +#endif
> +
> static int
> readline(char *buf, size_t n, int to)
> {
> @@ -254,10 +266,9 @@ readline(char *buf, size_t n, int to)
> if (debug > 2)
> printf ("readline: timeout(%d) at %u\n", to, tt);
> #endif
> - /* check for timeout expiration less often
> - (for some very constrained archs) */
> + /* Check for timeout expiration */
> while (!cnischar())
> - if (!(i++ % 1000) && (getsecs() >= tt))
> + if (!(i++ % TIMEOUT_LOOP) && (getsecs() >= tt))
> break;
>
> if (!cnischar()) {
>
>