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.

1456 lines
34 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, KeQueryActiveProcessors)
  17. #pragma alloc_text(PAGE, KeQueryLogicalProcessorInformation)
  18. #pragma alloc_text(PAGELK, KiCalibrateTimeAdjustment)
  19. #if !defined(_AMD64_)
  20. ULONGLONG
  21. KeQueryInterruptTime (
  22. VOID
  23. )
  24. /*++
  25. Routine Description:
  26. This function returns the current interrupt time by determining when the
  27. time is stable and then returning its value.
  28. Arguments:
  29. CurrentTime - Supplies a pointer to a variable that will receive the
  30. current system time.
  31. Return Value:
  32. None.
  33. --*/
  34. {
  35. LARGE_INTEGER CurrentTime;
  36. KiQueryInterruptTime(&CurrentTime);
  37. return CurrentTime.QuadPart;
  38. }
  39. VOID
  40. KeQuerySystemTime (
  41. OUT PLARGE_INTEGER CurrentTime
  42. )
  43. /*++
  44. Routine Description:
  45. This function returns the current system time by determining when the
  46. time is stable and then returning its value.
  47. Arguments:
  48. CurrentTime - Supplies a pointer to a variable that will receive the
  49. current system time.
  50. Return Value:
  51. None.
  52. --*/
  53. {
  54. KiQuerySystemTime(CurrentTime);
  55. return;
  56. }
  57. VOID
  58. KeQueryTickCount (
  59. OUT PLARGE_INTEGER CurrentCount
  60. )
  61. /*++
  62. Routine Description:
  63. This function returns the current tick count by determining when the
  64. count is stable and then returning its value.
  65. Arguments:
  66. CurrentCount - Supplies a pointer to a variable that will receive the
  67. current tick count.
  68. Return Value:
  69. None.
  70. --*/
  71. {
  72. KiQueryTickCount(CurrentCount);
  73. return;
  74. }
  75. #endif
  76. ULONG
  77. KeQueryTimeIncrement (
  78. VOID
  79. )
  80. /*++
  81. Routine Description:
  82. This function returns the time increment value in 100ns units. This
  83. is the value that is added to the system time at each interval clock
  84. interrupt.
  85. Arguments:
  86. None.
  87. Return Value:
  88. The time increment value is returned as the function value.
  89. --*/
  90. {
  91. return KeMaximumIncrement;
  92. }
  93. VOID
  94. KeEnableInterrupts (
  95. IN BOOLEAN Enable
  96. )
  97. /*++
  98. Routine Description:
  99. This function enables interrupts based on the specified enable state.
  100. Arguments:
  101. Enable - Supplies a boolean value that determines whether interrupts
  102. are to be enabled.
  103. Return Value:
  104. None.
  105. --*/
  106. {
  107. if (Enable != FALSE) {
  108. _enable();
  109. }
  110. return;
  111. }
  112. VOID
  113. KeSetDmaIoCoherency (
  114. IN ULONG Attributes
  115. )
  116. /*++
  117. Routine Description:
  118. This function sets (enables/disables) DMA I/O coherency with data
  119. caches.
  120. Arguments:
  121. Attributes - Supplies the set of DMA I/O coherency attributes for
  122. the host system.
  123. Return Value:
  124. None.
  125. --*/
  126. {
  127. KiDmaIoCoherency = Attributes;
  128. }
  129. #if defined(_AMD64_) || defined(_X86_)
  130. #pragma alloc_text(INIT, KeSetProfileIrql)
  131. VOID
  132. KeSetProfileIrql (
  133. IN KIRQL ProfileIrql
  134. )
  135. /*++
  136. Routine Description:
  137. This function sets the profile IRQL.
  138. N.B. There are only two valid values for the profile IRQL which are
  139. PROFILE_LEVEL and HIGH_LEVEL.
  140. Arguments:
  141. Irql - Supplies the synchronization IRQL value.
  142. Return Value:
  143. None.
  144. --*/
  145. {
  146. ASSERT((ProfileIrql == PROFILE_LEVEL) || (ProfileIrql == HIGH_LEVEL));
  147. KiProfileIrql = ProfileIrql;
  148. }
  149. #endif
  150. VOID
  151. KeSetSystemTime (
  152. IN PLARGE_INTEGER NewTime,
  153. OUT PLARGE_INTEGER OldTime,
  154. IN BOOLEAN AdjustInterruptTime,
  155. IN PLARGE_INTEGER HalTimeToSet OPTIONAL
  156. )
  157. /*++
  158. Routine Description:
  159. This function sets the system time to the specified value and updates
  160. timer queue entries to reflect the difference between the old system
  161. time and the new system time.
  162. Arguments:
  163. NewTime - Supplies a pointer to a variable that specifies the new system
  164. time.
  165. OldTime - Supplies a pointer to a variable that will receive the previous
  166. system time.
  167. AdjustInterruptTime - If TRUE the amount of time being adjusted is
  168. also applied to InterruptTime and TickCount.
  169. HalTimeToSet - Supplies an optional time that if specified is to be used
  170. to set the time in the realtime clock.
  171. Return Value:
  172. None.
  173. --*/
  174. {
  175. LIST_ENTRY AbsoluteListHead;
  176. LIST_ENTRY ExpiredListHead;
  177. ULONG Index;
  178. PLIST_ENTRY ListHead;
  179. PLIST_ENTRY NextEntry;
  180. KIRQL OldIrql1;
  181. KIRQL OldIrql2;
  182. LARGE_INTEGER TimeDelta;
  183. TIME_FIELDS TimeFields;
  184. PKTIMER Timer;
  185. ASSERT((NewTime->HighPart & 0xf0000000) == 0);
  186. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  187. //
  188. // If a realtime clock value is specified, then convert the time value
  189. // to time fields.
  190. //
  191. if (ARGUMENT_PRESENT(HalTimeToSet)) {
  192. RtlTimeToTimeFields(HalTimeToSet, &TimeFields);
  193. }
  194. //
  195. // Set affinity to the processor that keeps the system time, raise IRQL
  196. // to dispatcher level and lock the dispatcher database, then raise IRQL
  197. // to HIGH_LEVEL to synchronize with the clock interrupt routine.
  198. //
  199. KeSetSystemAffinityThread((KAFFINITY)1);
  200. KiLockDispatcherDatabase(&OldIrql1);
  201. KeRaiseIrql(HIGH_LEVEL, &OldIrql2);
  202. //
  203. // Save the previous system time, set the new system time, and set
  204. // the realtime clock, if a time value is specified.
  205. //
  206. KiQuerySystemTime(OldTime);
  207. SharedUserData->SystemTime.High2Time = NewTime->HighPart;
  208. SharedUserData->SystemTime.LowPart = NewTime->LowPart;
  209. SharedUserData->SystemTime.High1Time = NewTime->HighPart;
  210. if (ARGUMENT_PRESENT(HalTimeToSet)) {
  211. ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
  212. }
  213. //
  214. // Compute the difference between the previous system time and the new
  215. // system time.
  216. //
  217. TimeDelta.QuadPart = NewTime->QuadPart - OldTime->QuadPart;
  218. //
  219. // Update the boot time to reflect the delta. This keeps time based
  220. // on boot time constant
  221. //
  222. KeBootTime.QuadPart = KeBootTime.QuadPart + TimeDelta.QuadPart;
  223. //
  224. // Track the overall bias applied to the boot time.
  225. //
  226. KeBootTimeBias = KeBootTimeBias + TimeDelta.QuadPart;
  227. //
  228. // Lower IRQL to dispatch level and if needed adjust the physical
  229. // system interrupt time.
  230. //
  231. KeLowerIrql(OldIrql2);
  232. if (AdjustInterruptTime) {
  233. //
  234. // Adjust the physical time of the system
  235. //
  236. AdjustInterruptTime = KeAdjustInterruptTime (TimeDelta.QuadPart);
  237. }
  238. //
  239. // If the physical interrupt time of the system was not adjusted,
  240. // recompute any absolute timers in the system for the new
  241. // system time.
  242. //
  243. if (!AdjustInterruptTime) {
  244. //
  245. // Remove all absolute timers from the timer queue so their due time
  246. // can be recomputed.
  247. //
  248. InitializeListHead(&AbsoluteListHead);
  249. for (Index = 0; Index < TIMER_TABLE_SIZE; Index += 1) {
  250. ListHead = &KiTimerTableListHead[Index];
  251. NextEntry = ListHead->Flink;
  252. while (NextEntry != ListHead) {
  253. Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
  254. NextEntry = NextEntry->Flink;
  255. if (Timer->Header.Absolute != FALSE) {
  256. RemoveEntryList(&Timer->TimerListEntry);
  257. InsertTailList(&AbsoluteListHead, &Timer->TimerListEntry);
  258. }
  259. }
  260. }
  261. //
  262. // Recompute the due time and reinsert all absolute timers in the timer
  263. // tree. If a timer has already expired, then insert the timer in the
  264. // expired timer list.
  265. //
  266. InitializeListHead(&ExpiredListHead);
  267. while (AbsoluteListHead.Flink != &AbsoluteListHead) {
  268. Timer = CONTAINING_RECORD(AbsoluteListHead.Flink, KTIMER, TimerListEntry);
  269. KiRemoveTreeTimer(Timer);
  270. Timer->DueTime.QuadPart -= TimeDelta.QuadPart;
  271. if (KiReinsertTreeTimer(Timer, Timer->DueTime) == FALSE) {
  272. Timer->Header.Inserted = TRUE;
  273. InsertTailList(&ExpiredListHead, &Timer->TimerListEntry);
  274. }
  275. }
  276. //
  277. // If any of the attempts to reinsert a timer failed, then timers have
  278. // already expired and must be processed.
  279. //
  280. // N.B. The following function returns with the dispatcher database
  281. // unlocked.
  282. //
  283. KiTimerListExpire(&ExpiredListHead, OldIrql1);
  284. } else {
  285. KiUnlockDispatcherDatabase(OldIrql1);
  286. }
  287. //
  288. // Set affinity back to its original value.
  289. //
  290. KeRevertToUserAffinityThread();
  291. return;
  292. }
  293. BOOLEAN
  294. KeAdjustInterruptTime (
  295. IN LONGLONG TimeDelta
  296. )
  297. /*++
  298. Routine Description:
  299. This function moves the physical interrupt time of the system foreward by
  300. the specified time delta after a system wake has occurred.
  301. Arguments:
  302. TimeDelta - Supplies the time delta to be added to the interrupt time, tick
  303. count and the perforamnce counter in 100ns units.
  304. Return Value:
  305. None.
  306. --*/
  307. {
  308. ADJUST_INTERRUPT_TIME_CONTEXT Adjust;
  309. //
  310. // Time can only be moved forward.
  311. //
  312. if (TimeDelta < 0) {
  313. return FALSE;
  314. } else {
  315. Adjust.KiNumber = KeNumberProcessors;
  316. Adjust.HalNumber = KeNumberProcessors;
  317. Adjust.Adjustment = (ULONGLONG) TimeDelta;
  318. Adjust.Barrier = 1;
  319. KeIpiGenericCall((PKIPI_BROADCAST_WORKER)KiCalibrateTimeAdjustment,
  320. (ULONG_PTR)(&Adjust));
  321. return TRUE;
  322. }
  323. }
  324. VOID
  325. KiCalibrateTimeAdjustment (
  326. PADJUST_INTERRUPT_TIME_CONTEXT Adjust
  327. )
  328. /*++
  329. Routine Description:
  330. This function calibrates the adjustment of time on all processors.
  331. Arguments:
  332. Adjust - Supplies the operation context.
  333. Return Value:
  334. None.
  335. --*/
  336. {
  337. ULONG cl;
  338. ULONG divisor;
  339. BOOLEAN Enable;
  340. LARGE_INTEGER InterruptTime;
  341. ULARGE_INTEGER li;
  342. LARGE_INTEGER NewTickCount;
  343. ULONG NewTickOffset;
  344. LARGE_INTEGER PerfCount;
  345. LARGE_INTEGER PerfFreq;
  346. LARGE_INTEGER SetTime;
  347. //
  348. // As each processor arrives, decrement the remaining processor count. If
  349. // this is the last processor to arrive, then compute the time change, and
  350. // signal all processor when to apply the performance counter change.
  351. //
  352. if (InterlockedDecrement((PLONG)&Adjust->KiNumber)) {
  353. Enable = KeDisableInterrupts();
  354. //
  355. // It is possible to deadlock here if one or more of the
  356. // other processors gets and processes a freeze request
  357. // while this processor has interrupts disabled. Poll
  358. // for IPI_FREEZE requests until all processors are known
  359. // to be in this code and hence wont be requesting a
  360. // freeze.
  361. //
  362. do {
  363. KiPollFreezeExecution();
  364. } while (Adjust->KiNumber != (ULONG)-1);
  365. //
  366. // Wait to perform the time set
  367. //
  368. while (Adjust->Barrier) ;
  369. } else {
  370. //
  371. // Set timer expiration dpc to scan the timer queues once for any
  372. // expired timers.
  373. //
  374. KeRemoveQueueDpc(&KiTimerExpireDpc);
  375. KeInsertQueueDpc(&KiTimerExpireDpc,
  376. ULongToPtr(KiQueryLowTickCount() - TIMER_TABLE_SIZE),
  377. NULL);
  378. //
  379. // Disable interrupts and indicate that this processor is now
  380. // in final portion of this code.
  381. //
  382. Enable = KeDisableInterrupts();
  383. InterlockedDecrement((PLONG) &Adjust->KiNumber);
  384. //
  385. // Adjust Interrupt Time.
  386. //
  387. InterruptTime.QuadPart = KeQueryInterruptTime() + Adjust->Adjustment;
  388. SetTime.QuadPart = Adjust->Adjustment;
  389. //
  390. // Get the current times
  391. //
  392. PerfCount = KeQueryPerformanceCounter(&PerfFreq);
  393. //
  394. // Compute performance counter for current SetTime
  395. //
  396. //
  397. // Multiply SetTime * PerfCount and obtain 96bit result
  398. // in cl, li.LowPart, li.HighPart. Then divide the 96bit
  399. // result by 10,000,000 to get new performance counter value.
  400. //
  401. li.QuadPart = RtlEnlargedUnsignedMultiply((ULONG)SetTime.LowPart,
  402. (ULONG)PerfFreq.LowPart).QuadPart;
  403. cl = li.LowPart;
  404. li.QuadPart =
  405. li.HighPart + RtlEnlargedUnsignedMultiply((ULONG)SetTime.LowPart,
  406. (ULONG)PerfFreq.HighPart).QuadPart;
  407. li.QuadPart =
  408. li.QuadPart + RtlEnlargedUnsignedMultiply((ULONG)SetTime.HighPart,
  409. (ULONG)PerfFreq.LowPart).QuadPart;
  410. li.HighPart = li.HighPart + SetTime.HighPart * PerfFreq.HighPart;
  411. divisor = 10000000;
  412. Adjust->NewCount.HighPart = RtlEnlargedUnsignedDivide(li,
  413. divisor,
  414. &li.HighPart);
  415. li.LowPart = cl;
  416. Adjust->NewCount.LowPart = RtlEnlargedUnsignedDivide(li,
  417. divisor,
  418. NULL);
  419. Adjust->NewCount.QuadPart += PerfCount.QuadPart;
  420. //
  421. // Compute tick count and tick offset for current InterruptTime
  422. //
  423. NewTickCount = RtlExtendedLargeIntegerDivide(InterruptTime,
  424. KeMaximumIncrement,
  425. &NewTickOffset);
  426. //
  427. // Apply changes to InterruptTime, TickCount, TickOffset, and the
  428. // performance counter.
  429. //
  430. KiTickOffset = KeMaximumIncrement - NewTickOffset;
  431. KeInterruptTimeBias += Adjust->Adjustment;
  432. SharedUserData->TickCount.High2Time = NewTickCount.HighPart;
  433. #if defined(_WIN64)
  434. SharedUserData->TickCountQuad = NewTickCount.QuadPart;
  435. #else
  436. SharedUserData->TickCount.LowPart = NewTickCount.LowPart;
  437. SharedUserData->TickCount.High1Time = NewTickCount.HighPart;
  438. #endif
  439. #if defined(_IA64_)
  440. KeTickCount = NewTickCount;
  441. #elif defined(_X86_)
  442. KeTickCount.High2Time = NewTickCount.HighPart;
  443. KeTickCount.LowPart = NewTickCount.LowPart;
  444. KeTickCount.High1Time = NewTickCount.HighPart;
  445. #endif
  446. SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart;
  447. SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart;
  448. SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart;
  449. //
  450. // Apply the performance counter change.
  451. //
  452. Adjust->Barrier = 0;
  453. }
  454. HalCalibratePerformanceCounter((LONG volatile *)&Adjust->HalNumber,
  455. (ULONGLONG) Adjust->NewCount.QuadPart);
  456. KeEnableInterrupts(Enable);
  457. }
  458. VOID
  459. KeSetTimeIncrement (
  460. IN ULONG MaximumIncrement,
  461. IN ULONG MinimumIncrement
  462. )
  463. /*++
  464. Routine Description:
  465. This function sets the time increment value in 100ns units. This
  466. value is added to the system time at each interval clock interrupt.
  467. Arguments:
  468. MaximumIncrement - Supplies the maximum time between clock interrupts
  469. in 100ns units supported by the host HAL.
  470. MinimumIncrement - Supplies the minimum time between clock interrupts
  471. in 100ns units supported by the host HAL.
  472. Return Value:
  473. None.
  474. --*/
  475. {
  476. KeMaximumIncrement = MaximumIncrement;
  477. KeMinimumIncrement = max(MinimumIncrement, 10 * 1000);
  478. KeTimeAdjustment = MaximumIncrement;
  479. KeTimeIncrement = MaximumIncrement;
  480. KiTickOffset = MaximumIncrement;
  481. #if defined(_IA64_)
  482. KiMaxIntervalPerTimerInterrupt = MaximumIncrement * (TIMER_TABLE_SIZE - 1);
  483. #endif
  484. }
  485. BOOLEAN
  486. KeAddSystemServiceTable(
  487. IN PULONG_PTR Base,
  488. IN PULONG Count OPTIONAL,
  489. IN ULONG Limit,
  490. IN PUCHAR Number,
  491. IN ULONG Index
  492. )
  493. /*++
  494. Routine Description:
  495. This function allows the caller to add a system service table
  496. to the system
  497. Arguments:
  498. Base - Supplies the address of the system service table dispatch
  499. table.
  500. Count - Supplies an optional pointer to a table of per system service
  501. counters.
  502. Limit - Supplies the limit of the service table. Services greater
  503. than or equal to this limit will fail.
  504. Arguments - Supplies the address of the argument count table.
  505. Index - Supplies index of the service table.
  506. Return Value:
  507. TRUE - The operation was successful.
  508. FALSE - the operation failed. A service table is already bound to
  509. the specified location, or the specified index is larger than
  510. the maximum allowed index.
  511. --*/
  512. {
  513. PAGED_CODE();
  514. //
  515. // If a system service table is already defined for the specified
  516. // index, then return FALSE. Otherwise, establish the new system
  517. // service table.
  518. //
  519. if ((Index > NUMBER_SERVICE_TABLES - 1) ||
  520. (KeServiceDescriptorTable[Index].Base != NULL) ||
  521. (KeServiceDescriptorTableShadow[Index].Base != NULL)) {
  522. return FALSE;
  523. } else {
  524. //
  525. // If the service table index is equal to the Win32 table, then
  526. // only update the shadow system service table. Otherwise, both
  527. // the shadow and static system service tables are updated.
  528. //
  529. KeServiceDescriptorTableShadow[Index].Base = Base;
  530. KeServiceDescriptorTableShadow[Index].Count = Count;
  531. KeServiceDescriptorTableShadow[Index].Limit = Limit;
  532. //
  533. // The global pointer associated with the table base is
  534. // placed just before the service table.
  535. //
  536. #if defined(_IA64_)
  537. KeServiceDescriptorTableShadow[Index].TableBaseGpOffset =
  538. (LONG)(*(Base-1) - (ULONG_PTR)Base);
  539. #endif
  540. KeServiceDescriptorTableShadow[Index].Number = Number;
  541. if (Index != 1) {
  542. KeServiceDescriptorTable[Index].Base = Base;
  543. KeServiceDescriptorTable[Index].Count = Count;
  544. KeServiceDescriptorTable[Index].Limit = Limit;
  545. #if defined(_IA64_)
  546. KeServiceDescriptorTable[Index].TableBaseGpOffset =
  547. (LONG)(*(Base-1) - (ULONG_PTR)Base);
  548. #endif
  549. KeServiceDescriptorTable[Index].Number = Number;
  550. }
  551. return TRUE;
  552. }
  553. }
  554. BOOLEAN
  555. KeRemoveSystemServiceTable(
  556. IN ULONG Index
  557. )
  558. /*++
  559. Routine Description:
  560. This function allows the caller to remove a system service table
  561. from the system. This can only be called at system shutdown.
  562. Arguments:
  563. Index - Supplies index of the service table.
  564. Return Value:
  565. TRUE - The operation was successful.
  566. FALSE - the operation failed. A service table is is not bound or is illegal to remove
  567. --*/
  568. {
  569. PAGED_CODE();
  570. if ((Index > NUMBER_SERVICE_TABLES - 1) ||
  571. ((KeServiceDescriptorTable[Index].Base == NULL) &&
  572. (KeServiceDescriptorTableShadow[Index].Base == NULL))) {
  573. return FALSE;
  574. } else {
  575. KeServiceDescriptorTableShadow[Index].Base = NULL;
  576. KeServiceDescriptorTableShadow[Index].Count = 0;
  577. KeServiceDescriptorTableShadow[Index].Limit = 0;
  578. #if defined(_IA64_)
  579. KeServiceDescriptorTableShadow[Index].TableBaseGpOffset = 0;
  580. #endif
  581. KeServiceDescriptorTableShadow[Index].Number = 0;
  582. if (Index != 1) {
  583. KeServiceDescriptorTable[Index].Base = NULL;
  584. KeServiceDescriptorTable[Index].Count = 0;
  585. KeServiceDescriptorTable[Index].Limit = 0;
  586. #if defined(_IA64_)
  587. KeServiceDescriptorTable[Index].TableBaseGpOffset = 0;
  588. #endif
  589. KeServiceDescriptorTable[Index].Number = 0;
  590. }
  591. return TRUE;
  592. }
  593. }
  594. KAFFINITY
  595. KeQueryActiveProcessors(
  596. VOID
  597. )
  598. /*++
  599. Routine Description:
  600. This function returns the current set of active processors
  601. in the system.
  602. Arguments:
  603. None.
  604. Return Value:
  605. KAFFINITY bitmask representing the set of active processors
  606. --*/
  607. {
  608. PAGED_CODE();
  609. return(KeActiveProcessors);
  610. }
  611. NTSTATUS
  612. KeQueryLogicalProcessorInformation(
  613. OUT PVOID SystemInformation,
  614. IN ULONG SystemInformationLength,
  615. OUT PULONG ReturnedLength
  616. )
  617. /*++
  618. Routine Description:
  619. This function returns information about the logical processors in
  620. the system and is invoked via NtQuerySystemInformation. It runs
  621. in an existing try/except block.
  622. A group of structures will be written to the output
  623. buffer describing groups of logical processors, and the
  624. relationship between them.
  625. Currently it returns information about the logical processors that
  626. are produced by individual processor cores and the logical
  627. processors associated with individual NUMA nodes. The former
  628. makes it possible for an application to understand the
  629. relationship between logical processors and physical processors in
  630. hyperthreading scenarios which supports some licensing and
  631. performance optimization scenarios.
  632. This function may be extended in the future to support multicore
  633. processors and platform caches.
  634. Arguments:
  635. SystemInformation - A pointer to a buffer which receives the
  636. specified information. The buffer will be will be filled by
  637. this function with SYSTEM_LOGICAL_PROCESSOR_INFORMATION
  638. structures.
  639. SystemInformationLength - Specifies the length in bytes of the system
  640. information buffer.
  641. ReturnLength - A pointer which receives the number of bytes necessary to
  642. return all of the information records available.
  643. Return Value:
  644. NTSTATUS
  645. --*/
  646. {
  647. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Output;
  648. KAFFINITY ActiveProcessors;
  649. KAFFINITY Mask;
  650. PKPRCB Prcb;
  651. NTSTATUS Status = STATUS_SUCCESS;
  652. ULONG CurrentLength;
  653. ULONG i;
  654. UCHAR Flags;
  655. #if defined(KE_MULTINODE)
  656. PKNODE Node;
  657. #endif
  658. PAGED_CODE();
  659. CurrentLength = 0;
  660. Output = SystemInformation;
  661. ActiveProcessors = KeActiveProcessors;
  662. i = 0;
  663. for (; ActiveProcessors; ActiveProcessors >>= 1 , i++) {
  664. if ((ActiveProcessors & 1) == 0) {
  665. continue;
  666. }
  667. Prcb = KiProcessorBlock[i];
  668. Flags = 0;
  669. #if defined(NT_SMT)
  670. //
  671. // Ignore logical processors that are not the master of their
  672. // thread set. As a result, only one PRCB per physical
  673. // processor will be further interrogated.
  674. //
  675. if (Prcb != Prcb->MultiThreadSetMaster) {
  676. continue;
  677. }
  678. Mask = Prcb->MultiThreadProcessorSet;
  679. //
  680. // Determine if this physical processor is exposing multiple
  681. // logical processors. If so, mark it as a SMT relationship.
  682. //
  683. if (Prcb->SetMember != Mask) {
  684. Flags = LTP_PC_SMT;
  685. }
  686. #else
  687. Mask = Prcb->SetMember;
  688. #endif
  689. CurrentLength += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  690. if (CurrentLength <= SystemInformationLength) {
  691. Output->ProcessorMask = Mask;
  692. Output->Relationship = RelationProcessorCore;
  693. Output->Reserved[0] = Output->Reserved[1] = 0;
  694. Output->ProcessorCore.Flags = Flags;
  695. Output++;
  696. } else {
  697. Status = STATUS_INFO_LENGTH_MISMATCH;
  698. }
  699. }
  700. //
  701. // Add records indicating the association of logical processors
  702. // with NUMA nodes.
  703. //
  704. #if defined(KE_MULTINODE)
  705. for (i = 0; i < KeNumberNodes; i++) {
  706. Node = KeNodeBlock[i];
  707. if (Node->ProcessorMask == 0) {
  708. continue;
  709. }
  710. CurrentLength += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  711. if (CurrentLength <= SystemInformationLength) {
  712. Output->ProcessorMask = Node->ProcessorMask;
  713. Output->Relationship = RelationNumaNode;
  714. Output->Reserved[0] = Output->Reserved[1] = 0;
  715. Output->NumaNode.NodeNumber = i;
  716. Output++;
  717. } else {
  718. Status = STATUS_INFO_LENGTH_MISMATCH;
  719. }
  720. }
  721. #else
  722. CurrentLength += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  723. if (CurrentLength <= SystemInformationLength) {
  724. Output->ProcessorMask = KeActiveProcessors;
  725. Output->Relationship = RelationNumaNode;
  726. Output->NumaNode.NodeNumber = 0;
  727. Output++;
  728. } else {
  729. Status = STATUS_INFO_LENGTH_MISMATCH;
  730. }
  731. #endif
  732. //
  733. // Additional topology information would be added here such as
  734. // multicore and platform caches.
  735. //
  736. //
  737. // Always return how long the buffer needed to be for the API to
  738. // be successful.
  739. //
  740. *ReturnedLength = CurrentLength;
  741. return Status;
  742. }
  743. #undef KeIsAttachedProcess
  744. BOOLEAN
  745. KeIsAttachedProcess(
  746. VOID
  747. )
  748. /*++
  749. Routine Description:
  750. This function determines if the current thread is attached to a process.
  751. Arguments:
  752. None.
  753. Return Value:
  754. TRUE is returned if the current thread is attached to a process. Otherwise,
  755. FALSE is returned.
  756. --*/
  757. {
  758. return KiIsAttachedProcess() ? TRUE : FALSE;
  759. }
  760. ULONG
  761. KeGetRecommendedSharedDataAlignment (
  762. VOID
  763. )
  764. /*++
  765. Routine Description:
  766. This function returns the size of the largest cache line in the system.
  767. This value should be used as a recommended alignment / granularity for
  768. shared data.
  769. Arguments:
  770. None.
  771. Return Value:
  772. The size of the largest cache line in the system is returned as the
  773. function value.
  774. --*/
  775. {
  776. return KeLargestCacheLine;
  777. }
  778. PKPRCB
  779. KeGetPrcb(
  780. ULONG ProcessorNumber
  781. )
  782. /*++
  783. Routine Description:
  784. This function returns the address of the Processor Control Block (PRCB)
  785. for the specified processor.
  786. Arguments:
  787. ProcessorNumber - Supplies the number of the processor the PRCB
  788. is to be returned for.
  789. Return Value:
  790. Returns the address of the requested PRCB or NULL if ProcessorNumber
  791. is not valid.
  792. --*/
  793. {
  794. ASSERT(ProcessorNumber < MAXIMUM_PROCESSORS);
  795. if (ProcessorNumber < (ULONG)KeNumberProcessors) {
  796. return KiProcessorBlock[ProcessorNumber];
  797. }
  798. return NULL;
  799. }
  800. NTSTATUS
  801. KeCopySafe(
  802. VOID UNALIGNED *Destination,
  803. CONST VOID UNALIGNED *Source,
  804. SIZE_T Length
  805. )
  806. /*++
  807. Routine Description:
  808. This function attempts to safely copy a block of memory. If an exception
  809. occurs the exception status is returned.
  810. Arguments:
  811. Destination - Supplies a pointer to the destination memory.
  812. Source - Supplies a pointer to the source memory.
  813. Length - Supplies the size of memory in bytes to be copied.
  814. Return Value:
  815. Return the status of the copy.
  816. --*/
  817. {
  818. NTSTATUS Status = STATUS_SUCCESS;
  819. try {
  820. RtlCopyMemory(Destination, Source, Length);
  821. } __except(EXCEPTION_EXECUTE_HANDLER) {
  822. Status = _exception_code();
  823. }
  824. return Status;
  825. }
  826. typedef struct _KNMI_HANDLER_CALLBACK {
  827. struct _KNMI_HANDLER_CALLBACK * Next;
  828. PNMI_CALLBACK Callback;
  829. PVOID Context;
  830. PVOID Handle;
  831. } KNMI_HANDLER_CALLBACK, *PKNMI_HANDLER_CALLBACK;
  832. PKNMI_HANDLER_CALLBACK KiNmiCallbackListHead;
  833. KSPIN_LOCK KiNmiCallbackListLock;
  834. BOOLEAN
  835. KiHandleNmi(
  836. VOID
  837. )
  838. /*++
  839. Routine Description:
  840. This routine is called to process the list of registered Non-Maskable-
  841. Interrupt (NMI) handlers in the system. This routine is called from
  842. the NMI interrupt vector, the IRQL is unknown and must be treated as
  843. if at HIGH_LEVEL. Neither this function or any called function can
  844. alter system IRQL.
  845. The list of handlers must be edited in such a way that it is always
  846. valid. This routine cannot acquire a lock before transiting the list.
  847. Arguments:
  848. None.
  849. Return Value:
  850. Returns TRUE is any handler on the list claims to have handled the
  851. interrupt, FALSE otherwise.
  852. --*/
  853. {
  854. BOOLEAN Handled;
  855. PKNMI_HANDLER_CALLBACK Handler;
  856. Handler = KiNmiCallbackListHead;
  857. Handled = FALSE;
  858. while (Handler) {
  859. Handled |= Handler->Callback(Handler->Context, Handled);
  860. Handler = Handler->Next;
  861. }
  862. return Handled;
  863. }
  864. PVOID
  865. KeRegisterNmiCallback(
  866. PNMI_CALLBACK CallbackRoutine,
  867. PVOID Context
  868. )
  869. /*++
  870. Routine Description:
  871. This routine is called to add a callback to the list of Non-Maskable-
  872. Interrupt (NMI) handlers.
  873. This routine must be called at IRQL < DISPATCH_LEVEL.
  874. List insertion must be such that the list is ALWAYS valid, an NMI
  875. could occur during insertion and the NMI handler must be able to
  876. safely transit the list.
  877. Arguments:
  878. CallbackRoutine supplies a pointer to the routine to be called on NMI.
  879. Context supplies an arbitary value which will be passed
  880. to the CallbackRoutine.
  881. Return Value:
  882. Returns an arbitary handle that must be passed to KeDeregisterNmiCallback
  883. or NULL if registration was unsuccessful.
  884. --*/
  885. {
  886. PKNMI_HANDLER_CALLBACK Handler;
  887. PKNMI_HANDLER_CALLBACK Next;
  888. KIRQL OldIrql;
  889. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  890. //
  891. // Allocate memory for the callback object.
  892. //
  893. Handler = ExAllocatePoolWithTag(NonPagedPool,
  894. sizeof(KNMI_HANDLER_CALLBACK),
  895. 'IMNK');
  896. if (Handler == NULL) {
  897. return Handler;
  898. }
  899. //
  900. // Fill in the non-protected elements.
  901. //
  902. Handler->Callback = CallbackRoutine;
  903. Handler->Context = Context;
  904. Handler->Handle = Handler;
  905. //
  906. // Insert the handler onto the front of the list.
  907. //
  908. KeAcquireSpinLock(&KiNmiCallbackListLock, &OldIrql);
  909. Handler->Next = KiNmiCallbackListHead;
  910. //
  911. // Because the lock is held, the following can't fail but is needed
  912. // to ensure the compiler doesn't store KiNmiCallbackList before
  913. // storing Handler->Next because the NMI handler may run down this
  914. // list and does not (can not) take the lock.
  915. //
  916. Next = InterlockedCompareExchangePointer(&KiNmiCallbackListHead,
  917. Handler,
  918. Handler->Next);
  919. ASSERT(Next == Handler->Next);
  920. KeReleaseSpinLock(&KiNmiCallbackListLock, OldIrql);
  921. //
  922. // Return the address of this handler as an opaque handle.
  923. //
  924. return Handler->Handle;
  925. }
  926. NTSTATUS
  927. KeDeregisterNmiCallback(
  928. PVOID Handle
  929. )
  930. /*++
  931. Routine Description:
  932. This routine is called to remove a callback from the list of Non-
  933. Maskable-Interrupt callbacks.
  934. This routine must be called at IRQL < DISPATCH_LEVEL.
  935. List removal must be such that the list is ALWAYS valid, an NMI
  936. could occur during removal and the NMI handler must be able to
  937. safely transit the list.
  938. Arguments:
  939. Handle supplied an opaque handle to the callback object that was
  940. returned by KeRegisterNmiCallback.
  941. Return Value:
  942. Returns STATUS_SUCCESS if the object was successfully removed from
  943. the list. STATUS_INVALID_HANDLE otherwise.
  944. --*/
  945. {
  946. PKNMI_HANDLER_CALLBACK Handler;
  947. PKNMI_HANDLER_CALLBACK *PreviousNext;
  948. KIRQL OldIrql;
  949. #if !defined(NT_UP)
  950. KAFFINITY ActiveProcessors;
  951. KAFFINITY CurrentAffinity;
  952. #endif
  953. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  954. KeAcquireSpinLock(&KiNmiCallbackListLock, &OldIrql);
  955. //
  956. // Find the handler given the list of handlers.
  957. //
  958. // N.B. In the current implementation, the handle is the address
  959. // of the handler however this code is designed for a more opaque
  960. // handle.
  961. //
  962. PreviousNext = &KiNmiCallbackListHead;
  963. for (Handler = *PreviousNext;
  964. Handler;
  965. PreviousNext = &Handler->Next, Handler = Handler->Next) {
  966. if (Handler->Handle == Handle) {
  967. ASSERT(Handle == Handler);
  968. break;
  969. }
  970. }
  971. if ((Handler == NULL) || (Handler->Handle != Handle)) {
  972. KeReleaseSpinLock(&KiNmiCallbackListLock, OldIrql);
  973. return STATUS_INVALID_HANDLE;
  974. }
  975. //
  976. // Remove this handler from the list.
  977. //
  978. *PreviousNext = Handler->Next;
  979. KeReleaseSpinLock(&KiNmiCallbackListLock, OldIrql);
  980. //
  981. // Cycle through each processor in the system to ensure that any
  982. // NMI which has begun execution on another processor has completed
  983. // execution before releasing the memory for the NMI callback object.
  984. //
  985. #if !defined(NT_UP)
  986. ActiveProcessors = KeActiveProcessors;
  987. for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) {
  988. if (ActiveProcessors & CurrentAffinity) {
  989. ActiveProcessors &= ~CurrentAffinity;
  990. KeSetSystemAffinityThread(CurrentAffinity);
  991. }
  992. }
  993. KeRevertToUserAffinityThread();
  994. #endif
  995. ExFreePoolWithTag(Handler, 'INMK');
  996. return STATUS_SUCCESS;
  997. }