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