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