efi_app.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2015 Google, Inc
  4. *
  5. * EFI information obtained here:
  6. * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES
  7. *
  8. * This file implements U-Boot running as an EFI application.
  9. */
  10. #include <common.h>
  11. #include <debug_uart.h>
  12. #include <dm.h>
  13. #include <errno.h>
  14. #include <linux/err.h>
  15. #include <linux/types.h>
  16. #include <efi.h>
  17. #include <efi_api.h>
  18. #include <sysreset.h>
  19. DECLARE_GLOBAL_DATA_PTR;
  20. static struct efi_priv *global_priv;
  21. struct efi_system_table *efi_get_sys_table(void)
  22. {
  23. return global_priv->sys_table;
  24. }
  25. unsigned long efi_get_ram_base(void)
  26. {
  27. return global_priv->ram_base;
  28. }
  29. static efi_status_t setup_memory(struct efi_priv *priv)
  30. {
  31. struct efi_boot_services *boot = priv->boot;
  32. efi_physical_addr_t addr;
  33. efi_status_t ret;
  34. int pages;
  35. /*
  36. * Use global_data_ptr instead of gd since it is an assignment. There
  37. * are very few assignments to global_data in U-Boot and this makes
  38. * it easier to find them.
  39. */
  40. global_data_ptr = efi_malloc(priv, sizeof(struct global_data), &ret);
  41. if (!global_data_ptr)
  42. return ret;
  43. memset(gd, '\0', sizeof(*gd));
  44. gd->malloc_base = (ulong)efi_malloc(priv, CONFIG_VAL(SYS_MALLOC_F_LEN),
  45. &ret);
  46. if (!gd->malloc_base)
  47. return ret;
  48. pages = CONFIG_EFI_RAM_SIZE >> 12;
  49. /*
  50. * Don't allocate any memory above 4GB. U-Boot is a 32-bit application
  51. * so we want it to load below 4GB.
  52. */
  53. addr = 1ULL << 32;
  54. ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
  55. priv->image_data_type, pages, &addr);
  56. if (ret) {
  57. printf("(using pool %lx) ", ret);
  58. priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE,
  59. &ret);
  60. if (!priv->ram_base)
  61. return ret;
  62. priv->use_pool_for_malloc = true;
  63. } else {
  64. priv->ram_base = addr;
  65. }
  66. gd->ram_size = pages << 12;
  67. return 0;
  68. }
  69. static void free_memory(struct efi_priv *priv)
  70. {
  71. struct efi_boot_services *boot = priv->boot;
  72. if (priv->use_pool_for_malloc)
  73. efi_free(priv, (void *)priv->ram_base);
  74. else
  75. boot->free_pages(priv->ram_base, gd->ram_size >> 12);
  76. efi_free(priv, (void *)gd->malloc_base);
  77. efi_free(priv, gd);
  78. global_data_ptr = NULL;
  79. }
  80. /**
  81. * efi_main() - Start an EFI image
  82. *
  83. * This function is called by our EFI start-up code. It handles running
  84. * U-Boot. If it returns, EFI will continue. Another way to get back to EFI
  85. * is via reset_cpu().
  86. */
  87. efi_status_t EFIAPI efi_main(efi_handle_t image,
  88. struct efi_system_table *sys_table)
  89. {
  90. struct efi_priv local_priv, *priv = &local_priv;
  91. efi_status_t ret;
  92. /* Set up access to EFI data structures */
  93. efi_init(priv, "App", image, sys_table);
  94. global_priv = priv;
  95. /*
  96. * Set up the EFI debug UART so that printf() works. This is
  97. * implemented in the EFI serial driver, serial_efi.c. The application
  98. * can use printf() freely.
  99. */
  100. debug_uart_init();
  101. ret = setup_memory(priv);
  102. if (ret) {
  103. printf("Failed to set up memory: ret=%lx\n", ret);
  104. return ret;
  105. }
  106. printf("starting\n");
  107. board_init_f(GD_FLG_SKIP_RELOC);
  108. board_init_r(NULL, 0);
  109. free_memory(priv);
  110. return EFI_SUCCESS;
  111. }
  112. static void efi_exit(void)
  113. {
  114. struct efi_priv *priv = global_priv;
  115. free_memory(priv);
  116. printf("U-Boot EFI exiting\n");
  117. priv->boot->exit(priv->parent_image, EFI_SUCCESS, 0, NULL);
  118. }
  119. static int efi_sysreset_request(struct udevice *dev, enum sysreset_t type)
  120. {
  121. efi_exit();
  122. return -EINPROGRESS;
  123. }
  124. static const struct udevice_id efi_sysreset_ids[] = {
  125. { .compatible = "efi,reset" },
  126. { }
  127. };
  128. static struct sysreset_ops efi_sysreset_ops = {
  129. .request = efi_sysreset_request,
  130. };
  131. U_BOOT_DRIVER(efi_sysreset) = {
  132. .name = "efi-sysreset",
  133. .id = UCLASS_SYSRESET,
  134. .of_match = efi_sysreset_ids,
  135. .ops = &efi_sysreset_ops,
  136. };