xref: /reactos/ntoskrnl/ke/amd64/krnlinit.c (revision 7f26a396)
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->IdealProcessor = Prcb->Number;
130     Thread->Priority = HIGH_PRIORITY;
131     Thread->State = Running;
132     Thread->Affinity = (ULONG_PTR)1 << Prcb->Number;
133     Thread->WaitIrql = DISPATCH_LEVEL;
134     Process->ActiveProcessors |= (ULONG_PTR)1 << Prcb->Number;
135 
136 }
137 
138 CODE_SEG("INIT")
139 DECLSPEC_NORETURN
140 VOID
141 NTAPI
142 KiSystemStartupBootStack(VOID)
143 {
144     PLOADER_PARAMETER_BLOCK LoaderBlock = KeLoaderBlock; // hack
145     PKPRCB Prcb = KeGetCurrentPrcb();
146     PKTHREAD Thread = (PKTHREAD)KeLoaderBlock->Thread;
147     PKPROCESS Process = Thread->ApcState.Process;
148     PVOID KernelStack = (PVOID)KeLoaderBlock->KernelStack;
149 
150     /* Set Node Data */
151     Prcb->ParentNode = KeNodeBlock[0];
152     Prcb->ParentNode->ProcessorMask |= Prcb->SetMember;
153 
154     /* Initialize the Power Management Support for this PRCB */
155     PoInitializePrcb(Prcb);
156 
157     /* Save CPU state */
158     KiSaveProcessorControlState(&Prcb->ProcessorState);
159 
160     /* Get cache line information for this CPU */
161     KiGetCacheInformation();
162 
163     /* Initialize spinlocks and DPC data */
164     KiInitSpinLocks(Prcb, Prcb->Number);
165 
166     /* Set up the thread-related fields in the PRCB */
167     Prcb->CurrentThread = Thread;
168     Prcb->NextThread = NULL;
169     Prcb->IdleThread = Thread;
170 
171     /* Initialize PRCB pool lookaside pointers */
172     ExInitPoolLookasidePointers();
173 
174     /* Lower to APC_LEVEL */
175     KeLowerIrql(APC_LEVEL);
176 
177     /* Check if this is the boot cpu */
178     if (Prcb->Number == 0)
179     {
180         /* Initialize the kernel */
181         KiInitializeKernel(Process, Thread, KernelStack, Prcb, LoaderBlock);
182     }
183     else
184     {
185         /* Initialize the startup thread */
186         KiInitializeHandBuiltThread(Thread, Process, KernelStack);
187     }
188 
189     /* Calculate the CPU frequency */
190     KiCalculateCpuFrequency(Prcb);
191 
192     /* Raise to Dispatch */
193     KfRaiseIrql(DISPATCH_LEVEL);
194 
195     /* Set the Idle Priority to 0. This will jump into Phase 1 */
196     KeSetPriorityThread(Thread, 0);
197 
198     /* If there's no thread scheduled, put this CPU in the Idle summary */
199     KiAcquirePrcbLock(Prcb);
200     if (!Prcb->NextThread) KiIdleSummary |= (ULONG_PTR)1 << Prcb->Number;
201     KiReleasePrcbLock(Prcb);
202 
203     /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
204     KfRaiseIrql(HIGH_LEVEL);
205     LoaderBlock->Prcb = 0;
206 
207     /* Set the priority of this thread to 0 */
208     Thread = KeGetCurrentThread();
209     Thread->Priority = 0;
210 
211     /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
212     _enable();
213     KeLowerIrql(DISPATCH_LEVEL);
214 
215     /* Set the right wait IRQL */
216     Thread->WaitIrql = DISPATCH_LEVEL;
217 
218     /* Jump into the idle loop */
219     KiIdleLoop();
220 }
221 
222 CODE_SEG("INIT")
223 VOID
224 NTAPI
225 KiInitializeKernel(IN PKPROCESS InitProcess,
226                    IN PKTHREAD InitThread,
227                    IN PVOID IdleStack,
228                    IN PKPRCB Prcb,
229                    IN PLOADER_PARAMETER_BLOCK LoaderBlock)
230 {
231     ULONG_PTR PageDirectory[2];
232     PVOID DpcStack;
233     ULONG i;
234 
235     /* Set boot-level flags */
236     KeFeatureBits = Prcb->FeatureBits;
237 
238     /* Initialize 8/16 bit SList support */
239     RtlpUse16ByteSLists = (KeFeatureBits & KF_CMPXCHG16B) ? TRUE : FALSE;
240 
241     /* Set the current MP Master KPRCB to the Boot PRCB */
242     Prcb->MultiThreadSetMaster = Prcb;
243 
244     /* Initialize Bugcheck Callback data */
245     InitializeListHead(&KeBugcheckCallbackListHead);
246     InitializeListHead(&KeBugcheckReasonCallbackListHead);
247     KeInitializeSpinLock(&BugCheckCallbackLock);
248 
249     /* Initialize the Timer Expiration DPC */
250     KeInitializeDpc(&KiTimerExpireDpc, KiTimerExpiration, NULL);
251     KeSetTargetProcessorDpc(&KiTimerExpireDpc, 0);
252 
253     /* Initialize Profiling data */
254     KeInitializeSpinLock(&KiProfileLock);
255     InitializeListHead(&KiProfileListHead);
256     InitializeListHead(&KiProfileSourceListHead);
257 
258     /* Loop the timer table */
259     for (i = 0; i < TIMER_TABLE_SIZE; i++)
260     {
261         /* Initialize the list and entries */
262         InitializeListHead(&KiTimerTableListHead[i].Entry);
263         KiTimerTableListHead[i].Time.HighPart = 0xFFFFFFFF;
264         KiTimerTableListHead[i].Time.LowPart = 0;
265     }
266 
267     /* Initialize the Swap event and all swap lists */
268     KeInitializeEvent(&KiSwapEvent, SynchronizationEvent, FALSE);
269     InitializeListHead(&KiProcessInSwapListHead);
270     InitializeListHead(&KiProcessOutSwapListHead);
271     InitializeListHead(&KiStackInSwapListHead);
272 
273     /* Initialize the mutex for generic DPC calls */
274     ExInitializeFastMutex(&KiGenericCallDpcMutex);
275 
276     /* Initialize the syscall table */
277     KeServiceDescriptorTable[0].Base = MainSSDT;
278     KeServiceDescriptorTable[0].Count = NULL;
279     KeServiceDescriptorTable[0].Limit = KiServiceLimit;
280     KeServiceDescriptorTable[1].Limit = 0;
281     KeServiceDescriptorTable[0].Number = MainSSPT;
282 
283     /* Copy the the current table into the shadow table for win32k */
284     RtlCopyMemory(KeServiceDescriptorTableShadow,
285                   KeServiceDescriptorTable,
286                   sizeof(KeServiceDescriptorTable));
287 
288     /* Initialize the Idle Process and the Process Listhead */
289     InitializeListHead(&KiProcessListHead);
290     PageDirectory[0] = 0;
291     PageDirectory[1] = 0;
292     KeInitializeProcess(InitProcess,
293                         0,
294                         MAXULONG_PTR,
295                         PageDirectory,
296                         FALSE);
297     InitProcess->QuantumReset = MAXCHAR;
298 
299     /* Initialize the startup thread */
300     KiInitializeHandBuiltThread(InitThread, InitProcess, IdleStack);
301 
302     /* Initialize the Kernel Executive */
303     ExpInitializeExecutive(0, LoaderBlock);
304 
305     /* Calculate the time reciprocal */
306     KiTimeIncrementReciprocal =
307         KiComputeReciprocal(KeMaximumIncrement,
308                             &KiTimeIncrementShiftCount);
309 
310     /* Update DPC Values in case they got updated by the executive */
311     Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
312     Prcb->MinimumDpcRate = KiMinimumDpcRate;
313     Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
314 
315     /* Allocate the DPC Stack */
316     DpcStack = MmCreateKernelStack(FALSE, 0);
317     if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);
318     Prcb->DpcStack = DpcStack;
319 }
320 
321