You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

start32.S 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #include "virtaddr.h"
  2. .equ MSR_K6_EFER, 0xC0000080
  3. .equ EFER_LME, 0x00000100
  4. .equ X86_CR4_PAE, 0x00000020
  5. .equ CR0_PG, 0x80000000
  6. #ifdef GAS291
  7. #define DATA32 data32;
  8. #define ADDR32 addr32;
  9. #define LJMPI(x) ljmp x
  10. #else
  11. #define DATA32 data32
  12. #define ADDR32 addr32
  13. /* newer GAS295 require #define LJMPI(x) ljmp *x */
  14. #define LJMPI(x) ljmp x
  15. #endif
  16. /*
  17. * NOTE: if you write a subroutine that is called from C code (gcc/egcs),
  18. * then you only have to take care of %ebx, %esi, %edi and %ebp. These
  19. * registers must not be altered under any circumstance. All other registers
  20. * may be clobbered without any negative side effects. If you don't follow
  21. * this rule then you'll run into strange effects that only occur on some
  22. * gcc versions (because the register allocator may use different registers).
  23. *
  24. * All the data32 prefixes for the ljmp instructions are necessary, because
  25. * the assembler emits code with a relocation address of 0. This means that
  26. * all destinations are initially negative, which the assembler doesn't grok,
  27. * because for some reason negative numbers don't fit into 16 bits. The addr32
  28. * prefixes are there for the same reasons, because otherwise the memory
  29. * references are only 16 bit wide. Theoretically they are all superfluous.
  30. * One last note about prefixes: the data32 prefixes on all call _real_to_prot
  31. * instructions could be removed if the _real_to_prot function is changed to
  32. * deal correctly with 16 bit return addresses. I tried it, but failed.
  33. */
  34. .text
  35. .arch i386
  36. .code32
  37. /* This is a struct os_entry_regs */
  38. .globl os_regs
  39. os_regs: .space 56
  40. /**************************************************************************
  41. XSTART32 - Transfer control to the kernel just loaded
  42. **************************************************************************/
  43. .globl xstart32
  44. xstart32:
  45. /* Save the callee save registers */
  46. movl %ebp, os_regs + 32
  47. movl %esi, os_regs + 36
  48. movl %edi, os_regs + 40
  49. movl %ebx, os_regs + 44
  50. /* save the return address */
  51. popl %eax
  52. movl %eax, os_regs + 48
  53. /* save the stack pointer */
  54. movl %esp, os_regs + 52
  55. /* Get the new destination address */
  56. popl %ecx
  57. /* Store the physical address of xend on the stack */
  58. movl $xend32, %ebx
  59. addl virt_offset, %ebx
  60. pushl %ebx
  61. /* Store the destination address on the stack */
  62. pushl $PHYSICAL_CS
  63. pushl %ecx
  64. /* Cache virt_offset */
  65. movl virt_offset, %ebp
  66. /* Switch to using physical addresses */
  67. call _virt_to_phys
  68. /* Save the target stack pointer */
  69. movl %esp, os_regs + 12(%ebp)
  70. leal os_regs(%ebp), %esp
  71. /* Store the pointer to os_regs */
  72. movl %esp, os_regs_ptr(%ebp)
  73. /* Load my new registers */
  74. popal
  75. movl (-32 + 12)(%esp), %esp
  76. /* Jump to the new kernel
  77. * The lret switches to a flat code segment
  78. */
  79. lret
  80. .balign 4
  81. .globl xend32
  82. xend32:
  83. /* Fixup %eflags */
  84. nop
  85. cli
  86. cld
  87. /* Load %esp with &os_regs + virt_offset */
  88. .byte 0xbc /* movl $0, %esp */
  89. os_regs_ptr:
  90. .long 0
  91. /* Save the result registers */
  92. addl $32, %esp
  93. pushal
  94. /* Compute virt_offset */
  95. movl %esp, %ebp
  96. subl $os_regs, %ebp
  97. /* Load the stack pointer and convert it to physical address */
  98. movl 52(%esp), %esp
  99. addl %ebp, %esp
  100. /* Enable the virtual addresses */
  101. leal _phys_to_virt(%ebp), %eax
  102. call *%eax
  103. /* Restore the callee save registers */
  104. movl os_regs + 32, %ebp
  105. movl os_regs + 36, %esi
  106. movl os_regs + 40, %edi
  107. movl os_regs + 44, %ebx
  108. movl os_regs + 48, %edx
  109. movl os_regs + 52, %esp
  110. /* Get the C return value */
  111. movl os_regs + 28, %eax
  112. jmpl *%edx
  113. #ifdef CONFIG_X86_64
  114. .arch sledgehammer
  115. /**************************************************************************
  116. XSTART_lm - Transfer control to the kernel just loaded in long mode
  117. **************************************************************************/
  118. .globl xstart_lm
  119. xstart_lm:
  120. /* Save the callee save registers */
  121. pushl %ebp
  122. pushl %esi
  123. pushl %edi
  124. pushl %ebx
  125. /* Cache virt_offset && (virt_offset & 0xfffff000) */
  126. movl virt_offset, %ebp
  127. movl %ebp, %ebx
  128. andl $0xfffff000, %ebx
  129. /* Switch to using physical addresses */
  130. call _virt_to_phys
  131. /* Initialize the page tables */
  132. /* Level 4 */
  133. leal 0x23 + pgt_level3(%ebx), %eax
  134. leal pgt_level4(%ebx), %edi
  135. movl %eax, (%edi)
  136. /* Level 3 */
  137. leal 0x23 + pgt_level2(%ebx), %eax
  138. leal pgt_level3(%ebx), %edi
  139. movl %eax, 0x00(%edi)
  140. addl $4096, %eax
  141. movl %eax, 0x08(%edi)
  142. addl $4096, %eax
  143. movl %eax, 0x10(%edi)
  144. addl $4096, %eax
  145. movl %eax, 0x18(%edi)
  146. /* Level 2 */
  147. movl $0xe3, %eax
  148. leal pgt_level2(%ebx), %edi
  149. leal 16384(%edi), %esi
  150. pgt_level2_loop:
  151. movl %eax, (%edi)
  152. addl $8, %edi
  153. addl $0x200000, %eax
  154. cmp %esi, %edi
  155. jne pgt_level2_loop
  156. /* Point at the x86_64 page tables */
  157. leal pgt_level4(%ebx), %edi
  158. movl %edi, %cr3
  159. /* Setup for the return from 64bit mode */
  160. /* 64bit align the stack */
  161. movl %esp, %ebx /* original stack pointer + 16 */
  162. andl $0xfffffff8, %esp
  163. /* Save original stack pointer + 16 */
  164. pushl %ebx
  165. /* Save virt_offset */
  166. pushl %ebp
  167. /* Setup for the jmp to 64bit long mode */
  168. leal start_lm(%ebp), %eax
  169. movl %eax, 0x00 + start_lm_addr(%ebp)
  170. movl $LM_CODE_SEG, %eax
  171. movl %eax, 0x04 + start_lm_addr(%ebp)
  172. /* Setup for the jump out of 64bit long mode */
  173. leal end_lm(%ebp), %eax
  174. movl %eax, 0x00 + end_lm_addr(%ebp)
  175. movl $FLAT_CODE_SEG, %eax
  176. movl %eax, 0x04 + end_lm_addr(%ebp)
  177. /* Enable PAE mode */
  178. movl %cr4, %eax
  179. orl $X86_CR4_PAE, %eax
  180. movl %eax, %cr4
  181. /* Enable long mode */
  182. movl $MSR_K6_EFER, %ecx
  183. rdmsr
  184. orl $EFER_LME, %eax
  185. wrmsr
  186. /* Start paging, entering 32bit compatiblity mode */
  187. movl %cr0, %eax
  188. orl $CR0_PG, %eax
  189. movl %eax, %cr0
  190. /* Enter 64bit long mode */
  191. ljmp *start_lm_addr(%ebp)
  192. .code64
  193. start_lm:
  194. /* Load 64bit data segments */
  195. movl $LM_DATA_SEG, %eax
  196. movl %eax, %ds
  197. movl %eax, %es
  198. movl %eax, %ss
  199. andq $0xffffffff, %rbx
  200. /* Get the address to jump to */
  201. movl 20(%rbx), %edx
  202. andq $0xffffffff, %rdx
  203. /* Get the argument pointer */
  204. movl 24(%rbx), %ebx
  205. andq $0xffffffff, %rbx
  206. /* Jump to the 64bit code */
  207. call *%rdx
  208. /* Preserve the result */
  209. movl %eax, %edx
  210. /* Fixup %eflags */
  211. cli
  212. cld
  213. /* Switch to 32bit compatibility mode */
  214. ljmp *end_lm_addr(%rip)
  215. .code32
  216. end_lm:
  217. /* Disable paging */
  218. movl %cr0, %eax
  219. andl $~CR0_PG, %eax
  220. movl %eax, %cr0
  221. /* Disable long mode */
  222. movl $MSR_K6_EFER, %ecx
  223. rdmsr
  224. andl $~EFER_LME, %eax
  225. wrmsr
  226. /* Disable PAE */
  227. movl %cr4, %eax
  228. andl $~X86_CR4_PAE, %eax
  229. movl %eax, %cr4
  230. /* Compute virt_offset */
  231. popl %ebp
  232. /* Compute the original stack pointer + 16 */
  233. popl %ebx
  234. movl %ebx, %esp
  235. /* Enable the virtual addresses */
  236. leal _phys_to_virt(%ebp), %eax
  237. call *%eax
  238. /* Restore the callee save registers */
  239. popl %ebx
  240. popl %esi
  241. popl %edi
  242. popl %ebp
  243. /* Get the C return value */
  244. movl %edx, %eax
  245. /* Return */
  246. ret
  247. .arch i386
  248. #endif /* CONFIG_X86_64 */
  249. #ifdef CONFIG_X86_64
  250. .section ".bss"
  251. .p2align 12
  252. /* Include a dummy space in case we are loaded badly aligned */
  253. .space 4096
  254. /* Reserve enough space for a page table convering 4GB with 2MB pages */
  255. pgt_level4:
  256. .space 4096
  257. pgt_level3:
  258. .space 4096
  259. pgt_level2:
  260. .space 16384
  261. start_lm_addr:
  262. .space 8
  263. end_lm_addr:
  264. .space 8
  265. #endif