diff options
author | Jan Janssen <medhefgo@web.de> | 2015-04-03 18:03:06 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-04-07 18:51:45 +0200 |
commit | 5bdf22430e367799dfa66c724144b624c5479518 (patch) | |
tree | f26c8dbe3b4395e1b1b5d33ad185c8b7e4fed0e3 /src/shared | |
parent | 3d1137ac2b196cee345ac70fcdac675af142c8dc (diff) |
logind,systemctl: add reboot to EFI firmware support
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/efivars.c | 72 | ||||
-rw-r--r-- | src/shared/efivars.h | 3 |
2 files changed, 75 insertions, 0 deletions
diff --git a/src/shared/efivars.c b/src/shared/efivars.c index 20067c601a..b82f74a459 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -25,6 +25,7 @@ #include "util.h" #include "utf8.h" +#include "virt.h" #include "efivars.h" #ifdef ENABLE_EFI @@ -37,6 +38,7 @@ #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02 #define END_DEVICE_PATH_TYPE 0x7f #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff +#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001 struct boot_option { uint32_t attr; @@ -93,6 +95,76 @@ int is_efi_secure_boot_setup_mode(void) { return read_flag("SetupMode"); } +int efi_reboot_to_firmware_supported(void) { + int r; + size_t s; + uint64_t b; + _cleanup_free_ void *v = NULL; + + if (!is_efi_boot() || detect_container(NULL) > 0) + return -EOPNOTSUPP; + + r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s); + if (r < 0) + return r; + else if (s != sizeof(uint64_t)) + return -EINVAL; + + b = *(uint64_t *)v; + b &= EFI_OS_INDICATIONS_BOOT_TO_FW_UI; + return b > 0 ? 0 : -EOPNOTSUPP; +} + +static int get_os_indications(uint64_t *os_indication) { + int r; + size_t s; + _cleanup_free_ void *v = NULL; + + r = efi_reboot_to_firmware_supported(); + if (r < 0) + return r; + + r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s); + if (r < 0) + return r; + else if (s != sizeof(uint64_t)) + return -EINVAL; + + *os_indication = *(uint64_t *)v; + return 0; +} + +int efi_get_reboot_to_firmware(void) { + int r; + uint64_t b; + + r = get_os_indications(&b); + if (r < 0) + return r; + + return !!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI); +} + +int efi_set_reboot_to_firmware(bool value) { + int r; + uint64_t b, b_new; + + r = get_os_indications(&b); + if (r < 0) + return r; + + if (value) + b_new = b | EFI_OS_INDICATIONS_BOOT_TO_FW_UI; + else + b_new = b & ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI; + + /* Avoid writing to efi vars store if we can due to firmware bugs. */ + if (b != b_new) + return efi_set_variable(EFI_VENDOR_GLOBAL, "OsIndications", &b_new, sizeof(uint64_t)); + + return 0; +} + int efi_get_variable( sd_id128_t vendor, const char *name, diff --git a/src/shared/efivars.h b/src/shared/efivars.h index 2492893718..e796bf415d 100644 --- a/src/shared/efivars.h +++ b/src/shared/efivars.h @@ -35,6 +35,9 @@ bool is_efi_boot(void); int is_efi_secure_boot(void); int is_efi_secure_boot_setup_mode(void); +int efi_reboot_to_firmware_supported(void); +int efi_get_reboot_to_firmware(void); +int efi_set_reboot_to_firmware(bool value); int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size); int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size); |