^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * efibc: control EFI bootloaders which obey LoaderEntryOneShot var
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2013-2016, Intel Corporation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #define pr_fmt(fmt) "efibc: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/efi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) static void efibc_str_to_str16(const char *str, efi_char16_t *str16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) for (i = 0; i < strlen(str); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) str16[i] = str[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) str16[i] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static int efibc_set_variable(const char *name, const char *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) efi_guid_t guid = LINUX_EFI_LOADER_ENTRY_GUID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct efivar_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) size_t size = (strlen(value) + 1) * sizeof(efi_char16_t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) if (size > sizeof(entry->var.Data)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) pr_err("value is too large (%zu bytes) for '%s' EFI variable\n", size, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) entry = kmalloc(sizeof(*entry), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (!entry) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) pr_err("failed to allocate efivar entry for '%s' EFI variable\n", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) efibc_str_to_str16(name, entry->var.VariableName);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) efibc_str_to_str16(value, (efi_char16_t *)entry->var.Data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) memcpy(&entry->var.VendorGuid, &guid, sizeof(guid));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) ret = efivar_entry_set_safe(entry->var.VariableName,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) entry->var.VendorGuid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) EFI_VARIABLE_NON_VOLATILE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) | EFI_VARIABLE_BOOTSERVICE_ACCESS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) | EFI_VARIABLE_RUNTIME_ACCESS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) false, size, entry->var.Data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) pr_err("failed to set %s EFI variable: 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) kfree(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static int efibc_reboot_notifier_call(struct notifier_block *notifier,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) unsigned long event, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) const char *reason = "shutdown";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (event == SYS_RESTART)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) reason = "reboot";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ret = efibc_set_variable("LoaderEntryRebootReason", reason);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (ret || !data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) efibc_set_variable("LoaderEntryOneShot", (char *)data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static struct notifier_block efibc_reboot_notifier = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) .notifier_call = efibc_reboot_notifier_call,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static int __init efibc_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (!efivars_kobject() || !efivar_supports_writes())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ret = register_reboot_notifier(&efibc_reboot_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) pr_err("unable to register reboot notifier\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) module_init(efibc_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static void __exit efibc_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) unregister_reboot_notifier(&efibc_reboot_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) module_exit(efibc_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) MODULE_AUTHOR("Jeremy Compostella <jeremy.compostella@intel.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) MODULE_AUTHOR("Matt Gumbel <matthew.k.gumbel@intel.com");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) MODULE_DESCRIPTION("EFI Bootloader Control");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) MODULE_LICENSE("GPL v2");