bootm.c 7.5 KB

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