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.

382 lines
10 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. thredini.c
  5. Abstract:
  6. This module implements the machine dependent function to set the initial
  7. context and data alignment handling mode for a process or thread object.
  8. Author:
  9. David N. Cutler (davec) 4-May-2000
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. //
  16. // The following assert macros are used to check that an input object is
  17. // really the proper type.
  18. //
  19. #define ASSERT_PROCESS(E) { \
  20. ASSERT((E)->Header.Type == ProcessObject); \
  21. }
  22. #define ASSERT_THREAD(E) { \
  23. ASSERT((E)->Header.Type == ThreadObject); \
  24. }
  25. VOID
  26. KiInitializeContextThread (
  27. IN PKTHREAD Thread,
  28. IN PKSYSTEM_ROUTINE SystemRoutine,
  29. IN PKSTART_ROUTINE StartRoutine OPTIONAL,
  30. IN PVOID StartContext OPTIONAL,
  31. IN PCONTEXT ContextRecord OPTIONAL
  32. )
  33. /*++
  34. Routine Description:
  35. This function initializes the machine dependent context of a thread
  36. object.
  37. N.B. This function does not check if context record is accessibile.
  38. It is assumed the the caller of this routine is either prepared
  39. to handle access violations or has probed and copied the context
  40. record as appropriate.
  41. Arguments:
  42. Thread - Supplies a pointer to a dispatcher object of type thread.
  43. SystemRoutine - Supplies a pointer to the system function that is to be
  44. called when the thread is first scheduled for execution.
  45. StartRoutine - Supplies an optional pointer to a function that is to be
  46. called after the system has finished initializing the thread. This
  47. parameter is specified if the thread is a system thread and will
  48. execute totally in kernel mode.
  49. StartContext - Supplies an optional pointer to a data structure that
  50. will be passed to the StartRoutine as a parameter. This parameter
  51. is specified if the thread is a system thread and will execute
  52. totally in kernel mode.
  53. ContextRecord - Supplies an optional pointer a context record which
  54. contains the initial user mode state of the thread. This parameter
  55. is specified if the thread will execute in user mode.
  56. Return Value:
  57. None.
  58. --*/
  59. {
  60. CONTEXT ContextFrame;
  61. PKEXCEPTION_FRAME ExFrame;
  62. ULONG64 InitialStack;
  63. PLEGACY_SAVE_AREA NpxFrame;
  64. PKSTART_FRAME SfFrame;
  65. PKSWITCH_FRAME SwFrame;
  66. PKTRAP_FRAME TrFrame;
  67. //
  68. // Allocate a legacy floating point save area at the base of the thread
  69. // stack and record the initial stack as this address. All threads have
  70. // a legacy floating point save are to avoid special cases in the context
  71. // switch code.
  72. //
  73. InitialStack = (ULONG64)Thread->InitialStack;
  74. NpxFrame = (PLEGACY_SAVE_AREA)(InitialStack - LEGACY_SAVE_AREA_LENGTH);
  75. RtlZeroMemory(NpxFrame, LEGACY_SAVE_AREA_LENGTH);
  76. //
  77. // If a context record is specified, then initialize a trap frame, and
  78. // an exception frame with the specified user mode context.
  79. //
  80. if (ARGUMENT_PRESENT(ContextRecord)) {
  81. RtlCopyMemory(&ContextFrame, ContextRecord, sizeof(CONTEXT));
  82. ContextRecord = &ContextFrame;
  83. ContextRecord->ContextFlags |= CONTEXT_CONTROL;
  84. ContextRecord->ContextFlags &= ~(CONTEXT_DEBUG_REGISTERS ^ CONTEXT_AMD64);
  85. //
  86. // Allocate a trap frame, an exception frame, and a context switch
  87. // frame.
  88. //
  89. TrFrame = (PKTRAP_FRAME)(((ULONG64)NpxFrame - KTRAP_FRAME_LENGTH));
  90. ExFrame = (PKEXCEPTION_FRAME)(((ULONG64)TrFrame - KEXCEPTION_FRAME_LENGTH));
  91. SwFrame = (PKSWITCH_FRAME)(((ULONG64)ExFrame - KSWITCH_FRAME_LENGTH));
  92. //
  93. // Set CS and SS for user mode 64-bit execution in the machine frame.
  94. //
  95. ContextRecord->SegCs = KGDT64_R3_CODE | RPL_MASK;
  96. ContextRecord->SegSs = KGDT64_R3_DATA | RPL_MASK;
  97. //
  98. // The main entry point for the user thread will be jumped to via a
  99. // continue operation from the user APC dispatcher. Therefore, the
  100. // user stack must be initialized to an 8 mod 16 boundary.
  101. //
  102. // In addition, we must have room for the home addresses for the
  103. // first four parameters.
  104. //
  105. ContextRecord->Rsp =
  106. (ContextRecord->Rsp & ~STACK_ROUND) - ((4 * 8) + 8);
  107. //
  108. // Zero the exception and trap frames and copy information from the
  109. // specified context frame to the trap and exception frames.
  110. //
  111. RtlZeroMemory(ExFrame, sizeof(KEXCEPTION_FRAME));
  112. RtlZeroMemory(TrFrame, sizeof(KTRAP_FRAME));
  113. KeContextToKframes(TrFrame,
  114. ExFrame,
  115. ContextRecord,
  116. ContextRecord->ContextFlags,
  117. UserMode);
  118. //
  119. // Initialize user thread startup information.
  120. //
  121. ExFrame->P1Home = (ULONG64)StartContext;
  122. ExFrame->P2Home = (ULONG64)StartRoutine;
  123. ExFrame->P3Home = (ULONG64)SystemRoutine;
  124. ExFrame->Return = (ULONG64)KiStartUserThreadReturn;
  125. //
  126. // Initialize start address.
  127. //
  128. SwFrame->Return = (ULONG64)KiStartUserThread;
  129. //
  130. // Set the initial legacy floating point control/tag word state and
  131. // the XMM control/status state.
  132. //
  133. NpxFrame->ControlWord = 0x27f;
  134. TrFrame->MxCsr = INITIAL_MXCSR;
  135. NpxFrame->StatusWord = 0;
  136. NpxFrame->TagWord = 0xffff;
  137. NpxFrame->ErrorOffset = 0;
  138. NpxFrame->ErrorSelector = 0;
  139. NpxFrame->ErrorOpcode = 0;
  140. NpxFrame->DataOffset = 0;
  141. NpxFrame->DataSelector = 0;
  142. //
  143. // Set legacy floating point state to scrub.
  144. //
  145. Thread->NpxState = LEGACY_STATE_SCRUB;
  146. //
  147. // Set the saved previous processor mode in the trap frame and the
  148. // previous processor mode in the thread object to user mode.
  149. //
  150. TrFrame->PreviousMode = UserMode;
  151. Thread->PreviousMode = UserMode;
  152. } else {
  153. //
  154. // Allocate an exception frame and a context switch frame.
  155. //
  156. TrFrame = NULL;
  157. SfFrame = (PKSTART_FRAME)(((ULONG64)NpxFrame - KSTART_FRAME_LENGTH));
  158. SwFrame = (PKSWITCH_FRAME)(((ULONG64)SfFrame - KSWITCH_FRAME_LENGTH));
  159. //
  160. // Initialize the system thread start frame.
  161. //
  162. SfFrame->P1Home = (ULONG64)StartContext;
  163. SfFrame->P2Home = (ULONG64)StartRoutine;
  164. SfFrame->P3Home = (ULONG64)SystemRoutine;
  165. SfFrame->Return = 0;
  166. //
  167. // Initialize start address.
  168. //
  169. SwFrame->Return = (ULONG64)KiStartSystemThread;
  170. //
  171. // Set legacy floating point state to unused.
  172. //
  173. Thread->NpxState = LEGACY_STATE_UNUSED;
  174. //
  175. // Set the previous mode in thread object to kernel.
  176. //
  177. Thread->PreviousMode = KernelMode;
  178. }
  179. //
  180. // Initialize context switch frame and set thread start up parameters.
  181. //
  182. SwFrame->MxCsr = INITIAL_MXCSR;
  183. SwFrame->ApcBypass = APC_LEVEL;
  184. SwFrame->Rbp = (ULONG64)TrFrame + 128;
  185. //
  186. // Set the initial kernel stack pointer.
  187. //
  188. Thread->InitialStack = (PVOID)NpxFrame;
  189. Thread->KernelStack = SwFrame;
  190. return;
  191. }
  192. BOOLEAN
  193. KeSetAutoAlignmentProcess (
  194. IN PKPROCESS Process,
  195. IN BOOLEAN Enable
  196. )
  197. /*++
  198. Routine Description:
  199. This function sets the data alignment handling mode for the specified
  200. process and returns the previous data alignment handling mode.
  201. N.B. Data alignment fixup is always performed by hardware.
  202. Arguments:
  203. Process - Supplies a pointer to a dispatcher object of type process.
  204. Enable - Supplies a boolean value that determines the handling of data
  205. alignment exceptions for the process. A value of TRUE causes all
  206. data alignment exceptions to be automatically handled by the kernel.
  207. A value of FALSE causes all data alignment exceptions to be actually
  208. raised as exceptions.
  209. Return Value:
  210. A value of TRUE is returned if data alignment exceptions were previously
  211. automatically handled by the kernel. Otherwise, FALSE is returned.
  212. --*/
  213. {
  214. KIRQL OldIrql;
  215. BOOLEAN Previous;
  216. ASSERT_PROCESS(Process);
  217. //
  218. // Raise IRQL to dispatcher level and lock dispatcher database.
  219. //
  220. KiLockDispatcherDatabase(&OldIrql);
  221. //
  222. // Capture the previous data alignment handling mode and set the
  223. // specified data alignment mode.
  224. //
  225. Previous = Process->AutoAlignment;
  226. Process->AutoAlignment = Enable;
  227. //
  228. // Unlock dispatcher database, lower IRQL to its previous value, and
  229. // return the previous data alignment mode.
  230. //
  231. KiUnlockDispatcherDatabase(OldIrql);
  232. return Previous;
  233. }
  234. BOOLEAN
  235. KeSetAutoAlignmentThread (
  236. IN PKTHREAD Thread,
  237. IN BOOLEAN Enable
  238. )
  239. /*++
  240. Routine Description:
  241. This function sets the data alignment handling mode for the specified
  242. thread and returns the previous data alignment handling mode.
  243. N.B. Data alignment fixup is always performed by hardware.
  244. Arguments:
  245. Thread - Supplies a pointer to a dispatcher object of type thread.
  246. Enable - Supplies a boolean value that determines the handling of data
  247. alignment exceptions for the specified thread. A value of TRUE causes
  248. all data alignment exceptions to be automatically handled by the kernel.
  249. A value of FALSE causes all data alignment exceptions to be actually
  250. raised as exceptions.
  251. Return Value:
  252. A value of TRUE is returned if data alignment exceptions were previously
  253. automatically handled by the kernel. Otherwise, FALSE is returned.
  254. --*/
  255. {
  256. BOOLEAN Previous;
  257. KIRQL OldIrql;
  258. ASSERT_THREAD(Thread);
  259. //
  260. // Raise IRQL and lock dispatcher database.
  261. //
  262. KiLockDispatcherDatabase(&OldIrql);
  263. //
  264. // Capture the previous data alignment handling mode and set the
  265. // specified data alignment mode.
  266. //
  267. Previous = Thread->AutoAlignment;
  268. Thread->AutoAlignment = Enable;
  269. //
  270. // Unlock dispatcher database and lower IRQL.
  271. //
  272. KiUnlockDispatcherDatabase(OldIrql);
  273. return Previous;
  274. }