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