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