Blame view

arch/mips/lib/bootm.c 7.63 KB
c021880ac   wdenk   * Add support for...
1
2
3
4
  /*
   * (C) Copyright 2003
   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
5
   * SPDX-License-Identifier:	GPL-2.0+
c021880ac   wdenk   * Add support for...
6
7
8
   */
  
  #include <common.h>
c021880ac   wdenk   * Add support for...
9
  #include <image.h>
5002d8cc5   Daniel Schwierzeck   MIPS: bootm: prep...
10
  #include <fdt_support.h>
c021880ac   wdenk   * Add support for...
11
  #include <asm/addrspace.h>
d87080b72   Wolfgang Denk   GCC-4.x fixes: cl...
12
  DECLARE_GLOBAL_DATA_PTR;
c021880ac   wdenk   * Add support for...
13
14
  #define	LINUX_MAX_ENVS		256
  #define	LINUX_MAX_ARGS		256
e51a6b7a6   Daniel Schwierzeck   MIPS: bootm.c: ma...
15
16
  static int linux_argc;
  static char **linux_argv;
59e8cbdb1   Daniel Schwierzeck   MIPS: bootm: refa...
17
  static char *linux_argp;
c021880ac   wdenk   * Add support for...
18

e51a6b7a6   Daniel Schwierzeck   MIPS: bootm.c: ma...
19
20
21
  static char **linux_env;
  static char *linux_env_p;
  static int linux_env_idx;
c021880ac   wdenk   * Add support for...
22

f66cc1e34   Daniel Schwierzeck   MIPS: bootm: add ...
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  static ulong arch_get_sp(void)
  {
  	ulong ret;
  
  	__asm__ __volatile__("move %0, $sp" : "=r"(ret) : );
  
  	return ret;
  }
  
  void arch_lmb_reserve(struct lmb *lmb)
  {
  	ulong sp;
  
  	sp = arch_get_sp();
  	debug("## Current stack ends at 0x%08lx
  ", sp);
  
  	/* adjust sp by 4K to be safe */
  	sp -= 4096;
  	lmb_reserve(lmb, sp, CONFIG_SYS_SDRAM_BASE + gd->ram_size - sp);
  }
59e8cbdb1   Daniel Schwierzeck   MIPS: bootm: refa...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  static void linux_cmdline_init(void)
  {
  	linux_argc = 1;
  	linux_argv = (char **)UNCACHED_SDRAM(gd->bd->bi_boot_params);
  	linux_argv[0] = 0;
  	linux_argp = (char *)(linux_argv + LINUX_MAX_ARGS);
  }
  
  static void linux_cmdline_set(const char *value, size_t len)
  {
  	linux_argv[linux_argc] = linux_argp;
  	memcpy(linux_argp, value, len);
  	linux_argp[len] = 0;
  
  	linux_argp += len + 1;
  	linux_argc++;
  }
  
  static void linux_cmdline_dump(void)
  {
  	int i;
  
  	debug("## cmdline argv at 0x%p, argp at 0x%p
  ",
  	      linux_argv, linux_argp);
  
  	for (i = 1; i < linux_argc; i++)
  		debug("   arg %03d: %s
  ", i, linux_argv[i]);
  }
25fc664f4   Daniel Schwierzeck   MIPS: bootm: refa...
74
  static void linux_cmdline_legacy(bootm_headers_t *images)
59e8cbdb1   Daniel Schwierzeck   MIPS: bootm: refa...
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  {
  	const char *bootargs, *next, *quote;
  
  	linux_cmdline_init();
  
  	bootargs = getenv("bootargs");
  	if (!bootargs)
  		return;
  
  	next = bootargs;
  
  	while (bootargs && *bootargs && linux_argc < LINUX_MAX_ARGS) {
  		quote = strchr(bootargs, '"');
  		next = strchr(bootargs, ' ');
  
  		while (next && quote && quote < next) {
  			/*
  			 * we found a left quote before the next blank
  			 * now we have to find the matching right quote
  			 */
  			next = strchr(quote + 1, '"');
  			if (next) {
  				quote = strchr(next + 1, '"');
  				next = strchr(next + 1, ' ');
  			}
  		}
  
  		if (!next)
  			next = bootargs + strlen(bootargs);
  
  		linux_cmdline_set(bootargs, next - bootargs);
  
  		if (*next)
  			next++;
  
  		bootargs = next;
  	}
25fc664f4   Daniel Schwierzeck   MIPS: bootm: refa...
112
  }
59e8cbdb1   Daniel Schwierzeck   MIPS: bootm: refa...
113

8cec725ad   Daniel Schwierzeck   MIPS: bootm: add ...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  static void linux_cmdline_append(bootm_headers_t *images)
  {
  	char buf[24];
  	ulong mem, rd_start, rd_size;
  
  	/* append mem */
  	mem = gd->ram_size >> 20;
  	sprintf(buf, "mem=%luM", mem);
  	linux_cmdline_set(buf, strlen(buf));
  
  	/* append rd_start and rd_size */
  	rd_start = images->initrd_start;
  	rd_size = images->initrd_end - images->initrd_start;
  
  	if (rd_size) {
  		sprintf(buf, "rd_start=0x%08lX", rd_start);
  		linux_cmdline_set(buf, strlen(buf));
  		sprintf(buf, "rd_size=0x%lX", rd_size);
  		linux_cmdline_set(buf, strlen(buf));
  	}
  }
15f8aa909   Daniel Schwierzeck   MIPS: bootm: refa...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  static void linux_env_init(void)
  {
  	linux_env = (char **)(((ulong) linux_argp + 15) & ~15);
  	linux_env[0] = 0;
  	linux_env_p = (char *)(linux_env + LINUX_MAX_ENVS);
  	linux_env_idx = 0;
  }
  
  static void linux_env_set(const char *env_name, const char *env_val)
  {
  	if (linux_env_idx < LINUX_MAX_ENVS - 1) {
  		linux_env[linux_env_idx] = linux_env_p;
  
  		strcpy(linux_env_p, env_name);
  		linux_env_p += strlen(env_name);
347ea94e2   Daniel Schwierzeck   MIPS: bootm: use ...
150
  		if (CONFIG_IS_ENABLED(MALTA)) {
b87493f49   Daniel Schwierzeck   MIPS: bootm: add ...
151
152
153
154
155
  			linux_env_p++;
  			linux_env[++linux_env_idx] = linux_env_p;
  		} else {
  			*linux_env_p++ = '=';
  		}
15f8aa909   Daniel Schwierzeck   MIPS: bootm: refa...
156
157
158
159
160
161
162
163
  
  		strcpy(linux_env_p, env_val);
  		linux_env_p += strlen(env_val);
  
  		linux_env_p++;
  		linux_env[++linux_env_idx] = 0;
  	}
  }
ca65e5851   Daniel Schwierzeck   MIPS: bootm: refa...
164
  static void linux_env_legacy(bootm_headers_t *images)
c021880ac   wdenk   * Add support for...
165
  {
e51a6b7a6   Daniel Schwierzeck   MIPS: bootm.c: ma...
166
  	char env_buf[12];
15f8aa909   Daniel Schwierzeck   MIPS: bootm: refa...
167
  	const char *cp;
6c154552b   Daniel Schwierzeck   MIPS: bootm: add ...
168
  	ulong rd_start, rd_size;
5da627a42   wdenk   * Patch by Steven...
169

347ea94e2   Daniel Schwierzeck   MIPS: bootm: use ...
170
171
172
173
174
175
176
177
178
179
180
  	if (CONFIG_IS_ENABLED(MEMSIZE_IN_BYTES)) {
  		sprintf(env_buf, "%lu", (ulong)gd->ram_size);
  		debug("## Giving linux memsize in bytes, %lu
  ",
  		      (ulong)gd->ram_size);
  	} else {
  		sprintf(env_buf, "%lu", (ulong)(gd->ram_size >> 20));
  		debug("## Giving linux memsize in MB, %lu
  ",
  		      (ulong)(gd->ram_size >> 20));
  	}
c021880ac   wdenk   * Add support for...
181

6c154552b   Daniel Schwierzeck   MIPS: bootm: add ...
182
183
  	rd_start = UNCACHED_SDRAM(images->initrd_start);
  	rd_size = images->initrd_end - images->initrd_start;
15f8aa909   Daniel Schwierzeck   MIPS: bootm: refa...
184
  	linux_env_init();
e51a6b7a6   Daniel Schwierzeck   MIPS: bootm.c: ma...
185
  	linux_env_set("memsize", env_buf);
c021880ac   wdenk   * Add support for...
186

6c154552b   Daniel Schwierzeck   MIPS: bootm: add ...
187
  	sprintf(env_buf, "0x%08lX", rd_start);
e51a6b7a6   Daniel Schwierzeck   MIPS: bootm.c: ma...
188
  	linux_env_set("initrd_start", env_buf);
c021880ac   wdenk   * Add support for...
189

6c154552b   Daniel Schwierzeck   MIPS: bootm: add ...
190
  	sprintf(env_buf, "0x%lX", rd_size);
e51a6b7a6   Daniel Schwierzeck   MIPS: bootm.c: ma...
191
  	linux_env_set("initrd_size", env_buf);
c021880ac   wdenk   * Add support for...
192

e51a6b7a6   Daniel Schwierzeck   MIPS: bootm.c: ma...
193
194
  	sprintf(env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart));
  	linux_env_set("flash_start", env_buf);
c021880ac   wdenk   * Add support for...
195

e51a6b7a6   Daniel Schwierzeck   MIPS: bootm.c: ma...
196
197
  	sprintf(env_buf, "0x%X", (uint) (gd->bd->bi_flashsize));
  	linux_env_set("flash_size", env_buf);
c021880ac   wdenk   * Add support for...
198

e7c374529   Jason McMullan   mips: When bootin...
199
  	cp = getenv("ethaddr");
e51a6b7a6   Daniel Schwierzeck   MIPS: bootm.c: ma...
200
  	if (cp)
e7c374529   Jason McMullan   mips: When bootin...
201
  		linux_env_set("ethaddr", cp);
e7c374529   Jason McMullan   mips: When bootin...
202
203
  
  	cp = getenv("eth1addr");
e51a6b7a6   Daniel Schwierzeck   MIPS: bootm.c: ma...
204
  	if (cp)
e7c374529   Jason McMullan   mips: When bootin...
205
  		linux_env_set("eth1addr", cp);
b87493f49   Daniel Schwierzeck   MIPS: bootm: add ...
206

347ea94e2   Daniel Schwierzeck   MIPS: bootm: use ...
207
  	if (CONFIG_IS_ENABLED(MALTA)) {
d18d49d7a   Paul Burton   mips: don't hardc...
208
209
210
  		sprintf(env_buf, "%un8r", gd->baudrate);
  		linux_env_set("modetty0", env_buf);
  	}
0ea7213f6   Gabor Juhos   MIPS: bootm.c: se...
211
  }
2bb5b6387   Daniel Schwierzeck   MIPS: bootm: rewo...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  static int boot_reloc_ramdisk(bootm_headers_t *images)
  {
  	ulong rd_len = images->rd_end - images->rd_start;
  
  	/*
  	 * In case of legacy uImage's, relocation of ramdisk is already done
  	 * by do_bootm_states() and should not repeated in 'bootm prep'.
  	 */
  	if (images->state & BOOTM_STATE_RAMDISK) {
  		debug("## Ramdisk already relocated
  ");
  		return 0;
  	}
  
  	return boot_ramdisk_high(&images->lmb, images->rd_start,
  		rd_len, &images->initrd_start, &images->initrd_end);
  }
  
  static int boot_reloc_fdt(bootm_headers_t *images)
  {
  	/*
  	 * In case of legacy uImage's, relocation of FDT is already done
  	 * by do_bootm_states() and should not repeated in 'bootm prep'.
  	 */
  	if (images->state & BOOTM_STATE_FDT) {
  		debug("## FDT already relocated
  ");
  		return 0;
  	}
  
  #if CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && CONFIG_IS_ENABLED(OF_LIBFDT)
  	boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
  	return boot_relocate_fdt(&images->lmb, &images->ft_addr,
  		&images->ft_len);
  #else
  	return 0;
  #endif
  }
  
  int arch_fixup_memory_node(void *blob)
  {
  #if CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && CONFIG_IS_ENABLED(OF_LIBFDT)
  	u64 mem_start = 0;
  	u64 mem_size = gd->ram_size;
  
  	return fdt_fixup_memory_banks(blob, &mem_start, &mem_size, 1);
  #else
  	return 0;
  #endif
  }
  
  static int boot_setup_fdt(bootm_headers_t *images)
  {
  	return image_setup_libfdt(images, images->ft_addr, images->ft_len,
  		&images->lmb);
  }
ca65e5851   Daniel Schwierzeck   MIPS: bootm: refa...
268
269
  static void boot_prep_linux(bootm_headers_t *images)
  {
2bb5b6387   Daniel Schwierzeck   MIPS: bootm: rewo...
270
  	boot_reloc_ramdisk(images);
5002d8cc5   Daniel Schwierzeck   MIPS: bootm: prep...
271

2bb5b6387   Daniel Schwierzeck   MIPS: bootm: rewo...
272
273
  	if (CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && images->ft_len) {
  		boot_reloc_fdt(images);
5002d8cc5   Daniel Schwierzeck   MIPS: bootm: prep...
274
  		boot_setup_fdt(images);
2bb5b6387   Daniel Schwierzeck   MIPS: bootm: rewo...
275
276
277
278
279
280
281
282
283
284
285
286
287
  	} else {
  		if (CONFIG_IS_ENABLED(CONFIG_MIPS_BOOT_ENV_LEGACY))
  			linux_env_legacy(images);
  
  		if (CONFIG_IS_ENABLED(MIPS_BOOT_CMDLINE_LEGACY)) {
  			linux_cmdline_legacy(images);
  
  			if (!CONFIG_IS_ENABLED(CONFIG_MIPS_BOOT_ENV_LEGACY))
  				linux_cmdline_append(images);
  
  			linux_cmdline_dump();
  		}
  	}
ca65e5851   Daniel Schwierzeck   MIPS: bootm: refa...
288
  }
0ea7213f6   Gabor Juhos   MIPS: bootm.c: se...
289
290
  static void boot_jump_linux(bootm_headers_t *images)
  {
c4b37847d   Daniel Schwierzeck   MIPS: bootm: opti...
291
292
  	typedef void __noreturn (*kernel_entry_t)(int, ulong, ulong, ulong);
  	kernel_entry_t kernel = (kernel_entry_t) images->ep;
b87493f49   Daniel Schwierzeck   MIPS: bootm: add ...
293
  	ulong linux_extra = 0;
0ea7213f6   Gabor Juhos   MIPS: bootm.c: se...
294

c4b37847d   Daniel Schwierzeck   MIPS: bootm: opti...
295
296
  	debug("## Transferring control to Linux (at address %p) ...
  ", kernel);
0ea7213f6   Gabor Juhos   MIPS: bootm.c: se...
297
298
  
  	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
347ea94e2   Daniel Schwierzeck   MIPS: bootm: use ...
299
  	if (CONFIG_IS_ENABLED(MALTA))
b87493f49   Daniel Schwierzeck   MIPS: bootm: add ...
300
  		linux_extra = gd->ram_size;
347ea94e2   Daniel Schwierzeck   MIPS: bootm: use ...
301
  #if CONFIG_IS_ENABLED(BOOTSTAGE_FDT)
e13a50b34   Daniel Schwierzeck   MIPS: bootm: add ...
302
303
  	bootstage_fdt_add_report();
  #endif
347ea94e2   Daniel Schwierzeck   MIPS: bootm: use ...
304
  #if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
e13a50b34   Daniel Schwierzeck   MIPS: bootm: add ...
305
306
  	bootstage_report();
  #endif
0ea7213f6   Gabor Juhos   MIPS: bootm.c: se...
307

90b1c9fad   Daniel Schwierzeck   MIPS: implement d...
308
309
310
311
312
  	if (images->ft_len)
  		kernel(-2, (ulong)images->ft_addr, 0, 0);
  	else
  		kernel(linux_argc, (ulong)linux_argv, (ulong)linux_env,
  			linux_extra);
0ea7213f6   Gabor Juhos   MIPS: bootm.c: se...
313
314
315
316
317
  }
  
  int do_bootm_linux(int flag, int argc, char * const argv[],
  			bootm_headers_t *images)
  {
9c170e2ef   Gabor Juhos   MIPS: bootm.c: ad...
318
  	/* No need for those on MIPS */
59e8cbdb1   Daniel Schwierzeck   MIPS: bootm: refa...
319
  	if (flag & BOOTM_STATE_OS_BD_T)
9c170e2ef   Gabor Juhos   MIPS: bootm.c: ad...
320
  		return -1;
2bb5b6387   Daniel Schwierzeck   MIPS: bootm: rewo...
321
322
323
324
325
326
  	/*
  	 * Cmdline init has been moved to 'bootm prep' because it has to be
  	 * done after relocation of ramdisk to always pass correct values
  	 * for rd_start and rd_size to Linux kernel.
  	 */
  	if (flag & BOOTM_STATE_OS_CMDLINE)
59e8cbdb1   Daniel Schwierzeck   MIPS: bootm: refa...
327
  		return 0;
59e8cbdb1   Daniel Schwierzeck   MIPS: bootm: refa...
328

9c170e2ef   Gabor Juhos   MIPS: bootm.c: ad...
329
330
331
332
  	if (flag & BOOTM_STATE_OS_PREP) {
  		boot_prep_linux(images);
  		return 0;
  	}
2bb5b6387   Daniel Schwierzeck   MIPS: bootm: rewo...
333
  	if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
9c170e2ef   Gabor Juhos   MIPS: bootm.c: ad...
334
335
336
  		boot_jump_linux(images);
  		return 0;
  	}
e7c374529   Jason McMullan   mips: When bootin...
337

cd7c596e9   Marian Balakowicz   [new uImage] Add ...
338
  	/* does not return */
40d7e99d3   Kumar Gala   bootm: refactor d...
339
  	return 1;
c021880ac   wdenk   * Add support for...
340
  }