blob: 692f7dc6ca2dce8e0c4637ae2c11277765e08dbe [file] [log] [blame]
wdenkbb1b8262003-03-27 12:09:35 +00001/*
2 * (C) Copyright 2003
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenkbb1b8262003-03-27 12:09:35 +00006 */
7
8#include <common.h>
9#include <command.h>
wdenkbb1b8262003-03-27 12:09:35 +000010#include <image.h>
Jean-Christophe PLAGNIOL-VILLARD6bb94492009-04-04 12:49:11 +020011#include <u-boot/zlib.h>
wdenkbb1b8262003-03-27 12:09:35 +000012#include <asm/byteorder.h>
13#include <asm/addrspace.h>
14
Wolfgang Denk6405a152006-03-31 18:32:53 +020015DECLARE_GLOBAL_DATA_PTR;
16
wdenkbb1b8262003-03-27 12:09:35 +000017#define LINUX_MAX_ENVS 256
18#define LINUX_MAX_ARGS 256
19
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020020static int linux_argc;
21static char **linux_argv;
wdenkbb1b8262003-03-27 12:09:35 +000022
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020023static char **linux_env;
24static char *linux_env_p;
25static int linux_env_idx;
wdenkbb1b8262003-03-27 12:09:35 +000026
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020027static void linux_params_init(ulong start, char *commandline);
28static void linux_env_set(char *env_name, char *env_val);
wdenkbb1b8262003-03-27 12:09:35 +000029
Gabor Juhos72cb5f02013-01-07 02:53:41 +000030static void boot_prep_linux(bootm_headers_t *images)
wdenkbb1b8262003-03-27 12:09:35 +000031{
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020032 char *commandline = getenv("bootargs");
33 char env_buf[12];
34 char *cp;
Marian Balakowiczb4a12a92008-01-08 18:12:17 +010035
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020036 linux_params_init(UNCACHED_SDRAM(gd->bd->bi_boot_params), commandline);
wdenkbb1b8262003-03-27 12:09:35 +000037
wdenk9b7f3842003-10-09 20:09:04 +000038#ifdef CONFIG_MEMSIZE_IN_BYTES
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020039 sprintf(env_buf, "%lu", (ulong)gd->ram_size);
40 debug("## Giving linux memsize in bytes, %lu\n", (ulong)gd->ram_size);
wdenk9b7f3842003-10-09 20:09:04 +000041#else
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020042 sprintf(env_buf, "%lu", (ulong)(gd->ram_size >> 20));
43 debug("## Giving linux memsize in MB, %lu\n",
Daniel Schwierzeck40f30c02013-05-09 17:10:06 +020044 (ulong)(gd->ram_size >> 20));
wdenk9b7f3842003-10-09 20:09:04 +000045#endif /* CONFIG_MEMSIZE_IN_BYTES */
wdenkbb1b8262003-03-27 12:09:35 +000046
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020047 linux_env_set("memsize", env_buf);
wdenkbb1b8262003-03-27 12:09:35 +000048
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020049 sprintf(env_buf, "0x%08X", (uint) UNCACHED_SDRAM(images->rd_start));
50 linux_env_set("initrd_start", env_buf);
wdenkbb1b8262003-03-27 12:09:35 +000051
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020052 sprintf(env_buf, "0x%X", (uint) (images->rd_end - images->rd_start));
53 linux_env_set("initrd_size", env_buf);
wdenkbb1b8262003-03-27 12:09:35 +000054
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020055 sprintf(env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart));
56 linux_env_set("flash_start", env_buf);
wdenkbb1b8262003-03-27 12:09:35 +000057
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020058 sprintf(env_buf, "0x%X", (uint) (gd->bd->bi_flashsize));
59 linux_env_set("flash_size", env_buf);
wdenkbb1b8262003-03-27 12:09:35 +000060
Jason McMullancfbe4572008-06-08 23:56:00 -040061 cp = getenv("ethaddr");
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020062 if (cp)
Jason McMullancfbe4572008-06-08 23:56:00 -040063 linux_env_set("ethaddr", cp);
Jason McMullancfbe4572008-06-08 23:56:00 -040064
65 cp = getenv("eth1addr");
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +020066 if (cp)
Jason McMullancfbe4572008-06-08 23:56:00 -040067 linux_env_set("eth1addr", cp);
Gabor Juhos72cb5f02013-01-07 02:53:41 +000068}
69
70static void boot_jump_linux(bootm_headers_t *images)
71{
Daniel Schwierzeck0b95a7c2013-05-09 17:10:06 +020072 typedef void __noreturn (*kernel_entry_t)(int, ulong, ulong, ulong);
73 kernel_entry_t kernel = (kernel_entry_t) images->ep;
Gabor Juhos72cb5f02013-01-07 02:53:41 +000074
Daniel Schwierzeck0b95a7c2013-05-09 17:10:06 +020075 debug("## Transferring control to Linux (at address %p) ...\n", kernel);
Gabor Juhos72cb5f02013-01-07 02:53:41 +000076
77 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
78
79 /* we assume that the kernel is in place */
80 printf("\nStarting kernel ...\n\n");
81
Daniel Schwierzeck0b95a7c2013-05-09 17:10:06 +020082 kernel(linux_argc, (ulong)linux_argv, (ulong)linux_env, 0);
Gabor Juhos72cb5f02013-01-07 02:53:41 +000083}
84
85int do_bootm_linux(int flag, int argc, char * const argv[],
86 bootm_headers_t *images)
87{
Gabor Juhos7f959fd2013-01-07 02:53:42 +000088 /* No need for those on MIPS */
89 if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
90 return -1;
91
92 if (flag & BOOTM_STATE_OS_PREP) {
93 boot_prep_linux(images);
94 return 0;
95 }
96
97 if (flag & BOOTM_STATE_OS_GO) {
98 boot_jump_linux(images);
99 return 0;
100 }
Jason McMullancfbe4572008-06-08 23:56:00 -0400101
Gabor Juhos72cb5f02013-01-07 02:53:41 +0000102 boot_prep_linux(images);
Gabor Juhose0d783b2013-01-07 02:53:40 +0000103 boot_jump_linux(images);
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +0200104
Marian Balakowiczdf8ff332008-03-12 10:33:00 +0100105 /* does not return */
Kumar Gala48626aa2008-08-15 08:24:45 -0500106 return 1;
wdenkbb1b8262003-03-27 12:09:35 +0000107}
108
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +0200109static void linux_params_init(ulong start, char *line)
wdenkbb1b8262003-03-27 12:09:35 +0000110{
wdenk9b7f3842003-10-09 20:09:04 +0000111 char *next, *quote, *argp;
wdenkbb1b8262003-03-27 12:09:35 +0000112
wdenk9b7f3842003-10-09 20:09:04 +0000113 linux_argc = 1;
Daniel Schwierzeck40f30c02013-05-09 17:10:06 +0200114 linux_argv = (char **)start;
wdenk9b7f3842003-10-09 20:09:04 +0000115 linux_argv[0] = 0;
Daniel Schwierzeck40f30c02013-05-09 17:10:06 +0200116 argp = (char *)(linux_argv + LINUX_MAX_ARGS);
wdenkbb1b8262003-03-27 12:09:35 +0000117
wdenk9b7f3842003-10-09 20:09:04 +0000118 next = line;
wdenkbb1b8262003-03-27 12:09:35 +0000119
wdenk9b7f3842003-10-09 20:09:04 +0000120 while (line && *line && linux_argc < LINUX_MAX_ARGS) {
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +0200121 quote = strchr(line, '"');
122 next = strchr(line, ' ');
wdenkbb1b8262003-03-27 12:09:35 +0000123
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +0200124 while (next && quote && quote < next) {
Daniel Schwierzeck40f30c02013-05-09 17:10:06 +0200125 /*
126 * we found a left quote before the next blank
wdenk9b7f3842003-10-09 20:09:04 +0000127 * now we have to find the matching right quote
128 */
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +0200129 next = strchr(quote + 1, '"');
130 if (next) {
131 quote = strchr(next + 1, '"');
132 next = strchr(next + 1, ' ');
wdenk9b7f3842003-10-09 20:09:04 +0000133 }
134 }
wdenk57b2d802003-06-27 21:31:46 +0000135
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +0200136 if (!next)
137 next = line + strlen(line);
wdenkbb1b8262003-03-27 12:09:35 +0000138
wdenk9b7f3842003-10-09 20:09:04 +0000139 linux_argv[linux_argc] = argp;
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +0200140 memcpy(argp, line, next - line);
wdenk9b7f3842003-10-09 20:09:04 +0000141 argp[next - line] = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000142
wdenk9b7f3842003-10-09 20:09:04 +0000143 argp += next - line + 1;
144 linux_argc++;
wdenk57b2d802003-06-27 21:31:46 +0000145
wdenk9b7f3842003-10-09 20:09:04 +0000146 if (*next)
147 next++;
wdenk57b2d802003-06-27 21:31:46 +0000148
wdenk9b7f3842003-10-09 20:09:04 +0000149 line = next;
150 }
wdenkbb1b8262003-03-27 12:09:35 +0000151
Daniel Schwierzeck40f30c02013-05-09 17:10:06 +0200152 linux_env = (char **)(((ulong) argp + 15) & ~15);
wdenk9b7f3842003-10-09 20:09:04 +0000153 linux_env[0] = 0;
Daniel Schwierzeck40f30c02013-05-09 17:10:06 +0200154 linux_env_p = (char *)(linux_env + LINUX_MAX_ENVS);
wdenk9b7f3842003-10-09 20:09:04 +0000155 linux_env_idx = 0;
wdenkbb1b8262003-03-27 12:09:35 +0000156}
157
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +0200158static void linux_env_set(char *env_name, char *env_val)
wdenkbb1b8262003-03-27 12:09:35 +0000159{
wdenk9b7f3842003-10-09 20:09:04 +0000160 if (linux_env_idx < LINUX_MAX_ENVS - 1) {
161 linux_env[linux_env_idx] = linux_env_p;
wdenkbb1b8262003-03-27 12:09:35 +0000162
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +0200163 strcpy(linux_env_p, env_name);
164 linux_env_p += strlen(env_name);
wdenkbb1b8262003-03-27 12:09:35 +0000165
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +0200166 strcpy(linux_env_p, "=");
wdenk9b7f3842003-10-09 20:09:04 +0000167 linux_env_p += 1;
wdenkbb1b8262003-03-27 12:09:35 +0000168
Daniel Schwierzeck83010eb2012-06-03 23:46:04 +0200169 strcpy(linux_env_p, env_val);
170 linux_env_p += strlen(env_val);
wdenk57b2d802003-06-27 21:31:46 +0000171
wdenk9b7f3842003-10-09 20:09:04 +0000172 linux_env_p++;
173 linux_env[++linux_env_idx] = 0;
174 }
wdenkbb1b8262003-03-27 12:09:35 +0000175}