Copy i8042prt driver from 0.3.1 branch to trunk. Try #2
[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 KiInitializePcr(IN ULONG ProcessorNumber,
26 IN PKIPCR Pcr,
27 IN PKIDTENTRY Idt,
28 IN PKGDTENTRY Gdt,
29 IN PKTSS Tss,
30 IN PKTHREAD IdleThread,
31 IN PVOID DpcStack)
32 {
33 /* Setup the TIB */
34 Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
35 Pcr->NtTib.StackBase = 0;
36 Pcr->NtTib.StackLimit = 0;
37 Pcr->NtTib.Self = 0;
38
39 /* Set the Current Thread */
40 Pcr->PrcbData.CurrentThread = IdleThread;
41
42 /* Set pointers to ourselves */
43 Pcr->Self = (PKPCR)Pcr;
44 Pcr->Prcb = &Pcr->PrcbData;
45
46 /* Set the PCR Version */
47 Pcr->MajorVersion = PCR_MAJOR_VERSION;
48 Pcr->MinorVersion = PCR_MINOR_VERSION;
49
50 /* Set the PCRB Version */
51 Pcr->PrcbData.MajorVersion = 1;
52 Pcr->PrcbData.MinorVersion = 1;
53
54 /* Set the Build Type */
55 Pcr->PrcbData.BuildType = 0;
56
57 /* Set the Processor Number and current Processor Mask */
58 Pcr->PrcbData.Number = (UCHAR)ProcessorNumber;
59 Pcr->PrcbData.SetMember = 1 << ProcessorNumber;
60
61 /* Set the PRCB for this Processor */
62 KiProcessorBlock[ProcessorNumber] = Pcr->Prcb;
63
64 /* Start us out at PASSIVE_LEVEL */
65 Pcr->Irql = PASSIVE_LEVEL;
66
67 /* Set the GDI, IDT, TSS and DPC Stack */
68 Pcr->GDT = (PVOID)Gdt;
69 Pcr->IDT = Idt;
70 Pcr->TSS = Tss;
71 Pcr->PrcbData.DpcStack = DpcStack;
72 }
73
74 VOID
75 NTAPI
76 KiInitializeKernel(IN PKPROCESS InitProcess,
77 IN PKTHREAD InitThread,
78 IN PVOID IdleStack,
79 IN PKPRCB Prcb,
80 IN CCHAR Number,
81 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
82 {
83 BOOLEAN NpxPresent;
84 ULONG FeatureBits;
85 LARGE_INTEGER PageDirectory;
86 PVOID DpcStack;
87
88 /* Detect and set the CPU Type */
89 KiSetProcessorType();
90
91 /* Set CR0 features based on detected CPU */
92 KiSetCR0Bits();
93
94 /* Check if an FPU is present */
95 NpxPresent = KiIsNpxPresent();
96
97 /* Initialize the Power Management Support for this PRCB */
98 PoInitializePrcb(Prcb);
99
100 /* Bugcheck if this is a 386 CPU */
101 if (Prcb->CpuType == 3) KeBugCheckEx(0x5D, 0x386, 0, 0, 0);
102
103 /* Get the processor features for the CPU */
104 FeatureBits = KiGetFeatureBits();
105
106 /* Save feature bits */
107 Prcb->FeatureBits = FeatureBits;
108
109 /* Save CPU state */
110 KiSaveProcessorControlState(&Prcb->ProcessorState);
111
112 /* Get cache line information for this CPU */
113 KiGetCacheInformation();
114
115 /* Initialize spinlocks and DPC data */
116 KiInitSpinLocks(Prcb, Number);
117
118 /* Check if this is the Boot CPU */
119 if (!Number)
120 {
121 /* Set Node Data */
122 KeNodeBlock[0] = &KiNode0;
123 Prcb->ParentNode = KeNodeBlock[0];
124 KeNodeBlock[0]->ProcessorMask = Prcb->SetMember;
125
126 /* Set boot-level flags */
127 KeI386NpxPresent = NpxPresent;
128 KeI386CpuType = Prcb->CpuType;
129 KeI386CpuStep = Prcb->CpuStep;
130 KeProcessorArchitecture = 0;
131 KeProcessorLevel = (USHORT)Prcb->CpuType;
132 if (Prcb->CpuID) KeProcessorRevision = Prcb->CpuStep;
133 KeFeatureBits = FeatureBits;
134 KeI386FxsrPresent = (KeFeatureBits & KF_FXSR) ? TRUE : FALSE;
135 KeI386XMMIPresent = (KeFeatureBits & KF_XMMI) ? TRUE : FALSE;
136
137 /* Set the current MP Master KPRCB to the Boot PRCB */
138 Prcb->MultiThreadSetMaster = Prcb;
139
140 /* Lower to APC_LEVEL */
141 KfLowerIrql(APC_LEVEL);
142
143 /* Initialize some spinlocks */
144 KeInitializeSpinLock(&KiFreezeExecutionLock);
145 KeInitializeSpinLock(&Ki486CompatibilityLock);
146
147 /* Initialize portable parts of the OS */
148 KiInitSystem();
149
150 /* Initialize the Idle Process and the Process Listhead */
151 InitializeListHead(&KiProcessListHead);
152 PageDirectory.QuadPart = 0;
153 KeInitializeProcess(InitProcess,
154 0,
155 0xFFFFFFFF,
156 &PageDirectory,
157 FALSE);
158 InitProcess->QuantumReset = MAXCHAR;
159 }
160 else
161 {
162 /* FIXME */
163 DPRINT1("SMP Boot support not yet present\n");
164 }
165
166 /* Initialize Kernel Memory Address Space */
167 MmInit1(FirstKrnlPhysAddr,
168 LastKrnlPhysAddr,
169 LastKernelAddress,
170 (PADDRESS_RANGE)&KeMemoryMap,
171 KeMemoryMapRangeCount,
172 4096);
173
174 /* Sets up the Text Sections of the Kernel and HAL for debugging */
175 LdrInit1();
176
177 /* Setup the Idle Thread */
178 KeInitializeThread(InitProcess,
179 InitThread,
180 NULL,
181 NULL,
182 NULL,
183 NULL,
184 NULL,
185 IdleStack);
186 InitThread->NextProcessor = Number;
187 InitThread->Priority = HIGH_PRIORITY;
188 InitThread->State = Running;
189 InitThread->Affinity = 1 << Number;
190 InitThread->WaitIrql = DISPATCH_LEVEL;
191 InitProcess->ActiveProcessors = 1 << Number;
192
193 /* HACK for MmUpdatePageDir */
194 ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess;
195
196 /* Set up the thread-related fields in the PRCB */
197 Prcb->CurrentThread = InitThread;
198 Prcb->NextThread = NULL;
199 Prcb->IdleThread = InitThread;
200
201 /* Initialize the Kernel Executive */
202 ExpInitializeExecutive(Number, LoaderBlock);
203
204 /* Only do this on the boot CPU */
205 if (!Number)
206 {
207 /* Calculate the time reciprocal */
208 KiTimeIncrementReciprocal =
209 KiComputeReciprocal(KeMaximumIncrement,
210 &KiTimeIncrementShiftCount);
211
212 /* Update DPC Values in case they got updated by the executive */
213 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
214 Prcb->MinimumDpcRate = KiMinimumDpcRate;
215 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
216
217 /* Allocate the DPC Stack */
218 DpcStack = MmCreateKernelStack(FALSE);
219 if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);
220 Prcb->DpcStack = DpcStack;
221
222 /* Allocate the IOPM save area. */
223 Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
224 PAGE_SIZE * 2,
225 TAG('K', 'e', ' ', ' '));
226 if (!Ki386IopmSaveArea)
227 {
228 /* Bugcheck. We need this for V86/VDM support. */
229 KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
230 }
231 }
232
233 /* Raise to Dispatch */
234 KfRaiseIrql(DISPATCH_LEVEL);
235
236 /* Set the Idle Priority to 0. This will jump into Phase 1 */
237 KeSetPriorityThread(InitThread, 0);
238
239 /* If there's no thread scheduled, put this CPU in the Idle summary */
240 if (!Prcb->NextThread) KiIdleSummary |= 1 << Number;
241
242 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
243 KfRaiseIrql(HIGH_LEVEL);
244 LoaderBlock->Prcb = 0;
245 }
246
247 VOID
248 FASTCALL
249 KiGetMachineBootPointers(IN PKGDTENTRY *Gdt,
250 IN PKIDTENTRY *Idt,
251 IN PKIPCR *Pcr,
252 IN PKTSS *Tss)
253 {
254 KDESCRIPTOR GdtDescriptor, IdtDescriptor;
255 KGDTENTRY TssSelector, PcrSelector;
256 ULONG Tr, Fs;
257
258 /* Get GDT and IDT descriptors */
259 Ke386GetGlobalDescriptorTable(GdtDescriptor);
260 Ke386GetInterruptDescriptorTable(IdtDescriptor);
261
262 /* Save IDT and GDT */
263 *Gdt = (PKGDTENTRY)GdtDescriptor.Base;
264 *Idt = (PKIDTENTRY)IdtDescriptor.Base;
265
266 /* Get TSS and FS Selectors */
267 Ke386GetTr(&Tr);
268 if (Tr != KGDT_TSS) Tr = KGDT_TSS; // FIXME: HACKHACK
269 Fs = Ke386GetFs();
270
271 /* Get PCR Selector, mask it and get its GDT Entry */
272 PcrSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Fs & ~RPL_MASK));
273
274 /* Get the KPCR itself */
275 *Pcr = (PKIPCR)(ULONG_PTR)(PcrSelector.BaseLow |
276 PcrSelector.HighWord.Bytes.BaseMid << 16 |
277 PcrSelector.HighWord.Bytes.BaseHi << 24);
278
279 /* Get TSS Selector, mask it and get its GDT Entry */
280 TssSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Tr & ~RPL_MASK));
281
282 /* Get the KTSS itself */
283 *Tss = (PKTSS)(ULONG_PTR)(TssSelector.BaseLow |
284 TssSelector.HighWord.Bytes.BaseMid << 16 |
285 TssSelector.HighWord.Bytes.BaseHi << 24);
286 }
287
288 VOID
289 NTAPI
290 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
291 {
292 ULONG Cpu;
293 PKTHREAD InitialThread;
294 ULONG InitialStack;
295 PKGDTENTRY Gdt;
296 PKIDTENTRY Idt;
297 PKTSS Tss;
298 PKIPCR Pcr;
299
300 /* Save the loader block and get the current CPU */
301 KeLoaderBlock = LoaderBlock;
302 Cpu = KeNumberProcessors;
303 if (!Cpu)
304 {
305 /* If this is the boot CPU, set FS and the CPU Number*/
306 Ke386SetFs(KGDT_R0_PCR);
307 __writefsdword(KPCR_PROCESSOR_NUMBER, Cpu);
308
309 /* Set the initial stack and idle thread as well */
310 LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack;
311 LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread;
312 }
313
314 /* Save the initial thread and stack */
315 InitialStack = LoaderBlock->KernelStack;
316 InitialThread = (PKTHREAD)LoaderBlock->Thread;
317
318 /* Clean the APC List Head */
319 InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]);
320
321 /* Initialize the machine type */
322 KiInitializeMachineType();
323
324 /* Skip initial setup if this isn't the Boot CPU */
325 if (Cpu) goto AppCpuInit;
326
327 /* Get GDT, IDT, PCR and TSS pointers */
328 KiGetMachineBootPointers(&Gdt, &Idt, &Pcr, &Tss);
329
330 /* Setup the TSS descriptors and entries */
331 Ki386InitializeTss(Tss, Idt, Gdt);
332
333 /* Initialize the PCR */
334 RtlZeroMemory(Pcr, PAGE_SIZE);
335 KiInitializePcr(Cpu,
336 Pcr,
337 Idt,
338 Gdt,
339 Tss,
340 InitialThread,
341 KiDoubleFaultStack);
342
343 /* Set us as the current process */
344 InitialThread->ApcState.Process = &KiInitialProcess.Pcb;
345
346 /* Clear DR6/7 to cleanup bootloader debugging */
347 __writefsdword(KPCR_TEB, 0);
348 __writefsdword(KPCR_DR6, 0);
349 __writefsdword(KPCR_DR7, 0);
350
351 /* Load Ring 3 selectors for DS/ES */
352 Ke386SetDs(KGDT_R3_DATA | RPL_MASK);
353 Ke386SetEs(KGDT_R3_DATA | RPL_MASK);
354
355 AppCpuInit:
356 /* Loop until we can release the freeze lock */
357 do
358 {
359 /* Loop until execution can continue */
360 while ((volatile KSPIN_LOCK)KiFreezeExecutionLock == 1);
361 } while(InterlockedBitTestAndSet((PLONG)&KiFreezeExecutionLock, 0));
362
363 /* Setup CPU-related fields */
364 __writefsdword(KPCR_NUMBER, Cpu);
365 __writefsdword(KPCR_SET_MEMBER, 1 << Cpu);
366 __writefsdword(KPCR_SET_MEMBER_COPY, 1 << Cpu);
367 __writefsdword(KPCR_PRCB_SET_MEMBER, 1 << Cpu);
368
369 /* Initialize the Processor with HAL */
370 HalInitializeProcessor(Cpu, KeLoaderBlock);
371
372 /* Set active processors */
373 KeActiveProcessors |= __readfsdword(KPCR_SET_MEMBER);
374 KeNumberProcessors++;
375
376 /* Check if this is the boot CPU */
377 if (!Cpu)
378 {
379 /* Initialize debugging system */
380 KdInitSystem(0, KeLoaderBlock);
381
382 /* Check for break-in */
383 if (KdPollBreakIn()) DbgBreakPointWithStatus(1);
384 }
385
386 /* Raise to HIGH_LEVEL */
387 KfRaiseIrql(HIGH_LEVEL);
388
389 /* Align stack and make space for the trap frame and NPX frame */
390 InitialStack &= ~KTRAP_FRAME_ALIGN;
391 __asm__ __volatile__("movl %0,%%esp" : :"r" (InitialStack));
392 __asm__ __volatile__("subl %0,%%esp" : :"r" (NPX_FRAME_LENGTH +
393 KTRAP_FRAME_LENGTH +
394 KTRAP_FRAME_ALIGN));
395 __asm__ __volatile__("push %0" : :"r" (CR0_EM + CR0_TS + CR0_MP));
396
397 /* Call main kernel initialization */
398 KiInitializeKernel(&KiInitialProcess.Pcb,
399 InitialThread,
400 (PVOID)InitialStack,
401 (PKPRCB)__readfsdword(KPCR_PRCB),
402 Cpu,
403 KeLoaderBlock);
404
405 /* Set the priority of this thread to 0 */
406 KeGetCurrentThread()->Priority = 0;
407
408 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
409 _enable();
410 KfLowerIrql(DISPATCH_LEVEL);
411
412 /* Set the right wait IRQL */
413 KeGetCurrentThread()->WaitIrql = DISPATCH_LEVEL;
414
415 /* Set idle thread as running on UP builds */
416 #ifndef CONFIG_SMP
417 KeGetCurrentThread()->State = Running;
418 #endif
419
420 /* Jump into the idle loop */
421 KiIdleLoop();
422 }
423