]>
Commit | Line | Data |
---|---|---|
c021880a WD |
1 | /* |
2 | * (C) Copyright 2003 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * See file CREDITS for list of people who contributed to this | |
6 | * project. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | * | |
22 | */ | |
23 | ||
24 | #include <common.h> | |
25 | #include <command.h> | |
c021880a | 26 | #include <image.h> |
a31e091a | 27 | #include <u-boot/zlib.h> |
c021880a WD |
28 | #include <asm/byteorder.h> |
29 | #include <asm/addrspace.h> | |
30 | ||
d87080b7 WD |
31 | DECLARE_GLOBAL_DATA_PTR; |
32 | ||
c021880a WD |
33 | #define LINUX_MAX_ENVS 256 |
34 | #define LINUX_MAX_ARGS 256 | |
35 | ||
e51a6b7a DS |
36 | static int linux_argc; |
37 | static char **linux_argv; | |
c021880a | 38 | |
e51a6b7a DS |
39 | static char **linux_env; |
40 | static char *linux_env_p; | |
41 | static int linux_env_idx; | |
c021880a | 42 | |
e51a6b7a DS |
43 | static void linux_params_init(ulong start, char *commandline); |
44 | static void linux_env_set(char *env_name, char *env_val); | |
c021880a | 45 | |
e51a6b7a DS |
46 | int do_bootm_linux(int flag, int argc, char * const argv[], |
47 | bootm_headers_t *images) | |
c021880a | 48 | { |
e51a6b7a DS |
49 | void (*theKernel) (int, char **, char **, int *); |
50 | char *commandline = getenv("bootargs"); | |
51 | char env_buf[12]; | |
52 | char *cp; | |
f13e7b2e | 53 | |
49c3a861 KG |
54 | if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) |
55 | return 1; | |
56 | ||
d5934ad7 | 57 | /* find kernel entry point */ |
c160a954 | 58 | theKernel = (void (*)(int, char **, char **, int *))images->ep; |
c021880a | 59 | |
770605e4 | 60 | bootstage_mark(BOOTSTAGE_ID_RUN_OS); |
c021880a | 61 | |
75a279c8 | 62 | debug("## Transferring control to Linux (at address %08lx) ...\n", |
5da627a4 | 63 | (ulong) theKernel); |
c021880a | 64 | |
e51a6b7a | 65 | linux_params_init(UNCACHED_SDRAM(gd->bd->bi_boot_params), commandline); |
5da627a4 WD |
66 | |
67 | #ifdef CONFIG_MEMSIZE_IN_BYTES | |
e51a6b7a DS |
68 | sprintf(env_buf, "%lu", (ulong)gd->ram_size); |
69 | debug("## Giving linux memsize in bytes, %lu\n", (ulong)gd->ram_size); | |
5da627a4 | 70 | #else |
e51a6b7a DS |
71 | sprintf(env_buf, "%lu", (ulong)(gd->ram_size >> 20)); |
72 | debug("## Giving linux memsize in MB, %lu\n", | |
73 | (ulong)(gd->ram_size >> 20)); | |
5da627a4 | 74 | #endif /* CONFIG_MEMSIZE_IN_BYTES */ |
c021880a | 75 | |
e51a6b7a | 76 | linux_env_set("memsize", env_buf); |
c021880a | 77 | |
e51a6b7a DS |
78 | sprintf(env_buf, "0x%08X", (uint) UNCACHED_SDRAM(images->rd_start)); |
79 | linux_env_set("initrd_start", env_buf); | |
c021880a | 80 | |
e51a6b7a DS |
81 | sprintf(env_buf, "0x%X", (uint) (images->rd_end - images->rd_start)); |
82 | linux_env_set("initrd_size", env_buf); | |
c021880a | 83 | |
e51a6b7a DS |
84 | sprintf(env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart)); |
85 | linux_env_set("flash_start", env_buf); | |
c021880a | 86 | |
e51a6b7a DS |
87 | sprintf(env_buf, "0x%X", (uint) (gd->bd->bi_flashsize)); |
88 | linux_env_set("flash_size", env_buf); | |
c021880a | 89 | |
e7c37452 | 90 | cp = getenv("ethaddr"); |
e51a6b7a | 91 | if (cp) |
e7c37452 | 92 | linux_env_set("ethaddr", cp); |
e7c37452 JM |
93 | |
94 | cp = getenv("eth1addr"); | |
e51a6b7a | 95 | if (cp) |
e7c37452 | 96 | linux_env_set("eth1addr", cp); |
e7c37452 | 97 | |
5da627a4 | 98 | /* we assume that the kernel is in place */ |
e51a6b7a DS |
99 | printf("\nStarting kernel ...\n\n"); |
100 | ||
101 | theKernel(linux_argc, linux_argv, linux_env, 0); | |
c021880a | 102 | |
cd7c596e | 103 | /* does not return */ |
40d7e99d | 104 | return 1; |
c021880a WD |
105 | } |
106 | ||
e51a6b7a | 107 | static void linux_params_init(ulong start, char *line) |
c021880a | 108 | { |
5da627a4 | 109 | char *next, *quote, *argp; |
8bde7f77 | 110 | |
5da627a4 WD |
111 | linux_argc = 1; |
112 | linux_argv = (char **) start; | |
113 | linux_argv[0] = 0; | |
114 | argp = (char *) (linux_argv + LINUX_MAX_ARGS); | |
115 | ||
116 | next = line; | |
c021880a | 117 | |
5da627a4 | 118 | while (line && *line && linux_argc < LINUX_MAX_ARGS) { |
e51a6b7a DS |
119 | quote = strchr(line, '"'); |
120 | next = strchr(line, ' '); | |
c021880a | 121 | |
e51a6b7a | 122 | while (next && quote && quote < next) { |
5da627a4 WD |
123 | /* we found a left quote before the next blank |
124 | * now we have to find the matching right quote | |
125 | */ | |
e51a6b7a DS |
126 | next = strchr(quote + 1, '"'); |
127 | if (next) { | |
128 | quote = strchr(next + 1, '"'); | |
129 | next = strchr(next + 1, ' '); | |
5da627a4 WD |
130 | } |
131 | } | |
8bde7f77 | 132 | |
e51a6b7a DS |
133 | if (!next) |
134 | next = line + strlen(line); | |
8bde7f77 | 135 | |
5da627a4 | 136 | linux_argv[linux_argc] = argp; |
e51a6b7a | 137 | memcpy(argp, line, next - line); |
5da627a4 | 138 | argp[next - line] = 0; |
c021880a | 139 | |
5da627a4 WD |
140 | argp += next - line + 1; |
141 | linux_argc++; | |
142 | ||
143 | if (*next) | |
144 | next++; | |
145 | ||
146 | line = next; | |
147 | } | |
148 | ||
149 | linux_env = (char **) (((ulong) argp + 15) & ~15); | |
150 | linux_env[0] = 0; | |
151 | linux_env_p = (char *) (linux_env + LINUX_MAX_ENVS); | |
152 | linux_env_idx = 0; | |
c021880a WD |
153 | } |
154 | ||
e51a6b7a | 155 | static void linux_env_set(char *env_name, char *env_val) |
c021880a | 156 | { |
5da627a4 WD |
157 | if (linux_env_idx < LINUX_MAX_ENVS - 1) { |
158 | linux_env[linux_env_idx] = linux_env_p; | |
c021880a | 159 | |
e51a6b7a DS |
160 | strcpy(linux_env_p, env_name); |
161 | linux_env_p += strlen(env_name); | |
c021880a | 162 | |
e51a6b7a | 163 | strcpy(linux_env_p, "="); |
5da627a4 | 164 | linux_env_p += 1; |
c021880a | 165 | |
e51a6b7a DS |
166 | strcpy(linux_env_p, env_val); |
167 | linux_env_p += strlen(env_val); | |
8bde7f77 | 168 | |
5da627a4 WD |
169 | linux_env_p++; |
170 | linux_env[++linux_env_idx] = 0; | |
171 | } | |
c021880a | 172 | } |