relocate_kernel.S 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * relocate_kernel.S - put the kernel image in place to boot
  3. * 2005.9.17 kogiidena@eggplant.ddo.jp
  4. *
  5. * LANDISK/sh4 is supported. Maybe, SH archtecture works well.
  6. *
  7. * 2009-03-18 Magnus Damm - Added Kexec Jump support
  8. *
  9. * This source code is licensed under the GNU General Public License,
  10. * Version 2. See the file COPYING for more details.
  11. */
  12. #include <linux/linkage.h>
  13. #include <asm/addrspace.h>
  14. #include <asm/page.h>
  15. .globl relocate_new_kernel
  16. relocate_new_kernel:
  17. /* r4 = indirection_page */
  18. /* r5 = reboot_code_buffer */
  19. /* r6 = start_address */
  20. mov.l 10f, r0 /* PAGE_SIZE */
  21. add r5, r0 /* setup new stack at end of control page */
  22. /* save r15->r8 to new stack */
  23. mov.l r15, @-r0
  24. mov r0, r15
  25. mov.l r14, @-r15
  26. mov.l r13, @-r15
  27. mov.l r12, @-r15
  28. mov.l r11, @-r15
  29. mov.l r10, @-r15
  30. mov.l r9, @-r15
  31. mov.l r8, @-r15
  32. /* save other random registers */
  33. sts.l macl, @-r15
  34. sts.l mach, @-r15
  35. stc.l gbr, @-r15
  36. stc.l ssr, @-r15
  37. stc.l sr, @-r15
  38. sts.l pr, @-r15
  39. stc.l spc, @-r15
  40. /* switch to bank1 and save r7->r0 */
  41. mov.l 12f, r9
  42. stc sr, r8
  43. or r9, r8
  44. ldc r8, sr
  45. mov.l r7, @-r15
  46. mov.l r6, @-r15
  47. mov.l r5, @-r15
  48. mov.l r4, @-r15
  49. mov.l r3, @-r15
  50. mov.l r2, @-r15
  51. mov.l r1, @-r15
  52. mov.l r0, @-r15
  53. /* switch to bank0 and save r7->r0 */
  54. mov.l 12f, r9
  55. not r9, r9
  56. stc sr, r8
  57. and r9, r8
  58. ldc r8, sr
  59. mov.l r7, @-r15
  60. mov.l r6, @-r15
  61. mov.l r5, @-r15
  62. mov.l r4, @-r15
  63. mov.l r3, @-r15
  64. mov.l r2, @-r15
  65. mov.l r1, @-r15
  66. mov.l r0, @-r15
  67. mov.l r4, @-r15 /* save indirection page again */
  68. bsr swap_pages /* swap pages before jumping to new kernel */
  69. nop
  70. mova 11f, r0
  71. mov.l r15, @r0 /* save pointer to stack */
  72. jsr @r6 /* hand over control to new kernel */
  73. nop
  74. mov.l 11f, r15 /* get pointer to stack */
  75. mov.l @r15+, r4 /* restore r4 to get indirection page */
  76. bsr swap_pages /* swap pages back to previous state */
  77. nop
  78. /* make sure bank0 is active and restore r0->r7 */
  79. mov.l 12f, r9
  80. not r9, r9
  81. stc sr, r8
  82. and r9, r8
  83. ldc r8, sr
  84. mov.l @r15+, r0
  85. mov.l @r15+, r1
  86. mov.l @r15+, r2
  87. mov.l @r15+, r3
  88. mov.l @r15+, r4
  89. mov.l @r15+, r5
  90. mov.l @r15+, r6
  91. mov.l @r15+, r7
  92. /* switch to bank1 and restore r0->r7 */
  93. mov.l 12f, r9
  94. stc sr, r8
  95. or r9, r8
  96. ldc r8, sr
  97. mov.l @r15+, r0
  98. mov.l @r15+, r1
  99. mov.l @r15+, r2
  100. mov.l @r15+, r3
  101. mov.l @r15+, r4
  102. mov.l @r15+, r5
  103. mov.l @r15+, r6
  104. mov.l @r15+, r7
  105. /* switch back to bank0 */
  106. mov.l 12f, r9
  107. not r9, r9
  108. stc sr, r8
  109. and r9, r8
  110. ldc r8, sr
  111. /* restore other random registers */
  112. ldc.l @r15+, spc
  113. lds.l @r15+, pr
  114. ldc.l @r15+, sr
  115. ldc.l @r15+, ssr
  116. ldc.l @r15+, gbr
  117. lds.l @r15+, mach
  118. lds.l @r15+, macl
  119. /* restore r8->r15 */
  120. mov.l @r15+, r8
  121. mov.l @r15+, r9
  122. mov.l @r15+, r10
  123. mov.l @r15+, r11
  124. mov.l @r15+, r12
  125. mov.l @r15+, r13
  126. mov.l @r15+, r14
  127. mov.l @r15+, r15
  128. rts
  129. nop
  130. swap_pages:
  131. bra 1f
  132. mov r4,r0 /* cmd = indirection_page */
  133. 0:
  134. mov.l @r4+,r0 /* cmd = *ind++ */
  135. 1: /* addr = cmd & 0xfffffff0 */
  136. mov r0,r2
  137. mov #-16,r1
  138. and r1,r2
  139. /* if(cmd & IND_DESTINATION) dst = addr */
  140. tst #1,r0
  141. bt 2f
  142. bra 0b
  143. mov r2,r5
  144. 2: /* else if(cmd & IND_INDIRECTION) ind = addr */
  145. tst #2,r0
  146. bt 3f
  147. bra 0b
  148. mov r2,r4
  149. 3: /* else if(cmd & IND_DONE) return */
  150. tst #4,r0
  151. bt 4f
  152. rts
  153. nop
  154. 4: /* else if(cmd & IND_SOURCE) memcpy(dst,addr,PAGE_SIZE) */
  155. tst #8,r0
  156. bt 0b
  157. mov.l 10f,r3 /* PAGE_SIZE */
  158. shlr2 r3
  159. shlr2 r3
  160. 5:
  161. dt r3
  162. /* regular kexec just overwrites the destination page
  163. * with the contents of the source page.
  164. * for the kexec jump case we need to swap the contents
  165. * of the pages.
  166. * to keep it simple swap the contents for both cases.
  167. */
  168. mov.l @(0, r2), r8
  169. mov.l @(0, r5), r1
  170. mov.l r8, @(0, r5)
  171. mov.l r1, @(0, r2)
  172. mov.l @(4, r2), r8
  173. mov.l @(4, r5), r1
  174. mov.l r8, @(4, r5)
  175. mov.l r1, @(4, r2)
  176. mov.l @(8, r2), r8
  177. mov.l @(8, r5), r1
  178. mov.l r8, @(8, r5)
  179. mov.l r1, @(8, r2)
  180. mov.l @(12, r2), r8
  181. mov.l @(12, r5), r1
  182. mov.l r8, @(12, r5)
  183. mov.l r1, @(12, r2)
  184. add #16,r5
  185. add #16,r2
  186. bf 5b
  187. bra 0b
  188. nop
  189. .align 2
  190. 10:
  191. .long PAGE_SIZE
  192. 11:
  193. .long 0
  194. 12:
  195. .long 0x20000000 ! RB=1
  196. relocate_new_kernel_end:
  197. .globl relocate_new_kernel_size
  198. relocate_new_kernel_size:
  199. .long relocate_new_kernel_end - relocate_new_kernel