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