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