realmode.S 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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/i386/pc/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. GRUB_EXPORT_START
  43. GRUB_EXPORT(grub_reboot)
  44. GRUB_EXPORT_END
  45. .p2align 2 /* force 4-byte alignment */
  46. protstack:
  47. .long GRUB_MEMORY_MACHINE_PROT_STACK
  48. /*
  49. * This is the Global Descriptor Table
  50. *
  51. * An entry, a "Segment Descriptor", looks like this:
  52. *
  53. * 31 24 19 16 7 0
  54. * ------------------------------------------------------------
  55. * | | |B| |A| | | |1|0|E|W|A| |
  56. * | BASE 31..24 |G|/|L|V| LIMIT |P|DPL| TYPE | BASE 23:16 | 4
  57. * | | |D| |L| 19..16| | |1|1|C|R|A| |
  58. * ------------------------------------------------------------
  59. * | | |
  60. * | BASE 15..0 | LIMIT 15..0 | 0
  61. * | | |
  62. * ------------------------------------------------------------
  63. *
  64. * Note the ordering of the data items is reversed from the above
  65. * description.
  66. */
  67. .p2align 2 /* force 4-byte alignment */
  68. gdt:
  69. .word 0, 0
  70. .byte 0, 0, 0, 0
  71. /* -- code segment --
  72. * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present
  73. * type = 32bit code execute/read, DPL = 0
  74. */
  75. .word 0xFFFF, 0
  76. .byte 0, 0x9A, 0xCF, 0
  77. /* -- data segment --
  78. * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present
  79. * type = 32 bit data read/write, DPL = 0
  80. */
  81. .word 0xFFFF, 0
  82. .byte 0, 0x92, 0xCF, 0
  83. /* -- 16 bit real mode CS --
  84. * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present
  85. * type = 16 bit code execute/read only/conforming, DPL = 0
  86. */
  87. .word 0xFFFF, 0
  88. .byte 0, 0x9E, 0, 0
  89. /* -- 16 bit real mode DS --
  90. * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present
  91. * type = 16 bit data read/write, DPL = 0
  92. */
  93. .word 0xFFFF, 0
  94. .byte 0, 0x92, 0, 0
  95. /* this is the GDT descriptor */
  96. gdtdesc:
  97. .word 0x27 /* limit */
  98. .long gdt /* addr */
  99. /*
  100. * These next two routines, "real_to_prot" and "prot_to_real" are structured
  101. * in a very specific way. Be very careful when changing them.
  102. *
  103. * NOTE: Use of either one messes up %eax and %ebp.
  104. */
  105. real_to_prot:
  106. .code16
  107. cli
  108. /* load the GDT register */
  109. xorw %ax, %ax
  110. movw %ax, %ds
  111. /* DATA32 ADDR32 lgdt gdtdesc */
  112. .byte 0x67, 0x66, 0xf, 0x1, 0x15
  113. .long gdtdesc
  114. /* turn on protected mode */
  115. movl %cr0, %eax
  116. orl $GRUB_MEMORY_CPU_CR0_PE_ON, %eax
  117. movl %eax, %cr0
  118. /* jump to relocation, flush prefetch queue, and reload %cs */
  119. /* DATA32 ljmp $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $protcseg */
  120. .byte 0x66, 0xea
  121. .long protcseg
  122. .short GRUB_MEMORY_MACHINE_PROT_MODE_CSEG
  123. .code32
  124. protcseg:
  125. /* reload other segment registers */
  126. movw $GRUB_MEMORY_MACHINE_PROT_MODE_DSEG, %ax
  127. movw %ax, %ds
  128. movw %ax, %es
  129. movw %ax, %fs
  130. movw %ax, %gs
  131. movw %ax, %ss
  132. /* put the return address in a known safe location */
  133. movl (%esp), %eax
  134. movl %eax, GRUB_MEMORY_MACHINE_REAL_STACK
  135. /* get protected mode stack */
  136. movl protstack, %eax
  137. movl %eax, %esp
  138. movl %eax, %ebp
  139. /* get return address onto the right stack */
  140. movl GRUB_MEMORY_MACHINE_REAL_STACK, %eax
  141. movl %eax, (%esp)
  142. /* zero %eax */
  143. xorl %eax, %eax
  144. /* return on the old (or initialized) stack! */
  145. ret
  146. prot_to_real:
  147. /* just in case, set GDT */
  148. lgdt gdtdesc
  149. /* save the protected mode stack */
  150. movl %esp, %eax
  151. movl %eax, protstack
  152. /* get the return address */
  153. movl (%esp), %eax
  154. movl %eax, GRUB_MEMORY_MACHINE_REAL_STACK
  155. /* set up new stack */
  156. movl $GRUB_MEMORY_MACHINE_REAL_STACK, %eax
  157. movl %eax, %esp
  158. movl %eax, %ebp
  159. /* set up segment limits */
  160. movw $GRUB_MEMORY_MACHINE_PSEUDO_REAL_DSEG, %ax
  161. movw %ax, %ds
  162. movw %ax, %es
  163. movw %ax, %fs
  164. movw %ax, %gs
  165. movw %ax, %ss
  166. /* this might be an extra step */
  167. /* jump to a 16 bit segment */
  168. ljmp $GRUB_MEMORY_MACHINE_PSEUDO_REAL_CSEG, $tmpcseg
  169. tmpcseg:
  170. .code16
  171. /* clear the PE bit of CR0 */
  172. movl %cr0, %eax
  173. andl $(~GRUB_MEMORY_CPU_CR0_PE_ON), %eax
  174. movl %eax, %cr0
  175. /* flush prefetch queue, reload %cs */
  176. /* DATA32 ljmp $0, $realcseg */
  177. .byte 0x66, 0xea
  178. .long realcseg
  179. .short 0
  180. realcseg:
  181. /* we are in real mode now
  182. * set up the real mode segment registers : DS, SS, ES
  183. */
  184. /* zero %eax */
  185. xorl %eax, %eax
  186. movw %ax, %ds
  187. movw %ax, %es
  188. movw %ax, %fs
  189. movw %ax, %gs
  190. movw %ax, %ss
  191. #ifdef GRUB_MACHINE_PCBIOS
  192. /* restore interrupts */
  193. sti
  194. #endif
  195. /* return on new stack! */
  196. /* DATA32 ret */
  197. .byte 0x66, 0xc3
  198. .code32
  199. /*
  200. * grub_reboot()
  201. *
  202. * Reboot the system. At the moment, rely on BIOS.
  203. */
  204. FUNCTION(grub_reboot)
  205. call prot_to_real
  206. .code16
  207. cold_reboot:
  208. /* set 0x472 to 0x0000 for cold boot (0x1234 for warm boot) */
  209. movw $0x0472, %di
  210. movw %ax, (%di)
  211. ljmp $0xf000, $0xfff0
  212. .code32