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 11 #include <common.h> 12 #include <debug_uart.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 19 DECLARE_GLOBAL_DATA_PTR; 20 21 static struct efi_priv *global_priv; 22 23 struct efi_system_table *efi_get_sys_table(void) 24 { 25 return global_priv->sys_table; 26 } 27 28 unsigned long efi_get_ram_base(void) 29 { 30 return global_priv->ram_base; 31 } 32 33 static efi_status_t setup_memory(struct efi_priv *priv) 34 { 35 struct efi_boot_services *boot = priv->boot; 36 efi_physical_addr_t addr; 37 efi_status_t ret; 38 int pages; 39 40 /* 41 * Use global_data_ptr instead of gd since it is an assignment. There 42 * are very few assignments to global_data in U-Boot and this makes 43 * it easier to find them. 44 */ 45 global_data_ptr = efi_malloc(priv, sizeof(struct global_data), &ret); 46 if (!global_data_ptr) 47 return ret; 48 memset(gd, '\0', sizeof(*gd)); 49 50 gd->malloc_base = (ulong)efi_malloc(priv, CONFIG_VAL(SYS_MALLOC_F_LEN), 51 &ret); 52 if (!gd->malloc_base) 53 return ret; 54 pages = CONFIG_EFI_RAM_SIZE >> 12; 55 56 /* 57 * Don't allocate any memory above 4GB. U-Boot is a 32-bit application 58 * so we want it to load below 4GB. 59 */ 60 addr = 1ULL << 32; 61 ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, 62 priv->image_data_type, pages, &addr); 63 if (ret) { 64 printf("(using pool %lx) ", ret); 65 priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE, 66 &ret); 67 if (!priv->ram_base) 68 return ret; 69 priv->use_pool_for_malloc = true; 70 } else { 71 priv->ram_base = addr; 72 } 73 gd->ram_size = pages << 12; 74 75 return 0; 76 } 77 78 static void free_memory(struct efi_priv *priv) 79 { 80 struct efi_boot_services *boot = priv->boot; 81 82 if (priv->use_pool_for_malloc) 83 efi_free(priv, (void *)priv->ram_base); 84 else 85 boot->free_pages(priv->ram_base, gd->ram_size >> 12); 86 87 efi_free(priv, (void *)gd->malloc_base); 88 efi_free(priv, gd); 89 global_data_ptr = NULL; 90 } 91 92 /** 93 * efi_main() - Start an EFI image 94 * 95 * This function is called by our EFI start-up code. It handles running 96 * U-Boot. If it returns, EFI will continue. Another way to get back to EFI 97 * is via reset_cpu(). 98 */ 99 efi_status_t efi_main(efi_handle_t image, struct efi_system_table *sys_table) 100 { 101 struct efi_priv local_priv, *priv = &local_priv; 102 efi_status_t ret; 103 104 /* Set up access to EFI data structures */ 105 efi_init(priv, "App", image, sys_table); 106 107 global_priv = priv; 108 109 /* 110 * Set up the EFI debug UART so that printf() works. This is 111 * implemented in the EFI serial driver, serial_efi.c. The application 112 * can use printf() freely. 113 */ 114 debug_uart_init(); 115 116 ret = setup_memory(priv); 117 if (ret) { 118 printf("Failed to set up memory: ret=%lx\n", ret); 119 return ret; 120 } 121 122 printf("starting\n"); 123 124 board_init_f(GD_FLG_SKIP_RELOC); 125 board_init_r(NULL, 0); 126 free_memory(priv); 127 128 return EFI_SUCCESS; 129 } 130 131 void reset_cpu(ulong addr) 132 { 133 struct efi_priv *priv = global_priv; 134 135 free_memory(priv); 136 printf("U-Boot EFI exiting\n"); 137 priv->boot->exit(priv->parent_image, EFI_SUCCESS, 0, NULL); 138 } 139