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.

636 lines
15 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. allproc.c
  5. Abstract:
  6. This module allocates and initializes kernel resources required to
  7. start a new processor, and passes a complete process state structure
  8. to the hal to obtain a new processor.
  9. Author:
  10. David N. Cutler (davec) 5-May-2000
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. --*/
  15. #include "ki.h"
  16. //
  17. // Define local macros.
  18. //
  19. #define ROUNDUP16(x) (((x) + 15) & ~15)
  20. //
  21. // Define prototypes for forward referenced functions.
  22. //
  23. VOID
  24. KiCopyDescriptorMemory (
  25. IN PKDESCRIPTOR Source,
  26. IN PKDESCRIPTOR Destination,
  27. IN PVOID Base
  28. );
  29. VOID
  30. KiSetDescriptorBase (
  31. IN USHORT Selector,
  32. IN PKGDTENTRY64 GdtBase,
  33. IN PVOID Base
  34. );
  35. #if defined(KE_MULTINODE)
  36. NTSTATUS
  37. KiNotNumaQueryProcessorNode (
  38. IN ULONG ProcessorNumber,
  39. OUT PUSHORT Identifier,
  40. OUT PUCHAR Node
  41. );
  42. #pragma alloc_text(INIT, KiNotNumaQueryProcessorNode)
  43. #endif
  44. #pragma alloc_text(INIT, KeStartAllProcessors)
  45. #pragma alloc_text(INIT, KiCopyDescriptorMemory)
  46. #pragma alloc_text(INIT, KiSetDescriptorBase)
  47. #pragma alloc_text(INIT, KiAllProcessorsStarted)
  48. ULONG KiBarrierWait = 0;
  49. //
  50. // Statically allocate enough KNODE structures to allow memory management
  51. // to allocate pages by node during system initialization. As processors
  52. // are brought online, real KNODE structures are allocated in the correct
  53. // memory for the node.
  54. //
  55. #if defined(KE_MULTINODE)
  56. PHALNUMAQUERYPROCESSORNODE KiQueryProcessorNode = KiNotNumaQueryProcessorNode;
  57. #pragma data_seg("INITDATA")
  58. KNODE KiNodeInit[MAXIMUM_CCNUMA_NODES];
  59. #endif
  60. VOID
  61. KeStartAllProcessors (
  62. VOID
  63. )
  64. /*++
  65. Routine Description:
  66. This function is called during phase 1 initialization on the master boot
  67. processor to start all of the other registered processors.
  68. Arguments:
  69. None.
  70. Return Value:
  71. None.
  72. --*/
  73. {
  74. #if !defined(NT_UP)
  75. KAFFINITY Affinity;
  76. ULONG AllocationSize;
  77. PUCHAR Base;
  78. PKPCR CurrentPcr = KeGetPcr();
  79. PVOID DataBlock;
  80. PKTSS64 DfTssBase;
  81. PVOID DpcStack;
  82. PKGDTENTRY64 GdtBase;
  83. ULONG GdtOffset;
  84. ULONG IdtOffset;
  85. PVOID KernelStack;
  86. PKTSS64 NmiTssBase;
  87. PKNODE Node;
  88. UCHAR NodeNumber;
  89. UCHAR Number;
  90. PKPCR PcrBase;
  91. USHORT ProcessorId;
  92. KPROCESSOR_STATE ProcessorState;
  93. NTSTATUS Status;
  94. PKTSS64 SysTssBase;
  95. PETHREAD Thread;
  96. //
  97. // If processor zero is not on node zero, then move it to the appropriate
  98. // node.
  99. //
  100. #if defined(KE_MULTINODE)
  101. if (KeNumberNodes > 1) {
  102. Status = KiQueryProcessorNode(0, &ProcessorId, &NodeNumber);
  103. if (NT_SUCCESS(Status)) {
  104. if (NodeNumber != 0) {
  105. KeNodeBlock[0]->ProcessorMask &= ~1;
  106. KeNodeBlock[NodeNumber]->ProcessorMask |= 1;
  107. KeGetCurrentPrcb()->ParentNode = KeNodeBlock[NodeNumber];
  108. }
  109. }
  110. }
  111. #else
  112. NodeNumber = 0;
  113. #endif
  114. //
  115. // Calculate the size of the per processor data structures.
  116. //
  117. // This includes:
  118. //
  119. // PCR (including the PRCB)
  120. // System TSS
  121. // Idle Thread Object
  122. // Double Fault/NMI Panic Stack
  123. // Machine Check Stack
  124. // GDT
  125. // IDT
  126. //
  127. // If this is a multinode system, the KNODE structure is also allocated.
  128. //
  129. // A DPC and Idle stack are also allocated, but they are done separately.
  130. //
  131. AllocationSize = ROUNDUP16(sizeof(KPCR)) +
  132. ROUNDUP16(sizeof(KTSS64)) +
  133. ROUNDUP16(sizeof(ETHREAD)) +
  134. ROUNDUP16(DOUBLE_FAULT_STACK_SIZE) +
  135. ROUNDUP16(KERNEL_MCA_EXCEPTION_STACK_SIZE);
  136. #if defined(KE_MULTINODE)
  137. AllocationSize += ROUNDUP16(sizeof(KNODE));
  138. #endif
  139. //
  140. // Save the offset of the GDT in the allocation structure and add in
  141. // the size of the GDT.
  142. //
  143. GdtOffset = AllocationSize;
  144. AllocationSize +=
  145. CurrentPcr->Prcb.ProcessorState.SpecialRegisters.Gdtr.Limit + 1;
  146. //
  147. // Save the offset of the IDT in the allocation structure and add in
  148. // the size of the IDT.
  149. //
  150. IdtOffset = AllocationSize;
  151. AllocationSize +=
  152. CurrentPcr->Prcb.ProcessorState.SpecialRegisters.Idtr.Limit + 1;
  153. //
  154. // If the registered number of processors is greater than the maximum
  155. // number of processors supported, then only allow the maximum number
  156. // of supported processors.
  157. //
  158. if (KeRegisteredProcessors > MAXIMUM_PROCESSORS) {
  159. KeRegisteredProcessors = MAXIMUM_PROCESSORS;
  160. }
  161. //
  162. // Set barrier that will prevent any other processor from entering the
  163. // idle loop until all processors have been started.
  164. //
  165. KiBarrierWait = 1;
  166. //
  167. // Initialize the fixed part of the processor state that will be used to
  168. // start processors. Each processor starts in the system initialization
  169. // code with address of the loader parameter block as an argument.
  170. //
  171. RtlZeroMemory(&ProcessorState, sizeof(KPROCESSOR_STATE));
  172. ProcessorState.ContextFrame.Rcx = (ULONG64)KeLoaderBlock;
  173. ProcessorState.ContextFrame.Rip = (ULONG64)KiSystemStartup;
  174. ProcessorState.ContextFrame.SegCs = KGDT64_R0_CODE;
  175. ProcessorState.ContextFrame.SegDs = KGDT64_R3_DATA | RPL_MASK;
  176. ProcessorState.ContextFrame.SegEs = KGDT64_R3_DATA | RPL_MASK;
  177. ProcessorState.ContextFrame.SegFs = KGDT64_R3_CMTEB | RPL_MASK;
  178. ProcessorState.ContextFrame.SegGs = KGDT64_R3_DATA | RPL_MASK;
  179. ProcessorState.ContextFrame.SegSs = KGDT64_R3_DATA | RPL_MASK;
  180. //
  181. // Loop trying to start a new processors until a new processor can't be
  182. // started or an allocation failure occurs.
  183. //
  184. Number = 0;
  185. while ((ULONG)KeNumberProcessors < KeRegisteredProcessors) {
  186. Number++;
  187. #if defined(KE_MULTINODE)
  188. Status = KiQueryProcessorNode(Number, &ProcessorId, &NodeNumber);
  189. if (!NT_SUCCESS(Status)) {
  190. //
  191. // No such processor, advance to next.
  192. //
  193. continue;
  194. }
  195. Node = KeNodeBlock[NodeNumber];
  196. #endif
  197. //
  198. // Allocate memory for the new processor specific data. If the
  199. // allocation fails, then stop starting processors.
  200. //
  201. DataBlock = MmAllocateIndependentPages(AllocationSize, NodeNumber);
  202. if (DataBlock == NULL) {
  203. break;
  204. }
  205. //
  206. // Zero the allocated memory.
  207. //
  208. Base = (PUCHAR)DataBlock;
  209. RtlZeroMemory(DataBlock, AllocationSize);
  210. //
  211. // Copy and initialize the GDT for the next processor.
  212. //
  213. KiCopyDescriptorMemory(&CurrentPcr->Prcb.ProcessorState.SpecialRegisters.Gdtr,
  214. &ProcessorState.SpecialRegisters.Gdtr,
  215. Base + GdtOffset);
  216. GdtBase = (PKGDTENTRY64)ProcessorState.SpecialRegisters.Gdtr.Base;
  217. //
  218. // Copy and initialize the IDT for the next processor.
  219. //
  220. KiCopyDescriptorMemory(&CurrentPcr->Prcb.ProcessorState.SpecialRegisters.Gdtr,
  221. &ProcessorState.SpecialRegisters.Idtr,
  222. Base + IdtOffset);
  223. //
  224. // Set the PCR base address for the next processor and set the
  225. // processor number.
  226. //
  227. // N.B. The PCR address is passed to the next processor by computing
  228. // the containing address with respect to the PRCB.
  229. //
  230. PcrBase = (PKPCR)Base;
  231. PcrBase->Number = Number;
  232. Base += ROUNDUP16(sizeof(KPCR));
  233. //
  234. // Set the system TSS descriptor base for the next processor.
  235. //
  236. SysTssBase = (PKTSS64)Base;
  237. KiSetDescriptorBase(KGDT64_SYS_TSS / 16, GdtBase, SysTssBase);
  238. Base += ROUNDUP16(sizeof(KTSS64));
  239. //
  240. // Initialize the panic stack address for double fault and NMI.
  241. //
  242. Base += DOUBLE_FAULT_STACK_SIZE;
  243. SysTssBase->Ist[TSS_IST_PANIC] = (ULONG64)Base;
  244. //
  245. // Initialize the machine check stack address.
  246. //
  247. Base += KERNEL_MCA_EXCEPTION_STACK_SIZE;
  248. SysTssBase->Ist[TSS_IST_MCA] = (ULONG64)Base;
  249. //
  250. // Idle Thread thread object.
  251. //
  252. Thread = (PETHREAD)Base;
  253. Base += ROUNDUP16(sizeof(ETHREAD));
  254. //
  255. // Set other special registers in the processor state.
  256. //
  257. ProcessorState.SpecialRegisters.Cr0 = ReadCR0();
  258. ProcessorState.SpecialRegisters.Cr3 = ReadCR3();
  259. ProcessorState.ContextFrame.EFlags = 0; // ******fixfix what should this be??
  260. ProcessorState.SpecialRegisters.Tr = KGDT64_SYS_TSS;
  261. GdtBase[KGDT64_SYS_TSS / 16].Bytes.Flags1 = 0x89;
  262. ProcessorState.SpecialRegisters.Cr4 = CR4_PAE;
  263. //
  264. // Allocate a kernel stack and a DPC stack for the next processor.
  265. //
  266. KernelStack = MmCreateKernelStack(FALSE, NodeNumber);
  267. DpcStack = MmCreateKernelStack(FALSE, NodeNumber);
  268. if ((DpcStack == NULL) || (KernelStack == NULL)) {
  269. MmFreeIndependentPages(DataBlock, AllocationSize);
  270. break;
  271. }
  272. //
  273. // Initialize the kernel stack for the system TSS.
  274. //
  275. SysTssBase->Rsp0 = (ULONG64)KernelStack;
  276. ProcessorState.ContextFrame.Rsp = (ULONG64)KernelStack;
  277. //
  278. // If this is the first processor on this node, then use the space
  279. // allocated for KNODE as the KNODE.
  280. //
  281. #if defined(KE_MULTINODE)
  282. if (KeNodeBlock[NodeNumber] == &KiNodeInit[NodeNumber]) {
  283. Node = (PKNODE)Base;
  284. *Node = KiNodeInit[NodeNumber];
  285. KeNodeBlock[NodeNumber] = Node;
  286. }
  287. Base += ROUNDUP16(sizeof(KNODE));
  288. PcrBase->Prcb.ParentNode = Node;
  289. #else
  290. PcrBase->Prcb.ParentNode = KeNodeBlock[0];
  291. #endif
  292. //
  293. // Adjust the loader block so it has the next processor state.
  294. //
  295. KeLoaderBlock->KernelStack = (ULONG64)DpcStack;
  296. KeLoaderBlock->Thread = (ULONG64)Thread;
  297. KeLoaderBlock->Prcb = (ULONG64)(&PcrBase->Prcb);
  298. //
  299. // Attempt to start the next processor. If a processor cannot be
  300. // started, then deallocate memory and stop starting processors.
  301. //
  302. if (HalStartNextProcessor(KeLoaderBlock, &ProcessorState) == 0) {
  303. MmFreeIndependentPages(DataBlock, AllocationSize);
  304. MmDeleteKernelStack(KernelStack, FALSE);
  305. MmDeleteKernelStack(DpcStack, FALSE);
  306. break;
  307. }
  308. #if defined(KE_MULTINODE)
  309. Node->ProcessorMask |= AFFINITY_MASK(Number);
  310. #endif
  311. //
  312. // Wait for processor to initialize.
  313. //
  314. while (*((volatile ULONG64 *)&KeLoaderBlock->Prcb) != 0) {
  315. KeYieldProcessor();
  316. }
  317. Number += 1;
  318. }
  319. //
  320. // All processors have been stated.
  321. //
  322. KiAllProcessorsStarted();
  323. //
  324. // Reset and synchronize the performance counters of all processors, by
  325. // applying a null adjustment to the interrupt time
  326. //
  327. KiAdjustInterruptTime(0);
  328. //
  329. // Allow all processors that were started to enter the idle loop and
  330. // begin execution.
  331. //
  332. KiBarrierWait = 0;
  333. #endif // !defined(NT_UP)
  334. return;
  335. }
  336. VOID
  337. KiSetDescriptorBase (
  338. IN USHORT Selector,
  339. IN PKGDTENTRY64 GdtBase,
  340. IN PVOID Base
  341. )
  342. /*++
  343. Routine Description:
  344. This function sets the base address of a descriptor to the specified
  345. base address.
  346. Arguments:
  347. Selector - Supplies the selector for the descriptor.
  348. GdtBase - Supplies a pointer to the GDT.
  349. Base - Supplies a pointer to the base address.
  350. Return Value:
  351. None.
  352. --*/
  353. {
  354. GdtBase = &GdtBase[Selector];
  355. GdtBase->BaseLow = (USHORT)((ULONG64)Base);
  356. GdtBase->Bytes.BaseMiddle = (UCHAR)((ULONG64)Base >> 16);
  357. GdtBase->Bytes.BaseHigh = (UCHAR)((ULONG64)Base >> 24);
  358. GdtBase->BaseUpper = (ULONG)((ULONG64)Base >> 32);
  359. return;
  360. }
  361. VOID
  362. KiCopyDescriptorMemory (
  363. IN PKDESCRIPTOR Source,
  364. IN PKDESCRIPTOR Destination,
  365. IN PVOID Base
  366. )
  367. /*++
  368. Routine Description:
  369. This function copies the specified descriptor memory to the new memory
  370. and initializes a descriptor for the new memory.
  371. Arguments:
  372. Source - Supplies a pointer to the source descriptor that describes
  373. the memory to copy.
  374. Destination - Supplies a pointer to the destination descriptor to be
  375. initialized.
  376. Base - Supplies a pointer to the new memory.
  377. Return Value:
  378. None.
  379. --*/
  380. {
  381. Destination->Limit = Source->Limit;
  382. Destination->Base = Base;
  383. RtlCopyMemory(Base, Source->Base, Source->Limit + 1);
  384. return;
  385. }
  386. VOID
  387. KiAllProcessorsStarted(
  388. VOID
  389. )
  390. /*++
  391. Routine Description:
  392. This routine is called once all processors in the system have been started.
  393. Arguments:
  394. None.
  395. Return Value:
  396. None.
  397. --*/
  398. {
  399. ULONG i;
  400. //
  401. // Make sure there are no references to the temporary nodes used during
  402. // initialization.
  403. //
  404. #if defined(KE_MULTINODE)
  405. for (i = 0; i < KeNumberNodes; i += 1) {
  406. if (KeNodeBlock[i] == &KiNodeInit[i]) {
  407. //
  408. // No processor started on this node so no new node structure has
  409. // been allocated. This is possible if the node contains memory
  410. // only or IO busses. At this time we need to allocate a permanent
  411. // node structure for the node.
  412. //
  413. KeNodeBlock[i] = ExAllocatePoolWithTag(NonPagedPool,
  414. sizeof(KNODE),
  415. ' eK');
  416. if (KeNodeBlock[i]) {
  417. *KeNodeBlock[i] = KiNodeInit[i];
  418. }
  419. }
  420. }
  421. for (i = KeNumberNodes; i < MAXIMUM_CCNUMA_NODES; i += 1) {
  422. KeNodeBlock[i] = NULL;
  423. }
  424. #endif
  425. if (KeNumberNodes == 1) {
  426. //
  427. // For Non NUMA machines, Node 0 gets all processors.
  428. //
  429. KeNodeBlock[0]->ProcessorMask = KeActiveProcessors;
  430. }
  431. return;
  432. }
  433. NTSTATUS
  434. KiNotNumaQueryProcessorNode(
  435. IN ULONG ProcessorNumber,
  436. OUT PUSHORT Identifier,
  437. OUT PUCHAR Node
  438. )
  439. /*++
  440. Routine Description:
  441. This routine is a stub used on non NUMA systems to provide a
  442. consistent method of determining the NUMA configuration rather
  443. than checking for the presense of multiple nodes inline.
  444. Arguments:
  445. ProcessorNumber supplies the system logical processor number.
  446. Identifier supplies the address of a variable to receive
  447. the unique identifier for this processor.
  448. NodeNumber supplies the address of a variable to receive
  449. the number of the node this processor resides on.
  450. Return Value:
  451. Returns success.
  452. --*/
  453. {
  454. *Identifier = (USHORT)ProcessorNumber;
  455. *Node = 0;
  456. return STATUS_SUCCESS;
  457. }