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