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