uboot/arch/mips/lib/bootm.c
<<
>>
Prefs
   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#include <asm/io.h>
  13
  14DECLARE_GLOBAL_DATA_PTR;
  15
  16#define LINUX_MAX_ENVS          256
  17#define LINUX_MAX_ARGS          256
  18
  19static int linux_argc;
  20static char **linux_argv;
  21static char *linux_argp;
  22
  23static char **linux_env;
  24static char *linux_env_p;
  25static int linux_env_idx;
  26
  27static ulong arch_get_sp(void)
  28{
  29        ulong ret;
  30
  31        __asm__ __volatile__("move %0, $sp" : "=r"(ret) : );
  32
  33        return ret;
  34}
  35
  36void arch_lmb_reserve(struct lmb *lmb)
  37{
  38        ulong sp;
  39
  40        sp = arch_get_sp();
  41        debug("## Current stack ends at 0x%08lx\n", sp);
  42
  43        /* adjust sp by 4K to be safe */
  44        sp -= 4096;
  45        lmb_reserve(lmb, sp, CONFIG_SYS_SDRAM_BASE + gd->ram_size - sp);
  46}
  47
  48static void linux_cmdline_init(void)
  49{
  50        linux_argc = 1;
  51        linux_argv = (char **)UNCACHED_SDRAM(gd->bd->bi_boot_params);
  52        linux_argv[0] = 0;
  53        linux_argp = (char *)(linux_argv + LINUX_MAX_ARGS);
  54}
  55
  56static void linux_cmdline_set(const char *value, size_t len)
  57{
  58        linux_argv[linux_argc] = linux_argp;
  59        memcpy(linux_argp, value, len);
  60        linux_argp[len] = 0;
  61
  62        linux_argp += len + 1;
  63        linux_argc++;
  64}
  65
  66static void linux_cmdline_dump(void)
  67{
  68        int i;
  69
  70        debug("## cmdline argv at 0x%p, argp at 0x%p\n",
  71              linux_argv, linux_argp);
  72
  73        for (i = 1; i < linux_argc; i++)
  74                debug("   arg %03d: %s\n", i, linux_argv[i]);
  75}
  76
  77static void linux_cmdline_legacy(bootm_headers_t *images)
  78{
  79        const char *bootargs, *next, *quote;
  80
  81        linux_cmdline_init();
  82
  83        bootargs = getenv("bootargs");
  84        if (!bootargs)
  85                return;
  86
  87        next = bootargs;
  88
  89        while (bootargs && *bootargs && linux_argc < LINUX_MAX_ARGS) {
  90                quote = strchr(bootargs, '"');
  91                next = strchr(bootargs, ' ');
  92
  93                while (next && quote && quote < next) {
  94                        /*
  95                         * we found a left quote before the next blank
  96                         * now we have to find the matching right quote
  97                         */
  98                        next = strchr(quote + 1, '"');
  99                        if (next) {
 100                                quote = strchr(next + 1, '"');
 101                                next = strchr(next + 1, ' ');
 102                        }
 103                }
 104
 105                if (!next)
 106                        next = bootargs + strlen(bootargs);
 107
 108                linux_cmdline_set(bootargs, next - bootargs);
 109
 110                if (*next)
 111                        next++;
 112
 113                bootargs = next;
 114        }
 115}
 116
 117static void linux_cmdline_append(bootm_headers_t *images)
 118{
 119        char buf[24];
 120        ulong mem, rd_start, rd_size;
 121
 122        /* append mem */
 123        mem = gd->ram_size >> 20;
 124        sprintf(buf, "mem=%luM", mem);
 125        linux_cmdline_set(buf, strlen(buf));
 126
 127        /* append rd_start and rd_size */
 128        rd_start = images->initrd_start;
 129        rd_size = images->initrd_end - images->initrd_start;
 130
 131        if (rd_size) {
 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));
 136        }
 137}
 138
 139static void linux_env_init(void)
 140{
 141        linux_env = (char **)(((ulong) linux_argp + 15) & ~15);
 142        linux_env[0] = 0;
 143        linux_env_p = (char *)(linux_env + LINUX_MAX_ENVS);
 144        linux_env_idx = 0;
 145}
 146
 147static void linux_env_set(const char *env_name, const char *env_val)
 148{
 149        if (linux_env_idx < LINUX_MAX_ENVS - 1) {
 150                linux_env[linux_env_idx] = linux_env_p;
 151
 152                strcpy(linux_env_p, env_name);
 153                linux_env_p += strlen(env_name);
 154
 155                if (CONFIG_IS_ENABLED(MALTA)) {
 156                        linux_env_p++;
 157                        linux_env[++linux_env_idx] = linux_env_p;
 158                } else {
 159                        *linux_env_p++ = '=';
 160                }
 161
 162                strcpy(linux_env_p, env_val);
 163                linux_env_p += strlen(env_val);
 164
 165                linux_env_p++;
 166                linux_env[++linux_env_idx] = 0;
 167        }
 168}
 169
 170static void linux_env_legacy(bootm_headers_t *images)
 171{
 172        char env_buf[12];
 173        const char *cp;
 174        ulong rd_start, rd_size;
 175
 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);
 180        } else {
 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));
 184        }
 185
 186        rd_start = UNCACHED_SDRAM(images->initrd_start);
 187        rd_size = images->initrd_end - images->initrd_start;
 188
 189        linux_env_init();
 190
 191        linux_env_set("memsize", env_buf);
 192
 193        sprintf(env_buf, "0x%08lX", rd_start);
 194        linux_env_set("initrd_start", env_buf);
 195
 196        sprintf(env_buf, "0x%lX", rd_size);
 197        linux_env_set("initrd_size", env_buf);
 198
 199        sprintf(env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart));
 200        linux_env_set("flash_start", env_buf);
 201
 202        sprintf(env_buf, "0x%X", (uint) (gd->bd->bi_flashsize));
 203        linux_env_set("flash_size", env_buf);
 204
 205        cp = getenv("ethaddr");
 206        if (cp)
 207                linux_env_set("ethaddr", cp);
 208
 209        cp = getenv("eth1addr");
 210        if (cp)
 211                linux_env_set("eth1addr", cp);
 212
 213        if (CONFIG_IS_ENABLED(MALTA)) {
 214                sprintf(env_buf, "%un8r", gd->baudrate);
 215                linux_env_set("modetty0", env_buf);
 216        }
 217}
 218
 219static int boot_reloc_ramdisk(bootm_headers_t *images)
 220{
 221        ulong rd_len = images->rd_end - images->rd_start;
 222
 223        /*
 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'.
 226         */
 227        if (images->state & BOOTM_STATE_RAMDISK) {
 228                debug("## Ramdisk already relocated\n");
 229                return 0;
 230        }
 231
 232        return boot_ramdisk_high(&images->lmb, images->rd_start,
 233                rd_len, &images->initrd_start, &images->initrd_end);
 234}
 235
 236static int boot_reloc_fdt(bootm_headers_t *images)
 237{
 238        /*
 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'.
 241         */
 242        if (images->state & BOOTM_STATE_FDT) {
 243                debug("## FDT already relocated\n");
 244                return 0;
 245        }
 246
 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,
 250                &images->ft_len);
 251#else
 252        return 0;
 253#endif
 254}
 255
 256#ifdef CONFIG_ARCH_FIXUP_FDT
 257int arch_fixup_fdt(void *blob)
 258{
 259#if CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && CONFIG_IS_ENABLED(OF_LIBFDT)
 260        u64 mem_start = virt_to_phys((void *)gd->bd->bi_memstart);
 261        u64 mem_size = gd->ram_size;
 262
 263        return fdt_fixup_memory_banks(blob, &mem_start, &mem_size, 1);
 264#else
 265        return 0;
 266#endif
 267}
 268#endif
 269
 270static int boot_setup_fdt(bootm_headers_t *images)
 271{
 272        return image_setup_libfdt(images, images->ft_addr, images->ft_len,
 273                &images->lmb);
 274}
 275
 276static void boot_prep_linux(bootm_headers_t *images)
 277{
 278        boot_reloc_ramdisk(images);
 279
 280        if (CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && images->ft_len) {
 281                boot_reloc_fdt(images);
 282                boot_setup_fdt(images);
 283        } else {
 284                if (CONFIG_IS_ENABLED(CONFIG_MIPS_BOOT_ENV_LEGACY))
 285                        linux_env_legacy(images);
 286
 287                if (CONFIG_IS_ENABLED(MIPS_BOOT_CMDLINE_LEGACY)) {
 288                        linux_cmdline_legacy(images);
 289
 290                        if (!CONFIG_IS_ENABLED(CONFIG_MIPS_BOOT_ENV_LEGACY))
 291                                linux_cmdline_append(images);
 292
 293                        linux_cmdline_dump();
 294                }
 295        }
 296}
 297
 298static void boot_jump_linux(bootm_headers_t *images)
 299{
 300        typedef void __noreturn (*kernel_entry_t)(int, ulong, ulong, ulong);
 301        kernel_entry_t kernel = (kernel_entry_t) images->ep;
 302        ulong linux_extra = 0;
 303
 304        debug("## Transferring control to Linux (at address %p) ...\n", kernel);
 305
 306        bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 307
 308        if (CONFIG_IS_ENABLED(MALTA))
 309                linux_extra = gd->ram_size;
 310
 311#if CONFIG_IS_ENABLED(BOOTSTAGE_FDT)
 312        bootstage_fdt_add_report();
 313#endif
 314#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
 315        bootstage_report();
 316#endif
 317
 318        if (images->ft_len)
 319                kernel(-2, (ulong)images->ft_addr, 0, 0);
 320        else
 321                kernel(linux_argc, (ulong)linux_argv, (ulong)linux_env,
 322                        linux_extra);
 323}
 324
 325int do_bootm_linux(int flag, int argc, char * const argv[],
 326                        bootm_headers_t *images)
 327{
 328        /* No need for those on MIPS */
 329        if (flag & BOOTM_STATE_OS_BD_T)
 330                return -1;
 331
 332        /*
 333         * Cmdline init has been moved to 'bootm prep' because it has to be
 334         * done after relocation of ramdisk to always pass correct values
 335         * for rd_start and rd_size to Linux kernel.
 336         */
 337        if (flag & BOOTM_STATE_OS_CMDLINE)
 338                return 0;
 339
 340        if (flag & BOOTM_STATE_OS_PREP) {
 341                boot_prep_linux(images);
 342                return 0;
 343        }
 344
 345        if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
 346                boot_jump_linux(images);
 347                return 0;
 348        }
 349
 350        /* does not return */
 351        return 1;
 352}
 353