bootm.c 7.5 KB

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