Source code of Windows XP (NT5)
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.

655 lines
18 KiB

  1. /*++
  2. Copyright (c) 1990 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) 31-Mar-1990
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. 3 April 90 bryan willman
  14. This version ported to 386.
  15. --*/
  16. #include "ki.h"
  17. //
  18. // The following assert macros are used to check that an input object is
  19. // really the proper type.
  20. //
  21. #define ASSERT_PROCESS(E) { \
  22. ASSERT((E)->Header.Type == ProcessObject); \
  23. }
  24. #define ASSERT_THREAD(E) { \
  25. ASSERT((E)->Header.Type == ThreadObject); \
  26. }
  27. //
  28. // Our notion of alignment is different, so force use of ours
  29. //
  30. #undef ALIGN_UP
  31. #undef ALIGN_DOWN
  32. #define ALIGN_DOWN(address,amt) ((ULONG)(address) & ~(( amt ) - 1))
  33. #define ALIGN_UP(address,amt) (ALIGN_DOWN( (address + (amt) - 1), (amt) ))
  34. //
  35. // The function prototype for the special APC we use to set the
  36. // hardware alignment state for a thread
  37. //
  38. VOID
  39. KepSetAlignmentSpecialApc(
  40. IN PKAPC Apc,
  41. IN PKNORMAL_ROUTINE *NormalRoutine,
  42. IN PVOID *NormalContext,
  43. IN PVOID *SystemArgument1,
  44. IN PVOID *SystemArgument2
  45. );
  46. VOID
  47. KiInitializeContextThread (
  48. IN PKTHREAD Thread,
  49. IN PKSYSTEM_ROUTINE SystemRoutine,
  50. IN PKSTART_ROUTINE StartRoutine OPTIONAL,
  51. IN PVOID StartContext OPTIONAL,
  52. IN PCONTEXT ContextFrame OPTIONAL
  53. )
  54. /*++
  55. Routine Description:
  56. This function initializes the machine dependent context of a thread object.
  57. N.B. This function does not check the accessibility of the context record.
  58. It is assumed the the caller of this routine is either prepared to
  59. handle access violations or has probed and copied the context record
  60. as appropriate.
  61. Arguments:
  62. Thread - Supplies a pointer to a dispatcher object of type thread.
  63. SystemRoutine - Supplies a pointer to the system function that is to be
  64. called when the thread is first scheduled for execution.
  65. StartRoutine - Supplies an optional pointer to a function that is to be
  66. called after the system has finished initializing the thread. This
  67. parameter is specified if the thread is a system thread and will
  68. execute totally in kernel mode.
  69. StartContext - Supplies an optional pointer to an arbitrary data structure
  70. which will be passed to the StartRoutine as a parameter. This
  71. parameter is specified if the thread is a system thread and will
  72. execute totally in kernel mode.
  73. ContextFrame - Supplies an optional pointer a context frame which contains
  74. the initial user mode state of the thread. This parameter is specified
  75. if the thread is a user thread and will execute in user mode. If this
  76. parameter is not specified, then the Teb parameter is ignored.
  77. Return Value:
  78. None.
  79. --*/
  80. {
  81. PFX_SAVE_AREA NpxFrame;
  82. PKSWITCHFRAME SwitchFrame;
  83. PKTRAP_FRAME TrFrame;
  84. PULONG PSystemRoutine;
  85. PULONG PStartRoutine;
  86. PULONG PStartContext;
  87. PULONG PUserContextFlag;
  88. ULONG ContextFlags;
  89. CONTEXT Context2;
  90. PCONTEXT ContextFrame2 = NULL;
  91. PFXSAVE_FORMAT PFxSaveArea;
  92. //
  93. // If a context frame is specified, then initialize a trap frame and
  94. // and an exception frame with the specified user mode context.
  95. //
  96. if (ARGUMENT_PRESENT(ContextFrame)) {
  97. RtlCopyMemory(&Context2, ContextFrame, sizeof(CONTEXT));
  98. ContextFrame2 = &Context2;
  99. ContextFlags = CONTEXT_CONTROL;
  100. //
  101. // The 80387 save area is at the very base of the kernel stack.
  102. //
  103. NpxFrame = (PFX_SAVE_AREA)(((ULONG)(Thread->InitialStack) -
  104. sizeof(FX_SAVE_AREA)));
  105. //
  106. // Load up an initial NPX state.
  107. //
  108. if (KeI386FxsrPresent == TRUE) {
  109. PFxSaveArea = (PFXSAVE_FORMAT)ContextFrame2->ExtendedRegisters;
  110. PFxSaveArea->ControlWord = 0x27f; // like fpinit but 64bit mode
  111. PFxSaveArea->StatusWord = 0;
  112. PFxSaveArea->TagWord = 0;
  113. PFxSaveArea->ErrorOffset = 0;
  114. PFxSaveArea->ErrorSelector = 0;
  115. PFxSaveArea->DataOffset = 0;
  116. PFxSaveArea->DataSelector = 0;
  117. PFxSaveArea->MXCsr = 0x1f80; // mask all the exceptions
  118. } else {
  119. ContextFrame2->FloatSave.ControlWord = 0x27f; // like fpinit but 64bit mode
  120. ContextFrame2->FloatSave.StatusWord = 0;
  121. ContextFrame2->FloatSave.TagWord = 0xffff;
  122. ContextFrame2->FloatSave.ErrorOffset = 0;
  123. ContextFrame2->FloatSave.ErrorSelector = 0;
  124. ContextFrame2->FloatSave.DataOffset = 0;
  125. ContextFrame2->FloatSave.DataSelector = 0;
  126. }
  127. if (KeI386NpxPresent) {
  128. ContextFrame2->FloatSave.Cr0NpxState = 0;
  129. NpxFrame->Cr0NpxState = 0;
  130. NpxFrame->NpxSavedCpu = 0;
  131. if (KeI386FxsrPresent == TRUE) {
  132. ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
  133. } else {
  134. ContextFlags |= CONTEXT_FLOATING_POINT;
  135. }
  136. //
  137. // Threads NPX state is not in the coprocessor.
  138. //
  139. Thread->NpxState = NPX_STATE_NOT_LOADED;
  140. Thread->NpxIrql = PASSIVE_LEVEL;
  141. } else {
  142. NpxFrame->Cr0NpxState = CR0_EM;
  143. //
  144. // Threads NPX state is not in the coprocessor.
  145. // In the emulator case, do not set the CR0_EM bit as their
  146. // emulators may not want exceptions on FWAIT instructions.
  147. //
  148. Thread->NpxState = NPX_STATE_NOT_LOADED & ~CR0_MP;
  149. }
  150. //
  151. // Force debug registers off. They won't work anyway from an
  152. // initial frame, debuggers must set a hard breakpoint in the target
  153. //
  154. ContextFrame2->Dr0 = 0;
  155. ContextFrame2->Dr1 = 0;
  156. ContextFrame2->Dr2 = 0;
  157. ContextFrame2->Dr3 = 0;
  158. ContextFrame2->Dr6 = 0;
  159. ContextFrame2->Dr7 = 0;
  160. ContextFrame2->ContextFlags &= ~(CONTEXT_DEBUG_REGISTERS);
  161. #if 0
  162. //
  163. // If AutoAlignment is FALSE, we want to set the Alignment Check bit
  164. // in Eflags, so we will get alignment faults.
  165. //
  166. if (Thread->AutoAlignment == FALSE) {
  167. ContextFrame2->EFlags |= EFLAGS_ALIGN_CHECK;
  168. }
  169. #endif
  170. //
  171. // If the thread is set
  172. TrFrame = (PKTRAP_FRAME)(((ULONG)NpxFrame - KTRAP_FRAME_LENGTH));
  173. // Space for arguments to KiThreadStartup. Order is important,
  174. // Since args are passed on stack through KiThreadStartup to
  175. // PStartRoutine with PStartContext as an argument.
  176. PUserContextFlag = (PULONG)TrFrame - 1;
  177. PStartContext = PUserContextFlag - 1;
  178. PStartRoutine = PStartContext - 1;
  179. PSystemRoutine = PStartRoutine - 1;
  180. SwitchFrame = (PKSWITCHFRAME)((PUCHAR)PSystemRoutine -
  181. sizeof(KSWITCHFRAME));
  182. //
  183. // Copy information from the specified context frame to the trap and
  184. // exception frames.
  185. //
  186. KeContextToKframes(TrFrame, NULL, ContextFrame2,
  187. ContextFrame2->ContextFlags | ContextFlags,
  188. UserMode);
  189. TrFrame->HardwareSegSs |= RPL_MASK;
  190. TrFrame->SegDs |= RPL_MASK;
  191. TrFrame->SegEs |= RPL_MASK;
  192. #if DBG
  193. TrFrame->DbgArgMark = 0xBADB0D00;
  194. #endif
  195. //
  196. // Tell KiThreadStartup that a user context is present.
  197. //
  198. *PUserContextFlag = 1;
  199. //
  200. // Initialize the kernel mode ExceptionList pointer
  201. //
  202. TrFrame->ExceptionList = EXCEPTION_CHAIN_END;
  203. //
  204. // Initialize the saved previous processor mode.
  205. //
  206. TrFrame->PreviousPreviousMode = UserMode;
  207. //
  208. // Set the previous mode in thread object to user.
  209. //
  210. Thread->PreviousMode = UserMode;
  211. } else {
  212. //
  213. // Dummy floating save area. Kernel threads don't have or use
  214. // the floating point - the dummy save area is make the stacks
  215. // consistent.
  216. //
  217. NpxFrame = (PFX_SAVE_AREA)(((ULONG)(Thread->InitialStack) -
  218. sizeof(FX_SAVE_AREA)));
  219. //
  220. // Load up an initial NPX state.
  221. //
  222. RtlZeroMemory((PVOID)NpxFrame, sizeof(FX_SAVE_AREA));
  223. if (KeI386FxsrPresent == TRUE) {
  224. NpxFrame->U.FxArea.ControlWord = 0x27f;//like fpinit but 64bit mode
  225. NpxFrame->U.FxArea.MXCsr = 0x1f80;// mask all the exceptions
  226. } else {
  227. NpxFrame->U.FnArea.ControlWord = 0x27f;//like fpinit but 64bit mode
  228. NpxFrame->U.FnArea.TagWord = 0xffff;
  229. }
  230. //
  231. // Threads NPX state is not in the coprocessor.
  232. //
  233. Thread->NpxState = NPX_STATE_NOT_LOADED;
  234. //
  235. // Space for arguments to KiThreadStartup.
  236. // Order of fields in the switchframe is important,
  237. // Since args are passed on stack through KiThreadStartup to
  238. // PStartRoutine with PStartContext as an argument.
  239. //
  240. PUserContextFlag = (PULONG)((ULONG)NpxFrame) - 1;
  241. PStartContext = PUserContextFlag - 1;
  242. PStartRoutine = PStartContext - 1;
  243. PSystemRoutine = PStartRoutine - 1;
  244. SwitchFrame = (PKSWITCHFRAME)((PUCHAR)PSystemRoutine -
  245. sizeof(KSWITCHFRAME));
  246. //
  247. // Tell KiThreadStartup that a user context is NOT present.
  248. //
  249. *PUserContextFlag = 0;
  250. //
  251. // Set the previous mode in thread object to kernel.
  252. //
  253. Thread->PreviousMode = KernelMode;
  254. }
  255. //
  256. // Set up thread start parameters.
  257. // (UserContextFlag set above)
  258. //
  259. *PStartContext = (ULONG)StartContext;
  260. *PStartRoutine = (ULONG)StartRoutine;
  261. *PSystemRoutine = (ULONG)SystemRoutine;
  262. //
  263. // Set up switch frame. Assume the thread doesn't use the 80387;
  264. // if it ever does (and there is one), these flags will get reset.
  265. // Each thread starts with these same flags set, regardless of
  266. // whether the hardware exists or not.
  267. //
  268. SwitchFrame->RetAddr = (ULONG)KiThreadStartup;
  269. SwitchFrame->Eflags = EFLAGS_INTERRUPT_MASK;
  270. #if 0
  271. //
  272. // If AutoAlignment is FALSE, we want to set the Alignment Check bit
  273. // in Eflags, so we will get alignment faults.
  274. //
  275. if (Thread->AutoAlignment == FALSE) {
  276. SwitchFrame->Eflags |= EFLAGS_ALIGN_CHECK;
  277. }
  278. #endif
  279. SwitchFrame->ExceptionList = (ULONG)(EXCEPTION_CHAIN_END);
  280. //
  281. // Set the initial kernel stack pointer.
  282. //
  283. //DbgPrint("KiInitializeContextThread Thread %08x SwitchFrame %08x\n", Thread, SwitchFrame);
  284. //DbgPrint("PSystemRoutine %08x PStartRoutine %08x PStartContext %08x\n", *PSystemRoutine, *PStartRoutine, *PStartContext);
  285. Thread->KernelStack = (PVOID)SwitchFrame;
  286. return;
  287. }
  288. BOOLEAN
  289. KeSetAutoAlignmentProcess (
  290. IN PKPROCESS Process,
  291. IN BOOLEAN Enable
  292. )
  293. /*++
  294. Routine Description:
  295. This function sets the data alignment handling mode for the specified
  296. process and returns the previous data alignment handling mode.
  297. Arguments:
  298. Process - Supplies a pointer to a dispatcher object of type process.
  299. Enable - Supplies a boolean value that determines the handling of data
  300. alignment exceptions for the process. A value of TRUE causes all
  301. data alignment exceptions to be automatically handled by the kernel.
  302. A value of FALSE causes all data alignment exceptions to be actually
  303. raised as exceptions.
  304. Return Value:
  305. A value of TRUE is returned if data alignment exceptions were
  306. previously automatically handled by the kernel. Otherwise, a value
  307. of FALSE is returned.
  308. --*/
  309. {
  310. KIRQL OldIrql;
  311. BOOLEAN Previous;
  312. ASSERT_PROCESS(Process);
  313. //
  314. // Raise IRQL to dispatcher level and lock dispatcher database.
  315. //
  316. KiLockDispatcherDatabase(&OldIrql);
  317. //
  318. // Capture the previous data alignment handling mode and set the
  319. // specified data alignment mode.
  320. //
  321. Previous = Process->AutoAlignment;
  322. Process->AutoAlignment = Enable;
  323. //
  324. // Unlock dispatcher database, lower IRQL to its previous value, and
  325. // return the previous data alignment mode.
  326. //
  327. KiUnlockDispatcherDatabase(OldIrql);
  328. return Previous;
  329. }
  330. BOOLEAN
  331. KeSetAutoAlignmentThread (
  332. IN PKTHREAD Thread,
  333. IN BOOLEAN Enable
  334. )
  335. /*++
  336. Routine Description:
  337. This function sets the data alignment handling mode for the specified
  338. thread and returns the previous data alignment handling mode.
  339. Arguments:
  340. Thread - Supplies a pointer to a dispatcher object of type thread.
  341. Enable - Supplies a boolean value that determines the handling of data
  342. alignment exceptions for the specified thread. A value of TRUE causes
  343. all data alignment exceptions to be automatically handled by the kernel.
  344. A value of FALSE causes all data alignment exceptions to be actually
  345. raised as exceptions.
  346. Return Value:
  347. A value of TRUE is returned if data alignment exceptions were
  348. previously automatically handled by the kernel. Otherwise, a value
  349. of FALSE is returned.
  350. --*/
  351. {
  352. BOOLEAN Previous;
  353. PKAPC Apc;
  354. PKEVENT Event;
  355. KIRQL OldIrql;
  356. ASSERT_THREAD(Thread);
  357. //
  358. // Raise IRQL to dispatcher level and lock dispatcher database.
  359. //
  360. KiLockDispatcherDatabase(&OldIrql);
  361. //
  362. // Capture the previous data alignment handling mode and set the
  363. // specified data alignment mode.
  364. //
  365. Previous = Thread->AutoAlignment;
  366. Thread->AutoAlignment = Enable;
  367. //
  368. // Unlock dispatcher database and lower IRQL to its previous value.
  369. //
  370. KiUnlockDispatcherDatabase(OldIrql);
  371. #if 0
  372. Apc = ExAllocatePool(NonPagedPoolMustSucceed, sizeof(KAPC));
  373. Event = ExAllocatePool(NonPagedPoolMustSucceed, sizeof(KEVENT));
  374. KeInitializeEvent(Event, NotificationEvent, FALSE);
  375. if ( Thread == KeGetCurrentThread() ) {
  376. Apc->SystemArgument1 = Thread;
  377. Apc->SystemArgument2 = Event;
  378. KeRaiseIrql(APC_LEVEL, &Irql);
  379. KepSetAlignmentSpecialApc( Apc, NULL, NULL,
  380. &Apc->SystemArgument1,
  381. &Apc->SystemArgument2 );
  382. KeLowerIrql(Irql);
  383. } else {
  384. KeInitializeApc( Apc,
  385. Thread,
  386. CurrentApcEnvironment,
  387. KepSetAlignmentSpecialApc,
  388. NULL,
  389. NULL,
  390. KernelMode,
  391. NULL );
  392. if (!KeInsertQueueApc( Apc,
  393. Thread,
  394. Event,
  395. 2 ) ) {
  396. //
  397. // We couldn't queue the APC, so we will not be able to change
  398. // the AutoAlignment. Update the thread object so that it
  399. // stays in sync with the hardware state.
  400. //
  401. #if DBG
  402. DbgPrint("KeSetAutoAlignmentThread: unable to change thread's context\n");
  403. #endif
  404. Thread->AutoAlignment = Previous;
  405. }
  406. KeWaitForSingleObject( Event,
  407. Executive,
  408. KernelMode,
  409. FALSE,
  410. NULL );
  411. }
  412. ExFreePool(Apc);
  413. ExFreePool(Event);
  414. #endif
  415. return(Previous);
  416. }
  417. #if 0
  418. VOID
  419. KepSetAlignmentSpecialApc(
  420. IN PKAPC Apc,
  421. IN PKNORMAL_ROUTINE *NormalRoutine,
  422. IN PVOID *NormalContext,
  423. IN PVOID *SystemArgument1,
  424. IN PVOID *SystemArgument2
  425. )
  426. /*++
  427. Routine Description:
  428. This function updates the alignment check bit of the current thread's
  429. EFLAGS to reflect the AutoAlignment setting of the thread object.
  430. Arguments:
  431. Apc - Supplies a pointer to the APC control object that caused entry
  432. into this routine.
  433. NormalRoutine - Supplies a pointer to a pointer to the normal routine
  434. function that was specifed when the APC was initialized.
  435. NormalContext - Supplies a pointer to a pointer to an arbitrary data
  436. structure that was specified when the APC was initialized.
  437. SystemArgument1 - Supplies a pointer to a PKTHREAD
  438. SystemArgument2 - Supplies a pointer to a PKEVENT
  439. Return Value:
  440. None.
  441. --*/
  442. {
  443. PKTHREAD Thread;
  444. PKEVENT Event;
  445. PKTRAP_FRAME TrapFrame;
  446. CONTEXT ContextFrame;
  447. Thread = *(PKTHREAD *)SystemArgument1;
  448. Event = *(PKEVENT *)SystemArgument2;
  449. ASSERT( Thread == KeGetCurrentThread() );
  450. //
  451. // Find the trap frame on the stack, so we can get the thread context
  452. //
  453. TrapFrame = (PKTRAP_FRAME)((PUCHAR)Thread->InitialStack -
  454. ALIGN_UP(sizeof(KTRAP_FRAME),KTRAP_FRAME_ALIGN) -
  455. sizeof(FX_SAVE_AREA));
  456. ContextFrame.ContextFlags = CONTEXT_CONTROL;
  457. KeContextFromKframes( TrapFrame,
  458. NULL,
  459. &ContextFrame );
  460. //
  461. // If AutoAlignment is TRUE, we want the processor to transparently fixup
  462. // all alignment faults, so we clear the Alignment Check bit. If
  463. // AutoAlignment is FALSE, we set the bit, so 486 processors will
  464. // give us alignment faults.
  465. //
  466. if (Thread->AutoAlignment) {
  467. ContextFrame.EFlags &= (~EFLAGS_ALIGN_CHECK);
  468. } else {
  469. ContextFrame.EFlags |= EFLAGS_ALIGN_CHECK;
  470. }
  471. //
  472. // Replace the modified EFlags in the trap frame. When the thread returns
  473. // to user mode, it will be running with the new alignment setting.
  474. //
  475. KeContextToKframes( TrapFrame,
  476. NULL,
  477. &ContextFrame,
  478. CONTEXT_CONTROL,
  479. KeGetPreviousMode() );
  480. KeSetEvent(Event,0,FALSE);
  481. }
  482. #endif