2a0a0e7c9563e5e1d131d3de3929b2d2691b15a3
[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 /* Set the NX Support policy */
537 SharedUserData->NXSupportPolicy = (UCHAR)NXSupportPolicy;
538
539 /* Set basic CPU Features that user mode can read */
540 SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
541 (KeFeatureBits & KF_MMX) ? TRUE: FALSE;
542 SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] =
543 (KeFeatureBits & KF_CMPXCHG8B) ? TRUE: FALSE;
544 SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
545 ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI)) ? TRUE: FALSE;
546 SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
547 ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI64)) ? TRUE: FALSE;
548 SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
549 (KeFeatureBits & KF_3DNOW) ? TRUE: FALSE;
550 SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] =
551 (KeFeatureBits & KF_RDTSC) ? TRUE: FALSE;
552
553 /* Set up the thread-related fields in the PRCB */
554 Prcb->CurrentThread = InitThread;
555 Prcb->NextThread = NULL;
556 Prcb->IdleThread = InitThread;
557
558 /* Initialize the Kernel Executive */
559 ExpInitializeExecutive(Number, LoaderBlock);
560
561 /* Only do this on the boot CPU */
562 if (!Number)
563 {
564 /* Calculate the time reciprocal */
565 KiTimeIncrementReciprocal =
566 KiComputeReciprocal(KeMaximumIncrement,
567 &KiTimeIncrementShiftCount);
568
569 /* Update DPC Values in case they got updated by the executive */
570 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
571 Prcb->MinimumDpcRate = KiMinimumDpcRate;
572 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
573
574 /* Allocate the DPC Stack */
575 DpcStack = MmCreateKernelStack(FALSE);
576 if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);
577 Prcb->DpcStack = DpcStack;
578
579 /* Allocate the IOPM save area. */
580 Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
581 PAGE_SIZE * 2,
582 TAG('K', 'e', ' ', ' '));
583 if (!Ki386IopmSaveArea)
584 {
585 /* Bugcheck. We need this for V86/VDM support. */
586 KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
587 }
588 }
589
590 /* Raise to Dispatch */
591 KfRaiseIrql(DISPATCH_LEVEL);
592
593 /* Set the Idle Priority to 0. This will jump into Phase 1 */
594 KeSetPriorityThread(InitThread, 0);
595
596 /* If there's no thread scheduled, put this CPU in the Idle summary */
597 KiAcquirePrcbLock(Prcb);
598 if (!Prcb->NextThread) KiIdleSummary |= 1 << Number;
599 KiReleasePrcbLock(Prcb);
600
601 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
602 KfRaiseIrql(HIGH_LEVEL);
603 LoaderBlock->Prcb = 0;
604 }
605
606 VOID
607 FASTCALL
608 KiGetMachineBootPointers(IN PKGDTENTRY *Gdt,
609 IN PKIDTENTRY *Idt,
610 IN PKIPCR *Pcr,
611 IN PKTSS *Tss)
612 {
613 KDESCRIPTOR GdtDescriptor, IdtDescriptor;
614 KGDTENTRY TssSelector, PcrSelector;
615 USHORT Tr, Fs;
616
617 /* Get GDT and IDT descriptors */
618 Ke386GetGlobalDescriptorTable(GdtDescriptor);
619 Ke386GetInterruptDescriptorTable(IdtDescriptor);
620
621 /* Save IDT and GDT */
622 *Gdt = (PKGDTENTRY)GdtDescriptor.Base;
623 *Idt = (PKIDTENTRY)IdtDescriptor.Base;
624
625 /* Get TSS and FS Selectors */
626 Ke386GetTr(Tr);
627 if (Tr != KGDT_TSS) Tr = KGDT_TSS; // FIXME: HACKHACK
628 Fs = Ke386GetFs();
629
630 /* Get PCR Selector, mask it and get its GDT Entry */
631 PcrSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Fs & ~RPL_MASK));
632
633 /* Get the KPCR itself */
634 *Pcr = (PKIPCR)(ULONG_PTR)(PcrSelector.BaseLow |
635 PcrSelector.HighWord.Bytes.BaseMid << 16 |
636 PcrSelector.HighWord.Bytes.BaseHi << 24);
637
638 /* Get TSS Selector, mask it and get its GDT Entry */
639 TssSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Tr & ~RPL_MASK));
640
641 /* Get the KTSS itself */
642 *Tss = (PKTSS)(ULONG_PTR)(TssSelector.BaseLow |
643 TssSelector.HighWord.Bytes.BaseMid << 16 |
644 TssSelector.HighWord.Bytes.BaseHi << 24);
645 }
646
647 VOID
648 NTAPI
649 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
650 {
651 ULONG Cpu;
652 PKTHREAD InitialThread;
653 ULONG InitialStack;
654 PKGDTENTRY Gdt;
655 PKIDTENTRY Idt;
656 PKTSS Tss;
657 PKIPCR Pcr;
658
659 /* Save the loader block and get the current CPU */
660 KeLoaderBlock = LoaderBlock;
661 Cpu = KeNumberProcessors;
662 if (!Cpu)
663 {
664 /* If this is the boot CPU, set FS and the CPU Number*/
665 Ke386SetFs(KGDT_R0_PCR);
666 __writefsdword(KPCR_PROCESSOR_NUMBER, Cpu);
667
668 /* Set the initial stack and idle thread as well */
669 LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack;
670 LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread;
671 }
672
673 /* Save the initial thread and stack */
674 InitialStack = LoaderBlock->KernelStack;
675 InitialThread = (PKTHREAD)LoaderBlock->Thread;
676
677 /* Clean the APC List Head */
678 InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]);
679
680 /* Initialize the machine type */
681 KiInitializeMachineType();
682
683 /* Skip initial setup if this isn't the Boot CPU */
684 if (Cpu) goto AppCpuInit;
685
686 /* Get GDT, IDT, PCR and TSS pointers */
687 KiGetMachineBootPointers(&Gdt, &Idt, &Pcr, &Tss);
688
689 /* Setup the TSS descriptors and entries */
690 Ki386InitializeTss(Tss, Idt, Gdt);
691
692 /* Initialize the PCR */
693 RtlZeroMemory(Pcr, PAGE_SIZE);
694 KiInitializePcr(Cpu,
695 Pcr,
696 Idt,
697 Gdt,
698 Tss,
699 InitialThread,
700 KiDoubleFaultStack);
701
702 /* Set us as the current process */
703 InitialThread->ApcState.Process = &KiInitialProcess.Pcb;
704
705 /* Clear DR6/7 to cleanup bootloader debugging */
706 __writefsdword(KPCR_TEB, 0);
707 __writefsdword(KPCR_DR6, 0);
708 __writefsdword(KPCR_DR7, 0);
709
710 /* Setup the IDT */
711 KeInitExceptions();
712
713 /* Load Ring 3 selectors for DS/ES */
714 Ke386SetDs(KGDT_R3_DATA | RPL_MASK);
715 Ke386SetEs(KGDT_R3_DATA | RPL_MASK);
716
717 AppCpuInit:
718 /* Loop until we can release the freeze lock */
719 do
720 {
721 /* Loop until execution can continue */
722 while ((volatile KSPIN_LOCK)KiFreezeExecutionLock == 1);
723 } while(InterlockedBitTestAndSet((PLONG)&KiFreezeExecutionLock, 0));
724
725 /* Setup CPU-related fields */
726 __writefsdword(KPCR_NUMBER, Cpu);
727 __writefsdword(KPCR_SET_MEMBER, 1 << Cpu);
728 __writefsdword(KPCR_SET_MEMBER_COPY, 1 << Cpu);
729 __writefsdword(KPCR_PRCB_SET_MEMBER, 1 << Cpu);
730
731 /* Initialize the Processor with HAL */
732 HalInitializeProcessor(Cpu, KeLoaderBlock);
733
734 /* Set active processors */
735 KeActiveProcessors |= __readfsdword(KPCR_SET_MEMBER);
736 KeNumberProcessors++;
737
738 /* Check if this is the boot CPU */
739 if (!Cpu)
740 {
741 /* Initialize debugging system */
742 KdInitSystem(0, KeLoaderBlock);
743
744 /* Check for break-in */
745 if (KdPollBreakIn()) DbgBreakPointWithStatus(1);
746 }
747
748 /* Raise to HIGH_LEVEL */
749 KfRaiseIrql(HIGH_LEVEL);
750
751 /* Align stack and make space for the trap frame and NPX frame */
752 InitialStack &= ~KTRAP_FRAME_ALIGN;
753 #ifdef __GNUC__
754 __asm__ __volatile__("movl %0,%%esp" : :"r" (InitialStack));
755 __asm__ __volatile__("subl %0,%%esp" : :"r" (NPX_FRAME_LENGTH +
756 KTRAP_FRAME_LENGTH +
757 KTRAP_FRAME_ALIGN));
758 __asm__ __volatile__("push %0" : :"r" (CR0_EM + CR0_TS + CR0_MP));
759 #else
760 __asm mov esp, InitialStack;
761 __asm sub esp, NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH;
762 __asm push CR0_EM + CR0_TS + CR0_MP
763 #endif
764
765 /* Call main kernel initialization */
766 KiInitializeKernel(&KiInitialProcess.Pcb,
767 InitialThread,
768 (PVOID)InitialStack,
769 (PKPRCB)__readfsdword(KPCR_PRCB),
770 (CCHAR)Cpu,
771 KeLoaderBlock);
772
773 /* Set the priority of this thread to 0 */
774 KeGetCurrentThread()->Priority = 0;
775
776 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
777 _enable();
778 KfLowerIrql(DISPATCH_LEVEL);
779
780 /* Set the right wait IRQL */
781 KeGetCurrentThread()->WaitIrql = DISPATCH_LEVEL;
782
783 /* Jump into the idle loop */
784 KiIdleLoop();
785 }