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.

454 lines
12 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Copyright (c) 1993 Digital Equipment Corporation
  4. Module Name:
  5. allproc.c
  6. Abstract:
  7. This module allocates and initializes kernel resources required
  8. to start a new processor, and passes a complete processor state
  9. structure to the HAL to obtain a new processor.
  10. Author:
  11. David N. Cutler 29-Apr-1993
  12. Joe Notarangelo 30-Nov-1993
  13. Environment:
  14. Kernel mode only.
  15. Revision History:
  16. --*/
  17. #include "ki.h"
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(INIT, KeStartAllProcessors)
  20. #pragma alloc_text(INIT, KiAllProcessorsStarted)
  21. #endif
  22. #if defined(KE_MULTINODE)
  23. PHALNUMAQUERYNODEAFFINITY KiQueryNodeAffinity;
  24. //
  25. // Statically preallocate enough KNODE structures to allow MM
  26. // to allocate pages by node during system initialization. As
  27. // processors are brought online, real KNODE structures are
  28. // allocated in the appropriate memory for the node.
  29. //
  30. // This statically allocated set will be deallocated once the
  31. // system is initialized.
  32. //
  33. #ifdef ALLOC_DATA_PRAGMA
  34. #pragma data_seg("INITDATA")
  35. #endif
  36. KNODE KiNodeInit[MAXIMUM_CCNUMA_NODES];
  37. #endif
  38. //
  39. // Define macro to round up to 64-byte boundary and define block sizes.
  40. //
  41. #define ROUND_UP(x) ((sizeof(x) + 64) & (~64))
  42. #define BLOCK1_SIZE ((3 * KERNEL_STACK_SIZE) + PAGE_SIZE)
  43. #define BLOCK2_SIZE (ROUND_UP(KPRCB) + ROUND_UP(KNODE) + ROUND_UP(ETHREAD) + 64)
  44. //
  45. // Macros to compute whether an address is physically addressable.
  46. //
  47. #if defined(_AXP64_)
  48. #define IS_KSEG_ADDRESS(v) \
  49. (((v) >= KSEG43_BASE) && \
  50. ((v) < KSEG43_LIMIT) && \
  51. (KSEG_PFN(v) < ((KSEG2_BASE - KSEG0_BASE) >> PAGE_SHIFT)))
  52. #define KSEG_PFN(v) ((ULONG)(((v) - KSEG43_BASE) >> PAGE_SHIFT))
  53. #define KSEG0_ADDRESS(v) (KSEG0_BASE | ((v) - KSEG43_BASE))
  54. #else
  55. #define IS_KSEG_ADDRESS(v) (((v) >= KSEG0_BASE) && ((v) < KSEG2_BASE))
  56. #define KSEG_PFN(v) ((ULONG)(((v) - KSEG0_BASE) >> PAGE_SHIFT))
  57. #define KSEG0_ADDRESS(v) (v)
  58. #endif
  59. //
  60. // Define forward referenced prototypes.
  61. //
  62. VOID
  63. KiStartProcessor (
  64. IN PLOADER_PARAMETER_BLOCK Loaderblock
  65. );
  66. VOID
  67. KeStartAllProcessors(
  68. VOID
  69. )
  70. /*++
  71. Routine Description:
  72. This function is called during phase 1 initialization on the master boot
  73. processor to start all of the other registered processors.
  74. Arguments:
  75. None.
  76. Return Value:
  77. None.
  78. --*/
  79. {
  80. #if !defined(NT_UP)
  81. ULONG_PTR MemoryBlock1;
  82. ULONG_PTR MemoryBlock2;
  83. ULONG Number;
  84. ULONG PcrPage;
  85. PKPRCB Prcb;
  86. KPROCESSOR_STATE ProcessorState;
  87. struct _RESTART_BLOCK *RestartBlock;
  88. BOOLEAN Started;
  89. LOGICAL SpecialPoolState;
  90. UCHAR NodeNumber = 0;
  91. #if defined(KE_MULTINODE)
  92. KAFFINITY NewProcessorAffinity;
  93. PKNODE Node;
  94. NTSTATUS Status;
  95. //
  96. // If this is a NUMA system, find out the number of nodes and the
  97. // processors which belong to each node.
  98. //
  99. if (KeNumberNodes > 1) {
  100. for (NodeNumber = 0; NodeNumber < KeNumberNodes; NodeNumber++) {
  101. Node = KeNodeBlock[NodeNumber];
  102. //
  103. // Ask HAL which processors belong to this node and
  104. // what Node Color to use for page coloring.
  105. //
  106. Status = KiQueryNodeAffinity(NodeNumber,
  107. &Node->ProcessorMask);
  108. if (!NT_SUCCESS(Status)) {
  109. DbgPrint(
  110. "KE/HAL: NUMA Hal failed to return info for Node %i.\n",
  111. NodeNumber);
  112. DbgPrint("KE/HAL: Reverting to non NUMA configuration.\n");
  113. ASSERT(NT_SUCCESS(Status));
  114. KeNumberNodes = 1;
  115. } else {
  116. //
  117. // In the unlikely event that processor 0 is not
  118. // on node 0, now would be the perfect time to
  119. // fix it.
  120. //
  121. if (Node->ProcessorMask & 1) {
  122. KeGetCurrentPrcb()->ParentNode = Node;
  123. }
  124. }
  125. }
  126. }
  127. #endif
  128. //
  129. // If the registered number of processors is greater than the maximum
  130. // number of processors supported, then only allow the maximum number
  131. // of supported processors.
  132. //
  133. if (KeRegisteredProcessors > MAXIMUM_PROCESSORS) {
  134. KeRegisteredProcessors = MAXIMUM_PROCESSORS;
  135. }
  136. //
  137. // Initialize the processor state that will be used to start each of
  138. // processors. Each processor starts in the system initialization code
  139. // with address of the loader parameter block as an argument.
  140. //
  141. RtlZeroMemory(&ProcessorState, sizeof(KPROCESSOR_STATE));
  142. ProcessorState.ContextFrame.IntA0 = (ULONGLONG)(LONG_PTR)KeLoaderBlock;
  143. ProcessorState.ContextFrame.Fir = (ULONGLONG)(LONG_PTR)KiStartProcessor;
  144. Number = 1;
  145. while (Number < KeRegisteredProcessors) {
  146. #if defined(KE_MULTINODE)
  147. NewProcessorAffinity = 1 << Number;
  148. for (NodeNumber = 0; NodeNumber < KeNumberNodes; NodeNumber++) {
  149. Node = KeNodeBlock[NodeNumber];
  150. if (Node->ProcessorMask & NewProcessorAffinity) {
  151. break;
  152. }
  153. }
  154. if (NodeNumber == KeNumberNodes) {
  155. //
  156. // This should only happen when we're about to ask
  157. // for one processor more than is in the system. We
  158. // could bail here but we have always depended on
  159. // the HAL to tell us we're done. Set up as if
  160. // on Node 0 so MM and friends won't be referencing
  161. // uninitialized structures.
  162. //
  163. NodeNumber = 0;
  164. Node = KeNodeBlock[0];
  165. }
  166. #endif
  167. //
  168. // Allocate a DPC stack, an idle thread kernel stack, a panic
  169. // stack, a PCR page, a processor block, and an executive thread
  170. // object. If the allocation fails or the allocation cannot be
  171. // made from unmapped nonpaged pool, then stop starting processors.
  172. //
  173. // Disable any special pooling that the user may have set in the
  174. // registry as the next couple of allocations must come from KSEG0.
  175. //
  176. SpecialPoolState = MmSetSpecialPool(FALSE);
  177. MemoryBlock1 = (ULONG_PTR)ExAllocatePool(NonPagedPool, BLOCK1_SIZE);
  178. if (IS_KSEG_ADDRESS(MemoryBlock1) == FALSE) {
  179. MmSetSpecialPool(SpecialPoolState);
  180. if ((PVOID)MemoryBlock1 != NULL) {
  181. ExFreePool((PVOID)MemoryBlock1);
  182. }
  183. break;
  184. }
  185. MemoryBlock2 = (ULONG_PTR)ExAllocatePool(NonPagedPool, BLOCK2_SIZE);
  186. if (IS_KSEG_ADDRESS(MemoryBlock2) == FALSE) {
  187. MmSetSpecialPool(SpecialPoolState);
  188. ExFreePool((PVOID)MemoryBlock1);
  189. if ((PVOID)MemoryBlock2 != NULL) {
  190. ExFreePool((PVOID)MemoryBlock2);
  191. }
  192. break;
  193. }
  194. MmSetSpecialPool(SpecialPoolState);
  195. //
  196. // Zero both blocks of allocated memory.
  197. //
  198. RtlZeroMemory((PVOID)MemoryBlock1, BLOCK1_SIZE);
  199. RtlZeroMemory((PVOID)MemoryBlock2, BLOCK2_SIZE);
  200. //
  201. // Set address of interrupt stack in loader parameter block.
  202. //
  203. KeLoaderBlock->u.Alpha.PanicStack =
  204. KSEG0_ADDRESS(MemoryBlock1 + (1 * KERNEL_STACK_SIZE));
  205. //
  206. // Set address of idle thread kernel stack in loader parameter block.
  207. //
  208. KeLoaderBlock->KernelStack =
  209. KSEG0_ADDRESS(MemoryBlock1 + (2 * KERNEL_STACK_SIZE));
  210. ProcessorState.ContextFrame.IntSp =
  211. (ULONGLONG)(LONG_PTR)KeLoaderBlock->KernelStack;
  212. //
  213. // Set address of panic stack in loader parameter block.
  214. //
  215. KeLoaderBlock->u.Alpha.DpcStack =
  216. KSEG0_ADDRESS(MemoryBlock1 + (3 * KERNEL_STACK_SIZE));
  217. //
  218. // Set the page frame of the PCR page in the loader parameter block.
  219. //
  220. PcrPage = KSEG_PFN(MemoryBlock1 + (3 * KERNEL_STACK_SIZE));
  221. KeLoaderBlock->u.Alpha.PcrPage = PcrPage;
  222. //
  223. // Set the address of the processor block and executive thread in the
  224. // loader parameter block.
  225. //
  226. KeLoaderBlock->Prcb = KSEG0_ADDRESS((MemoryBlock2 + 63) & ~63);
  227. KeLoaderBlock->Thread = KeLoaderBlock->Prcb +
  228. ROUND_UP(KPRCB) +
  229. ROUND_UP(KNODE);
  230. #if defined(KE_MULTINODE)
  231. //
  232. // If this is the first processor on this node, use the
  233. // space allocated for KNODE as the KNODE.
  234. //
  235. if (KeNodeBlock[NodeNumber] == &KiNodeInit[NodeNumber]) {
  236. Node = (PKNODE)(KeLoaderBlock->Prcb + ROUND_UP(KPRCB));
  237. *Node = KiNodeInit[NodeNumber];
  238. KeNodeBlock[NodeNumber] = Node;
  239. }
  240. ((PKPRCB)KeLoaderBlock->Prcb)->ParentNode = Node;
  241. #else
  242. ((PKPRCB)KeLoaderBlock->Prcb)->ParentNode = KeNodeBlock[0];
  243. #endif
  244. //
  245. // Attempt to start the next processor. If attempt is successful,
  246. // then wait for the processor to get initialized. Otherwise,
  247. // deallocate the processor resources and terminate the loop.
  248. //
  249. Started = HalStartNextProcessor(KeLoaderBlock, &ProcessorState);
  250. if (Started == FALSE) {
  251. ExFreePool((PVOID)MemoryBlock1);
  252. ExFreePool((PVOID)MemoryBlock2);
  253. break;
  254. } else {
  255. //
  256. // Wait until boot is finished on the target processor before
  257. // starting the next processor. Booting is considered to be
  258. // finished when a processor completes its initialization and
  259. // drops into the idle loop.
  260. //
  261. Prcb = (PKPRCB)(KeLoaderBlock->Prcb);
  262. RestartBlock = Prcb->RestartBlock;
  263. while (RestartBlock->BootStatus.BootFinished == 0) {
  264. KiMb();
  265. }
  266. }
  267. Number += 1;
  268. }
  269. //
  270. //
  271. // All processors have been stated.
  272. //
  273. KiAllProcessorsStarted();
  274. #endif
  275. //
  276. // Reset and synchronize the performance counters of all processors, by
  277. // applying a null adjustment to the interrupt time
  278. //
  279. KiAdjustInterruptTime(0);
  280. return;
  281. }
  282. #if !defined(NT_UP)
  283. VOID
  284. KiAllProcessorsStarted(
  285. VOID
  286. )
  287. /*++
  288. Routine Description:
  289. This routine is called once all processors in the system
  290. have been started.
  291. Arguments:
  292. None.
  293. Return Value:
  294. None.
  295. --*/
  296. {
  297. ULONG i;
  298. #if defined(KE_MULTINODE)
  299. //
  300. // Make sure there are no references to the temporary nodes
  301. // used during initialization.
  302. //
  303. for (i = 0; i < KeNumberNodes; i++) {
  304. if (KeNodeBlock[i] == &KiNodeInit[i]) {
  305. //
  306. // No processor started on this node so no new node
  307. // structure has been allocated. This is possible
  308. // if the node contains only memory or IO busses. At
  309. // this time we need to allocate a permanent node
  310. // structure for the node.
  311. //
  312. KeNodeBlock[i] = ExAllocatePoolWithTag(NonPagedPool,
  313. sizeof(KNODE),
  314. ' eK');
  315. if (KeNodeBlock[i]) {
  316. *KeNodeBlock[i] = KiNodeInit[i];
  317. }
  318. }
  319. }
  320. for (i = KeNumberNodes; i < MAXIMUM_CCNUMA_NODES; i++) {
  321. KeNodeBlock[i] = NULL;
  322. }
  323. #endif
  324. if (KeNumberNodes == 1) {
  325. //
  326. // For Non NUMA machines, Node 0 gets all processors.
  327. //
  328. KeNodeBlock[0]->ProcessorMask = KeActiveProcessors;
  329. }
  330. }
  331. #endif