uboot/arch/powerpc/lib/bootm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2008 Semihalf
   4 *
   5 * (C) Copyright 2000-2006
   6 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   7 */
   8
   9
  10#include <common.h>
  11#include <watchdog.h>
  12#include <command.h>
  13#include <image.h>
  14#include <malloc.h>
  15#include <u-boot/zlib.h>
  16#include <bzlib.h>
  17#include <environment.h>
  18#include <asm/byteorder.h>
  19#include <asm/mp.h>
  20#include <bootm.h>
  21#include <vxworks.h>
  22
  23#if defined(CONFIG_OF_LIBFDT)
  24#include <linux/libfdt.h>
  25#include <fdt_support.h>
  26#endif
  27
  28#ifdef CONFIG_SYS_INIT_RAM_LOCK
  29#include <asm/cache.h>
  30#endif
  31
  32DECLARE_GLOBAL_DATA_PTR;
  33
  34static ulong get_sp (void);
  35extern void ft_fixup_num_cores(void *blob);
  36static void set_clocks_in_mhz (bd_t *kbd);
  37
  38#ifndef CONFIG_SYS_LINUX_LOWMEM_MAX_SIZE
  39#define CONFIG_SYS_LINUX_LOWMEM_MAX_SIZE        (768*1024*1024)
  40#endif
  41
  42static void boot_jump_linux(bootm_headers_t *images)
  43{
  44        void    (*kernel)(bd_t *, ulong r4, ulong r5, ulong r6,
  45                          ulong r7, ulong r8, ulong r9);
  46#ifdef CONFIG_OF_LIBFDT
  47        char *of_flat_tree = images->ft_addr;
  48#endif
  49
  50        kernel = (void (*)(bd_t *, ulong, ulong, ulong,
  51                           ulong, ulong, ulong))images->ep;
  52        debug ("## Transferring control to Linux (at address %08lx) ...\n",
  53                (ulong)kernel);
  54
  55        bootstage_mark(BOOTSTAGE_ID_RUN_OS);
  56
  57#ifdef CONFIG_BOOTSTAGE_FDT
  58        bootstage_fdt_add_report();
  59#endif
  60#ifdef CONFIG_BOOTSTAGE_REPORT
  61        bootstage_report();
  62#endif
  63
  64#if defined(CONFIG_SYS_INIT_RAM_LOCK) && !defined(CONFIG_E500)
  65        unlock_ram_in_cache();
  66#endif
  67
  68#if defined(CONFIG_OF_LIBFDT)
  69        if (of_flat_tree) {     /* device tree; boot new style */
  70                /*
  71                 * Linux Kernel Parameters (passing device tree):
  72                 *   r3: pointer to the fdt
  73                 *   r4: 0
  74                 *   r5: 0
  75                 *   r6: epapr magic
  76                 *   r7: size of IMA in bytes
  77                 *   r8: 0
  78                 *   r9: 0
  79                 */
  80                debug ("   Booting using OF flat tree...\n");
  81                WATCHDOG_RESET ();
  82                (*kernel) ((bd_t *)of_flat_tree, 0, 0, EPAPR_MAGIC,
  83                           env_get_bootm_mapsize(), 0, 0);
  84                /* does not return */
  85        } else
  86#endif
  87        {
  88                /*
  89                 * Linux Kernel Parameters (passing board info data):
  90                 *   r3: ptr to board info data
  91                 *   r4: initrd_start or 0 if no initrd
  92                 *   r5: initrd_end - unused if r4 is 0
  93                 *   r6: Start of command line string
  94                 *   r7: End   of command line string
  95                 *   r8: 0
  96                 *   r9: 0
  97                 */
  98                ulong cmd_start = images->cmdline_start;
  99                ulong cmd_end = images->cmdline_end;
 100                ulong initrd_start = images->initrd_start;
 101                ulong initrd_end = images->initrd_end;
 102                bd_t *kbd = images->kbd;
 103
 104                debug ("   Booting using board info...\n");
 105                WATCHDOG_RESET ();
 106                (*kernel) (kbd, initrd_start, initrd_end,
 107                           cmd_start, cmd_end, 0, 0);
 108                /* does not return */
 109        }
 110        return ;
 111}
 112
 113void arch_lmb_reserve(struct lmb *lmb)
 114{
 115        phys_size_t bootm_size;
 116        ulong size, sp, bootmap_base;
 117
 118        bootmap_base = env_get_bootm_low();
 119        bootm_size = env_get_bootm_size();
 120
 121#ifdef DEBUG
 122        if (((u64)bootmap_base + bootm_size) >
 123            (CONFIG_SYS_SDRAM_BASE + (u64)gd->ram_size))
 124                puts("WARNING: bootm_low + bootm_size exceed total memory\n");
 125        if ((bootmap_base + bootm_size) > get_effective_memsize())
 126                puts("WARNING: bootm_low + bootm_size exceed eff. memory\n");
 127#endif
 128
 129        size = min(bootm_size, get_effective_memsize());
 130        size = min(size, (ulong)CONFIG_SYS_LINUX_LOWMEM_MAX_SIZE);
 131
 132        if (size < bootm_size) {
 133                ulong base = bootmap_base + size;
 134                printf("WARNING: adjusting available memory to %lx\n", size);
 135                lmb_reserve(lmb, base, bootm_size - size);
 136        }
 137
 138        /*
 139         * Booting a (Linux) kernel image
 140         *
 141         * Allocate space for command line and board info - the
 142         * address should be as high as possible within the reach of
 143         * the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused
 144         * memory, which means far enough below the current stack
 145         * pointer.
 146         */
 147        sp = get_sp();
 148        debug ("## Current stack ends at 0x%08lx\n", sp);
 149
 150        /* adjust sp by 4K to be safe */
 151        sp -= 4096;
 152        lmb_reserve(lmb, sp, (CONFIG_SYS_SDRAM_BASE + get_effective_memsize() - sp));
 153
 154#ifdef CONFIG_MP
 155        cpu_mp_lmb_reserve(lmb);
 156#endif
 157
 158        return ;
 159}
 160
 161static void boot_prep_linux(bootm_headers_t *images)
 162{
 163#ifdef CONFIG_MP
 164        /*
 165         * if we are MP make sure to flush the device tree so any changes are
 166         * made visibile to all other cores.  In AMP boot scenarios the cores
 167         * might not be HW cache coherent with each other.
 168         */
 169        flush_cache((unsigned long)images->ft_addr, images->ft_len);
 170#endif
 171}
 172
 173static int boot_cmdline_linux(bootm_headers_t *images)
 174{
 175        ulong of_size = images->ft_len;
 176        struct lmb *lmb = &images->lmb;
 177        ulong *cmd_start = &images->cmdline_start;
 178        ulong *cmd_end = &images->cmdline_end;
 179
 180        int ret = 0;
 181
 182        if (!of_size) {
 183                /* allocate space and init command line */
 184                ret = boot_get_cmdline (lmb, cmd_start, cmd_end);
 185                if (ret) {
 186                        puts("ERROR with allocation of cmdline\n");
 187                        return ret;
 188                }
 189        }
 190
 191        return ret;
 192}
 193
 194static int boot_bd_t_linux(bootm_headers_t *images)
 195{
 196        ulong of_size = images->ft_len;
 197        struct lmb *lmb = &images->lmb;
 198        bd_t **kbd = &images->kbd;
 199
 200        int ret = 0;
 201
 202        if (!of_size) {
 203                /* allocate space for kernel copy of board info */
 204                ret = boot_get_kbd (lmb, kbd);
 205                if (ret) {
 206                        puts("ERROR with allocation of kernel bd\n");
 207                        return ret;
 208                }
 209                set_clocks_in_mhz(*kbd);
 210        }
 211
 212        return ret;
 213}
 214
 215static int boot_body_linux(bootm_headers_t *images)
 216{
 217        int ret;
 218
 219        /* allocate space for kernel copy of board info */
 220        ret = boot_bd_t_linux(images);
 221        if (ret)
 222                return ret;
 223
 224        ret = image_setup_linux(images);
 225        if (ret)
 226                return ret;
 227
 228        return 0;
 229}
 230
 231noinline
 232int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images)
 233{
 234        int     ret;
 235
 236        if (flag & BOOTM_STATE_OS_CMDLINE) {
 237                boot_cmdline_linux(images);
 238                return 0;
 239        }
 240
 241        if (flag & BOOTM_STATE_OS_BD_T) {
 242                boot_bd_t_linux(images);
 243                return 0;
 244        }
 245
 246        if (flag & BOOTM_STATE_OS_PREP) {
 247                boot_prep_linux(images);
 248                return 0;
 249        }
 250
 251        boot_prep_linux(images);
 252        ret = boot_body_linux(images);
 253        if (ret)
 254                return ret;
 255        boot_jump_linux(images);
 256
 257        return 0;
 258}
 259
 260static ulong get_sp (void)
 261{
 262        ulong sp;
 263
 264        asm( "mr %0,1": "=r"(sp) : );
 265        return sp;
 266}
 267
 268static void set_clocks_in_mhz (bd_t *kbd)
 269{
 270        char    *s;
 271
 272        s = env_get("clocks_in_mhz");
 273        if (s) {
 274                /* convert all clock information to MHz */
 275                kbd->bi_intfreq /= 1000000L;
 276                kbd->bi_busfreq /= 1000000L;
 277#if defined(CONFIG_CPM2)
 278                kbd->bi_cpmfreq /= 1000000L;
 279                kbd->bi_brgfreq /= 1000000L;
 280                kbd->bi_sccfreq /= 1000000L;
 281                kbd->bi_vco     /= 1000000L;
 282#endif
 283        }
 284}
 285
 286#if defined(CONFIG_BOOTM_VXWORKS)
 287void boot_prep_vxworks(bootm_headers_t *images)
 288{
 289#if defined(CONFIG_OF_LIBFDT)
 290        int off;
 291        u64 base, size;
 292
 293        if (!images->ft_addr)
 294                return;
 295
 296        base = (u64)gd->bd->bi_memstart;
 297        size = (u64)gd->bd->bi_memsize;
 298
 299        off = fdt_path_offset(images->ft_addr, "/memory");
 300        if (off < 0)
 301                fdt_fixup_memory(images->ft_addr, base, size);
 302
 303#if defined(CONFIG_MP)
 304#if defined(CONFIG_MPC85xx)
 305        ft_fixup_cpu(images->ft_addr, base + size);
 306        ft_fixup_num_cores(images->ft_addr);
 307#elif defined(CONFIG_MPC86xx)
 308        off = fdt_add_mem_rsv(images->ft_addr,
 309                        determine_mp_bootpg(NULL), (u64)4096);
 310        if (off < 0)
 311                printf("## WARNING %s: %s\n", __func__, fdt_strerror(off));
 312        ft_fixup_num_cores(images->ft_addr);
 313#endif
 314        flush_cache((unsigned long)images->ft_addr, images->ft_len);
 315#endif
 316#endif
 317}
 318
 319void boot_jump_vxworks(bootm_headers_t *images)
 320{
 321        /* PowerPC VxWorks boot interface conforms to the ePAPR standard
 322         * general purpuse registers:
 323         *
 324         *      r3: Effective address of the device tree image
 325         *      r4: 0
 326         *      r5: 0
 327         *      r6: ePAPR magic value
 328         *      r7: shall be the size of the boot IMA in bytes
 329         *      r8: 0
 330         *      r9: 0
 331         *      TCR: WRC = 0, no watchdog timer reset will occur
 332         */
 333        WATCHDOG_RESET();
 334
 335        ((void (*)(void *, ulong, ulong, ulong,
 336                ulong, ulong, ulong))images->ep)(images->ft_addr,
 337                0, 0, EPAPR_MAGIC, env_get_bootm_mapsize(), 0, 0);
 338}
 339#endif
 340