relocate_kernel_32.S 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * relocate_kernel.S - put the kernel image in place to boot
  3. * Copyright (C) 2002-2004 Eric Biederman <ebiederm@xmission.com>
  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 <linux/linkage.h>
  9. #include <asm/page.h>
  10. #include <asm/kexec.h>
  11. /*
  12. * Must be relocatable PIC code callable as a C function
  13. */
  14. #define PTR(x) (x << 2)
  15. #define PAGE_ATTR 0x63 /* _PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY */
  16. #define PAE_PGD_ATTR 0x01 /* _PAGE_PRESENT */
  17. .text
  18. .align PAGE_SIZE
  19. .globl relocate_kernel
  20. relocate_kernel:
  21. movl 8(%esp), %ebp /* list of pages */
  22. #ifdef CONFIG_X86_PAE
  23. /* map the control page at its virtual address */
  24. movl PTR(VA_PGD)(%ebp), %edi
  25. movl PTR(VA_CONTROL_PAGE)(%ebp), %eax
  26. andl $0xc0000000, %eax
  27. shrl $27, %eax
  28. addl %edi, %eax
  29. movl PTR(PA_PMD_0)(%ebp), %edx
  30. orl $PAE_PGD_ATTR, %edx
  31. movl %edx, (%eax)
  32. movl PTR(VA_PMD_0)(%ebp), %edi
  33. movl PTR(VA_CONTROL_PAGE)(%ebp), %eax
  34. andl $0x3fe00000, %eax
  35. shrl $18, %eax
  36. addl %edi, %eax
  37. movl PTR(PA_PTE_0)(%ebp), %edx
  38. orl $PAGE_ATTR, %edx
  39. movl %edx, (%eax)
  40. movl PTR(VA_PTE_0)(%ebp), %edi
  41. movl PTR(VA_CONTROL_PAGE)(%ebp), %eax
  42. andl $0x001ff000, %eax
  43. shrl $9, %eax
  44. addl %edi, %eax
  45. movl PTR(PA_CONTROL_PAGE)(%ebp), %edx
  46. orl $PAGE_ATTR, %edx
  47. movl %edx, (%eax)
  48. /* identity map the control page at its physical address */
  49. movl PTR(VA_PGD)(%ebp), %edi
  50. movl PTR(PA_CONTROL_PAGE)(%ebp), %eax
  51. andl $0xc0000000, %eax
  52. shrl $27, %eax
  53. addl %edi, %eax
  54. movl PTR(PA_PMD_1)(%ebp), %edx
  55. orl $PAE_PGD_ATTR, %edx
  56. movl %edx, (%eax)
  57. movl PTR(VA_PMD_1)(%ebp), %edi
  58. movl PTR(PA_CONTROL_PAGE)(%ebp), %eax
  59. andl $0x3fe00000, %eax
  60. shrl $18, %eax
  61. addl %edi, %eax
  62. movl PTR(PA_PTE_1)(%ebp), %edx
  63. orl $PAGE_ATTR, %edx
  64. movl %edx, (%eax)
  65. movl PTR(VA_PTE_1)(%ebp), %edi
  66. movl PTR(PA_CONTROL_PAGE)(%ebp), %eax
  67. andl $0x001ff000, %eax
  68. shrl $9, %eax
  69. addl %edi, %eax
  70. movl PTR(PA_CONTROL_PAGE)(%ebp), %edx
  71. orl $PAGE_ATTR, %edx
  72. movl %edx, (%eax)
  73. #else
  74. /* map the control page at its virtual address */
  75. movl PTR(VA_PGD)(%ebp), %edi
  76. movl PTR(VA_CONTROL_PAGE)(%ebp), %eax
  77. andl $0xffc00000, %eax
  78. shrl $20, %eax
  79. addl %edi, %eax
  80. movl PTR(PA_PTE_0)(%ebp), %edx
  81. orl $PAGE_ATTR, %edx
  82. movl %edx, (%eax)
  83. movl PTR(VA_PTE_0)(%ebp), %edi
  84. movl PTR(VA_CONTROL_PAGE)(%ebp), %eax
  85. andl $0x003ff000, %eax
  86. shrl $10, %eax
  87. addl %edi, %eax
  88. movl PTR(PA_CONTROL_PAGE)(%ebp), %edx
  89. orl $PAGE_ATTR, %edx
  90. movl %edx, (%eax)
  91. /* identity map the control page at its physical address */
  92. movl PTR(VA_PGD)(%ebp), %edi
  93. movl PTR(PA_CONTROL_PAGE)(%ebp), %eax
  94. andl $0xffc00000, %eax
  95. shrl $20, %eax
  96. addl %edi, %eax
  97. movl PTR(PA_PTE_1)(%ebp), %edx
  98. orl $PAGE_ATTR, %edx
  99. movl %edx, (%eax)
  100. movl PTR(VA_PTE_1)(%ebp), %edi
  101. movl PTR(PA_CONTROL_PAGE)(%ebp), %eax
  102. andl $0x003ff000, %eax
  103. shrl $10, %eax
  104. addl %edi, %eax
  105. movl PTR(PA_CONTROL_PAGE)(%ebp), %edx
  106. orl $PAGE_ATTR, %edx
  107. movl %edx, (%eax)
  108. #endif
  109. relocate_new_kernel:
  110. /* read the arguments and say goodbye to the stack */
  111. movl 4(%esp), %ebx /* page_list */
  112. movl 8(%esp), %ebp /* list of pages */
  113. movl 12(%esp), %edx /* start address */
  114. movl 16(%esp), %ecx /* cpu_has_pae */
  115. /* zero out flags, and disable interrupts */
  116. pushl $0
  117. popfl
  118. /* get physical address of control page now */
  119. /* this is impossible after page table switch */
  120. movl PTR(PA_CONTROL_PAGE)(%ebp), %edi
  121. /* switch to new set of page tables */
  122. movl PTR(PA_PGD)(%ebp), %eax
  123. movl %eax, %cr3
  124. /* setup a new stack at the end of the physical control page */
  125. lea 4096(%edi), %esp
  126. /* jump to identity mapped page */
  127. movl %edi, %eax
  128. addl $(identity_mapped - relocate_kernel), %eax
  129. pushl %eax
  130. ret
  131. identity_mapped:
  132. /* store the start address on the stack */
  133. pushl %edx
  134. /* Set cr0 to a known state:
  135. * 31 0 == Paging disabled
  136. * 18 0 == Alignment check disabled
  137. * 16 0 == Write protect disabled
  138. * 3 0 == No task switch
  139. * 2 0 == Don't do FP software emulation.
  140. * 0 1 == Proctected mode enabled
  141. */
  142. movl %cr0, %eax
  143. andl $~((1<<31)|(1<<18)|(1<<16)|(1<<3)|(1<<2)), %eax
  144. orl $(1<<0), %eax
  145. movl %eax, %cr0
  146. /* clear cr4 if applicable */
  147. testl %ecx, %ecx
  148. jz 1f
  149. /* Set cr4 to a known state:
  150. * Setting everything to zero seems safe.
  151. */
  152. movl %cr4, %eax
  153. andl $0, %eax
  154. movl %eax, %cr4
  155. jmp 1f
  156. 1:
  157. /* Flush the TLB (needed?) */
  158. xorl %eax, %eax
  159. movl %eax, %cr3
  160. /* Do the copies */
  161. movl %ebx, %ecx
  162. jmp 1f
  163. 0: /* top, read another word from the indirection page */
  164. movl (%ebx), %ecx
  165. addl $4, %ebx
  166. 1:
  167. testl $0x1, %ecx /* is it a destination page */
  168. jz 2f
  169. movl %ecx, %edi
  170. andl $0xfffff000, %edi
  171. jmp 0b
  172. 2:
  173. testl $0x2, %ecx /* is it an indirection page */
  174. jz 2f
  175. movl %ecx, %ebx
  176. andl $0xfffff000, %ebx
  177. jmp 0b
  178. 2:
  179. testl $0x4, %ecx /* is it the done indicator */
  180. jz 2f
  181. jmp 3f
  182. 2:
  183. testl $0x8, %ecx /* is it the source indicator */
  184. jz 0b /* Ignore it otherwise */
  185. movl %ecx, %esi /* For every source page do a copy */
  186. andl $0xfffff000, %esi
  187. movl $1024, %ecx
  188. rep ; movsl
  189. jmp 0b
  190. 3:
  191. /* To be certain of avoiding problems with self-modifying code
  192. * I need to execute a serializing instruction here.
  193. * So I flush the TLB, it's handy, and not processor dependent.
  194. */
  195. xorl %eax, %eax
  196. movl %eax, %cr3
  197. /* set all of the registers to known values */
  198. /* leave %esp alone */
  199. xorl %eax, %eax
  200. xorl %ebx, %ebx
  201. xorl %ecx, %ecx
  202. xorl %edx, %edx
  203. xorl %esi, %esi
  204. xorl %edi, %edi
  205. xorl %ebp, %ebp
  206. ret