realmode.S 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2009,2010 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/machine/memory.h>
  19. /*
  20. * Note: These functions defined in this file may be called from C.
  21. * Be careful of that you must not modify some registers. Quote
  22. * from gcc-2.95.2/gcc/config/i386/i386.h:
  23. 1 for registers not available across function calls.
  24. These must include the FIXED_REGISTERS and also any
  25. registers that can be used without being saved.
  26. The latter must include the registers where values are returned
  27. and the register where structure-value addresses are passed.
  28. Aside from that, you can include as many other registers as you like.
  29. ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
  30. { 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
  31. */
  32. /*
  33. * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
  34. * So the first three arguments are passed in %eax, %edx, and %ecx,
  35. * respectively, and if a function has a fixed number of arguments
  36. * and the number if greater than three, the function must return
  37. * with "ret $N" where N is ((the number of arguments) - 3) * 4.
  38. */
  39. /*
  40. * This is the area for all of the special variables.
  41. */
  42. protstack:
  43. .long GRUB_MEMORY_MACHINE_PROT_STACK
  44. .macro PROT_TO_REAL
  45. call prot_to_real
  46. .endm
  47. .macro REAL_TO_PROT
  48. calll real_to_prot
  49. .endm
  50. /*
  51. * This is the Global Descriptor Table
  52. *
  53. * An entry, a "Segment Descriptor", looks like this:
  54. *
  55. * 31 24 19 16 7 0
  56. * ------------------------------------------------------------
  57. * | | |B| |A| | | |1|0|E|W|A| |
  58. * | BASE 31..24 |G|/|L|V| LIMIT |P|DPL| TYPE | BASE 23:16 | 4
  59. * | | |D| |L| 19..16| | |1|1|C|R|A| |
  60. * ------------------------------------------------------------
  61. * | | |
  62. * | BASE 15..0 | LIMIT 15..0 | 0
  63. * | | |
  64. * ------------------------------------------------------------
  65. *
  66. * Note the ordering of the data items is reversed from the above
  67. * description.
  68. */
  69. .p2align 5 /* force 32-byte alignment */
  70. gdt:
  71. .word 0, 0
  72. .byte 0, 0, 0, 0
  73. /* -- code segment --
  74. * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present
  75. * type = 32bit code execute/read, DPL = 0
  76. */
  77. .word 0xFFFF, 0
  78. .byte 0, 0x9A, 0xCF, 0
  79. /* -- data segment --
  80. * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present
  81. * type = 32 bit data read/write, DPL = 0
  82. */
  83. .word 0xFFFF, 0
  84. .byte 0, 0x92, 0xCF, 0
  85. /* -- 16 bit real mode CS --
  86. * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present
  87. * type = 16 bit code execute/read only/conforming, DPL = 0
  88. */
  89. .word 0xFFFF, 0
  90. .byte 0, 0x9E, 0, 0
  91. /* -- 16 bit real mode DS --
  92. * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present
  93. * type = 16 bit data read/write, DPL = 0
  94. */
  95. .word 0xFFFF, 0
  96. .byte 0, 0x92, 0, 0
  97. .p2align 5
  98. /* this is the GDT descriptor */
  99. gdtdesc:
  100. .word 0x27 /* limit */
  101. .long gdt /* addr */
  102. LOCAL(realidt):
  103. .word 0x400
  104. .long 0
  105. protidt:
  106. .word 0
  107. .long 0
  108. /*
  109. * These next two routines, "real_to_prot" and "prot_to_real" are structured
  110. * in a very specific way. Be very careful when changing them.
  111. *
  112. * NOTE: Use of either one messes up %eax and %ebp.
  113. */
  114. real_to_prot:
  115. .code16
  116. cli
  117. /* load the GDT register */
  118. xorw %ax, %ax
  119. movw %ax, %ds
  120. #ifdef GRUB_MACHINE_QEMU
  121. /*
  122. qemu is special: gdtdesc is in ROM.
  123. %cs = 0xf000
  124. _start + GRUB_BOOT_MACHINE_SIZE = 0x100000
  125. So
  126. _start + GRUB_BOOT_MACHINE_SIZE - 0x10000 points to the same point
  127. as %cs.
  128. gdtdesc - (_start + GRUB_BOOT_MACHINE_SIZE - 0x10000)
  129. = gdtdesc - _start - GRUB_BOOT_MACHINE_SIZE + 0x10000
  130. but the later can be computed by assembly.
  131. */
  132. lgdtl %cs:(gdtdesc - _start - GRUB_BOOT_MACHINE_SIZE + 0x10000)
  133. #else
  134. lgdtl gdtdesc
  135. #endif
  136. /* turn on protected mode */
  137. movl %cr0, %eax
  138. orl $GRUB_MEMORY_CPU_CR0_PE_ON, %eax
  139. movl %eax, %cr0
  140. /* jump to relocation, flush prefetch queue, and reload %cs */
  141. ljmpl $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $protcseg
  142. .code32
  143. protcseg:
  144. /* reload other segment registers */
  145. movw $GRUB_MEMORY_MACHINE_PROT_MODE_DSEG, %ax
  146. movw %ax, %ds
  147. movw %ax, %es
  148. movw %ax, %fs
  149. movw %ax, %gs
  150. movw %ax, %ss
  151. /* put the return address in a known safe location */
  152. movl (%esp), %eax
  153. movl %eax, GRUB_MEMORY_MACHINE_REAL_STACK
  154. /* get protected mode stack */
  155. movl protstack, %eax
  156. movl %eax, %esp
  157. movl %eax, %ebp
  158. /* get return address onto the right stack */
  159. movl GRUB_MEMORY_MACHINE_REAL_STACK, %eax
  160. movl %eax, (%esp)
  161. /* zero %eax */
  162. xorl %eax, %eax
  163. sidt LOCAL(realidt)
  164. lidt protidt
  165. /* return on the old (or initialized) stack! */
  166. ret
  167. /* prot_to_real assumes that this code is under 64K which is not
  168. true for qemu. */
  169. #ifndef GRUB_MACHINE_QEMU
  170. /*
  171. * GRUB -- GRand Unified Bootloader
  172. * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2009,2010 Free Software Foundation, Inc.
  173. *
  174. * GRUB is free software: you can redistribute it and/or modify
  175. * it under the terms of the GNU General Public License as published by
  176. * the Free Software Foundation, either version 3 of the License, or
  177. * (at your option) any later version.
  178. *
  179. * GRUB is distributed in the hope that it will be useful,
  180. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  181. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  182. * GNU General Public License for more details.
  183. *
  184. * You should have received a copy of the GNU General Public License
  185. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  186. */
  187. prot_to_real:
  188. /* just in case, set GDT */
  189. lgdt gdtdesc
  190. sidt protidt
  191. lidt LOCAL(realidt)
  192. /* save the protected mode stack */
  193. movl %esp, %eax
  194. movl %eax, protstack
  195. /* get the return address */
  196. movl (%esp), %eax
  197. movl %eax, GRUB_MEMORY_MACHINE_REAL_STACK
  198. /* set up new stack */
  199. movl $GRUB_MEMORY_MACHINE_REAL_STACK, %eax
  200. movl %eax, %esp
  201. movl %eax, %ebp
  202. /* set up segment limits */
  203. movw $GRUB_MEMORY_MACHINE_PSEUDO_REAL_DSEG, %ax
  204. movw %ax, %ds
  205. movw %ax, %es
  206. movw %ax, %fs
  207. movw %ax, %gs
  208. movw %ax, %ss
  209. /* this might be an extra step */
  210. /* jump to a 16 bit segment */
  211. ljmp $GRUB_MEMORY_MACHINE_PSEUDO_REAL_CSEG, $tmpcseg
  212. tmpcseg:
  213. .code16
  214. /* clear the PE bit of CR0 */
  215. movl %cr0, %eax
  216. andl $(~GRUB_MEMORY_CPU_CR0_PE_ON), %eax
  217. movl %eax, %cr0
  218. /* flush prefetch queue, reload %cs */
  219. ljmpl $0, $realcseg
  220. realcseg:
  221. /* we are in real mode now
  222. * set up the real mode segment registers : DS, SS, ES
  223. */
  224. /* zero %eax */
  225. xorl %eax, %eax
  226. movw %ax, %ds
  227. movw %ax, %es
  228. movw %ax, %fs
  229. movw %ax, %gs
  230. movw %ax, %ss
  231. #ifdef GRUB_MACHINE_PCBIOS
  232. /* restore interrupts */
  233. sti
  234. #endif
  235. /* return on new stack! */
  236. retl
  237. #endif
  238. .code32