summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorJan Janssen <medhefgo@web.de>2015-04-03 18:03:06 +0200
committerLennart Poettering <lennart@poettering.net>2015-04-07 18:51:45 +0200
commit5bdf22430e367799dfa66c724144b624c5479518 (patch)
treef26c8dbe3b4395e1b1b5d33ad185c8b7e4fed0e3 /src/shared
parent3d1137ac2b196cee345ac70fcdac675af142c8dc (diff)
logind,systemctl: add reboot to EFI firmware support
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/efivars.c72
-rw-r--r--src/shared/efivars.h3
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);