uboot/arch/x86/lib/zimage.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011 The Chromium OS Authors.
   3 * (C) Copyright 2002
   4 * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9/*
  10 * Linux x86 zImage and bzImage loading
  11 *
  12 * based on the procdure described in
  13 * linux/Documentation/i386/boot.txt
  14 */
  15
  16#include <common.h>
  17#include <asm/io.h>
  18#include <asm/ptrace.h>
  19#include <asm/zimage.h>
  20#include <asm/byteorder.h>
  21#include <asm/bootm.h>
  22#include <asm/bootparam.h>
  23#ifdef CONFIG_SYS_COREBOOT
  24#include <asm/arch/timestamp.h>
  25#endif
  26#include <linux/compiler.h>
  27
  28DECLARE_GLOBAL_DATA_PTR;
  29
  30/*
  31 * Memory lay-out:
  32 *
  33 * relative to setup_base (which is 0x90000 currently)
  34 *
  35 *      0x0000-0x7FFF   Real mode kernel
  36 *      0x8000-0x8FFF   Stack and heap
  37 *      0x9000-0x90FF   Kernel command line
  38 */
  39#define DEFAULT_SETUP_BASE      0x90000
  40#define COMMAND_LINE_OFFSET     0x9000
  41#define HEAP_END_OFFSET         0x8e00
  42
  43#define COMMAND_LINE_SIZE       2048
  44
  45static void build_command_line(char *command_line, int auto_boot)
  46{
  47        char *env_command_line;
  48
  49        command_line[0] = '\0';
  50
  51        env_command_line =  env_get("bootargs");
  52
  53        /* set console= argument if we use a serial console */
  54        if (!strstr(env_command_line, "console=")) {
  55                if (!strcmp(env_get("stdout"), "serial")) {
  56
  57                        /* We seem to use serial console */
  58                        sprintf(command_line, "console=ttyS0,%s ",
  59                                env_get("baudrate"));
  60                }
  61        }
  62
  63        if (auto_boot)
  64                strcat(command_line, "auto ");
  65
  66        if (env_command_line)
  67                strcat(command_line, env_command_line);
  68
  69        printf("Kernel command line: \"%s\"\n", command_line);
  70}
  71
  72static int kernel_magic_ok(struct setup_header *hdr)
  73{
  74        if (KERNEL_MAGIC != hdr->boot_flag) {
  75                printf("Error: Invalid Boot Flag "
  76                        "(found 0x%04x, expected 0x%04x)\n",
  77                        hdr->boot_flag, KERNEL_MAGIC);
  78                return 0;
  79        } else {
  80                printf("Valid Boot Flag\n");
  81                return 1;
  82        }
  83}
  84
  85static int get_boot_protocol(struct setup_header *hdr)
  86{
  87        if (hdr->header == KERNEL_V2_MAGIC) {
  88                printf("Magic signature found\n");
  89                return hdr->version;
  90        } else {
  91                /* Very old kernel */
  92                printf("Magic signature not found\n");
  93                return 0x0100;
  94        }
  95}
  96
  97struct boot_params *load_zimage(char *image, unsigned long kernel_size,
  98                                ulong *load_addressp)
  99{
 100        struct boot_params *setup_base;
 101        int setup_size;
 102        int bootproto;
 103        int big_image;
 104
 105        struct boot_params *params = (struct boot_params *)image;
 106        struct setup_header *hdr = &params->hdr;
 107
 108        /* base address for real-mode segment */
 109        setup_base = (struct boot_params *)DEFAULT_SETUP_BASE;
 110
 111        if (!kernel_magic_ok(hdr))
 112                return 0;
 113
 114        /* determine size of setup */
 115        if (0 == hdr->setup_sects) {
 116                printf("Setup Sectors = 0 (defaulting to 4)\n");
 117                setup_size = 5 * 512;
 118        } else {
 119                setup_size = (hdr->setup_sects + 1) * 512;
 120        }
 121
 122        printf("Setup Size = 0x%8.8lx\n", (ulong)setup_size);
 123
 124        if (setup_size > SETUP_MAX_SIZE)
 125                printf("Error: Setup is too large (%d bytes)\n", setup_size);
 126
 127        /* determine boot protocol version */
 128        bootproto = get_boot_protocol(hdr);
 129
 130        printf("Using boot protocol version %x.%02x\n",
 131               (bootproto & 0xff00) >> 8, bootproto & 0xff);
 132
 133        if (bootproto >= 0x0200) {
 134                if (hdr->setup_sects >= 15) {
 135                        printf("Linux kernel version %s\n",
 136                                (char *)params +
 137                                hdr->kernel_version + 0x200);
 138                } else {
 139                        printf("Setup Sectors < 15 - "
 140                                "Cannot print kernel version.\n");
 141                }
 142        }
 143
 144        /* Determine image type */
 145        big_image = (bootproto >= 0x0200) &&
 146                    (hdr->loadflags & BIG_KERNEL_FLAG);
 147
 148        /* Determine load address */
 149        if (big_image)
 150                *load_addressp = BZIMAGE_LOAD_ADDR;
 151        else
 152                *load_addressp = ZIMAGE_LOAD_ADDR;
 153
 154        printf("Building boot_params at 0x%8.8lx\n", (ulong)setup_base);
 155        memset(setup_base, 0, sizeof(*setup_base));
 156        setup_base->hdr = params->hdr;
 157
 158        if (bootproto >= 0x0204)
 159                kernel_size = hdr->syssize * 16;
 160        else
 161                kernel_size -= setup_size;
 162
 163        if (bootproto == 0x0100) {
 164                /*
 165                 * A very old kernel MUST have its real-mode code
 166                 * loaded at 0x90000
 167                 */
 168                if ((ulong)setup_base != 0x90000) {
 169                        /* Copy the real-mode kernel */
 170                        memmove((void *)0x90000, setup_base, setup_size);
 171
 172                        /* Copy the command line */
 173                        memmove((void *)0x99000,
 174                                (u8 *)setup_base + COMMAND_LINE_OFFSET,
 175                                COMMAND_LINE_SIZE);
 176
 177                         /* Relocated */
 178                        setup_base = (struct boot_params *)0x90000;
 179                }
 180
 181                /* It is recommended to clear memory up to the 32K mark */
 182                memset((u8 *)0x90000 + setup_size, 0,
 183                       SETUP_MAX_SIZE - setup_size);
 184        }
 185
 186        if (big_image) {
 187                if (kernel_size > BZIMAGE_MAX_SIZE) {
 188                        printf("Error: bzImage kernel too big! "
 189                                "(size: %ld, max: %d)\n",
 190                                kernel_size, BZIMAGE_MAX_SIZE);
 191                        return 0;
 192                }
 193        } else if ((kernel_size) > ZIMAGE_MAX_SIZE) {
 194                printf("Error: zImage kernel too big! (size: %ld, max: %d)\n",
 195                       kernel_size, ZIMAGE_MAX_SIZE);
 196                return 0;
 197        }
 198
 199        printf("Loading %s at address %lx (%ld bytes)\n",
 200               big_image ? "bzImage" : "zImage", *load_addressp, kernel_size);
 201
 202        memmove((void *)*load_addressp, image + setup_size, kernel_size);
 203
 204        return setup_base;
 205}
 206
 207int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,
 208                 unsigned long initrd_addr, unsigned long initrd_size)
 209{
 210        struct setup_header *hdr = &setup_base->hdr;
 211        int bootproto = get_boot_protocol(hdr);
 212
 213        setup_base->e820_entries = install_e820_map(
 214                ARRAY_SIZE(setup_base->e820_map), setup_base->e820_map);
 215
 216        if (bootproto == 0x0100) {
 217                setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC;
 218                setup_base->screen_info.cl_offset = COMMAND_LINE_OFFSET;
 219        }
 220        if (bootproto >= 0x0200) {
 221                hdr->type_of_loader = 8;
 222
 223                if (initrd_addr) {
 224                        printf("Initial RAM disk at linear address "
 225                               "0x%08lx, size %ld bytes\n",
 226                               initrd_addr, initrd_size);
 227
 228                        hdr->ramdisk_image = initrd_addr;
 229                        hdr->ramdisk_size = initrd_size;
 230                }
 231        }
 232
 233        if (bootproto >= 0x0201) {
 234                hdr->heap_end_ptr = HEAP_END_OFFSET;
 235                hdr->loadflags |= HEAP_FLAG;
 236        }
 237
 238        if (cmd_line) {
 239                if (bootproto >= 0x0202) {
 240                        hdr->cmd_line_ptr = (uintptr_t)cmd_line;
 241                } else if (bootproto >= 0x0200) {
 242                        setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC;
 243                        setup_base->screen_info.cl_offset =
 244                                (uintptr_t)cmd_line - (uintptr_t)setup_base;
 245
 246                        hdr->setup_move_size = 0x9100;
 247                }
 248
 249#if defined(CONFIG_INTEL_MID)
 250                hdr->hardware_subarch = X86_SUBARCH_INTEL_MID;
 251#endif
 252
 253                /* build command line at COMMAND_LINE_OFFSET */
 254                build_command_line(cmd_line, auto_boot);
 255        }
 256
 257        setup_video(&setup_base->screen_info);
 258
 259        return 0;
 260}
 261
 262void setup_pcat_compatibility(void)
 263        __attribute__((weak, alias("__setup_pcat_compatibility")));
 264
 265void __setup_pcat_compatibility(void)
 266{
 267}
 268
 269int do_zboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 270{
 271        struct boot_params *base_ptr;
 272        void *bzImage_addr = NULL;
 273        ulong load_address;
 274        char *s;
 275        ulong bzImage_size = 0;
 276        ulong initrd_addr = 0;
 277        ulong initrd_size = 0;
 278
 279        disable_interrupts();
 280
 281        /* Setup board for maximum PC/AT Compatibility */
 282        setup_pcat_compatibility();
 283
 284        if (argc >= 2) {
 285                /* argv[1] holds the address of the bzImage */
 286                s = argv[1];
 287        } else {
 288                s = env_get("fileaddr");
 289        }
 290
 291        if (s)
 292                bzImage_addr = (void *)simple_strtoul(s, NULL, 16);
 293
 294        if (argc >= 3) {
 295                /* argv[2] holds the size of the bzImage */
 296                bzImage_size = simple_strtoul(argv[2], NULL, 16);
 297        }
 298
 299        if (argc >= 4)
 300                initrd_addr = simple_strtoul(argv[3], NULL, 16);
 301        if (argc >= 5)
 302                initrd_size = simple_strtoul(argv[4], NULL, 16);
 303
 304        /* Lets look for */
 305        base_ptr = load_zimage(bzImage_addr, bzImage_size, &load_address);
 306
 307        if (!base_ptr) {
 308                puts("## Kernel loading failed ...\n");
 309                return -1;
 310        }
 311        if (setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET,
 312                        0, initrd_addr, initrd_size)) {
 313                puts("Setting up boot parameters failed ...\n");
 314                return -1;
 315        }
 316
 317        /* we assume that the kernel is in place */
 318        return boot_linux_kernel((ulong)base_ptr, load_address, false);
 319}
 320
 321U_BOOT_CMD(
 322        zboot, 5, 0,    do_zboot,
 323        "Boot bzImage",
 324        "[addr] [size] [initrd addr] [initrd size]\n"
 325        "      addr -        The optional starting address of the bzimage.\n"
 326        "                    If not set it defaults to the environment\n"
 327        "                    variable \"fileaddr\".\n"
 328        "      size -        The optional size of the bzimage. Defaults to\n"
 329        "                    zero.\n"
 330        "      initrd addr - The address of the initrd image to use, if any.\n"
 331        "      initrd size - The size of the initrd image to use, if any.\n"
 332);
 333