realmexe.S 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /*++
  2. Copyright (c) 2012 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. realmexe.S
  9. Abstract:
  10. This module implements the real and protected mode code necessary to call
  11. BIOS services.
  12. Author:
  13. Evan Green 18-Jul-2012
  14. Environment:
  15. Boot
  16. --*/
  17. ##
  18. ## ------------------------------------------------------------------ Includes
  19. ##
  20. #include <minoca/kernel/x86.inc>
  21. ##
  22. ## --------------------------------------------------------------- Definitions
  23. ##
  24. ##
  25. ## BIOS_CALL_CONTEXT structure definition.
  26. ##
  27. .equ CODEPAGE, 0x00
  28. .equ DATAPAGE, 0x04
  29. .equ STACKPAGE, 0x08
  30. .equ EAX, 0x0C
  31. .equ EBX, 0x10
  32. .equ ECX, 0x14
  33. .equ EDX, 0x18
  34. .equ ESI, 0x1C
  35. .equ EDI, 0x20
  36. .equ ESP, 0x24
  37. .equ EBP, 0x28
  38. .equ EIP, 0x2C
  39. .equ EFLAGS, 0x30
  40. .equ CS, 0x34
  41. .equ DS, 0x38
  42. .equ ES, 0x3C
  43. .equ FS, 0x40
  44. .equ GS, 0x44
  45. .equ SS, 0x48
  46. ##
  47. ## ----------------------------------------------------------------------- Code
  48. ##
  49. ##
  50. ## .text specifies that this code belongs in the executable section.
  51. ##
  52. ## .code32 specifies that this is 32-bit protected mode code.
  53. ##
  54. .text
  55. .code32
  56. ##
  57. ## .globl allows this label to be visible to the linker.
  58. ##
  59. .globl EfiBiosCallTemplate
  60. .globl EfiBiosCallTemplateLongJump
  61. .globl EfiBiosCallTemplateLongJump2
  62. .globl EfiBiosCallTemplateLongJump3
  63. .globl EfiBiosCallTemplateIntInstruction
  64. .globl EfiBiosCallTemplateEnd
  65. .globl EfipExecuteBiosCall
  66. ##
  67. ## This code represents the real-mode code run to call BIOS code. It is 16-bit
  68. ## real-mode code. SI contains a pointer to the context structure.
  69. ##
  70. FUNCTION(EfiBiosCallTemplate)
  71. ##
  72. ## Save the GDT, IDT, and CR0.
  73. ##
  74. subl $0x8, %esp
  75. sgdt (%esp)
  76. subl $0x8, %esp
  77. sidt (%esp)
  78. movl %cr0, %ecx
  79. push %ecx
  80. andl $0xFFFFFFFE, %ecx
  81. pushl %esi
  82. ##
  83. ## Push the registers from the context onto the stack.
  84. ##
  85. movl EFLAGS(%esi), %eax
  86. pushl %eax
  87. movl EAX(%esi), %eax
  88. pushl %eax
  89. movl ECX(%esi), %eax
  90. pushl %eax
  91. movl EDX(%esi), %eax
  92. pushl %eax
  93. movl EBX(%esi), %eax
  94. pushl %eax
  95. movl EDI(%esi), %eax
  96. pushl %eax
  97. movl ESI(%esi), %eax
  98. pushl %eax
  99. movl DS(%esi), %eax
  100. pushl %eax
  101. movl ES(%esi), %eax
  102. pushl %eax
  103. movl FS(%esi), %eax
  104. pushl %eax
  105. movl GS(%esi), %eax
  106. pushl %eax
  107. ##
  108. ## Load 16-bit protected mode GDT and IDT registers.
  109. ##
  110. lgdt Efi16BitGdt
  111. lidt Efi16BitIdt
  112. ##
  113. ## Jump to consummate the transition to 16-bit protected mode.
  114. ##
  115. EfiBiosCallTemplateLongJump:
  116. ljmp $KERNEL_CS, $0x3456
  117. ##
  118. ## This is now 16-bit protected mode code (a weird combination). Remove the
  119. ## protected mode bit to get to real mode.
  120. ##
  121. .code16
  122. movl %ecx, %cr0
  123. ##
  124. ## Perform a long jump to get back to 16 bit real mode. This assumes that
  125. ## the code is located below 64k. The actual constants will be patched up,
  126. ## this constant is a dummy.
  127. ##
  128. EfiBiosCallTemplateLongJump2:
  129. ljmp $0x12, $0x3456
  130. ##
  131. ## Reset the stack segment, and pop the registers into place.
  132. ##
  133. xorw %ax, %ax
  134. movw %ax, %ss
  135. popl %eax
  136. movw %ax, %gs
  137. popl %eax
  138. movw %ax, %fs
  139. popl %eax
  140. movw %ax, %es
  141. popl %eax
  142. movw %ax, %ds
  143. popl %esi
  144. popl %edi
  145. popl %ebx
  146. popl %edx
  147. popl %ecx
  148. popl %eax
  149. popfl
  150. ##
  151. ## Blast off. This 0x1B is a dummy value, the setup code will have
  152. ## modified that to be the correct vector.
  153. ##
  154. EfiBiosCallTemplateIntInstruction:
  155. int $0x1B
  156. ##
  157. ## Push the registers onto the stack. This is still 16 bit code.
  158. ##
  159. pushfl
  160. cli
  161. pushl %esi
  162. pushl %edi
  163. pushl %ebx
  164. pushl %edx
  165. pushl %ecx
  166. pushl %eax
  167. xorl %eax, %eax
  168. movw %gs, %ax
  169. pushl %eax
  170. movw %fs, %ax
  171. pushl %eax
  172. movw %es, %ax
  173. pushl %eax
  174. movw %ds, %ax
  175. pushl %eax
  176. ##
  177. ## Restore back to 32-bit protected mode by loading up the GDT and IDT,
  178. ## then applying the original CR0.
  179. ##
  180. xorw %ax, %ax
  181. movw %ax, %ds
  182. leal 0x34(%esp), %eax
  183. lidt (%eax)
  184. addl $0x8, %eax
  185. lgdt (%eax)
  186. movl 0x30(%esp), %eax
  187. ##
  188. ## Restore protected mode, and perform a long jump to make it apply.
  189. ##
  190. movl %eax, %cr0
  191. EfiBiosCallTemplateLongJump3:
  192. ljmp $KERNEL_CS, $0x3456
  193. .code32
  194. ##
  195. ## Restore the protected mode segment registers.
  196. ##
  197. movw $KERNEL_DS, %dx
  198. movw %dx, %ds
  199. movw %dx, %es
  200. movw %dx, %fs
  201. movw %dx, %gs
  202. movw %dx, %ss
  203. ##
  204. ## Safely back in 32-bit land, get the address of the context structure,
  205. ## and save the registers saved onto the stack into the context structure.
  206. ##
  207. movl 0x2C(%esp), %esi
  208. popl %eax
  209. movl %eax, DS(%esi)
  210. popl %eax
  211. movl %eax, ES(%esi)
  212. popl %eax
  213. movl %eax, FS(%esi)
  214. popl %eax
  215. movl %eax, GS(%esi)
  216. popl %eax
  217. movl %eax, EAX(%esi)
  218. popl %eax
  219. movl %eax, ECX(%esi)
  220. popl %eax
  221. movl %eax, EDX(%esi)
  222. popl %eax
  223. movl %eax, EBX(%esi)
  224. popl %eax
  225. movl %eax, EDI(%esi)
  226. popl %eax
  227. movl %eax, ESI(%esi)
  228. popl %eax
  229. movl %eax, EFLAGS(%esi)
  230. addl $0x18, %esp
  231. movl $EfipExecuteBiosCallRestore, %eax
  232. jmp *%eax
  233. ##
  234. ## That was the end of the code. Now define a 16-bit protected mode GDT.
  235. ## The GDT must be aligned to 8 bytes.
  236. ##
  237. .align 8
  238. Efi16BitGdt:
  239. .word (3 * 8) - 1 # GDT table limit
  240. .long Efi16BitGdtTable # GDT table location
  241. Efi16BitGdtTable:
  242. .long 0x0 # The first GDT entry is called the
  243. .long 0x0 # null descriptor, it is essentially
  244. # unused by the processor.
  245. ##
  246. ## Define the code segment descriptor.
  247. ##
  248. .word 0xFFFF # Limit 15:0
  249. .word 0x0 # Base 15:0
  250. .byte 0x0 # Base 23:16
  251. .byte 0x9A # Access: Present, Ring 0, Code Segment
  252. .byte 0x8F # Granularity: 1Kb, 16-bit mode
  253. .byte 0x00 # Base 31:24
  254. ##
  255. ## Define the dat segment descriptor.
  256. ##
  257. .word 0xFFFF # Limit 15:0
  258. .word 0x0 # Base 15:0
  259. .byte 0x0 # Base 23:16
  260. .byte 0x92 # Access: Present, Ring 0, Data Segment
  261. .byte 0x8F # Granularity: 1kB, 16-bit mode
  262. .byte 0x00 # Base 31:24
  263. ##
  264. ## Also define a 16-bit protected mode IDT.
  265. ##
  266. Efi16BitIdt:
  267. .word 0x3FF # IDT Table Limit
  268. .long 0x0 # IDT Table base
  269. ##
  270. ## This label marks the end of the template code. It is useful for determining
  271. ## the size of the template code.
  272. ##
  273. EfiBiosCallTemplateEnd:
  274. nop
  275. END_FUNCTION(EfiBiosCallTemplate)
  276. ##
  277. ## This function is 32-bit protected mode code.
  278. ##
  279. .code32
  280. ##
  281. ## VOID
  282. ## EfipExecuteBiosCall (
  283. ## PBIOS_CALL_CONTEXT Context
  284. ## )
  285. ##
  286. /*++
  287. Routine Description:
  288. This routine executes 16-bit real mode code by switching the processor back
  289. to real mode.
  290. Arguments:
  291. Context - Supplies a pointer to the context structure that will be
  292. executed. On return, this will contain the executed context.
  293. Return Value:
  294. None.
  295. --*/
  296. FUNCTION(EfipExecuteBiosCall)
  297. push %ebp
  298. movl %esp, %ebp
  299. ##
  300. ## Save the non-volatile registers and flags.
  301. ##
  302. push %ebx
  303. push %esi
  304. push %edi
  305. push %ebp
  306. pushfl
  307. cli
  308. ##
  309. ## Load the context parameter into ESI, get EIP, and jump to it.
  310. ##
  311. movl 8(%ebp), %esi
  312. movl CS(%esi), %eax
  313. shll $4, %eax
  314. movl EIP(%esi), %edx
  315. add %edx, %eax
  316. jmp *%eax
  317. ##
  318. ## This code is jumped to by the end of the BIOS call template.
  319. ##
  320. EfipExecuteBiosCallRestore:
  321. ##
  322. ## Restore the non-volatile registers and flags.
  323. ##
  324. popfl
  325. popl %ebp
  326. popl %edi
  327. popl %esi
  328. popl %ebx
  329. leave
  330. ret
  331. END_FUNCTION(EfipExecuteBiosCall)