12e192b24SSimon Glass /* 22e192b24SSimon Glass * Copyright (c) 2001 William L. Pitts 32e192b24SSimon Glass * All rights reserved. 42e192b24SSimon Glass * 52e192b24SSimon Glass * Redistribution and use in source and binary forms are freely 62e192b24SSimon Glass * permitted provided that the above copyright notice and this 72e192b24SSimon Glass * paragraph and the following disclaimer are duplicated in all 82e192b24SSimon Glass * such forms. 92e192b24SSimon Glass * 102e192b24SSimon Glass * This software is provided "AS IS" and without any express or 112e192b24SSimon Glass * implied warranties, including, without limitation, the implied 122e192b24SSimon Glass * warranties of merchantability and fitness for a particular 132e192b24SSimon Glass * purpose. 142e192b24SSimon Glass */ 152e192b24SSimon Glass 162e192b24SSimon Glass #include <common.h> 172e192b24SSimon Glass #include <command.h> 182e192b24SSimon Glass #include <elf.h> 199925f1dbSAlex Kiernan #include <environment.h> 202e192b24SSimon Glass #include <net.h> 212e192b24SSimon Glass #include <vxworks.h> 222e192b24SSimon Glass #ifdef CONFIG_X86 23447ae4f7SBin Meng #include <vbe.h> 242e192b24SSimon Glass #include <asm/e820.h> 252e192b24SSimon Glass #include <linux/linkage.h> 262e192b24SSimon Glass #endif 272e192b24SSimon Glass 282e192b24SSimon Glass /* 29839c4e9cSBin Meng * A very simple ELF64 loader, assumes the image is valid, returns the 302e192b24SSimon Glass * entry point address. 31839c4e9cSBin Meng * 32839c4e9cSBin Meng * Note if U-Boot is 32-bit, the loader assumes the to segment's 33839c4e9cSBin Meng * physical address and size is within the lower 32-bit address space. 34839c4e9cSBin Meng */ 35839c4e9cSBin Meng static unsigned long load_elf64_image_phdr(unsigned long addr) 36839c4e9cSBin Meng { 37839c4e9cSBin Meng Elf64_Ehdr *ehdr; /* Elf header structure pointer */ 38839c4e9cSBin Meng Elf64_Phdr *phdr; /* Program header structure pointer */ 39839c4e9cSBin Meng int i; 40839c4e9cSBin Meng 41839c4e9cSBin Meng ehdr = (Elf64_Ehdr *)addr; 42839c4e9cSBin Meng phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff); 43839c4e9cSBin Meng 44839c4e9cSBin Meng /* Load each program header */ 45839c4e9cSBin Meng for (i = 0; i < ehdr->e_phnum; ++i) { 46839c4e9cSBin Meng void *dst = (void *)(ulong)phdr->p_paddr; 47839c4e9cSBin Meng void *src = (void *)addr + phdr->p_offset; 48839c4e9cSBin Meng 49839c4e9cSBin Meng debug("Loading phdr %i to 0x%p (%lu bytes)\n", 50839c4e9cSBin Meng i, dst, (ulong)phdr->p_filesz); 51839c4e9cSBin Meng if (phdr->p_filesz) 52839c4e9cSBin Meng memcpy(dst, src, phdr->p_filesz); 53839c4e9cSBin Meng if (phdr->p_filesz != phdr->p_memsz) 54839c4e9cSBin Meng memset(dst + phdr->p_filesz, 0x00, 55839c4e9cSBin Meng phdr->p_memsz - phdr->p_filesz); 56*957f51e8SKurban Mallachiev flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), 57*957f51e8SKurban Mallachiev roundup(phdr->p_memsz, ARCH_DMA_MINALIGN)); 58839c4e9cSBin Meng ++phdr; 59839c4e9cSBin Meng } 60839c4e9cSBin Meng 612846ea81SRob Bracero if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags & 622846ea81SRob Bracero EF_PPC64_ELFV1_ABI)) { 632846ea81SRob Bracero /* 642846ea81SRob Bracero * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function 652846ea81SRob Bracero * descriptor pointer with the first double word being the 662846ea81SRob Bracero * address of the entry point of the function. 672846ea81SRob Bracero */ 682846ea81SRob Bracero uintptr_t addr = ehdr->e_entry; 692846ea81SRob Bracero 702846ea81SRob Bracero return *(Elf64_Addr *)addr; 712846ea81SRob Bracero } 722846ea81SRob Bracero 732846ea81SRob Bracero return ehdr->e_entry; 742846ea81SRob Bracero } 752846ea81SRob Bracero 762846ea81SRob Bracero static unsigned long load_elf64_image_shdr(unsigned long addr) 772846ea81SRob Bracero { 782846ea81SRob Bracero Elf64_Ehdr *ehdr; /* Elf header structure pointer */ 792846ea81SRob Bracero Elf64_Shdr *shdr; /* Section header structure pointer */ 802846ea81SRob Bracero unsigned char *strtab = 0; /* String table pointer */ 812846ea81SRob Bracero unsigned char *image; /* Binary image pointer */ 822846ea81SRob Bracero int i; /* Loop counter */ 832846ea81SRob Bracero 842846ea81SRob Bracero ehdr = (Elf64_Ehdr *)addr; 852846ea81SRob Bracero 862846ea81SRob Bracero /* Find the section header string table for output info */ 872846ea81SRob Bracero shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff + 882846ea81SRob Bracero (ehdr->e_shstrndx * sizeof(Elf64_Shdr))); 892846ea81SRob Bracero 902846ea81SRob Bracero if (shdr->sh_type == SHT_STRTAB) 912846ea81SRob Bracero strtab = (unsigned char *)(addr + (ulong)shdr->sh_offset); 922846ea81SRob Bracero 932846ea81SRob Bracero /* Load each appropriate section */ 942846ea81SRob Bracero for (i = 0; i < ehdr->e_shnum; ++i) { 952846ea81SRob Bracero shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff + 962846ea81SRob Bracero (i * sizeof(Elf64_Shdr))); 972846ea81SRob Bracero 982846ea81SRob Bracero if (!(shdr->sh_flags & SHF_ALLOC) || 992846ea81SRob Bracero shdr->sh_addr == 0 || shdr->sh_size == 0) { 1002846ea81SRob Bracero continue; 1012846ea81SRob Bracero } 1022846ea81SRob Bracero 1032846ea81SRob Bracero if (strtab) { 1042846ea81SRob Bracero debug("%sing %s @ 0x%08lx (%ld bytes)\n", 1052846ea81SRob Bracero (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load", 1062846ea81SRob Bracero &strtab[shdr->sh_name], 1072846ea81SRob Bracero (unsigned long)shdr->sh_addr, 1082846ea81SRob Bracero (long)shdr->sh_size); 1092846ea81SRob Bracero } 1102846ea81SRob Bracero 1112846ea81SRob Bracero if (shdr->sh_type == SHT_NOBITS) { 1122846ea81SRob Bracero memset((void *)(uintptr_t)shdr->sh_addr, 0, 1132846ea81SRob Bracero shdr->sh_size); 1142846ea81SRob Bracero } else { 1152846ea81SRob Bracero image = (unsigned char *)addr + (ulong)shdr->sh_offset; 1162846ea81SRob Bracero memcpy((void *)(uintptr_t)shdr->sh_addr, 1172846ea81SRob Bracero (const void *)image, shdr->sh_size); 1182846ea81SRob Bracero } 1198744d6c5SNeil Stainton flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN), 1208744d6c5SNeil Stainton roundup((shdr->sh_addr + shdr->sh_size), 1218744d6c5SNeil Stainton ARCH_DMA_MINALIGN) - 1228744d6c5SNeil Stainton rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN)); 1232846ea81SRob Bracero } 1242846ea81SRob Bracero 1252846ea81SRob Bracero if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags & 1262846ea81SRob Bracero EF_PPC64_ELFV1_ABI)) { 1272846ea81SRob Bracero /* 1282846ea81SRob Bracero * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function 1292846ea81SRob Bracero * descriptor pointer with the first double word being the 1302846ea81SRob Bracero * address of the entry point of the function. 1312846ea81SRob Bracero */ 1322846ea81SRob Bracero uintptr_t addr = ehdr->e_entry; 1332846ea81SRob Bracero 1342846ea81SRob Bracero return *(Elf64_Addr *)addr; 1352846ea81SRob Bracero } 1362846ea81SRob Bracero 137839c4e9cSBin Meng return ehdr->e_entry; 138839c4e9cSBin Meng } 139839c4e9cSBin Meng 140839c4e9cSBin Meng /* 141839c4e9cSBin Meng * A very simple ELF loader, assumes the image is valid, returns the 142839c4e9cSBin Meng * entry point address. 143839c4e9cSBin Meng * 144839c4e9cSBin Meng * The loader firstly reads the EFI class to see if it's a 64-bit image. 145839c4e9cSBin Meng * If yes, call the ELF64 loader. Otherwise continue with the ELF32 loader. 1462e192b24SSimon Glass */ 1472e192b24SSimon Glass static unsigned long load_elf_image_phdr(unsigned long addr) 1482e192b24SSimon Glass { 1492e192b24SSimon Glass Elf32_Ehdr *ehdr; /* Elf header structure pointer */ 1502e192b24SSimon Glass Elf32_Phdr *phdr; /* Program header structure pointer */ 1512e192b24SSimon Glass int i; 1522e192b24SSimon Glass 1532e192b24SSimon Glass ehdr = (Elf32_Ehdr *)addr; 154839c4e9cSBin Meng if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) 155839c4e9cSBin Meng return load_elf64_image_phdr(addr); 156839c4e9cSBin Meng 1572e192b24SSimon Glass phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff); 1582e192b24SSimon Glass 1592e192b24SSimon Glass /* Load each program header */ 1602e192b24SSimon Glass for (i = 0; i < ehdr->e_phnum; ++i) { 1612e192b24SSimon Glass void *dst = (void *)(uintptr_t)phdr->p_paddr; 1622e192b24SSimon Glass void *src = (void *)addr + phdr->p_offset; 163839c4e9cSBin Meng 1642e192b24SSimon Glass debug("Loading phdr %i to 0x%p (%i bytes)\n", 1652e192b24SSimon Glass i, dst, phdr->p_filesz); 1662e192b24SSimon Glass if (phdr->p_filesz) 1672e192b24SSimon Glass memcpy(dst, src, phdr->p_filesz); 1682e192b24SSimon Glass if (phdr->p_filesz != phdr->p_memsz) 1692e192b24SSimon Glass memset(dst + phdr->p_filesz, 0x00, 1702e192b24SSimon Glass phdr->p_memsz - phdr->p_filesz); 171*957f51e8SKurban Mallachiev flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), 172*957f51e8SKurban Mallachiev roundup(phdr->p_memsz, ARCH_DMA_MINALIGN)); 1732e192b24SSimon Glass ++phdr; 1742e192b24SSimon Glass } 1752e192b24SSimon Glass 1762e192b24SSimon Glass return ehdr->e_entry; 1772e192b24SSimon Glass } 1782e192b24SSimon Glass 1792e192b24SSimon Glass static unsigned long load_elf_image_shdr(unsigned long addr) 1802e192b24SSimon Glass { 1812e192b24SSimon Glass Elf32_Ehdr *ehdr; /* Elf header structure pointer */ 1822e192b24SSimon Glass Elf32_Shdr *shdr; /* Section header structure pointer */ 1832e192b24SSimon Glass unsigned char *strtab = 0; /* String table pointer */ 1842e192b24SSimon Glass unsigned char *image; /* Binary image pointer */ 1852e192b24SSimon Glass int i; /* Loop counter */ 1862e192b24SSimon Glass 1872e192b24SSimon Glass ehdr = (Elf32_Ehdr *)addr; 1882846ea81SRob Bracero if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) 1892846ea81SRob Bracero return load_elf64_image_shdr(addr); 1902e192b24SSimon Glass 1912e192b24SSimon Glass /* Find the section header string table for output info */ 1922e192b24SSimon Glass shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + 1932e192b24SSimon Glass (ehdr->e_shstrndx * sizeof(Elf32_Shdr))); 1942e192b24SSimon Glass 1952e192b24SSimon Glass if (shdr->sh_type == SHT_STRTAB) 1962e192b24SSimon Glass strtab = (unsigned char *)(addr + shdr->sh_offset); 1972e192b24SSimon Glass 1982e192b24SSimon Glass /* Load each appropriate section */ 1992e192b24SSimon Glass for (i = 0; i < ehdr->e_shnum; ++i) { 2002e192b24SSimon Glass shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + 2012e192b24SSimon Glass (i * sizeof(Elf32_Shdr))); 2022e192b24SSimon Glass 2032e192b24SSimon Glass if (!(shdr->sh_flags & SHF_ALLOC) || 2042e192b24SSimon Glass shdr->sh_addr == 0 || shdr->sh_size == 0) { 2052e192b24SSimon Glass continue; 2062e192b24SSimon Glass } 2072e192b24SSimon Glass 2082e192b24SSimon Glass if (strtab) { 2092e192b24SSimon Glass debug("%sing %s @ 0x%08lx (%ld bytes)\n", 2102e192b24SSimon Glass (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load", 2112e192b24SSimon Glass &strtab[shdr->sh_name], 2122e192b24SSimon Glass (unsigned long)shdr->sh_addr, 2132e192b24SSimon Glass (long)shdr->sh_size); 2142e192b24SSimon Glass } 2152e192b24SSimon Glass 2162e192b24SSimon Glass if (shdr->sh_type == SHT_NOBITS) { 2172e192b24SSimon Glass memset((void *)(uintptr_t)shdr->sh_addr, 0, 2182e192b24SSimon Glass shdr->sh_size); 2192e192b24SSimon Glass } else { 2202e192b24SSimon Glass image = (unsigned char *)addr + shdr->sh_offset; 2212e192b24SSimon Glass memcpy((void *)(uintptr_t)shdr->sh_addr, 2222e192b24SSimon Glass (const void *)image, shdr->sh_size); 2232e192b24SSimon Glass } 22418f201eaSNeil Stainton flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN), 22518f201eaSNeil Stainton roundup((shdr->sh_addr + shdr->sh_size), 22618f201eaSNeil Stainton ARCH_DMA_MINALIGN) - 22718f201eaSNeil Stainton rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN)); 2282e192b24SSimon Glass } 2292e192b24SSimon Glass 2302e192b24SSimon Glass return ehdr->e_entry; 2312e192b24SSimon Glass } 2322e192b24SSimon Glass 2332e192b24SSimon Glass /* Allow ports to override the default behavior */ 2342e192b24SSimon Glass static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]), 2352e192b24SSimon Glass int argc, char * const argv[]) 2362e192b24SSimon Glass { 2372e192b24SSimon Glass unsigned long ret; 2382e192b24SSimon Glass 2392e192b24SSimon Glass /* 2402e192b24SSimon Glass * pass address parameter as argv[0] (aka command name), 2412e192b24SSimon Glass * and all remaining args 2422e192b24SSimon Glass */ 2432e192b24SSimon Glass ret = entry(argc, argv); 2442e192b24SSimon Glass 2452e192b24SSimon Glass return ret; 2462e192b24SSimon Glass } 2472e192b24SSimon Glass 2482e192b24SSimon Glass /* 2492e192b24SSimon Glass * Determine if a valid ELF image exists at the given memory location. 2502e192b24SSimon Glass * First look at the ELF header magic field, then make sure that it is 2512e192b24SSimon Glass * executable. 2522e192b24SSimon Glass */ 2532e192b24SSimon Glass int valid_elf_image(unsigned long addr) 2542e192b24SSimon Glass { 2552e192b24SSimon Glass Elf32_Ehdr *ehdr; /* Elf header structure pointer */ 2562e192b24SSimon Glass 2572e192b24SSimon Glass ehdr = (Elf32_Ehdr *)addr; 2582e192b24SSimon Glass 2592e192b24SSimon Glass if (!IS_ELF(*ehdr)) { 2602e192b24SSimon Glass printf("## No elf image at address 0x%08lx\n", addr); 2612e192b24SSimon Glass return 0; 2622e192b24SSimon Glass } 2632e192b24SSimon Glass 2642e192b24SSimon Glass if (ehdr->e_type != ET_EXEC) { 2652e192b24SSimon Glass printf("## Not a 32-bit elf image at address 0x%08lx\n", addr); 2662e192b24SSimon Glass return 0; 2672e192b24SSimon Glass } 2682e192b24SSimon Glass 2692e192b24SSimon Glass return 1; 2702e192b24SSimon Glass } 2712e192b24SSimon Glass 2722e192b24SSimon Glass /* Interpreter command to boot an arbitrary ELF image from memory */ 2732e192b24SSimon Glass int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 2742e192b24SSimon Glass { 2752e192b24SSimon Glass unsigned long addr; /* Address of the ELF image */ 2762e192b24SSimon Glass unsigned long rc; /* Return value from user code */ 277be1b8679STom Rini char *sload = NULL; 27800caae6dSSimon Glass const char *ep = env_get("autostart"); 2792e192b24SSimon Glass int rcode = 0; 2802e192b24SSimon Glass 281be1b8679STom Rini /* Consume 'bootelf' */ 282be1b8679STom Rini argc--; argv++; 2832e192b24SSimon Glass 284be1b8679STom Rini /* Check for flag. */ 285be1b8679STom Rini if (argc >= 1 && (argv[0][0] == '-' && \ 286be1b8679STom Rini (argv[0][1] == 'p' || argv[0][1] == 's'))) { 287be1b8679STom Rini sload = argv[0]; 288be1b8679STom Rini /* Consume flag. */ 289be1b8679STom Rini argc--; argv++; 290be1b8679STom Rini } 291be1b8679STom Rini /* Check for address. */ 292be1b8679STom Rini if (argc >= 1 && strict_strtoul(argv[0], 16, &addr) != -EINVAL) { 293be1b8679STom Rini /* Consume address */ 294be1b8679STom Rini argc--; argv++; 295be1b8679STom Rini } else 2962e192b24SSimon Glass addr = load_addr; 2972e192b24SSimon Glass 2982e192b24SSimon Glass if (!valid_elf_image(addr)) 2992e192b24SSimon Glass return 1; 3002e192b24SSimon Glass 3012e192b24SSimon Glass if (sload && sload[1] == 'p') 3022e192b24SSimon Glass addr = load_elf_image_phdr(addr); 3032e192b24SSimon Glass else 3042e192b24SSimon Glass addr = load_elf_image_shdr(addr); 3052e192b24SSimon Glass 3062e192b24SSimon Glass if (ep && !strcmp(ep, "no")) 3072e192b24SSimon Glass return rcode; 3082e192b24SSimon Glass 3092e192b24SSimon Glass printf("## Starting application at 0x%08lx ...\n", addr); 3102e192b24SSimon Glass 3112e192b24SSimon Glass /* 3122e192b24SSimon Glass * pass address parameter as argv[0] (aka command name), 3132e192b24SSimon Glass * and all remaining args 3142e192b24SSimon Glass */ 315be1b8679STom Rini rc = do_bootelf_exec((void *)addr, argc, argv); 3162e192b24SSimon Glass if (rc != 0) 3172e192b24SSimon Glass rcode = 1; 3182e192b24SSimon Glass 3192e192b24SSimon Glass printf("## Application terminated, rc = 0x%lx\n", rc); 3202e192b24SSimon Glass 3212e192b24SSimon Glass return rcode; 3222e192b24SSimon Glass } 3232e192b24SSimon Glass 3242e192b24SSimon Glass /* 3252e192b24SSimon Glass * Interpreter command to boot VxWorks from a memory image. The image can 3262e192b24SSimon Glass * be either an ELF image or a raw binary. Will attempt to setup the 3272e192b24SSimon Glass * bootline and other parameters correctly. 3282e192b24SSimon Glass */ 3292e192b24SSimon Glass int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 3302e192b24SSimon Glass { 3312e192b24SSimon Glass unsigned long addr; /* Address of image */ 33279c584e5SBin Meng unsigned long bootaddr = 0; /* Address to put the bootline */ 3332e192b24SSimon Glass char *bootline; /* Text of the bootline */ 3342e192b24SSimon Glass char *tmp; /* Temporary char pointer */ 3352e192b24SSimon Glass char build_buf[128]; /* Buffer for building the bootline */ 3362e192b24SSimon Glass int ptr = 0; 3372e192b24SSimon Glass #ifdef CONFIG_X86 3382902be86SBin Meng ulong base; 339fa5e91f7SBin Meng struct e820_info *info; 34045519924SBin Meng struct e820_entry *data; 341447ae4f7SBin Meng struct efi_gop_info *gop; 342447ae4f7SBin Meng struct vesa_mode_info *vesa = &mode_info.vesa; 3432e192b24SSimon Glass #endif 3442e192b24SSimon Glass 3452e192b24SSimon Glass /* 3462e192b24SSimon Glass * Check the loadaddr variable. 3472e192b24SSimon Glass * If we don't know where the image is then we're done. 3482e192b24SSimon Glass */ 3492e192b24SSimon Glass if (argc < 2) 3502e192b24SSimon Glass addr = load_addr; 3512e192b24SSimon Glass else 3522e192b24SSimon Glass addr = simple_strtoul(argv[1], NULL, 16); 3532e192b24SSimon Glass 3542e192b24SSimon Glass #if defined(CONFIG_CMD_NET) 3552e192b24SSimon Glass /* 3562e192b24SSimon Glass * Check to see if we need to tftp the image ourselves 3572e192b24SSimon Glass * before starting 3582e192b24SSimon Glass */ 3592e192b24SSimon Glass if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) { 3602e192b24SSimon Glass if (net_loop(TFTPGET) <= 0) 3612e192b24SSimon Glass return 1; 3622e192b24SSimon Glass printf("Automatic boot of VxWorks image at address 0x%08lx ...\n", 3632e192b24SSimon Glass addr); 3642e192b24SSimon Glass } 3652e192b24SSimon Glass #endif 3662e192b24SSimon Glass 3672e192b24SSimon Glass /* 3682e192b24SSimon Glass * This should equate to 3692e192b24SSimon Glass * NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET 3702e192b24SSimon Glass * from the VxWorks BSP header files. 3712e192b24SSimon Glass * This will vary from board to board 3722e192b24SSimon Glass */ 3738996975fSTuomas Tynkkynen #if defined(CONFIG_SYS_VXWORKS_MAC_PTR) 3742e192b24SSimon Glass tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR; 37535affd7aSSimon Glass eth_env_get_enetaddr("ethaddr", (uchar *)build_buf); 3762e192b24SSimon Glass memcpy(tmp, build_buf, 6); 3772e192b24SSimon Glass #else 3782e192b24SSimon Glass puts("## Ethernet MAC address not copied to NV RAM\n"); 3792e192b24SSimon Glass #endif 3802e192b24SSimon Glass 38179c584e5SBin Meng #ifdef CONFIG_X86 38279c584e5SBin Meng /* 38379c584e5SBin Meng * Get VxWorks's physical memory base address from environment, 38479c584e5SBin Meng * if we don't specify it in the environment, use a default one. 38579c584e5SBin Meng */ 38679c584e5SBin Meng base = env_get_hex("vx_phys_mem_base", VXWORKS_PHYS_MEM_BASE); 38779c584e5SBin Meng data = (struct e820_entry *)(base + E820_DATA_OFFSET); 38879c584e5SBin Meng info = (struct e820_info *)(base + E820_INFO_OFFSET); 38979c584e5SBin Meng 39079c584e5SBin Meng memset(info, 0, sizeof(struct e820_info)); 39179c584e5SBin Meng info->sign = E820_SIGNATURE; 39279c584e5SBin Meng info->entries = install_e820_map(E820MAX, data); 39379c584e5SBin Meng info->addr = (info->entries - 1) * sizeof(struct e820_entry) + 39479c584e5SBin Meng E820_DATA_OFFSET; 39579c584e5SBin Meng 39679c584e5SBin Meng /* 39779c584e5SBin Meng * Explicitly clear the bootloader image size otherwise if memory 39879c584e5SBin Meng * at this offset happens to contain some garbage data, the final 39979c584e5SBin Meng * available memory size for the kernel is insane. 40079c584e5SBin Meng */ 40179c584e5SBin Meng *(u32 *)(base + BOOT_IMAGE_SIZE_OFFSET) = 0; 40279c584e5SBin Meng 40379c584e5SBin Meng /* 40479c584e5SBin Meng * Prepare compatible framebuffer information block. 40579c584e5SBin Meng * The VESA mode has to be 32-bit RGBA. 40679c584e5SBin Meng */ 40779c584e5SBin Meng if (vesa->x_resolution && vesa->y_resolution) { 40879c584e5SBin Meng gop = (struct efi_gop_info *)(base + EFI_GOP_INFO_OFFSET); 40979c584e5SBin Meng gop->magic = EFI_GOP_INFO_MAGIC; 41079c584e5SBin Meng gop->info.version = 0; 41179c584e5SBin Meng gop->info.width = vesa->x_resolution; 41279c584e5SBin Meng gop->info.height = vesa->y_resolution; 41379c584e5SBin Meng gop->info.pixel_format = EFI_GOT_RGBA8; 41479c584e5SBin Meng gop->info.pixels_per_scanline = vesa->bytes_per_scanline / 4; 41579c584e5SBin Meng gop->fb_base = vesa->phys_base_ptr; 41679c584e5SBin Meng gop->fb_size = vesa->bytes_per_scanline * vesa->y_resolution; 41779c584e5SBin Meng } 41879c584e5SBin Meng #endif 41979c584e5SBin Meng 4202e192b24SSimon Glass /* 4212e192b24SSimon Glass * Use bootaddr to find the location in memory that VxWorks 4222e192b24SSimon Glass * will look for the bootline string. The default value is 4232e192b24SSimon Glass * (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by 4242e192b24SSimon Glass * VxWorks BSP. For example, on PowerPC it defaults to 0x4200. 4252e192b24SSimon Glass */ 42600caae6dSSimon Glass tmp = env_get("bootaddr"); 4272e192b24SSimon Glass if (!tmp) { 42879c584e5SBin Meng #ifdef CONFIG_X86 42979c584e5SBin Meng bootaddr = base + X86_BOOT_LINE_OFFSET; 43079c584e5SBin Meng #else 4312e192b24SSimon Glass printf("## VxWorks bootline address not specified\n"); 432ced71a2fSBin Meng return 1; 43379c584e5SBin Meng #endif 434ced71a2fSBin Meng } 435ced71a2fSBin Meng 43679c584e5SBin Meng if (!bootaddr) 4372e192b24SSimon Glass bootaddr = simple_strtoul(tmp, NULL, 16); 4382e192b24SSimon Glass 4392e192b24SSimon Glass /* 440ced71a2fSBin Meng * Check to see if the bootline is defined in the 'bootargs' parameter. 441ced71a2fSBin Meng * If it is not defined, we may be able to construct the info. 4422e192b24SSimon Glass */ 44300caae6dSSimon Glass bootline = env_get("bootargs"); 4447824ad6aSBin Meng if (!bootline) { 44500caae6dSSimon Glass tmp = env_get("bootdev"); 4462e192b24SSimon Glass if (tmp) { 4472e192b24SSimon Glass strcpy(build_buf, tmp); 4482e192b24SSimon Glass ptr = strlen(tmp); 449ced71a2fSBin Meng } else { 4502e192b24SSimon Glass printf("## VxWorks boot device not specified\n"); 451ced71a2fSBin Meng } 4522e192b24SSimon Glass 45300caae6dSSimon Glass tmp = env_get("bootfile"); 4542e192b24SSimon Glass if (tmp) 455ced71a2fSBin Meng ptr += sprintf(build_buf + ptr, "host:%s ", tmp); 4562e192b24SSimon Glass else 457ced71a2fSBin Meng ptr += sprintf(build_buf + ptr, "host:vxWorks "); 4582e192b24SSimon Glass 4592e192b24SSimon Glass /* 4602e192b24SSimon Glass * The following parameters are only needed if 'bootdev' 4612e192b24SSimon Glass * is an ethernet device, otherwise they are optional. 4622e192b24SSimon Glass */ 46300caae6dSSimon Glass tmp = env_get("ipaddr"); 4642e192b24SSimon Glass if (tmp) { 4652e192b24SSimon Glass ptr += sprintf(build_buf + ptr, "e=%s", tmp); 46600caae6dSSimon Glass tmp = env_get("netmask"); 4672e192b24SSimon Glass if (tmp) { 468723806ccSSimon Glass u32 mask = env_get_ip("netmask").s_addr; 4692e192b24SSimon Glass ptr += sprintf(build_buf + ptr, 4702e192b24SSimon Glass ":%08x ", ntohl(mask)); 4712e192b24SSimon Glass } else { 4722e192b24SSimon Glass ptr += sprintf(build_buf + ptr, " "); 4732e192b24SSimon Glass } 4742e192b24SSimon Glass } 4752e192b24SSimon Glass 47600caae6dSSimon Glass tmp = env_get("serverip"); 4772e192b24SSimon Glass if (tmp) 4782e192b24SSimon Glass ptr += sprintf(build_buf + ptr, "h=%s ", tmp); 4792e192b24SSimon Glass 48000caae6dSSimon Glass tmp = env_get("gatewayip"); 4812e192b24SSimon Glass if (tmp) 4822e192b24SSimon Glass ptr += sprintf(build_buf + ptr, "g=%s ", tmp); 4832e192b24SSimon Glass 48400caae6dSSimon Glass tmp = env_get("hostname"); 4852e192b24SSimon Glass if (tmp) 4862e192b24SSimon Glass ptr += sprintf(build_buf + ptr, "tn=%s ", tmp); 4872e192b24SSimon Glass 48800caae6dSSimon Glass tmp = env_get("othbootargs"); 4892e192b24SSimon Glass if (tmp) { 4902e192b24SSimon Glass strcpy(build_buf + ptr, tmp); 4912e192b24SSimon Glass ptr += strlen(tmp); 4922e192b24SSimon Glass } 4932e192b24SSimon Glass 4947824ad6aSBin Meng bootline = build_buf; 4952e192b24SSimon Glass } 4962e192b24SSimon Glass 497ced71a2fSBin Meng memcpy((void *)bootaddr, bootline, max(strlen(bootline), (size_t)255)); 4987824ad6aSBin Meng flush_cache(bootaddr, max(strlen(bootline), (size_t)255)); 499ced71a2fSBin Meng printf("## Using bootline (@ 0x%lx): %s\n", bootaddr, (char *)bootaddr); 5002e192b24SSimon Glass 5012e192b24SSimon Glass /* 5022e192b24SSimon Glass * If the data at the load address is an elf image, then 5032e192b24SSimon Glass * treat it like an elf image. Otherwise, assume that it is a 5042e192b24SSimon Glass * binary image. 5052e192b24SSimon Glass */ 5062e192b24SSimon Glass if (valid_elf_image(addr)) 507476c2fcdSChristian Gmeiner addr = load_elf_image_phdr(addr); 5082e192b24SSimon Glass else 5092e192b24SSimon Glass puts("## Not an ELF image, assuming binary\n"); 5102e192b24SSimon Glass 5112e192b24SSimon Glass printf("## Starting vxWorks at 0x%08lx ...\n", addr); 5122e192b24SSimon Glass 5132e192b24SSimon Glass dcache_disable(); 5143194daa1SVasyl Vavrychuk #if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI) 5153194daa1SVasyl Vavrychuk armv8_setup_psci(); 5163194daa1SVasyl Vavrychuk smp_kick_all_cpus(); 5173194daa1SVasyl Vavrychuk #endif 5183194daa1SVasyl Vavrychuk 5192e192b24SSimon Glass #ifdef CONFIG_X86 5202e192b24SSimon Glass /* VxWorks on x86 uses stack to pass parameters */ 5212e192b24SSimon Glass ((asmlinkage void (*)(int))addr)(0); 5222e192b24SSimon Glass #else 5232e192b24SSimon Glass ((void (*)(int))addr)(0); 5242e192b24SSimon Glass #endif 5252e192b24SSimon Glass 5262e192b24SSimon Glass puts("## vxWorks terminated\n"); 5272e192b24SSimon Glass 5282e192b24SSimon Glass return 1; 5292e192b24SSimon Glass } 5302e192b24SSimon Glass 5312e192b24SSimon Glass U_BOOT_CMD( 532be1b8679STom Rini bootelf, CONFIG_SYS_MAXARGS, 0, do_bootelf, 5332e192b24SSimon Glass "Boot from an ELF image in memory", 5342e192b24SSimon Glass "[-p|-s] [address]\n" 5352e192b24SSimon Glass "\t- load ELF image at [address] via program headers (-p)\n" 5362e192b24SSimon Glass "\t or via section headers (-s)" 5372e192b24SSimon Glass ); 5382e192b24SSimon Glass 5392e192b24SSimon Glass U_BOOT_CMD( 5402e192b24SSimon Glass bootvx, 2, 0, do_bootvx, 5412e192b24SSimon Glass "Boot vxWorks from an ELF image", 5422e192b24SSimon Glass " [address] - load address of vxWorks ELF image." 5432e192b24SSimon Glass ); 544