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