blob: 8cee139ebbdfa6df93ca7348a910e8b38fdaa165 [file] [log] [blame]
Googlere00b8eb2019-07-08 16:37:07 -07001/*
2 * (C) Copyright 2000-2009
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
Googler40bc9d02023-12-15 16:42:49 +08004 *
5 * SPDX-License-Identifier: GPL-2.0+
Googlere00b8eb2019-07-08 16:37:07 -07006 */
7
8#include <common.h>
9#include <bootm.h>
10#include <fdt_support.h>
Googler40bc9d02023-12-15 16:42:49 +080011#include <libfdt.h>
Googlere00b8eb2019-07-08 16:37:07 -070012#include <malloc.h>
13#include <vxworks.h>
Googlere00b8eb2019-07-08 16:37:07 -070014
15DECLARE_GLOBAL_DATA_PTR;
16
Googler40bc9d02023-12-15 16:42:49 +080017/* void jump_to_a32_kernel(unsigned long a, unsigned long b,
18 unsigned long c); */
Googlere00b8eb2019-07-08 16:37:07 -070019static int do_bootm_standalone(int flag, int argc, char * const argv[],
20 bootm_headers_t *images)
21{
22 char *s;
23 int (*appl)(int, char *const[]);
24
Googler06419a42022-05-17 21:32:34 +080025 if (images->os.arch == IH_ARCH_ARM) {
26 jump_to_a32_kernel(images->ep, 0, 0);
27 } else {
28 /* Don't start if "autostart" is set to "no" */
Googler40bc9d02023-12-15 16:42:49 +080029 s = getenv("autostart");
Googler06419a42022-05-17 21:32:34 +080030 if ((s != NULL) && !strcmp(s, "no")) {
Googler40bc9d02023-12-15 16:42:49 +080031 setenv_hex("filesize", images->os.image_len);
Googler06419a42022-05-17 21:32:34 +080032 return 0;
33 }
34 appl = (int (*)(int, char * const []))images->ep;
35 appl(argc, argv);
Googlere00b8eb2019-07-08 16:37:07 -070036 }
Googlere00b8eb2019-07-08 16:37:07 -070037 return 0;
38}
39
40/*******************************************************************/
41/* OS booting routines */
42/*******************************************************************/
43
44#if defined(CONFIG_BOOTM_NETBSD) || defined(CONFIG_BOOTM_PLAN9)
45static void copy_args(char *dest, int argc, char * const argv[], char delim)
46{
47 int i;
48
49 for (i = 0; i < argc; i++) {
50 if (i > 0)
51 *dest++ = delim;
52 strcpy(dest, argv[i]);
53 dest += strlen(argv[i]);
54 }
55}
56#endif
57
58#ifdef CONFIG_BOOTM_NETBSD
59static int do_bootm_netbsd(int flag, int argc, char * const argv[],
60 bootm_headers_t *images)
61{
62 void (*loader)(bd_t *, image_header_t *, char *, char *);
63 image_header_t *os_hdr, *hdr;
64 ulong kernel_data, kernel_len;
Googler40bc9d02023-12-15 16:42:49 +080065 char *consdev;
Googlere00b8eb2019-07-08 16:37:07 -070066 char *cmdline;
67
68 if (flag != BOOTM_STATE_OS_GO)
69 return 0;
70
71#if defined(CONFIG_FIT)
72 if (!images->legacy_hdr_valid) {
73 fit_unsupported_reset("NetBSD");
74 return 1;
75 }
76#endif
77 hdr = images->legacy_hdr_os;
78
79 /*
80 * Booting a (NetBSD) kernel image
81 *
82 * This process is pretty similar to a standalone application:
83 * The (first part of an multi-) image must be a stage-2 loader,
84 * which in turn is responsible for loading & invoking the actual
85 * kernel. The only differences are the parameters being passed:
86 * besides the board info strucure, the loader expects a command
87 * line, the name of the console device, and (optionally) the
88 * address of the original image header.
89 */
90 os_hdr = NULL;
91 if (image_check_type(&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) {
92 image_multi_getimg(hdr, 1, &kernel_data, &kernel_len);
93 if (kernel_len)
94 os_hdr = hdr;
95 }
96
Googler40bc9d02023-12-15 16:42:49 +080097 consdev = "";
98#if defined(CONFIG_8xx_CONS_SMC1)
99 consdev = "smc1";
100#elif defined(CONFIG_8xx_CONS_SMC2)
101 consdev = "smc2";
102#elif defined(CONFIG_8xx_CONS_SCC2)
103 consdev = "scc2";
104#elif defined(CONFIG_8xx_CONS_SCC3)
105 consdev = "scc3";
106#endif
107
Googlere00b8eb2019-07-08 16:37:07 -0700108 if (argc > 0) {
109 ulong len;
110 int i;
111
112 for (i = 0, len = 0; i < argc; i += 1)
113 len += strlen(argv[i]) + 1;
114 cmdline = malloc(len);
115 copy_args(cmdline, argc, argv, ' ');
116 } else {
Googler40bc9d02023-12-15 16:42:49 +0800117 cmdline = getenv("bootargs");
Googlere00b8eb2019-07-08 16:37:07 -0700118 if (cmdline == NULL)
119 cmdline = "";
120 }
121
122 loader = (void (*)(bd_t *, image_header_t *, char *, char *))images->ep;
123
124 printf("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n",
125 (ulong)loader);
126
127 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
128
129 /*
130 * NetBSD Stage-2 Loader Parameters:
131 * arg[0]: pointer to board info data
132 * arg[1]: image load address
133 * arg[2]: char pointer to the console device to use
134 * arg[3]: char pointer to the boot arguments
135 */
Googler40bc9d02023-12-15 16:42:49 +0800136 (*loader)(gd->bd, os_hdr, consdev, cmdline);
Googlere00b8eb2019-07-08 16:37:07 -0700137
138 return 1;
139}
140#endif /* CONFIG_BOOTM_NETBSD*/
141
142#ifdef CONFIG_LYNXKDI
143static int do_bootm_lynxkdi(int flag, int argc, char * const argv[],
144 bootm_headers_t *images)
145{
146 image_header_t *hdr = &images->legacy_hdr_os_copy;
147
148 if (flag != BOOTM_STATE_OS_GO)
149 return 0;
150
151#if defined(CONFIG_FIT)
152 if (!images->legacy_hdr_valid) {
153 fit_unsupported_reset("Lynx");
154 return 1;
155 }
156#endif
157
158 lynxkdi_boot((image_header_t *)hdr);
159
160 return 1;
161}
162#endif /* CONFIG_LYNXKDI */
163
164#ifdef CONFIG_BOOTM_RTEMS
165static int do_bootm_rtems(int flag, int argc, char * const argv[],
166 bootm_headers_t *images)
167{
168 void (*entry_point)(bd_t *);
169
170 if (flag != BOOTM_STATE_OS_GO)
171 return 0;
172
173#if defined(CONFIG_FIT)
174 if (!images->legacy_hdr_valid) {
175 fit_unsupported_reset("RTEMS");
176 return 1;
177 }
178#endif
179
180 entry_point = (void (*)(bd_t *))images->ep;
181
182 printf("## Transferring control to RTEMS (at address %08lx) ...\n",
183 (ulong)entry_point);
184
185 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
186
187 /*
188 * RTEMS Parameters:
189 * r3: ptr to board info data
190 */
191 (*entry_point)(gd->bd);
192
193 return 1;
194}
195#endif /* CONFIG_BOOTM_RTEMS */
196
197#if defined(CONFIG_BOOTM_OSE)
198static int do_bootm_ose(int flag, int argc, char * const argv[],
199 bootm_headers_t *images)
200{
201 void (*entry_point)(void);
202
203 if (flag != BOOTM_STATE_OS_GO)
204 return 0;
205
206#if defined(CONFIG_FIT)
207 if (!images->legacy_hdr_valid) {
208 fit_unsupported_reset("OSE");
209 return 1;
210 }
211#endif
212
213 entry_point = (void (*)(void))images->ep;
214
215 printf("## Transferring control to OSE (at address %08lx) ...\n",
216 (ulong)entry_point);
217
218 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
219
220 /*
221 * OSE Parameters:
222 * None
223 */
224 (*entry_point)();
225
226 return 1;
227}
228#endif /* CONFIG_BOOTM_OSE */
229
230#if defined(CONFIG_BOOTM_PLAN9)
231static int do_bootm_plan9(int flag, int argc, char * const argv[],
232 bootm_headers_t *images)
233{
234 void (*entry_point)(void);
235 char *s;
236
237 if (flag != BOOTM_STATE_OS_GO)
238 return 0;
239
240#if defined(CONFIG_FIT)
241 if (!images->legacy_hdr_valid) {
242 fit_unsupported_reset("Plan 9");
243 return 1;
244 }
245#endif
246
247 /* See README.plan9 */
Googler40bc9d02023-12-15 16:42:49 +0800248 s = getenv("confaddr");
Googlere00b8eb2019-07-08 16:37:07 -0700249 if (s != NULL) {
250 char *confaddr = (char *)simple_strtoul(s, NULL, 16);
251
252 if (argc > 0) {
253 copy_args(confaddr, argc, argv, '\n');
254 } else {
Googler40bc9d02023-12-15 16:42:49 +0800255 s = getenv("bootargs");
Googlere00b8eb2019-07-08 16:37:07 -0700256 if (s != NULL)
257 strcpy(confaddr, s);
258 }
259 }
260
261 entry_point = (void (*)(void))images->ep;
262
263 printf("## Transferring control to Plan 9 (at address %08lx) ...\n",
264 (ulong)entry_point);
265
266 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
267
268 /*
269 * Plan 9 Parameters:
270 * None
271 */
272 (*entry_point)();
273
274 return 1;
275}
276#endif /* CONFIG_BOOTM_PLAN9 */
277
278#if defined(CONFIG_BOOTM_VXWORKS) && \
279 (defined(CONFIG_PPC) || defined(CONFIG_ARM))
280
Googler40bc9d02023-12-15 16:42:49 +0800281void do_bootvx_fdt(bootm_headers_t *images)
Googlere00b8eb2019-07-08 16:37:07 -0700282{
283#if defined(CONFIG_OF_LIBFDT)
284 int ret;
285 char *bootline;
286 ulong of_size = images->ft_len;
287 char **of_flat_tree = &images->ft_addr;
288 struct lmb *lmb = &images->lmb;
289
290 if (*of_flat_tree) {
291 boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree);
292
293 ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size);
294 if (ret)
295 return;
296
Googlere00b8eb2019-07-08 16:37:07 -0700297 ret = fdt_add_subnode(*of_flat_tree, 0, "chosen");
298 if ((ret >= 0 || ret == -FDT_ERR_EXISTS)) {
Googler40bc9d02023-12-15 16:42:49 +0800299 bootline = getenv("bootargs");
Googlere00b8eb2019-07-08 16:37:07 -0700300 if (bootline) {
301 ret = fdt_find_and_setprop(*of_flat_tree,
302 "/chosen", "bootargs",
303 bootline,
304 strlen(bootline) + 1, 1);
305 if (ret < 0) {
306 printf("## ERROR: %s : %s\n", __func__,
307 fdt_strerror(ret));
308 return;
309 }
310 }
311 } else {
312 printf("## ERROR: %s : %s\n", __func__,
313 fdt_strerror(ret));
314 return;
315 }
316 }
317#endif
318
319 boot_prep_vxworks(images);
320
321 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
322
323#if defined(CONFIG_OF_LIBFDT)
324 printf("## Starting vxWorks at 0x%08lx, device tree at 0x%08lx ...\n",
325 (ulong)images->ep, (ulong)*of_flat_tree);
326#else
327 printf("## Starting vxWorks at 0x%08lx\n", (ulong)images->ep);
328#endif
329
330 boot_jump_vxworks(images);
331
332 puts("## vxWorks terminated\n");
333}
334
Googler40bc9d02023-12-15 16:42:49 +0800335static int do_bootm_vxworks(int flag, int argc, char * const argv[],
336 bootm_headers_t *images)
Googlere00b8eb2019-07-08 16:37:07 -0700337{
338 if (flag != BOOTM_STATE_OS_GO)
339 return 0;
340
341#if defined(CONFIG_FIT)
342 if (!images->legacy_hdr_valid) {
343 fit_unsupported_reset("VxWorks");
344 return 1;
345 }
346#endif
347
348 do_bootvx_fdt(images);
349
350 return 1;
351}
352#endif
353
354#if defined(CONFIG_CMD_ELF)
355static int do_bootm_qnxelf(int flag, int argc, char * const argv[],
356 bootm_headers_t *images)
357{
358 char *local_args[2];
359 char str[16];
Googlere00b8eb2019-07-08 16:37:07 -0700360
361 if (flag != BOOTM_STATE_OS_GO)
362 return 0;
363
364#if defined(CONFIG_FIT)
365 if (!images->legacy_hdr_valid) {
366 fit_unsupported_reset("QNX");
367 return 1;
368 }
369#endif
370
371 sprintf(str, "%lx", images->ep); /* write entry-point into string */
372 local_args[0] = argv[0];
373 local_args[1] = str; /* and provide it via the arguments */
Googlere00b8eb2019-07-08 16:37:07 -0700374 do_bootelf(NULL, 0, 2, local_args);
375
Googlere00b8eb2019-07-08 16:37:07 -0700376 return 1;
377}
378#endif
379
380#ifdef CONFIG_INTEGRITY
381static int do_bootm_integrity(int flag, int argc, char * const argv[],
382 bootm_headers_t *images)
383{
384 void (*entry_point)(void);
385
386 if (flag != BOOTM_STATE_OS_GO)
387 return 0;
388
389#if defined(CONFIG_FIT)
390 if (!images->legacy_hdr_valid) {
391 fit_unsupported_reset("INTEGRITY");
392 return 1;
393 }
394#endif
395
396 entry_point = (void (*)(void))images->ep;
397
398 printf("## Transferring control to INTEGRITY (at address %08lx) ...\n",
399 (ulong)entry_point);
400
401 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
402
403 /*
404 * INTEGRITY Parameters:
405 * None
406 */
407 (*entry_point)();
408
409 return 1;
410}
411#endif
412
Googlere00b8eb2019-07-08 16:37:07 -0700413static boot_os_fn *boot_os[] = {
414 [IH_OS_U_BOOT] = do_bootm_standalone,
415#ifdef CONFIG_BOOTM_LINUX
416 [IH_OS_LINUX] = do_bootm_linux,
417#endif
418#ifdef CONFIG_BOOTM_NETBSD
419 [IH_OS_NETBSD] = do_bootm_netbsd,
420#endif
421#ifdef CONFIG_LYNXKDI
422 [IH_OS_LYNXOS] = do_bootm_lynxkdi,
423#endif
424#ifdef CONFIG_BOOTM_RTEMS
425 [IH_OS_RTEMS] = do_bootm_rtems,
426#endif
427#if defined(CONFIG_BOOTM_OSE)
428 [IH_OS_OSE] = do_bootm_ose,
429#endif
430#if defined(CONFIG_BOOTM_PLAN9)
431 [IH_OS_PLAN9] = do_bootm_plan9,
432#endif
433#if defined(CONFIG_BOOTM_VXWORKS) && \
Googler40bc9d02023-12-15 16:42:49 +0800434 (defined(CONFIG_PPC) || defined(CONFIG_ARM))
Googlere00b8eb2019-07-08 16:37:07 -0700435 [IH_OS_VXWORKS] = do_bootm_vxworks,
436#endif
437#if defined(CONFIG_CMD_ELF)
438 [IH_OS_QNX] = do_bootm_qnxelf,
439#endif
440#ifdef CONFIG_INTEGRITY
441 [IH_OS_INTEGRITY] = do_bootm_integrity,
442#endif
Googlere00b8eb2019-07-08 16:37:07 -0700443};
444
445/* Allow for arch specific config before we boot */
446__weak void arch_preboot_os(void)
447{
448 /* please define platform specific arch_preboot_os() */
449}
450
Googlere00b8eb2019-07-08 16:37:07 -0700451int boot_selected_os(int argc, char * const argv[], int state,
452 bootm_headers_t *images, boot_os_fn *boot_fn)
453{
454 arch_preboot_os();
Googlere00b8eb2019-07-08 16:37:07 -0700455 boot_fn(state, argc, argv, images);
456
457 /* Stand-alone may return when 'autostart' is 'no' */
458 if (images->os.type == IH_TYPE_STANDALONE ||
Googlere00b8eb2019-07-08 16:37:07 -0700459 state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
460 return 0;
461 bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
Googler40bc9d02023-12-15 16:42:49 +0800462#ifdef DEBUG
463 puts("\n## Control returned to monitor - resetting...\n");
464#endif
Googlere00b8eb2019-07-08 16:37:07 -0700465 return BOOTM_ERR_RESET;
466}
467
468boot_os_fn *bootm_os_get_boot_func(int os)
469{
470#ifdef CONFIG_NEEDS_MANUAL_RELOC
471 static bool relocated;
472
473 if (!relocated) {
474 int i;
475
476 /* relocate boot function table */
477 for (i = 0; i < ARRAY_SIZE(boot_os); i++)
478 if (boot_os[i] != NULL)
479 boot_os[i] += gd->reloc_off;
480
481 relocated = true;
482 }
483#endif
484 return boot_os[os];
485}