blob: 692f7dc6ca2dce8e0c4637ae2c11277765e08dbe [file] [log] [blame]
wdenkc0218802003-03-27 12:09:35 +00001/*
2 * (C) Copyright 2003
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenkc0218802003-03-27 12:09:35 +00006 */
7
8#include <common.h>
9#include <command.h>
wdenkc0218802003-03-27 12:09:35 +000010#include <image.h>
Jean-Christophe PLAGNIOL-VILLARDa31e0912009-04-04 12:49:11 +020011#include <u-boot/zlib.h>
wdenkc0218802003-03-27 12:09:35 +000012#include <asm/byteorder.h>
13#include <asm/addrspace.h>
14
Wolfgang Denkd87080b2006-03-31 18:32:53 +020015DECLARE_GLOBAL_DATA_PTR;
16
wdenkc0218802003-03-27 12:09:35 +000017#define LINUX_MAX_ENVS 256
18#define LINUX_MAX_ARGS 256
19
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +020020static int linux_argc;
21static char **linux_argv;
wdenkc0218802003-03-27 12:09:35 +000022
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +020023static char **linux_env;
24static char *linux_env_p;
25static int linux_env_idx;
wdenkc0218802003-03-27 12:09:35 +000026
Daniel Schwierzecke51a6b72012-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);
wdenkc0218802003-03-27 12:09:35 +000029
Gabor Juhos0ea72132013-01-07 02:53:41 +000030static void boot_prep_linux(bootm_headers_t *images)
wdenkc0218802003-03-27 12:09:35 +000031{
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +020032 char *commandline = getenv("bootargs");
33 char env_buf[12];
34 char *cp;
Marian Balakowiczf13e7b22008-01-08 18:12:17 +010035
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +020036 linux_params_init(UNCACHED_SDRAM(gd->bd->bi_boot_params), commandline);
wdenkc0218802003-03-27 12:09:35 +000037
wdenk5da627a2003-10-09 20:09:04 +000038#ifdef CONFIG_MEMSIZE_IN_BYTES
Daniel Schwierzecke51a6b72012-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);
wdenk5da627a2003-10-09 20:09:04 +000041#else
Daniel Schwierzecke51a6b72012-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 Schwierzeck45bde482013-05-09 17:10:06 +020044 (ulong)(gd->ram_size >> 20));
wdenk5da627a2003-10-09 20:09:04 +000045#endif /* CONFIG_MEMSIZE_IN_BYTES */
wdenkc0218802003-03-27 12:09:35 +000046
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +020047 linux_env_set("memsize", env_buf);
wdenkc0218802003-03-27 12:09:35 +000048
Daniel Schwierzecke51a6b72012-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);
wdenkc0218802003-03-27 12:09:35 +000051
Daniel Schwierzecke51a6b72012-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);
wdenkc0218802003-03-27 12:09:35 +000054
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +020055 sprintf(env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart));
56 linux_env_set("flash_start", env_buf);
wdenkc0218802003-03-27 12:09:35 +000057
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +020058 sprintf(env_buf, "0x%X", (uint) (gd->bd->bi_flashsize));
59 linux_env_set("flash_size", env_buf);
wdenkc0218802003-03-27 12:09:35 +000060
Jason McMullane7c37452008-06-08 23:56:00 -040061 cp = getenv("ethaddr");
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +020062 if (cp)
Jason McMullane7c37452008-06-08 23:56:00 -040063 linux_env_set("ethaddr", cp);
Jason McMullane7c37452008-06-08 23:56:00 -040064
65 cp = getenv("eth1addr");
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +020066 if (cp)
Jason McMullane7c37452008-06-08 23:56:00 -040067 linux_env_set("eth1addr", cp);
Gabor Juhos0ea72132013-01-07 02:53:41 +000068}
Jason McMullane7c37452008-06-08 23:56:00 -040069
Gabor Juhos0ea72132013-01-07 02:53:41 +000070static void boot_jump_linux(bootm_headers_t *images)
71{
Daniel Schwierzeckc4b37842013-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 Juhos0ea72132013-01-07 02:53:41 +000074
Daniel Schwierzeckc4b37842013-05-09 17:10:06 +020075 debug("## Transferring control to Linux (at address %p) ...\n", kernel);
Gabor Juhos0ea72132013-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 Schwierzeckc4b37842013-05-09 17:10:06 +020082 kernel(linux_argc, (ulong)linux_argv, (ulong)linux_env, 0);
Gabor Juhos0ea72132013-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 Juhos9c170e22013-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 }
Gabor Juhos0ea72132013-01-07 02:53:41 +0000101
102 boot_prep_linux(images);
Gabor Juhose08634c2013-01-07 02:53:40 +0000103 boot_jump_linux(images);
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200104
Marian Balakowiczcd7c5962008-03-12 10:33:00 +0100105 /* does not return */
Kumar Gala40d7e992008-08-15 08:24:45 -0500106 return 1;
wdenkc0218802003-03-27 12:09:35 +0000107}
108
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200109static void linux_params_init(ulong start, char *line)
wdenkc0218802003-03-27 12:09:35 +0000110{
wdenk5da627a2003-10-09 20:09:04 +0000111 char *next, *quote, *argp;
wdenkc0218802003-03-27 12:09:35 +0000112
wdenk5da627a2003-10-09 20:09:04 +0000113 linux_argc = 1;
Daniel Schwierzeck45bde482013-05-09 17:10:06 +0200114 linux_argv = (char **)start;
wdenk5da627a2003-10-09 20:09:04 +0000115 linux_argv[0] = 0;
Daniel Schwierzeck45bde482013-05-09 17:10:06 +0200116 argp = (char *)(linux_argv + LINUX_MAX_ARGS);
wdenkc0218802003-03-27 12:09:35 +0000117
wdenk5da627a2003-10-09 20:09:04 +0000118 next = line;
wdenkc0218802003-03-27 12:09:35 +0000119
wdenk5da627a2003-10-09 20:09:04 +0000120 while (line && *line && linux_argc < LINUX_MAX_ARGS) {
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200121 quote = strchr(line, '"');
122 next = strchr(line, ' ');
wdenkc0218802003-03-27 12:09:35 +0000123
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200124 while (next && quote && quote < next) {
Daniel Schwierzeck45bde482013-05-09 17:10:06 +0200125 /*
126 * we found a left quote before the next blank
wdenk5da627a2003-10-09 20:09:04 +0000127 * now we have to find the matching right quote
128 */
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200129 next = strchr(quote + 1, '"');
130 if (next) {
131 quote = strchr(next + 1, '"');
132 next = strchr(next + 1, ' ');
wdenk5da627a2003-10-09 20:09:04 +0000133 }
134 }
135
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200136 if (!next)
137 next = line + strlen(line);
wdenk5da627a2003-10-09 20:09:04 +0000138
139 linux_argv[linux_argc] = argp;
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200140 memcpy(argp, line, next - line);
wdenk5da627a2003-10-09 20:09:04 +0000141 argp[next - line] = 0;
142
143 argp += next - line + 1;
144 linux_argc++;
145
146 if (*next)
147 next++;
148
149 line = next;
wdenk8bde7f72003-06-27 21:31:46 +0000150 }
151
Daniel Schwierzeck45bde482013-05-09 17:10:06 +0200152 linux_env = (char **)(((ulong) argp + 15) & ~15);
wdenk5da627a2003-10-09 20:09:04 +0000153 linux_env[0] = 0;
Daniel Schwierzeck45bde482013-05-09 17:10:06 +0200154 linux_env_p = (char *)(linux_env + LINUX_MAX_ENVS);
wdenk5da627a2003-10-09 20:09:04 +0000155 linux_env_idx = 0;
wdenkc0218802003-03-27 12:09:35 +0000156}
157
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200158static void linux_env_set(char *env_name, char *env_val)
wdenkc0218802003-03-27 12:09:35 +0000159{
wdenk5da627a2003-10-09 20:09:04 +0000160 if (linux_env_idx < LINUX_MAX_ENVS - 1) {
161 linux_env[linux_env_idx] = linux_env_p;
wdenkc0218802003-03-27 12:09:35 +0000162
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200163 strcpy(linux_env_p, env_name);
164 linux_env_p += strlen(env_name);
wdenkc0218802003-03-27 12:09:35 +0000165
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200166 strcpy(linux_env_p, "=");
wdenk5da627a2003-10-09 20:09:04 +0000167 linux_env_p += 1;
wdenkc0218802003-03-27 12:09:35 +0000168
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200169 strcpy(linux_env_p, env_val);
170 linux_env_p += strlen(env_val);
wdenk8bde7f72003-06-27 21:31:46 +0000171
wdenk5da627a2003-10-09 20:09:04 +0000172 linux_env_p++;
173 linux_env[++linux_env_idx] = 0;
174 }
wdenkc0218802003-03-27 12:09:35 +0000175}