/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ke/i386/kiinit.c * PURPOSE: Kernel Initialization for x86 CPUs * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */ /* INCLUDES *****************************************************************/ #include #define NDEBUG #include #include "internal/i386/trap_x.h" /* GLOBALS *******************************************************************/ /* Boot and double-fault/NMI/DPC stack */ UCHAR DECLSPEC_ALIGN(PAGE_SIZE) P0BootStackData[KERNEL_STACK_SIZE] = {0}; UCHAR DECLSPEC_ALIGN(PAGE_SIZE) KiDoubleFaultStackData[KERNEL_STACK_SIZE] = {0}; ULONG_PTR P0BootStack = (ULONG_PTR)&P0BootStackData[KERNEL_STACK_SIZE]; ULONG_PTR KiDoubleFaultStack = (ULONG_PTR)&KiDoubleFaultStackData[KERNEL_STACK_SIZE]; /* Spinlocks used only on X86 */ KSPIN_LOCK KiFreezeExecutionLock; KSPIN_LOCK Ki486CompatibilityLock; /* Perf */ ULONG ProcessCount; ULONGLONG BootCycles, BootCyclesEnd; /* FUNCTIONS *****************************************************************/ INIT_FUNCTION VOID NTAPI KiInitMachineDependent(VOID) { ULONG CpuCount; BOOLEAN FbCaching = FALSE; NTSTATUS Status; ULONG ReturnLength; ULONG i, Affinity, Sample = 0; PFX_SAVE_AREA FxSaveArea; ULONG MXCsrMask = 0xFFBF; CPU_INFO CpuInfo; KI_SAMPLE_MAP Samples[10]; PKI_SAMPLE_MAP CurrentSample = Samples; LARGE_IDENTITY_MAP IdentityMap; /* Check for large page support */ if (KeFeatureBits & KF_LARGE_PAGE) { /* Do an IPI to enable it on all CPUs */ if (Ki386CreateIdentityMap(&IdentityMap, Ki386EnableCurrentLargePage, 2)) KeIpiGenericCall(Ki386EnableTargetLargePage, (ULONG_PTR)&IdentityMap); /* Free the pages allocated for identity map */ Ki386FreeIdentityMap(&IdentityMap); } /* Check for global page support */ if (KeFeatureBits & KF_GLOBAL_PAGE) { /* Do an IPI to enable it on all CPUs */ CpuCount = KeNumberProcessors; KeIpiGenericCall(Ki386EnableGlobalPage, (ULONG_PTR)&CpuCount); } /* Check for PAT and/or MTRR support */ if (KeFeatureBits & (KF_PAT | KF_MTRR)) { /* Query the HAL to make sure we can use it */ Status = HalQuerySystemInformation(HalFrameBufferCachingInformation, sizeof(BOOLEAN), &FbCaching, &ReturnLength); if ((NT_SUCCESS(Status)) && (FbCaching)) { /* We can't, disable it */ KeFeatureBits &= ~(KF_PAT | KF_MTRR); } } /* Check for PAT support and enable it */ if (KeFeatureBits & KF_PAT) KiInitializePAT(); /* Assume no errata for now */ SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = 0; /* Check if we have an NPX */ if (KeI386NpxPresent) { /* Loop every CPU */ i = KeActiveProcessors; for (Affinity = 1; i; Affinity <<= 1) { /* Check if this is part of the set */ if (i & Affinity) { /* Run on this CPU */ i &= ~Affinity; KeSetSystemAffinityThread(Affinity); /* Detect FPU errata */ if (KiIsNpxErrataPresent()) { /* Disable NPX support */ KeI386NpxPresent = FALSE; SharedUserData-> ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE; break; } } } } /* If there's no NPX, then we're emulating the FPU */ SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] = !KeI386NpxPresent; /* Check if there's no NPX, so that we can disable associated features */ if (!KeI386NpxPresent) { /* Remove NPX-related bits */ KeFeatureBits &= ~(KF_XMMI64 | KF_XMMI | KF_FXSR | KF_MMX); /* Disable kernel flags */ KeI386FxsrPresent = KeI386XMMIPresent = FALSE; /* Disable processor features that might've been set until now */ SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] = SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] = SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] = SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = 0; } /* Check for CR4 support */ if (KeFeatureBits & KF_CR4) { /* Do an IPI call to enable the Debug Exceptions */ CpuCount = KeNumberProcessors; KeIpiGenericCall(Ki386EnableDE, (ULONG_PTR)&CpuCount); } /* Check if FXSR was found */ if (KeFeatureBits & KF_FXSR) { /* Do an IPI call to enable the FXSR */ CpuCount = KeNumberProcessors; KeIpiGenericCall(Ki386EnableFxsr, (ULONG_PTR)&CpuCount); /* Check if XMM was found too */ if (KeFeatureBits & KF_XMMI) { /* Do an IPI call to enable XMMI exceptions */ CpuCount = KeNumberProcessors; KeIpiGenericCall(Ki386EnableXMMIExceptions, (ULONG_PTR)&CpuCount); /* FIXME: Implement and enable XMM Page Zeroing for Mm */ /* Patch the RtlPrefetchMemoryNonTemporal routine to enable it */ *(PCHAR)RtlPrefetchMemoryNonTemporal = 0x90; // NOP } } /* Check for, and enable SYSENTER support */ KiRestoreFastSyscallReturnState(); /* Loop every CPU */ i = KeActiveProcessors; for (Affinity = 1; i; Affinity <<= 1) { /* Check if this is part of the set */ if (i & Affinity) { /* Run on this CPU */ i &= ~Affinity; KeSetSystemAffinityThread(Affinity); /* Reset MHz to 0 for this CPU */ KeGetCurrentPrcb()->MHz = 0; /* Check if we can use RDTSC */ if (KeFeatureBits & KF_RDTSC) { /* Start sampling loop */ for (;;) { /* Do a dummy CPUID to start the sample */ KiCpuId(&CpuInfo, 0); /* Fill out the starting data */ CurrentSample->PerfStart = KeQueryPerformanceCounter(NULL); CurrentSample->TSCStart = __rdtsc(); CurrentSample->PerfFreq.QuadPart = -50000; /* Sleep for this sample */ KeDelayExecutionThread(KernelMode, FALSE, &CurrentSample->PerfFreq); /* Do another dummy CPUID */ KiCpuId(&CpuInfo, 0); /* Fill out the ending data */ CurrentSample->PerfEnd = KeQueryPerformanceCounter(&CurrentSample->PerfFreq); CurrentSample->TSCEnd = __rdtsc(); /* Calculate the differences */ CurrentSample->PerfDelta = CurrentSample->PerfEnd.QuadPart - CurrentSample->PerfStart.QuadPart; CurrentSample->TSCDelta = CurrentSample->TSCEnd - CurrentSample->TSCStart; /* Compute CPU Speed */ CurrentSample->MHz = (ULONG)((CurrentSample->TSCDelta * CurrentSample-> PerfFreq.QuadPart + 500000) / (CurrentSample->PerfDelta * 1000000)); /* Check if this isn't the first sample */ if (Sample) { /* Check if we got a good precision within 1MHz */ if ((CurrentSample->MHz == CurrentSample[-1].MHz) || (CurrentSample->MHz == CurrentSample[-1].MHz + 1) || (CurrentSample->MHz == CurrentSample[-1].MHz - 1)) { /* We did, stop sampling */ break; } } /* Move on */ CurrentSample++; Sample++; if (Sample == RTL_NUMBER_OF(Samples)) { /* No luck. Average the samples and be done */ ULONG TotalMHz = 0; while (Sample--) { TotalMHz += Samples[Sample].MHz; } CurrentSample[-1].MHz = TotalMHz / RTL_NUMBER_OF(Samples); DPRINT1("Sampling CPU frequency failed. Using average of %lu MHz\n", CurrentSample[-1].MHz); break; } } /* Save the CPU Speed */ KeGetCurrentPrcb()->MHz = CurrentSample[-1].MHz; } /* Check if we have MTRR */ if (KeFeatureBits & KF_MTRR) { /* Then manually initialize MTRR for the CPU */ KiInitializeMTRR(i ? FALSE : TRUE); } /* Check if we have AMD MTRR and initialize it for the CPU */ if (KeFeatureBits & KF_AMDK6MTRR) KiAmdK6InitializeMTRR(); /* Check if this is a buggy Pentium and apply the fixup if so */ if (KiI386PentiumLockErrataPresent) KiI386PentiumLockErrataFixup(); /* Check if the CPU supports FXSR */ if (KeFeatureBits & KF_FXSR) { /* Get the current thread NPX state */ FxSaveArea = KiGetThreadNpxArea(KeGetCurrentThread()); /* Clear initial MXCsr mask */ FxSaveArea->U.FxArea.MXCsrMask = 0; /* Save the current NPX State */ Ke386SaveFpuState(FxSaveArea); /* Check if the current mask doesn't match the reserved bits */ if (FxSaveArea->U.FxArea.MXCsrMask != 0) { /* Then use whatever it's holding */ MXCsrMask = FxSaveArea->U.FxArea.MXCsrMask; } /* Check if nobody set the kernel-wide mask */ if (!KiMXCsrMask) { /* Then use the one we calculated above */ KiMXCsrMask = MXCsrMask; } else { /* Was it set to the same value we found now? */ if (KiMXCsrMask != MXCsrMask) { /* No, something is definitely wrong */ KeBugCheckEx(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_FXSR, KiMXCsrMask, MXCsrMask, 0); } } /* Now set the kernel mask */ KiMXCsrMask &= MXCsrMask; } } } /* Return affinity back to where it was */ KeRevertToUserAffinityThread(); /* NT allows limiting the duration of an ISR with a registry key */ if (KiTimeLimitIsrMicroseconds) { /* FIXME: TODO */ DPRINT1("ISR Time Limit not yet supported\n"); } /* Set CR0 features based on detected CPU */ KiSetCR0Bits(); } INIT_FUNCTION VOID NTAPI KiInitializePcr(IN ULONG ProcessorNumber, IN PKIPCR Pcr, IN PKIDTENTRY Idt, IN PKGDTENTRY Gdt, IN PKTSS Tss, IN PKTHREAD IdleThread, IN PVOID DpcStack) { /* Setup the TIB */ Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END; Pcr->NtTib.StackBase = 0; Pcr->NtTib.StackLimit = 0; Pcr->NtTib.Self = NULL; /* Set the Current Thread */ Pcr->PrcbData.CurrentThread = IdleThread; /* Set pointers to ourselves */ Pcr->SelfPcr = (PKPCR)Pcr; Pcr->Prcb = &Pcr->PrcbData; /* Set the PCR Version */ Pcr->MajorVersion = PCR_MAJOR_VERSION; Pcr->MinorVersion = PCR_MINOR_VERSION; /* Set the PCRB Version */ Pcr->PrcbData.MajorVersion = 1; Pcr->PrcbData.MinorVersion = 1; /* Set the Build Type */ Pcr->PrcbData.BuildType = 0; #ifndef CONFIG_SMP Pcr->PrcbData.BuildType |= PRCB_BUILD_UNIPROCESSOR; #endif #if DBG Pcr->PrcbData.BuildType |= PRCB_BUILD_DEBUG; #endif /* Set the Processor Number and current Processor Mask */ Pcr->PrcbData.Number = (UCHAR)ProcessorNumber; Pcr->PrcbData.SetMember = 1 << ProcessorNumber; /* Set the PRCB for this Processor */ KiProcessorBlock[ProcessorNumber] = Pcr->Prcb; /* Start us out at PASSIVE_LEVEL */ Pcr->Irql = PASSIVE_LEVEL; /* Set the GDI, IDT, TSS and DPC Stack */ Pcr->GDT = (PVOID)Gdt; Pcr->IDT = Idt; Pcr->TSS = Tss; Pcr->TssCopy = Tss; Pcr->PrcbData.DpcStack = DpcStack; /* Setup the processor set */ Pcr->PrcbData.MultiThreadProcessorSet = Pcr->PrcbData.SetMember; } INIT_FUNCTION VOID NTAPI KiInitializeKernel(IN PKPROCESS InitProcess, IN PKTHREAD InitThread, IN PVOID IdleStack, IN PKPRCB Prcb, IN CCHAR Number, IN PLOADER_PARAMETER_BLOCK LoaderBlock) { BOOLEAN NpxPresent; ULONG FeatureBits; ULONG PageDirectory[2]; PVOID DpcStack; ULONG Vendor[3]; KIRQL DummyIrql; /* Detect and set the CPU Type */ KiSetProcessorType(); /* Check if an FPU is present */ NpxPresent = KiIsNpxPresent(); /* Initialize the Power Management Support for this PRCB */ PoInitializePrcb(Prcb); /* Bugcheck if this is a 386 CPU */ if (Prcb->CpuType == 3) KeBugCheckEx(UNSUPPORTED_PROCESSOR, 0x386, 0, 0, 0); /* Get the processor features for the CPU */ FeatureBits = KiGetFeatureBits(); /* Set the default NX policy (opt-in) */ SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN; /* Check if NPX is always on */ if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSON")) { /* Set it always on */ SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON; FeatureBits |= KF_NX_ENABLED; } else if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTOUT")) { /* Set it in opt-out mode */ SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTOUT; FeatureBits |= KF_NX_ENABLED; } else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTIN")) || (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE"))) { /* Set the feature bits */ FeatureBits |= KF_NX_ENABLED; } else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSOFF")) || (strstr(KeLoaderBlock->LoadOptions, "EXECUTE"))) { /* Set disabled mode */ SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSOFF; FeatureBits |= KF_NX_DISABLED; } /* Save feature bits */ Prcb->FeatureBits = FeatureBits; /* Save CPU state */ KiSaveProcessorControlState(&Prcb->ProcessorState); /* Get cache line information for this CPU */ KiGetCacheInformation(); /* Initialize spinlocks and DPC data */ KiInitSpinLocks(Prcb, Number); /* Check if this is the Boot CPU */ if (!Number) { /* Set Node Data */ KeNodeBlock[0] = &KiNode0; Prcb->ParentNode = KeNodeBlock[0]; KeNodeBlock[0]->ProcessorMask = Prcb->SetMember; /* Set boot-level flags */ KeI386NpxPresent = NpxPresent; KeI386CpuType = Prcb->CpuType; KeI386CpuStep = Prcb->CpuStep; KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL; KeProcessorLevel = (USHORT)Prcb->CpuType; if (Prcb->CpuID) KeProcessorRevision = Prcb->CpuStep; KeFeatureBits = FeatureBits; KeI386FxsrPresent = (KeFeatureBits & KF_FXSR) ? TRUE : FALSE; KeI386XMMIPresent = (KeFeatureBits & KF_XMMI) ? TRUE : FALSE; /* Detect 8-byte compare exchange support */ if (!(KeFeatureBits & KF_CMPXCHG8B)) { /* Copy the vendor string */ RtlCopyMemory(Vendor, Prcb->VendorString, sizeof(Vendor)); /* Bugcheck the system. Windows *requires* this */ KeBugCheckEx(UNSUPPORTED_PROCESSOR, (1 << 24 ) | (Prcb->CpuType << 16) | Prcb->CpuStep, Vendor[0], Vendor[1], Vendor[2]); } /* Set the current MP Master KPRCB to the Boot PRCB */ Prcb->MultiThreadSetMaster = Prcb; /* Lower to APC_LEVEL */ KeLowerIrql(APC_LEVEL); /* Initialize some spinlocks */ KeInitializeSpinLock(&KiFreezeExecutionLock); KeInitializeSpinLock(&Ki486CompatibilityLock); /* Initialize portable parts of the OS */ KiInitSystem(); /* Initialize the Idle Process and the Process Listhead */ InitializeListHead(&KiProcessListHead); PageDirectory[0] = 0; PageDirectory[1] = 0; KeInitializeProcess(InitProcess, 0, 0xFFFFFFFF, PageDirectory, FALSE); InitProcess->QuantumReset = MAXCHAR; } else { /* FIXME */ DPRINT1("SMP Boot support not yet present\n"); } /* Setup the Idle Thread */ KeInitializeThread(InitProcess, InitThread, NULL, NULL, NULL, NULL, NULL, IdleStack); InitThread->NextProcessor = Number; InitThread->Priority = HIGH_PRIORITY; InitThread->State = Running; InitThread->Affinity = 1 << Number; InitThread->WaitIrql = DISPATCH_LEVEL; InitProcess->ActiveProcessors = 1 << Number; /* HACK for MmUpdatePageDir */ ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess; /* Set basic CPU Features that user mode can read */ SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = (KeFeatureBits & KF_MMX) ? TRUE: FALSE; SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = (KeFeatureBits & KF_CMPXCHG8B) ? TRUE: FALSE; SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] = ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI)) ? TRUE: FALSE; SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] = ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI64)) ? TRUE: FALSE; SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] = (KeFeatureBits & KF_3DNOW) ? TRUE: FALSE; SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] = (KeFeatureBits & KF_RDTSC) ? TRUE: FALSE; /* Set up the thread-related fields in the PRCB */ Prcb->CurrentThread = InitThread; Prcb->NextThread = NULL; Prcb->IdleThread = InitThread; /* Initialize the Kernel Executive */ ExpInitializeExecutive(Number, LoaderBlock); /* Only do this on the boot CPU */ if (!Number) { /* Calculate the time reciprocal */ KiTimeIncrementReciprocal = KiComputeReciprocal(KeMaximumIncrement, &KiTimeIncrementShiftCount); /* Update DPC Values in case they got updated by the executive */ Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth; Prcb->MinimumDpcRate = KiMinimumDpcRate; Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold; /* Allocate the DPC Stack */ DpcStack = MmCreateKernelStack(FALSE, 0); if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0); Prcb->DpcStack = DpcStack; /* Allocate the IOPM save area. */ Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE * 2, ' eK'); if (!Ki386IopmSaveArea) { /* Bugcheck. We need this for V86/VDM support. */ KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0); } } /* Raise to Dispatch */ KeRaiseIrql(DISPATCH_LEVEL, &DummyIrql); /* Set the Idle Priority to 0. This will jump into Phase 1 */ KeSetPriorityThread(InitThread, 0); /* If there's no thread scheduled, put this CPU in the Idle summary */ KiAcquirePrcbLock(Prcb); if (!Prcb->NextThread) KiIdleSummary |= 1 << Number; KiReleasePrcbLock(Prcb); /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */ KeRaiseIrql(HIGH_LEVEL, &DummyIrql); LoaderBlock->Prcb = 0; } INIT_FUNCTION VOID FASTCALL KiGetMachineBootPointers(IN PKGDTENTRY *Gdt, IN PKIDTENTRY *Idt, IN PKIPCR *Pcr, IN PKTSS *Tss) { KDESCRIPTOR GdtDescriptor, IdtDescriptor; KGDTENTRY TssSelector, PcrSelector; USHORT Tr, Fs; /* Get GDT and IDT descriptors */ Ke386GetGlobalDescriptorTable(&GdtDescriptor.Limit); __sidt(&IdtDescriptor.Limit); /* Save IDT and GDT */ *Gdt = (PKGDTENTRY)GdtDescriptor.Base; *Idt = (PKIDTENTRY)IdtDescriptor.Base; /* Get TSS and FS Selectors */ Tr = Ke386GetTr(); Fs = Ke386GetFs(); /* Get PCR Selector, mask it and get its GDT Entry */ PcrSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Fs & ~RPL_MASK)); /* Get the KPCR itself */ *Pcr = (PKIPCR)(ULONG_PTR)(PcrSelector.BaseLow | PcrSelector.HighWord.Bytes.BaseMid << 16 | PcrSelector.HighWord.Bytes.BaseHi << 24); /* Get TSS Selector, mask it and get its GDT Entry */ TssSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Tr & ~RPL_MASK)); /* Get the KTSS itself */ *Tss = (PKTSS)(ULONG_PTR)(TssSelector.BaseLow | TssSelector.HighWord.Bytes.BaseMid << 16 | TssSelector.HighWord.Bytes.BaseHi << 24); } INIT_FUNCTION VOID NTAPI KiSystemStartupBootStack(VOID) { PKTHREAD Thread; /* Initialize the kernel for the current CPU */ KiInitializeKernel(&KiInitialProcess.Pcb, (PKTHREAD)KeLoaderBlock->Thread, (PVOID)(KeLoaderBlock->KernelStack & ~3), (PKPRCB)__readfsdword(KPCR_PRCB), KeNumberProcessors - 1, KeLoaderBlock); /* Set the priority of this thread to 0 */ Thread = KeGetCurrentThread(); Thread->Priority = 0; /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */ _enable(); KeLowerIrql(DISPATCH_LEVEL); /* Set the right wait IRQL */ Thread->WaitIrql = DISPATCH_LEVEL; /* Jump into the idle loop */ KiIdleLoop(); } static VOID KiMarkPageAsReadOnly( PVOID Address) { PHARDWARE_PTE PointerPte; /* Make sure the address is page aligned */ ASSERT(ALIGN_DOWN_POINTER_BY(Address, PAGE_SIZE) == Address); /* Get the PTE address */ PointerPte = ((PHARDWARE_PTE)PTE_BASE) + ((ULONG_PTR)Address / PAGE_SIZE); ASSERT(PointerPte->Valid); ASSERT(PointerPte->Write); /* Set as read-only */ PointerPte->Write = 0; /* Flush the TLB entry */ __invlpg(Address); } INIT_FUNCTION VOID NTAPI KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock) { ULONG Cpu; PKTHREAD InitialThread; ULONG InitialStack; PKGDTENTRY Gdt; PKIDTENTRY Idt; KIDTENTRY NmiEntry, DoubleFaultEntry; PKTSS Tss; PKIPCR Pcr; KIRQL DummyIrql; /* Boot cycles timestamp */ BootCycles = __rdtsc(); /* Save the loader block and get the current CPU */ KeLoaderBlock = LoaderBlock; Cpu = KeNumberProcessors; if (!Cpu) { /* If this is the boot CPU, set FS and the CPU Number*/ Ke386SetFs(KGDT_R0_PCR); __writefsdword(KPCR_PROCESSOR_NUMBER, Cpu); /* Set the initial stack and idle thread as well */ LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack; LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread; } /* Save the initial thread and stack */ InitialStack = LoaderBlock->KernelStack; InitialThread = (PKTHREAD)LoaderBlock->Thread; /* Clean the APC List Head */ InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]); /* Initialize the machine type */ KiInitializeMachineType(); /* Skip initial setup if this isn't the Boot CPU */ if (Cpu) goto AppCpuInit; /* Get GDT, IDT, PCR and TSS pointers */ KiGetMachineBootPointers(&Gdt, &Idt, &Pcr, &Tss); /* Setup the TSS descriptors and entries */ Ki386InitializeTss(Tss, Idt, Gdt); /* Initialize the PCR */ RtlZeroMemory(Pcr, PAGE_SIZE); KiInitializePcr(Cpu, Pcr, Idt, Gdt, Tss, InitialThread, (PVOID)KiDoubleFaultStack); /* Set us as the current process */ InitialThread->ApcState.Process = &KiInitialProcess.Pcb; /* Clear DR6/7 to cleanup bootloader debugging */ __writefsdword(KPCR_TEB, 0); __writefsdword(KPCR_DR6, 0); __writefsdword(KPCR_DR7, 0); /* Setup the IDT */ KeInitExceptions(); /* Load Ring 3 selectors for DS/ES */ Ke386SetDs(KGDT_R3_DATA | RPL_MASK); Ke386SetEs(KGDT_R3_DATA | RPL_MASK); /* Save NMI and double fault traps */ RtlCopyMemory(&NmiEntry, &Idt[2], sizeof(KIDTENTRY)); RtlCopyMemory(&DoubleFaultEntry, &Idt[8], sizeof(KIDTENTRY)); /* Copy kernel's trap handlers */ RtlCopyMemory(Idt, (PVOID)KiIdtDescriptor.Base, KiIdtDescriptor.Limit + 1); /* Restore NMI and double fault */ RtlCopyMemory(&Idt[2], &NmiEntry, sizeof(KIDTENTRY)); RtlCopyMemory(&Idt[8], &DoubleFaultEntry, sizeof(KIDTENTRY)); AppCpuInit: /* Loop until we can release the freeze lock */ do { /* Loop until execution can continue */ while (*(volatile PKSPIN_LOCK*)&KiFreezeExecutionLock == (PVOID)1); } while(InterlockedBitTestAndSet((PLONG)&KiFreezeExecutionLock, 0)); /* Setup CPU-related fields */ __writefsdword(KPCR_NUMBER, Cpu); __writefsdword(KPCR_SET_MEMBER, 1 << Cpu); __writefsdword(KPCR_SET_MEMBER_COPY, 1 << Cpu); __writefsdword(KPCR_PRCB_SET_MEMBER, 1 << Cpu); /* Initialize the Processor with HAL */ HalInitializeProcessor(Cpu, KeLoaderBlock); /* Set active processors */ KeActiveProcessors |= __readfsdword(KPCR_SET_MEMBER); KeNumberProcessors++; /* Check if this is the boot CPU */ if (!Cpu) { /* Initialize debugging system */ KdInitSystem(0, KeLoaderBlock); /* Check for break-in */ if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); /* Make the lowest page of the boot and double fault stack read-only */ KiMarkPageAsReadOnly(P0BootStackData); KiMarkPageAsReadOnly(KiDoubleFaultStackData); } /* Raise to HIGH_LEVEL */ KeRaiseIrql(HIGH_LEVEL, &DummyIrql); /* Switch to new kernel stack and start kernel bootstrapping */ KiSwitchToBootStack(InitialStack & ~3); }