efibc.c 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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. #define pr_fmt(fmt) "efibc: " fmt
  7. #include <linux/efi.h>
  8. #include <linux/module.h>
  9. #include <linux/reboot.h>
  10. #include <linux/slab.h>
  11. #include <linux/ucs2_string.h>
  12. #define MAX_DATA_LEN 512
  13. static int efibc_set_variable(efi_char16_t *name, efi_char16_t *value,
  14. unsigned long len)
  15. {
  16. efi_status_t status;
  17. status = efi.set_variable(name, &LINUX_EFI_LOADER_ENTRY_GUID,
  18. EFI_VARIABLE_NON_VOLATILE
  19. | EFI_VARIABLE_BOOTSERVICE_ACCESS
  20. | EFI_VARIABLE_RUNTIME_ACCESS,
  21. len * sizeof(efi_char16_t), value);
  22. if (status != EFI_SUCCESS) {
  23. pr_err("failed to set EFI variable: 0x%lx\n", status);
  24. return -EIO;
  25. }
  26. return 0;
  27. }
  28. static int efibc_reboot_notifier_call(struct notifier_block *notifier,
  29. unsigned long event, void *data)
  30. {
  31. efi_char16_t *reason = event == SYS_RESTART ? L"reboot"
  32. : L"shutdown";
  33. const u8 *str = data;
  34. efi_char16_t *wdata;
  35. unsigned long l;
  36. int ret;
  37. ret = efibc_set_variable(L"LoaderEntryRebootReason", reason,
  38. ucs2_strlen(reason));
  39. if (ret || !data)
  40. return NOTIFY_DONE;
  41. wdata = kmalloc(MAX_DATA_LEN * sizeof(efi_char16_t), GFP_KERNEL);
  42. if (!wdata)
  43. return NOTIFY_DONE;
  44. for (l = 0; l < MAX_DATA_LEN - 1 && str[l] != '\0'; l++)
  45. wdata[l] = str[l];
  46. wdata[l] = L'\0';
  47. efibc_set_variable(L"LoaderEntryOneShot", wdata, l);
  48. kfree(wdata);
  49. return NOTIFY_DONE;
  50. }
  51. static struct notifier_block efibc_reboot_notifier = {
  52. .notifier_call = efibc_reboot_notifier_call,
  53. };
  54. static int __init efibc_init(void)
  55. {
  56. int ret;
  57. if (!efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE))
  58. return -ENODEV;
  59. ret = register_reboot_notifier(&efibc_reboot_notifier);
  60. if (ret)
  61. pr_err("unable to register reboot notifier\n");
  62. return ret;
  63. }
  64. module_init(efibc_init);
  65. static void __exit efibc_exit(void)
  66. {
  67. unregister_reboot_notifier(&efibc_reboot_notifier);
  68. }
  69. module_exit(efibc_exit);
  70. MODULE_AUTHOR("Jeremy Compostella <[email protected]>");
  71. MODULE_AUTHOR("Matt Gumbel <[email protected]");
  72. MODULE_DESCRIPTION("EFI Bootloader Control");
  73. MODULE_LICENSE("GPL v2");