qemu/hw/arm_boot.c
<<
>>
Prefs
   1/*
   2 * ARM kernel loader.
   3 *
   4 * Copyright (c) 2006-2007 CodeSourcery.
   5 * Written by Paul Brook
   6 *
   7 * This code is licenced under the GPL.
   8 */
   9
  10#include "hw.h"
  11#include "arm-misc.h"
  12#include "sysemu.h"
  13
  14#define KERNEL_ARGS_ADDR 0x100
  15#define KERNEL_LOAD_ADDR 0x00010000
  16#define INITRD_LOAD_ADDR 0x00800000
  17
  18/* The worlds second smallest bootloader.  Set r0-r2, then jump to kernel.  */
  19static uint32_t bootloader[] = {
  20  0xe3a00000, /* mov     r0, #0 */
  21  0xe3a01000, /* mov     r1, #0x?? */
  22  0xe3811c00, /* orr     r1, r1, #0x??00 */
  23  0xe59f2000, /* ldr     r2, [pc, #0] */
  24  0xe59ff000, /* ldr     pc, [pc, #0] */
  25  0, /* Address of kernel args.  Set by integratorcp_init.  */
  26  0  /* Kernel entry point.  Set by integratorcp_init.  */
  27};
  28
  29/* Entry point for secondary CPUs.  Enable interrupt controller and
  30   Issue WFI until start address is written to system controller.  */
  31static uint32_t smpboot[] = {
  32  0xe3a00201, /* mov     r0, #0x10000000 */
  33  0xe3800601, /* orr     r0, r0, #0x001000000 */
  34  0xe3a01001, /* mov     r1, #1 */
  35  0xe5801100, /* str     r1, [r0, #0x100] */
  36  0xe3a00201, /* mov     r0, #0x10000000 */
  37  0xe3800030, /* orr     r0, #0x30 */
  38  0xe320f003, /* wfi */
  39  0xe5901000, /* ldr     r1, [r0] */
  40  0xe3110003, /* tst     r1, #3 */
  41  0x1afffffb, /* bne     <wfi> */
  42  0xe12fff11  /* bx      r1 */
  43};
  44
  45static void main_cpu_reset(void *opaque)
  46{
  47    CPUState *env = opaque;
  48
  49    cpu_reset(env);
  50    if (env->boot_info)
  51        arm_load_kernel(env, env->boot_info);
  52
  53    /* TODO:  Reset secondary CPUs.  */
  54}
  55
  56static void set_kernel_args(struct arm_boot_info *info,
  57                int initrd_size, void *base)
  58{
  59    uint32_t *p;
  60
  61    p = (uint32_t *)(base + KERNEL_ARGS_ADDR);
  62    /* ATAG_CORE */
  63    stl_raw(p++, 5);
  64    stl_raw(p++, 0x54410001);
  65    stl_raw(p++, 1);
  66    stl_raw(p++, 0x1000);
  67    stl_raw(p++, 0);
  68    /* ATAG_MEM */
  69    /* TODO: handle multiple chips on one ATAG list */
  70    stl_raw(p++, 4);
  71    stl_raw(p++, 0x54410002);
  72    stl_raw(p++, info->ram_size);
  73    stl_raw(p++, info->loader_start);
  74    if (initrd_size) {
  75        /* ATAG_INITRD2 */
  76        stl_raw(p++, 4);
  77        stl_raw(p++, 0x54420005);
  78        stl_raw(p++, info->loader_start + INITRD_LOAD_ADDR);
  79        stl_raw(p++, initrd_size);
  80    }
  81    if (info->kernel_cmdline && *info->kernel_cmdline) {
  82        /* ATAG_CMDLINE */
  83        int cmdline_size;
  84
  85        cmdline_size = strlen(info->kernel_cmdline);
  86        memcpy(p + 2, info->kernel_cmdline, cmdline_size + 1);
  87        cmdline_size = (cmdline_size >> 2) + 1;
  88        stl_raw(p++, cmdline_size + 2);
  89        stl_raw(p++, 0x54410009);
  90        p += cmdline_size;
  91    }
  92    if (info->atag_board) {
  93        /* ATAG_BOARD */
  94        int atag_board_len;
  95
  96        atag_board_len = (info->atag_board(info, p + 2) + 3) >> 2;
  97        stl_raw(p++, 2 + atag_board_len);
  98        stl_raw(p++, 0x414f4d50);
  99        p += atag_board_len;
 100    }
 101    /* ATAG_END */
 102    stl_raw(p++, 0);
 103    stl_raw(p++, 0);
 104}
 105
 106static void set_kernel_args_old(struct arm_boot_info *info,
 107                int initrd_size, void *base)
 108{
 109    uint32_t *p;
 110    unsigned char *s;
 111
 112    /* see linux/include/asm-arm/setup.h */
 113    p = (uint32_t *)(base + KERNEL_ARGS_ADDR);
 114    /* page_size */
 115    stl_raw(p++, 4096);
 116    /* nr_pages */
 117    stl_raw(p++, info->ram_size / 4096);
 118    /* ramdisk_size */
 119    stl_raw(p++, 0);
 120#define FLAG_READONLY   1
 121#define FLAG_RDLOAD     4
 122#define FLAG_RDPROMPT   8
 123    /* flags */
 124    stl_raw(p++, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
 125    /* rootdev */
 126    stl_raw(p++, (31 << 8) | 0);        /* /dev/mtdblock0 */
 127    /* video_num_cols */
 128    stl_raw(p++, 0);
 129    /* video_num_rows */
 130    stl_raw(p++, 0);
 131    /* video_x */
 132    stl_raw(p++, 0);
 133    /* video_y */
 134    stl_raw(p++, 0);
 135    /* memc_control_reg */
 136    stl_raw(p++, 0);
 137    /* unsigned char sounddefault */
 138    /* unsigned char adfsdrives */
 139    /* unsigned char bytes_per_char_h */
 140    /* unsigned char bytes_per_char_v */
 141    stl_raw(p++, 0);
 142    /* pages_in_bank[4] */
 143    stl_raw(p++, 0);
 144    stl_raw(p++, 0);
 145    stl_raw(p++, 0);
 146    stl_raw(p++, 0);
 147    /* pages_in_vram */
 148    stl_raw(p++, 0);
 149    /* initrd_start */
 150    if (initrd_size)
 151        stl_raw(p++, info->loader_start + INITRD_LOAD_ADDR);
 152    else
 153        stl_raw(p++, 0);
 154    /* initrd_size */
 155    stl_raw(p++, initrd_size);
 156    /* rd_start */
 157    stl_raw(p++, 0);
 158    /* system_rev */
 159    stl_raw(p++, 0);
 160    /* system_serial_low */
 161    stl_raw(p++, 0);
 162    /* system_serial_high */
 163    stl_raw(p++, 0);
 164    /* mem_fclk_21285 */
 165    stl_raw(p++, 0);
 166    /* zero unused fields */
 167    memset(p, 0, 256 + 1024 -
 168           (p - ((uint32_t *)(base + KERNEL_ARGS_ADDR))));
 169    s = base + KERNEL_ARGS_ADDR + 256 + 1024;
 170    if (info->kernel_cmdline)
 171        strcpy (s, info->kernel_cmdline);
 172    else
 173        stb_raw(s, 0);
 174}
 175
 176void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
 177{
 178    int kernel_size;
 179    int initrd_size;
 180    int n;
 181    int is_linux = 0;
 182    uint64_t elf_entry;
 183    target_ulong entry;
 184    uint32_t pd;
 185    void *loader_phys;
 186
 187    /* Load the kernel.  */
 188    if (!info->kernel_filename) {
 189        fprintf(stderr, "Kernel image must be specified\n");
 190        exit(1);
 191    }
 192
 193    if (!env->boot_info) {
 194        if (info->nb_cpus == 0)
 195            info->nb_cpus = 1;
 196        env->boot_info = info;
 197        qemu_register_reset(main_cpu_reset, env);
 198    }
 199
 200    pd = cpu_get_physical_page_desc(info->loader_start);
 201    loader_phys = phys_ram_base + (pd & TARGET_PAGE_MASK) +
 202            (info->loader_start & ~TARGET_PAGE_MASK);
 203
 204    /* Assume that raw images are linux kernels, and ELF images are not.  */
 205    kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL);
 206    entry = elf_entry;
 207    if (kernel_size < 0) {
 208        kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
 209                                  &is_linux);
 210    }
 211    if (kernel_size < 0) {
 212        kernel_size = load_image(info->kernel_filename,
 213                                 loader_phys + KERNEL_LOAD_ADDR);
 214        entry = info->loader_start + KERNEL_LOAD_ADDR;
 215        is_linux = 1;
 216    }
 217    if (kernel_size < 0) {
 218        fprintf(stderr, "qemu: could not load kernel '%s'\n",
 219                info->kernel_filename);
 220        exit(1);
 221    }
 222    if (!is_linux) {
 223        /* Jump to the entry point.  */
 224        env->regs[15] = entry & 0xfffffffe;
 225        env->thumb = entry & 1;
 226    } else {
 227        if (info->initrd_filename) {
 228            initrd_size = load_image(info->initrd_filename,
 229                                     loader_phys + INITRD_LOAD_ADDR);
 230            if (initrd_size < 0) {
 231                fprintf(stderr, "qemu: could not load initrd '%s'\n",
 232                        info->initrd_filename);
 233                exit(1);
 234            }
 235        } else {
 236            initrd_size = 0;
 237        }
 238        bootloader[1] |= info->board_id & 0xff;
 239        bootloader[2] |= (info->board_id >> 8) & 0xff;
 240        bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
 241        bootloader[6] = entry;
 242        for (n = 0; n < sizeof(bootloader) / 4; n++)
 243            stl_raw(loader_phys + (n * 4), bootloader[n]);
 244        if (info->nb_cpus > 1)
 245            for (n = 0; n < sizeof(smpboot) / 4; n++)
 246                stl_raw(loader_phys + info->ram_size + (n * 4), smpboot[n]);
 247        if (old_param)
 248            set_kernel_args_old(info, initrd_size, loader_phys);
 249        else
 250            set_kernel_args(info, initrd_size, loader_phys);
 251    }
 252}
 253