From c2111d31835619f42dfae07a0b4925f019bfe0c7 Mon Sep 17 00:00:00 2001 From: kn Date: Thu, 25 Apr 2024 18:31:49 +0000 Subject: [PATCH] Add boot.conf(8) 'mach idle [secs]' to halt at idle passphrase prompts 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 | 18 ++++- sys/arch/amd64/stand/efiboot/Makefile.common | 3 +- sys/arch/amd64/stand/efiboot/cmd_i386.c | 5 +- sys/arch/amd64/stand/efiboot/conf.c | 4 +- sys/arch/amd64/stand/efiboot/efiboot.c | 74 +++++++++++++++++++- sys/arch/amd64/stand/efiboot/efiboot.h | 5 +- sys/lib/libsa/softraid.c | 6 +- 7 files changed, 105 insertions(+), 10 deletions(-) diff --git a/sys/arch/amd64/stand/boot/boot.8 b/sys/arch/amd64/stand/boot/boot.8 index 6b3eee8ffcb..cdeb55a3cc1 100644 --- a/sys/arch/amd64/stand/boot/boot.8 +++ b/sys/arch/amd64/stand/boot/boot.8 @@ -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 , diff --git a/sys/arch/amd64/stand/efiboot/Makefile.common b/sys/arch/amd64/stand/efiboot/Makefile.common index 80b36b71a68..8421a2b4332 100644 --- a/sys/arch/amd64/stand/efiboot/Makefile.common +++ b/sys/arch/amd64/stand/efiboot/Makefile.common @@ -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 diff --git a/sys/arch/amd64/stand/efiboot/cmd_i386.c b/sys/arch/amd64/stand/efiboot/cmd_i386.c index f79e2b1e090..8f6cd67f0c3 100644 --- a/sys/arch/amd64/stand/efiboot/cmd_i386.c +++ b/sys/arch/amd64/stand/efiboot/cmd_i386.c @@ -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 } }; diff --git a/sys/arch/amd64/stand/efiboot/conf.c b/sys/arch/amd64/stand/efiboot/conf.c index a7d10203bf3..1204987c8ea 100644 --- a/sys/arch/amd64/stand/efiboot/conf.c +++ b/sys/arch/amd64/stand/efiboot/conf.c @@ -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; diff --git a/sys/arch/amd64/stand/efiboot/efiboot.c b/sys/arch/amd64/stand/efiboot/efiboot.c index 95cf92d298d..b4ff8576201 100644 --- a/sys/arch/amd64/stand/efiboot/efiboot.c +++ b/sys/arch/amd64/stand/efiboot/efiboot.c @@ -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 @@ -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 */ diff --git a/sys/arch/amd64/stand/efiboot/efiboot.h b/sys/arch/amd64/stand/efiboot/efiboot.h index 725aebcccbd..8fdc5beb08d 100644 --- a/sys/arch/amd64/stand/efiboot/efiboot.h +++ b/sys/arch/amd64/stand/efiboot/efiboot.h @@ -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 @@ -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)); diff --git a/sys/lib/libsa/softraid.c b/sys/lib/libsa/softraid.c index d31c167e0e4..2dd0785674c 100644 --- a/sys/lib/libsa/softraid.c +++ b/sys/lib/libsa/softraid.c @@ -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 @@ -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') { -- 2.20.1