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.

543 lines
13 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. kiinit.c
  5. Abstract:
  6. This module implements architecture independent kernel initialization.
  7. Author:
  8. David N. Cutler 11-May-1993
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "ki.h"
  14. //
  15. // External data.
  16. //
  17. extern KSPIN_LOCK AfdWorkQueueSpinLock;
  18. extern KSPIN_LOCK CcBcbSpinLock;
  19. extern KSPIN_LOCK CcMasterSpinLock;
  20. extern KSPIN_LOCK CcVacbSpinLock;
  21. extern KSPIN_LOCK CcWorkQueueSpinLock;
  22. extern KSPIN_LOCK IopCancelSpinLock;
  23. extern KSPIN_LOCK IopCompletionLock;
  24. extern KSPIN_LOCK IopDatabaseLock;
  25. extern KSPIN_LOCK IopVpbSpinLock;
  26. extern KSPIN_LOCK KiContextSwapLock;
  27. extern KSPIN_LOCK KiDispatcherLock;
  28. extern KSPIN_LOCK NtfsStructLock;
  29. extern KSPIN_LOCK MmPfnLock;
  30. extern KSPIN_LOCK NonPagedPoolLock;
  31. extern KSPIN_LOCK MmSystemSpaceLock;
  32. #if DBG && !defined(_X86_)
  33. extern KSPIN_LOCK KipGlobalAlignmentDatabaseLock;
  34. #endif
  35. //
  36. //
  37. // The following exist to allow testing of NUMA support.
  38. //
  39. ULONG KeVerifyNumaPageShift;
  40. ULONG KeVerifyNumaAffinityShift;
  41. ULONG KeVerifyNumaNodeCount;
  42. ULONG KeVerifyNumaAffinity;
  43. ULONG KeVerifyNumaPageMask;
  44. // End numa test support variables.
  45. //
  46. // Put all code for kernel initialization in the INIT section. It will be
  47. // deallocated by memory management when phase 1 initialization is completed.
  48. //
  49. #if defined(ALLOC_PRAGMA)
  50. #pragma alloc_text(INIT, KeInitSystem)
  51. #pragma alloc_text(INIT, KiInitQueuedSpinLocks)
  52. #pragma alloc_text(INIT, KiInitSystem)
  53. #pragma alloc_text(INIT, KiComputeReciprocal)
  54. #pragma alloc_text(INIT, KeNumaInitialize)
  55. #endif
  56. BOOLEAN
  57. KeInitSystem (
  58. VOID
  59. )
  60. /*++
  61. Routine Description:
  62. This function initializes executive structures implemented by the
  63. kernel.
  64. N.B. This function is only called during phase 1 initialization.
  65. Arguments:
  66. None.
  67. Return Value:
  68. A value of TRUE is returned if initialization is successful. Otherwise,
  69. a value of FALSE is returned.
  70. --*/
  71. {
  72. //
  73. // Perform platform dependent initialization.
  74. //
  75. return KiInitMachineDependent();
  76. }
  77. VOID
  78. KiInitQueuedSpinLocks (
  79. PKPRCB Prcb,
  80. ULONG Number
  81. )
  82. /*++
  83. Routine Description:
  84. This function initializes the queued spinlock structures in the per
  85. processor PRCB. This function is called once for each processor as
  86. it is initialized in an MP system.
  87. Arguments:
  88. Prcb - Supplies a pointer to a PRCB.
  89. Number - Supplies the number of respective processor.
  90. Return Value:
  91. None.
  92. --*/
  93. {
  94. //
  95. // Initialize queued spinlock structures.
  96. //
  97. Prcb->LockQueue[LockQueueDispatcherLock].Next = NULL;
  98. Prcb->LockQueue[LockQueueDispatcherLock].Lock = &KiDispatcherLock;
  99. Prcb->LockQueue[LockQueueContextSwapLock].Next = NULL;
  100. Prcb->LockQueue[LockQueueContextSwapLock].Lock = &KiContextSwapLock;
  101. Prcb->LockQueue[LockQueuePfnLock].Next = NULL;
  102. Prcb->LockQueue[LockQueuePfnLock].Lock = &MmPfnLock;
  103. Prcb->LockQueue[LockQueueSystemSpaceLock].Next = NULL;
  104. Prcb->LockQueue[LockQueueSystemSpaceLock].Lock = &MmSystemSpaceLock;
  105. Prcb->LockQueue[LockQueueBcbLock].Next = NULL;
  106. Prcb->LockQueue[LockQueueBcbLock].Lock = &CcBcbSpinLock;
  107. Prcb->LockQueue[LockQueueMasterLock].Next = NULL;
  108. Prcb->LockQueue[LockQueueMasterLock].Lock = &CcMasterSpinLock;
  109. Prcb->LockQueue[LockQueueVacbLock].Next = NULL;
  110. Prcb->LockQueue[LockQueueVacbLock].Lock = &CcVacbSpinLock;
  111. Prcb->LockQueue[LockQueueWorkQueueLock].Next = NULL;
  112. Prcb->LockQueue[LockQueueWorkQueueLock].Lock = &CcWorkQueueSpinLock;
  113. Prcb->LockQueue[LockQueueNonPagedPoolLock].Next = NULL;
  114. Prcb->LockQueue[LockQueueNonPagedPoolLock].Lock = &NonPagedPoolLock;
  115. Prcb->LockQueue[LockQueueIoCancelLock].Next = NULL;
  116. Prcb->LockQueue[LockQueueIoCancelLock].Lock = &IopCancelSpinLock;
  117. Prcb->LockQueue[LockQueueIoVpbLock].Next = NULL;
  118. Prcb->LockQueue[LockQueueIoVpbLock].Lock = &IopVpbSpinLock;
  119. Prcb->LockQueue[LockQueueIoDatabaseLock].Next = NULL;
  120. Prcb->LockQueue[LockQueueIoDatabaseLock].Lock = &IopDatabaseLock;
  121. Prcb->LockQueue[LockQueueIoCompletionLock].Next = NULL;
  122. Prcb->LockQueue[LockQueueIoCompletionLock].Lock = &IopCompletionLock;
  123. Prcb->LockQueue[LockQueueNtfsStructLock].Next = NULL;
  124. Prcb->LockQueue[LockQueueNtfsStructLock].Lock = &NtfsStructLock;
  125. Prcb->LockQueue[LockQueueAfdWorkQueueLock].Next = NULL;
  126. Prcb->LockQueue[LockQueueAfdWorkQueueLock].Lock = &AfdWorkQueueSpinLock;
  127. //
  128. // If this is processor zero, then also initialize the queued spin lock
  129. // home address.
  130. //
  131. if (Number == 0) {
  132. KeInitializeSpinLock(&KiContextSwapLock);
  133. KeInitializeSpinLock(&KiDispatcherLock);
  134. KeInitializeSpinLock(&MmPfnLock);
  135. KeInitializeSpinLock(&MmSystemSpaceLock);
  136. KeInitializeSpinLock(&CcBcbSpinLock);
  137. KeInitializeSpinLock(&CcMasterSpinLock);
  138. KeInitializeSpinLock(&CcVacbSpinLock);
  139. KeInitializeSpinLock(&CcWorkQueueSpinLock);
  140. KeInitializeSpinLock(&IopCancelSpinLock);
  141. KeInitializeSpinLock(&IopCompletionLock);
  142. KeInitializeSpinLock(&IopDatabaseLock);
  143. KeInitializeSpinLock(&IopVpbSpinLock);
  144. KeInitializeSpinLock(&NonPagedPoolLock);
  145. KeInitializeSpinLock(&NtfsStructLock);
  146. KeInitializeSpinLock(&AfdWorkQueueSpinLock);
  147. }
  148. return;
  149. }
  150. VOID
  151. KiInitSystem (
  152. VOID
  153. )
  154. /*++
  155. Routine Description:
  156. This function initializes architecture independent kernel structures.
  157. Arguments:
  158. None.
  159. Return Value:
  160. None.
  161. --*/
  162. {
  163. ULONG Index;
  164. //
  165. // Initialize dispatcher ready queue listheads.
  166. //
  167. for (Index = 0; Index < MAXIMUM_PRIORITY; Index += 1) {
  168. InitializeListHead(&KiDispatcherReadyListHead[Index]);
  169. }
  170. //
  171. // Initialize bug check callback listhead and spinlock.
  172. //
  173. InitializeListHead(&KeBugCheckCallbackListHead);
  174. InitializeListHead(&KeBugCheckReasonCallbackListHead);
  175. KeInitializeSpinLock(&KeBugCheckCallbackLock);
  176. //
  177. // Initialize the timer expiration DPC object.
  178. //
  179. KeInitializeDpc(&KiTimerExpireDpc,
  180. (PKDEFERRED_ROUTINE)KiTimerExpiration, NIL);
  181. //
  182. // Initialize the profile listhead and profile locks
  183. //
  184. KeInitializeSpinLock(&KiProfileLock);
  185. InitializeListHead(&KiProfileListHead);
  186. #if DBG && !defined(_X86_)
  187. //
  188. // Initialize the global alignment fault database lock
  189. //
  190. KeInitializeSpinLock(&KipGlobalAlignmentDatabaseLock);
  191. #endif
  192. //
  193. // Initialize the active profile source listhead.
  194. //
  195. InitializeListHead(&KiProfileSourceListHead);
  196. //
  197. // Initialize the timer table, the timer completion listhead, and the
  198. // timer completion DPC.
  199. //
  200. for (Index = 0; Index < TIMER_TABLE_SIZE; Index += 1) {
  201. InitializeListHead(&KiTimerTableListHead[Index]);
  202. }
  203. //
  204. // Initialize the swap event, the process inswap listhead, the
  205. // process outswap listhead, the kernel stack inswap listhead,
  206. // the wait in listhead, and the wait out listhead.
  207. //
  208. KeInitializeEvent(&KiSwapEvent,
  209. SynchronizationEvent,
  210. FALSE);
  211. KiProcessInSwapListHead.Next = NULL;
  212. KiProcessOutSwapListHead.Next = NULL;
  213. KiStackInSwapListHead.Next = NULL;
  214. InitializeListHead(&KiWaitListHead);
  215. //
  216. // Initialize the system service descriptor table.
  217. //
  218. KeServiceDescriptorTable[0].Base = &KiServiceTable[0];
  219. KeServiceDescriptorTable[0].Count = NULL;
  220. KeServiceDescriptorTable[0].Limit = KiServiceLimit;
  221. //
  222. // The global pointer associated with the table base is placed just
  223. // before the service table on the ia64.
  224. //
  225. #if defined(_IA64_)
  226. KeServiceDescriptorTable[0].TableBaseGpOffset =
  227. (LONG)(*(KiServiceTable-1) - (ULONG_PTR)KiServiceTable);
  228. #endif
  229. KeServiceDescriptorTable[0].Number = &KiArgumentTable[0];
  230. for (Index = 1; Index < NUMBER_SERVICE_TABLES; Index += 1) {
  231. KeServiceDescriptorTable[Index].Limit = 0;
  232. }
  233. //
  234. // Copy the system service descriptor table to the shadow table
  235. // which is used to record the Win32 system services.
  236. //
  237. RtlCopyMemory(KeServiceDescriptorTableShadow,
  238. KeServiceDescriptorTable,
  239. sizeof(KeServiceDescriptorTable));
  240. //
  241. // Initialize call performance data structures.
  242. //
  243. #if defined(_COLLECT_FLUSH_SINGLE_CALLDATA_)
  244. ExInitializeCallData(&KiFlushSingleCallData);
  245. #endif
  246. #if defined(_COLLECT_SET_EVENT_CALLDATA_)
  247. ExInitializeCallData(&KiSetEventCallData);
  248. #endif
  249. #if defined(_COLLECT_WAIT_SINGLE_CALLDATA_)
  250. ExInitializeCallData(&KiWaitSingleCallData);
  251. #endif
  252. return;
  253. }
  254. LARGE_INTEGER
  255. KiComputeReciprocal (
  256. IN LONG Divisor,
  257. OUT PCCHAR Shift
  258. )
  259. /*++
  260. Routine Description:
  261. This function computes the large integer reciprocal of the specified
  262. value.
  263. Arguments:
  264. Divisor - Supplies the value for which the large integer reciprocal is
  265. computed.
  266. Shift - Supplies a pointer to a variable that receives the computed
  267. shift count.
  268. Return Value:
  269. The large integer reciprocal is returned as the fucntion value.
  270. --*/
  271. {
  272. LARGE_INTEGER Fraction;
  273. LONG NumberBits;
  274. LONG Remainder;
  275. //
  276. // Compute the large integer reciprocal of the specified value.
  277. //
  278. NumberBits = 0;
  279. Remainder = 1;
  280. Fraction.LowPart = 0;
  281. Fraction.HighPart = 0;
  282. while (Fraction.HighPart >= 0) {
  283. NumberBits += 1;
  284. Fraction.HighPart = (Fraction.HighPart << 1) | (Fraction.LowPart >> 31);
  285. Fraction.LowPart <<= 1;
  286. Remainder <<= 1;
  287. if (Remainder >= Divisor) {
  288. Remainder -= Divisor;
  289. Fraction.LowPart |= 1;
  290. }
  291. }
  292. if (Remainder != 0) {
  293. if ((Fraction.LowPart == 0xffffffff) && (Fraction.HighPart == 0xffffffff)) {
  294. Fraction.LowPart = 0;
  295. Fraction.HighPart = 0x80000000;
  296. NumberBits -= 1;
  297. } else {
  298. if (Fraction.LowPart == 0xffffffff) {
  299. Fraction.LowPart = 0;
  300. Fraction.HighPart += 1;
  301. } else {
  302. Fraction.LowPart += 1;
  303. }
  304. }
  305. }
  306. //
  307. // Compute the shift count value and return the reciprocal fraction.
  308. //
  309. *Shift = (CCHAR)(NumberBits - 64);
  310. return Fraction;
  311. }
  312. VOID
  313. KeNumaInitialize (
  314. VOID
  315. )
  316. /*++
  317. Routine Description:
  318. Initialize ntos kernel structures needed to support NUMA.
  319. Arguments:
  320. None.
  321. Return Value:
  322. None.
  323. --*/
  324. {
  325. #if defined(KE_MULTINODE)
  326. NTSTATUS Status;
  327. HAL_NUMA_TOPOLOGY_INTERFACE HalNumaInfo;
  328. ULONG ReturnedLength;
  329. extern PHALNUMAQUERYPROCESSORNODE KiQueryProcessorNode;
  330. extern PHALNUMAPAGETONODE MmPageToNode;
  331. //
  332. // Mega Kludge: For testing purposes on NON-Numa systems,
  333. // we can have non-numa MP systems report a NUMA configuration.
  334. //
  335. // Pass the information obtained from the registry to the HAL
  336. // in the return info buffer.
  337. //
  338. if (KeVerifyNumaNodeCount &&
  339. (KeVerifyNumaNodeCount < 8) &&
  340. KeVerifyNumaAffinity &&
  341. KeVerifyNumaAffinityShift &&
  342. (KeVerifyNumaAffinityShift < 32) &&
  343. KeVerifyNumaPageMask &&
  344. (KeVerifyNumaPageMask < KeVerifyNumaNodeCount)&&
  345. KeVerifyNumaPageShift &&
  346. (KeVerifyNumaPageShift < 32) ) {
  347. struct {
  348. ULONG Nodes:3;
  349. ULONG AffinityShift:6;
  350. ULONG PageShift:6;
  351. ULONG Signature:17;
  352. ULONG Affinity;
  353. ULONG Mask;
  354. } Fake;
  355. C_ASSERT(sizeof(Fake) <= sizeof(HalNumaInfo));
  356. Fake.Signature = 0x15a5a;
  357. Fake.PageShift = KeVerifyNumaPageShift;
  358. Fake.AffinityShift = KeVerifyNumaAffinityShift;
  359. Fake.Nodes = KeVerifyNumaNodeCount;
  360. Fake.Affinity = KeVerifyNumaAffinity;
  361. Fake.Mask = KeVerifyNumaPageMask;
  362. RtlCopyMemory(&HalNumaInfo, &Fake, sizeof(Fake));
  363. }
  364. //
  365. // End Mega Kludge.
  366. //
  367. Status = HalQuerySystemInformation (HalNumaTopologyInterface,
  368. sizeof(HalNumaInfo),
  369. &HalNumaInfo,
  370. &ReturnedLength);
  371. if (NT_SUCCESS(Status)) {
  372. ASSERT (ReturnedLength == sizeof(HalNumaInfo));
  373. ASSERT (HalNumaInfo.NumberOfNodes <= MAXIMUM_CCNUMA_NODES);
  374. ASSERT (HalNumaInfo.QueryProcessorNode);
  375. ASSERT (HalNumaInfo.PageToNode);
  376. if (HalNumaInfo.NumberOfNodes > 1) {
  377. KeNumberNodes = (UCHAR)HalNumaInfo.NumberOfNodes;
  378. MmPageToNode = HalNumaInfo.PageToNode;
  379. KiQueryProcessorNode = HalNumaInfo.QueryProcessorNode;
  380. }
  381. }
  382. #endif
  383. }