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; 22*59e8cbdbSDaniel Schwierzeck static char *linux_argp; 23ea0364f1SPeter Tyser 24ea0364f1SPeter Tyser static char **linux_env; 25ea0364f1SPeter Tyser static char *linux_env_p; 26ea0364f1SPeter Tyser static int linux_env_idx; 27ea0364f1SPeter Tyser 28*59e8cbdbSDaniel Schwierzeck static void linux_params_init(void); 29ea0364f1SPeter Tyser static void linux_env_set(char *env_name, char *env_val); 30ea0364f1SPeter Tyser 31f66cc1e3SDaniel Schwierzeck static ulong arch_get_sp(void) 32f66cc1e3SDaniel Schwierzeck { 33f66cc1e3SDaniel Schwierzeck ulong ret; 34f66cc1e3SDaniel Schwierzeck 35f66cc1e3SDaniel Schwierzeck __asm__ __volatile__("move %0, $sp" : "=r"(ret) : ); 36f66cc1e3SDaniel Schwierzeck 37f66cc1e3SDaniel Schwierzeck return ret; 38f66cc1e3SDaniel Schwierzeck } 39f66cc1e3SDaniel Schwierzeck 40f66cc1e3SDaniel Schwierzeck void arch_lmb_reserve(struct lmb *lmb) 41f66cc1e3SDaniel Schwierzeck { 42f66cc1e3SDaniel Schwierzeck ulong sp; 43f66cc1e3SDaniel Schwierzeck 44f66cc1e3SDaniel Schwierzeck sp = arch_get_sp(); 45f66cc1e3SDaniel Schwierzeck debug("## Current stack ends at 0x%08lx\n", sp); 46f66cc1e3SDaniel Schwierzeck 47f66cc1e3SDaniel Schwierzeck /* adjust sp by 4K to be safe */ 48f66cc1e3SDaniel Schwierzeck sp -= 4096; 49f66cc1e3SDaniel Schwierzeck lmb_reserve(lmb, sp, CONFIG_SYS_SDRAM_BASE + gd->ram_size - sp); 50f66cc1e3SDaniel Schwierzeck } 51f66cc1e3SDaniel Schwierzeck 52*59e8cbdbSDaniel Schwierzeck static void linux_cmdline_init(void) 53*59e8cbdbSDaniel Schwierzeck { 54*59e8cbdbSDaniel Schwierzeck linux_argc = 1; 55*59e8cbdbSDaniel Schwierzeck linux_argv = (char **)UNCACHED_SDRAM(gd->bd->bi_boot_params); 56*59e8cbdbSDaniel Schwierzeck linux_argv[0] = 0; 57*59e8cbdbSDaniel Schwierzeck linux_argp = (char *)(linux_argv + LINUX_MAX_ARGS); 58*59e8cbdbSDaniel Schwierzeck } 59*59e8cbdbSDaniel Schwierzeck 60*59e8cbdbSDaniel Schwierzeck static void linux_cmdline_set(const char *value, size_t len) 61*59e8cbdbSDaniel Schwierzeck { 62*59e8cbdbSDaniel Schwierzeck linux_argv[linux_argc] = linux_argp; 63*59e8cbdbSDaniel Schwierzeck memcpy(linux_argp, value, len); 64*59e8cbdbSDaniel Schwierzeck linux_argp[len] = 0; 65*59e8cbdbSDaniel Schwierzeck 66*59e8cbdbSDaniel Schwierzeck linux_argp += len + 1; 67*59e8cbdbSDaniel Schwierzeck linux_argc++; 68*59e8cbdbSDaniel Schwierzeck } 69*59e8cbdbSDaniel Schwierzeck 70*59e8cbdbSDaniel Schwierzeck static void linux_cmdline_dump(void) 71*59e8cbdbSDaniel Schwierzeck { 72*59e8cbdbSDaniel Schwierzeck int i; 73*59e8cbdbSDaniel Schwierzeck 74*59e8cbdbSDaniel Schwierzeck debug("## cmdline argv at 0x%p, argp at 0x%p\n", 75*59e8cbdbSDaniel Schwierzeck linux_argv, linux_argp); 76*59e8cbdbSDaniel Schwierzeck 77*59e8cbdbSDaniel Schwierzeck for (i = 1; i < linux_argc; i++) 78*59e8cbdbSDaniel Schwierzeck debug(" arg %03d: %s\n", i, linux_argv[i]); 79*59e8cbdbSDaniel Schwierzeck } 80*59e8cbdbSDaniel Schwierzeck 81*59e8cbdbSDaniel Schwierzeck static void boot_cmdline_linux(bootm_headers_t *images) 82*59e8cbdbSDaniel Schwierzeck { 83*59e8cbdbSDaniel Schwierzeck const char *bootargs, *next, *quote; 84*59e8cbdbSDaniel Schwierzeck 85*59e8cbdbSDaniel Schwierzeck linux_cmdline_init(); 86*59e8cbdbSDaniel Schwierzeck 87*59e8cbdbSDaniel Schwierzeck bootargs = getenv("bootargs"); 88*59e8cbdbSDaniel Schwierzeck if (!bootargs) 89*59e8cbdbSDaniel Schwierzeck return; 90*59e8cbdbSDaniel Schwierzeck 91*59e8cbdbSDaniel Schwierzeck next = bootargs; 92*59e8cbdbSDaniel Schwierzeck 93*59e8cbdbSDaniel Schwierzeck while (bootargs && *bootargs && linux_argc < LINUX_MAX_ARGS) { 94*59e8cbdbSDaniel Schwierzeck quote = strchr(bootargs, '"'); 95*59e8cbdbSDaniel Schwierzeck next = strchr(bootargs, ' '); 96*59e8cbdbSDaniel Schwierzeck 97*59e8cbdbSDaniel Schwierzeck while (next && quote && quote < next) { 98*59e8cbdbSDaniel Schwierzeck /* 99*59e8cbdbSDaniel Schwierzeck * we found a left quote before the next blank 100*59e8cbdbSDaniel Schwierzeck * now we have to find the matching right quote 101*59e8cbdbSDaniel Schwierzeck */ 102*59e8cbdbSDaniel Schwierzeck next = strchr(quote + 1, '"'); 103*59e8cbdbSDaniel Schwierzeck if (next) { 104*59e8cbdbSDaniel Schwierzeck quote = strchr(next + 1, '"'); 105*59e8cbdbSDaniel Schwierzeck next = strchr(next + 1, ' '); 106*59e8cbdbSDaniel Schwierzeck } 107*59e8cbdbSDaniel Schwierzeck } 108*59e8cbdbSDaniel Schwierzeck 109*59e8cbdbSDaniel Schwierzeck if (!next) 110*59e8cbdbSDaniel Schwierzeck next = bootargs + strlen(bootargs); 111*59e8cbdbSDaniel Schwierzeck 112*59e8cbdbSDaniel Schwierzeck linux_cmdline_set(bootargs, next - bootargs); 113*59e8cbdbSDaniel Schwierzeck 114*59e8cbdbSDaniel Schwierzeck if (*next) 115*59e8cbdbSDaniel Schwierzeck next++; 116*59e8cbdbSDaniel Schwierzeck 117*59e8cbdbSDaniel Schwierzeck bootargs = next; 118*59e8cbdbSDaniel Schwierzeck } 119*59e8cbdbSDaniel Schwierzeck 120*59e8cbdbSDaniel Schwierzeck linux_cmdline_dump(); 121*59e8cbdbSDaniel Schwierzeck } 122*59e8cbdbSDaniel Schwierzeck 1230ea7213fSGabor Juhos static void boot_prep_linux(bootm_headers_t *images) 124ea0364f1SPeter Tyser { 125ea0364f1SPeter Tyser char env_buf[12]; 126ea0364f1SPeter Tyser char *cp; 127ea0364f1SPeter Tyser 128*59e8cbdbSDaniel Schwierzeck linux_params_init(); 129ea0364f1SPeter Tyser 130ea0364f1SPeter Tyser #ifdef CONFIG_MEMSIZE_IN_BYTES 131ea0364f1SPeter Tyser sprintf(env_buf, "%lu", (ulong)gd->ram_size); 132ea0364f1SPeter Tyser debug("## Giving linux memsize in bytes, %lu\n", (ulong)gd->ram_size); 133ea0364f1SPeter Tyser #else 134ea0364f1SPeter Tyser sprintf(env_buf, "%lu", (ulong)(gd->ram_size >> 20)); 135e51a6b7aSDaniel Schwierzeck debug("## Giving linux memsize in MB, %lu\n", 136e51a6b7aSDaniel Schwierzeck (ulong)(gd->ram_size >> 20)); 137ea0364f1SPeter Tyser #endif /* CONFIG_MEMSIZE_IN_BYTES */ 138ea0364f1SPeter Tyser 139ea0364f1SPeter Tyser linux_env_set("memsize", env_buf); 140ea0364f1SPeter Tyser 141ea0364f1SPeter Tyser sprintf(env_buf, "0x%08X", (uint) UNCACHED_SDRAM(images->rd_start)); 142ea0364f1SPeter Tyser linux_env_set("initrd_start", env_buf); 143ea0364f1SPeter Tyser 144ea0364f1SPeter Tyser sprintf(env_buf, "0x%X", (uint) (images->rd_end - images->rd_start)); 145ea0364f1SPeter Tyser linux_env_set("initrd_size", env_buf); 146ea0364f1SPeter Tyser 147ea0364f1SPeter Tyser sprintf(env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart)); 148ea0364f1SPeter Tyser linux_env_set("flash_start", env_buf); 149ea0364f1SPeter Tyser 150ea0364f1SPeter Tyser sprintf(env_buf, "0x%X", (uint) (gd->bd->bi_flashsize)); 151ea0364f1SPeter Tyser linux_env_set("flash_size", env_buf); 152ea0364f1SPeter Tyser 153ea0364f1SPeter Tyser cp = getenv("ethaddr"); 154e51a6b7aSDaniel Schwierzeck if (cp) 155ea0364f1SPeter Tyser linux_env_set("ethaddr", cp); 156ea0364f1SPeter Tyser 157ea0364f1SPeter Tyser cp = getenv("eth1addr"); 158e51a6b7aSDaniel Schwierzeck if (cp) 159ea0364f1SPeter Tyser linux_env_set("eth1addr", cp); 1600ea7213fSGabor Juhos } 161ea0364f1SPeter Tyser 1620ea7213fSGabor Juhos static void boot_jump_linux(bootm_headers_t *images) 1630ea7213fSGabor Juhos { 164c4b37847SDaniel Schwierzeck typedef void __noreturn (*kernel_entry_t)(int, ulong, ulong, ulong); 165c4b37847SDaniel Schwierzeck kernel_entry_t kernel = (kernel_entry_t) images->ep; 1660ea7213fSGabor Juhos 167c4b37847SDaniel Schwierzeck debug("## Transferring control to Linux (at address %p) ...\n", kernel); 1680ea7213fSGabor Juhos 1690ea7213fSGabor Juhos bootstage_mark(BOOTSTAGE_ID_RUN_OS); 1700ea7213fSGabor Juhos 1710ea7213fSGabor Juhos /* we assume that the kernel is in place */ 1720ea7213fSGabor Juhos printf("\nStarting kernel ...\n\n"); 1730ea7213fSGabor Juhos 174c4b37847SDaniel Schwierzeck kernel(linux_argc, (ulong)linux_argv, (ulong)linux_env, 0); 1750ea7213fSGabor Juhos } 1760ea7213fSGabor Juhos 1770ea7213fSGabor Juhos int do_bootm_linux(int flag, int argc, char * const argv[], 1780ea7213fSGabor Juhos bootm_headers_t *images) 1790ea7213fSGabor Juhos { 1809c170e2eSGabor Juhos /* No need for those on MIPS */ 181*59e8cbdbSDaniel Schwierzeck if (flag & BOOTM_STATE_OS_BD_T) 1829c170e2eSGabor Juhos return -1; 1839c170e2eSGabor Juhos 184*59e8cbdbSDaniel Schwierzeck if (flag & BOOTM_STATE_OS_CMDLINE) { 185*59e8cbdbSDaniel Schwierzeck boot_cmdline_linux(images); 186*59e8cbdbSDaniel Schwierzeck return 0; 187*59e8cbdbSDaniel Schwierzeck } 188*59e8cbdbSDaniel Schwierzeck 1899c170e2eSGabor Juhos if (flag & BOOTM_STATE_OS_PREP) { 1909c170e2eSGabor Juhos boot_prep_linux(images); 1919c170e2eSGabor Juhos return 0; 1929c170e2eSGabor Juhos } 1939c170e2eSGabor Juhos 1949c170e2eSGabor Juhos if (flag & BOOTM_STATE_OS_GO) { 1959c170e2eSGabor Juhos boot_jump_linux(images); 1969c170e2eSGabor Juhos return 0; 1979c170e2eSGabor Juhos } 1980ea7213fSGabor Juhos 199*59e8cbdbSDaniel Schwierzeck boot_cmdline_linux(images); 2000ea7213fSGabor Juhos boot_prep_linux(images); 201e08634c7SGabor Juhos boot_jump_linux(images); 202e51a6b7aSDaniel Schwierzeck 203ea0364f1SPeter Tyser /* does not return */ 204ea0364f1SPeter Tyser return 1; 205ea0364f1SPeter Tyser } 206ea0364f1SPeter Tyser 207*59e8cbdbSDaniel Schwierzeck static void linux_params_init(void) 208ea0364f1SPeter Tyser { 209*59e8cbdbSDaniel Schwierzeck linux_env = (char **)(((ulong) linux_argp + 15) & ~15); 210ea0364f1SPeter Tyser linux_env[0] = 0; 211ea0364f1SPeter Tyser linux_env_p = (char *)(linux_env + LINUX_MAX_ENVS); 212ea0364f1SPeter Tyser linux_env_idx = 0; 213ea0364f1SPeter Tyser } 214ea0364f1SPeter Tyser 215ea0364f1SPeter Tyser static void linux_env_set(char *env_name, char *env_val) 216ea0364f1SPeter Tyser { 217ea0364f1SPeter Tyser if (linux_env_idx < LINUX_MAX_ENVS - 1) { 218ea0364f1SPeter Tyser linux_env[linux_env_idx] = linux_env_p; 219ea0364f1SPeter Tyser 220ea0364f1SPeter Tyser strcpy(linux_env_p, env_name); 221ea0364f1SPeter Tyser linux_env_p += strlen(env_name); 222ea0364f1SPeter Tyser 223ea0364f1SPeter Tyser strcpy(linux_env_p, "="); 224ea0364f1SPeter Tyser linux_env_p += 1; 225ea0364f1SPeter Tyser 226ea0364f1SPeter Tyser strcpy(linux_env_p, env_val); 227ea0364f1SPeter Tyser linux_env_p += strlen(env_val); 228ea0364f1SPeter Tyser 229ea0364f1SPeter Tyser linux_env_p++; 230ea0364f1SPeter Tyser linux_env[++linux_env_idx] = 0; 231ea0364f1SPeter Tyser } 232ea0364f1SPeter Tyser } 233