#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
-#include <intrin.h>
/* GLOBALS *******************************************************************/
/* FUNCTIONS *****************************************************************/
+VOID
+NTAPI
+KiInitMachineDependent(VOID)
+{
+ ULONG Protect;
+ ULONG CpuCount;
+ BOOLEAN FbCaching = FALSE;
+ NTSTATUS Status;
+ ULONG ReturnLength;
+ ULONG i, Affinity, Sample = 0;
+ PFX_SAVE_AREA FxSaveArea;
+ ULONG MXCsrMask = 0xFFBF;
+ ULONG Dummy[4];
+ KI_SAMPLE_MAP Samples[4];
+ PKI_SAMPLE_MAP CurrentSample = Samples;
+
+ /* Check for large page support */
+ if (KeFeatureBits & KF_LARGE_PAGE)
+ {
+ /* FIXME: Support this */
+ DPRINT1("Large Page support detected but not yet taken advantage of!\n");
+ }
+
+ /* 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 */
+ Protect = MmGetPageProtect(NULL, RtlPrefetchMemoryNonTemporal);
+ MmSetPageProtect(NULL,
+ RtlPrefetchMemoryNonTemporal,
+ Protect | PAGE_IS_WRITABLE);
+ *(PCHAR)RtlPrefetchMemoryNonTemporal = 0x90;
+ MmSetPageProtect(NULL, RtlPrefetchMemoryNonTemporal, Protect);
+ }
+ }
+
+ /* 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 */
+ CPUID(Dummy, 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 */
+ CPUID(Dummy, 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 = ((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++;
+ }
+
+ /* 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((BOOLEAN)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 = (PVOID)
+ ((ULONG_PTR)KeGetCurrentThread()->InitialStack -
+ NPX_FRAME_LENGTH);
+
+ /* Clear initial MXCsr mask */
+ FxSaveArea->U.FxArea.MXCsrMask = 0;
+
+ /* Save the current NPX State */
+#ifdef __GNUC__
+ asm volatile("fxsave %0\n\t" : "=m" (*FxSaveArea));
+#else
+ __asm fxsave [FxSaveArea]
+#endif
+ /* 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");
+ }
+}
+
VOID
NTAPI
KiInitializePcr(IN ULONG ProcessorNumber,
Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
Pcr->NtTib.StackBase = 0;
Pcr->NtTib.StackLimit = 0;
- Pcr->NtTib.Self = 0;
+ Pcr->NtTib.Self = NULL;
/* Set the Current Thread */
Pcr->PrcbData.CurrentThread = IdleThread;
/* Set the Build Type */
Pcr->PrcbData.BuildType = 0;
+#ifndef CONFIG_SMP
+ Pcr->PrcbData.BuildType |= PRCB_BUILD_UNIPROCESSOR;
+#endif
+#ifdef DBG
+ Pcr->PrcbData.BuildType |= PRCB_BUILD_DEBUG;
+#endif
/* Set the Processor Number and current Processor Mask */
Pcr->PrcbData.Number = (UCHAR)ProcessorNumber;
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;
}
VOID
ULONG FeatureBits;
LARGE_INTEGER PageDirectory;
PVOID DpcStack;
+ ULONG NXSupportPolicy;
+ ULONG Vendor[3];
/* Detect and set the CPU Type */
KiSetProcessorType();
/* Get the processor features for the CPU */
FeatureBits = KiGetFeatureBits();
+ /* Set the default NX policy (opt-in) */
+ NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN;
+
+ /* Check if NPX is always on */
+ if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSON"))
+ {
+ /* Set it always on */
+ NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON;
+ FeatureBits |= KF_NX_ENABLED;
+ }
+ else if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTOUT"))
+ {
+ /* Set it in opt-out mode */
+ 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 */
+ NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSOFF;
+ FeatureBits |= KF_NX_DISABLED;
+ }
+
/* Save feature bits */
Prcb->FeatureBits = FeatureBits;
KeI386NpxPresent = NpxPresent;
KeI386CpuType = Prcb->CpuType;
KeI386CpuStep = Prcb->CpuStep;
- KeProcessorArchitecture = 0;
+ 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(0x5D,
+ (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 */
- KfLowerIrql(APC_LEVEL);
+ KeLowerIrql(APC_LEVEL);
/* Initialize some spinlocks */
KeInitializeSpinLock(&KiFreezeExecutionLock);
/* HACK for MmUpdatePageDir */
((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess;
+ /* Initialize Kernel Memory Address Space */
+ MmInit1(MmFreeLdrFirstKrnlPhysAddr,
+ MmFreeLdrLastKrnlPhysAddr,
+ MmFreeLdrLastKernelAddress,
+ NULL,
+ 0,
+ 4096);
+
+ /* Sets up the Text Sections of the Kernel and HAL for debugging */
+ LdrInit1();
+
+ /* Set the NX Support policy */
+ SharedUserData->NXSupportPolicy = (UCHAR)NXSupportPolicy;
+
+ /* 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;
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 */
KfRaiseIrql(HIGH_LEVEL);
{
KDESCRIPTOR GdtDescriptor, IdtDescriptor;
KGDTENTRY TssSelector, PcrSelector;
- ULONG Tr, Fs;
+ USHORT Tr, Fs;
/* Get GDT and IDT descriptors */
Ke386GetGlobalDescriptorTable(GdtDescriptor);
*Idt = (PKIDTENTRY)IdtDescriptor.Base;
/* Get TSS and FS Selectors */
- Ke386GetTr(&Tr);
+ Ke386GetTr(Tr);
if (Tr != KGDT_TSS) Tr = KGDT_TSS; // FIXME: HACKHACK
Fs = Ke386GetFs();
__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);
/* Align stack and make space for the trap frame and NPX frame */
InitialStack &= ~KTRAP_FRAME_ALIGN;
+#ifdef __GNUC__
__asm__ __volatile__("movl %0,%%esp" : :"r" (InitialStack));
__asm__ __volatile__("subl %0,%%esp" : :"r" (NPX_FRAME_LENGTH +
KTRAP_FRAME_LENGTH +
KTRAP_FRAME_ALIGN));
__asm__ __volatile__("push %0" : :"r" (CR0_EM + CR0_TS + CR0_MP));
+#else
+ __asm mov esp, InitialStack;
+ __asm sub esp, NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH;
+ __asm push CR0_EM + CR0_TS + CR0_MP
+#endif
/* Call main kernel initialization */
KiInitializeKernel(&KiInitialProcess.Pcb,
InitialThread,
(PVOID)InitialStack,
(PKPRCB)__readfsdword(KPCR_PRCB),
- Cpu,
+ (CCHAR)Cpu,
KeLoaderBlock);
/* Set the priority of this thread to 0 */
/* Set the right wait IRQL */
KeGetCurrentThread()->WaitIrql = DISPATCH_LEVEL;
- /* Set idle thread as running on UP builds */
-#ifndef CONFIG_SMP
- KeGetCurrentThread()->State = Running;
-#endif
-
/* Jump into the idle loop */
KiIdleLoop();
}
-