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; 2259e8cbdbSDaniel 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 28f66cc1e3SDaniel Schwierzeck static ulong arch_get_sp(void) 29f66cc1e3SDaniel Schwierzeck { 30f66cc1e3SDaniel Schwierzeck ulong ret; 31f66cc1e3SDaniel Schwierzeck 32f66cc1e3SDaniel Schwierzeck __asm__ __volatile__("move %0, $sp" : "=r"(ret) : ); 33f66cc1e3SDaniel Schwierzeck 34f66cc1e3SDaniel Schwierzeck return ret; 35f66cc1e3SDaniel Schwierzeck } 36f66cc1e3SDaniel Schwierzeck 37f66cc1e3SDaniel Schwierzeck void arch_lmb_reserve(struct lmb *lmb) 38f66cc1e3SDaniel Schwierzeck { 39f66cc1e3SDaniel Schwierzeck ulong sp; 40f66cc1e3SDaniel Schwierzeck 41f66cc1e3SDaniel Schwierzeck sp = arch_get_sp(); 42f66cc1e3SDaniel Schwierzeck debug("## Current stack ends at 0x%08lx\n", sp); 43f66cc1e3SDaniel Schwierzeck 44f66cc1e3SDaniel Schwierzeck /* adjust sp by 4K to be safe */ 45f66cc1e3SDaniel Schwierzeck sp -= 4096; 46f66cc1e3SDaniel Schwierzeck lmb_reserve(lmb, sp, CONFIG_SYS_SDRAM_BASE + gd->ram_size - sp); 47f66cc1e3SDaniel Schwierzeck } 48f66cc1e3SDaniel Schwierzeck 4959e8cbdbSDaniel Schwierzeck static void linux_cmdline_init(void) 5059e8cbdbSDaniel Schwierzeck { 5159e8cbdbSDaniel Schwierzeck linux_argc = 1; 5259e8cbdbSDaniel Schwierzeck linux_argv = (char **)UNCACHED_SDRAM(gd->bd->bi_boot_params); 5359e8cbdbSDaniel Schwierzeck linux_argv[0] = 0; 5459e8cbdbSDaniel Schwierzeck linux_argp = (char *)(linux_argv + LINUX_MAX_ARGS); 5559e8cbdbSDaniel Schwierzeck } 5659e8cbdbSDaniel Schwierzeck 5759e8cbdbSDaniel Schwierzeck static void linux_cmdline_set(const char *value, size_t len) 5859e8cbdbSDaniel Schwierzeck { 5959e8cbdbSDaniel Schwierzeck linux_argv[linux_argc] = linux_argp; 6059e8cbdbSDaniel Schwierzeck memcpy(linux_argp, value, len); 6159e8cbdbSDaniel Schwierzeck linux_argp[len] = 0; 6259e8cbdbSDaniel Schwierzeck 6359e8cbdbSDaniel Schwierzeck linux_argp += len + 1; 6459e8cbdbSDaniel Schwierzeck linux_argc++; 6559e8cbdbSDaniel Schwierzeck } 6659e8cbdbSDaniel Schwierzeck 6759e8cbdbSDaniel Schwierzeck static void linux_cmdline_dump(void) 6859e8cbdbSDaniel Schwierzeck { 6959e8cbdbSDaniel Schwierzeck int i; 7059e8cbdbSDaniel Schwierzeck 7159e8cbdbSDaniel Schwierzeck debug("## cmdline argv at 0x%p, argp at 0x%p\n", 7259e8cbdbSDaniel Schwierzeck linux_argv, linux_argp); 7359e8cbdbSDaniel Schwierzeck 7459e8cbdbSDaniel Schwierzeck for (i = 1; i < linux_argc; i++) 7559e8cbdbSDaniel Schwierzeck debug(" arg %03d: %s\n", i, linux_argv[i]); 7659e8cbdbSDaniel Schwierzeck } 7759e8cbdbSDaniel Schwierzeck 7859e8cbdbSDaniel Schwierzeck static void boot_cmdline_linux(bootm_headers_t *images) 7959e8cbdbSDaniel Schwierzeck { 8059e8cbdbSDaniel Schwierzeck const char *bootargs, *next, *quote; 8159e8cbdbSDaniel Schwierzeck 8259e8cbdbSDaniel Schwierzeck linux_cmdline_init(); 8359e8cbdbSDaniel Schwierzeck 8459e8cbdbSDaniel Schwierzeck bootargs = getenv("bootargs"); 8559e8cbdbSDaniel Schwierzeck if (!bootargs) 8659e8cbdbSDaniel Schwierzeck return; 8759e8cbdbSDaniel Schwierzeck 8859e8cbdbSDaniel Schwierzeck next = bootargs; 8959e8cbdbSDaniel Schwierzeck 9059e8cbdbSDaniel Schwierzeck while (bootargs && *bootargs && linux_argc < LINUX_MAX_ARGS) { 9159e8cbdbSDaniel Schwierzeck quote = strchr(bootargs, '"'); 9259e8cbdbSDaniel Schwierzeck next = strchr(bootargs, ' '); 9359e8cbdbSDaniel Schwierzeck 9459e8cbdbSDaniel Schwierzeck while (next && quote && quote < next) { 9559e8cbdbSDaniel Schwierzeck /* 9659e8cbdbSDaniel Schwierzeck * we found a left quote before the next blank 9759e8cbdbSDaniel Schwierzeck * now we have to find the matching right quote 9859e8cbdbSDaniel Schwierzeck */ 9959e8cbdbSDaniel Schwierzeck next = strchr(quote + 1, '"'); 10059e8cbdbSDaniel Schwierzeck if (next) { 10159e8cbdbSDaniel Schwierzeck quote = strchr(next + 1, '"'); 10259e8cbdbSDaniel Schwierzeck next = strchr(next + 1, ' '); 10359e8cbdbSDaniel Schwierzeck } 10459e8cbdbSDaniel Schwierzeck } 10559e8cbdbSDaniel Schwierzeck 10659e8cbdbSDaniel Schwierzeck if (!next) 10759e8cbdbSDaniel Schwierzeck next = bootargs + strlen(bootargs); 10859e8cbdbSDaniel Schwierzeck 10959e8cbdbSDaniel Schwierzeck linux_cmdline_set(bootargs, next - bootargs); 11059e8cbdbSDaniel Schwierzeck 11159e8cbdbSDaniel Schwierzeck if (*next) 11259e8cbdbSDaniel Schwierzeck next++; 11359e8cbdbSDaniel Schwierzeck 11459e8cbdbSDaniel Schwierzeck bootargs = next; 11559e8cbdbSDaniel Schwierzeck } 11659e8cbdbSDaniel Schwierzeck 11759e8cbdbSDaniel Schwierzeck linux_cmdline_dump(); 11859e8cbdbSDaniel Schwierzeck } 11959e8cbdbSDaniel Schwierzeck 120*15f8aa90SDaniel Schwierzeck static void linux_env_init(void) 121*15f8aa90SDaniel Schwierzeck { 122*15f8aa90SDaniel Schwierzeck linux_env = (char **)(((ulong) linux_argp + 15) & ~15); 123*15f8aa90SDaniel Schwierzeck linux_env[0] = 0; 124*15f8aa90SDaniel Schwierzeck linux_env_p = (char *)(linux_env + LINUX_MAX_ENVS); 125*15f8aa90SDaniel Schwierzeck linux_env_idx = 0; 126*15f8aa90SDaniel Schwierzeck } 127*15f8aa90SDaniel Schwierzeck 128*15f8aa90SDaniel Schwierzeck static void linux_env_set(const char *env_name, const char *env_val) 129*15f8aa90SDaniel Schwierzeck { 130*15f8aa90SDaniel Schwierzeck if (linux_env_idx < LINUX_MAX_ENVS - 1) { 131*15f8aa90SDaniel Schwierzeck linux_env[linux_env_idx] = linux_env_p; 132*15f8aa90SDaniel Schwierzeck 133*15f8aa90SDaniel Schwierzeck strcpy(linux_env_p, env_name); 134*15f8aa90SDaniel Schwierzeck linux_env_p += strlen(env_name); 135*15f8aa90SDaniel Schwierzeck 136*15f8aa90SDaniel Schwierzeck *linux_env_p++ = '='; 137*15f8aa90SDaniel Schwierzeck 138*15f8aa90SDaniel Schwierzeck strcpy(linux_env_p, env_val); 139*15f8aa90SDaniel Schwierzeck linux_env_p += strlen(env_val); 140*15f8aa90SDaniel Schwierzeck 141*15f8aa90SDaniel Schwierzeck linux_env_p++; 142*15f8aa90SDaniel Schwierzeck linux_env[++linux_env_idx] = 0; 143*15f8aa90SDaniel Schwierzeck } 144*15f8aa90SDaniel Schwierzeck } 145*15f8aa90SDaniel Schwierzeck 1460ea7213fSGabor Juhos static void boot_prep_linux(bootm_headers_t *images) 147ea0364f1SPeter Tyser { 148ea0364f1SPeter Tyser char env_buf[12]; 149*15f8aa90SDaniel Schwierzeck const char *cp; 150ea0364f1SPeter Tyser 151ea0364f1SPeter Tyser #ifdef CONFIG_MEMSIZE_IN_BYTES 152ea0364f1SPeter Tyser sprintf(env_buf, "%lu", (ulong)gd->ram_size); 153ea0364f1SPeter Tyser debug("## Giving linux memsize in bytes, %lu\n", (ulong)gd->ram_size); 154ea0364f1SPeter Tyser #else 155ea0364f1SPeter Tyser sprintf(env_buf, "%lu", (ulong)(gd->ram_size >> 20)); 156e51a6b7aSDaniel Schwierzeck debug("## Giving linux memsize in MB, %lu\n", 157e51a6b7aSDaniel Schwierzeck (ulong)(gd->ram_size >> 20)); 158ea0364f1SPeter Tyser #endif /* CONFIG_MEMSIZE_IN_BYTES */ 159ea0364f1SPeter Tyser 160*15f8aa90SDaniel Schwierzeck linux_env_init(); 161*15f8aa90SDaniel Schwierzeck 162ea0364f1SPeter Tyser linux_env_set("memsize", env_buf); 163ea0364f1SPeter Tyser 164ea0364f1SPeter Tyser sprintf(env_buf, "0x%08X", (uint) UNCACHED_SDRAM(images->rd_start)); 165ea0364f1SPeter Tyser linux_env_set("initrd_start", env_buf); 166ea0364f1SPeter Tyser 167ea0364f1SPeter Tyser sprintf(env_buf, "0x%X", (uint) (images->rd_end - images->rd_start)); 168ea0364f1SPeter Tyser linux_env_set("initrd_size", env_buf); 169ea0364f1SPeter Tyser 170ea0364f1SPeter Tyser sprintf(env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart)); 171ea0364f1SPeter Tyser linux_env_set("flash_start", env_buf); 172ea0364f1SPeter Tyser 173ea0364f1SPeter Tyser sprintf(env_buf, "0x%X", (uint) (gd->bd->bi_flashsize)); 174ea0364f1SPeter Tyser linux_env_set("flash_size", env_buf); 175ea0364f1SPeter Tyser 176ea0364f1SPeter Tyser cp = getenv("ethaddr"); 177e51a6b7aSDaniel Schwierzeck if (cp) 178ea0364f1SPeter Tyser linux_env_set("ethaddr", cp); 179ea0364f1SPeter Tyser 180ea0364f1SPeter Tyser cp = getenv("eth1addr"); 181e51a6b7aSDaniel Schwierzeck if (cp) 182ea0364f1SPeter Tyser linux_env_set("eth1addr", cp); 1830ea7213fSGabor Juhos } 184ea0364f1SPeter Tyser 1850ea7213fSGabor Juhos static void boot_jump_linux(bootm_headers_t *images) 1860ea7213fSGabor Juhos { 187c4b37847SDaniel Schwierzeck typedef void __noreturn (*kernel_entry_t)(int, ulong, ulong, ulong); 188c4b37847SDaniel Schwierzeck kernel_entry_t kernel = (kernel_entry_t) images->ep; 1890ea7213fSGabor Juhos 190c4b37847SDaniel Schwierzeck debug("## Transferring control to Linux (at address %p) ...\n", kernel); 1910ea7213fSGabor Juhos 1920ea7213fSGabor Juhos bootstage_mark(BOOTSTAGE_ID_RUN_OS); 1930ea7213fSGabor Juhos 1940ea7213fSGabor Juhos /* we assume that the kernel is in place */ 1950ea7213fSGabor Juhos printf("\nStarting kernel ...\n\n"); 1960ea7213fSGabor Juhos 197c4b37847SDaniel Schwierzeck kernel(linux_argc, (ulong)linux_argv, (ulong)linux_env, 0); 1980ea7213fSGabor Juhos } 1990ea7213fSGabor Juhos 2000ea7213fSGabor Juhos int do_bootm_linux(int flag, int argc, char * const argv[], 2010ea7213fSGabor Juhos bootm_headers_t *images) 2020ea7213fSGabor Juhos { 2039c170e2eSGabor Juhos /* No need for those on MIPS */ 20459e8cbdbSDaniel Schwierzeck if (flag & BOOTM_STATE_OS_BD_T) 2059c170e2eSGabor Juhos return -1; 2069c170e2eSGabor Juhos 20759e8cbdbSDaniel Schwierzeck if (flag & BOOTM_STATE_OS_CMDLINE) { 20859e8cbdbSDaniel Schwierzeck boot_cmdline_linux(images); 20959e8cbdbSDaniel Schwierzeck return 0; 21059e8cbdbSDaniel Schwierzeck } 21159e8cbdbSDaniel Schwierzeck 2129c170e2eSGabor Juhos if (flag & BOOTM_STATE_OS_PREP) { 2139c170e2eSGabor Juhos boot_prep_linux(images); 2149c170e2eSGabor Juhos return 0; 2159c170e2eSGabor Juhos } 2169c170e2eSGabor Juhos 2179c170e2eSGabor Juhos if (flag & BOOTM_STATE_OS_GO) { 2189c170e2eSGabor Juhos boot_jump_linux(images); 2199c170e2eSGabor Juhos return 0; 2209c170e2eSGabor Juhos } 2210ea7213fSGabor Juhos 22259e8cbdbSDaniel Schwierzeck boot_cmdline_linux(images); 2230ea7213fSGabor Juhos boot_prep_linux(images); 224e08634c7SGabor Juhos boot_jump_linux(images); 225e51a6b7aSDaniel Schwierzeck 226ea0364f1SPeter Tyser /* does not return */ 227ea0364f1SPeter Tyser return 1; 228ea0364f1SPeter Tyser } 229