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. */ 19 static 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. */ 31 static 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 45 static 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 56 #define WRITE_WORD(p, value) do { \ 57 stl_phys_notdirty(p, value); \ 58 p += 4; \ 59 } while (0) 60 61 static void set_kernel_args(struct arm_boot_info *info, 62 int initrd_size, target_phys_addr_t base) 63 { 64 target_phys_addr_t p; 65 66 p = base + KERNEL_ARGS_ADDR; 67 /* ATAG_CORE */ 68 WRITE_WORD(p, 5); 69 WRITE_WORD(p, 0x54410001); 70 WRITE_WORD(p, 1); 71 WRITE_WORD(p, 0x1000); 72 WRITE_WORD(p, 0); 73 /* ATAG_MEM */ 74 /* TODO: handle multiple chips on one ATAG list */ 75 WRITE_WORD(p, 4); 76 WRITE_WORD(p, 0x54410002); 77 WRITE_WORD(p, info->ram_size); 78 WRITE_WORD(p, info->loader_start); 79 if (initrd_size) { 80 /* ATAG_INITRD2 */ 81 WRITE_WORD(p, 4); 82 WRITE_WORD(p, 0x54420005); 83 WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR); 84 WRITE_WORD(p, initrd_size); 85 } 86 if (info->kernel_cmdline && *info->kernel_cmdline) { 87 /* ATAG_CMDLINE */ 88 int cmdline_size; 89 90 cmdline_size = strlen(info->kernel_cmdline); 91 cpu_physical_memory_write(p + 8, (void *)info->kernel_cmdline, 92 cmdline_size + 1); 93 cmdline_size = (cmdline_size >> 2) + 1; 94 WRITE_WORD(p, cmdline_size + 2); 95 WRITE_WORD(p, 0x54410009); 96 p += cmdline_size * 4; 97 } 98 if (info->atag_board) { 99 /* ATAG_BOARD */ 100 int atag_board_len; 101 uint8_t atag_board_buf[0x1000]; 102 103 atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3; 104 WRITE_WORD(p, (atag_board_len + 8) >> 2); 105 WRITE_WORD(p, 0x414f4d50); 106 cpu_physical_memory_write(p, atag_board_buf, atag_board_len); 107 p += atag_board_len; 108 } 109 /* ATAG_END */ 110 WRITE_WORD(p, 0); 111 WRITE_WORD(p, 0); 112 } 113 114 static void set_kernel_args_old(struct arm_boot_info *info, 115 int initrd_size, target_phys_addr_t base) 116 { 117 target_phys_addr_t p; 118 const char *s; 119 120 121 /* see linux/include/asm-arm/setup.h */ 122 p = base + KERNEL_ARGS_ADDR; 123 /* page_size */ 124 WRITE_WORD(p, 4096); 125 /* nr_pages */ 126 WRITE_WORD(p, info->ram_size / 4096); 127 /* ramdisk_size */ 128 WRITE_WORD(p, 0); 129 #define FLAG_READONLY 1 130 #define FLAG_RDLOAD 4 131 #define FLAG_RDPROMPT 8 132 /* flags */ 133 WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT); 134 /* rootdev */ 135 WRITE_WORD(p, (31 << 8) | 0); /* /dev/mtdblock0 */ 136 /* video_num_cols */ 137 WRITE_WORD(p, 0); 138 /* video_num_rows */ 139 WRITE_WORD(p, 0); 140 /* video_x */ 141 WRITE_WORD(p, 0); 142 /* video_y */ 143 WRITE_WORD(p, 0); 144 /* memc_control_reg */ 145 WRITE_WORD(p, 0); 146 /* unsigned char sounddefault */ 147 /* unsigned char adfsdrives */ 148 /* unsigned char bytes_per_char_h */ 149 /* unsigned char bytes_per_char_v */ 150 WRITE_WORD(p, 0); 151 /* pages_in_bank[4] */ 152 WRITE_WORD(p, 0); 153 WRITE_WORD(p, 0); 154 WRITE_WORD(p, 0); 155 WRITE_WORD(p, 0); 156 /* pages_in_vram */ 157 WRITE_WORD(p, 0); 158 /* initrd_start */ 159 if (initrd_size) 160 WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR); 161 else 162 WRITE_WORD(p, 0); 163 /* initrd_size */ 164 WRITE_WORD(p, initrd_size); 165 /* rd_start */ 166 WRITE_WORD(p, 0); 167 /* system_rev */ 168 WRITE_WORD(p, 0); 169 /* system_serial_low */ 170 WRITE_WORD(p, 0); 171 /* system_serial_high */ 172 WRITE_WORD(p, 0); 173 /* mem_fclk_21285 */ 174 WRITE_WORD(p, 0); 175 /* zero unused fields */ 176 while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) { 177 WRITE_WORD(p, 0); 178 } 179 s = info->kernel_cmdline; 180 if (s) { 181 cpu_physical_memory_write(p, (void *)s, strlen(s) + 1); 182 } else { 183 WRITE_WORD(p, 0); 184 } 185 } 186 187 void arm_load_kernel(CPUState *env, struct arm_boot_info *info) 188 { 189 int kernel_size; 190 int initrd_size; 191 int n; 192 int is_linux = 0; 193 uint64_t elf_entry; 194 target_phys_addr_t entry; 195 int big_endian; 196 197 /* Load the kernel. */ 198 if (!info->kernel_filename) { 199 fprintf(stderr, "Kernel image must be specified\n"); 200 exit(1); 201 } 202 203 if (info->nb_cpus == 0) 204 info->nb_cpus = 1; 205 env->boot_info = info; 206 207 #ifdef TARGET_WORDS_BIGENDIAN 208 big_endian = 1; 209 #else 210 big_endian = 0; 211 #endif 212 213 /* Assume that raw images are linux kernels, and ELF images are not. */ 214 kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL); 215 entry = elf_entry; 216 if (kernel_size < 0) { 217 kernel_size = load_uimage(info->kernel_filename, &entry, NULL, 218 &is_linux); 219 } 220 if (kernel_size < 0) { 221 entry = info->loader_start + KERNEL_LOAD_ADDR; 222 kernel_size = load_image_targphys(info->kernel_filename, entry, 223 ram_size - KERNEL_LOAD_ADDR); 224 is_linux = 1; 225 } 226 if (kernel_size < 0) { 227 fprintf(stderr, "qemu: could not load kernel '%s'\n", 228 info->kernel_filename); 229 exit(1); 230 } 231 if (!is_linux) { 232 /* Jump to the entry point. */ 233 env->regs[15] = entry & 0xfffffffe; 234 env->thumb = entry & 1; 235 } else { 236 if (info->initrd_filename) { 237 initrd_size = load_image_targphys(info->initrd_filename, 238 info->loader_start 239 + INITRD_LOAD_ADDR, 240 ram_size - INITRD_LOAD_ADDR); 241 if (initrd_size < 0) { 242 fprintf(stderr, "qemu: could not load initrd '%s'\n", 243 info->initrd_filename); 244 exit(1); 245 } 246 } else { 247 initrd_size = 0; 248 } 249 bootloader[1] |= info->board_id & 0xff; 250 bootloader[2] |= (info->board_id >> 8) & 0xff; 251 bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR; 252 bootloader[6] = entry; 253 for (n = 0; n < sizeof(bootloader) / 4; n++) { 254 stl_phys_notdirty(info->loader_start + (n * 4), bootloader[n]); 255 } 256 if (info->nb_cpus > 1) { 257 for (n = 0; n < sizeof(smpboot) / 4; n++) { 258 stl_phys_notdirty(info->smp_loader_start + (n * 4), smpboot[n]); 259 } 260 } 261 if (old_param) 262 set_kernel_args_old(info, initrd_size, info->loader_start); 263 else 264 set_kernel_args(info, initrd_size, info->loader_start); 265 } 266 info->is_linux = is_linux; 267 qemu_register_reset(main_cpu_reset, 0, env); 268 } 269