blob: ade9af47e3b3df60d4fd1f765cfaa8186bfa0824 [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",
44 (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{
72 void (*theKernel) (int, char **, char **, int *);
73
74 /* find kernel entry point */
75 theKernel = (void (*)(int, char **, char **, int *))images->ep;
76
77 debug("## Transferring control to Linux (at address %08lx) ...\n",
78 (ulong) theKernel);
79
80 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
81
82 /* we assume that the kernel is in place */
83 printf("\nStarting kernel ...\n\n");
84
85 theKernel(linux_argc, linux_argv, linux_env, 0);
86}
87
88int do_bootm_linux(int flag, int argc, char * const argv[],
89 bootm_headers_t *images)
90{
Gabor Juhos9c170e22013-01-07 02:53:42 +000091 /* No need for those on MIPS */
92 if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
93 return -1;
94
95 if (flag & BOOTM_STATE_OS_PREP) {
96 boot_prep_linux(images);
97 return 0;
98 }
99
100 if (flag & BOOTM_STATE_OS_GO) {
101 boot_jump_linux(images);
102 return 0;
103 }
Gabor Juhos0ea72132013-01-07 02:53:41 +0000104
105 boot_prep_linux(images);
Gabor Juhose08634c2013-01-07 02:53:40 +0000106 boot_jump_linux(images);
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200107
Marian Balakowiczcd7c5962008-03-12 10:33:00 +0100108 /* does not return */
Kumar Gala40d7e992008-08-15 08:24:45 -0500109 return 1;
wdenkc0218802003-03-27 12:09:35 +0000110}
111
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200112static void linux_params_init(ulong start, char *line)
wdenkc0218802003-03-27 12:09:35 +0000113{
wdenk5da627a2003-10-09 20:09:04 +0000114 char *next, *quote, *argp;
wdenkc0218802003-03-27 12:09:35 +0000115
wdenk5da627a2003-10-09 20:09:04 +0000116 linux_argc = 1;
117 linux_argv = (char **) start;
118 linux_argv[0] = 0;
119 argp = (char *) (linux_argv + LINUX_MAX_ARGS);
wdenkc0218802003-03-27 12:09:35 +0000120
wdenk5da627a2003-10-09 20:09:04 +0000121 next = line;
wdenkc0218802003-03-27 12:09:35 +0000122
wdenk5da627a2003-10-09 20:09:04 +0000123 while (line && *line && linux_argc < LINUX_MAX_ARGS) {
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200124 quote = strchr(line, '"');
125 next = strchr(line, ' ');
wdenkc0218802003-03-27 12:09:35 +0000126
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200127 while (next && quote && quote < next) {
wdenk5da627a2003-10-09 20:09:04 +0000128 /* we found a left quote before the next blank
129 * now we have to find the matching right quote
130 */
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200131 next = strchr(quote + 1, '"');
132 if (next) {
133 quote = strchr(next + 1, '"');
134 next = strchr(next + 1, ' ');
wdenk5da627a2003-10-09 20:09:04 +0000135 }
136 }
137
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200138 if (!next)
139 next = line + strlen(line);
wdenk5da627a2003-10-09 20:09:04 +0000140
141 linux_argv[linux_argc] = argp;
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200142 memcpy(argp, line, next - line);
wdenk5da627a2003-10-09 20:09:04 +0000143 argp[next - line] = 0;
144
145 argp += next - line + 1;
146 linux_argc++;
147
148 if (*next)
149 next++;
150
151 line = next;
wdenk8bde7f72003-06-27 21:31:46 +0000152 }
153
wdenk5da627a2003-10-09 20:09:04 +0000154 linux_env = (char **) (((ulong) argp + 15) & ~15);
155 linux_env[0] = 0;
156 linux_env_p = (char *) (linux_env + LINUX_MAX_ENVS);
157 linux_env_idx = 0;
wdenkc0218802003-03-27 12:09:35 +0000158}
159
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200160static void linux_env_set(char *env_name, char *env_val)
wdenkc0218802003-03-27 12:09:35 +0000161{
wdenk5da627a2003-10-09 20:09:04 +0000162 if (linux_env_idx < LINUX_MAX_ENVS - 1) {
163 linux_env[linux_env_idx] = linux_env_p;
wdenkc0218802003-03-27 12:09:35 +0000164
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200165 strcpy(linux_env_p, env_name);
166 linux_env_p += strlen(env_name);
wdenkc0218802003-03-27 12:09:35 +0000167
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200168 strcpy(linux_env_p, "=");
wdenk5da627a2003-10-09 20:09:04 +0000169 linux_env_p += 1;
wdenkc0218802003-03-27 12:09:35 +0000170
Daniel Schwierzecke51a6b72012-06-03 23:46:04 +0200171 strcpy(linux_env_p, env_val);
172 linux_env_p += strlen(env_val);
wdenk8bde7f72003-06-27 21:31:46 +0000173
wdenk5da627a2003-10-09 20:09:04 +0000174 linux_env_p++;
175 linux_env[++linux_env_idx] = 0;
176 }
wdenkc0218802003-03-27 12:09:35 +0000177}