[systemd-devel] [PATCH v2] Add reboot to EFI support

Dimitri John Ledkov dimitri.j.ledkov at intel.com
Mon Mar 30 03:20:23 PDT 2015


I like this. +1

On 26 March 2015 at 15:09, Jan Janssen <medhefgo at web.de> wrote:
> ---
>  man/systemctl.xml                         |  6 +++-
>  src/libsystemd/sd-bus/bus-common-errors.h |  1 +
>  src/login/logind-dbus.c                   | 49 +++++++++++++++++++++++++++--
>  src/login/org.freedesktop.login1.conf     |  8 +++++
>  src/shared/efivars.c                      | 52 +++++++++++++++++++++++++++++++
>  src/shared/efivars.h                      |  2 ++
>  src/systemctl/systemctl.c                 | 16 ++++++++--
>  7 files changed, 127 insertions(+), 7 deletions(-)
>
> diff --git a/man/systemctl.xml b/man/systemctl.xml
> index 50e6bc9..eafdd73 100644
> --- a/man/systemctl.xml
> +++ b/man/systemctl.xml
> @@ -1538,7 +1538,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
>              systems. This may result in data loss.</para>
>
>              <para>If the optional argument
> -            <replaceable>arg</replaceable> is given, it will be passed
> +            <replaceable>arg</replaceable> is given and is equal to
> +            <literal>efi</literal>, the system will be rebooted to
> +            the EFI firmware interface on machines that support it.
> +            Note that this requires the system to be booted in EFI mode.
> +            Otherwise, the argument will be passed
>              as the optional argument to the
>              <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
>              system call. The value is architecture and firmware
> diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h
> index b17b62a..3019140 100644
> --- a/src/libsystemd/sd-bus/bus-common-errors.h
> +++ b/src/libsystemd/sd-bus/bus-common-errors.h
> @@ -57,6 +57,7 @@
>  #define BUS_ERROR_DEVICE_IS_TAKEN "org.freedesktop.login1.DeviceIsTaken"
>  #define BUS_ERROR_DEVICE_NOT_TAKEN "org.freedesktop.login1.DeviceNotTaken"
>  #define BUS_ERROR_OPERATION_IN_PROGRESS "org.freedesktop.login1.OperationInProgress"
> +#define BUS_ERROR_REBOOT_TO_EFI_NOT_SUPPORTED "org.freedesktop.login1.RebootToEfiNotSupported"
>  #define BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED "org.freedesktop.login1.SleepVerbNotSupported"
>
>  #define BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED "org.freedesktop.timedate1.AutomaticTimeSyncEnabled"
> diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
> index a3d49ef..8fec90f 100644
> --- a/src/login/logind-dbus.c
> +++ b/src/login/logind-dbus.c
> @@ -38,8 +38,11 @@
>  #include "bus-common-errors.h"
>  #include "udev-util.h"
>  #include "selinux-util.h"
> +#include "efivars.h"
>  #include "logind.h"
>
> +#define SPECIAL_REBOOT_TO_EFI_TARGET "x-logind-reboot-to-efi.target"
> +
>  int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
>          _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
>          Session *session;
> @@ -1422,6 +1425,13 @@ static int execute_shutdown_or_sleep(
>          assert(w < _INHIBIT_WHAT_MAX);
>          assert(unit_name);
>
> +        if (streq(unit_name, SPECIAL_REBOOT_TO_EFI_TARGET)) {
> +                unit_name = SPECIAL_REBOOT_TARGET;
> +                r = efi_indicate_reboot_to_fw();
> +                if (r < 0)
> +                        return r;
> +        }
> +
>          bus_manager_log_shutdown(m, w, unit_name);
>
>          r = sd_bus_call_method(
> @@ -1563,6 +1573,9 @@ static int method_do_shutdown_or_sleep(
>          if (m->action_what)
>                  return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
>
> +        if (streq(unit_name, SPECIAL_REBOOT_TO_EFI_TARGET) && !is_efi_reboot_to_fw_supported())
> +                return sd_bus_error_setf(error, BUS_ERROR_REBOOT_TO_EFI_NOT_SUPPORTED, "Reboot to EFI not supported");
> +
>          if (sleep_verb) {
>                  r = can_sleep(sleep_verb);
>                  if (r < 0)
> @@ -1648,6 +1661,21 @@ static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, s
>                          error);
>  }
>
> +static int method_reboot_to_efi(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
> +        Manager *m = userdata;
> +
> +        return method_do_shutdown_or_sleep(
> +                        m, message,
> +                        SPECIAL_REBOOT_TO_EFI_TARGET,
> +                        INHIBIT_SHUTDOWN,
> +                        "org.freedesktop.login1.reboot",
> +                        "org.freedesktop.login1.reboot-multiple-sessions",
> +                        "org.freedesktop.login1.reboot-ignore-inhibit",
> +                        NULL,
> +                        method_reboot_to_efi,
> +                        error);
> +}
> +
>  static int method_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
>          Manager *m = userdata;
>
> @@ -1700,7 +1728,7 @@ static int method_can_shutdown_or_sleep(
>                  const char *action,
>                  const char *action_multiple_sessions,
>                  const char *action_ignore_inhibit,
> -                const char *sleep_verb,
> +                const char *arg,
>                  sd_bus_error *error) {
>
>          _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
> @@ -1717,8 +1745,8 @@ static int method_can_shutdown_or_sleep(
>          assert(action_multiple_sessions);
>          assert(action_ignore_inhibit);
>
> -        if (sleep_verb) {
> -                r = can_sleep(sleep_verb);
> +        if (arg) {
> +                r = streq(arg, "reboot-to-efi") ? is_efi_reboot_to_fw_supported() : can_sleep(arg);
>                  if (r < 0)
>                          return r;
>                  if (r == 0)
> @@ -1811,6 +1839,19 @@ static int method_can_reboot(sd_bus *bus, sd_bus_message *message, void *userdat
>                          error);
>  }
>
> +static int method_can_reboot_to_efi(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
> +        Manager *m = userdata;
> +
> +        return method_can_shutdown_or_sleep(
> +                        m, message,
> +                        INHIBIT_SHUTDOWN,
> +                        "org.freedesktop.login1.reboot",
> +                        "org.freedesktop.login1.reboot-multiple-sessions",
> +                        "org.freedesktop.login1.reboot-ignore-inhibit",
> +                        "reboot-to-efi",
> +                        error);
> +}
> +
>  static int method_can_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
>          Manager *m = userdata;
>
> @@ -2014,11 +2055,13 @@ const sd_bus_vtable manager_vtable[] = {
>          SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED),
>          SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
>          SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
> +        SD_BUS_METHOD("RebootToEfi", "b", NULL, method_reboot_to_efi, SD_BUS_VTABLE_UNPRIVILEGED),
>          SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
>          SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
>          SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
>          SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
>          SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
> +        SD_BUS_METHOD("CanRebootToEfi", NULL, "s", method_can_reboot_to_efi, SD_BUS_VTABLE_UNPRIVILEGED),
>          SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
>          SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
>          SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
> diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
> index 1318328..7ea3014 100644
> --- a/src/login/org.freedesktop.login1.conf
> +++ b/src/login/org.freedesktop.login1.conf
> @@ -98,6 +98,10 @@
>
>                  <allow send_destination="org.freedesktop.login1"
>                         send_interface="org.freedesktop.login1.Manager"
> +                       send_member="RebootToEfi"/>
> +
> +                <allow send_destination="org.freedesktop.login1"
> +                       send_interface="org.freedesktop.login1.Manager"
>                         send_member="Suspend"/>
>
>                  <allow send_destination="org.freedesktop.login1"
> @@ -118,6 +122,10 @@
>
>                  <allow send_destination="org.freedesktop.login1"
>                         send_interface="org.freedesktop.login1.Manager"
> +                       send_member="CanRebootToEfi"/>
> +
> +                <allow send_destination="org.freedesktop.login1"
> +                       send_interface="org.freedesktop.login1.Manager"
>                         send_member="CanSuspend"/>
>
>                  <allow send_destination="org.freedesktop.login1"
> diff --git a/src/shared/efivars.c b/src/shared/efivars.c
> index 20067c6..ea80d6b 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,56 @@ int is_efi_secure_boot_setup_mode(void) {
>          return read_flag("SetupMode");
>  }
>
> +bool is_efi_reboot_to_fw_supported(void) {
> +        int r;
> +        size_t s;
> +        uint64_t b;
> +        _cleanup_free_ void *v = NULL;
> +
> +        if (!is_efi_boot() || detect_container(NULL) > 0)
> +                return false;
> +
> +        r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s);
> +        if (r < 0 || s != sizeof(uint64_t))
> +                return false;
> +
> +        b = *(uint64_t *)v;
> +        return !!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
> +}
> +
> +int efi_indicate_reboot_to_fw(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;
> +        if (!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
> +                return -EOPNOTSUPP;
> +
> +        free(v);
> +        v = NULL;
> +        r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", 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;
> +        r = efi_set_variable(EFI_VENDOR_GLOBAL, "OsIndications", &b, s);
> +        return r;
> +}
> +
>  int efi_get_variable(
>                  sd_id128_t vendor,
>                  const char *name,
> diff --git a/src/shared/efivars.h b/src/shared/efivars.h
> index 2492893..5c1e28f 100644
> --- a/src/shared/efivars.h
> +++ b/src/shared/efivars.h
> @@ -35,6 +35,8 @@
>  bool is_efi_boot(void);
>  int is_efi_secure_boot(void);
>  int is_efi_secure_boot_setup_mode(void);
> +bool is_efi_reboot_to_fw_supported(void);
> +int efi_indicate_reboot_to_fw(void);
>
>  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);
> diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
> index 3158a38..372542b 100644
> --- a/src/systemctl/systemctl.c
> +++ b/src/systemctl/systemctl.c
> @@ -68,6 +68,7 @@
>  #include "bus-common-errors.h"
>  #include "mkdir.h"
>  #include "dropin.h"
> +#include "efivars.h"
>
>  static char **arg_types = NULL;
>  static char **arg_states = NULL;
> @@ -2929,9 +2930,18 @@ static int start_special(sd_bus *bus, char **args) {
>          }
>
>          if (a == ACTION_REBOOT && args[1]) {
> -                r = update_reboot_param_file(args[1]);
> -                if (r < 0)
> -                        return r;
> +                if (streq(args[1], "efi")) {
> +                        if (!is_efi_reboot_to_fw_supported())
> +                                return log_error_errno(EOPNOTSUPP, "Reboot to EFI not supported.");
> +
> +                        r = efi_indicate_reboot_to_fw();
> +                        if (r < 0)
> +                                return log_error_errno(r, "Failed to indicate reboot to EFI: %m");
> +                } else {
> +                        r = update_reboot_param_file(args[1]);
> +                        if (r < 0)
> +                                return r;
> +                }
>          }
>
>          if (arg_force >= 2 &&
> --
> 2.3.4
>
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel



-- 
Regards,

Dimitri.

https://clearlinux.org
Open Source Technology Center
Intel Corporation (UK) Ltd. - Co. Reg. #1134945 - Pipers Way, Swindon SN3 1RJ.


More information about the systemd-devel mailing list