From ccee43a3604fc6c4c0c0383f465e96d36f7f0465 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Thu, 18 Jan 2007 06:23:14 +0000 Subject: [PATCH] - Fix __rdtsc so it's considered volatile by GCC instead of caching it. - Add NtInitialUserProcessBuffer settings and validate/user them when launching smss. - Use SePublicDefaultUnrestrictedSd for the root system link. - Make enough space for the smss process parameters, there's 6 strings, not 4. - Fix incorrect length of NtSystemRoot string. - Disable SYSENTER on CPUs that don't support it. - Detect and enable NX feature bit. - Detect and enable DTS support. - Implement Ki386EnableXMMIExceptions (the XMMI handler still needs to be done, however). - Implement KiI386PentiumLockErrataFixup to work around the F00F bug. - Implement KiIsNpxErrataPresent to detect the FDIV bug. - Implement CPU Speed detection. - Only setup Initial FX State if the CPU supports FXSR. - Setup some more PCR fields during init. - Use NX_SUPPORT_POLICY flags documented in ntddk.h - Don't boot if CMPXCHG8B is not supported by the CPU. This is the same requirement as Windows. - Don't overwrite all the PRCB locks in KiInitSpinlocks due to a stupid bug in the timer spinlock initialization. svn path=/trunk/; revision=25503 --- reactos/include/ddk/winddk.h | 5 + reactos/include/ndk/ketypes.h | 11 +- reactos/include/psdk/intrin.h | 2 +- reactos/ntoskrnl/KrnlFun.c | 5 - reactos/ntoskrnl/ex/init.c | 98 ++++++--- reactos/ntoskrnl/include/internal/i386/ke.h | 6 + reactos/ntoskrnl/include/internal/ke.h | 21 +- reactos/ntoskrnl/ke/dpc.c | 2 +- reactos/ntoskrnl/ke/i386/cpu.c | 61 +++++- reactos/ntoskrnl/ke/i386/ctxswitch.S | 48 +++++ reactos/ntoskrnl/ke/i386/kiinit.c | 216 ++++++++++++++------ reactos/ntoskrnl/ke/i386/patpge.c | 2 +- reactos/ntoskrnl/ke/krnlinit.c | 12 +- 13 files changed, 382 insertions(+), 107 deletions(-) diff --git a/reactos/include/ddk/winddk.h b/reactos/include/ddk/winddk.h index 579df6d9063..6c5a206fc1a 100644 --- a/reactos/include/ddk/winddk.h +++ b/reactos/include/ddk/winddk.h @@ -427,6 +427,11 @@ typedef struct _KSYSTEM_TIME extern volatile KSYSTEM_TIME KeTickCount; +#define NX_SUPPORT_POLICY_ALWAYSOFF 0 +#define NX_SUPPORT_POLICY_ALWAYSON 1 +#define NX_SUPPORT_POLICY_OPTIN 2 +#define NX_SUPPORT_POLICY_OPTOUT 3 + typedef struct _KUSER_SHARED_DATA { ULONG TickCountLowDeprecated; diff --git a/reactos/include/ndk/ketypes.h b/reactos/include/ndk/ketypes.h index 1aa5c679288..290c08aedcb 100644 --- a/reactos/include/ndk/ketypes.h +++ b/reactos/include/ndk/ketypes.h @@ -39,6 +39,11 @@ Author: // #define SSDT_MAX_ENTRIES 2 +// +// Processor Architectures +// +#define PROCESSOR_ARCHITECTURE_INTEL 0 + // // Object Type Mask for Kernel Dispatcher Objects // @@ -87,8 +92,10 @@ Author: #define KF_3DNOW 0x00004000 #define KF_AMDK6MTRR 0x00008000 #define KF_XMMI64 0x00010000 -#define KF_NX_DISABLED 0x00400000 -#define KF_NX_ENABLED 0x00800000 +#define KF_DTS 0x00020000 +#define KF_NX_BIT 0x20000000 +#define KF_NX_DISABLED 0x40000000 +#define KF_NX_ENABLED 0x80000000 // // KPCR Access for non-IA64 builds diff --git a/reactos/include/psdk/intrin.h b/reactos/include/psdk/intrin.h index bb701d3224e..24245117337 100644 --- a/reactos/include/psdk/intrin.h +++ b/reactos/include/psdk/intrin.h @@ -930,7 +930,7 @@ static __inline__ __attribute__((always_inline)) unsigned long long __rdtsc(void unsigned long lo32; unsigned long hi32; - __asm__("rdtsc" : "=a" (lo32), "=d" (hi32)); + __asm__ __volatile__("rdtsc" : "=a" (lo32), "=d" (hi32)); { union u_ diff --git a/reactos/ntoskrnl/KrnlFun.c b/reactos/ntoskrnl/KrnlFun.c index 3688d299aa5..bf01c0ddcf5 100644 --- a/reactos/ntoskrnl/KrnlFun.c +++ b/reactos/ntoskrnl/KrnlFun.c @@ -9,7 +9,6 @@ // Failure to respect this will *ACHIEVE NOTHING*. // // Ke1: -// - Implement KiInitMachineDependent. // - Implement Privileged Instruction Handler in Umode GPF. // // Ex: @@ -28,10 +27,6 @@ // Kd: // - Implement KD Kernel Debugging and WinDBG support. // -// Native: -// - Rewrite loader. -// - Make smss NT-compatible. -// /////////////////////////////////////////////////////////////////////////////// // REACTOS GUIDANCE PLAN diff --git a/reactos/ntoskrnl/ex/init.c b/reactos/ntoskrnl/ex/init.c index 068d5d9263c..0b0efd029c8 100644 --- a/reactos/ntoskrnl/ex/init.c +++ b/reactos/ntoskrnl/ex/init.c @@ -39,6 +39,12 @@ BOOLEAN NoGuiBoot = FALSE; /* NT Boot Path */ UNICODE_STRING NtSystemRoot; +/* NT Initial User Application */ +WCHAR NtInitialUserProcessBuffer[128] = L"\\SystemRoot\\System32\\smss.exe"; +ULONG NtInitialUserProcessBufferLength = sizeof(NtInitialUserProcessBuffer) - + sizeof(WCHAR); +ULONG NtInitialUserProcessBufferType = REG_SZ; + /* Boot NLS information */ PVOID ExpNlsTableBase; ULONG ExpAnsiCodePageDataOffset, ExpOemCodePageDataOffset; @@ -68,7 +74,7 @@ ExpCreateSystemRootLink(IN PLOADER_PARAMETER_BLOCK LoaderBlock) &LinkName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, - SePublicDefaultSd); + SePublicDefaultUnrestrictedSd); /* Create it */ Status = NtCreateDirectoryObject(&LinkHandle, @@ -88,7 +94,7 @@ ExpCreateSystemRootLink(IN PLOADER_PARAMETER_BLOCK LoaderBlock) &LinkName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, - SePublicDefaultSd); + SePublicDefaultUnrestrictedSd); /* Create it */ Status = NtCreateDirectoryObject(&LinkHandle, @@ -115,7 +121,7 @@ ExpCreateSystemRootLink(IN PLOADER_PARAMETER_BLOCK LoaderBlock) &LinkName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, - SePublicDefaultSd); + SePublicDefaultUnrestrictedSd); /* Build the ARC name */ sprintf(Buffer, @@ -353,10 +359,11 @@ ExpLoadInitialProcess(IN PHANDLE ProcessHandle, PWSTR p; UNICODE_STRING NullString = RTL_CONSTANT_STRING(L""); UNICODE_STRING SmssName, Environment, SystemDriveString; + PVOID EnvironmentPtr = NULL; /* Allocate memory for the process parameters */ Size = sizeof(RTL_USER_PROCESS_PARAMETERS) + - ((MAX_PATH * 4) * sizeof(WCHAR)); + ((MAX_PATH * 6) * sizeof(WCHAR)); Status = ZwAllocateVirtualMemory(NtCurrentProcess(), (PVOID)&ProcessParameters, 0, @@ -378,7 +385,7 @@ ExpLoadInitialProcess(IN PHANDLE ProcessHandle, /* Allocate a page for the environment */ Size = PAGE_SIZE; Status = ZwAllocateVirtualMemory(NtCurrentProcess(), - (PVOID)&ProcessParameters->Environment, + &EnvironmentPtr, 0, &Size, MEM_COMMIT, @@ -389,6 +396,9 @@ ExpLoadInitialProcess(IN PHANDLE ProcessHandle, KeBugCheckEx(SESSION2_INITIALIZATION_FAILED, Status, 0, 0, 0); } + /* Write the pointer */ + ProcessParameters->Environment = EnvironmentPtr; + /* Make a buffer for the DOS path */ p = (PWSTR)(ProcessParameters + 1); ProcessParameters->CurrentDirectory.DosPath.Buffer = p; @@ -416,11 +426,48 @@ ExpLoadInitialProcess(IN PHANDLE ProcessHandle, ProcessParameters->ImagePathName.Buffer = p; ProcessParameters->ImagePathName.MaximumLength = MAX_PATH * sizeof(WCHAR); - /* Append the system path and session manager name */ - RtlAppendUnicodeToString(&ProcessParameters->ImagePathName, - L"\\SystemRoot\\System32"); - RtlAppendUnicodeToString(&ProcessParameters->ImagePathName, - L"\\smss.exe"); + /* Make sure the buffer is a valid string which within the given length */ + if ((NtInitialUserProcessBufferType != REG_SZ) || + ((NtInitialUserProcessBufferLength != -1) && + ((NtInitialUserProcessBufferLength < sizeof(WCHAR)) || + (NtInitialUserProcessBufferLength > + sizeof(NtInitialUserProcessBuffer) - sizeof(WCHAR))))) + { + /* Invalid initial process string, bugcheck */ + KeBugCheckEx(SESSION2_INITIALIZATION_FAILED, + (ULONG_PTR)STATUS_INVALID_PARAMETER, + NtInitialUserProcessBufferType, + NtInitialUserProcessBufferLength, + sizeof(NtInitialUserProcessBuffer)); + } + + /* Cut out anything after a space */ + p = NtInitialUserProcessBuffer; + while (*p && *p != L' ') p++; + + /* Set the image path length */ + ProcessParameters->ImagePathName.Length = + (USHORT)((PCHAR)p - (PCHAR)NtInitialUserProcessBuffer); + + /* Copy the actual buffer */ + RtlCopyMemory(ProcessParameters->ImagePathName.Buffer, + NtInitialUserProcessBuffer, + ProcessParameters->ImagePathName.Length); + + /* Null-terminate it */ + ProcessParameters-> + ImagePathName.Buffer[ProcessParameters->ImagePathName.Length / + sizeof(WCHAR)] = UNICODE_NULL; + + /* Make a buffer for the command line */ + p = (PWSTR)((PCHAR)ProcessParameters->ImagePathName.Buffer + + ProcessParameters->ImagePathName.MaximumLength); + ProcessParameters->CommandLine.Buffer = p; + ProcessParameters->CommandLine.MaximumLength = MAX_PATH * sizeof(WCHAR); + + /* Add the image name to the command line */ + RtlAppendUnicodeToString(&ProcessParameters->CommandLine, + NtInitialUserProcessBuffer); /* Create the environment string */ RtlInitEmptyUnicodeString(&Environment, @@ -446,11 +493,8 @@ ExpLoadInitialProcess(IN PHANDLE ProcessHandle, RtlAppendUnicodeStringToString(&Environment, &NtSystemRoot); RtlAppendUnicodeStringToString(&Environment, &NullString); - /* Get and set the command line equal to the image path */ - ProcessParameters->CommandLine = ProcessParameters->ImagePathName; - SmssName = ProcessParameters->ImagePathName; - /* Create SMSS process */ + SmssName = ProcessParameters->ImagePathName; Status = RtlCreateUserProcess(&SmssName, OBJ_CASE_INSENSITIVE, RtlDeNormalizeProcessParams( @@ -731,9 +775,9 @@ ExpInitializeExecutive(IN ULONG Cpu, Buffer[--AnsiPath.Length] = ANSI_NULL; /* Get the string from KUSER_SHARED_DATA's buffer */ - NtSystemRoot.Buffer = SharedUserData->NtSystemRoot; - NtSystemRoot.MaximumLength = sizeof(SharedUserData->NtSystemRoot) / sizeof(WCHAR); - NtSystemRoot.Length = 0; + RtlInitEmptyUnicodeString(&NtSystemRoot, + SharedUserData->NtSystemRoot, + sizeof(SharedUserData->NtSystemRoot)); /* Now fill it in */ Status = RtlAnsiStringToUnicodeString(&NtSystemRoot, &AnsiPath, FALSE); @@ -960,19 +1004,17 @@ ExPhase2Init(PVOID Context) /* Bugcheck the system if SMSS couldn't initialize */ KeBugCheck(SESSION5_INITIALIZATION_FAILED); } - else - { - /* Close process handles */ - ZwClose(ThreadHandle); - ZwClose(ProcessHandle); - /* FIXME: We should free the initial process' memory!*/ + /* Close process handles */ + ZwClose(ThreadHandle); + ZwClose(ProcessHandle); - /* Increase init phase */ - ExpInitializationPhase += 1; + /* FIXME: We should free the initial process' memory!*/ - /* Jump into zero page thread */ - MmZeroPageThreadMain(NULL); - } + /* Increase init phase */ + ExpInitializationPhase += 1; + + /* Jump into zero page thread */ + MmZeroPageThreadMain(NULL); } /* EOF */ diff --git a/reactos/ntoskrnl/include/internal/i386/ke.h b/reactos/ntoskrnl/include/internal/i386/ke.h index b13f133ddee..c189288fd89 100644 --- a/reactos/ntoskrnl/include/internal/i386/ke.h +++ b/reactos/ntoskrnl/include/internal/i386/ke.h @@ -92,6 +92,12 @@ KiIsNpxPresent( VOID ); +BOOLEAN +NTAPI +KiIsNpxErrataPresent( + VOID +); + VOID NTAPI KiSetProcessorType(VOID); diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 985ffda0d84..7260f78d4f6 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -37,6 +37,18 @@ typedef struct _DISPATCH_INFO PKINTERRUPT_ROUTINE *FlatDispatch; } DISPATCH_INFO, *PDISPATCH_INFO; +typedef struct _KI_SAMPLE_MAP +{ + LARGE_INTEGER PerfStart; + LARGE_INTEGER PerfEnd; + LONGLONG PerfDelta; + LARGE_INTEGER PerfFreq; + LONGLONG TSCStart; + LONGLONG TSCEnd; + LONGLONG TSCDelta; + ULONG MHz; +} KI_SAMPLE_MAP, *PKI_SAMPLE_MAP; + typedef struct _KTIMER_TABLE_ENTRY { LIST_ENTRY Entry; @@ -113,7 +125,7 @@ extern KSPIN_LOCK BugCheckCallbackLock; extern KDPC KiExpireTimerDpc; extern KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]; extern LIST_ENTRY KiTimerListHead; -extern KMUTEX KiGenericCallDpcMutex; +extern FAST_MUTEX KiGenericCallDpcMutex; extern LIST_ENTRY KiProfileListHead, KiProfileSourceListHead; extern KSPIN_LOCK KiProfileLock; extern LIST_ENTRY KiProcessListHead; @@ -235,6 +247,13 @@ KiSelectNextThread( IN PKPRCB Prcb ); +VOID +NTAPI +CPUID( + OUT ULONG CpuInfo[4], + IN ULONG InfoType +); + /* gmutex.c ********************************************************************/ VOID diff --git a/reactos/ntoskrnl/ke/dpc.c b/reactos/ntoskrnl/ke/dpc.c index a0760762143..49b2a894ea3 100644 --- a/reactos/ntoskrnl/ke/dpc.c +++ b/reactos/ntoskrnl/ke/dpc.c @@ -23,7 +23,7 @@ ULONG KiMinimumDpcRate = 3; ULONG KiAdjustDpcThreshold = 20; ULONG KiIdealDpcRate = 20; BOOLEAN KeThreadDpcEnable; -KMUTEX KiGenericCallDpcMutex; +FAST_MUTEX KiGenericCallDpcMutex; /* PRIVATE FUNCTIONS *********************************************************/ diff --git a/reactos/ntoskrnl/ke/i386/cpu.c b/reactos/ntoskrnl/ke/i386/cpu.c index b057fb0527a..c69fd44d3ce 100644 --- a/reactos/ntoskrnl/ke/i386/cpu.c +++ b/reactos/ntoskrnl/ke/i386/cpu.c @@ -340,6 +340,14 @@ KiGetFeatureBits(VOID) FeatureBits &= ~KF_WORKING_PTE; } + /* Check if the CPU is too old to support SYSENTER */ + if ((Prcb->CpuType < 6) || + ((Prcb->CpuType == 6) && (Prcb->CpuStep < 0x0303))) + { + /* Disable it */ + Reg[3] &= ~0x800; + } + /* Set the current features */ CpuFeatures = Reg[3]; } @@ -354,6 +362,7 @@ KiGetFeatureBits(VOID) if (CpuFeatures & 0x00002000) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4; if (CpuFeatures & 0x00008000) FeatureBits |= KF_CMOV; if (CpuFeatures & 0x00010000) FeatureBits |= KF_PAT; + if (CpuFeatures & 0x00200000) FeatureBits |= KF_DTS; if (CpuFeatures & 0x00800000) FeatureBits |= KF_MMX; if (CpuFeatures & 0x01000000) FeatureBits |= KF_FXSR; if (CpuFeatures & 0x02000000) FeatureBits |= KF_XMMI; @@ -389,6 +398,9 @@ KiGetFeatureBits(VOID) /* Check which extended features are available. */ CPUID(Reg, 0x80000001); + /* Check if NX-bit is supported */ + if (Reg[3] & 0x00100000) FeatureBits |= KF_NX_BIT; + /* Now handle each features for each CPU Vendor */ switch (Vendor) { @@ -741,8 +753,23 @@ ULONG_PTR NTAPI Ki386EnableXMMIExceptions(IN ULONG_PTR Context) { - /* FIXME: Support this */ - DPRINT1("Your machine supports XMMI exceptions but ReactOS doesn't\n"); +#if 0 // needs kitrap13 + PKIDTENTRY IdtEntry; + + /* Get the IDT Entry for Interrupt 19 */ + IdtEntry = ((PKIPCR)KeGetPcr())->IDT[19]; + + /* Set it up */ + IdtEntry->Selector = KGDT_R0_CODE; + IdtEntry->Offset = (KiTrap13 & 0xFFFF); + IdtEntry->ExtendedOffset = (KiTrap13 >> 16) & 0xFFFF; + ((PKIDT_ACCESS)&IdtEntry->Access)->Dpl = 0; + ((PKIDT_ACCESS)&IdtEntry->Access)->Present = 1; + ((PKIDT_ACCESS)&IdtEntry->Access)->SegmentType = I386_INTERRUPT_GATE; +#endif + + /* Enable XMMI exceptions */ + __writecr4(__readcr4() | CR4_XMMEXCPT); return 0; } @@ -750,8 +777,34 @@ VOID NTAPI KiI386PentiumLockErrataFixup(VOID) { - /* FIXME: Support this */ - DPRINT1("WARNING: Your machine has a CPU bug that ReactOS can't bypass!\n"); + KDESCRIPTOR IdtDescriptor; + PKIDTENTRY NewIdt, NewIdt2; + + /* Allocate memory for a new IDT */ + NewIdt = ExAllocatePool(NonPagedPool, 2 * PAGE_SIZE); + + /* Put everything after the first 7 entries on a new page */ + NewIdt2 = (PVOID)((ULONG_PTR)NewIdt + PAGE_SIZE - (7 * sizeof(KIDTENTRY))); + + /* Disable interrupts */ + _disable(); + + /* Get the current IDT and copy it */ + Ke386GetInterruptDescriptorTable(IdtDescriptor); + RtlCopyMemory(NewIdt2, + (PVOID)IdtDescriptor.Base, + IdtDescriptor.Limit + 1); + IdtDescriptor.Base = (ULONG)NewIdt2; + + /* Set the new IDT */ + Ke386SetInterruptDescriptorTable(IdtDescriptor); + ((PKIPCR)KeGetPcr())->IDT = NewIdt2; + + /* Restore interrupts */ + _enable(); + + /* Set the first 7 entries as read-only to produce a fault */ + MmSetPageProtect(NULL, NewIdt, PAGE_READONLY); } /* PUBLIC FUNCTIONS **********************************************************/ diff --git a/reactos/ntoskrnl/ke/i386/ctxswitch.S b/reactos/ntoskrnl/ke/i386/ctxswitch.S index 9d2d30e34e2..64003ab7570 100644 --- a/reactos/ntoskrnl/ke/i386/ctxswitch.S +++ b/reactos/ntoskrnl/ke/i386/ctxswitch.S @@ -17,8 +17,56 @@ #define Running 2 #define WrDispatchInt 0x1F +Dividend: .float 4195835.0 +Divisor: .float 3145727.0 +Result1: .float 0 +Result2: .float 0 + /* FUNCTIONS ****************************************************************/ +.globl _KiIsNpxErrataPresent@0 +.func KiIsNpxErrataPresent@0 +_KiIsNpxErrataPresent@0: + + /* Disable interrupts */ + cli + + /* Get CR0 and mask out FPU flags */ + mov eax, cr0 + mov ecx, eax + and eax, ~(CR0_MP + CR0_TS + CR0_EM) + mov cr0, eax + + /* Initialize the FPU */ + fninit + + /* Do the divison and inverse multiplication */ + fld qword ptr Dividend + fstp qword ptr Result1 + fld qword ptr Divisor + fstp qword ptr Result2 + fld qword ptr Result1 + fdiv qword ptr Result2 + fmul qword ptr Result2 + + /* Do the compare and check flags */ + fcomp qword ptr Result1 + fstsw ax + sahf + + /* Restore CR0 and interrupts */ + mov cr0, ecx + sti + + /* Return errata status */ + xor eax, eax + jz NoErrata + inc eax + +NoErrata: + ret +.endfunc + .globl _KiIsNpxPresent@0 .func KiIsNpxPresent@0 _KiIsNpxPresent@0: diff --git a/reactos/ntoskrnl/ke/i386/kiinit.c b/reactos/ntoskrnl/ke/i386/kiinit.c index 3d57fa92563..5965b310ed3 100644 --- a/reactos/ntoskrnl/ke/i386/kiinit.c +++ b/reactos/ntoskrnl/ke/i386/kiinit.c @@ -30,15 +30,18 @@ KiInitMachineDependent(VOID) BOOLEAN FbCaching = FALSE; NTSTATUS Status; ULONG ReturnLength; - ULONG i, Affinity; + ULONG i, Affinity, Sample = 0; PFX_SAVE_AREA FxSaveArea; - ULONG MXCsrMask = 0xFFBF, NewMask; + 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("Your machine supports PGE but ReactOS doesn't yet.\n"); + DPRINT1("Large Page support detected but not yet taken advantage of!\n"); } /* Check for global page support */ @@ -70,6 +73,34 @@ KiInitMachineDependent(VOID) /* 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; @@ -148,18 +179,66 @@ KiInitMachineDependent(VOID) /* Start sampling loop */ for (;;) { - // - // FIXME: TODO - // - break; + /* 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 without PAT */ - if (!(KeFeatureBits & KF_PAT) && (KeFeatureBits & KF_MTRR)) + /* Check if we have MTRR */ + if (KeFeatureBits & KF_MTRR) { /* Then manually initialize MTRR for the CPU */ - KiInitializeMTRR((BOOLEAN)i); + KiInitializeMTRR((BOOLEAN)i ? FALSE : TRUE); } /* Check if we have AMD MTRR and initialize it for the CPU */ @@ -168,52 +247,53 @@ KiInitMachineDependent(VOID) /* Check if this is a buggy Pentium and apply the fixup if so */ if (KiI386PentiumLockErrataPresent) KiI386PentiumLockErrataFixup(); - /* Get the current thread NPX state */ - FxSaveArea = (PVOID) - ((ULONG_PTR)KeGetCurrentThread()->InitialStack - - NPX_FRAME_LENGTH); + /* 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; + /* Clear initial MXCsr mask */ + FxSaveArea->U.FxArea.MXCsrMask = 0; - /* Save the current NPX State */ + /* Save the current NPX State */ #ifdef __GNUC__ - asm volatile("fxsave %0\n\t" : "=m" (*FxSaveArea)); + asm volatile("fxsave %0\n\t" : "=m" (*FxSaveArea)); #else - __asm fxsave [FxSaveArea] + __asm fxsave [FxSaveArea] #endif - /* Check if the current mask doesn't match the reserved bits */ - if (FxSaveArea->U.FxArea.MXCsrMask != MXCsrMask) - { - /* 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 */ - NewMask = MXCsrMask; - } - else - { - /* Use the existing mask */ - NewMask = KiMXCsrMask; - - /* Was it set to the same value we found now? */ - if (NewMask != MXCsrMask) + /* Check if the current mask doesn't match the reserved bits */ + if (FxSaveArea->U.FxArea.MXCsrMask != 0) { - /* No, something is definitely wrong */ - KEBUGCHECKEX(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, - KF_FXSR, - NewMask, - MXCsrMask, - 0); + /* Then use whatever it's holding */ + MXCsrMask = FxSaveArea->U.FxArea.MXCsrMask; } - } - /* Now set the kernel mask */ - KiMXCsrMask = NewMask & 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; + } } } @@ -242,7 +322,7 @@ 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; @@ -282,7 +362,11 @@ KiInitializePcr(IN ULONG 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 @@ -299,6 +383,7 @@ KiInitializeKernel(IN PKPROCESS InitProcess, LARGE_INTEGER PageDirectory; PVOID DpcStack; ULONG NXSupportPolicy; + ULONG Vendor[3]; /* Detect and set the CPU Type */ KiSetProcessorType(); @@ -319,19 +404,19 @@ KiInitializeKernel(IN PKPROCESS InitProcess, FeatureBits = KiGetFeatureBits(); /* Set the default NX policy (opt-in) */ - NXSupportPolicy = 2; + NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN; /* Check if NPX is always on */ if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSON")) { /* Set it always on */ - NXSupportPolicy = 1; + NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON; FeatureBits |= KF_NX_ENABLED; } else if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTOUT")) { /* Set it in opt-out mode */ - NXSupportPolicy = 3; + NXSupportPolicy = NX_SUPPORT_POLICY_OPTOUT; FeatureBits |= KF_NX_ENABLED; } else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTIN")) || @@ -344,7 +429,7 @@ KiInitializeKernel(IN PKPROCESS InitProcess, (strstr(KeLoaderBlock->LoadOptions, "EXECUTE"))) { /* Set disabled mode */ - NXSupportPolicy = 0; + NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSOFF; FeatureBits |= KF_NX_DISABLED; } @@ -372,18 +457,32 @@ KiInitializeKernel(IN PKPROCESS InitProcess, 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); @@ -499,7 +598,9 @@ KiInitializeKernel(IN PKPROCESS InitProcess, 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); @@ -683,11 +784,6 @@ AppCpuInit: /* 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(); } diff --git a/reactos/ntoskrnl/ke/i386/patpge.c b/reactos/ntoskrnl/ke/i386/patpge.c index f571c7184d9..95e2307a0b4 100644 --- a/reactos/ntoskrnl/ke/i386/patpge.c +++ b/reactos/ntoskrnl/ke/i386/patpge.c @@ -59,5 +59,5 @@ NTAPI KiInitializePAT(VOID) { /* FIXME: Support this */ - DPRINT1("Your machine supports PAT but ReactOS doesn't yet.\n"); + DPRINT1("Advanced Memory features detected but not yet taken advantage of.\n"); } diff --git a/reactos/ntoskrnl/ke/krnlinit.c b/reactos/ntoskrnl/ke/krnlinit.c index 05188c4ab59..0b709bc7682 100644 --- a/reactos/ntoskrnl/ke/krnlinit.c +++ b/reactos/ntoskrnl/ke/krnlinit.c @@ -94,7 +94,7 @@ KiInitSystem(VOID) InitializeListHead(&KiStackInSwapListHead); /* Initialize the mutex for generic DPC calls */ - KeInitializeMutex(&KiGenericCallDpcMutex, 0); + ExInitializeFastMutex(&KiGenericCallDpcMutex); /* Initialize the syscall table */ KeServiceDescriptorTable[0].Base = MainSSDT; @@ -183,7 +183,7 @@ KiInitSpinLocks(IN PKPRCB Prcb, Prcb->QueueIndex = 1; Prcb->ReadySummary = 0; Prcb->DeferredReadyListHead.Next = NULL; - for (i = 0; i < 32; i++) + for (i = 0; i < MAXIMUM_PRIORITY; i++) { /* Initialize the ready list */ InitializeListHead(&Prcb->DispatcherReadyListHead[i]); @@ -246,10 +246,14 @@ KiInitSpinLocks(IN PKPRCB Prcb, { /* Initialize the lock and setup the Queued Spinlock */ KeInitializeSpinLock(&KiTimerTableLock[i]); - Prcb->LockQueue[i].Next = NULL; - Prcb->LockQueue[i].Lock = &KiTimerTableLock[i]; + Prcb->LockQueue[LockQueueTimerTableLock + i].Next = NULL; + Prcb->LockQueue[LockQueueTimerTableLock + i].Lock = + &KiTimerTableLock[i]; } + /* Initialize the PRCB lock */ + KeInitializeSpinLock(&Prcb->PrcbLock); + /* Check if this is the boot CPU */ if (!Number) {