bootm.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2008 Semihalf
  4. *
  5. * (C) Copyright 2000-2006
  6. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  7. */
  8. #include <common.h>
  9. #include <bootstage.h>
  10. #include <cpu_func.h>
  11. #include <env.h>
  12. #include <init.h>
  13. #include <watchdog.h>
  14. #include <command.h>
  15. #include <image.h>
  16. #include <malloc.h>
  17. #include <u-boot/zlib.h>
  18. #include <bzlib.h>
  19. #include <asm/byteorder.h>
  20. #include <asm/mp.h>
  21. #include <bootm.h>
  22. #include <vxworks.h>
  23. #if defined(CONFIG_OF_LIBFDT)
  24. #include <linux/libfdt.h>
  25. #include <fdt_support.h>
  26. #endif
  27. #ifdef CONFIG_SYS_INIT_RAM_LOCK
  28. #include <asm/cache.h>
  29. #endif
  30. DECLARE_GLOBAL_DATA_PTR;
  31. static ulong get_sp (void);
  32. extern void ft_fixup_num_cores(void *blob);
  33. static void set_clocks_in_mhz (bd_t *kbd);
  34. #ifndef CONFIG_SYS_LINUX_LOWMEM_MAX_SIZE
  35. #define CONFIG_SYS_LINUX_LOWMEM_MAX_SIZE (768*1024*1024)
  36. #endif
  37. static void boot_jump_linux(bootm_headers_t *images)
  38. {
  39. void (*kernel)(bd_t *, ulong r4, ulong r5, ulong r6,
  40. ulong r7, ulong r8, ulong r9);
  41. #ifdef CONFIG_OF_LIBFDT
  42. char *of_flat_tree = images->ft_addr;
  43. #endif
  44. kernel = (void (*)(bd_t *, ulong, ulong, ulong,
  45. ulong, ulong, ulong))images->ep;
  46. debug ("## Transferring control to Linux (at address %08lx) ...\n",
  47. (ulong)kernel);
  48. bootstage_mark(BOOTSTAGE_ID_RUN_OS);
  49. #ifdef CONFIG_BOOTSTAGE_FDT
  50. bootstage_fdt_add_report();
  51. #endif
  52. #ifdef CONFIG_BOOTSTAGE_REPORT
  53. bootstage_report();
  54. #endif
  55. #if defined(CONFIG_SYS_INIT_RAM_LOCK) && !defined(CONFIG_E500)
  56. unlock_ram_in_cache();
  57. #endif
  58. #if defined(CONFIG_OF_LIBFDT)
  59. if (of_flat_tree) { /* device tree; boot new style */
  60. /*
  61. * Linux Kernel Parameters (passing device tree):
  62. * r3: pointer to the fdt
  63. * r4: 0
  64. * r5: 0
  65. * r6: epapr magic
  66. * r7: size of IMA in bytes
  67. * r8: 0
  68. * r9: 0
  69. */
  70. debug (" Booting using OF flat tree...\n");
  71. WATCHDOG_RESET ();
  72. (*kernel) ((bd_t *)of_flat_tree, 0, 0, EPAPR_MAGIC,
  73. env_get_bootm_mapsize(), 0, 0);
  74. /* does not return */
  75. } else
  76. #endif
  77. {
  78. /*
  79. * Linux Kernel Parameters (passing board info data):
  80. * r3: ptr to board info data
  81. * r4: initrd_start or 0 if no initrd
  82. * r5: initrd_end - unused if r4 is 0
  83. * r6: Start of command line string
  84. * r7: End of command line string
  85. * r8: 0
  86. * r9: 0
  87. */
  88. ulong cmd_start = images->cmdline_start;
  89. ulong cmd_end = images->cmdline_end;
  90. ulong initrd_start = images->initrd_start;
  91. ulong initrd_end = images->initrd_end;
  92. bd_t *kbd = images->kbd;
  93. debug (" Booting using board info...\n");
  94. WATCHDOG_RESET ();
  95. (*kernel) (kbd, initrd_start, initrd_end,
  96. cmd_start, cmd_end, 0, 0);
  97. /* does not return */
  98. }
  99. return ;
  100. }
  101. void arch_lmb_reserve(struct lmb *lmb)
  102. {
  103. phys_size_t bootm_size;
  104. ulong size, sp, bootmap_base;
  105. bootmap_base = env_get_bootm_low();
  106. bootm_size = env_get_bootm_size();
  107. #ifdef DEBUG
  108. if (((u64)bootmap_base + bootm_size) >
  109. (CONFIG_SYS_SDRAM_BASE + (u64)gd->ram_size))
  110. puts("WARNING: bootm_low + bootm_size exceed total memory\n");
  111. if ((bootmap_base + bootm_size) > get_effective_memsize())
  112. puts("WARNING: bootm_low + bootm_size exceed eff. memory\n");
  113. #endif
  114. size = min(bootm_size, get_effective_memsize());
  115. size = min(size, (ulong)CONFIG_SYS_LINUX_LOWMEM_MAX_SIZE);
  116. if (size < bootm_size) {
  117. ulong base = bootmap_base + size;
  118. printf("WARNING: adjusting available memory to %lx\n", size);
  119. lmb_reserve(lmb, base, bootm_size - size);
  120. }
  121. /*
  122. * Booting a (Linux) kernel image
  123. *
  124. * Allocate space for command line and board info - the
  125. * address should be as high as possible within the reach of
  126. * the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused
  127. * memory, which means far enough below the current stack
  128. * pointer.
  129. */
  130. sp = get_sp();
  131. debug ("## Current stack ends at 0x%08lx\n", sp);
  132. /* adjust sp by 4K to be safe */
  133. sp -= 4096;
  134. lmb_reserve(lmb, sp, (CONFIG_SYS_SDRAM_BASE + get_effective_memsize() - sp));
  135. #ifdef CONFIG_MP
  136. cpu_mp_lmb_reserve(lmb);
  137. #endif
  138. return ;
  139. }
  140. static void boot_prep_linux(bootm_headers_t *images)
  141. {
  142. #ifdef CONFIG_MP
  143. /*
  144. * if we are MP make sure to flush the device tree so any changes are
  145. * made visibile to all other cores. In AMP boot scenarios the cores
  146. * might not be HW cache coherent with each other.
  147. */
  148. flush_cache((unsigned long)images->ft_addr, images->ft_len);
  149. #endif
  150. }
  151. static int boot_cmdline_linux(bootm_headers_t *images)
  152. {
  153. ulong of_size = images->ft_len;
  154. struct lmb *lmb = &images->lmb;
  155. ulong *cmd_start = &images->cmdline_start;
  156. ulong *cmd_end = &images->cmdline_end;
  157. int ret = 0;
  158. if (!of_size) {
  159. /* allocate space and init command line */
  160. ret = boot_get_cmdline (lmb, cmd_start, cmd_end);
  161. if (ret) {
  162. puts("ERROR with allocation of cmdline\n");
  163. return ret;
  164. }
  165. }
  166. return ret;
  167. }
  168. static int boot_bd_t_linux(bootm_headers_t *images)
  169. {
  170. ulong of_size = images->ft_len;
  171. struct lmb *lmb = &images->lmb;
  172. bd_t **kbd = &images->kbd;
  173. int ret = 0;
  174. if (!of_size) {
  175. /* allocate space for kernel copy of board info */
  176. ret = boot_get_kbd (lmb, kbd);
  177. if (ret) {
  178. puts("ERROR with allocation of kernel bd\n");
  179. return ret;
  180. }
  181. set_clocks_in_mhz(*kbd);
  182. }
  183. return ret;
  184. }
  185. static int boot_body_linux(bootm_headers_t *images)
  186. {
  187. int ret;
  188. /* allocate space for kernel copy of board info */
  189. ret = boot_bd_t_linux(images);
  190. if (ret)
  191. return ret;
  192. ret = image_setup_linux(images);
  193. if (ret)
  194. return ret;
  195. return 0;
  196. }
  197. noinline
  198. int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images)
  199. {
  200. int ret;
  201. if (flag & BOOTM_STATE_OS_CMDLINE) {
  202. boot_cmdline_linux(images);
  203. return 0;
  204. }
  205. if (flag & BOOTM_STATE_OS_BD_T) {
  206. boot_bd_t_linux(images);
  207. return 0;
  208. }
  209. if (flag & BOOTM_STATE_OS_PREP) {
  210. boot_prep_linux(images);
  211. return 0;
  212. }
  213. boot_prep_linux(images);
  214. ret = boot_body_linux(images);
  215. if (ret)
  216. return ret;
  217. boot_jump_linux(images);
  218. return 0;
  219. }
  220. static ulong get_sp (void)
  221. {
  222. ulong sp;
  223. asm( "mr %0,1": "=r"(sp) : );
  224. return sp;
  225. }
  226. static void set_clocks_in_mhz (bd_t *kbd)
  227. {
  228. char *s;
  229. s = env_get("clocks_in_mhz");
  230. if (s) {
  231. /* convert all clock information to MHz */
  232. kbd->bi_intfreq /= 1000000L;
  233. kbd->bi_busfreq /= 1000000L;
  234. #if defined(CONFIG_CPM2)
  235. kbd->bi_cpmfreq /= 1000000L;
  236. kbd->bi_brgfreq /= 1000000L;
  237. kbd->bi_sccfreq /= 1000000L;
  238. kbd->bi_vco /= 1000000L;
  239. #endif
  240. }
  241. }
  242. #if defined(CONFIG_BOOTM_VXWORKS)
  243. void boot_prep_vxworks(bootm_headers_t *images)
  244. {
  245. #if defined(CONFIG_OF_LIBFDT)
  246. int off;
  247. u64 base, size;
  248. if (!images->ft_addr)
  249. return;
  250. base = (u64)gd->bd->bi_memstart;
  251. size = (u64)gd->bd->bi_memsize;
  252. off = fdt_path_offset(images->ft_addr, "/memory");
  253. if (off < 0)
  254. fdt_fixup_memory(images->ft_addr, base, size);
  255. #if defined(CONFIG_MP)
  256. #if defined(CONFIG_MPC85xx)
  257. ft_fixup_cpu(images->ft_addr, base + size);
  258. ft_fixup_num_cores(images->ft_addr);
  259. #elif defined(CONFIG_MPC86xx)
  260. off = fdt_add_mem_rsv(images->ft_addr,
  261. determine_mp_bootpg(NULL), (u64)4096);
  262. if (off < 0)
  263. printf("## WARNING %s: %s\n", __func__, fdt_strerror(off));
  264. ft_fixup_num_cores(images->ft_addr);
  265. #endif
  266. flush_cache((unsigned long)images->ft_addr, images->ft_len);
  267. #endif
  268. #endif
  269. }
  270. void boot_jump_vxworks(bootm_headers_t *images)
  271. {
  272. /* PowerPC VxWorks boot interface conforms to the ePAPR standard
  273. * general purpuse registers:
  274. *
  275. * r3: Effective address of the device tree image
  276. * r4: 0
  277. * r5: 0
  278. * r6: ePAPR magic value
  279. * r7: shall be the size of the boot IMA in bytes
  280. * r8: 0
  281. * r9: 0
  282. * TCR: WRC = 0, no watchdog timer reset will occur
  283. */
  284. WATCHDOG_RESET();
  285. ((void (*)(void *, ulong, ulong, ulong,
  286. ulong, ulong, ulong))images->ep)(images->ft_addr,
  287. 0, 0, EPAPR_MAGIC, env_get_bootm_mapsize(), 0, 0);
  288. }
  289. #endif