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.

535 lines
12 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. allproc.c
  5. Abstract:
  6. This module allocates and intializes kernel resources required
  7. to start a new processor, and passes a complete processor state
  8. structure to the HAL to obtain a new processor.
  9. Author:
  10. Bernard Lint 31-Jul-96
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. Based on MIPS original (David N. Cutler 29-Apr-1993)
  15. --*/
  16. #include "ki.h"
  17. #if defined(KE_MULTINODE)
  18. NTSTATUS
  19. KiNotNumaQueryProcessorNode(
  20. IN ULONG ProcessorNumber,
  21. OUT PUSHORT Identifier,
  22. OUT PUCHAR Node
  23. );
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text(INIT, KiNotNumaQueryProcessorNode)
  26. #endif
  27. #endif
  28. #ifdef ALLOC_PRAGMA
  29. #pragma alloc_text(INIT, KeStartAllProcessors)
  30. #pragma alloc_text(INIT, KiAllProcessorsStarted)
  31. #endif
  32. //
  33. // Define macro to round up to 64-byte boundary and define block sizes.
  34. //
  35. #define ROUND_UP(x) ((sizeof(x) + 63) & (~63))
  36. #define BLOCK1_SIZE (2 * (KERNEL_BSTORE_SIZE + KERNEL_STACK_SIZE) + PAGE_SIZE)
  37. #define BLOCK2_SIZE (ROUND_UP(KPRCB) + ROUND_UP(KNODE) + ROUND_UP(ETHREAD) + 64)
  38. #if !defined(NT_UP)
  39. //
  40. // Define barrier wait static data.
  41. //
  42. ULONG KiBarrierWait = 0;
  43. #endif
  44. #if defined(KE_MULTINODE)
  45. PHALNUMAQUERYPROCESSORNODE KiQueryProcessorNode = KiNotNumaQueryProcessorNode;
  46. //
  47. // Statically preallocate enough KNODE structures to allow MM
  48. // to allocate pages by node during system initialization. As
  49. // processors are brought online, real KNODE structures are
  50. // allocated in the appropriate memory for the node.
  51. //
  52. // This statically allocated set will be deallocated once the
  53. // system is initialized.
  54. //
  55. #ifdef ALLOC_DATA_PRAGMA
  56. #pragma data_seg("INITDATA")
  57. #endif
  58. KNODE KiNodeInit[MAXIMUM_PROCESSORS];
  59. #endif
  60. extern ULONG_PTR KiUserSharedDataPage;
  61. extern ULONG_PTR KiKernelPcrPage;
  62. //
  63. // Define forward referenced prototypes.
  64. //
  65. VOID
  66. KiCalibratePerformanceCounter(
  67. VOID
  68. );
  69. VOID
  70. KiCalibratePerformanceCounterTarget (
  71. IN PULONG SignalDone,
  72. IN PVOID Count,
  73. IN PVOID Parameter2,
  74. IN PVOID Parameter3
  75. );
  76. VOID
  77. KiOSRendezvous (
  78. VOID
  79. );
  80. VOID
  81. KeStartAllProcessors(
  82. VOID
  83. )
  84. /*++
  85. Routine Description:
  86. This function is called during phase 1 initialize on the master boot
  87. processor to start all of the other registered processors.
  88. Arguments:
  89. None.
  90. Return Value:
  91. None.
  92. --*/
  93. {
  94. #if !defined(NT_UP)
  95. ULONG_PTR MemoryBlock1;
  96. ULONG_PTR MemoryBlock2;
  97. ULONG_PTR MemoryBlock3;
  98. ULONG_PTR PcrAddress;
  99. ULONG Number;
  100. ULONG Count;
  101. PHYSICAL_ADDRESS PcrPage;
  102. PKPRCB Prcb;
  103. BOOLEAN Started;
  104. KPROCESSOR_STATE ProcessorState;
  105. UCHAR NodeNumber = 0;
  106. USHORT ProcessorId;
  107. SIZE_T ProcessorDataSize;
  108. PKNODE Node;
  109. NTSTATUS Status;
  110. PKPCR NewPcr;
  111. #if defined(KE_MULTINODE)
  112. //
  113. // In the unlikely event that processor 0 is not on node
  114. // 0, fix it.
  115. //
  116. if (KeNumberNodes > 1) {
  117. Status = KiQueryProcessorNode(0,
  118. &ProcessorId,
  119. &NodeNumber);
  120. if (NT_SUCCESS(Status)) {
  121. //
  122. // This should never fail.
  123. //
  124. if (NodeNumber != 0) {
  125. KeNodeBlock[0]->ProcessorMask &= ~1I64;
  126. KeNodeBlock[NodeNumber]->ProcessorMask |= 1;
  127. KeGetCurrentPrcb()->ParentNode = KeNodeBlock[NodeNumber];
  128. }
  129. KeGetCurrentPrcb()->ProcessorId = ProcessorId;
  130. }
  131. }
  132. #endif
  133. //
  134. // If the registered number of processors is greater than the maximum
  135. // number of processors supported, then only allow the maximum number
  136. // of supported processors.
  137. //
  138. if (KeRegisteredProcessors > MAXIMUM_PROCESSORS) {
  139. KeRegisteredProcessors = MAXIMUM_PROCESSORS;
  140. }
  141. //
  142. // Set barrier that will prevent any other processor from entering the
  143. // idle loop until all processors have been started.
  144. //
  145. KiBarrierWait = 1;
  146. //
  147. // Initialize the processor state that will be used to start each of
  148. // processors. Each processor starts in the system initialization code
  149. // with address of the loader parameter block as an argument.
  150. //
  151. Number = 0;
  152. Count = 1;
  153. RtlZeroMemory(&ProcessorState, sizeof(KPROCESSOR_STATE));
  154. ProcessorState.ContextFrame.StIIP = ((PPLABEL_DESCRIPTOR)KiOSRendezvous)->EntryPoint;
  155. while (Count < KeRegisteredProcessors) {
  156. Number++;
  157. if (Number >= MAXIMUM_PROCESSORS) {
  158. break;
  159. }
  160. #if defined(KE_MULTINODE)
  161. Status = KiQueryProcessorNode(Number,
  162. &ProcessorId,
  163. &NodeNumber);
  164. if (!NT_SUCCESS(Status)) {
  165. //
  166. // No such processor, advance to next.
  167. //
  168. continue;
  169. }
  170. Node = KeNodeBlock[NodeNumber];
  171. #endif
  172. //
  173. // Allocate a DPC stack, an idle thread kernel stack, a panic
  174. // stack, a PCR page, a processor block, a kernel node structure
  175. // and an executive thread object. If the allocation fails, stop
  176. // starting processors.
  177. //
  178. #if 0
  179. //PLJTMP: Need to investigate which pieces need to be in KSEG0
  180. //and allocate the other stuff per node. plus deal with any alignment
  181. //padding for the size below based on roundup of BLOCK1_SIZE.
  182. ProcessorDataSize = BLOCK1_SIZE + BLOCK2_SIZE;
  183. MemoryBlock1 = (ULONG_PTR)MmAllocateIndependentPages (ProcessorDataSize,
  184. NodeNumber);
  185. if ((PVOID)MemoryBlock1 == NULL) {
  186. break;
  187. }
  188. MemoryBlock2 = MemoryBlock1 + BLOCK1_SIZE;
  189. //
  190. // Zero the allocated memory.
  191. //
  192. RtlZeroMemory((PVOID)MemoryBlock1, ProcessorDataSize);
  193. #else
  194. MemoryBlock1 = (ULONG_PTR)ExAllocatePool(NonPagedPool, BLOCK1_SIZE);
  195. if ((PVOID)MemoryBlock1 == NULL) {
  196. break;
  197. }
  198. MemoryBlock2 = (ULONG_PTR)ExAllocatePool(NonPagedPool, BLOCK2_SIZE);
  199. if ((PVOID)MemoryBlock2 == NULL) {
  200. ExFreePool((PVOID)MemoryBlock1);
  201. break;
  202. }
  203. //
  204. // Zero both blocks of allocated memory.
  205. //
  206. RtlZeroMemory((PVOID)MemoryBlock1, BLOCK1_SIZE);
  207. RtlZeroMemory((PVOID)MemoryBlock2, BLOCK2_SIZE);
  208. #endif
  209. //
  210. // Set address of idle thread kernel stack in loader parameter block.
  211. //
  212. KeLoaderBlock->KernelStack = MemoryBlock1 + KERNEL_STACK_SIZE;
  213. //
  214. // Set address of panic stack in loader parameter block.
  215. //
  216. KeLoaderBlock->u.Ia64.PanicStack = MemoryBlock1 + KERNEL_BSTORE_SIZE +
  217. (2 * KERNEL_STACK_SIZE);
  218. //
  219. // Set the address of the processor block and executive thread in the
  220. // loader parameter block.
  221. //
  222. KeLoaderBlock->Prcb = MemoryBlock2;
  223. KeLoaderBlock->Thread = KeLoaderBlock->Prcb + ROUND_UP(KPRCB) +
  224. ROUND_UP(KNODE);
  225. ((PKPRCB)KeLoaderBlock->Prcb)->Number = (UCHAR)Number;
  226. #if defined(KE_MULTINODE)
  227. //
  228. // If this is the first processor on this node, use the
  229. // space allocated for KNODE as the KNODE.
  230. //
  231. if (KeNodeBlock[NodeNumber] == &KiNodeInit[NodeNumber]) {
  232. Node = (PKNODE)(MemoryBlock1 + ROUND_UP(KPRCB));
  233. *Node = KiNodeInit[NodeNumber];
  234. KeNodeBlock[NodeNumber] = Node;
  235. }
  236. ((PKPRCB)KeLoaderBlock->Prcb)->ParentNode = Node;
  237. ((PKPRCB)KeLoaderBlock->Prcb)->ProcessorId = ProcessorId;
  238. #else
  239. ((PKPRCB)KeLoaderBlock->Prcb)->ParentNode = KeNodeBlock[0];
  240. #endif
  241. //
  242. // Set the page frame of the PCR page in the loader parameter block.
  243. //
  244. PcrAddress = MemoryBlock1 + (2 * (KERNEL_BSTORE_SIZE + KERNEL_STACK_SIZE));
  245. PcrPage = MmGetPhysicalAddress((PVOID)PcrAddress);
  246. KeLoaderBlock->u.Ia64.PcrPage = PcrPage.QuadPart >> PAGE_SHIFT;
  247. KeLoaderBlock->u.Ia64.PcrPage2 = KiUserSharedDataPage;
  248. KiKernelPcrPage = KeLoaderBlock->u.Ia64.PcrPage;
  249. //
  250. // Initialize the NT page table base addresses in PCR
  251. //
  252. NewPcr = (PKPCR) PcrAddress;
  253. NewPcr->PteUbase = PCR->PteUbase;
  254. NewPcr->PteKbase = PCR->PteKbase;
  255. NewPcr->PteSbase = PCR->PteSbase;
  256. NewPcr->PdeUbase = PCR->PdeUbase;
  257. NewPcr->PdeKbase = PCR->PdeKbase;
  258. NewPcr->PdeSbase = PCR->PdeSbase;
  259. NewPcr->PdeUtbase = PCR->PdeUtbase;
  260. NewPcr->PdeKtbase = PCR->PdeKtbase;
  261. NewPcr->PdeStbase = PCR->PdeStbase;
  262. //
  263. // Attempt to start the next processor. If attempt is successful,
  264. // then wait for the processor to get initialized. Otherwise,
  265. // deallocate the processor resources and terminate the loop.
  266. //
  267. Started = HalStartNextProcessor(KeLoaderBlock, &ProcessorState);
  268. if (Started) {
  269. //
  270. // Wait for processor to initialize in kernel,
  271. // then loop for another
  272. //
  273. while (*((volatile ULONG_PTR *) &KeLoaderBlock->Prcb) != 0) {
  274. KeYieldProcessor();
  275. }
  276. #if defined(KE_MULTINODE)
  277. Node->ProcessorMask |= 1I64 << Number;
  278. #endif
  279. } else {
  280. #if 0
  281. MmFreeIndependentPages((PVOID)MemoryBlock1, ProcessorDataSize);
  282. #else
  283. ExFreePool((PVOID)MemoryBlock1);
  284. ExFreePool((PVOID)MemoryBlock2);
  285. #endif
  286. break;
  287. }
  288. Count += 1;
  289. }
  290. //
  291. // All processors have been stated.
  292. //
  293. KiAllProcessorsStarted();
  294. //
  295. // Allow all processor that were started to enter the idle loop and
  296. // begin execution.
  297. //
  298. KiBarrierWait = 0;
  299. #endif
  300. //
  301. // Reset and synchronize the performance counters of all processors.
  302. //
  303. KiAdjustInterruptTime (0);
  304. return;
  305. }
  306. #if !defined(NT_UP)
  307. VOID
  308. KiAllProcessorsStarted(
  309. VOID
  310. )
  311. /*++
  312. Routine Description:
  313. This routine is called once all processors in the system
  314. have been started.
  315. Arguments:
  316. None.
  317. Return Value:
  318. None.
  319. --*/
  320. {
  321. ULONG i;
  322. #if defined(KE_MULTINODE)
  323. //
  324. // Make sure there are no references to the temporary nodes
  325. // used during initialization.
  326. //
  327. for (i = 0; i < KeNumberNodes; i++) {
  328. if (KeNodeBlock[i] == &KiNodeInit[i]) {
  329. //
  330. // No processor started on this node so no new node
  331. // structure has been allocated. This is possible
  332. // if the node contains only memory or IO busses. At
  333. // this time we need to allocate a permanent node
  334. // structure for the node.
  335. //
  336. KeNodeBlock[i] = ExAllocatePoolWithTag(NonPagedPool,
  337. sizeof(KNODE),
  338. ' eK');
  339. if (KeNodeBlock[i]) {
  340. *KeNodeBlock[i] = KiNodeInit[i];
  341. }
  342. }
  343. }
  344. for (i = KeNumberNodes; i < MAXIMUM_CCNUMA_NODES; i++) {
  345. KeNodeBlock[i] = NULL;
  346. }
  347. #endif
  348. if (KeNumberNodes == 1) {
  349. //
  350. // For Non NUMA machines, Node 0 gets all processors.
  351. //
  352. KeNodeBlock[0]->ProcessorMask = KeActiveProcessors;
  353. }
  354. }
  355. #endif
  356. #if defined(KE_MULTINODE)
  357. NTSTATUS
  358. KiNotNumaQueryProcessorNode(
  359. IN ULONG ProcessorNumber,
  360. OUT PUSHORT Identifier,
  361. OUT PUCHAR Node
  362. )
  363. /*++
  364. Routine Description:
  365. This routine is a stub used on non NUMA systems to provide a
  366. consistent method of determining the NUMA configuration rather
  367. than checking for the presense of multiple nodes inline.
  368. Arguments:
  369. ProcessorNumber supplies the system logical processor number.
  370. Identifier supplies the address of a variable to receive
  371. the unique identifier for this processor.
  372. NodeNumber supplies the address of a variable to receive
  373. the number of the node this processor resides on.
  374. Return Value:
  375. Returns success.
  376. --*/
  377. {
  378. *Identifier = (USHORT)ProcessorNumber;
  379. *Node = 0;
  380. return STATUS_SUCCESS;
  381. }
  382. #endif