xref: /rk3399_rockchip-uboot/arch/mips/lib/bootm.c (revision f66cc1e34842da7ed23de23a5c5cd7a8f1305326)
1ea0364f1SPeter Tyser /*
2ea0364f1SPeter Tyser  * (C) Copyright 2003
3ea0364f1SPeter Tyser  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4ea0364f1SPeter Tyser  *
51a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
6ea0364f1SPeter Tyser  */
7ea0364f1SPeter Tyser 
8ea0364f1SPeter Tyser #include <common.h>
9ea0364f1SPeter Tyser #include <command.h>
10ea0364f1SPeter Tyser #include <image.h>
11ea0364f1SPeter Tyser #include <u-boot/zlib.h>
12ea0364f1SPeter Tyser #include <asm/byteorder.h>
13ea0364f1SPeter Tyser #include <asm/addrspace.h>
14ea0364f1SPeter Tyser 
15ea0364f1SPeter Tyser DECLARE_GLOBAL_DATA_PTR;
16ea0364f1SPeter Tyser 
17ea0364f1SPeter Tyser #define	LINUX_MAX_ENVS		256
18ea0364f1SPeter Tyser #define	LINUX_MAX_ARGS		256
19ea0364f1SPeter Tyser 
20ea0364f1SPeter Tyser static int linux_argc;
21ea0364f1SPeter Tyser static char **linux_argv;
22ea0364f1SPeter Tyser 
23ea0364f1SPeter Tyser static char **linux_env;
24ea0364f1SPeter Tyser static char *linux_env_p;
25ea0364f1SPeter Tyser static int linux_env_idx;
26ea0364f1SPeter Tyser 
27ea0364f1SPeter Tyser static void linux_params_init(ulong start, char *commandline);
28ea0364f1SPeter Tyser static void linux_env_set(char *env_name, char *env_val);
29ea0364f1SPeter Tyser 
30*f66cc1e3SDaniel Schwierzeck static ulong arch_get_sp(void)
31*f66cc1e3SDaniel Schwierzeck {
32*f66cc1e3SDaniel Schwierzeck 	ulong ret;
33*f66cc1e3SDaniel Schwierzeck 
34*f66cc1e3SDaniel Schwierzeck 	__asm__ __volatile__("move %0, $sp" : "=r"(ret) : );
35*f66cc1e3SDaniel Schwierzeck 
36*f66cc1e3SDaniel Schwierzeck 	return ret;
37*f66cc1e3SDaniel Schwierzeck }
38*f66cc1e3SDaniel Schwierzeck 
39*f66cc1e3SDaniel Schwierzeck void arch_lmb_reserve(struct lmb *lmb)
40*f66cc1e3SDaniel Schwierzeck {
41*f66cc1e3SDaniel Schwierzeck 	ulong sp;
42*f66cc1e3SDaniel Schwierzeck 
43*f66cc1e3SDaniel Schwierzeck 	sp = arch_get_sp();
44*f66cc1e3SDaniel Schwierzeck 	debug("## Current stack ends at 0x%08lx\n", sp);
45*f66cc1e3SDaniel Schwierzeck 
46*f66cc1e3SDaniel Schwierzeck 	/* adjust sp by 4K to be safe */
47*f66cc1e3SDaniel Schwierzeck 	sp -= 4096;
48*f66cc1e3SDaniel Schwierzeck 	lmb_reserve(lmb, sp, CONFIG_SYS_SDRAM_BASE + gd->ram_size - sp);
49*f66cc1e3SDaniel Schwierzeck }
50*f66cc1e3SDaniel Schwierzeck 
510ea7213fSGabor Juhos static void boot_prep_linux(bootm_headers_t *images)
52ea0364f1SPeter Tyser {
53ea0364f1SPeter Tyser 	char *commandline = getenv("bootargs");
54ea0364f1SPeter Tyser 	char env_buf[12];
55ea0364f1SPeter Tyser 	char *cp;
56ea0364f1SPeter Tyser 
57ea0364f1SPeter Tyser 	linux_params_init(UNCACHED_SDRAM(gd->bd->bi_boot_params), commandline);
58ea0364f1SPeter Tyser 
59ea0364f1SPeter Tyser #ifdef CONFIG_MEMSIZE_IN_BYTES
60ea0364f1SPeter Tyser 	sprintf(env_buf, "%lu", (ulong)gd->ram_size);
61ea0364f1SPeter Tyser 	debug("## Giving linux memsize in bytes, %lu\n", (ulong)gd->ram_size);
62ea0364f1SPeter Tyser #else
63ea0364f1SPeter Tyser 	sprintf(env_buf, "%lu", (ulong)(gd->ram_size >> 20));
64e51a6b7aSDaniel Schwierzeck 	debug("## Giving linux memsize in MB, %lu\n",
65e51a6b7aSDaniel Schwierzeck 	      (ulong)(gd->ram_size >> 20));
66ea0364f1SPeter Tyser #endif /* CONFIG_MEMSIZE_IN_BYTES */
67ea0364f1SPeter Tyser 
68ea0364f1SPeter Tyser 	linux_env_set("memsize", env_buf);
69ea0364f1SPeter Tyser 
70ea0364f1SPeter Tyser 	sprintf(env_buf, "0x%08X", (uint) UNCACHED_SDRAM(images->rd_start));
71ea0364f1SPeter Tyser 	linux_env_set("initrd_start", env_buf);
72ea0364f1SPeter Tyser 
73ea0364f1SPeter Tyser 	sprintf(env_buf, "0x%X", (uint) (images->rd_end - images->rd_start));
74ea0364f1SPeter Tyser 	linux_env_set("initrd_size", env_buf);
75ea0364f1SPeter Tyser 
76ea0364f1SPeter Tyser 	sprintf(env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart));
77ea0364f1SPeter Tyser 	linux_env_set("flash_start", env_buf);
78ea0364f1SPeter Tyser 
79ea0364f1SPeter Tyser 	sprintf(env_buf, "0x%X", (uint) (gd->bd->bi_flashsize));
80ea0364f1SPeter Tyser 	linux_env_set("flash_size", env_buf);
81ea0364f1SPeter Tyser 
82ea0364f1SPeter Tyser 	cp = getenv("ethaddr");
83e51a6b7aSDaniel Schwierzeck 	if (cp)
84ea0364f1SPeter Tyser 		linux_env_set("ethaddr", cp);
85ea0364f1SPeter Tyser 
86ea0364f1SPeter Tyser 	cp = getenv("eth1addr");
87e51a6b7aSDaniel Schwierzeck 	if (cp)
88ea0364f1SPeter Tyser 		linux_env_set("eth1addr", cp);
890ea7213fSGabor Juhos }
90ea0364f1SPeter Tyser 
910ea7213fSGabor Juhos static void boot_jump_linux(bootm_headers_t *images)
920ea7213fSGabor Juhos {
93c4b37847SDaniel Schwierzeck 	typedef void __noreturn (*kernel_entry_t)(int, ulong, ulong, ulong);
94c4b37847SDaniel Schwierzeck 	kernel_entry_t kernel = (kernel_entry_t) images->ep;
950ea7213fSGabor Juhos 
96c4b37847SDaniel Schwierzeck 	debug("## Transferring control to Linux (at address %p) ...\n", kernel);
970ea7213fSGabor Juhos 
980ea7213fSGabor Juhos 	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
990ea7213fSGabor Juhos 
1000ea7213fSGabor Juhos 	/* we assume that the kernel is in place */
1010ea7213fSGabor Juhos 	printf("\nStarting kernel ...\n\n");
1020ea7213fSGabor Juhos 
103c4b37847SDaniel Schwierzeck 	kernel(linux_argc, (ulong)linux_argv, (ulong)linux_env, 0);
1040ea7213fSGabor Juhos }
1050ea7213fSGabor Juhos 
1060ea7213fSGabor Juhos int do_bootm_linux(int flag, int argc, char * const argv[],
1070ea7213fSGabor Juhos 			bootm_headers_t *images)
1080ea7213fSGabor Juhos {
1099c170e2eSGabor Juhos 	/* No need for those on MIPS */
1109c170e2eSGabor Juhos 	if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
1119c170e2eSGabor Juhos 		return -1;
1129c170e2eSGabor Juhos 
1139c170e2eSGabor Juhos 	if (flag & BOOTM_STATE_OS_PREP) {
1149c170e2eSGabor Juhos 		boot_prep_linux(images);
1159c170e2eSGabor Juhos 		return 0;
1169c170e2eSGabor Juhos 	}
1179c170e2eSGabor Juhos 
1189c170e2eSGabor Juhos 	if (flag & BOOTM_STATE_OS_GO) {
1199c170e2eSGabor Juhos 		boot_jump_linux(images);
1209c170e2eSGabor Juhos 		return 0;
1219c170e2eSGabor Juhos 	}
1220ea7213fSGabor Juhos 
1230ea7213fSGabor Juhos 	boot_prep_linux(images);
124e08634c7SGabor Juhos 	boot_jump_linux(images);
125e51a6b7aSDaniel Schwierzeck 
126ea0364f1SPeter Tyser 	/* does not return */
127ea0364f1SPeter Tyser 	return 1;
128ea0364f1SPeter Tyser }
129ea0364f1SPeter Tyser 
130ea0364f1SPeter Tyser static void linux_params_init(ulong start, char *line)
131ea0364f1SPeter Tyser {
132ea0364f1SPeter Tyser 	char *next, *quote, *argp;
133ea0364f1SPeter Tyser 
134ea0364f1SPeter Tyser 	linux_argc = 1;
135ea0364f1SPeter Tyser 	linux_argv = (char **)start;
136ea0364f1SPeter Tyser 	linux_argv[0] = 0;
137ea0364f1SPeter Tyser 	argp = (char *)(linux_argv + LINUX_MAX_ARGS);
138ea0364f1SPeter Tyser 
139ea0364f1SPeter Tyser 	next = line;
140ea0364f1SPeter Tyser 
141ea0364f1SPeter Tyser 	while (line && *line && linux_argc < LINUX_MAX_ARGS) {
142ea0364f1SPeter Tyser 		quote = strchr(line, '"');
143ea0364f1SPeter Tyser 		next = strchr(line, ' ');
144ea0364f1SPeter Tyser 
145e51a6b7aSDaniel Schwierzeck 		while (next && quote && quote < next) {
14645bde489SDaniel Schwierzeck 			/*
14745bde489SDaniel Schwierzeck 			 * we found a left quote before the next blank
148ea0364f1SPeter Tyser 			 * now we have to find the matching right quote
149ea0364f1SPeter Tyser 			 */
150ea0364f1SPeter Tyser 			next = strchr(quote + 1, '"');
151e51a6b7aSDaniel Schwierzeck 			if (next) {
152ea0364f1SPeter Tyser 				quote = strchr(next + 1, '"');
153ea0364f1SPeter Tyser 				next = strchr(next + 1, ' ');
154ea0364f1SPeter Tyser 			}
155ea0364f1SPeter Tyser 		}
156ea0364f1SPeter Tyser 
157e51a6b7aSDaniel Schwierzeck 		if (!next)
158ea0364f1SPeter Tyser 			next = line + strlen(line);
159ea0364f1SPeter Tyser 
160ea0364f1SPeter Tyser 		linux_argv[linux_argc] = argp;
161ea0364f1SPeter Tyser 		memcpy(argp, line, next - line);
162ea0364f1SPeter Tyser 		argp[next - line] = 0;
163ea0364f1SPeter Tyser 
164ea0364f1SPeter Tyser 		argp += next - line + 1;
165ea0364f1SPeter Tyser 		linux_argc++;
166ea0364f1SPeter Tyser 
167ea0364f1SPeter Tyser 		if (*next)
168ea0364f1SPeter Tyser 			next++;
169ea0364f1SPeter Tyser 
170ea0364f1SPeter Tyser 		line = next;
171ea0364f1SPeter Tyser 	}
172ea0364f1SPeter Tyser 
173ea0364f1SPeter Tyser 	linux_env = (char **)(((ulong) argp + 15) & ~15);
174ea0364f1SPeter Tyser 	linux_env[0] = 0;
175ea0364f1SPeter Tyser 	linux_env_p = (char *)(linux_env + LINUX_MAX_ENVS);
176ea0364f1SPeter Tyser 	linux_env_idx = 0;
177ea0364f1SPeter Tyser }
178ea0364f1SPeter Tyser 
179ea0364f1SPeter Tyser static void linux_env_set(char *env_name, char *env_val)
180ea0364f1SPeter Tyser {
181ea0364f1SPeter Tyser 	if (linux_env_idx < LINUX_MAX_ENVS - 1) {
182ea0364f1SPeter Tyser 		linux_env[linux_env_idx] = linux_env_p;
183ea0364f1SPeter Tyser 
184ea0364f1SPeter Tyser 		strcpy(linux_env_p, env_name);
185ea0364f1SPeter Tyser 		linux_env_p += strlen(env_name);
186ea0364f1SPeter Tyser 
187ea0364f1SPeter Tyser 		strcpy(linux_env_p, "=");
188ea0364f1SPeter Tyser 		linux_env_p += 1;
189ea0364f1SPeter Tyser 
190ea0364f1SPeter Tyser 		strcpy(linux_env_p, env_val);
191ea0364f1SPeter Tyser 		linux_env_p += strlen(env_val);
192ea0364f1SPeter Tyser 
193ea0364f1SPeter Tyser 		linux_env_p++;
194ea0364f1SPeter Tyser 		linux_env[++linux_env_idx] = 0;
195ea0364f1SPeter Tyser 	}
196ea0364f1SPeter Tyser }
197