xref: /OK3568_Linux_fs/u-boot/arch/mips/lib/bootm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2003
3*4882a593Smuzhiyun  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <image.h>
10*4882a593Smuzhiyun #include <fdt_support.h>
11*4882a593Smuzhiyun #include <asm/addrspace.h>
12*4882a593Smuzhiyun #include <asm/io.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define	LINUX_MAX_ENVS		256
17*4882a593Smuzhiyun #define	LINUX_MAX_ARGS		256
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun static int linux_argc;
20*4882a593Smuzhiyun static char **linux_argv;
21*4882a593Smuzhiyun static char *linux_argp;
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun static char **linux_env;
24*4882a593Smuzhiyun static char *linux_env_p;
25*4882a593Smuzhiyun static int linux_env_idx;
26*4882a593Smuzhiyun 
arch_get_sp(void)27*4882a593Smuzhiyun static ulong arch_get_sp(void)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	ulong ret;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	__asm__ __volatile__("move %0, $sp" : "=r"(ret) : );
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	return ret;
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun 
arch_lmb_reserve(struct lmb * lmb)36*4882a593Smuzhiyun void arch_lmb_reserve(struct lmb *lmb)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun 	ulong sp;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	sp = arch_get_sp();
41*4882a593Smuzhiyun 	debug("## Current stack ends at 0x%08lx\n", sp);
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	/* adjust sp by 4K to be safe */
44*4882a593Smuzhiyun 	sp -= 4096;
45*4882a593Smuzhiyun 	lmb_reserve(lmb, sp, gd->ram_top - sp);
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun 
linux_cmdline_init(void)48*4882a593Smuzhiyun static void linux_cmdline_init(void)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	linux_argc = 1;
51*4882a593Smuzhiyun 	linux_argv = (char **)UNCACHED_SDRAM(gd->bd->bi_boot_params);
52*4882a593Smuzhiyun 	linux_argv[0] = 0;
53*4882a593Smuzhiyun 	linux_argp = (char *)(linux_argv + LINUX_MAX_ARGS);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
linux_cmdline_set(const char * value,size_t len)56*4882a593Smuzhiyun static void linux_cmdline_set(const char *value, size_t len)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	linux_argv[linux_argc] = linux_argp;
59*4882a593Smuzhiyun 	memcpy(linux_argp, value, len);
60*4882a593Smuzhiyun 	linux_argp[len] = 0;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	linux_argp += len + 1;
63*4882a593Smuzhiyun 	linux_argc++;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
linux_cmdline_dump(void)66*4882a593Smuzhiyun static void linux_cmdline_dump(void)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	int i;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	debug("## cmdline argv at 0x%p, argp at 0x%p\n",
71*4882a593Smuzhiyun 	      linux_argv, linux_argp);
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	for (i = 1; i < linux_argc; i++)
74*4882a593Smuzhiyun 		debug("   arg %03d: %s\n", i, linux_argv[i]);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
linux_cmdline_legacy(bootm_headers_t * images)77*4882a593Smuzhiyun static void linux_cmdline_legacy(bootm_headers_t *images)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	const char *bootargs, *next, *quote;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	linux_cmdline_init();
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	bootargs = env_get("bootargs");
84*4882a593Smuzhiyun 	if (!bootargs)
85*4882a593Smuzhiyun 		return;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	next = bootargs;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	while (bootargs && *bootargs && linux_argc < LINUX_MAX_ARGS) {
90*4882a593Smuzhiyun 		quote = strchr(bootargs, '"');
91*4882a593Smuzhiyun 		next = strchr(bootargs, ' ');
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 		while (next && quote && quote < next) {
94*4882a593Smuzhiyun 			/*
95*4882a593Smuzhiyun 			 * we found a left quote before the next blank
96*4882a593Smuzhiyun 			 * now we have to find the matching right quote
97*4882a593Smuzhiyun 			 */
98*4882a593Smuzhiyun 			next = strchr(quote + 1, '"');
99*4882a593Smuzhiyun 			if (next) {
100*4882a593Smuzhiyun 				quote = strchr(next + 1, '"');
101*4882a593Smuzhiyun 				next = strchr(next + 1, ' ');
102*4882a593Smuzhiyun 			}
103*4882a593Smuzhiyun 		}
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 		if (!next)
106*4882a593Smuzhiyun 			next = bootargs + strlen(bootargs);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 		linux_cmdline_set(bootargs, next - bootargs);
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 		if (*next)
111*4882a593Smuzhiyun 			next++;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 		bootargs = next;
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
linux_cmdline_append(bootm_headers_t * images)117*4882a593Smuzhiyun static void linux_cmdline_append(bootm_headers_t *images)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun 	char buf[24];
120*4882a593Smuzhiyun 	ulong mem, rd_start, rd_size;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	/* append mem */
123*4882a593Smuzhiyun 	mem = gd->ram_size >> 20;
124*4882a593Smuzhiyun 	sprintf(buf, "mem=%luM", mem);
125*4882a593Smuzhiyun 	linux_cmdline_set(buf, strlen(buf));
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	/* append rd_start and rd_size */
128*4882a593Smuzhiyun 	rd_start = images->initrd_start;
129*4882a593Smuzhiyun 	rd_size = images->initrd_end - images->initrd_start;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (rd_size) {
132*4882a593Smuzhiyun 		sprintf(buf, "rd_start=0x%08lX", rd_start);
133*4882a593Smuzhiyun 		linux_cmdline_set(buf, strlen(buf));
134*4882a593Smuzhiyun 		sprintf(buf, "rd_size=0x%lX", rd_size);
135*4882a593Smuzhiyun 		linux_cmdline_set(buf, strlen(buf));
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
linux_env_init(void)139*4882a593Smuzhiyun static void linux_env_init(void)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	linux_env = (char **)(((ulong) linux_argp + 15) & ~15);
142*4882a593Smuzhiyun 	linux_env[0] = 0;
143*4882a593Smuzhiyun 	linux_env_p = (char *)(linux_env + LINUX_MAX_ENVS);
144*4882a593Smuzhiyun 	linux_env_idx = 0;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
linux_env_set(const char * env_name,const char * env_val)147*4882a593Smuzhiyun static void linux_env_set(const char *env_name, const char *env_val)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	if (linux_env_idx < LINUX_MAX_ENVS - 1) {
150*4882a593Smuzhiyun 		linux_env[linux_env_idx] = linux_env_p;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 		strcpy(linux_env_p, env_name);
153*4882a593Smuzhiyun 		linux_env_p += strlen(env_name);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		if (CONFIG_IS_ENABLED(MALTA)) {
156*4882a593Smuzhiyun 			linux_env_p++;
157*4882a593Smuzhiyun 			linux_env[++linux_env_idx] = linux_env_p;
158*4882a593Smuzhiyun 		} else {
159*4882a593Smuzhiyun 			*linux_env_p++ = '=';
160*4882a593Smuzhiyun 		}
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 		strcpy(linux_env_p, env_val);
163*4882a593Smuzhiyun 		linux_env_p += strlen(env_val);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 		linux_env_p++;
166*4882a593Smuzhiyun 		linux_env[++linux_env_idx] = 0;
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
linux_env_legacy(bootm_headers_t * images)170*4882a593Smuzhiyun static void linux_env_legacy(bootm_headers_t *images)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	char env_buf[12];
173*4882a593Smuzhiyun 	const char *cp;
174*4882a593Smuzhiyun 	ulong rd_start, rd_size;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	if (CONFIG_IS_ENABLED(MEMSIZE_IN_BYTES)) {
177*4882a593Smuzhiyun 		sprintf(env_buf, "%lu", (ulong)gd->ram_size);
178*4882a593Smuzhiyun 		debug("## Giving linux memsize in bytes, %lu\n",
179*4882a593Smuzhiyun 		      (ulong)gd->ram_size);
180*4882a593Smuzhiyun 	} else {
181*4882a593Smuzhiyun 		sprintf(env_buf, "%lu", (ulong)(gd->ram_size >> 20));
182*4882a593Smuzhiyun 		debug("## Giving linux memsize in MB, %lu\n",
183*4882a593Smuzhiyun 		      (ulong)(gd->ram_size >> 20));
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	rd_start = UNCACHED_SDRAM(images->initrd_start);
187*4882a593Smuzhiyun 	rd_size = images->initrd_end - images->initrd_start;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	linux_env_init();
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	linux_env_set("memsize", env_buf);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	sprintf(env_buf, "0x%08lX", rd_start);
194*4882a593Smuzhiyun 	linux_env_set("initrd_start", env_buf);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	sprintf(env_buf, "0x%lX", rd_size);
197*4882a593Smuzhiyun 	linux_env_set("initrd_size", env_buf);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	sprintf(env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart));
200*4882a593Smuzhiyun 	linux_env_set("flash_start", env_buf);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	sprintf(env_buf, "0x%X", (uint) (gd->bd->bi_flashsize));
203*4882a593Smuzhiyun 	linux_env_set("flash_size", env_buf);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	cp = env_get("ethaddr");
206*4882a593Smuzhiyun 	if (cp)
207*4882a593Smuzhiyun 		linux_env_set("ethaddr", cp);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	cp = env_get("eth1addr");
210*4882a593Smuzhiyun 	if (cp)
211*4882a593Smuzhiyun 		linux_env_set("eth1addr", cp);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	if (CONFIG_IS_ENABLED(MALTA)) {
214*4882a593Smuzhiyun 		sprintf(env_buf, "%un8r", gd->baudrate);
215*4882a593Smuzhiyun 		linux_env_set("modetty0", env_buf);
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
boot_reloc_ramdisk(bootm_headers_t * images)219*4882a593Smuzhiyun static int boot_reloc_ramdisk(bootm_headers_t *images)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	ulong rd_len = images->rd_end - images->rd_start;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	/*
224*4882a593Smuzhiyun 	 * In case of legacy uImage's, relocation of ramdisk is already done
225*4882a593Smuzhiyun 	 * by do_bootm_states() and should not repeated in 'bootm prep'.
226*4882a593Smuzhiyun 	 */
227*4882a593Smuzhiyun 	if (images->state & BOOTM_STATE_RAMDISK) {
228*4882a593Smuzhiyun 		debug("## Ramdisk already relocated\n");
229*4882a593Smuzhiyun 		return 0;
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	return boot_ramdisk_high(&images->lmb, images->rd_start,
233*4882a593Smuzhiyun 		rd_len, &images->initrd_start, &images->initrd_end);
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
boot_reloc_fdt(bootm_headers_t * images)236*4882a593Smuzhiyun static int boot_reloc_fdt(bootm_headers_t *images)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun 	/*
239*4882a593Smuzhiyun 	 * In case of legacy uImage's, relocation of FDT is already done
240*4882a593Smuzhiyun 	 * by do_bootm_states() and should not repeated in 'bootm prep'.
241*4882a593Smuzhiyun 	 */
242*4882a593Smuzhiyun 	if (images->state & BOOTM_STATE_FDT) {
243*4882a593Smuzhiyun 		debug("## FDT already relocated\n");
244*4882a593Smuzhiyun 		return 0;
245*4882a593Smuzhiyun 	}
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && CONFIG_IS_ENABLED(OF_LIBFDT)
248*4882a593Smuzhiyun 	boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
249*4882a593Smuzhiyun 	return boot_relocate_fdt(&images->lmb, &images->ft_addr,
250*4882a593Smuzhiyun 		&images->ft_len);
251*4882a593Smuzhiyun #else
252*4882a593Smuzhiyun 	return 0;
253*4882a593Smuzhiyun #endif
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && CONFIG_IS_ENABLED(OF_LIBFDT)
arch_fixup_fdt(void * blob)257*4882a593Smuzhiyun int arch_fixup_fdt(void *blob)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	u64 mem_start = virt_to_phys((void *)gd->bd->bi_memstart);
260*4882a593Smuzhiyun 	u64 mem_size = gd->ram_size;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	return fdt_fixup_memory_banks(blob, &mem_start, &mem_size, 1);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun #endif
265*4882a593Smuzhiyun 
boot_setup_fdt(bootm_headers_t * images)266*4882a593Smuzhiyun static int boot_setup_fdt(bootm_headers_t *images)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	return image_setup_libfdt(images, images->ft_addr, images->ft_len,
269*4882a593Smuzhiyun 		&images->lmb);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
boot_prep_linux(bootm_headers_t * images)272*4882a593Smuzhiyun static void boot_prep_linux(bootm_headers_t *images)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	boot_reloc_ramdisk(images);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	if (CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && images->ft_len) {
277*4882a593Smuzhiyun 		boot_reloc_fdt(images);
278*4882a593Smuzhiyun 		boot_setup_fdt(images);
279*4882a593Smuzhiyun 	} else {
280*4882a593Smuzhiyun 		if (CONFIG_IS_ENABLED(MIPS_BOOT_CMDLINE_LEGACY)) {
281*4882a593Smuzhiyun 			linux_cmdline_legacy(images);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 			if (!CONFIG_IS_ENABLED(MIPS_BOOT_ENV_LEGACY))
284*4882a593Smuzhiyun 				linux_cmdline_append(images);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 			linux_cmdline_dump();
287*4882a593Smuzhiyun 		}
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 		if (CONFIG_IS_ENABLED(MIPS_BOOT_ENV_LEGACY))
290*4882a593Smuzhiyun 			linux_env_legacy(images);
291*4882a593Smuzhiyun 	}
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
boot_jump_linux(bootm_headers_t * images)294*4882a593Smuzhiyun static void boot_jump_linux(bootm_headers_t *images)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	typedef void __noreturn (*kernel_entry_t)(int, ulong, ulong, ulong);
297*4882a593Smuzhiyun 	kernel_entry_t kernel = (kernel_entry_t) images->ep;
298*4882a593Smuzhiyun 	ulong linux_extra = 0;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	debug("## Transferring control to Linux (at address %p) ...\n", kernel);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	if (CONFIG_IS_ENABLED(MALTA))
305*4882a593Smuzhiyun 		linux_extra = gd->ram_size;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(BOOTSTAGE_FDT)
308*4882a593Smuzhiyun 	bootstage_fdt_add_report();
309*4882a593Smuzhiyun #endif
310*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
311*4882a593Smuzhiyun 	bootstage_report();
312*4882a593Smuzhiyun #endif
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	if (images->ft_len)
315*4882a593Smuzhiyun 		kernel(-2, (ulong)images->ft_addr, 0, 0);
316*4882a593Smuzhiyun 	else
317*4882a593Smuzhiyun 		kernel(linux_argc, (ulong)linux_argv, (ulong)linux_env,
318*4882a593Smuzhiyun 			linux_extra);
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
do_bootm_linux(int flag,int argc,char * const argv[],bootm_headers_t * images)321*4882a593Smuzhiyun int do_bootm_linux(int flag, int argc, char * const argv[],
322*4882a593Smuzhiyun 			bootm_headers_t *images)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	/* No need for those on MIPS */
325*4882a593Smuzhiyun 	if (flag & BOOTM_STATE_OS_BD_T)
326*4882a593Smuzhiyun 		return -1;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	/*
329*4882a593Smuzhiyun 	 * Cmdline init has been moved to 'bootm prep' because it has to be
330*4882a593Smuzhiyun 	 * done after relocation of ramdisk to always pass correct values
331*4882a593Smuzhiyun 	 * for rd_start and rd_size to Linux kernel.
332*4882a593Smuzhiyun 	 */
333*4882a593Smuzhiyun 	if (flag & BOOTM_STATE_OS_CMDLINE)
334*4882a593Smuzhiyun 		return 0;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	if (flag & BOOTM_STATE_OS_PREP) {
337*4882a593Smuzhiyun 		boot_prep_linux(images);
338*4882a593Smuzhiyun 		return 0;
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
342*4882a593Smuzhiyun 		boot_jump_linux(images);
343*4882a593Smuzhiyun 		return 0;
344*4882a593Smuzhiyun 	}
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	/* does not return */
347*4882a593Smuzhiyun 	return 1;
348*4882a593Smuzhiyun }
349