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