arm_boot.c 7.3 KB

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