Add boot.conf(8) 'mach idle [secs]' to halt at idle passphrase prompts
authorkn <kn@openbsd.org>
Thu, 25 Apr 2024 18:31:49 +0000 (18:31 +0000)
committerkn <kn@openbsd.org>
Thu, 25 Apr 2024 18:31:49 +0000 (18:31 +0000)
Enable users to power down their machines if there was no input after N
seconds during disk descryption.

Motivation is to save battery and prevent pocket heaters when notebooks
unhibernate (e.g. lid accidentially opened) and sit at "Passphrase: ".

Only available on efi(4) systems as the timeout is saved as EFI variable;
mostly because that's trivial to do, but also because we lack a better
mechanism to configure that and persist such data without the root disk.

Discussed with many, starting at h2k23
OK Tests gnezdo

sys/arch/amd64/stand/boot/boot.8
sys/arch/amd64/stand/efiboot/Makefile.common
sys/arch/amd64/stand/efiboot/cmd_i386.c
sys/arch/amd64/stand/efiboot/conf.c
sys/arch/amd64/stand/efiboot/efiboot.c
sys/arch/amd64/stand/efiboot/efiboot.h
sys/lib/libsa/softraid.c

index 6b3eee8..cdeb55a 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: boot.8,v 1.34 2023/02/23 19:48:21 miod Exp $
+.\"    $OpenBSD: boot.8,v 1.35 2024/04/25 18:31:49 kn Exp $
 .\"
 .\" Copyright (c) 1997-2001 Michael Shalayeff
 .\" All rights reserved.
@@ -25,7 +25,7 @@
 .\" THE POSSIBILITY OF SUCH DAMAGE.
 .\"
 .\"
-.Dd $Mdocdate: February 23 2023 $
+.Dd $Mdocdate: April 25 2024 $
 .Dt BOOT 8 amd64
 .Os
 .Sh NAME
@@ -245,6 +245,19 @@ If
 .Ar mode
 is not given,
 a list of available modes is shown.
+.It Ic idle Op Ar secs
+On
+.Xr efi 4
+systems,
+sets the timeout in seconds to power down the machine,
+if no input has been given at the
+.Xr softraid 4
+passphrase prompt.
+A value of 0 unsets the timeout.
+If
+.Ar secs
+is not given,
+the current timeout is shown.
 .It Ic memory
 If used without any arguments, this command will print out
 the memory configuration as determined through BIOS routines.
@@ -426,6 +439,7 @@ option.
 .Xr gzip 1 ,
 .Xr autoconf 4 ,
 .Xr ddb 4 ,
+.Xr efi 4 ,
 .Xr softraid 4 ,
 .Xr biosboot 8 ,
 .Xr boot_amd64 8 ,
index 80b36b7..8421a2b 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile.common,v 1.22 2021/11/14 21:51:48 guenther Exp $
+#      $OpenBSD: Makefile.common,v 1.23 2024/04/25 18:31:49 kn Exp $
 
 S=             ${.CURDIR}/../../../../..
 SADIR=         ${.CURDIR}/../..
@@ -18,6 +18,7 @@ COPTS+=               -ffreestanding -std=gnu99
 COPTS+=                -fshort-wchar -fPIC -mno-red-zone
 .if ${SOFTRAID:L} == "yes"
 COPTS+=                -DSOFTRAID
+COPTS+=                -DIDLE_POWEROFF
 .endif
 COPTS+=                -D_STANDALONE -nostdinc -fno-builtin
 
index f79e2b1..8f6cd67 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cmd_i386.c,v 1.1 2019/05/10 21:20:42 mlarkin Exp $    */
+/*     $OpenBSD: cmd_i386.c,v 1.2 2024/04/25 18:31:49 kn Exp $ */
 
 /*
  * Copyright (c) 1997-1999 Michael Shalayeff
@@ -61,6 +61,9 @@ const struct cmd_table cmd_machine[] = {
        { "poweroff",   CMDT_CMD, Xpoweroff_efi },
 #ifdef DEBUG
        { "regs",       CMDT_CMD, Xregs },
+#endif
+#ifdef IDLE_POWEROFF
+       { "idle",       CMDT_CMD, Xidle_efi },
 #endif
        { NULL, 0 }
 };
index a7d1020..1204987 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conf.c,v 1.42 2023/07/22 10:11:19 jsg Exp $   */
+/*     $OpenBSD: conf.c,v 1.43 2024/04/25 18:31:49 kn Exp $    */
 
 /*
  * Copyright (c) 1996 Michael Shalayeff
@@ -40,7 +40,7 @@
 #include "efidev.h"
 #include "efipxe.h"
 
-const char version[] = "3.65";
+const char version[] = "3.66";
 
 #ifdef EFI_DEBUG
 int    debug = 0;
index 95cf92d..b4ff857 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: efiboot.c,v 1.41 2023/01/02 22:41:17 kettenis Exp $   */
+/*     $OpenBSD: efiboot.c,v 1.42 2024/04/25 18:31:49 kn Exp $ */
 
 /*
  * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@@ -1078,17 +1078,69 @@ u_int
 sleep(u_int i)
 {
        time_t t;
+       u_int intr = 0;
 
        /*
         * Loop for the requested number of seconds, polling,
         * so that it may handle interrupts.
         */
-       for (t = getsecs() + i; getsecs() < t; cnischar())
+       for (t = getsecs() + i; intr == 0 && getsecs() < t; intr = cnischar())
                ;
 
+       return intr;
+}
+
+#ifdef IDLE_POWEROFF
+CHAR16         *idle_name = L"IdlePoweroff";
+EFI_STATUS      idle_status;
+/* randomly generated f948e8a9-0570-4338-ad10-29f4cf12849d */
+EFI_GUID        openbsd_guid = { 0xf948e8a9, 0x0570, 0x4338,
+    { 0xad, 0x10, 0x29, 0xf4, 0xcf, 0x12, 0x84, 0x9d } };
+/* Non-Volatile, Boot Service Access, Runtime Service Access */
+UINT32          idle_attrs = 0x1 | 0x2 | 0x4;
+UINT16          idle_secs;
+UINTN           idle_sz = sizeof(idle_secs);
+
+int
+get_idle_timeout(void)
+{
+       idle_status = RS->GetVariable(idle_name, &openbsd_guid, NULL,
+           &idle_sz, &idle_secs);
+       if (idle_status != EFI_SUCCESS) {
+               if (idle_status != EFI_NOT_FOUND) {
+                       printf("%s: %d\n", __func__, idle_status);
+                       return 1;
+               }
+               return -1;
+       }
+       return 0;
+}
+
+int
+set_idle_timeout(int secs)
+{
+       idle_secs = secs;
+       idle_sz = idle_secs > 0 ? sizeof(idle_secs) : 0;
+       idle_status = RS->SetVariable(idle_name, &openbsd_guid, idle_attrs,
+           idle_sz, &idle_secs);
+       if (idle_status != EFI_SUCCESS) {
+               printf("%s: %d\n", __func__, idle_status);
+               return -1;
+       }
        return 0;
 }
 
+/* see lib/libsa/softraid.c sr_crypto_passphrase_decrypt() */
+void
+idle_poweroff(void)
+{
+       if (get_idle_timeout() == 0 && sleep(idle_secs) == 0) {
+               printf("\nno input after %us, powering off...\n", idle_secs);
+               Xpoweroff_efi();
+       }
+}
+#endif /* IDLE_POWEROFF */
+
 /***********************************************************************
  * Commands
  ***********************************************************************/
@@ -1173,3 +1225,21 @@ Xgop_efi(void)
 
        return (0);
 }
+
+#ifdef IDLE_POWEROFF
+int
+Xidle_efi(void)
+{
+       if (cmd.argc >= 2) {
+               int secs;
+
+               secs = strtol(cmd.argv[1], NULL, 10);
+               if (0 <= secs && secs < UINT16_MAX)
+                       set_idle_timeout(secs);
+       } else {
+               if (get_idle_timeout() == 0)
+                       printf("Timeout = %us\n", idle_secs);
+       }
+       return 0;
+}
+#endif /* IDLE_POWEROFF */
index 725aebc..8fdc5be 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: efiboot.h,v 1.5 2022/07/11 19:45:02 kettenis Exp $    */
+/*     $OpenBSD: efiboot.h,v 1.6 2024/04/25 18:31:49 kn Exp $  */
 
 /*
  * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@@ -37,6 +37,9 @@ void   efi_makebootargs(void);
 void    efi_setconsdev(void);
 
 int     Xpoweroff_efi(void);
+#ifdef IDLE_POWEROFF
+int     Xidle_efi(void);
+#endif
 
 extern void (*run_i386)(u_long, u_long, int, int, int, int, int, int, int, int)
     __attribute__ ((noreturn));
index d31c167..2dd0785 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: softraid.c,v 1.6 2024/03/24 05:50:20 jsg Exp $        */
+/*     $OpenBSD: softraid.c,v 1.7 2024/04/25 18:31:49 kn Exp $ */
 
 /*
  * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
@@ -150,6 +150,10 @@ sr_crypto_passphrase_decrypt(struct sr_meta_crypto *cm,
 
        for (;;) {
                printf("Passphrase: ");
+#ifdef IDLE_POWEROFF
+extern int idle_poweroff(void);
+               idle_poweroff();
+#endif /* IDLE_POWEROFF */
                for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
                        c = cngetc();
                        if (c == '\r' || c == '\n') {