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 */
load_elf64_image_phdr(unsigned long addr)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
load_elf64_image_shdr(unsigned long addr)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 */
load_elf_image_phdr(unsigned long addr)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
load_elf_image_shdr(unsigned long addr)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 */
do_bootelf_exec(ulong (* entry)(int,char * const[]),int argc,char * const argv[])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 */
valid_elf_image(unsigned long addr)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 */
do_bootelf(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])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 */
do_bootvx(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])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