xref: /reactos/ntoskrnl/ke/amd64/krnlinit.c (revision 6a6b5ec2)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/ke/amd64/krnlinit.c
5  * PURPOSE:         Portable part of kernel initialization
6  * PROGRAMMERS:     Timo Kreuzer (timo.kreuzer@reactos.org)
7  *                  Alex Ionescu (alex.ionescu@reactos.org)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 extern ULONG_PTR MainSSDT[];
17 extern UCHAR MainSSPT[];
18 
19 extern BOOLEAN RtlpUse16ByteSLists;
20 
21 /* FUNCTIONS *****************************************************************/
22 
23 CODE_SEG("INIT")
24 VOID
25 NTAPI
26 KiInitializeKernel(IN PKPROCESS InitProcess,
27                    IN PKTHREAD InitThread,
28                    IN PVOID IdleStack,
29                    IN PKPRCB Prcb,
30                    IN PLOADER_PARAMETER_BLOCK LoaderBlock);
31 
32 
33 CODE_SEG("INIT")
34 VOID
35 KiCalculateCpuFrequency(
36     IN PKPRCB Prcb)
37 {
38     if (Prcb->FeatureBits & KF_RDTSC)
39     {
40         ULONG Sample = 0;
41         CPU_INFO CpuInfo;
42         KI_SAMPLE_MAP Samples[10];
43         PKI_SAMPLE_MAP CurrentSample = Samples;
44 
45         /* Start sampling loop */
46         for (;;)
47         {
48             /* Do a dummy CPUID to start the sample */
49             KiCpuId(&CpuInfo, 0);
50 
51             /* Fill out the starting data */
52             CurrentSample->PerfStart = KeQueryPerformanceCounter(NULL);
53             CurrentSample->TSCStart = __rdtsc();
54             CurrentSample->PerfFreq.QuadPart = -50000;
55 
56             /* Sleep for this sample */
57             KeStallExecutionProcessor(CurrentSample->PerfFreq.QuadPart * -1 / 10);
58 
59             /* Do another dummy CPUID */
60             KiCpuId(&CpuInfo, 0);
61 
62             /* Fill out the ending data */
63             CurrentSample->PerfEnd =
64                 KeQueryPerformanceCounter(&CurrentSample->PerfFreq);
65             CurrentSample->TSCEnd = __rdtsc();
66 
67             /* Calculate the differences */
68             CurrentSample->PerfDelta = CurrentSample->PerfEnd.QuadPart -
69                                        CurrentSample->PerfStart.QuadPart;
70             CurrentSample->TSCDelta = CurrentSample->TSCEnd -
71                                       CurrentSample->TSCStart;
72 
73             /* Compute CPU Speed */
74             CurrentSample->MHz = (ULONG)((CurrentSample->TSCDelta *
75                                           CurrentSample->
76                                           PerfFreq.QuadPart + 500000) /
77                                          (CurrentSample->PerfDelta *
78                                           1000000));
79 
80             /* Check if this isn't the first sample */
81             if (Sample)
82             {
83                 /* Check if we got a good precision within 1MHz */
84                 if ((CurrentSample->MHz == CurrentSample[-1].MHz) ||
85                     (CurrentSample->MHz == CurrentSample[-1].MHz + 1) ||
86                     (CurrentSample->MHz == CurrentSample[-1].MHz - 1))
87                 {
88                     /* We did, stop sampling */
89                     break;
90                 }
91             }
92 
93             /* Move on */
94             CurrentSample++;
95             Sample++;
96 
97             if (Sample == RTL_NUMBER_OF(Samples))
98             {
99                 /* No luck. Average the samples and be done */
100                 ULONG TotalMHz = 0;
101                 while (Sample--)
102                 {
103                     TotalMHz += Samples[Sample].MHz;
104                 }
105                 CurrentSample[-1].MHz = TotalMHz / RTL_NUMBER_OF(Samples);
106                 DPRINT1("Sampling CPU frequency failed. Using average of %lu MHz\n", CurrentSample[-1].MHz);
107                 break;
108             }
109         }
110 
111         /* Save the CPU Speed */
112         Prcb->MHz = CurrentSample[-1].MHz;
113     }
114 }
115 
116 VOID
117 NTAPI
118 KiInitializeHandBuiltThread(
119     IN PKTHREAD Thread,
120     IN PKPROCESS Process,
121     IN PVOID Stack)
122 {
123     PKPRCB Prcb = KeGetCurrentPrcb();
124 
125     /* Setup the Thread */
126     KeInitializeThread(Process, Thread, NULL, NULL, NULL, NULL, NULL, Stack);
127 
128     Thread->NextProcessor = Prcb->Number;
129     Thread->Priority = HIGH_PRIORITY;
130     Thread->State = Running;
131     Thread->Affinity = (ULONG_PTR)1 << Prcb->Number;
132     Thread->WaitIrql = DISPATCH_LEVEL;
133     Process->ActiveProcessors |= (ULONG_PTR)1 << Prcb->Number;
134 
135 }
136 
137 CODE_SEG("INIT")
138 DECLSPEC_NORETURN
139 VOID
140 NTAPI
141 KiSystemStartupBootStack(VOID)
142 {
143     PLOADER_PARAMETER_BLOCK LoaderBlock = KeLoaderBlock; // hack
144     PKPRCB Prcb = KeGetCurrentPrcb();
145     PKTHREAD Thread = (PKTHREAD)KeLoaderBlock->Thread;
146     PKPROCESS Process = Thread->ApcState.Process;
147     PVOID KernelStack = (PVOID)KeLoaderBlock->KernelStack;
148 
149     /* Initialize the Power Management Support for this PRCB */
150     PoInitializePrcb(Prcb);
151 
152     /* Save CPU state */
153     KiSaveProcessorControlState(&Prcb->ProcessorState);
154 
155     /* Get cache line information for this CPU */
156     KiGetCacheInformation();
157 
158     /* Initialize spinlocks and DPC data */
159     KiInitSpinLocks(Prcb, Prcb->Number);
160 
161     /* Set up the thread-related fields in the PRCB */
162     Prcb->CurrentThread = Thread;
163     Prcb->NextThread = NULL;
164     Prcb->IdleThread = Thread;
165 
166     /* Initialize PRCB pool lookaside pointers */
167     ExInitPoolLookasidePointers();
168 
169     /* Lower to APC_LEVEL */
170     KeLowerIrql(APC_LEVEL);
171 
172     /* Check if this is the boot cpu */
173     if (Prcb->Number == 0)
174     {
175         /* Initialize the kernel */
176         KiInitializeKernel(Process, Thread, KernelStack, Prcb, LoaderBlock);
177     }
178     else
179     {
180         /* Initialize the startup thread */
181         KiInitializeHandBuiltThread(Thread, Process, KernelStack);
182 
183         /* Initialize cpu with HAL */
184         if (!HalInitSystem(0, LoaderBlock))
185         {
186             /* Initialization failed */
187             KeBugCheck(HAL_INITIALIZATION_FAILED);
188         }
189     }
190 
191     /* Calculate the CPU frequency */
192     KiCalculateCpuFrequency(Prcb);
193 
194     /* Raise to Dispatch */
195     KfRaiseIrql(DISPATCH_LEVEL);
196 
197     /* Set the Idle Priority to 0. This will jump into Phase 1 */
198     KeSetPriorityThread(Thread, 0);
199 
200     /* If there's no thread scheduled, put this CPU in the Idle summary */
201     KiAcquirePrcbLock(Prcb);
202     if (!Prcb->NextThread) KiIdleSummary |= (ULONG_PTR)1 << Prcb->Number;
203     KiReleasePrcbLock(Prcb);
204 
205     /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
206     KfRaiseIrql(HIGH_LEVEL);
207     LoaderBlock->Prcb = 0;
208 
209     /* Set the priority of this thread to 0 */
210     Thread = KeGetCurrentThread();
211     Thread->Priority = 0;
212 
213     /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
214     _enable();
215     KeLowerIrql(DISPATCH_LEVEL);
216 
217     /* Set the right wait IRQL */
218     Thread->WaitIrql = DISPATCH_LEVEL;
219 
220     /* Jump into the idle loop */
221     KiIdleLoop();
222 }
223 
224 CODE_SEG("INIT")
225 VOID
226 NTAPI
227 KiInitializeKernel(IN PKPROCESS InitProcess,
228                    IN PKTHREAD InitThread,
229                    IN PVOID IdleStack,
230                    IN PKPRCB Prcb,
231                    IN PLOADER_PARAMETER_BLOCK LoaderBlock)
232 {
233     ULONG_PTR PageDirectory[2];
234     PVOID DpcStack;
235     ULONG i;
236 
237     /* Set Node Data */
238     KeNodeBlock[0] = &KiNode0;
239     Prcb->ParentNode = KeNodeBlock[0];
240     KeNodeBlock[0]->ProcessorMask = Prcb->SetMember;
241 
242     /* Set boot-level flags */
243     KeFeatureBits = Prcb->FeatureBits;
244 
245     /* Initialize 8/16 bit SList support */
246     RtlpUse16ByteSLists = (KeFeatureBits & KF_CMPXCHG16B) ? TRUE : FALSE;
247 
248     /* Set the current MP Master KPRCB to the Boot PRCB */
249     Prcb->MultiThreadSetMaster = Prcb;
250 
251     /* Initialize Bugcheck Callback data */
252     InitializeListHead(&KeBugcheckCallbackListHead);
253     InitializeListHead(&KeBugcheckReasonCallbackListHead);
254     KeInitializeSpinLock(&BugCheckCallbackLock);
255 
256     /* Initialize the Timer Expiration DPC */
257     KeInitializeDpc(&KiTimerExpireDpc, KiTimerExpiration, NULL);
258     KeSetTargetProcessorDpc(&KiTimerExpireDpc, 0);
259 
260     /* Initialize Profiling data */
261     KeInitializeSpinLock(&KiProfileLock);
262     InitializeListHead(&KiProfileListHead);
263     InitializeListHead(&KiProfileSourceListHead);
264 
265     /* Loop the timer table */
266     for (i = 0; i < TIMER_TABLE_SIZE; i++)
267     {
268         /* Initialize the list and entries */
269         InitializeListHead(&KiTimerTableListHead[i].Entry);
270         KiTimerTableListHead[i].Time.HighPart = 0xFFFFFFFF;
271         KiTimerTableListHead[i].Time.LowPart = 0;
272     }
273 
274     /* Initialize the Swap event and all swap lists */
275     KeInitializeEvent(&KiSwapEvent, SynchronizationEvent, FALSE);
276     InitializeListHead(&KiProcessInSwapListHead);
277     InitializeListHead(&KiProcessOutSwapListHead);
278     InitializeListHead(&KiStackInSwapListHead);
279 
280     /* Initialize the mutex for generic DPC calls */
281     ExInitializeFastMutex(&KiGenericCallDpcMutex);
282 
283     /* Initialize the syscall table */
284     KeServiceDescriptorTable[0].Base = MainSSDT;
285     KeServiceDescriptorTable[0].Count = NULL;
286     KeServiceDescriptorTable[0].Limit = KiServiceLimit;
287     KeServiceDescriptorTable[1].Limit = 0;
288     KeServiceDescriptorTable[0].Number = MainSSPT;
289 
290     /* Copy the the current table into the shadow table for win32k */
291     RtlCopyMemory(KeServiceDescriptorTableShadow,
292                   KeServiceDescriptorTable,
293                   sizeof(KeServiceDescriptorTable));
294 
295     /* Initialize the Idle Process and the Process Listhead */
296     InitializeListHead(&KiProcessListHead);
297     PageDirectory[0] = 0;
298     PageDirectory[1] = 0;
299     KeInitializeProcess(InitProcess,
300                         0,
301                         0xFFFFFFFF,
302                         PageDirectory,
303                         FALSE);
304     InitProcess->QuantumReset = MAXCHAR;
305 
306     /* Initialize the startup thread */
307     KiInitializeHandBuiltThread(InitThread, InitProcess, IdleStack);
308 
309     /* Initialize the Kernel Executive */
310     ExpInitializeExecutive(0, LoaderBlock);
311 
312     /* Calculate the time reciprocal */
313     KiTimeIncrementReciprocal =
314         KiComputeReciprocal(KeMaximumIncrement,
315                             &KiTimeIncrementShiftCount);
316 
317     /* Update DPC Values in case they got updated by the executive */
318     Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
319     Prcb->MinimumDpcRate = KiMinimumDpcRate;
320     Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
321 
322     /* Allocate the DPC Stack */
323     DpcStack = MmCreateKernelStack(FALSE, 0);
324     if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);
325     Prcb->DpcStack = DpcStack;
326 }
327 
328