relocate_kernel.S 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * relocate_kernel.S for kexec
  3. * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
  4. *
  5. * This source code is licensed under the GNU General Public License,
  6. * Version 2. See the file COPYING for more details.
  7. */
  8. #include <asm/asm.h>
  9. #include <asm/asmmacro.h>
  10. #include <asm/regdef.h>
  11. #include <asm/page.h>
  12. #include <asm/mipsregs.h>
  13. #include <asm/stackframe.h>
  14. #include <asm/addrspace.h>
  15. LEAF(relocate_new_kernel)
  16. PTR_L a0, arg0
  17. PTR_L a1, arg1
  18. PTR_L a2, arg2
  19. PTR_L a3, arg3
  20. PTR_L s0, kexec_indirection_page
  21. PTR_L s1, kexec_start_address
  22. process_entry:
  23. PTR_L s2, (s0)
  24. PTR_ADD s0, s0, SZREG
  25. /* destination page */
  26. and s3, s2, 0x1
  27. beq s3, zero, 1f
  28. and s4, s2, ~0x1 /* store destination addr in s4 */
  29. b process_entry
  30. 1:
  31. /* indirection page, update s0 */
  32. and s3, s2, 0x2
  33. beq s3, zero, 1f
  34. and s0, s2, ~0x2
  35. b process_entry
  36. 1:
  37. /* done page */
  38. and s3, s2, 0x4
  39. beq s3, zero, 1f
  40. b done
  41. 1:
  42. /* source page */
  43. and s3, s2, 0x8
  44. beq s3, zero, process_entry
  45. and s2, s2, ~0x8
  46. li s6, (1 << PAGE_SHIFT) / SZREG
  47. copy_word:
  48. /* copy page word by word */
  49. REG_L s5, (s2)
  50. REG_S s5, (s4)
  51. PTR_ADD s4, s4, SZREG
  52. PTR_ADD s2, s2, SZREG
  53. LONG_SUB s6, s6, 1
  54. beq s6, zero, process_entry
  55. b copy_word
  56. b process_entry
  57. done:
  58. #ifdef CONFIG_SMP
  59. /* kexec_flag reset is signal to other CPUs what kernel
  60. was moved to it's location. Note - we need relocated address
  61. of kexec_flag. */
  62. bal 1f
  63. 1: move t1,ra;
  64. PTR_LA t2,1b
  65. PTR_LA t0,kexec_flag
  66. PTR_SUB t0,t0,t2;
  67. PTR_ADD t0,t1,t0;
  68. LONG_S zero,(t0)
  69. #endif
  70. #ifdef CONFIG_CPU_CAVIUM_OCTEON
  71. /* We need to flush I-cache before jumping to new kernel.
  72. * Unfortunatelly, this code is cpu-specific.
  73. */
  74. .set push
  75. .set noreorder
  76. syncw
  77. syncw
  78. synci 0($0)
  79. .set pop
  80. #else
  81. sync
  82. #endif
  83. /* jump to kexec_start_address */
  84. j s1
  85. END(relocate_new_kernel)
  86. #ifdef CONFIG_SMP
  87. /*
  88. * Other CPUs should wait until code is relocated and
  89. * then start at entry (?) point.
  90. */
  91. LEAF(kexec_smp_wait)
  92. PTR_L a0, s_arg0
  93. PTR_L a1, s_arg1
  94. PTR_L a2, s_arg2
  95. PTR_L a3, s_arg3
  96. PTR_L s1, kexec_start_address
  97. /* Non-relocated address works for args and kexec_start_address ( old
  98. * kernel is not overwritten). But we need relocated address of
  99. * kexec_flag.
  100. */
  101. bal 1f
  102. 1: move t1,ra;
  103. PTR_LA t2,1b
  104. PTR_LA t0,kexec_flag
  105. PTR_SUB t0,t0,t2;
  106. PTR_ADD t0,t1,t0;
  107. 1: LONG_L s0, (t0)
  108. bne s0, zero,1b
  109. #ifdef CONFIG_CPU_CAVIUM_OCTEON
  110. .set push
  111. .set noreorder
  112. synci 0($0)
  113. .set pop
  114. #else
  115. sync
  116. #endif
  117. j s1
  118. END(kexec_smp_wait)
  119. #endif
  120. #ifdef __mips64
  121. /* all PTR's must be aligned to 8 byte in 64-bit mode */
  122. .align 3
  123. #endif
  124. /* All parameters to new kernel are passed in registers a0-a3.
  125. * kexec_args[0..3] are uses to prepare register values.
  126. */
  127. kexec_args:
  128. EXPORT(kexec_args)
  129. arg0: PTR 0x0
  130. arg1: PTR 0x0
  131. arg2: PTR 0x0
  132. arg3: PTR 0x0
  133. .size kexec_args,PTRSIZE*4
  134. #ifdef CONFIG_SMP
  135. /*
  136. * Secondary CPUs may have different kernel parameters in
  137. * their registers a0-a3. secondary_kexec_args[0..3] are used
  138. * to prepare register values.
  139. */
  140. secondary_kexec_args:
  141. EXPORT(secondary_kexec_args)
  142. s_arg0: PTR 0x0
  143. s_arg1: PTR 0x0
  144. s_arg2: PTR 0x0
  145. s_arg3: PTR 0x0
  146. .size secondary_kexec_args,PTRSIZE*4
  147. kexec_flag:
  148. LONG 0x1
  149. #endif
  150. kexec_start_address:
  151. EXPORT(kexec_start_address)
  152. PTR 0x0
  153. .size kexec_start_address, PTRSIZE
  154. kexec_indirection_page:
  155. EXPORT(kexec_indirection_page)
  156. PTR 0
  157. .size kexec_indirection_page, PTRSIZE
  158. relocate_new_kernel_end:
  159. relocate_new_kernel_size:
  160. EXPORT(relocate_new_kernel_size)
  161. PTR relocate_new_kernel_end - relocate_new_kernel
  162. .size relocate_new_kernel_size, PTRSIZE