1 /* 2 * Copyright (c) 2015 Google, Inc 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 * 6 * EFI information obtained here: 7 * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES 8 * 9 * This file implements U-Boot running as an EFI application. 10 */ 11 12 #include <common.h> 13 #include <debug_uart.h> 14 #include <errno.h> 15 #include <linux/err.h> 16 #include <linux/types.h> 17 #include <efi.h> 18 #include <efi_api.h> 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 static struct efi_priv *global_priv; 23 24 struct efi_system_table *efi_get_sys_table(void) 25 { 26 return global_priv->sys_table; 27 } 28 29 unsigned long efi_get_ram_base(void) 30 { 31 return global_priv->ram_base; 32 } 33 34 static efi_status_t setup_memory(struct efi_priv *priv) 35 { 36 struct efi_boot_services *boot = priv->boot; 37 efi_physical_addr_t addr; 38 efi_status_t ret; 39 int pages; 40 41 /* 42 * Use global_data_ptr instead of gd since it is an assignment. There 43 * are very few assignments to global_data in U-Boot and this makes 44 * it easier to find them. 45 */ 46 global_data_ptr = efi_malloc(priv, sizeof(struct global_data), &ret); 47 if (!global_data_ptr) 48 return ret; 49 memset(gd, '\0', sizeof(*gd)); 50 51 gd->malloc_base = (ulong)efi_malloc(priv, CONFIG_SYS_MALLOC_F_LEN, 52 &ret); 53 if (!gd->malloc_base) 54 return ret; 55 pages = CONFIG_EFI_RAM_SIZE >> 12; 56 57 /* 58 * Don't allocate any memory above 4GB. U-Boot is a 32-bit application 59 * so we want it to load below 4GB. 60 */ 61 addr = 1ULL << 32; 62 ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, 63 priv->image_data_type, pages, &addr); 64 if (ret) { 65 printf("(using pool %lx) ", ret); 66 priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE, 67 &ret); 68 if (!priv->ram_base) 69 return ret; 70 priv->use_pool_for_malloc = true; 71 } else { 72 priv->ram_base = addr; 73 } 74 gd->ram_size = pages << 12; 75 76 return 0; 77 } 78 79 static void free_memory(struct efi_priv *priv) 80 { 81 struct efi_boot_services *boot = priv->boot; 82 83 if (priv->use_pool_for_malloc) 84 efi_free(priv, (void *)priv->ram_base); 85 else 86 boot->free_pages(priv->ram_base, gd->ram_size >> 12); 87 88 efi_free(priv, (void *)gd->malloc_base); 89 efi_free(priv, gd); 90 global_data_ptr = NULL; 91 } 92 93 /** 94 * efi_main() - Start an EFI image 95 * 96 * This function is called by our EFI start-up code. It handles running 97 * U-Boot. If it returns, EFI will continue. Another way to get back to EFI 98 * is via reset_cpu(). 99 */ 100 efi_status_t efi_main(efi_handle_t image, 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