- Fix __rdtsc so it's considered volatile by GCC instead of caching it.
[reactos.git] / reactos / ntoskrnl / ke / i386 / kiinit.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/i386/kiinit.c
5 * PURPOSE: Kernel Initialization for x86 CPUs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NTDDI_VERSION NTDDI_WS03SP1
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 /* Spinlocks used only on X86 */
19 KSPIN_LOCK KiFreezeExecutionLock;
20 KSPIN_LOCK Ki486CompatibilityLock;
21
22 /* FUNCTIONS *****************************************************************/
23
24 VOID
25 NTAPI
26 KiInitMachineDependent(VOID)
27 {
28 ULONG Protect;
29 ULONG CpuCount;
30 BOOLEAN FbCaching = FALSE;
31 NTSTATUS Status;
32 ULONG ReturnLength;
33 ULONG i, Affinity, Sample = 0;
34 PFX_SAVE_AREA FxSaveArea;
35 ULONG MXCsrMask = 0xFFBF;
36 ULONG Dummy[4];
37 KI_SAMPLE_MAP Samples[4];
38 PKI_SAMPLE_MAP CurrentSample = Samples;
39
40 /* Check for large page support */
41 if (KeFeatureBits & KF_LARGE_PAGE)
42 {
43 /* FIXME: Support this */
44 DPRINT1("Large Page support detected but not yet taken advantage of!\n");
45 }
46
47 /* Check for global page support */
48 if (KeFeatureBits & KF_GLOBAL_PAGE)
49 {
50 /* Do an IPI to enable it on all CPUs */
51 CpuCount = KeNumberProcessors;
52 KeIpiGenericCall(Ki386EnableGlobalPage, (ULONG_PTR)&CpuCount);
53 }
54
55 /* Check for PAT and/or MTRR support */
56 if (KeFeatureBits & (KF_PAT | KF_MTRR))
57 {
58 /* Query the HAL to make sure we can use it */
59 Status = HalQuerySystemInformation(HalFrameBufferCachingInformation,
60 sizeof(BOOLEAN),
61 &FbCaching,
62 &ReturnLength);
63 if ((NT_SUCCESS(Status)) && (FbCaching))
64 {
65 /* We can't, disable it */
66 KeFeatureBits &= ~(KF_PAT | KF_MTRR);
67 }
68 }
69
70 /* Check for PAT support and enable it */
71 if (KeFeatureBits & KF_PAT) KiInitializePAT();
72
73 /* Assume no errata for now */
74 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = 0;
75
76 /* Check if we have an NPX */
77 if (KeI386NpxPresent)
78 {
79 /* Loop every CPU */
80 i = KeActiveProcessors;
81 for (Affinity = 1; i; Affinity <<= 1)
82 {
83 /* Check if this is part of the set */
84 if (i & Affinity)
85 {
86 /* Run on this CPU */
87 i &= ~Affinity;
88 KeSetSystemAffinityThread(Affinity);
89
90 /* Detect FPU errata */
91 if (KiIsNpxErrataPresent())
92 {
93 /* Disable NPX support */
94 KeI386NpxPresent = FALSE;
95 SharedUserData->
96 ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] =
97 TRUE;
98 break;
99 }
100 }
101 }
102 }
103
104 /* If there's no NPX, then we're emulating the FPU */
105 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] =
106 !KeI386NpxPresent;
107
108 /* Check if there's no NPX, so that we can disable associated features */
109 if (!KeI386NpxPresent)
110 {
111 /* Remove NPX-related bits */
112 KeFeatureBits &= ~(KF_XMMI64 | KF_XMMI | KF_FXSR | KF_MMX);
113
114 /* Disable kernel flags */
115 KeI386FxsrPresent = KeI386XMMIPresent = FALSE;
116
117 /* Disable processor features that might've been set until now */
118 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] =
119 SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
120 SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
121 SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
122 SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = 0;
123 }
124
125 /* Check for CR4 support */
126 if (KeFeatureBits & KF_CR4)
127 {
128 /* Do an IPI call to enable the Debug Exceptions */
129 CpuCount = KeNumberProcessors;
130 KeIpiGenericCall(Ki386EnableDE, (ULONG_PTR)&CpuCount);
131 }
132
133 /* Check if FXSR was found */
134 if (KeFeatureBits & KF_FXSR)
135 {
136 /* Do an IPI call to enable the FXSR */
137 CpuCount = KeNumberProcessors;
138 KeIpiGenericCall(Ki386EnableFxsr, (ULONG_PTR)&CpuCount);
139
140 /* Check if XMM was found too */
141 if (KeFeatureBits & KF_XMMI)
142 {
143 /* Do an IPI call to enable XMMI exceptions */
144 CpuCount = KeNumberProcessors;
145 KeIpiGenericCall(Ki386EnableXMMIExceptions, (ULONG_PTR)&CpuCount);
146
147 /* FIXME: Implement and enable XMM Page Zeroing for Mm */
148
149 /* Patch the RtlPrefetchMemoryNonTemporal routine to enable it */
150 Protect = MmGetPageProtect(NULL, RtlPrefetchMemoryNonTemporal);
151 MmSetPageProtect(NULL,
152 RtlPrefetchMemoryNonTemporal,
153 Protect | PAGE_IS_WRITABLE);
154 *(PCHAR)RtlPrefetchMemoryNonTemporal = 0x90;
155 MmSetPageProtect(NULL, RtlPrefetchMemoryNonTemporal, Protect);
156 }
157 }
158
159 /* Check for, and enable SYSENTER support */
160 KiRestoreFastSyscallReturnState();
161
162 /* Loop every CPU */
163 i = KeActiveProcessors;
164 for (Affinity = 1; i; Affinity <<= 1)
165 {
166 /* Check if this is part of the set */
167 if (i & Affinity)
168 {
169 /* Run on this CPU */
170 i &= ~Affinity;
171 KeSetSystemAffinityThread(Affinity);
172
173 /* Reset MHz to 0 for this CPU */
174 KeGetCurrentPrcb()->MHz = 0;
175
176 /* Check if we can use RDTSC */
177 if (KeFeatureBits & KF_RDTSC)
178 {
179 /* Start sampling loop */
180 for (;;)
181 {
182 /* Do a dummy CPUID to start the sample */
183 CPUID(Dummy, 0);
184
185 /* Fill out the starting data */
186 CurrentSample->PerfStart = KeQueryPerformanceCounter(NULL);
187 CurrentSample->TSCStart = __rdtsc();
188 CurrentSample->PerfFreq.QuadPart = -50000;
189
190 /* Sleep for this sample */
191 KeDelayExecutionThread(KernelMode,
192 FALSE,
193 &CurrentSample->PerfFreq);
194
195 /* Do another dummy CPUID */
196 CPUID(Dummy, 0);
197
198 /* Fill out the ending data */
199 CurrentSample->PerfEnd =
200 KeQueryPerformanceCounter(&CurrentSample->PerfFreq);
201 CurrentSample->TSCEnd = __rdtsc();
202
203 /* Calculate the differences */
204 CurrentSample->PerfDelta = CurrentSample->PerfEnd.QuadPart -
205 CurrentSample->PerfStart.QuadPart;
206 CurrentSample->TSCDelta = CurrentSample->TSCEnd -
207 CurrentSample->TSCStart;
208
209 /* Compute CPU Speed */
210 CurrentSample->MHz = ((CurrentSample->TSCDelta *
211 CurrentSample->PerfFreq.QuadPart +
212 500000) /
213 (CurrentSample->PerfDelta * 1000000));
214
215 /* Check if this isn't the first sample */
216 if (Sample)
217 {
218 /* Check if we got a good precision within 1MHz */
219 if ((CurrentSample->MHz == CurrentSample[-1].MHz) ||
220 (CurrentSample->MHz == CurrentSample[-1].MHz + 1) ||
221 (CurrentSample->MHz == CurrentSample[-1].MHz - 1))
222 {
223 /* We did, stop sampling */
224 break;
225 }
226 }
227
228 /* Move on */
229 CurrentSample++;
230 Sample++;
231 }
232
233 /* Save the CPU Speed */
234 KeGetCurrentPrcb()->MHz = CurrentSample[-1].MHz;
235 }
236
237 /* Check if we have MTRR */
238 if (KeFeatureBits & KF_MTRR)
239 {
240 /* Then manually initialize MTRR for the CPU */
241 KiInitializeMTRR((BOOLEAN)i ? FALSE : TRUE);
242 }
243
244 /* Check if we have AMD MTRR and initialize it for the CPU */
245 if (KeFeatureBits & KF_AMDK6MTRR) KiAmdK6InitializeMTRR();
246
247 /* Check if this is a buggy Pentium and apply the fixup if so */
248 if (KiI386PentiumLockErrataPresent) KiI386PentiumLockErrataFixup();
249
250 /* Check if the CPU supports FXSR */
251 if (KeFeatureBits & KF_FXSR)
252 {
253 /* Get the current thread NPX state */
254 FxSaveArea = (PVOID)
255 ((ULONG_PTR)KeGetCurrentThread()->InitialStack -
256 NPX_FRAME_LENGTH);
257
258 /* Clear initial MXCsr mask */
259 FxSaveArea->U.FxArea.MXCsrMask = 0;
260
261 /* Save the current NPX State */
262 #ifdef __GNUC__
263 asm volatile("fxsave %0\n\t" : "=m" (*FxSaveArea));
264 #else
265 __asm fxsave [FxSaveArea]
266 #endif
267 /* Check if the current mask doesn't match the reserved bits */
268 if (FxSaveArea->U.FxArea.MXCsrMask != 0)
269 {
270 /* Then use whatever it's holding */
271 MXCsrMask = FxSaveArea->U.FxArea.MXCsrMask;
272 }
273
274 /* Check if nobody set the kernel-wide mask */
275 if (!KiMXCsrMask)
276 {
277 /* Then use the one we calculated above */
278 KiMXCsrMask = MXCsrMask;
279 }
280 else
281 {
282 /* Was it set to the same value we found now? */
283 if (KiMXCsrMask != MXCsrMask)
284 {
285 /* No, something is definitely wrong */
286 KEBUGCHECKEX(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED,
287 KF_FXSR,
288 KiMXCsrMask,
289 MXCsrMask,
290 0);
291 }
292 }
293
294 /* Now set the kernel mask */
295 KiMXCsrMask &= MXCsrMask;
296 }
297 }
298 }
299
300 /* Return affinity back to where it was */
301 KeRevertToUserAffinityThread();
302
303 /* NT allows limiting the duration of an ISR with a registry key */
304 if (KiTimeLimitIsrMicroseconds)
305 {
306 /* FIXME: TODO */
307 DPRINT1("ISR Time Limit not yet supported\n");
308 }
309 }
310
311 VOID
312 NTAPI
313 KiInitializePcr(IN ULONG ProcessorNumber,
314 IN PKIPCR Pcr,
315 IN PKIDTENTRY Idt,
316 IN PKGDTENTRY Gdt,
317 IN PKTSS Tss,
318 IN PKTHREAD IdleThread,
319 IN PVOID DpcStack)
320 {
321 /* Setup the TIB */
322 Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
323 Pcr->NtTib.StackBase = 0;
324 Pcr->NtTib.StackLimit = 0;
325 Pcr->NtTib.Self = NULL;
326
327 /* Set the Current Thread */
328 Pcr->PrcbData.CurrentThread = IdleThread;
329
330 /* Set pointers to ourselves */
331 Pcr->Self = (PKPCR)Pcr;
332 Pcr->Prcb = &Pcr->PrcbData;
333
334 /* Set the PCR Version */
335 Pcr->MajorVersion = PCR_MAJOR_VERSION;
336 Pcr->MinorVersion = PCR_MINOR_VERSION;
337
338 /* Set the PCRB Version */
339 Pcr->PrcbData.MajorVersion = 1;
340 Pcr->PrcbData.MinorVersion = 1;
341
342 /* Set the Build Type */
343 Pcr->PrcbData.BuildType = 0;
344 #ifndef CONFIG_SMP
345 Pcr->PrcbData.BuildType |= PRCB_BUILD_UNIPROCESSOR;
346 #endif
347 #ifdef DBG
348 Pcr->PrcbData.BuildType |= PRCB_BUILD_DEBUG;
349 #endif
350
351 /* Set the Processor Number and current Processor Mask */
352 Pcr->PrcbData.Number = (UCHAR)ProcessorNumber;
353 Pcr->PrcbData.SetMember = 1 << ProcessorNumber;
354
355 /* Set the PRCB for this Processor */
356 KiProcessorBlock[ProcessorNumber] = Pcr->Prcb;
357
358 /* Start us out at PASSIVE_LEVEL */
359 Pcr->Irql = PASSIVE_LEVEL;
360
361 /* Set the GDI, IDT, TSS and DPC Stack */
362 Pcr->GDT = (PVOID)Gdt;
363 Pcr->IDT = Idt;
364 Pcr->TSS = Tss;
365 Pcr->TssCopy = Tss;
366 Pcr->PrcbData.DpcStack = DpcStack;
367
368 /* Setup the processor set */
369 Pcr->PrcbData.MultiThreadProcessorSet = Pcr->PrcbData.SetMember;
370 }
371
372 VOID
373 NTAPI
374 KiInitializeKernel(IN PKPROCESS InitProcess,
375 IN PKTHREAD InitThread,
376 IN PVOID IdleStack,
377 IN PKPRCB Prcb,
378 IN CCHAR Number,
379 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
380 {
381 BOOLEAN NpxPresent;
382 ULONG FeatureBits;
383 LARGE_INTEGER PageDirectory;
384 PVOID DpcStack;
385 ULONG NXSupportPolicy;
386 ULONG Vendor[3];
387
388 /* Detect and set the CPU Type */
389 KiSetProcessorType();
390
391 /* Set CR0 features based on detected CPU */
392 KiSetCR0Bits();
393
394 /* Check if an FPU is present */
395 NpxPresent = KiIsNpxPresent();
396
397 /* Initialize the Power Management Support for this PRCB */
398 PoInitializePrcb(Prcb);
399
400 /* Bugcheck if this is a 386 CPU */
401 if (Prcb->CpuType == 3) KeBugCheckEx(0x5D, 0x386, 0, 0, 0);
402
403 /* Get the processor features for the CPU */
404 FeatureBits = KiGetFeatureBits();
405
406 /* Set the default NX policy (opt-in) */
407 NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN;
408
409 /* Check if NPX is always on */
410 if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSON"))
411 {
412 /* Set it always on */
413 NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON;
414 FeatureBits |= KF_NX_ENABLED;
415 }
416 else if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTOUT"))
417 {
418 /* Set it in opt-out mode */
419 NXSupportPolicy = NX_SUPPORT_POLICY_OPTOUT;
420 FeatureBits |= KF_NX_ENABLED;
421 }
422 else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTIN")) ||
423 (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE")))
424 {
425 /* Set the feature bits */
426 FeatureBits |= KF_NX_ENABLED;
427 }
428 else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSOFF")) ||
429 (strstr(KeLoaderBlock->LoadOptions, "EXECUTE")))
430 {
431 /* Set disabled mode */
432 NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSOFF;
433 FeatureBits |= KF_NX_DISABLED;
434 }
435
436 /* Save feature bits */
437 Prcb->FeatureBits = FeatureBits;
438
439 /* Save CPU state */
440 KiSaveProcessorControlState(&Prcb->ProcessorState);
441
442 /* Get cache line information for this CPU */
443 KiGetCacheInformation();
444
445 /* Initialize spinlocks and DPC data */
446 KiInitSpinLocks(Prcb, Number);
447
448 /* Check if this is the Boot CPU */
449 if (!Number)
450 {
451 /* Set Node Data */
452 KeNodeBlock[0] = &KiNode0;
453 Prcb->ParentNode = KeNodeBlock[0];
454 KeNodeBlock[0]->ProcessorMask = Prcb->SetMember;
455
456 /* Set boot-level flags */
457 KeI386NpxPresent = NpxPresent;
458 KeI386CpuType = Prcb->CpuType;
459 KeI386CpuStep = Prcb->CpuStep;
460 KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
461 KeProcessorLevel = (USHORT)Prcb->CpuType;
462 if (Prcb->CpuID) KeProcessorRevision = Prcb->CpuStep;
463 KeFeatureBits = FeatureBits;
464 KeI386FxsrPresent = (KeFeatureBits & KF_FXSR) ? TRUE : FALSE;
465 KeI386XMMIPresent = (KeFeatureBits & KF_XMMI) ? TRUE : FALSE;
466
467 /* Detect 8-byte compare exchange support */
468 if (!(KeFeatureBits & KF_CMPXCHG8B))
469 {
470 /* Copy the vendor string */
471 RtlCopyMemory(Vendor, Prcb->VendorString, sizeof(Vendor));
472
473 /* Bugcheck the system. Windows *requires* this */
474 KeBugCheckEx(0x5D,
475 (1 << 24 ) | (Prcb->CpuType << 16) | Prcb->CpuStep,
476 Vendor[0],
477 Vendor[1],
478 Vendor[2]);
479 }
480
481 /* Set the current MP Master KPRCB to the Boot PRCB */
482 Prcb->MultiThreadSetMaster = Prcb;
483
484 /* Lower to APC_LEVEL */
485 KeLowerIrql(APC_LEVEL);
486
487 /* Initialize some spinlocks */
488 KeInitializeSpinLock(&KiFreezeExecutionLock);
489 KeInitializeSpinLock(&Ki486CompatibilityLock);
490
491 /* Initialize portable parts of the OS */
492 KiInitSystem();
493
494 /* Initialize the Idle Process and the Process Listhead */
495 InitializeListHead(&KiProcessListHead);
496 PageDirectory.QuadPart = 0;
497 KeInitializeProcess(InitProcess,
498 0,
499 0xFFFFFFFF,
500 &PageDirectory,
501 FALSE);
502 InitProcess->QuantumReset = MAXCHAR;
503 }
504 else
505 {
506 /* FIXME */
507 DPRINT1("SMP Boot support not yet present\n");
508 }
509
510 /* Setup the Idle Thread */
511 KeInitializeThread(InitProcess,
512 InitThread,
513 NULL,
514 NULL,
515 NULL,
516 NULL,
517 NULL,
518 IdleStack);
519 InitThread->NextProcessor = Number;
520 InitThread->Priority = HIGH_PRIORITY;
521 InitThread->State = Running;
522 InitThread->Affinity = 1 << Number;
523 InitThread->WaitIrql = DISPATCH_LEVEL;
524 InitProcess->ActiveProcessors = 1 << Number;
525
526 /* HACK for MmUpdatePageDir */
527 ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess;
528
529 /* Initialize Kernel Memory Address Space */
530 MmInit1(MmFreeLdrFirstKrnlPhysAddr,
531 MmFreeLdrLastKrnlPhysAddr,
532 MmFreeLdrLastKernelAddress,
533 NULL,
534 0,
535 4096);
536
537 /* Sets up the Text Sections of the Kernel and HAL for debugging */
538 LdrInit1();
539
540 /* Set the NX Support policy */
541 SharedUserData->NXSupportPolicy = (UCHAR)NXSupportPolicy;
542
543 /* Set basic CPU Features that user mode can read */
544 SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
545 (KeFeatureBits & KF_MMX) ? TRUE: FALSE;
546 SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] =
547 (KeFeatureBits & KF_CMPXCHG8B) ? TRUE: FALSE;
548 SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
549 ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI)) ? TRUE: FALSE;
550 SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
551 ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI64)) ? TRUE: FALSE;
552 SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
553 (KeFeatureBits & KF_3DNOW) ? TRUE: FALSE;
554 SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] =
555 (KeFeatureBits & KF_RDTSC) ? TRUE: FALSE;
556
557 /* Set up the thread-related fields in the PRCB */
558 Prcb->CurrentThread = InitThread;
559 Prcb->NextThread = NULL;
560 Prcb->IdleThread = InitThread;
561
562 /* Initialize the Kernel Executive */
563 ExpInitializeExecutive(Number, LoaderBlock);
564
565 /* Only do this on the boot CPU */
566 if (!Number)
567 {
568 /* Calculate the time reciprocal */
569 KiTimeIncrementReciprocal =
570 KiComputeReciprocal(KeMaximumIncrement,
571 &KiTimeIncrementShiftCount);
572
573 /* Update DPC Values in case they got updated by the executive */
574 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
575 Prcb->MinimumDpcRate = KiMinimumDpcRate;
576 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
577
578 /* Allocate the DPC Stack */
579 DpcStack = MmCreateKernelStack(FALSE);
580 if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);
581 Prcb->DpcStack = DpcStack;
582
583 /* Allocate the IOPM save area. */
584 Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
585 PAGE_SIZE * 2,
586 TAG('K', 'e', ' ', ' '));
587 if (!Ki386IopmSaveArea)
588 {
589 /* Bugcheck. We need this for V86/VDM support. */
590 KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
591 }
592 }
593
594 /* Raise to Dispatch */
595 KfRaiseIrql(DISPATCH_LEVEL);
596
597 /* Set the Idle Priority to 0. This will jump into Phase 1 */
598 KeSetPriorityThread(InitThread, 0);
599
600 /* If there's no thread scheduled, put this CPU in the Idle summary */
601 KiAcquirePrcbLock(Prcb);
602 if (!Prcb->NextThread) KiIdleSummary |= 1 << Number;
603 KiReleasePrcbLock(Prcb);
604
605 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
606 KfRaiseIrql(HIGH_LEVEL);
607 LoaderBlock->Prcb = 0;
608 }
609
610 VOID
611 FASTCALL
612 KiGetMachineBootPointers(IN PKGDTENTRY *Gdt,
613 IN PKIDTENTRY *Idt,
614 IN PKIPCR *Pcr,
615 IN PKTSS *Tss)
616 {
617 KDESCRIPTOR GdtDescriptor, IdtDescriptor;
618 KGDTENTRY TssSelector, PcrSelector;
619 USHORT Tr, Fs;
620
621 /* Get GDT and IDT descriptors */
622 Ke386GetGlobalDescriptorTable(GdtDescriptor);
623 Ke386GetInterruptDescriptorTable(IdtDescriptor);
624
625 /* Save IDT and GDT */
626 *Gdt = (PKGDTENTRY)GdtDescriptor.Base;
627 *Idt = (PKIDTENTRY)IdtDescriptor.Base;
628
629 /* Get TSS and FS Selectors */
630 Ke386GetTr(Tr);
631 if (Tr != KGDT_TSS) Tr = KGDT_TSS; // FIXME: HACKHACK
632 Fs = Ke386GetFs();
633
634 /* Get PCR Selector, mask it and get its GDT Entry */
635 PcrSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Fs & ~RPL_MASK));
636
637 /* Get the KPCR itself */
638 *Pcr = (PKIPCR)(ULONG_PTR)(PcrSelector.BaseLow |
639 PcrSelector.HighWord.Bytes.BaseMid << 16 |
640 PcrSelector.HighWord.Bytes.BaseHi << 24);
641
642 /* Get TSS Selector, mask it and get its GDT Entry */
643 TssSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Tr & ~RPL_MASK));
644
645 /* Get the KTSS itself */
646 *Tss = (PKTSS)(ULONG_PTR)(TssSelector.BaseLow |
647 TssSelector.HighWord.Bytes.BaseMid << 16 |
648 TssSelector.HighWord.Bytes.BaseHi << 24);
649 }
650
651 VOID
652 NTAPI
653 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
654 {
655 ULONG Cpu;
656 PKTHREAD InitialThread;
657 ULONG InitialStack;
658 PKGDTENTRY Gdt;
659 PKIDTENTRY Idt;
660 PKTSS Tss;
661 PKIPCR Pcr;
662
663 /* Save the loader block and get the current CPU */
664 KeLoaderBlock = LoaderBlock;
665 Cpu = KeNumberProcessors;
666 if (!Cpu)
667 {
668 /* If this is the boot CPU, set FS and the CPU Number*/
669 Ke386SetFs(KGDT_R0_PCR);
670 __writefsdword(KPCR_PROCESSOR_NUMBER, Cpu);
671
672 /* Set the initial stack and idle thread as well */
673 LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack;
674 LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread;
675 }
676
677 /* Save the initial thread and stack */
678 InitialStack = LoaderBlock->KernelStack;
679 InitialThread = (PKTHREAD)LoaderBlock->Thread;
680
681 /* Clean the APC List Head */
682 InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]);
683
684 /* Initialize the machine type */
685 KiInitializeMachineType();
686
687 /* Skip initial setup if this isn't the Boot CPU */
688 if (Cpu) goto AppCpuInit;
689
690 /* Get GDT, IDT, PCR and TSS pointers */
691 KiGetMachineBootPointers(&Gdt, &Idt, &Pcr, &Tss);
692
693 /* Setup the TSS descriptors and entries */
694 Ki386InitializeTss(Tss, Idt, Gdt);
695
696 /* Initialize the PCR */
697 RtlZeroMemory(Pcr, PAGE_SIZE);
698 KiInitializePcr(Cpu,
699 Pcr,
700 Idt,
701 Gdt,
702 Tss,
703 InitialThread,
704 KiDoubleFaultStack);
705
706 /* Set us as the current process */
707 InitialThread->ApcState.Process = &KiInitialProcess.Pcb;
708
709 /* Clear DR6/7 to cleanup bootloader debugging */
710 __writefsdword(KPCR_TEB, 0);
711 __writefsdword(KPCR_DR6, 0);
712 __writefsdword(KPCR_DR7, 0);
713
714 /* Setup the IDT */
715 KeInitExceptions();
716
717 /* Load Ring 3 selectors for DS/ES */
718 Ke386SetDs(KGDT_R3_DATA | RPL_MASK);
719 Ke386SetEs(KGDT_R3_DATA | RPL_MASK);
720
721 AppCpuInit:
722 /* Loop until we can release the freeze lock */
723 do
724 {
725 /* Loop until execution can continue */
726 while ((volatile KSPIN_LOCK)KiFreezeExecutionLock == 1);
727 } while(InterlockedBitTestAndSet((PLONG)&KiFreezeExecutionLock, 0));
728
729 /* Setup CPU-related fields */
730 __writefsdword(KPCR_NUMBER, Cpu);
731 __writefsdword(KPCR_SET_MEMBER, 1 << Cpu);
732 __writefsdword(KPCR_SET_MEMBER_COPY, 1 << Cpu);
733 __writefsdword(KPCR_PRCB_SET_MEMBER, 1 << Cpu);
734
735 /* Initialize the Processor with HAL */
736 HalInitializeProcessor(Cpu, KeLoaderBlock);
737
738 /* Set active processors */
739 KeActiveProcessors |= __readfsdword(KPCR_SET_MEMBER);
740 KeNumberProcessors++;
741
742 /* Check if this is the boot CPU */
743 if (!Cpu)
744 {
745 /* Initialize debugging system */
746 KdInitSystem(0, KeLoaderBlock);
747
748 /* Check for break-in */
749 if (KdPollBreakIn()) DbgBreakPointWithStatus(1);
750 }
751
752 /* Raise to HIGH_LEVEL */
753 KfRaiseIrql(HIGH_LEVEL);
754
755 /* Align stack and make space for the trap frame and NPX frame */
756 InitialStack &= ~KTRAP_FRAME_ALIGN;
757 #ifdef __GNUC__
758 __asm__ __volatile__("movl %0,%%esp" : :"r" (InitialStack));
759 __asm__ __volatile__("subl %0,%%esp" : :"r" (NPX_FRAME_LENGTH +
760 KTRAP_FRAME_LENGTH +
761 KTRAP_FRAME_ALIGN));
762 __asm__ __volatile__("push %0" : :"r" (CR0_EM + CR0_TS + CR0_MP));
763 #else
764 __asm mov esp, InitialStack;
765 __asm sub esp, NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH;
766 __asm push CR0_EM + CR0_TS + CR0_MP
767 #endif
768
769 /* Call main kernel initialization */
770 KiInitializeKernel(&KiInitialProcess.Pcb,
771 InitialThread,
772 (PVOID)InitialStack,
773 (PKPRCB)__readfsdword(KPCR_PRCB),
774 (CCHAR)Cpu,
775 KeLoaderBlock);
776
777 /* Set the priority of this thread to 0 */
778 KeGetCurrentThread()->Priority = 0;
779
780 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
781 _enable();
782 KfLowerIrql(DISPATCH_LEVEL);
783
784 /* Set the right wait IRQL */
785 KeGetCurrentThread()->WaitIrql = DISPATCH_LEVEL;
786
787 /* Jump into the idle loop */
788 KiIdleLoop();
789 }
790