3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * SPDX-License-Identifier: GPL-2.0+
10 #include <fdt_support.h>
11 #include <asm/addrspace.h>
14 DECLARE_GLOBAL_DATA_PTR
;
16 #define LINUX_MAX_ENVS 256
17 #define LINUX_MAX_ARGS 256
19 static int linux_argc
;
20 static char **linux_argv
;
21 static char *linux_argp
;
23 static char **linux_env
;
24 static char *linux_env_p
;
25 static int linux_env_idx
;
27 static ulong
arch_get_sp(void)
31 __asm__
__volatile__("move %0, $sp" : "=r"(ret
) : );
36 void arch_lmb_reserve(struct lmb
*lmb
)
41 debug("## Current stack ends at 0x%08lx\n", sp
);
43 /* adjust sp by 4K to be safe */
45 lmb_reserve(lmb
, sp
, CONFIG_SYS_SDRAM_BASE
+ gd
->ram_size
- sp
);
48 static void linux_cmdline_init(void)
51 linux_argv
= (char **)UNCACHED_SDRAM(gd
->bd
->bi_boot_params
);
53 linux_argp
= (char *)(linux_argv
+ LINUX_MAX_ARGS
);
56 static void linux_cmdline_set(const char *value
, size_t len
)
58 linux_argv
[linux_argc
] = linux_argp
;
59 memcpy(linux_argp
, value
, len
);
62 linux_argp
+= len
+ 1;
66 static void linux_cmdline_dump(void)
70 debug("## cmdline argv at 0x%p, argp at 0x%p\n",
71 linux_argv
, linux_argp
);
73 for (i
= 1; i
< linux_argc
; i
++)
74 debug(" arg %03d: %s\n", i
, linux_argv
[i
]);
77 static void linux_cmdline_legacy(bootm_headers_t
*images
)
79 const char *bootargs
, *next
, *quote
;
83 bootargs
= getenv("bootargs");
89 while (bootargs
&& *bootargs
&& linux_argc
< LINUX_MAX_ARGS
) {
90 quote
= strchr(bootargs
, '"');
91 next
= strchr(bootargs
, ' ');
93 while (next
&& quote
&& quote
< next
) {
95 * we found a left quote before the next blank
96 * now we have to find the matching right quote
98 next
= strchr(quote
+ 1, '"');
100 quote
= strchr(next
+ 1, '"');
101 next
= strchr(next
+ 1, ' ');
106 next
= bootargs
+ strlen(bootargs
);
108 linux_cmdline_set(bootargs
, next
- bootargs
);
117 static void linux_cmdline_append(bootm_headers_t
*images
)
120 ulong mem
, rd_start
, rd_size
;
123 mem
= gd
->ram_size
>> 20;
124 sprintf(buf
, "mem=%luM", mem
);
125 linux_cmdline_set(buf
, strlen(buf
));
127 /* append rd_start and rd_size */
128 rd_start
= images
->initrd_start
;
129 rd_size
= images
->initrd_end
- images
->initrd_start
;
132 sprintf(buf
, "rd_start=0x%08lX", rd_start
);
133 linux_cmdline_set(buf
, strlen(buf
));
134 sprintf(buf
, "rd_size=0x%lX", rd_size
);
135 linux_cmdline_set(buf
, strlen(buf
));
139 static void linux_env_init(void)
141 linux_env
= (char **)(((ulong
) linux_argp
+ 15) & ~15);
143 linux_env_p
= (char *)(linux_env
+ LINUX_MAX_ENVS
);
147 static void linux_env_set(const char *env_name
, const char *env_val
)
149 if (linux_env_idx
< LINUX_MAX_ENVS
- 1) {
150 linux_env
[linux_env_idx
] = linux_env_p
;
152 strcpy(linux_env_p
, env_name
);
153 linux_env_p
+= strlen(env_name
);
155 if (CONFIG_IS_ENABLED(MALTA
)) {
157 linux_env
[++linux_env_idx
] = linux_env_p
;
159 *linux_env_p
++ = '=';
162 strcpy(linux_env_p
, env_val
);
163 linux_env_p
+= strlen(env_val
);
166 linux_env
[++linux_env_idx
] = 0;
170 static void linux_env_legacy(bootm_headers_t
*images
)
174 ulong rd_start
, rd_size
;
176 if (CONFIG_IS_ENABLED(MEMSIZE_IN_BYTES
)) {
177 sprintf(env_buf
, "%lu", (ulong
)gd
->ram_size
);
178 debug("## Giving linux memsize in bytes, %lu\n",
179 (ulong
)gd
->ram_size
);
181 sprintf(env_buf
, "%lu", (ulong
)(gd
->ram_size
>> 20));
182 debug("## Giving linux memsize in MB, %lu\n",
183 (ulong
)(gd
->ram_size
>> 20));
186 rd_start
= UNCACHED_SDRAM(images
->initrd_start
);
187 rd_size
= images
->initrd_end
- images
->initrd_start
;
191 linux_env_set("memsize", env_buf
);
193 sprintf(env_buf
, "0x%08lX", rd_start
);
194 linux_env_set("initrd_start", env_buf
);
196 sprintf(env_buf
, "0x%lX", rd_size
);
197 linux_env_set("initrd_size", env_buf
);
199 sprintf(env_buf
, "0x%08X", (uint
) (gd
->bd
->bi_flashstart
));
200 linux_env_set("flash_start", env_buf
);
202 sprintf(env_buf
, "0x%X", (uint
) (gd
->bd
->bi_flashsize
));
203 linux_env_set("flash_size", env_buf
);
205 cp
= getenv("ethaddr");
207 linux_env_set("ethaddr", cp
);
209 cp
= getenv("eth1addr");
211 linux_env_set("eth1addr", cp
);
213 if (CONFIG_IS_ENABLED(MALTA
)) {
214 sprintf(env_buf
, "%un8r", gd
->baudrate
);
215 linux_env_set("modetty0", env_buf
);
219 static int boot_reloc_ramdisk(bootm_headers_t
*images
)
221 ulong rd_len
= images
->rd_end
- images
->rd_start
;
224 * In case of legacy uImage's, relocation of ramdisk is already done
225 * by do_bootm_states() and should not repeated in 'bootm prep'.
227 if (images
->state
& BOOTM_STATE_RAMDISK
) {
228 debug("## Ramdisk already relocated\n");
232 return boot_ramdisk_high(&images
->lmb
, images
->rd_start
,
233 rd_len
, &images
->initrd_start
, &images
->initrd_end
);
236 static int boot_reloc_fdt(bootm_headers_t
*images
)
239 * In case of legacy uImage's, relocation of FDT is already done
240 * by do_bootm_states() and should not repeated in 'bootm prep'.
242 if (images
->state
& BOOTM_STATE_FDT
) {
243 debug("## FDT already relocated\n");
247 #if CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && CONFIG_IS_ENABLED(OF_LIBFDT)
248 boot_fdt_add_mem_rsv_regions(&images
->lmb
, images
->ft_addr
);
249 return boot_relocate_fdt(&images
->lmb
, &images
->ft_addr
,
256 int arch_fixup_fdt(void *blob
)
258 #if CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && CONFIG_IS_ENABLED(OF_LIBFDT)
259 u64 mem_start
= virt_to_phys((void *)gd
->bd
->bi_memstart
);
260 u64 mem_size
= gd
->ram_size
;
262 return fdt_fixup_memory_banks(blob
, &mem_start
, &mem_size
, 1);
268 static int boot_setup_fdt(bootm_headers_t
*images
)
270 return image_setup_libfdt(images
, images
->ft_addr
, images
->ft_len
,
274 static void boot_prep_linux(bootm_headers_t
*images
)
276 boot_reloc_ramdisk(images
);
278 if (CONFIG_IS_ENABLED(MIPS_BOOT_FDT
) && images
->ft_len
) {
279 boot_reloc_fdt(images
);
280 boot_setup_fdt(images
);
282 if (CONFIG_IS_ENABLED(CONFIG_MIPS_BOOT_ENV_LEGACY
))
283 linux_env_legacy(images
);
285 if (CONFIG_IS_ENABLED(MIPS_BOOT_CMDLINE_LEGACY
)) {
286 linux_cmdline_legacy(images
);
288 if (!CONFIG_IS_ENABLED(CONFIG_MIPS_BOOT_ENV_LEGACY
))
289 linux_cmdline_append(images
);
291 linux_cmdline_dump();
296 static void boot_jump_linux(bootm_headers_t
*images
)
298 typedef void __noreturn (*kernel_entry_t
)(int, ulong
, ulong
, ulong
);
299 kernel_entry_t kernel
= (kernel_entry_t
) images
->ep
;
300 ulong linux_extra
= 0;
302 debug("## Transferring control to Linux (at address %p) ...\n", kernel
);
304 bootstage_mark(BOOTSTAGE_ID_RUN_OS
);
306 if (CONFIG_IS_ENABLED(MALTA
))
307 linux_extra
= gd
->ram_size
;
309 #if CONFIG_IS_ENABLED(BOOTSTAGE_FDT)
310 bootstage_fdt_add_report();
312 #if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
317 kernel(-2, (ulong
)images
->ft_addr
, 0, 0);
319 kernel(linux_argc
, (ulong
)linux_argv
, (ulong
)linux_env
,
323 int do_bootm_linux(int flag
, int argc
, char * const argv
[],
324 bootm_headers_t
*images
)
326 /* No need for those on MIPS */
327 if (flag
& BOOTM_STATE_OS_BD_T
)
331 * Cmdline init has been moved to 'bootm prep' because it has to be
332 * done after relocation of ramdisk to always pass correct values
333 * for rd_start and rd_size to Linux kernel.
335 if (flag
& BOOTM_STATE_OS_CMDLINE
)
338 if (flag
& BOOTM_STATE_OS_PREP
) {
339 boot_prep_linux(images
);
343 if (flag
& (BOOTM_STATE_OS_GO
| BOOTM_STATE_OS_FAKE_GO
)) {
344 boot_jump_linux(images
);
348 /* does not return */