realmode_switch.S 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * (C) Copyright 2002
  3. * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. /* 32bit -> 16bit -> 32bit mode switch code */
  24. /*
  25. * Stack frame at 0xe00
  26. * e00 ebx;
  27. * e04 ecx;
  28. * e08 edx;
  29. * e0c esi;
  30. * e10 edi;
  31. * e14 ebp;
  32. * e18 eax;
  33. * e1c ds;
  34. * e20 es;
  35. * e24 fs;
  36. * e28 gs;
  37. * e2c orig_eax;
  38. * e30 eip;
  39. * e34 cs;
  40. * e38 eflags;
  41. * e3c esp;
  42. * e40 ss;
  43. */
  44. #define a32 .byte 0x67; /* address size prefix 32 */
  45. #define o32 .byte 0x66; /* operand size prefix 32 */
  46. .section .realmode, "ax"
  47. .code16
  48. /* 16bit protected mode code here */
  49. .globl realmode_enter
  50. realmode_enter:
  51. o32 pusha
  52. o32 pushf
  53. cli
  54. sidt saved_idt
  55. sgdt saved_gdt
  56. movl %esp, %eax
  57. movl %eax, saved_protected_mode_esp
  58. movl $0x10, %eax
  59. movl %eax, %esp
  60. movw $0x28, %ax
  61. movw %ax, %ds
  62. movw %ax, %es
  63. movw %ax, %fs
  64. movw %ax, %gs
  65. lidt realmode_idt_ptr
  66. /* Go back into real mode by clearing PE to 0 */
  67. movl %cr0, %eax
  68. andl $0x7ffffffe, %eax
  69. movl %eax, %cr0
  70. /* switch to real mode */
  71. ljmp $0x0,$do_realmode
  72. do_realmode:
  73. /* realmode code from here */
  74. movw %cs,%ax
  75. movw %ax,%ds
  76. movw %ax,%es
  77. movw %ax,%fs
  78. movw %ax,%gs
  79. /* create a temporary stack */
  80. movw $0xc0, %ax
  81. movw %ax, %ss
  82. movw $0x200, %ax
  83. movw %ax, %sp
  84. popl %ebx
  85. popl %ecx
  86. popl %edx
  87. popl %esi
  88. popl %edi
  89. popl %ebp
  90. popl %eax
  91. movl %eax, temp_eax
  92. popl %eax
  93. movw %ax, %ds
  94. popl %eax
  95. movw %ax, %es
  96. popl %eax
  97. movw %ax, %fs
  98. popl %eax
  99. movw %ax, %gs
  100. popl %eax /* orig_eax */
  101. popl %eax
  102. cs movw %ax, temp_ip
  103. popl %eax
  104. cs movw %ax, temp_cs
  105. o32 popf
  106. popl %eax
  107. popw %ss
  108. movl %eax, %esp
  109. cs movl temp_eax, %eax
  110. /* self-modifying code, better flush the cache */
  111. wbinvd
  112. .byte 0x9a /* lcall */
  113. temp_ip:
  114. .word 0 /* new ip */
  115. temp_cs:
  116. .word 0 /* new cs */
  117. realmode_ret:
  118. /* save eax, esp and ss */
  119. cs movl %eax, saved_eax
  120. movl %esp, %eax
  121. cs movl %eax, saved_esp
  122. movw %ss, %ax
  123. cs movw %ax, saved_ss
  124. /*
  125. * restore the stack, note that we set sp to 0x244;
  126. * pt_regs is 0x44 bytes long and we push the structure
  127. * backwards on to the stack, bottom first
  128. */
  129. movw $0xc0, %ax
  130. movw %ax, %ss
  131. movw $0x244, %ax
  132. movw %ax, %sp
  133. xorl %eax,%eax
  134. cs movw saved_ss, %ax
  135. pushl %eax
  136. cs movl saved_esp, %eax
  137. pushl %eax
  138. o32 pushf
  139. xorl %eax,%eax
  140. cs movw temp_cs, %ax
  141. pushl %eax
  142. cs movw temp_ip, %ax
  143. pushl %eax
  144. pushl $0
  145. movw %gs, %ax
  146. pushl %eax
  147. movw %fs, %ax
  148. pushl %eax
  149. movw %es, %ax
  150. pushl %eax
  151. movw %ds, %ax
  152. pushl %eax
  153. movl saved_eax, %eax
  154. pushl %eax
  155. pushl %ebp
  156. pushl %edi
  157. pushl %esi
  158. pushl %edx
  159. pushl %ecx
  160. pushl %ebx
  161. o32 cs lidt saved_idt
  162. o32 cs lgdt saved_gdt
  163. /* Go back into protected mode reset PE to 1 */
  164. movl %cr0, %eax
  165. orl $1,%eax
  166. movl %eax, %cr0
  167. /* flush prefetch queue */
  168. jmp next_line
  169. next_line:
  170. movw $return_ptr, %ax
  171. movw %ax,%bp
  172. o32 cs ljmp *(%bp)
  173. .code32
  174. protected_mode:
  175. /* Reload segment registers */
  176. movl $0x18, %eax
  177. movw %ax, %fs
  178. movw %ax, %ds
  179. movw %ax, %gs
  180. movw %ax, %es
  181. movw %ax, %ss
  182. movl saved_protected_mode_esp, %eax
  183. movl %eax, %esp
  184. popf
  185. popa
  186. ret
  187. temp_eax:
  188. .long 0
  189. saved_ss:
  190. .word 0
  191. saved_esp:
  192. .long 0
  193. saved_eax:
  194. .long 0
  195. realmode_idt_ptr:
  196. .word 0x400
  197. .word 0x0, 0x0
  198. saved_gdt:
  199. .word 0, 0, 0, 0
  200. saved_idt:
  201. .word 0, 0, 0, 0
  202. saved_protected_mode_esp:
  203. .long 0
  204. return_ptr:
  205. .long protected_mode
  206. .word 0x10