1476476e7SSimon Glass /* 2476476e7SSimon Glass * Copyright (c) 2015 Google, Inc 3476476e7SSimon Glass * 4476476e7SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 5476476e7SSimon Glass * 6476476e7SSimon Glass * EFI information obtained here: 7476476e7SSimon Glass * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES 8476476e7SSimon Glass * 9*96a8d409SSimon Glass * Loads a payload (U-Boot) within the EFI environment. This is built as an 10*96a8d409SSimon Glass * EFI application. It can be built either in 32-bit or 64-bit mode. 11476476e7SSimon Glass */ 12476476e7SSimon Glass 13476476e7SSimon Glass #include <common.h> 14476476e7SSimon Glass #include <debug_uart.h> 15476476e7SSimon Glass #include <efi.h> 16476476e7SSimon Glass #include <efi_api.h> 17476476e7SSimon Glass #include <errno.h> 18476476e7SSimon Glass #include <ns16550.h> 19476476e7SSimon Glass #include <asm/cpu.h> 20476476e7SSimon Glass #include <asm/io.h> 21476476e7SSimon Glass #include <linux/err.h> 22476476e7SSimon Glass #include <linux/types.h> 23476476e7SSimon Glass 24476476e7SSimon Glass DECLARE_GLOBAL_DATA_PTR; 25476476e7SSimon Glass 26476476e7SSimon Glass #ifndef CONFIG_X86 27476476e7SSimon Glass /* 28476476e7SSimon Glass * Problem areas: 29476476e7SSimon Glass * - putc() uses the ns16550 address directly and assumed I/O access. Many 30476476e7SSimon Glass * platforms will use memory access 31476476e7SSimon Glass * get_codeseg32() is only meaningful on x86 32476476e7SSimon Glass */ 33476476e7SSimon Glass #error "This file needs to be ported for use on architectures" 34476476e7SSimon Glass #endif 35476476e7SSimon Glass 36476476e7SSimon Glass static struct efi_priv *global_priv; 37476476e7SSimon Glass static bool use_uart; 38476476e7SSimon Glass 39476476e7SSimon Glass struct __packed desctab_info { 40476476e7SSimon Glass uint16_t limit; 41476476e7SSimon Glass uint64_t addr; 42476476e7SSimon Glass uint16_t pad; 43476476e7SSimon Glass }; 44476476e7SSimon Glass 45476476e7SSimon Glass /* 46476476e7SSimon Glass * EFI uses Unicode and we don't. The easiest way to get a sensible output 47476476e7SSimon Glass * function is to use the U-Boot debug UART. We use EFI's console output 48476476e7SSimon Glass * function where available, and assume the built-in UART after that. We rely 49476476e7SSimon Glass * on EFI to set up the UART for us and just bring in the functions here. 50476476e7SSimon Glass * This last bit is a bit icky, but it's only for debugging anyway. We could 51476476e7SSimon Glass * build in ns16550.c with some effort, but this is a payload loader after 52476476e7SSimon Glass * all. 53476476e7SSimon Glass * 54476476e7SSimon Glass * Note: We avoid using printf() so we don't need to bring in lib/vsprintf.c. 55476476e7SSimon Glass * That would require some refactoring since we already build this for U-Boot. 56476476e7SSimon Glass * Building an EFI shared library version would have to be a separate stem. 57476476e7SSimon Glass * That might push us to using the SPL framework to build this stub. However 58476476e7SSimon Glass * that would involve a round of EFI-specific changes in SPL. Worth 59476476e7SSimon Glass * considering if we start needing more U-Boot functionality. Note that we 60476476e7SSimon Glass * could then move get_codeseg32() to arch/x86/cpu/cpu.c. 61476476e7SSimon Glass */ 62476476e7SSimon Glass void debug_uart_init(void) 63476476e7SSimon Glass { 64476476e7SSimon Glass } 65476476e7SSimon Glass 66476476e7SSimon Glass void putc(const char ch) 67476476e7SSimon Glass { 68476476e7SSimon Glass if (use_uart) { 69476476e7SSimon Glass NS16550_t com_port = (NS16550_t)0x3f8; 70476476e7SSimon Glass 71476476e7SSimon Glass while ((inb((ulong)&com_port->lsr) & UART_LSR_THRE) == 0) 72476476e7SSimon Glass ; 73476476e7SSimon Glass outb(ch, (ulong)&com_port->thr); 74476476e7SSimon Glass } else { 75476476e7SSimon Glass efi_putc(global_priv, ch); 76476476e7SSimon Glass } 77476476e7SSimon Glass if (ch == '\n') 78476476e7SSimon Glass putc('\r'); 79476476e7SSimon Glass } 80476476e7SSimon Glass 81476476e7SSimon Glass void puts(const char *str) 82476476e7SSimon Glass { 83476476e7SSimon Glass while (*str) 84476476e7SSimon Glass putc(*str++); 85476476e7SSimon Glass } 86476476e7SSimon Glass 87476476e7SSimon Glass static void _debug_uart_putc(int ch) 88476476e7SSimon Glass { 89476476e7SSimon Glass putc(ch); 90476476e7SSimon Glass } 91476476e7SSimon Glass 92476476e7SSimon Glass DEBUG_UART_FUNCS 93476476e7SSimon Glass 94476476e7SSimon Glass void *memcpy(void *dest, const void *src, size_t size) 95476476e7SSimon Glass { 96476476e7SSimon Glass unsigned char *dptr = dest; 97476476e7SSimon Glass const unsigned char *ptr = src; 98476476e7SSimon Glass const unsigned char *end = src + size; 99476476e7SSimon Glass 100476476e7SSimon Glass while (ptr < end) 101476476e7SSimon Glass *dptr++ = *ptr++; 102476476e7SSimon Glass 103476476e7SSimon Glass return dest; 104476476e7SSimon Glass } 105476476e7SSimon Glass 106476476e7SSimon Glass void *memset(void *inptr, int ch, size_t size) 107476476e7SSimon Glass { 108476476e7SSimon Glass char *ptr = inptr; 109476476e7SSimon Glass char *end = ptr + size; 110476476e7SSimon Glass 111476476e7SSimon Glass while (ptr < end) 112476476e7SSimon Glass *ptr++ = ch; 113476476e7SSimon Glass 114476476e7SSimon Glass return ptr; 115476476e7SSimon Glass } 116476476e7SSimon Glass 117476476e7SSimon Glass static void jump_to_uboot(ulong cs32, ulong addr, ulong info) 118476476e7SSimon Glass { 119476476e7SSimon Glass #ifdef CONFIG_EFI_STUB_32BIT 120476476e7SSimon Glass /* 121476476e7SSimon Glass * U-Boot requires these parameters in registers, not on the stack. 122476476e7SSimon Glass * See _x86boot_start() for this code. 123476476e7SSimon Glass */ 124476476e7SSimon Glass typedef void (*func_t)(int bist, int unused, ulong info) 125476476e7SSimon Glass __attribute__((regparm(3))); 126476476e7SSimon Glass 127476476e7SSimon Glass ((func_t)addr)(0, 0, info); 128476476e7SSimon Glass #else 129*96a8d409SSimon Glass cpu_call32(cs32, CONFIG_SYS_TEXT_BASE, info); 130476476e7SSimon Glass #endif 131476476e7SSimon Glass } 132476476e7SSimon Glass 133*96a8d409SSimon Glass #ifdef CONFIG_EFI_STUB_64BIT 134476476e7SSimon Glass static void get_gdt(struct desctab_info *info) 135476476e7SSimon Glass { 136476476e7SSimon Glass asm volatile ("sgdt %0" : : "m"(*info) : "memory"); 137476476e7SSimon Glass } 138*96a8d409SSimon Glass #endif 139476476e7SSimon Glass 140476476e7SSimon Glass static inline unsigned long read_cr3(void) 141476476e7SSimon Glass { 142476476e7SSimon Glass unsigned long val; 143476476e7SSimon Glass 144476476e7SSimon Glass asm volatile("mov %%cr3,%0" : "=r" (val) : : "memory"); 145476476e7SSimon Glass return val; 146476476e7SSimon Glass } 147476476e7SSimon Glass 148476476e7SSimon Glass /** 149476476e7SSimon Glass * get_codeseg32() - Find the code segment to use for 32-bit code 150476476e7SSimon Glass * 151476476e7SSimon Glass * U-Boot only works in 32-bit mode at present, so when booting from 64-bit 152476476e7SSimon Glass * EFI we must first change to 32-bit mode. To do this we need to find the 153476476e7SSimon Glass * correct code segment to use (an entry in the Global Descriptor Table). 154476476e7SSimon Glass * 155476476e7SSimon Glass * @return code segment GDT offset, or 0 for 32-bit EFI, -ENOENT if not found 156476476e7SSimon Glass */ 157476476e7SSimon Glass static int get_codeseg32(void) 158476476e7SSimon Glass { 159476476e7SSimon Glass int cs32 = 0; 160476476e7SSimon Glass 161*96a8d409SSimon Glass #ifdef CONFIG_EFI_STUB_64BIT 162*96a8d409SSimon Glass struct desctab_info gdt; 163*96a8d409SSimon Glass uint64_t *ptr; 164*96a8d409SSimon Glass int i; 165*96a8d409SSimon Glass 166*96a8d409SSimon Glass get_gdt(&gdt); 167*96a8d409SSimon Glass for (ptr = (uint64_t *)(unsigned long)gdt.addr, i = 0; i < gdt.limit; 168*96a8d409SSimon Glass i += 8, ptr++) { 169*96a8d409SSimon Glass uint64_t desc = *ptr; 170*96a8d409SSimon Glass uint64_t base, limit; 171*96a8d409SSimon Glass 172*96a8d409SSimon Glass /* 173*96a8d409SSimon Glass * Check that the target U-Boot jump address is within the 174*96a8d409SSimon Glass * selector and that the selector is of the right type. 175*96a8d409SSimon Glass */ 176*96a8d409SSimon Glass base = ((desc >> GDT_BASE_LOW_SHIFT) & GDT_BASE_LOW_MASK) | 177*96a8d409SSimon Glass ((desc >> GDT_BASE_HIGH_SHIFT) & GDT_BASE_HIGH_MASK) 178*96a8d409SSimon Glass << 16; 179*96a8d409SSimon Glass limit = ((desc >> GDT_LIMIT_LOW_SHIFT) & GDT_LIMIT_LOW_MASK) | 180*96a8d409SSimon Glass ((desc >> GDT_LIMIT_HIGH_SHIFT) & GDT_LIMIT_HIGH_MASK) 181*96a8d409SSimon Glass << 16; 182*96a8d409SSimon Glass base <<= 12; /* 4KB granularity */ 183*96a8d409SSimon Glass limit <<= 12; 184*96a8d409SSimon Glass if ((desc & GDT_PRESENT) && (desc && GDT_NOTSYS) && 185*96a8d409SSimon Glass !(desc & GDT_LONG) && (desc & GDT_4KB) && 186*96a8d409SSimon Glass (desc & GDT_32BIT) && (desc & GDT_CODE) && 187*96a8d409SSimon Glass CONFIG_SYS_TEXT_BASE > base && 188*96a8d409SSimon Glass CONFIG_SYS_TEXT_BASE + CONFIG_SYS_MONITOR_LEN < limit 189*96a8d409SSimon Glass ) { 190*96a8d409SSimon Glass cs32 = i; 191*96a8d409SSimon Glass break; 192*96a8d409SSimon Glass } 193*96a8d409SSimon Glass } 194*96a8d409SSimon Glass 195*96a8d409SSimon Glass #ifdef DEBUG 196*96a8d409SSimon Glass puts("\ngdt: "); 197*96a8d409SSimon Glass printhex8(gdt.limit); 198*96a8d409SSimon Glass puts(", addr: "); 199*96a8d409SSimon Glass printhex8(gdt.addr >> 32); 200*96a8d409SSimon Glass printhex8(gdt.addr); 201*96a8d409SSimon Glass for (i = 0; i < gdt.limit; i += 8) { 202*96a8d409SSimon Glass uint32_t *ptr = (uint32_t *)((unsigned long)gdt.addr + i); 203*96a8d409SSimon Glass 204*96a8d409SSimon Glass puts("\n"); 205*96a8d409SSimon Glass printhex2(i); 206*96a8d409SSimon Glass puts(": "); 207*96a8d409SSimon Glass printhex8(ptr[1]); 208*96a8d409SSimon Glass puts(" "); 209*96a8d409SSimon Glass printhex8(ptr[0]); 210*96a8d409SSimon Glass } 211*96a8d409SSimon Glass puts("\n "); 212*96a8d409SSimon Glass puts("32-bit code segment: "); 213*96a8d409SSimon Glass printhex2(cs32); 214*96a8d409SSimon Glass puts("\n "); 215*96a8d409SSimon Glass 216*96a8d409SSimon Glass puts("page_table: "); 217*96a8d409SSimon Glass printhex8(read_cr3()); 218*96a8d409SSimon Glass puts("\n "); 219*96a8d409SSimon Glass #endif 220*96a8d409SSimon Glass if (!cs32) { 221*96a8d409SSimon Glass puts("Can't find 32-bit code segment\n"); 222*96a8d409SSimon Glass return -ENOENT; 223*96a8d409SSimon Glass } 224*96a8d409SSimon Glass #endif 225*96a8d409SSimon Glass 226476476e7SSimon Glass return cs32; 227476476e7SSimon Glass } 228476476e7SSimon Glass 229476476e7SSimon Glass static int setup_info_table(struct efi_priv *priv, int size) 230476476e7SSimon Glass { 231476476e7SSimon Glass struct efi_info_hdr *info; 232476476e7SSimon Glass efi_status_t ret; 233476476e7SSimon Glass 234476476e7SSimon Glass /* Get some memory for our info table */ 235476476e7SSimon Glass priv->info_size = size; 236476476e7SSimon Glass info = efi_malloc(priv, priv->info_size, &ret); 237476476e7SSimon Glass if (ret) { 238476476e7SSimon Glass printhex2(ret); 239476476e7SSimon Glass puts(" No memory for info table: "); 240476476e7SSimon Glass return ret; 241476476e7SSimon Glass } 242476476e7SSimon Glass 243476476e7SSimon Glass memset(info, '\0', sizeof(*info)); 244476476e7SSimon Glass info->version = EFI_TABLE_VERSION; 245476476e7SSimon Glass info->hdr_size = sizeof(*info); 246476476e7SSimon Glass priv->info = info; 247476476e7SSimon Glass priv->next_hdr = (char *)info + info->hdr_size; 248476476e7SSimon Glass 249476476e7SSimon Glass return 0; 250476476e7SSimon Glass } 251476476e7SSimon Glass 252476476e7SSimon Glass static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type, 253476476e7SSimon Glass void *ptr1, int size1, void *ptr2, int size2) 254476476e7SSimon Glass { 255476476e7SSimon Glass struct efi_entry_hdr *hdr = priv->next_hdr; 256476476e7SSimon Glass 257476476e7SSimon Glass hdr->type = type; 258476476e7SSimon Glass hdr->size = size1 + size2; 259476476e7SSimon Glass hdr->addr = 0; 260476476e7SSimon Glass hdr->link = ALIGN(sizeof(*hdr) + hdr->size, 16); 261476476e7SSimon Glass priv->next_hdr += hdr->link; 262476476e7SSimon Glass memcpy(hdr + 1, ptr1, size1); 263476476e7SSimon Glass memcpy((void *)(hdr + 1) + size1, ptr2, size2); 264476476e7SSimon Glass priv->info->total_size = (ulong)priv->next_hdr - (ulong)priv->info; 265476476e7SSimon Glass } 266476476e7SSimon Glass 267476476e7SSimon Glass /** 268476476e7SSimon Glass * efi_main() - Start an EFI image 269476476e7SSimon Glass * 270476476e7SSimon Glass * This function is called by our EFI start-up code. It handles running 271476476e7SSimon Glass * U-Boot. If it returns, EFI will continue. 272476476e7SSimon Glass */ 273476476e7SSimon Glass efi_status_t efi_main(efi_handle_t image, struct efi_system_table *sys_table) 274476476e7SSimon Glass { 275476476e7SSimon Glass struct efi_priv local_priv, *priv = &local_priv; 276476476e7SSimon Glass struct efi_boot_services *boot = sys_table->boottime; 277476476e7SSimon Glass struct efi_mem_desc *desc; 278476476e7SSimon Glass struct efi_entry_memmap map; 279476476e7SSimon Glass ulong key, desc_size, size; 280476476e7SSimon Glass efi_status_t ret; 281476476e7SSimon Glass u32 version; 282476476e7SSimon Glass int cs32; 283476476e7SSimon Glass 284476476e7SSimon Glass ret = efi_init(priv, "Payload", image, sys_table); 285476476e7SSimon Glass if (ret) { 286476476e7SSimon Glass printhex2(ret); puts(" efi_init() failed\n"); 287476476e7SSimon Glass return ret; 288476476e7SSimon Glass } 289476476e7SSimon Glass global_priv = priv; 290476476e7SSimon Glass 291476476e7SSimon Glass cs32 = get_codeseg32(); 292476476e7SSimon Glass if (cs32 < 0) 293476476e7SSimon Glass return EFI_UNSUPPORTED; 294476476e7SSimon Glass 295476476e7SSimon Glass /* Get the memory map so we can switch off EFI */ 296476476e7SSimon Glass size = 0; 297476476e7SSimon Glass ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version); 298476476e7SSimon Glass if (ret != EFI_BUFFER_TOO_SMALL) { 299476476e7SSimon Glass printhex2(BITS_PER_LONG); 300476476e7SSimon Glass printhex2(ret); 301476476e7SSimon Glass puts(" No memory map\n"); 302476476e7SSimon Glass return ret; 303476476e7SSimon Glass } 304476476e7SSimon Glass size += 1024; /* Since doing a malloc() may change the memory map! */ 305476476e7SSimon Glass desc = efi_malloc(priv, size, &ret); 306476476e7SSimon Glass if (!desc) { 307476476e7SSimon Glass printhex2(ret); 308476476e7SSimon Glass puts(" No memory for memory descriptor: "); 309476476e7SSimon Glass return ret; 310476476e7SSimon Glass } 311476476e7SSimon Glass ret = setup_info_table(priv, size + 128); 312476476e7SSimon Glass if (ret) 313476476e7SSimon Glass return ret; 314476476e7SSimon Glass 315476476e7SSimon Glass ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version); 316476476e7SSimon Glass if (ret) { 317476476e7SSimon Glass printhex2(ret); 318476476e7SSimon Glass puts(" Can't get memory map\n"); 319476476e7SSimon Glass return ret; 320476476e7SSimon Glass } 321476476e7SSimon Glass 322476476e7SSimon Glass ret = boot->exit_boot_services(image, key); 323476476e7SSimon Glass if (ret) { 324476476e7SSimon Glass /* 325476476e7SSimon Glass * Unfortunately it happens that we cannot exit boot services 326476476e7SSimon Glass * the first time. But the second time it work. I don't know 327476476e7SSimon Glass * why but this seems to be a repeatable problem. To get 328476476e7SSimon Glass * around it, just try again. 329476476e7SSimon Glass */ 330476476e7SSimon Glass printhex2(ret); 331476476e7SSimon Glass puts(" Can't exit boot services\n"); 332476476e7SSimon Glass size = sizeof(desc); 333476476e7SSimon Glass ret = boot->get_memory_map(&size, desc, &key, &desc_size, 334476476e7SSimon Glass &version); 335476476e7SSimon Glass if (ret) { 336476476e7SSimon Glass printhex2(ret); 337476476e7SSimon Glass puts(" Can't get memory map\n"); 338476476e7SSimon Glass return ret; 339476476e7SSimon Glass } 340476476e7SSimon Glass ret = boot->exit_boot_services(image, key); 341476476e7SSimon Glass if (ret) { 342476476e7SSimon Glass printhex2(ret); 343476476e7SSimon Glass puts(" Can't exit boot services 2\n"); 344476476e7SSimon Glass return ret; 345476476e7SSimon Glass } 346476476e7SSimon Glass } 347476476e7SSimon Glass 348476476e7SSimon Glass map.version = version; 349476476e7SSimon Glass map.desc_size = desc_size; 350476476e7SSimon Glass add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), desc, size); 351476476e7SSimon Glass add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0); 352476476e7SSimon Glass 353476476e7SSimon Glass /* The EFI UART won't work now, switch to a debug one */ 354476476e7SSimon Glass use_uart = true; 355476476e7SSimon Glass 356476476e7SSimon Glass memcpy((void *)CONFIG_SYS_TEXT_BASE, _binary_u_boot_dtb_bin_start, 357476476e7SSimon Glass (ulong)_binary_u_boot_dtb_bin_end - 358476476e7SSimon Glass (ulong)_binary_u_boot_dtb_bin_start); 359476476e7SSimon Glass 360476476e7SSimon Glass #ifdef DEBUG 361476476e7SSimon Glass puts("EFI table at "); 362476476e7SSimon Glass printhex8((ulong)priv->info); 363476476e7SSimon Glass puts(" size "); 364476476e7SSimon Glass printhex8(priv->info->total_size); 365476476e7SSimon Glass #endif 366476476e7SSimon Glass putc('\n'); 367476476e7SSimon Glass jump_to_uboot(cs32, CONFIG_SYS_TEXT_BASE, (ulong)priv->info); 368476476e7SSimon Glass 369476476e7SSimon Glass return EFI_LOAD_ERROR; 370476476e7SSimon Glass } 371