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