- Create a KD-compatible KiDebugRoutine and piggyback KDBG on it.
[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 VOID
18 FASTCALL
19 KiIdleLoop(VOID);
20
21 /* Spinlocks used only on X86 */
22 KSPIN_LOCK KiFreezeExecutionLock;
23 KSPIN_LOCK Ki486CompatibilityLock;
24
25 /* FUNCTIONS *****************************************************************/
26
27 VOID
28 NTAPI
29 KiInitializePcr(IN ULONG ProcessorNumber,
30 IN PKIPCR Pcr,
31 IN PKIDTENTRY Idt,
32 IN PKGDTENTRY Gdt,
33 IN PKTSS Tss,
34 IN PKTHREAD IdleThread,
35 IN PVOID DpcStack)
36 {
37 /* Setup the TIB */
38 Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
39 Pcr->NtTib.StackBase = 0;
40 Pcr->NtTib.StackLimit = 0;
41 Pcr->NtTib.Self = 0;
42
43 /* Set the Current Thread */
44 Pcr->PrcbData.CurrentThread = IdleThread;
45
46 /* Set pointers to ourselves */
47 Pcr->Self = (PKPCR)Pcr;
48 Pcr->Prcb = &Pcr->PrcbData;
49
50 /* Set the PCR Version */
51 Pcr->MajorVersion = PCR_MAJOR_VERSION;
52 Pcr->MinorVersion = PCR_MINOR_VERSION;
53
54 /* Set the PCRB Version */
55 Pcr->PrcbData.MajorVersion = 1;
56 Pcr->PrcbData.MinorVersion = 1;
57
58 /* Set the Build Type */
59 Pcr->PrcbData.BuildType = 0;
60
61 /* Set the Processor Number and current Processor Mask */
62 Pcr->PrcbData.Number = (UCHAR)ProcessorNumber;
63 Pcr->PrcbData.SetMember = 1 << ProcessorNumber;
64
65 /* Set the PRCB for this Processor */
66 KiProcessorBlock[ProcessorNumber] = Pcr->Prcb;
67
68 /* Start us out at PASSIVE_LEVEL */
69 Pcr->Irql = PASSIVE_LEVEL;
70
71 /* Set the GDI, IDT, TSS and DPC Stack */
72 Pcr->GDT = (PVOID)Gdt;
73 Pcr->IDT = Idt;
74 Pcr->TSS = Tss;
75 Pcr->PrcbData.DpcStack = DpcStack;
76 }
77
78 VOID
79 NTAPI
80 KiInitializeKernel(IN PKPROCESS InitProcess,
81 IN PKTHREAD InitThread,
82 IN PVOID IdleStack,
83 IN PKPRCB Prcb,
84 IN CCHAR Number,
85 IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock)
86 {
87 BOOLEAN NpxPresent;
88 ULONG FeatureBits;
89 LARGE_INTEGER PageDirectory;
90 PVOID DpcStack;
91
92 /* Detect and set the CPU Type */
93 KiSetProcessorType();
94
95 /* Set CR0 features based on detected CPU */
96 KiSetCR0Bits();
97
98 /* Check if an FPU is present */
99 NpxPresent = KiIsNpxPresent();
100
101 /* Initialize the Power Management Support for this PRCB */
102 PoInitializePrcb(Prcb);
103
104 /* Bugcheck if this is a 386 CPU */
105 if (Prcb->CpuType == 3) KeBugCheckEx(0x5D, 0x386, 0, 0, 0);
106
107 /* Get the processor features for the CPU */
108 FeatureBits = KiGetFeatureBits();
109
110 /* Save feature bits */
111 Prcb->FeatureBits = FeatureBits;
112
113 /* Get cache line information for this CPU */
114 KiGetCacheInformation();
115
116 /* Initialize spinlocks and DPC data */
117 KiInitSpinLocks(Prcb, Number);
118
119 /* Check if this is the Boot CPU */
120 if (!Number)
121 {
122 /* Set Node Data */
123 KeNodeBlock[0] = &KiNode0;
124 Prcb->ParentNode = KeNodeBlock[0];
125 KeNodeBlock[0]->ProcessorMask = Prcb->SetMember;
126
127 /* Set boot-level flags */
128 KeI386NpxPresent = NpxPresent;
129 KeI386CpuType = Prcb->CpuType;
130 KeI386CpuStep = Prcb->CpuStep;
131 KeProcessorArchitecture = 0;
132 KeProcessorLevel = (USHORT)Prcb->CpuType;
133 if (Prcb->CpuID) KeProcessorRevision = Prcb->CpuStep;
134 KeFeatureBits = FeatureBits;
135 KeI386FxsrPresent = (KeFeatureBits & KF_FXSR) ? TRUE : FALSE;
136 KeI386XMMIPresent = (KeFeatureBits & KF_XMMI) ? TRUE : FALSE;
137
138 /* Set the current MP Master KPRCB to the Boot PRCB */
139 Prcb->MultiThreadSetMaster = Prcb;
140
141 /* Lower to APC_LEVEL */
142 KfLowerIrql(APC_LEVEL);
143
144 /* Initialize some spinlocks */
145 KeInitializeSpinLock(&KiFreezeExecutionLock);
146 KeInitializeSpinLock(&Ki486CompatibilityLock);
147
148 /* Initialize portable parts of the OS */
149 KiInitSystem();
150
151 /* Initialize the Idle Process and the Process Listhead */
152 InitializeListHead(&KiProcessListHead);
153 PageDirectory.QuadPart = 0;
154 KeInitializeProcess(InitProcess,
155 0,
156 0xFFFFFFFF,
157 &PageDirectory,
158 FALSE);
159 InitProcess->QuantumReset = MAXCHAR;
160 }
161 else
162 {
163 /* FIXME */
164 DPRINT1("SMP Boot support not yet present\n");
165 }
166
167 /* Setup the Idle Thread */
168 KeInitializeThread(InitProcess,
169 InitThread,
170 NULL,
171 NULL,
172 NULL,
173 NULL,
174 NULL,
175 IdleStack);
176 InitThread->NextProcessor = Number;
177 InitThread->Priority = HIGH_PRIORITY;
178 InitThread->State = Running;
179 InitThread->Affinity = 1 << Number;
180 InitThread->WaitIrql = DISPATCH_LEVEL;
181 InitProcess->ActiveProcessors = 1 << Number;
182
183 /* HACK for MmUpdatePageDir */
184 ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess;
185
186 /* Set up the thread-related fields in the PRCB */
187 Prcb->CurrentThread = InitThread;
188 Prcb->NextThread = NULL;
189 Prcb->IdleThread = InitThread;
190
191 /* Initialize the Kernel Executive */
192 ExpInitializeExecutive();
193
194 /* Only do this on the boot CPU */
195 if (!Number)
196 {
197 /* Calculate the time reciprocal */
198 KiTimeIncrementReciprocal =
199 KiComputeReciprocal(KeMaximumIncrement,
200 &KiTimeIncrementShiftCount);
201
202 /* Update DPC Values in case they got updated by the executive */
203 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
204 Prcb->MinimumDpcRate = KiMinimumDpcRate;
205 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
206
207 /* Allocate the DPC Stack */
208 DpcStack = MmCreateKernelStack(FALSE);
209 if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);
210 Prcb->DpcStack = DpcStack;
211
212 /* Allocate the IOPM save area. */
213 Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
214 PAGE_SIZE * 2,
215 TAG('K', 'e', ' ', ' '));
216 if (!Ki386IopmSaveArea)
217 {
218 /* Bugcheck. We need this for V86/VDM support. */
219 KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
220 }
221 }
222
223 /* Raise to Dispatch */
224 KfRaiseIrql(DISPATCH_LEVEL);
225
226 /* Set the Idle Priority to 0. This will jump into Phase 1 */
227 KeSetPriorityThread(InitThread, 0);
228 }
229
230 VOID
231 NTAPI
232 KiSystemStartup(IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock)
233 {
234 ULONG Cpu;
235 PKIPCR Pcr = (PKIPCR)KPCR_BASE;
236 PKPRCB Prcb;
237
238 /* Save the loader block and get the current CPU */
239 //KeLoaderBlock = LoaderBlock;
240 Cpu = KeNumberProcessors;
241 if (!Cpu)
242 {
243 /* If this is the boot CPU, set FS and the CPU Number*/
244 Ke386SetFs(KGDT_R0_PCR);
245 KeGetPcr()->Number = Cpu;
246 }
247
248 /* Skip initial setup if this isn't the Boot CPU */
249 if (Cpu) goto AppCpuInit;
250
251 /* Setup the boot (Freeldr should've done), double fault and NMI TSS */
252 Ki386InitializeTss();
253
254 /* Initialize the PCR */
255 RtlZeroMemory(Pcr, PAGE_SIZE);
256 KiInitializePcr(Cpu,
257 Pcr,
258 KiIdt,
259 KiBootGdt,
260 &KiBootTss,
261 &KiInitialThread.Tcb,
262 KiDoubleFaultStack);
263
264 /* Set us as the current process */
265 KiInitialThread.Tcb.ApcState.Process = &KiInitialProcess.Pcb;
266
267 /* Clear DR6/7 to cleanup bootloader debugging */
268 Pcr->PrcbData.ProcessorState.SpecialRegisters.KernelDr6 = 0;
269 Pcr->PrcbData.ProcessorState.SpecialRegisters.KernelDr7 = 0;
270
271 /* Load Ring 3 selectors for DS/ES */
272 Ke386SetDs(KGDT_R3_DATA | RPL_MASK);
273 Ke386SetEs(KGDT_R3_DATA | RPL_MASK);
274
275 /* Setup CPU-related fields */
276 AppCpuInit:
277 Prcb = Pcr->Prcb;
278 Pcr->Number = Cpu;
279 Pcr->SetMember = 1 << Cpu;
280 Pcr->SetMemberCopy = 1 << Cpu;
281 Prcb->SetMember = 1 << Cpu;
282
283 /* Initialize the Processor with HAL */
284 HalInitializeProcessor(Cpu, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
285
286 /* Set active processors */
287 KeActiveProcessors |= Pcr->SetMember;
288 KeNumberProcessors++;
289
290 /* Initialize the Debugger for the Boot CPU */
291 if (!Cpu) KdInitSystem (0, &KeLoaderBlock);
292
293 /* Check for break-in */
294 if (KdPollBreakIn()) DbgBreakPointWithStatus(1);
295
296 /* Raise to HIGH_LEVEL */
297 KfRaiseIrql(HIGH_LEVEL);
298
299 /* Call main kernel intialization */
300 KiInitializeKernel(&KiInitialProcess.Pcb,
301 &KiInitialThread.Tcb,
302 P0BootStack,
303 Prcb,
304 Cpu,
305 LoaderBlock);
306
307 /* Lower IRQL back to DISPATCH_LEVEL */
308 KfLowerIrql(DISPATCH_LEVEL);
309
310 /* Set the priority of this thread to 0 */
311 KeGetCurrentThread()->Priority = 0;
312
313 /* Jump into the idle loop */
314 KiIdleLoop();
315 }
316