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.

1174 lines
24 KiB

  1. /*++
  2. Copyright (c) 1989-1992 Microsoft Corporation
  3. Module Name:
  4. miscc.c
  5. Abstract:
  6. This module implements machine independent miscellaneous kernel functions.
  7. Author:
  8. David N. Cutler (davec) 13-May-1989
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "ki.h"
  14. #pragma alloc_text(PAGE, KeAddSystemServiceTable)
  15. #pragma alloc_text(PAGE, KeRemoveSystemServiceTable)
  16. #pragma alloc_text(PAGE, KeSetTimeUpdateNotifyRoutine)
  17. #pragma alloc_text(PAGE, KeQueryActiveProcessors)
  18. #pragma alloc_text(PAGELK, KiCalibrateTimeAdjustment)
  19. #undef KeEnterCriticalRegion
  20. VOID
  21. KeEnterCriticalRegion (
  22. VOID
  23. )
  24. /*++
  25. Routine Description:
  26. This function disables kernel APC's.
  27. N.B. The following code does not require any interlocks. There are
  28. two cases of interest: 1) On an MP system, the thread cannot
  29. be running on two processors as once, and 2) if the thread is
  30. is interrupted to deliver a kernel mode APC which also calls
  31. this routine, the values read and stored will stack and unstack
  32. properly.
  33. Arguments:
  34. None.
  35. Return Value:
  36. None.
  37. --*/
  38. {
  39. //
  40. // Simply directly disable kernel APCs.
  41. //
  42. KeGetCurrentThread()->KernelApcDisable -= 1;
  43. return;
  44. }
  45. #undef KeLeaveCriticalRegion
  46. VOID
  47. KeLeaveCriticalRegion (
  48. VOID
  49. )
  50. /*++
  51. Routine Description:
  52. This function enables kernel APC's and requests an APC interrupt if
  53. appropriate.
  54. Arguments:
  55. None.
  56. Return Value:
  57. None.
  58. --*/
  59. {
  60. //
  61. // Increment the kernel APC disable count. If the resultant count is
  62. // zero and the thread's kernel APC List is not empty, then request an
  63. // APC interrupt.
  64. //
  65. // For multiprocessor performance, the following code utilizes the fact
  66. // that queuing an APC is done by first queuing the APC, then checking
  67. // the AST disable count. The following code increments the disable
  68. // count first, checks to determine if it is zero, and then checks the
  69. // kernel AST queue.
  70. //
  71. // See also KiInsertQueueApc().
  72. //
  73. KiLeaveCriticalRegion();
  74. return;
  75. }
  76. ULONGLONG
  77. KeQueryInterruptTime (
  78. VOID
  79. )
  80. /*++
  81. Routine Description:
  82. This function returns the current interrupt time by determining when the
  83. time is stable and then returning its value.
  84. Arguments:
  85. CurrentTime - Supplies a pointer to a variable that will receive the
  86. current system time.
  87. Return Value:
  88. None.
  89. --*/
  90. {
  91. LARGE_INTEGER CurrentTime;
  92. KiQueryInterruptTime(&CurrentTime);
  93. return CurrentTime.QuadPart;
  94. }
  95. VOID
  96. KeQuerySystemTime (
  97. OUT PLARGE_INTEGER CurrentTime
  98. )
  99. /*++
  100. Routine Description:
  101. This function returns the current system time by determining when the
  102. time is stable and then returning its value.
  103. Arguments:
  104. CurrentTime - Supplies a pointer to a variable that will receive the
  105. current system time.
  106. Return Value:
  107. None.
  108. --*/
  109. {
  110. KiQuerySystemTime(CurrentTime);
  111. return;
  112. }
  113. VOID
  114. KeQueryTickCount (
  115. OUT PLARGE_INTEGER CurrentCount
  116. )
  117. /*++
  118. Routine Description:
  119. This function returns the current tick count by determining when the
  120. count is stable and then returning its value.
  121. Arguments:
  122. CurrentCount - Supplies a pointer to a variable that will receive the
  123. current tick count.
  124. Return Value:
  125. None.
  126. --*/
  127. {
  128. KiQueryTickCount(CurrentCount);
  129. return;
  130. }
  131. ULONG
  132. KeQueryTimeIncrement (
  133. VOID
  134. )
  135. /*++
  136. Routine Description:
  137. This function returns the time increment value in 100ns units. This
  138. is the value that is added to the system time at each interval clock
  139. interrupt.
  140. Arguments:
  141. None.
  142. Return Value:
  143. The time increment value is returned as the function value.
  144. --*/
  145. {
  146. return KeMaximumIncrement;
  147. }
  148. VOID
  149. KeEnableInterrupts (
  150. IN BOOLEAN Enable
  151. )
  152. /*++
  153. Routine Description:
  154. This function enables interrupts based on the specified enable state.
  155. Arguments:
  156. Enable - Supplies a boolean value that determines whether interrupts
  157. are to be enabled.
  158. Return Value:
  159. None.
  160. --*/
  161. {
  162. if (Enable != FALSE) {
  163. _enable();
  164. }
  165. return;
  166. }
  167. VOID
  168. KeSetDmaIoCoherency (
  169. IN ULONG Attributes
  170. )
  171. /*++
  172. Routine Description:
  173. This function sets (enables/disables) DMA I/O coherency with data
  174. caches.
  175. Arguments:
  176. Attributes - Supplies the set of DMA I/O coherency attributes for
  177. the host system.
  178. Return Value:
  179. None.
  180. --*/
  181. {
  182. KiDmaIoCoherency = Attributes;
  183. }
  184. #if defined(_AMD64_) || defined(_X86_)
  185. #pragma alloc_text(INIT, KeSetProfileIrql)
  186. VOID
  187. KeSetProfileIrql (
  188. IN KIRQL ProfileIrql
  189. )
  190. /*++
  191. Routine Description:
  192. This function sets the profile IRQL.
  193. N.B. There are only two valid values for the profile IRQL which are
  194. PROFILE_LEVEL and HIGH_LEVEL.
  195. Arguments:
  196. Irql - Supplies the synchronization IRQL value.
  197. Return Value:
  198. None.
  199. --*/
  200. {
  201. ASSERT((ProfileIrql == PROFILE_LEVEL) || (ProfileIrql == HIGH_LEVEL));
  202. KiProfileIrql = ProfileIrql;
  203. }
  204. #endif
  205. VOID
  206. KeSetSystemTime (
  207. IN PLARGE_INTEGER NewTime,
  208. OUT PLARGE_INTEGER OldTime,
  209. IN BOOLEAN AdjustInterruptTime,
  210. IN PLARGE_INTEGER HalTimeToSet OPTIONAL
  211. )
  212. /*++
  213. Routine Description:
  214. This function sets the system time to the specified value and updates
  215. timer queue entries to reflect the difference between the old system
  216. time and the new system time.
  217. Arguments:
  218. NewTime - Supplies a pointer to a variable that specifies the new system
  219. time.
  220. OldTime - Supplies a pointer to a variable that will receive the previous
  221. system time.
  222. AdjustInterruptTime - If TRUE the amount of time being adjusted is
  223. also applied to InterruptTime and TickCount.
  224. HalTimeToSet - Supplies an optional time that if specified is to be used
  225. to set the time in the realtime clock.
  226. Return Value:
  227. None.
  228. --*/
  229. {
  230. LIST_ENTRY AbsoluteListHead;
  231. LIST_ENTRY ExpiredListHead;
  232. ULONG Index;
  233. PLIST_ENTRY ListHead;
  234. PLIST_ENTRY NextEntry;
  235. KIRQL OldIrql1;
  236. KIRQL OldIrql2;
  237. LARGE_INTEGER TimeDelta;
  238. TIME_FIELDS TimeFields;
  239. PKTIMER Timer;
  240. ASSERT((NewTime->HighPart & 0xf0000000) == 0);
  241. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  242. //
  243. // If a realtime clock value is specified, then convert the time value
  244. // to time fields.
  245. //
  246. if (ARGUMENT_PRESENT(HalTimeToSet)) {
  247. RtlTimeToTimeFields(HalTimeToSet, &TimeFields);
  248. }
  249. //
  250. // Set affinity to the processor that keeps the system time, raise IRQL
  251. // to dispatcher level and lock the dispatcher database, then raise IRQL
  252. // to HIGH_LEVEL to synchronize with the clock interrupt routine.
  253. //
  254. KeSetSystemAffinityThread((KAFFINITY)1);
  255. KiLockDispatcherDatabase(&OldIrql1);
  256. KeRaiseIrql(HIGH_LEVEL, &OldIrql2);
  257. //
  258. // Save the previous system time, set the new system time, and set
  259. // the realtime clock, if a time value is specified.
  260. //
  261. KiQuerySystemTime(OldTime);
  262. SharedUserData->SystemTime.High2Time = NewTime->HighPart;
  263. SharedUserData->SystemTime.LowPart = NewTime->LowPart;
  264. SharedUserData->SystemTime.High1Time = NewTime->HighPart;
  265. if (ARGUMENT_PRESENT(HalTimeToSet)) {
  266. ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
  267. }
  268. //
  269. // Compute the difference between the previous system time and the new
  270. // system time.
  271. //
  272. TimeDelta.QuadPart = NewTime->QuadPart - OldTime->QuadPart;
  273. //
  274. // Update the boot time to reflect the delta. This keeps time based
  275. // on boot time constant
  276. //
  277. KeBootTime.QuadPart = KeBootTime.QuadPart + TimeDelta.QuadPart;
  278. //
  279. // Track the overall bias applied to the boot time.
  280. //
  281. KeBootTimeBias = KeBootTimeBias + TimeDelta.QuadPart;
  282. //
  283. // Lower IRQL to dispatch level and if needed adjust the physical
  284. // system interrupt time.
  285. //
  286. KeLowerIrql(OldIrql2);
  287. if (AdjustInterruptTime) {
  288. //
  289. // Adjust the physical time of the system
  290. //
  291. AdjustInterruptTime = KiAdjustInterruptTime (TimeDelta.QuadPart);
  292. }
  293. //
  294. // If the physical interrupt time of the system was not adjusted,
  295. // recompute any absolute timers in the system for the new
  296. // system time.
  297. //
  298. if (!AdjustInterruptTime) {
  299. //
  300. // Remove all absolute timers from the timer queue so their due time
  301. // can be recomputed.
  302. //
  303. InitializeListHead(&AbsoluteListHead);
  304. for (Index = 0; Index < TIMER_TABLE_SIZE; Index += 1) {
  305. ListHead = &KiTimerTableListHead[Index];
  306. NextEntry = ListHead->Flink;
  307. while (NextEntry != ListHead) {
  308. Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
  309. NextEntry = NextEntry->Flink;
  310. if (Timer->Header.Absolute != FALSE) {
  311. RemoveEntryList(&Timer->TimerListEntry);
  312. InsertTailList(&AbsoluteListHead, &Timer->TimerListEntry);
  313. }
  314. }
  315. }
  316. //
  317. // Recompute the due time and reinsert all absolute timers in the timer
  318. // tree. If a timer has already expired, then insert the timer in the
  319. // expired timer list.
  320. //
  321. InitializeListHead(&ExpiredListHead);
  322. while (AbsoluteListHead.Flink != &AbsoluteListHead) {
  323. Timer = CONTAINING_RECORD(AbsoluteListHead.Flink, KTIMER, TimerListEntry);
  324. KiRemoveTreeTimer(Timer);
  325. Timer->DueTime.QuadPart -= TimeDelta.QuadPart;
  326. if (KiReinsertTreeTimer(Timer, Timer->DueTime) == FALSE) {
  327. Timer->Header.Inserted = TRUE;
  328. InsertTailList(&ExpiredListHead, &Timer->TimerListEntry);
  329. }
  330. }
  331. //
  332. // If any of the attempts to reinsert a timer failed, then timers have
  333. // already expired and must be processed.
  334. //
  335. // N.B. The following function returns with the dispatcher database
  336. // unlocked.
  337. //
  338. KiTimerListExpire(&ExpiredListHead, OldIrql1);
  339. } else {
  340. KiUnlockDispatcherDatabase(OldIrql1);
  341. }
  342. //
  343. // Set affinity back to its original value.
  344. //
  345. KeRevertToUserAffinityThread();
  346. return;
  347. }
  348. BOOLEAN
  349. KiAdjustInterruptTime (
  350. IN LONGLONG TimeDelta
  351. )
  352. /*++
  353. Routine Description:
  354. This function moves the physical interrupt time of the system foreward by
  355. the specified time delta after a system wake has occurred.
  356. Arguments:
  357. TimeDelta - Supplies the time delta to be added to the interrupt time, tick
  358. count and the perforamnce counter in 100ns units.
  359. Return Value:
  360. None.
  361. --*/
  362. {
  363. ADJUST_INTERRUPT_TIME_CONTEXT Adjust;
  364. //
  365. // Time can only be moved forward.
  366. //
  367. if (TimeDelta < 0) {
  368. return FALSE;
  369. } else {
  370. Adjust.KiNumber = KeNumberProcessors;
  371. Adjust.HalNumber = KeNumberProcessors;
  372. Adjust.Adjustment = (ULONGLONG) TimeDelta;
  373. Adjust.Barrier = 1;
  374. KiIpiGenericCall((PKIPI_BROADCAST_WORKER)KiCalibrateTimeAdjustment,
  375. (ULONG_PTR)(&Adjust));
  376. return TRUE;
  377. }
  378. }
  379. VOID
  380. KiCalibrateTimeAdjustment (
  381. PADJUST_INTERRUPT_TIME_CONTEXT Adjust
  382. )
  383. /*++
  384. Routine Description:
  385. Worker function to calibrate the adjustment of time on all processors.
  386. Arguments:
  387. Adjust - Supplies the operation context.
  388. Return Value:
  389. None.
  390. --*/
  391. {
  392. BOOLEAN Enable;
  393. LARGE_INTEGER InterruptTime;
  394. LARGE_INTEGER SetTime;
  395. LARGE_INTEGER PerfFreq;
  396. ULARGE_INTEGER li;
  397. LARGE_INTEGER NewTickCount;
  398. ULONG NewTickOffset;
  399. ULONG cl, divisor;
  400. LARGE_INTEGER PerfCount;
  401. //
  402. // As each processor arrives, subtract one off the remaining processor
  403. // count. If this is the last processor to arrive compute the time
  404. // change, and signal all processor when to apply the performance
  405. // counter change.
  406. //
  407. if (InterlockedDecrement((PLONG)&Adjust->KiNumber)) {
  408. Enable = KeDisableInterrupts();
  409. //
  410. // It is possible to deadlock here if one or more of the
  411. // other processors gets and processes a freeze request
  412. // while this processor has interrupts disabled. Poll
  413. // for IPI_FREEZE requests until all processors are known
  414. // to be in this code and hence wont be requesting a
  415. // freeze.
  416. //
  417. do {
  418. KiPollFreezeExecution();
  419. } while (Adjust->KiNumber != (ULONG)-1);
  420. //
  421. // Wait to perform the time set
  422. //
  423. while (Adjust->Barrier) ;
  424. } else {
  425. //
  426. // Set timer expiration dpc to scan the timer queues once for any
  427. // expired timers.
  428. //
  429. KeRemoveQueueDpc (&KiTimerExpireDpc);
  430. KeInsertQueueDpc (&KiTimerExpireDpc, (PVOID) TIMER_TABLE_SIZE, NULL);
  431. //
  432. // Disable interrupts and indicate that this processor is now
  433. // in final portion of this code.
  434. //
  435. Enable = KeDisableInterrupts();
  436. InterlockedDecrement((PLONG) &Adjust->KiNumber);
  437. //
  438. // Adjust Interrupt Time.
  439. //
  440. InterruptTime.QuadPart = KeQueryInterruptTime() + Adjust->Adjustment;
  441. SetTime.QuadPart = Adjust->Adjustment;
  442. //
  443. // Get the current times
  444. //
  445. PerfCount = KeQueryPerformanceCounter (&PerfFreq);
  446. //
  447. // Compute performance counter for current SetTime
  448. //
  449. //
  450. // Multiply SetTime * PerfCount and obtain 96bit result
  451. // in cl, li.LowPart, li.HighPart. Then divide the 96bit
  452. // result by 10,000,000 to get new performance counter value.
  453. //
  454. li.QuadPart = RtlEnlargedUnsignedMultiply (
  455. (ULONG) SetTime.LowPart,
  456. (ULONG) PerfFreq.LowPart
  457. ).QuadPart;
  458. cl = li.LowPart;
  459. li.QuadPart = li.HighPart +
  460. RtlEnlargedUnsignedMultiply (
  461. (ULONG) SetTime.LowPart,
  462. (ULONG) PerfFreq.HighPart
  463. ).QuadPart;
  464. li.QuadPart = li.QuadPart +
  465. RtlEnlargedUnsignedMultiply (
  466. (ULONG) SetTime.HighPart,
  467. (ULONG) PerfFreq.LowPart
  468. ).QuadPart;
  469. li.HighPart = li.HighPart + SetTime.HighPart * PerfFreq.HighPart;
  470. divisor = 10000000;
  471. Adjust->NewCount.HighPart =
  472. RtlEnlargedUnsignedDivide (
  473. li,
  474. divisor,
  475. &li.HighPart
  476. );
  477. li.LowPart = cl;
  478. Adjust->NewCount.LowPart =
  479. RtlEnlargedUnsignedDivide (
  480. li,
  481. divisor,
  482. NULL
  483. );
  484. Adjust->NewCount.QuadPart += PerfCount.QuadPart;
  485. //
  486. // Compute tick count and tick offset for current InterruptTime
  487. //
  488. NewTickCount = RtlExtendedLargeIntegerDivide(
  489. InterruptTime,
  490. KeMaximumIncrement,
  491. &NewTickOffset
  492. );
  493. //
  494. // Apply changes to InterruptTime, TickCount, TickOffset, and the
  495. // performance counter
  496. //
  497. KiTickOffset = KeMaximumIncrement - NewTickOffset;
  498. KeInterruptTimeBias += Adjust->Adjustment;
  499. SharedUserData->TickCountLow = NewTickCount.LowPart;
  500. #if defined(_AMD64_) || defined(_IA64_)
  501. KeTickCount = NewTickCount;
  502. #else
  503. KeTickCount.High2Time = NewTickCount.HighPart;
  504. KeTickCount.LowPart = NewTickCount.LowPart;
  505. KeTickCount.High1Time = NewTickCount.HighPart;
  506. #endif
  507. SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart;
  508. SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart;
  509. SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart;
  510. //
  511. // Apply the performance counter change
  512. //
  513. Adjust->Barrier = 0;
  514. }
  515. HalCalibratePerformanceCounter (
  516. (LONG volatile *) &Adjust->HalNumber,
  517. (ULONGLONG) Adjust->NewCount.QuadPart
  518. );
  519. KeEnableInterrupts(Enable);
  520. }
  521. VOID
  522. KeSetTimeIncrement (
  523. IN ULONG MaximumIncrement,
  524. IN ULONG MinimumIncrement
  525. )
  526. /*++
  527. Routine Description:
  528. This function sets the time increment value in 100ns units. This
  529. value is added to the system time at each interval clock interrupt.
  530. Arguments:
  531. MaximumIncrement - Supplies the maximum time between clock interrupts
  532. in 100ns units supported by the host HAL.
  533. MinimumIncrement - Supplies the minimum time between clock interrupts
  534. in 100ns units supported by the host HAL.
  535. Return Value:
  536. None.
  537. --*/
  538. {
  539. KeMaximumIncrement = MaximumIncrement;
  540. KeMinimumIncrement = max(MinimumIncrement, 10 * 1000);
  541. KeTimeAdjustment = MaximumIncrement;
  542. KeTimeIncrement = MaximumIncrement;
  543. KiTickOffset = MaximumIncrement;
  544. }
  545. BOOLEAN
  546. KeAddSystemServiceTable(
  547. IN PULONG_PTR Base,
  548. IN PULONG Count OPTIONAL,
  549. IN ULONG Limit,
  550. IN PUCHAR Number,
  551. IN ULONG Index
  552. )
  553. /*++
  554. Routine Description:
  555. This function allows the caller to add a system service table
  556. to the system
  557. Arguments:
  558. Base - Supplies the address of the system service table dispatch
  559. table.
  560. Count - Supplies an optional pointer to a table of per system service
  561. counters.
  562. Limit - Supplies the limit of the service table. Services greater
  563. than or equal to this limit will fail.
  564. Arguments - Supplies the address of the argument count table.
  565. Index - Supplies index of the service table.
  566. Return Value:
  567. TRUE - The operation was successful.
  568. FALSE - the operation failed. A service table is already bound to
  569. the specified location, or the specified index is larger than
  570. the maximum allowed index.
  571. --*/
  572. {
  573. PAGED_CODE();
  574. //
  575. // If a system service table is already defined for the specified
  576. // index, then return FALSE. Otherwise, establish the new system
  577. // service table.
  578. //
  579. if ((Index > NUMBER_SERVICE_TABLES - 1) ||
  580. (KeServiceDescriptorTable[Index].Base != NULL) ||
  581. (KeServiceDescriptorTableShadow[Index].Base != NULL)) {
  582. return FALSE;
  583. } else {
  584. //
  585. // If the service table index is equal to the Win32 table, then
  586. // only update the shadow system service table. Otherwise, both
  587. // the shadow and static system service tables are updated.
  588. //
  589. KeServiceDescriptorTableShadow[Index].Base = Base;
  590. KeServiceDescriptorTableShadow[Index].Count = Count;
  591. KeServiceDescriptorTableShadow[Index].Limit = Limit;
  592. //
  593. // The global pointer associated with the table base is
  594. // placed just before the service table.
  595. //
  596. #if defined(_IA64_)
  597. KeServiceDescriptorTableShadow[Index].TableBaseGpOffset =
  598. (LONG)(*(Base-1) - (ULONG_PTR)Base);
  599. #endif
  600. KeServiceDescriptorTableShadow[Index].Number = Number;
  601. if (Index != 1) {
  602. KeServiceDescriptorTable[Index].Base = Base;
  603. KeServiceDescriptorTable[Index].Count = Count;
  604. KeServiceDescriptorTable[Index].Limit = Limit;
  605. #if defined(_IA64_)
  606. KeServiceDescriptorTable[Index].TableBaseGpOffset =
  607. (LONG)(*(Base-1) - (ULONG_PTR)Base);
  608. #endif
  609. KeServiceDescriptorTable[Index].Number = Number;
  610. }
  611. return TRUE;
  612. }
  613. }
  614. BOOLEAN
  615. KeRemoveSystemServiceTable(
  616. IN ULONG Index
  617. )
  618. /*++
  619. Routine Description:
  620. This function allows the caller to remove a system service table
  621. from the system. This can only be called at system shutdown.
  622. Arguments:
  623. Index - Supplies index of the service table.
  624. Return Value:
  625. TRUE - The operation was successful.
  626. FALSE - the operation failed. A service table is is not bound or is illegal to remove
  627. --*/
  628. {
  629. PAGED_CODE();
  630. if ((Index > NUMBER_SERVICE_TABLES - 1) ||
  631. ((KeServiceDescriptorTable[Index].Base == NULL) &&
  632. (KeServiceDescriptorTableShadow[Index].Base == NULL))) {
  633. return FALSE;
  634. } else {
  635. KeServiceDescriptorTableShadow[Index].Base = NULL;
  636. KeServiceDescriptorTableShadow[Index].Count = 0;
  637. KeServiceDescriptorTableShadow[Index].Limit = 0;
  638. #if defined(_IA64_)
  639. KeServiceDescriptorTableShadow[Index].TableBaseGpOffset = 0;
  640. #endif
  641. KeServiceDescriptorTableShadow[Index].Number = 0;
  642. if (Index != 1) {
  643. KeServiceDescriptorTable[Index].Base = NULL;
  644. KeServiceDescriptorTable[Index].Count = 0;
  645. KeServiceDescriptorTable[Index].Limit = 0;
  646. #if defined(_IA64_)
  647. KeServiceDescriptorTable[Index].TableBaseGpOffset = 0;
  648. #endif
  649. KeServiceDescriptorTable[Index].Number = 0;
  650. }
  651. return TRUE;
  652. }
  653. }
  654. VOID
  655. FASTCALL
  656. KeSetTimeUpdateNotifyRoutine(
  657. IN PTIME_UPDATE_NOTIFY_ROUTINE NotifyRoutine
  658. )
  659. /*++
  660. Routine Description:
  661. This function sets the address of a callout routine which will be called
  662. each time the runtime for a thread is updated.
  663. Arguments:
  664. RoutineNotify - Supplies the address of the time update notify callout
  665. routine.
  666. Return Value:
  667. None.
  668. --*/
  669. {
  670. PAGED_CODE();
  671. KiTimeUpdateNotifyRoutine = NotifyRoutine;
  672. return;
  673. }
  674. KAFFINITY
  675. KeQueryActiveProcessors(
  676. VOID
  677. )
  678. /*++
  679. Routine Description:
  680. This function returns the current set of active processors
  681. in the system.
  682. Arguments:
  683. None.
  684. Return Value:
  685. KAFFINITY bitmask representing the set of active processors
  686. --*/
  687. {
  688. PAGED_CODE();
  689. return(KeActiveProcessors);
  690. }
  691. #undef KeIsAttachedProcess
  692. BOOLEAN
  693. KeIsAttachedProcess(
  694. VOID
  695. )
  696. /*++
  697. Routine Description:
  698. This function determines if the current thread is attached to a process.
  699. Arguments:
  700. None.
  701. Return Value:
  702. TRUE is returned if the current thread is attached to a process. Otherwise,
  703. FALSE is returned.
  704. --*/
  705. {
  706. return KiIsAttachedProcess();
  707. }
  708. #undef KeAreApcsDisabled
  709. BOOLEAN
  710. KeAreApcsDisabled(
  711. VOID
  712. )
  713. /*++
  714. Routine Description:
  715. This function determines if APCs are disabled for the current thread.
  716. Arguments:
  717. None.
  718. Return Value:
  719. TRUE is returned if APCs are disabled for the current thread. Otherwise,
  720. FALE is returned.
  721. --*/
  722. {
  723. return KeGetCurrentThread()->KernelApcDisable != 0;
  724. }
  725. ULONG
  726. KeGetRecommendedSharedDataAlignment (
  727. VOID
  728. )
  729. /*++
  730. Routine Description:
  731. This function returns the size of the largest cache line in the system.
  732. This value should be used as a recommended alignment / granularity for
  733. shared data.
  734. Arguments:
  735. None.
  736. Return Value:
  737. The size of the largest cache line in the system is returned as the
  738. function value.
  739. --*/
  740. {
  741. return KeLargestCacheLine;
  742. }
  743. PKPRCB
  744. KeGetPrcb(
  745. ULONG ProcessorNumber
  746. )
  747. /*++
  748. Routine Description:
  749. This function returns the address of the Processor Control Block (PRCB)
  750. for the specified processor.
  751. Arguments:
  752. ProcessorNumber - Supplies the number of the processor the PRCB
  753. is to be returned for.
  754. Return Value:
  755. Returns the address of the requested PRCB or NULL if ProcessorNumber
  756. is not valid.
  757. --*/
  758. {
  759. ASSERT(ProcessorNumber < MAXIMUM_PROCESSORS);
  760. if (ProcessorNumber < (ULONG)KeNumberProcessors) {
  761. return KiProcessorBlock[ProcessorNumber];
  762. }
  763. return NULL;
  764. }
  765. NTSTATUS
  766. KeCopySafe(
  767. VOID UNALIGNED *Destination,
  768. CONST VOID UNALIGNED *Source,
  769. SIZE_T Length
  770. )
  771. /*++
  772. Routine Description:
  773. This function attempts to safely copy a block of memory. If an excpetion occurs the
  774. exception status is returned.
  775. Arguments:
  776. Destination - Supplies a pointer to the destination memory.
  777. Source - Supplies a pointer to the source memory.
  778. Length - Supplies the size of memory in bytes to be copied.
  779. Return Value:
  780. Return the status of the copy.
  781. --*/
  782. {
  783. NTSTATUS Status = STATUS_SUCCESS;
  784. try {
  785. RtlCopyMemory(Destination, Source, Length);
  786. } __except(EXCEPTION_EXECUTE_HANDLER) {
  787. Status = _exception_code();
  788. }
  789. return Status;
  790. }