Merge tag 'u-boot-stm32-20200813' of https://gitlab.denx.de/u-boot/custodians/u-boot-stm
[platform/kernel/u-boot.git] / cmd / elf.c
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2001 William L. Pitts
4  * All rights reserved.
5  */
6
7 #include <common.h>
8 #include <command.h>
9 #include <cpu_func.h>
10 #include <elf.h>
11 #include <env.h>
12 #include <image.h>
13 #include <log.h>
14 #include <net.h>
15 #include <vxworks.h>
16 #ifdef CONFIG_X86
17 #include <vbe.h>
18 #include <asm/cache.h>
19 #include <asm/e820.h>
20 #include <linux/linkage.h>
21 #endif
22
23 /* Allow ports to override the default behavior */
24 static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]),
25                                      int argc, char *const argv[])
26 {
27         unsigned long ret;
28
29         /*
30          * pass address parameter as argv[0] (aka command name),
31          * and all remaining args
32          */
33         ret = entry(argc, argv);
34
35         return ret;
36 }
37
38 /* Interpreter command to boot an arbitrary ELF image from memory */
39 int do_bootelf(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
40 {
41         unsigned long addr; /* Address of the ELF image */
42         unsigned long rc; /* Return value from user code */
43         char *sload = NULL;
44         const char *ep = env_get("autostart");
45         int rcode = 0;
46
47         /* Consume 'bootelf' */
48         argc--; argv++;
49
50         /* Check for flag. */
51         if (argc >= 1 && (argv[0][0] == '-' && \
52                                 (argv[0][1] == 'p' || argv[0][1] == 's'))) {
53                 sload = argv[0];
54                 /* Consume flag. */
55                 argc--; argv++;
56         }
57         /* Check for address. */
58         if (argc >= 1 && strict_strtoul(argv[0], 16, &addr) != -EINVAL) {
59                 /* Consume address */
60                 argc--; argv++;
61         } else
62                 addr = image_load_addr;
63
64         if (!valid_elf_image(addr))
65                 return 1;
66
67         if (sload && sload[1] == 'p')
68                 addr = load_elf_image_phdr(addr);
69         else
70                 addr = load_elf_image_shdr(addr);
71
72         if (ep && !strcmp(ep, "no"))
73                 return rcode;
74
75         printf("## Starting application at 0x%08lx ...\n", addr);
76
77         /*
78          * pass address parameter as argv[0] (aka command name),
79          * and all remaining args
80          */
81         rc = do_bootelf_exec((void *)addr, argc, argv);
82         if (rc != 0)
83                 rcode = 1;
84
85         printf("## Application terminated, rc = 0x%lx\n", rc);
86
87         return rcode;
88 }
89
90 /*
91  * Interpreter command to boot VxWorks from a memory image.  The image can
92  * be either an ELF image or a raw binary.  Will attempt to setup the
93  * bootline and other parameters correctly.
94  */
95 int do_bootvx(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
96 {
97         unsigned long addr; /* Address of image */
98         unsigned long bootaddr = 0; /* Address to put the bootline */
99         char *bootline; /* Text of the bootline */
100         char *tmp; /* Temporary char pointer */
101         char build_buf[128]; /* Buffer for building the bootline */
102         int ptr = 0;
103 #ifdef CONFIG_X86
104         ulong base;
105         struct e820_info *info;
106         struct e820_entry *data;
107         struct efi_gop_info *gop;
108         struct vesa_mode_info *vesa = &mode_info.vesa;
109 #endif
110
111         /*
112          * Check the loadaddr variable.
113          * If we don't know where the image is then we're done.
114          */
115         if (argc < 2)
116                 addr = image_load_addr;
117         else
118                 addr = simple_strtoul(argv[1], NULL, 16);
119
120 #if defined(CONFIG_CMD_NET)
121         /*
122          * Check to see if we need to tftp the image ourselves
123          * before starting
124          */
125         if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) {
126                 if (net_loop(TFTPGET) <= 0)
127                         return 1;
128                 printf("Automatic boot of VxWorks image at address 0x%08lx ...\n",
129                         addr);
130         }
131 #endif
132
133         /*
134          * This should equate to
135          * NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET
136          * from the VxWorks BSP header files.
137          * This will vary from board to board
138          */
139 #if defined(CONFIG_SYS_VXWORKS_MAC_PTR)
140         tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR;
141         eth_env_get_enetaddr("ethaddr", (uchar *)build_buf);
142         memcpy(tmp, build_buf, 6);
143 #else
144         puts("## Ethernet MAC address not copied to NV RAM\n");
145 #endif
146
147 #ifdef CONFIG_X86
148         /*
149          * Get VxWorks's physical memory base address from environment,
150          * if we don't specify it in the environment, use a default one.
151          */
152         base = env_get_hex("vx_phys_mem_base", VXWORKS_PHYS_MEM_BASE);
153         data = (struct e820_entry *)(base + E820_DATA_OFFSET);
154         info = (struct e820_info *)(base + E820_INFO_OFFSET);
155
156         memset(info, 0, sizeof(struct e820_info));
157         info->sign = E820_SIGNATURE;
158         info->entries = install_e820_map(E820MAX, data);
159         info->addr = (info->entries - 1) * sizeof(struct e820_entry) +
160                      E820_DATA_OFFSET;
161
162         /*
163          * Explicitly clear the bootloader image size otherwise if memory
164          * at this offset happens to contain some garbage data, the final
165          * available memory size for the kernel is insane.
166          */
167         *(u32 *)(base + BOOT_IMAGE_SIZE_OFFSET) = 0;
168
169         /*
170          * Prepare compatible framebuffer information block.
171          * The VESA mode has to be 32-bit RGBA.
172          */
173         if (vesa->x_resolution && vesa->y_resolution) {
174                 gop = (struct efi_gop_info *)(base + EFI_GOP_INFO_OFFSET);
175                 gop->magic = EFI_GOP_INFO_MAGIC;
176                 gop->info.version = 0;
177                 gop->info.width = vesa->x_resolution;
178                 gop->info.height = vesa->y_resolution;
179                 gop->info.pixel_format = EFI_GOT_RGBA8;
180                 gop->info.pixels_per_scanline = vesa->bytes_per_scanline / 4;
181                 gop->fb_base = vesa->phys_base_ptr;
182                 gop->fb_size = vesa->bytes_per_scanline * vesa->y_resolution;
183         }
184 #endif
185
186         /*
187          * Use bootaddr to find the location in memory that VxWorks
188          * will look for the bootline string. The default value is
189          * (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by
190          * VxWorks BSP. For example, on PowerPC it defaults to 0x4200.
191          */
192         tmp = env_get("bootaddr");
193         if (!tmp) {
194 #ifdef CONFIG_X86
195                 bootaddr = base + X86_BOOT_LINE_OFFSET;
196 #else
197                 printf("## VxWorks bootline address not specified\n");
198                 return 1;
199 #endif
200         }
201
202         if (!bootaddr)
203                 bootaddr = simple_strtoul(tmp, NULL, 16);
204
205         /*
206          * Check to see if the bootline is defined in the 'bootargs' parameter.
207          * If it is not defined, we may be able to construct the info.
208          */
209         bootline = env_get("bootargs");
210         if (!bootline) {
211                 tmp = env_get("bootdev");
212                 if (tmp) {
213                         strcpy(build_buf, tmp);
214                         ptr = strlen(tmp);
215                 } else {
216                         printf("## VxWorks boot device not specified\n");
217                 }
218
219                 tmp = env_get("bootfile");
220                 if (tmp)
221                         ptr += sprintf(build_buf + ptr, "host:%s ", tmp);
222                 else
223                         ptr += sprintf(build_buf + ptr, "host:vxWorks ");
224
225                 /*
226                  * The following parameters are only needed if 'bootdev'
227                  * is an ethernet device, otherwise they are optional.
228                  */
229                 tmp = env_get("ipaddr");
230                 if (tmp) {
231                         ptr += sprintf(build_buf + ptr, "e=%s", tmp);
232                         tmp = env_get("netmask");
233                         if (tmp) {
234                                 u32 mask = env_get_ip("netmask").s_addr;
235                                 ptr += sprintf(build_buf + ptr,
236                                                ":%08x ", ntohl(mask));
237                         } else {
238                                 ptr += sprintf(build_buf + ptr, " ");
239                         }
240                 }
241
242                 tmp = env_get("serverip");
243                 if (tmp)
244                         ptr += sprintf(build_buf + ptr, "h=%s ", tmp);
245
246                 tmp = env_get("gatewayip");
247                 if (tmp)
248                         ptr += sprintf(build_buf + ptr, "g=%s ", tmp);
249
250                 tmp = env_get("hostname");
251                 if (tmp)
252                         ptr += sprintf(build_buf + ptr, "tn=%s ", tmp);
253
254                 tmp = env_get("othbootargs");
255                 if (tmp) {
256                         strcpy(build_buf + ptr, tmp);
257                         ptr += strlen(tmp);
258                 }
259
260                 bootline = build_buf;
261         }
262
263         memcpy((void *)bootaddr, bootline, max(strlen(bootline), (size_t)255));
264         flush_cache(bootaddr, max(strlen(bootline), (size_t)255));
265         printf("## Using bootline (@ 0x%lx): %s\n", bootaddr, (char *)bootaddr);
266
267         /*
268          * If the data at the load address is an elf image, then
269          * treat it like an elf image. Otherwise, assume that it is a
270          * binary image.
271          */
272         if (valid_elf_image(addr))
273                 addr = load_elf_image_phdr(addr);
274         else
275                 puts("## Not an ELF image, assuming binary\n");
276
277         printf("## Starting vxWorks at 0x%08lx ...\n", addr);
278
279         dcache_disable();
280 #if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI)
281         armv8_setup_psci();
282         smp_kick_all_cpus();
283 #endif
284
285 #ifdef CONFIG_X86
286         /* VxWorks on x86 uses stack to pass parameters */
287         ((asmlinkage void (*)(int))addr)(0);
288 #else
289         ((void (*)(int))addr)(0);
290 #endif
291
292         puts("## vxWorks terminated\n");
293
294         return 1;
295 }
296
297 U_BOOT_CMD(
298         bootelf, CONFIG_SYS_MAXARGS, 0, do_bootelf,
299         "Boot from an ELF image in memory",
300         "[-p|-s] [address]\n"
301         "\t- load ELF image at [address] via program headers (-p)\n"
302         "\t  or via section headers (-s)"
303 );
304
305 U_BOOT_CMD(
306         bootvx, 2, 0, do_bootvx,
307         "Boot vxWorks from an ELF image",
308         " [address] - load address of vxWorks ELF image."
309 );