archsupc.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*++
  2. Copyright (c) 2014 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. archsupc.c
  9. Abstract:
  10. This module implements x86 processor architecture features.
  11. Author:
  12. Evan Green 18-Jul-2014
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/kernel.h>
  20. #include <minoca/kernel/x86.h>
  21. //
  22. // ---------------------------------------------------------------- Definitions
  23. //
  24. //
  25. // ------------------------------------------------------ Data Type Definitions
  26. //
  27. //
  28. // ----------------------------------------------- Internal Function Prototypes
  29. //
  30. //
  31. // -------------------------------------------------------------------- Globals
  32. //
  33. //
  34. // ------------------------------------------------------------------ Functions
  35. //
  36. VOID
  37. ArSetUpUserSharedDataFeatures (
  38. VOID
  39. )
  40. /*++
  41. Routine Description:
  42. This routine initialize the user shared data processor specific features.
  43. Arguments:
  44. None.
  45. Return Value:
  46. None.
  47. --*/
  48. {
  49. PUSER_SHARED_DATA Data;
  50. ULONG Eax;
  51. ULONG Ebx;
  52. ULONG Ecx;
  53. ULONG Edx;
  54. PPROCESSOR_BLOCK ProcessorBlock;
  55. PTSS Tss;
  56. Data = MmGetUserSharedData();
  57. Eax = X86_CPUID_IDENTIFICATION;
  58. ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
  59. if (Eax < X86_CPUID_BASIC_INFORMATION) {
  60. return;
  61. }
  62. Eax = X86_CPUID_BASIC_INFORMATION;
  63. ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
  64. //
  65. // Check for CMOV instructions, which is an indication of Pentium Pro
  66. // (i686) vs Pentium (i586). One might imagine that a modern OS such as
  67. // this one might not need to trifle with processor architectures before
  68. // 1995. One might be wrong. The Intel Quark for instance uses the Pentium
  69. // instruction set.
  70. //
  71. if ((Edx & X86_CPUID_BASIC_EDX_CMOV) != 0) {
  72. Data->ProcessorFeatures |= X86_FEATURE_I686;
  73. }
  74. //
  75. // In 32-bit mode, shoot for sysenter, and then syscall. (Note that in
  76. // long mode, syscall is just assumed to be present architecturally).
  77. //
  78. if ((Edx & X86_CPUID_BASIC_EDX_SYSENTER) != 0) {
  79. //
  80. // Set up SYSENTER support. Sysenter shares the double fault stack,
  81. // which happens to be right below the main TSS.
  82. // Normally sysenter doesn't need a stack, as the first thing the
  83. // handler does with interrupts disabled is to load Tss->Esp0. The one
  84. // exception is if usermode sets the trap flag when calling sysenter,
  85. // in which case a single step exception occurs in kernel mode with
  86. // whatever stack is set in the MSR. Sharing with the double fault
  87. // stack means that if a double fault occurs in the single step
  88. // handler, the developer trying to debug what's going on will be
  89. // presented with a confused stack (though EIP and the registers will
  90. // still be correct). Double faults are fatal anyway, so the corruption
  91. // of its stack isn't really any more fatal.
  92. //
  93. ProcessorBlock = KeGetCurrentProcessorBlock();
  94. Tss = ProcessorBlock->Tss;
  95. Data->ProcessorFeatures |= X86_FEATURE_SYSENTER;
  96. ArWriteMsr(X86_MSR_SYSENTER_CS, KERNEL_CS);
  97. ArWriteMsr(X86_MSR_SYSENTER_EIP, (UINTN)ArSysenterHandlerAsm);
  98. ArWriteMsr(X86_MSR_SYSENTER_ESP, (UINTN)Tss);
  99. } else {
  100. ASSERT((Data->ProcessorFeatures & X86_FEATURE_SYSENTER) == 0);
  101. Eax = X86_CPUID_EXTENDED_IDENTIFICATION;
  102. ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
  103. if (Eax < X86_CPUID_EXTENDED_INFORMATION) {
  104. return;
  105. }
  106. Eax = X86_CPUID_EXTENDED_INFORMATION;
  107. ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
  108. if ((Edx & X86_CPUID_EXTENDED_INFORMATION_EDX_SYSCALL) != 0) {
  109. //
  110. // Set up SYSCALL support.
  111. //
  112. RtlDebugPrint("Syscall but no sysenter!\n");
  113. Data->ProcessorFeatures |= X86_FEATURE_SYSCALL;
  114. }
  115. }
  116. //
  117. // Remember if the processor supports the fxsave instruction.
  118. //
  119. if ((Edx & X86_CPUID_BASIC_EDX_FX_SAVE_RESTORE) != 0) {
  120. Data->ProcessorFeatures |= X86_FEATURE_FXSAVE;
  121. }
  122. return;
  123. }
  124. PFPU_CONTEXT
  125. ArAllocateFpuContext (
  126. ULONG AllocationTag
  127. )
  128. /*++
  129. Routine Description:
  130. This routine allocates a buffer that can be used for FPU context.
  131. Arguments:
  132. AllocationTag - Supplies the pool allocation tag to use for the allocation.
  133. Return Value:
  134. Returns a pointer to the newly allocated FPU context on success.
  135. NULL on allocation failure.
  136. --*/
  137. {
  138. UINTN AllocationSize;
  139. PFPU_CONTEXT Context;
  140. AllocationSize = sizeof(FPU_CONTEXT) + FPU_CONTEXT_ALIGNMENT;
  141. Context = MmAllocateNonPagedPool(AllocationSize, AllocationTag);
  142. if (Context == NULL) {
  143. return NULL;
  144. }
  145. //
  146. // Zero out the buffer to avoid leaking kernel pool to user mode.
  147. //
  148. RtlZeroMemory(Context, AllocationSize);
  149. return Context;
  150. }
  151. VOID
  152. ArDestroyFpuContext (
  153. PFPU_CONTEXT Context
  154. )
  155. /*++
  156. Routine Description:
  157. This routine destroys a previously allocated FPU context buffer.
  158. Arguments:
  159. Context - Supplies a pointer to the context to destroy.
  160. Return Value:
  161. None.
  162. --*/
  163. {
  164. MmFreeNonPagedPool(Context);
  165. return;
  166. }
  167. VOID
  168. ArSetThreadPointer (
  169. PVOID Thread,
  170. PVOID NewThreadPointer
  171. )
  172. /*++
  173. Routine Description:
  174. This routine sets the new thread pointer value.
  175. Arguments:
  176. Thread - Supplies a pointer to the thread to set the thread pointer for.
  177. NewThreadPointer - Supplies the new thread pointer value to set.
  178. Return Value:
  179. None.
  180. --*/
  181. {
  182. PGDT_ENTRY Gdt;
  183. PGDT_ENTRY GdtEntry;
  184. RUNLEVEL OldRunLevel;
  185. PPROCESSOR_BLOCK Processor;
  186. PKTHREAD TypedThread;
  187. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  188. TypedThread = Thread;
  189. GdtEntry = (PGDT_ENTRY)&(TypedThread->ThreadPointer);
  190. ASSERT(sizeof(GDT_ENTRY) <= sizeof(TypedThread->ThreadPointer));
  191. ArpCreateSegmentDescriptor(GdtEntry,
  192. NewThreadPointer,
  193. MAX_GDT_LIMIT,
  194. GDT_GRANULARITY_KILOBYTE | GDT_GRANULARITY_32BIT,
  195. GATE_ACCESS_USER | GDT_TYPE_DATA_WRITE);
  196. if (Thread == KeGetCurrentThread()) {
  197. Processor = KeGetCurrentProcessorBlock();
  198. Gdt = Processor->Gdt;
  199. RtlCopyMemory(&(Gdt[GDT_THREAD / sizeof(GDT_ENTRY)]),
  200. GdtEntry,
  201. sizeof(GDT_ENTRY));
  202. ArReloadThreadSegment();
  203. }
  204. KeLowerRunLevel(OldRunLevel);
  205. return;
  206. }
  207. //
  208. // --------------------------------------------------------- Internal Functions
  209. //