efi_selftest_exitbootservices.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * efi_selftest_exitbootservices
  4. *
  5. * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
  6. *
  7. * This unit test checks that the notification function of an
  8. * EVT_SIGNAL_EXIT_BOOT_SERVICES event is called exactly once.
  9. */
  10. #include <efi_selftest.h>
  11. static efi_guid_t guid_before_exit_boot_services =
  12. EFI_GUID(0x8be0e274, 0x3970, 0x4b44, 0x80, 0xc5,
  13. 0x1a, 0xb9, 0x50, 0x2f, 0x3b, 0xfc);
  14. #define CAPACITY 4
  15. struct notification_record {
  16. unsigned int count;
  17. unsigned int type[CAPACITY];
  18. };
  19. struct notification_context {
  20. struct notification_record *record;
  21. unsigned int type;
  22. };
  23. static struct efi_boot_services *boottime;
  24. static struct efi_event *efi_st_event_notify;
  25. static struct notification_record record;
  26. struct notification_context context_before = {
  27. .record = &record,
  28. .type = 1,
  29. };
  30. struct notification_context context = {
  31. .record = &record,
  32. .type = 2,
  33. };
  34. /*
  35. * Notification function, increments the notification count.
  36. *
  37. * @event notified event
  38. * @context pointer to the notification count
  39. */
  40. static void EFIAPI ebs_notify(struct efi_event *event, void *context)
  41. {
  42. struct notification_context *ctx = context;
  43. if (ctx->record->count >= CAPACITY)
  44. return;
  45. ctx->record->type[ctx->record->count] = ctx->type;
  46. ctx->record->count++;
  47. }
  48. /*
  49. * Setup unit test.
  50. *
  51. * Create an EVT_SIGNAL_EXIT_BOOT_SERVICES event.
  52. *
  53. * @handle: handle of the loaded image
  54. * @systable: system table
  55. * Return: EFI_ST_SUCCESS for success
  56. */
  57. static int setup(const efi_handle_t handle,
  58. const struct efi_system_table *systable)
  59. {
  60. efi_status_t ret;
  61. boottime = systable->boottime;
  62. ret = boottime->create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES,
  63. TPL_CALLBACK, ebs_notify,
  64. &context,
  65. &efi_st_event_notify);
  66. if (ret != EFI_SUCCESS) {
  67. efi_st_error("could not create event\n");
  68. return EFI_ST_FAILURE;
  69. }
  70. ret = boottime->create_event_ex(0, TPL_CALLBACK, ebs_notify,
  71. &context_before,
  72. &guid_before_exit_boot_services,
  73. &efi_st_event_notify);
  74. if (ret != EFI_SUCCESS) {
  75. efi_st_error("could not create event\n");
  76. return EFI_ST_FAILURE;
  77. }
  78. return EFI_ST_SUCCESS;
  79. }
  80. /*
  81. * Execute unit test.
  82. *
  83. * Check that the notification function of the EVT_SIGNAL_EXIT_BOOT_SERVICES
  84. * event has been called.
  85. *
  86. * Call ExitBootServices again and check that the notification function is
  87. * not called again.
  88. *
  89. * Return: EFI_ST_SUCCESS for success
  90. */
  91. static int execute(void)
  92. {
  93. if (record.count != 2) {
  94. efi_st_error("Incorrect event count %u\n", record.count);
  95. return EFI_ST_FAILURE;
  96. }
  97. if (record.type[0] != 1) {
  98. efi_st_error("EFI_GROUP_BEFORE_EXIT_BOOT_SERVICE not notified\n");
  99. return EFI_ST_FAILURE;
  100. }
  101. if (record.type[1] != 2) {
  102. efi_st_error("EVT_SIGNAL_EXIT_BOOT_SERVICES was not notified\n");
  103. return EFI_ST_FAILURE;
  104. }
  105. efi_st_exit_boot_services();
  106. if (record.count != 2) {
  107. efi_st_error("Incorrect event count %u\n", record.count);
  108. return EFI_ST_FAILURE;
  109. }
  110. return EFI_ST_SUCCESS;
  111. }
  112. EFI_UNIT_TEST(exitbootservices) = {
  113. .name = "ExitBootServices",
  114. .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
  115. .setup = setup,
  116. .execute = execute,
  117. };