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 EFIAPI efi_main(efi_handle_t image, 100 struct efi_system_table *sys_table) 101 { 102 struct efi_priv local_priv, *priv = &local_priv; 103 efi_status_t ret; 104 105 /* Set up access to EFI data structures */ 106 efi_init(priv, "App", image, sys_table); 107 108 global_priv = priv; 109 110 /* 111 * Set up the EFI debug UART so that printf() works. This is 112 * implemented in the EFI serial driver, serial_efi.c. The application 113 * can use printf() freely. 114 */ 115 debug_uart_init(); 116 117 ret = setup_memory(priv); 118 if (ret) { 119 printf("Failed to set up memory: ret=%lx\n", ret); 120 return ret; 121 } 122 123 printf("starting\n"); 124 125 board_init_f(GD_FLG_SKIP_RELOC); 126 board_init_r(NULL, 0); 127 free_memory(priv); 128 129 return EFI_SUCCESS; 130 } 131 132 void reset_cpu(ulong addr) 133 { 134 struct efi_priv *priv = global_priv; 135 136 free_memory(priv); 137 printf("U-Boot EFI exiting\n"); 138 priv->boot->exit(priv->parent_image, EFI_SUCCESS, 0, NULL); 139 } 140