efi.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Functions shared by the app and stub
  4. *
  5. * Copyright (c) 2015 Google, Inc
  6. *
  7. * EFI information obtained here:
  8. * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES
  9. *
  10. * Common EFI functions
  11. */
  12. #include <common.h>
  13. #include <debug_uart.h>
  14. #include <errno.h>
  15. #include <malloc.h>
  16. #include <linux/err.h>
  17. #include <linux/types.h>
  18. #include <efi.h>
  19. #include <efi_api.h>
  20. static struct efi_priv *global_priv;
  21. struct efi_priv *efi_get_priv(void)
  22. {
  23. return global_priv;
  24. }
  25. void efi_set_priv(struct efi_priv *priv)
  26. {
  27. global_priv = priv;
  28. }
  29. struct efi_system_table *efi_get_sys_table(void)
  30. {
  31. return global_priv->sys_table;
  32. }
  33. struct efi_boot_services *efi_get_boot(void)
  34. {
  35. return global_priv->boot;
  36. }
  37. unsigned long efi_get_ram_base(void)
  38. {
  39. return global_priv->ram_base;
  40. }
  41. /*
  42. * Global declaration of gd.
  43. *
  44. * As we write to it before relocation we have to make sure it is not put into
  45. * a .bss section which may overlap a .rela section. Initialization forces it
  46. * into a .data section which cannot overlap any .rela section.
  47. */
  48. struct global_data *global_data_ptr = (struct global_data *)~0;
  49. /*
  50. * Unfortunately we cannot access any code outside what is built especially
  51. * for the stub. lib/string.c is already being built for the U-Boot payload
  52. * so it uses the wrong compiler flags. Add our own memset() here.
  53. */
  54. static void efi_memset(void *ptr, int ch, int size)
  55. {
  56. char *dest = ptr;
  57. while (size-- > 0)
  58. *dest++ = ch;
  59. }
  60. /*
  61. * Since the EFI stub cannot access most of the U-Boot code, add our own
  62. * simple console output functions here. The EFI app will not use these since
  63. * it can use the normal console.
  64. */
  65. void efi_putc(struct efi_priv *priv, const char ch)
  66. {
  67. struct efi_simple_text_output_protocol *con = priv->sys_table->con_out;
  68. uint16_t ucode[2];
  69. ucode[0] = ch;
  70. ucode[1] = '\0';
  71. con->output_string(con, ucode);
  72. }
  73. void efi_puts(struct efi_priv *priv, const char *str)
  74. {
  75. while (*str)
  76. efi_putc(priv, *str++);
  77. }
  78. int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image,
  79. struct efi_system_table *sys_table)
  80. {
  81. efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
  82. struct efi_boot_services *boot = sys_table->boottime;
  83. struct efi_loaded_image *loaded_image;
  84. int ret;
  85. efi_memset(priv, '\0', sizeof(*priv));
  86. priv->sys_table = sys_table;
  87. priv->boot = sys_table->boottime;
  88. priv->parent_image = image;
  89. priv->run = sys_table->runtime;
  90. efi_puts(priv, "U-Boot EFI ");
  91. efi_puts(priv, banner);
  92. efi_putc(priv, ' ');
  93. ret = boot->open_protocol(priv->parent_image, &loaded_image_guid,
  94. (void **)&loaded_image, priv->parent_image,
  95. NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  96. if (ret) {
  97. efi_puts(priv, "Failed to get loaded image protocol\n");
  98. return ret;
  99. }
  100. priv->image_data_type = loaded_image->image_data_type;
  101. return 0;
  102. }
  103. void *efi_malloc(struct efi_priv *priv, int size, efi_status_t *retp)
  104. {
  105. struct efi_boot_services *boot = priv->boot;
  106. void *buf = NULL;
  107. *retp = boot->allocate_pool(priv->image_data_type, size, &buf);
  108. return buf;
  109. }
  110. void efi_free(struct efi_priv *priv, void *ptr)
  111. {
  112. struct efi_boot_services *boot = priv->boot;
  113. boot->free_pool(ptr);
  114. }
  115. int efi_store_memory_map(struct efi_priv *priv)
  116. {
  117. struct efi_boot_services *boot = priv->sys_table->boottime;
  118. efi_uintn_t size, desc_size;
  119. efi_status_t ret;
  120. /* Get the memory map so we can switch off EFI */
  121. size = 0;
  122. ret = boot->get_memory_map(&size, NULL, &priv->memmap_key,
  123. &priv->memmap_desc_size,
  124. &priv->memmap_version);
  125. if (ret != EFI_BUFFER_TOO_SMALL) {
  126. /*
  127. * Note this function avoids using printf() since it is not
  128. * available in the stub
  129. */
  130. printhex2(EFI_BITS_PER_LONG);
  131. putc(' ');
  132. printhex2(ret);
  133. puts(" No memory map\n");
  134. return ret;
  135. }
  136. /*
  137. * Since doing a malloc() may change the memory map and also we want to
  138. * be able to read the memory map in efi_call_exit_boot_services()
  139. * below, after more changes have happened
  140. */
  141. priv->memmap_alloc = size + 1024;
  142. priv->memmap_size = priv->memmap_alloc;
  143. priv->memmap_desc = efi_malloc(priv, size, &ret);
  144. if (!priv->memmap_desc) {
  145. printhex2(ret);
  146. puts(" No memory for memory descriptor\n");
  147. return ret;
  148. }
  149. ret = boot->get_memory_map(&priv->memmap_size, priv->memmap_desc,
  150. &priv->memmap_key, &desc_size,
  151. &priv->memmap_version);
  152. if (ret) {
  153. printhex2(ret);
  154. puts(" Can't get memory map\n");
  155. return ret;
  156. }
  157. return 0;
  158. }
  159. int efi_call_exit_boot_services(void)
  160. {
  161. struct efi_priv *priv = efi_get_priv();
  162. const struct efi_boot_services *boot = priv->boot;
  163. efi_uintn_t size;
  164. u32 version;
  165. efi_status_t ret;
  166. size = priv->memmap_alloc;
  167. ret = boot->get_memory_map(&size, priv->memmap_desc,
  168. &priv->memmap_key,
  169. &priv->memmap_desc_size, &version);
  170. if (ret) {
  171. printhex2(ret);
  172. puts(" Can't get memory map\n");
  173. return ret;
  174. }
  175. ret = boot->exit_boot_services(priv->parent_image, priv->memmap_key);
  176. if (ret)
  177. return ret;
  178. return 0;
  179. }