Leaked source code of windows server 2003
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.

315 lines
6.3 KiB

  1. ;++
  2. ;
  3. ;Copyright (c) 2000 Microsoft Corporation
  4. ;
  5. ;Module Name:
  6. ;
  7. ; amd64s.asm
  8. ;
  9. ;Abstract:
  10. ;
  11. ; Contains routines to aid in detecting and enabling Amd64 long mode.
  12. ;
  13. ;Author:
  14. ;
  15. ; Forrest Foltz (forrestf) 04-20-00
  16. ;
  17. ;
  18. ;Revision History:
  19. ;
  20. ;--
  21. .586p
  22. .xlist
  23. include ks386.inc
  24. .list
  25. extrn _BlAmd64GdtDescriptor:QWORD
  26. extrn _BlAmd64IdtDescriptor:QWORD
  27. extrn _BlAmd64IdleStack64:QWORD
  28. extrn _BlAmd64TopLevelPte:QWORD
  29. extrn _BlAmd64KernelEntry:QWORD
  30. extrn _BlAmd64LoaderParameterBlock:QWORD
  31. extrn _BlAmd64_MSR_EFER:DWORD
  32. extrn _BlAmd64_MSR_EFER_Flags:DWORD
  33. extrn _BlAmd64_MSR_GS_BASE:DWORD
  34. extrn _BlAmd64_KGDT64_SYS_TSS:WORD
  35. extrn _BlAmd32GdtDescriptor:QWORD
  36. extrn _HiberInProgress:DWORD
  37. OP64 macro
  38. db 048h
  39. endm
  40. ICEBP macro
  41. db 0f1h
  42. endm
  43. ;
  44. ; LOADREG loads the 64-bit contents of a memory location specified by
  45. ; a 32-bit immediate address.
  46. ;
  47. ; The resultant 64-bit address is zero-extended, as a result this macro
  48. ; only works with addresses < 2^32.
  49. ;
  50. ; This macro also assumes that esi is zero.
  51. ;
  52. LDREG64 macro reg, address
  53. OP64
  54. mov reg, ds:[esi + offset address]
  55. endm
  56. _TEXT SEGMENT PARA PUBLIC 'CODE'
  57. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  58. EFLAGS_ID equ 200000h
  59. ;++
  60. ;
  61. ; BOOLEAN
  62. ; BlIsAmd64Supported (
  63. ; VOID
  64. ; )
  65. ;
  66. ; Routine Description:
  67. ;
  68. ; This rouine determines whether the current processor supports AMD64
  69. ; mode, a.k.a. "long mode".
  70. ;
  71. ; Arguments:
  72. ;
  73. ; None.
  74. ;
  75. ; Return value:
  76. ;
  77. ; 0 if long mode is not supported, non-zero otherwise.
  78. ;
  79. ;--
  80. public _BlIsAmd64Supported@0
  81. _BlIsAmd64Supported@0 proc
  82. ;
  83. ; First determine whether the CPUID instruction is supported. If
  84. ; the EFLAGS_ID bit "sticks" when popped into the flags
  85. ; register then the CPUID instruction is available.
  86. ;
  87. mov ecx, EFLAGS_ID
  88. pushfd
  89. pop eax ; eax == flags
  90. xor ecx, eax ; ecx == flags ^ EFLAGS_ID
  91. push ecx
  92. popfd ; load new flags
  93. pushfd
  94. pop ecx ; ecx == result of flag load
  95. xor eax, ecx ; Q: did the EFLAGS_ID bit stick?
  96. jz done ; N: CPUID is not available
  97. ;
  98. ; We can use the CPUID instruction. Detect whether this is an
  99. ; AMD processor and if so whether long mode is supported.
  100. ;
  101. push ebx ; CPUID steps on eax, ebx, ecx, edx
  102. xor eax, eax ; eax = 0
  103. cpuid
  104. xor eax, eax ; Assume no long mode
  105. cmp ebx, 'htuA' ; Q: ebx == 'Auth' ?
  106. jne nolong ; N: no long mode
  107. ;
  108. ; We have an AMD processor, now determine whether long mode is
  109. ; available.
  110. ;
  111. mov eax, 80000001h
  112. xor edx, edx
  113. cpuid
  114. bt edx, 29 ; Q: Bit 29 is long mode bit, is it set?
  115. sbb eax, eax ; Yes (eax != 0) if carry set, else eax == 0
  116. nolong: pop ebx
  117. done: ret
  118. _BlIsAmd64Supported@0 endp
  119. ;++
  120. ;
  121. ; VOID
  122. ; BlAmd64SwitchToLongMode (
  123. ; VOID
  124. ; )
  125. ;
  126. ; Routine Description:
  127. ;
  128. ; Arguments:
  129. ;
  130. ; None.
  131. ;
  132. ; Return value:
  133. ;
  134. ; None.
  135. ;
  136. ;--
  137. public _BlAmd64SwitchToLongMode@0
  138. _BlAmd64SwitchToLongMode@0 proc
  139. public _BlAmd64SwitchToLongModeStart
  140. _BlAmd64SwitchToLongModeStart label dword
  141. ;
  142. ; Save the value of _HiberInProgress before disabling paging
  143. ;
  144. mov ebx, dword ptr [_HiberInProgress]
  145. cli
  146. ;
  147. ; Disable paging
  148. ;
  149. mov eax, cr0
  150. and eax, NOT CR0_PG
  151. mov cr0, eax
  152. jmp $+2
  153. ;
  154. ; Enable XMM and physical address extensions (paging still off)
  155. ;
  156. mov eax, cr4
  157. or eax, CR4_PAE OR CR4_FXSR OR CR4_XMMEXCPT OR CR4_PGE
  158. mov cr4, eax
  159. ;
  160. ; Reference the four-level paging structure. This must exist
  161. ; below 4G physical (in fact it is somewhere in the low 32MB)
  162. ;
  163. mov eax, DWORD PTR [_BlAmd64TopLevelPte]
  164. and eax, 0FFFFF000h
  165. mov cr3, eax
  166. ;
  167. ; Set Long Mode enable and enable syscall
  168. ;
  169. mov ecx, [_BlAmd64_MSR_EFER]
  170. rdmsr
  171. or eax, [_BlAmd64_MSR_EFER_Flags]
  172. wrmsr
  173. ;
  174. ; Turn paging on. Also turn on the write protect and alignment mask
  175. ; bits
  176. ;
  177. mov eax, cr0
  178. or eax, CR0_PG OR CR0_WP OR CR0_AM OR CR0_NE
  179. mov cr0, eax
  180. jmp $+2
  181. ;
  182. ; Return if we are waking up from hibernate.
  183. ;
  184. cmp ebx, 1
  185. jnz @f
  186. ret
  187. ;
  188. ; Load the new global descriptor table. Note that because we're
  189. ; not in long mode (current code selector indicates compatibility
  190. ; mode), only a 32-bit base is loaded here.
  191. ;
  192. @@: lgdt fword ptr _BlAmd32GdtDescriptor
  193. ;
  194. ; Far jump to the 64-bit code segment.
  195. ;
  196. db 0eah
  197. dd start64
  198. ;
  199. ; The following selector is set in amd64.c, BlAmd64BuildAmd64GDT, and
  200. ; is included as part of the far jump instruction.
  201. ;
  202. public _BlAmd64_KGDT64_R0_CODE
  203. _BlAmd64_KGDT64_R0_CODE:
  204. dw ?
  205. start64:
  206. ;
  207. ; Zero rsi so that the LDREG64 macros work
  208. ;
  209. sub esi, esi ; zero rsi (zeroed esi is sign extended)
  210. ;
  211. ; Running in long mode now. Execute another lgdt, this one
  212. ; referencing the 64-bit mapping of the gdt.
  213. ;
  214. ; Note that an esi-relative address is used to avoid RIP-relative
  215. ; addressing.
  216. ;
  217. ; Keep in mind that a 32-bit assembler is used here to generate
  218. ; long-mode code.
  219. ;
  220. lgdt fword ptr ds:[esi + offset _BlAmd64GdtDescriptor]
  221. ;
  222. ; Load the new interrupt descriptor table
  223. ;
  224. lidt fword ptr ds:[esi + offset _BlAmd64IdtDescriptor]
  225. ;
  226. ; Switch stacks to the 64-bit idle stack
  227. ;
  228. LDREG64 esp, _BlAmd64IdleStack64
  229. ;
  230. ; Set the current TSS
  231. ;
  232. LDREG64 eax, _BlAmd64_KGDT64_SYS_TSS
  233. ltr ax
  234. ;
  235. ; Set ss to the kernel-mode SS value (0)
  236. ;
  237. sub eax, eax ; zero rax
  238. mov ss, ax
  239. ;
  240. ; Allocate space on the stack for a parameter target area and jump
  241. ; to the kernel entrypoint. Rather than a call, we push a return
  242. ; address of zero to indicate to any stack walkers that this is the
  243. ; end.
  244. ;
  245. push eax ; push null return address
  246. LDREG64 ecx, _BlAmd64LoaderParameterBlock
  247. LDREG64 eax, _BlAmd64KernelEntry
  248. jmp eax ; jmp rax
  249. public _BlAmd64SwitchToLongModeEnd
  250. _BlAmd64SwitchToLongModeEnd label dword
  251. _BlAmd64SwitchToLongMode@0 endp
  252. _TEXT ends