- Multiple changes to low-level Kernel initalization sequence to bring it a bit closer to Windows.

- Main difference is new CPU detection algorithms for ID, cache, etc, as well as using KF_ Kernel Feature bits instead of x86 CPU features (For portability).
- Also many many other cleanups and re-sequencing.

svn path=/trunk/; revision=23852
This commit is contained in:
Alex Ionescu 2006-09-01 03:05:30 +00:00
parent 3c411c196d
commit 369f93b984
15 changed files with 979 additions and 549 deletions

View file

@ -1046,26 +1046,27 @@ typedef struct _KDEVICE_QUEUE_ENTRY {
#define LOCK_QUEUE_TIMER_LOCK_SHIFT 4
#define LOCK_QUEUE_TIMER_TABLE_LOCKS (1 << (8 - LOCK_QUEUE_TIMER_LOCK_SHIFT))
typedef enum _KSPIN_LOCK_QUEUE_NUMBER {
LockQueueDispatcherLock,
LockQueueContextSwapLock,
LockQueuePfnLock,
LockQueueSystemSpaceLock,
LockQueueVacbLock,
LockQueueMasterLock,
LockQueueNonPagedPoolLock,
LockQueueIoCancelLock,
LockQueueWorkQueueLock,
LockQueueIoVpbLock,
LockQueueIoDatabaseLock,
LockQueueIoCompletionLock,
LockQueueNtfsStructLock,
LockQueueAfdWorkQueueLock,
LockQueueBcbLock,
LockQueueMmNonPagedPoolLock,
LockQueueUnusedSpare16,
LockQueueTimerTableLock,
LockQueueMaximumLock = LockQueueTimerTableLock + LOCK_QUEUE_TIMER_TABLE_LOCKS
typedef enum _KSPIN_LOCK_QUEUE_NUMBER
{
LockQueueDispatcherLock,
LockQueueExpansionLock,
LockQueuePfnLock,
LockQueueSystemSpaceLock,
LockQueueVacbLock,
LockQueueMasterLock,
LockQueueNonPagedPoolLock,
LockQueueIoCancelLock,
LockQueueWorkQueueLock,
LockQueueIoVpbLock,
LockQueueIoDatabaseLock,
LockQueueIoCompletionLock,
LockQueueNtfsStructLock,
LockQueueAfdWorkQueueLock,
LockQueueBcbLock,
LockQueueMmNonPagedPoolLock,
LockQueueUnusedSpare16,
LockQueueTimerTableLock,
LockQueueMaximumLock = LockQueueTimerTableLock + LOCK_QUEUE_TIMER_TABLE_LOCKS
} KSPIN_LOCK_QUEUE_NUMBER, *PKSPIN_LOCK_QUEUE_NUMBER;
typedef struct _KSPIN_LOCK_QUEUE {

View file

@ -62,7 +62,22 @@ Author:
//
// Kernel Feature Bits
//
#define KF_V86_VIS 0x00000001
#define KF_RDTSC 0x00000002
#define KF_CR4 0x00000004
#define KF_CMOV 0x00000008
#define KF_GLOBAL_PAGE 0x00000010
#define KF_LARGE_PAGE 0x00000020
#define KF_MTRR 0x00000040
#define KF_CMPXCHG8B 0x00000080
#define KF_MMX 0x00000100
#define KF_WORKING_PTE 0x00000200
#define KF_PAT 0x00000400
#define KF_FXSR 0x00000800
#define KF_FAST_SYSCALL 0x00001000
#define KF_XMMI 0x00002000
#define KF_3DNOW 0x00004000
#define KF_AMDK6MTRR 0x00008000
//
// KPCR Access for non-IA64 builds

View file

@ -25,11 +25,18 @@
// - Use Object Type Mutex/Lock.
//
// Ke:
// - Get rid of KiRosPrintAddress and use KiDumpParameterImages instead.
// - Sanitize some context fields during conversions.
// - Implement stack fault and segment fault handlers.
// - Add DR macro/save and VM macro/save.
// - Implement KiCallbackReturn, KiGetTickCount, KiRaiseAssertion.
//
// - FIXES:
// * Get rid of KiRosPrintAddress and use KiDumpParameterImages instead.
// * Sanitize some context fields during conversions.
// * Implement stack fault and segment fault handlers.
// * Add DR macro/save and VM macro/save.
// * Make boot process more NT-like.
// - FEATURES:
// * Use Queued Spinlocks for scheduling and dispatching.
// * New optimized table-based tick-hashed timer implementation.
// * New Thread Scheduler based on XP.
// * Implement KiCallbackReturn, KiGetTickCount, KiRaiseAssertion.
//
// Ex:
// - Use pushlocks for handle implementation.

View file

@ -26,21 +26,6 @@
#define X86_CR4_OSFXSR 0x00000200 /* enable FXSAVE/FXRSTOR instructions */
#define X86_CR4_OSXMMEXCPT 0x00000400 /* enable #XF exception */
#define X86_FEATURE_VME 0x00000002 /* Virtual 8086 Extensions are present */
#define X86_FEATURE_TSC 0x00000010 /* time stamp counters are present */
#define X86_FEATURE_PAE 0x00000040 /* physical address extension is present */
#define X86_FEATURE_CX8 0x00000100 /* CMPXCHG8B instruction present */
#define X86_FEATURE_SYSCALL 0x00000800 /* SYSCALL/SYSRET support present */
#define X86_FEATURE_PGE 0x00002000 /* Page Global Enable */
#define X86_FEATURE_MMX 0x00800000 /* MMX extension present */
#define X86_FEATURE_FXSR 0x01000000 /* FXSAVE/FXRSTOR instructions present */
#define X86_FEATURE_SSE 0x02000000 /* SSE extension present */
#define X86_FEATURE_SSE2 0x04000000 /* SSE2 extension present */
#define X86_FEATURE_HT 0x10000000 /* Hyper-Threading present */
#define X86_EXT_FEATURE_SSE3 0x00000001 /* SSE3 extension present */
#define X86_EXT_FEATURE_3DNOW 0x40000000 /* 3DNOW! extension present */
#define DR7_ACTIVE 0x00000055 /* If any of these bits are set, a Dr is active */
#define FRAME_EDITED 0xFFF8
@ -64,6 +49,29 @@ VOID
Ki386InitializeLdt(VOID);
VOID
Ki386SetProcessorFeatures(VOID);
VOID
NTAPI
KiSetCR0Bits(VOID);
VOID
NTAPI
KiGetCacheInformation(VOID);
BOOLEAN
NTAPI
KiIsNpxPresent(
VOID
);
VOID
NTAPI
KiSetProcessorType(VOID);
ULONG
NTAPI
KiGetFeatureBits(VOID);
ULONG KeAllocateGdtSelector(ULONG Desc[2]);
VOID KeFreeGdtSelector(ULONG Entry);
VOID

View file

@ -70,6 +70,12 @@ extern ULONG_PTR KERNEL_BASE;
extern ULONG KeI386NpxPresent;
extern ULONG KeI386XMMIPresent;
extern ULONG KeI386FxsrPresent;
extern ULONG KeI386CpuType;
extern ULONG KeI386CpuStep;
extern ULONG KeProcessorArchitecture;
extern ULONG KeProcessorLevel;
extern ULONG KeProcessorRevision;
extern ULONG KeFeatureBits;
extern PKNODE KeNodeBlock[1];
extern UCHAR KeNumberNodes;
extern UCHAR KeProcessNodeSeed;
@ -84,6 +90,10 @@ extern ULONG KeI386EFlagsOrMaskV86;
extern BOOLEAN KeI386VirtualIntExtensions;
extern KIDTENTRY KiIdt[];
extern FAST_MUTEX KernelAddressSpaceLock;
extern ULONG KiMaximumDpcQueueDepth;
extern ULONG KiMinimumDpcRate;
extern ULONG KiAdjustDpcThreshold;
extern ULONG KiIdealDpcRate;
/* MACROS *************************************************************************/
@ -583,10 +593,6 @@ VOID
NTAPI
KeInitTimer(VOID);
VOID
NTAPI
KeInitDpc(struct _KPRCB* Prcb);
VOID
NTAPI
KeInitDispatcher(VOID);
@ -606,8 +612,7 @@ Phase1Initialization(PVOID Context);
VOID
NTAPI
KeInit1(
PCHAR CommandLine,
PULONG LastKernelAddress
VOID
);
VOID
@ -689,7 +694,7 @@ KeBugCheckWithTf(
);
VOID
STDCALL
NTAPI
KeFlushCurrentTb(VOID);
VOID

View file

@ -12,10 +12,20 @@ PoInit(
NTSTATUS
NTAPI
PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState);
PopSetSystemPowerState(
SYSTEM_POWER_STATE PowerState
);
VOID
NTAPI
PopCleanupPowerState(IN PPOWER_STATE PowerState);
PopCleanupPowerState(
IN PPOWER_STATE PowerState
);
VOID
NTAPI
PoInitializePrcb(
IN PKPRCB Prcb
);
#endif /* __NTOSKRNL_INCLUDE_INTERNAL_PO_H */

View file

@ -36,28 +36,6 @@ ULONG KiIdealDpcRate = 20;
/* FUNCTIONS ****************************************************************/
/*
* FUNCTION: Initialize DPC handling
*/
VOID
INIT_FUNCTION
NTAPI
KeInitDpc(PKPRCB Prcb)
{
InitializeListHead(&Prcb->DpcData[0].DpcListHead);
#if 0
/*
* FIXME:
* Prcb->DpcEvent is a NULL pointer.
*/
KeInitializeEvent(Prcb->DpcEvent, 0, 0);
#endif
KeInitializeSpinLock(&Prcb->DpcData[0].DpcLock);
Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
Prcb->MinimumDpcRate = KiMinimumDpcRate;
Prcb->DpcData[0].DpcQueueDepth = 0;
}
/*
* @implemented
*/

View file

@ -1,39 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Kernel
* FILE: ntoskrnl/ke/i386/cpu.S
* PURPOSE: Handles CPU-centric operations: TLB Flushes, Breakpoints, FPU
* PROGRAMMERS: Alex Ionescu
*/
/* INCLUDES ******************************************************************/
#include <asm.h>
.intel_syntax noprefix
/* FUNCTIONS ****************************************************************/
.globl _KeFlushCurrentTb@0
.func KeFlushCurrentTb@0
_KeFlushCurrentTb@0:
/* Check for global page support */
test byte ptr [_Ke386GlobalPagesEnabled], 0xff
jz .L1
/* Modifying the PSE, PGE or PAE Flag in CR4 causes the TLB to be flushed */
mov eax, cr4
and eax, ~CR4_PGE
mov cr4, eax
or eax, CR4_PGE
mov cr4, eax
ret
.L1:
/* the old way ... */
mov eax, cr3
mov cr3, eax
ret
.endfunc

View file

@ -0,0 +1,561 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ke/i386/cpu.c
* PURPOSE: Routines for CPU-level support
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* FIXME: Local EFLAGS defines not used anywhere else */
#define EFLAGS_IOPL 0x3000
#define EFLAGS_NF 0x4000
#define EFLAGS_RF 0x10000
#define EFLAGS_ID 0x200000
/* GLOBALS *******************************************************************/
ULONG KeI386CpuType;
ULONG KeI386CpuStep;
ULONG KeProcessorArchitecture;
ULONG KeProcessorLevel;
ULONG KeProcessorRevision;
ULONG KeFeatureBits;
ULONG KiFastSystemCallDisable = 1;
ULONG KeI386NpxPresent = 0;
ULONG MxcsrFeatureMask = 0;
ULONG KeI386XMMIPresent = 0;
ULONG KeI386FxsrPresent = 0;
ULONG Ke386Pae = FALSE;
ULONG Ke386GlobalPagesEnabled = FALSE;
ULONG Ke386NoExecute = FALSE;
BOOLEAN KiI386PentiumLockErrataPresent;
CHAR CmpIntelID[] = "GenuineIntel";
CHAR CmpAmdID[] = "AuthenticAMD";
CHAR CmpCyrixID[] = "CyrixInstead";
CHAR CmpTransmetaID[] = "GenuineTMx86";
CHAR CmpCentaurID[] = "CentaurHauls";
CHAR CmpRiseID[] = "RiseRiseRise";
/* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/
VOID
NTAPI
CPUID(IN ULONG CpuInfo[4],
IN ULONG InfoType)
{
Ki386Cpuid(InfoType, &CpuInfo[0], &CpuInfo[1], &CpuInfo[2], &CpuInfo[3]);
}
VOID
WRMSR(IN ULONG Register,
IN LONGLONG Value)
{
LARGE_INTEGER LargeVal;
LargeVal.QuadPart = Value;
Ke386Wrmsr(Register, LargeVal.HighPart, LargeVal.LowPart);
}
LONGLONG
RDMSR(IN ULONG Register)
{
LARGE_INTEGER LargeVal;
Ke386Rdmsr(Register, LargeVal.HighPart, LargeVal.LowPart);
return LargeVal.QuadPart;
}
/* FUNCTIONS *****************************************************************/
VOID
NTAPI
KiSetProcessorType(VOID)
{
ULONG EFlags, NewEFlags;
ULONG Reg[4];
ULONG Stepping, Type;
/* Start by assuming no CPUID data */
KeGetCurrentPrcb()->CpuID = 0;
/* Save EFlags */
Ke386SaveFlags(EFlags);
/* XOR out the ID bit and update EFlags */
NewEFlags = EFlags ^ EFLAGS_ID;
Ke386RestoreFlags(NewEFlags);
/* Get them back and see if they were modified */
Ke386SaveFlags(NewEFlags);
if (NewEFlags != EFlags)
{
/* The modification worked, so CPUID exists. Set the ID Bit again. */
EFlags |= EFLAGS_ID;
Ke386RestoreFlags(EFlags);
/* Peform CPUID 0 to see if CPUID 1 is supported */
CPUID(Reg, 0);
if (Reg[0] > 0)
{
/* Do CPUID 1 now */
CPUID(Reg, 1);
/*
* Get the Stepping and Type. The stepping contains both the
* Model and the Step, while the Type contains the returned Type.
* We ignore the family.
*
* For the stepping, we convert this: zzzzzzxy into this: x0y
*/
Stepping = Reg[0] & 0xF0;
Stepping <<= 4;
Stepping += (Reg[0] & 0xFF);
Stepping &= 0xF0F;
Type = Reg[0] & 0xF00;
Type >>= 8;
/* Save them in the PRCB */
KeGetCurrentPrcb()->CpuID = TRUE;
KeGetCurrentPrcb()->CpuType = (UCHAR)Type;
KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping;
}
else
{
DPRINT1("CPUID Support lacking\n");
}
}
else
{
DPRINT1("CPUID Support lacking\n");
}
/* Restore EFLAGS */
Ke386RestoreFlags(EFlags);
}
ULONG
NTAPI
KiGetCpuVendor(VOID)
{
PKPRCB Prcb = KeGetCurrentPrcb();
ULONG Vendor[5];
/* Assume no Vendor ID and fail if no CPUID Support. */
Prcb->VendorString[0] = 0;
if (!Prcb->CpuID) return 0;
/* Get the Vendor ID and null-terminate it */
CPUID(Vendor, 0);
Vendor[4] = 0;
/* Re-arrange vendor string */
Vendor[5] = Vendor[2];
Vendor[2] = Vendor[3];
Vendor[3] = Vendor[5];
/* Copy it to the PRCB and null-terminate it again */
RtlCopyMemory(Prcb->VendorString,
&Vendor[1],
sizeof(Prcb->VendorString) - sizeof(CHAR));
Prcb->VendorString[sizeof(Prcb->VendorString) - sizeof(CHAR)] = ANSI_NULL;
/* Now check the CPU Type */
if (!strcmp(Prcb->VendorString, CmpIntelID))
{
return CPU_INTEL;
}
else if (!strcmp(Prcb->VendorString, CmpAmdID))
{
return CPU_AMD;
}
else if (!strcmp(Prcb->VendorString, CmpCyrixID))
{
DPRINT1("Cyrix CPUs not fully supported\n");
return 0;
}
else if (!strcmp(Prcb->VendorString, CmpTransmetaID))
{
DPRINT1("Transmeta CPUs not fully supported\n");
return 0;
}
else if (!strcmp(Prcb->VendorString, CmpCentaurID))
{
DPRINT1("VIA CPUs not fully supported\n");
return 0;
}
else if (!strcmp(Prcb->VendorString, CmpRiseID))
{
DPRINT1("Rise CPUs not fully supported\n");
return 0;
}
/* Invalid CPU */
return 0;
}
ULONG
NTAPI
KiGetFeatureBits(VOID)
{
PKPRCB Prcb = KeGetCurrentPrcb();
ULONG Vendor;
ULONG FeatureBits = KF_WORKING_PTE;
ULONG Reg[4];
BOOLEAN ExtendedCPUID = TRUE;
ULONG CpuFeatures = 0;
/* Get the Vendor ID */
Vendor = KiGetCpuVendor();
/* Make sure we got a valid vendor ID at least. */
if (!Vendor) return FeatureBits;
/* Get the CPUID Info. Features are in Reg[3]. */
CPUID(Reg, 1);
/* Check for AMD CPU */
if (Vendor == CPU_AMD)
{
/* Check if this is a K5 or higher. */
if ((Reg[0] & 0x0F00) >= 0x0500)
{
/* Check if this is a K5 specifically. */
if ((Reg[0] & 0x0F00) == 0x0500)
{
/* Get the Model Number */
switch (Reg[0] & 0x00F0)
{
/* Check if this is the Model 1 */
case 0x0010:
/* Check if this is Step 0 or 1. They don't support PGE */
if ((Reg[0] & 0x000F) > 0x03) break;
case 0x0000:
/* Model 0 doesn't support PGE at all. */
Reg[3] &= ~0x2000;
break;
case 0x0080:
/* K6-2, Step 8 and over have support for MTRR. */
if ((Reg[0] & 0x000F) >= 0x8) FeatureBits |= KF_AMDK6MTRR;
break;
case 0x0090:
/* As does the K6-3 */
FeatureBits |= KF_AMDK6MTRR;
break;
default:
break;
}
}
}
else
{
/* Familes below 5 don't support PGE, PSE or CMOV at all */
Reg[3] &= ~(0x08 | 0x2000 | 0x8000);
/* They also don't support advanced CPUID functions. */
ExtendedCPUID = FALSE;
}
/* Set the current features */
CpuFeatures = Reg[3];
}
/* Now check if this is Intel */
if (Vendor == CPU_INTEL)
{
/* Check if it's a P6 */
if (Prcb->CpuType == 6)
{
/* Perform the special sequence to get the MicroCode Signature */
WRMSR(0x8B, 0);
CPUID(Reg, 1);
Prcb->UpdateSignature.QuadPart = RDMSR(0x8B);
}
else if (Prcb->CpuType == 5)
{
/* On P5, enable workaround for the LOCK errata. */
KiI386PentiumLockErrataPresent = TRUE;
}
/* Check for broken P6 with bad SMP PTE implementation */
if (((Reg[0] & 0x0FF0) == 0x0610 && (Reg[0] & 0x000F) <= 0x9) ||
((Reg[0] & 0x0FF0) == 0x0630 && (Reg[0] & 0x000F) <= 0x4))
{
/* Remove support for correct PTE support. */
FeatureBits &= ~KF_WORKING_PTE;
}
/* Set the current features */
CpuFeatures = Reg[3];
}
/* Convert all CPUID Feature bits into our format */
if (CpuFeatures & 0x00000002) FeatureBits |= KF_V86_VIS | KF_CR4;
if (CpuFeatures & 0x00000008) FeatureBits |= KF_LARGE_PAGE | KF_CR4;
if (CpuFeatures & 0x00000010) FeatureBits |= KF_RDTSC;
if (CpuFeatures & 0x00000100) FeatureBits |= KF_CMPXCHG8B;
if (CpuFeatures & 0x00000800) FeatureBits |= KF_FAST_SYSCALL;
if (CpuFeatures & 0x00001000) FeatureBits |= KF_MTRR;
if (CpuFeatures & 0x00002000) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4;
if (CpuFeatures & 0x00008000) FeatureBits |= KF_CMOV;
if (CpuFeatures & 0x00010000) FeatureBits |= KF_PAT;
if (CpuFeatures & 0x00800000) FeatureBits |= KF_MMX;
if (CpuFeatures & 0x01000000) FeatureBits |= KF_FXSR;
if (CpuFeatures & 0x02000000) FeatureBits |= KF_XMMI;
/* Check if CPUID 0x80000000 is supported */
if (ExtendedCPUID)
{
/* Do the call */
CPUID(Reg, 0x80000000);
if ((Reg[0] & 0xffffff00) == 0x80000000)
{
/* Check if CPUID 0x80000001 is supported */
if (Reg[0] >= 0x80000001)
{
/* Check which extended features are available. */
CPUID(Reg, 0x80000001);
/* Now handle each features for each CPU Vendor */
switch (Vendor)
{
case CPU_AMD:
if (Reg[3] & 0x80000000) FeatureBits |= KF_3DNOW;
break;
}
}
}
}
/* Return the Feature Bits */
return FeatureBits;
}
VOID
NTAPI
KiGetCacheInformation(VOID)
{
PKIPCR Pcr = (PKIPCR)KeGetPcr();
ULONG Vendor;
ULONG Data[4];
ULONG CacheRequests = 0, i;
ULONG CurrentRegister;
UCHAR RegisterByte;
BOOLEAN FirstPass = TRUE;
/* Set default L2 size */
Pcr->SecondLevelCacheSize = 0;
/* Get the Vendor ID and make sure we support CPUID */
Vendor = KiGetCpuVendor();
if (!Vendor) return;
/* Check the Vendor ID */
switch (Vendor)
{
/* Handle Intel case */
case CPU_INTEL:
/*Check if we support CPUID 2 */
CPUID(Data, 0);
if (Data[0] >= 2)
{
/* We need to loop for the number of times CPUID will tell us to */
do
{
/* Do the CPUID call */
CPUID(Data, 2);
/* Check if it was the first call */
if (FirstPass)
{
/*
* The number of times to loop is the first byte. Read
* it and then destroy it so we don't get confused.
*/
CacheRequests = Data[0] & 0xFF;
Data[0] &= 0xFFFFFF00;
/* Don't go over this again */
FirstPass = FALSE;
}
/* Loop all 4 registers */
for (i = 0; i < 4; i++)
{
/* Get the current register */
CurrentRegister = Data[i];
/*
* If the upper bit is set, then this register should
* be skipped.
*/
if (CurrentRegister & 0x80000000) continue;
/* Keep looping for every byte inside this register */
while (CurrentRegister)
{
/* Read a byte, skip a byte. */
RegisterByte = (UCHAR)(CurrentRegister & 0xFF);
CurrentRegister >>= 8;
if (!RegisterByte) continue;
/*
* Valid values are from 0x40 (0 bytes) to 0x49
* (32MB), or from 0x80 to 0x89 (same size but
* 8-way associative.
*/
if (((RegisterByte > 0x40) &&
(RegisterByte <= 0x49)) ||
((RegisterByte > 0x80) &&
(RegisterByte <= 0x89)))
{
/* Mask out only the first nibble */
RegisterByte &= 0x0F;
/* Set the L2 Cache Size */
Pcr->SecondLevelCacheSize = 0x10000 <<
RegisterByte;
}
}
}
} while (--CacheRequests);
}
break;
case CPU_AMD:
/* FIXME */
DPRINT1("Not handling AMD caches yet\n");
break;
}
}
VOID
NTAPI
KiSetCR0Bits(VOID)
{
ULONG Cr0;
/* Save current CR0 */
Cr0 = Ke386GetCr0();
/* If this is a 486, enable Write-Protection */
if (KeGetCurrentPrcb()->CpuType > 3) Cr0 |= CR0_WP;
/* Set new Cr0 */
Ke386SetCr0(Cr0);
}
VOID INIT_FUNCTION
Ki386SetProcessorFeatures(VOID)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName =
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Kernel");
UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"FastSystemCallDisable");
HANDLE KeyHandle;
ULONG ResultLength;
struct
{
KEY_VALUE_PARTIAL_INFORMATION Info;
UCHAR Buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
Data[0]) + sizeof(ULONG)];
} ValueData;
NTSTATUS Status;
ULONG FastSystemCallDisable = 0;
SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = FALSE;
SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] = FALSE;
SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] =
(KeFeatureBits & KF_CMPXCHG8B) ? TRUE : FALSE;
SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
(KeFeatureBits & KF_MMX) ? TRUE : FALSE;
SharedUserData->ProcessorFeatures[PF_PPC_MOVEMEM_64BIT_OK] = FALSE;
SharedUserData->ProcessorFeatures[PF_ALPHA_BYTE_INSTRUCTIONS] = FALSE;
SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
(KeFeatureBits & KF_XMMI) ? TRUE : FALSE;
SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] =
(KeFeatureBits & KF_RDTSC) ? TRUE : FALSE;
/* Does the CPU Support Fast System Call? */
if (KeFeatureBits & KF_FAST_SYSCALL) {
/* FIXME: Check for Family == 6, Model < 3 and Stepping < 3 and disable */
/* Make sure it's not disabled in registry */
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&KeyHandle,
KEY_QUERY_VALUE,
&ObjectAttributes);
if (NT_SUCCESS(Status)) {
/* Read the Value then Close the Key */
Status = ZwQueryValueKey(KeyHandle,
&ValueName,
KeyValuePartialInformation,
&ValueData,
sizeof(ValueData),
&ResultLength);
if (NT_SUCCESS(Status))
{
if (ResultLength == sizeof(ValueData) &&
ValueData.Info.Type == REG_DWORD)
{
FastSystemCallDisable = *(PULONG)ValueData.Info.Data != 0;
}
ZwClose(KeyHandle);
}
}
} else {
/* Disable SYSENTER/SYSEXIT, because the CPU doesn't support it */
FastSystemCallDisable = 1;
}
if (FastSystemCallDisable) {
/* Use INT2E */
const unsigned char Entry[7] = {0x8D, 0x54, 0x24, 0x08, /* lea 0x8(%esp),%edx */
0xCD, 0x2E, /* int 0x2e */
0xC3}; /* ret */
memcpy(&SharedUserData->SystemCall, Entry, sizeof(Entry));
} else {
/* Use SYSENTER */
const unsigned char Entry[5] = {0x8B, 0xD4, /* movl %esp,%edx */
0x0F, 0x34, /* sysenter */
0xC3}; /* ret */
memcpy(&SharedUserData->SystemCall, Entry, sizeof(Entry));
/* Enable SYSENTER/SYSEXIT */
KiFastSystemCallDisable = 0;
}
}
VOID
NTAPI
KeFlushCurrentTb(VOID)
{
/* Flush the TLB by resetting CR3 */
_Ke386SetCr(3, _Ke386GetCr(3));
}

View file

@ -21,54 +21,214 @@ PKNODE KeNodeBlock[1];
UCHAR KeNumberNodes = 1;
UCHAR KeProcessNodeSeed;
ULONG KiPcrInitDone = 0;
static ULONG PcrsAllocated = 0;
static ULONG Ke386CpuidFlags2, Ke386CpuidExFlags, Ke386CpuidExMisc;
ULONG Ke386CacheAlignment;
CHAR Ke386CpuidModel[49] = {0,};
ULONG Ke386L1CacheSize;
BOOLEAN Ke386NoExecute = FALSE;
BOOLEAN Ke386Pae = FALSE;
BOOLEAN Ke386GlobalPagesEnabled = FALSE;
ULONG KiFastSystemCallDisable = 1;
ULONG KeI386NpxPresent = 0;
ULONG MxcsrFeatureMask = 0;
ULONG KeI386XMMIPresent = 0;
ULONG KeI386FxsrPresent = 0;
extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS];
extern ULONG IdleProcessorMask;
extern KIDTENTRY KiIdt[256];
static VOID INIT_FUNCTION Ki386GetCpuId(VOID);
extern ULONG Ke386GlobalPagesEnabled;
/* System-defined Spinlocks */
KSPIN_LOCK KiDispatcherLock;
KSPIN_LOCK MmPfnLock;
KSPIN_LOCK MmSystemSpaceLock;
KSPIN_LOCK CcBcbSpinLock;
KSPIN_LOCK CcMasterSpinLock;
KSPIN_LOCK CcVacbSpinLock;
KSPIN_LOCK CcWorkQueueSpinLock;
KSPIN_LOCK NonPagedPoolLock;
KSPIN_LOCK MmNonPagedPoolLock;
KSPIN_LOCK IopCancelSpinLock;
KSPIN_LOCK IopVpbSpinLock;
KSPIN_LOCK IopDatabaseLock;
KSPIN_LOCK IopCompletionLock;
KSPIN_LOCK NtfsStructLock;
KSPIN_LOCK AfdWorkQueueSpinLock;
KSPIN_LOCK KiTimerTableLock[16];
KSPIN_LOCK KiReverseStallIpiLock;
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, Ki386GetCpuId)
#pragma alloc_text(INIT, KeInit1)
#pragma alloc_text(INIT, KeInit2)
#pragma alloc_text(INIT, Ki386SetProcessorFeatures)
#endif
BOOLEAN
NTAPI
KiIsNpxPresent(
VOID
);
/* FUNCTIONS *****************************************************************/
VOID
INIT_FUNCTION
NTAPI
KiCheckFPU(VOID)
KiInitSpinLocks(IN PKPRCB Prcb,
IN CCHAR Number)
{
PKPRCB Prcb = KeGetCurrentPrcb();
ULONG i;
/* Check for a math co-processor (NPX) */
KeI386NpxPresent = KiIsNpxPresent();
/* Initialize Dispatcher Fields */
Prcb->QueueIndex = 1;
Prcb->ReadySummary = 0;
Prcb->DeferredReadyListHead.Next = NULL;
for (i = 0; i < 32; i++)
{
/* Initialize the ready list */
InitializeListHead(&Prcb->DispatcherReadyListHead[i]);
}
/* Check for and enable MMX/SSE support if possible */
KeI386FxsrPresent = Prcb->FeatureBits & X86_FEATURE_FXSR ? TRUE : FALSE;
/* Initialize DPC Fields */
InitializeListHead(&Prcb->DpcData[0].DpcListHead);
KeInitializeSpinLock(&Prcb->DpcData[0].DpcLock);
Prcb->DpcData[0].DpcQueueDepth = 0;
Prcb->DpcData[0].DpcCount = 0;
Prcb->DpcRoutineActive = FALSE;
Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
Prcb->MinimumDpcRate = KiMinimumDpcRate;
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
KeInitializeDpc(&Prcb->CallDpc, NULL, NULL);
//KeSetTargetProcessorDpc(&Prcb->CallDpc, Number);
KeSetImportanceDpc(&Prcb->CallDpc, HighImportance);
/* Check for SSE (2 and 3 should have this set too) */
KeI386XMMIPresent = Prcb->FeatureBits & X86_FEATURE_SSE ? TRUE : FALSE;
/* Initialize the Wait List Head */
InitializeListHead(&Prcb->WaitListHead);
/* Initialize Queued Spinlocks */
Prcb->LockQueue[LockQueueDispatcherLock].Next = NULL;
Prcb->LockQueue[LockQueueDispatcherLock].Lock = &KiDispatcherLock;
Prcb->LockQueue[LockQueueExpansionLock].Next = NULL;
Prcb->LockQueue[LockQueueExpansionLock].Lock = NULL;
Prcb->LockQueue[LockQueuePfnLock].Next = NULL;
Prcb->LockQueue[LockQueuePfnLock].Lock = &MmPfnLock;
Prcb->LockQueue[LockQueueSystemSpaceLock].Next = NULL;
Prcb->LockQueue[LockQueueSystemSpaceLock].Lock = &MmSystemSpaceLock;
Prcb->LockQueue[LockQueueBcbLock].Next = NULL;
Prcb->LockQueue[LockQueueBcbLock].Lock = &CcBcbSpinLock;
Prcb->LockQueue[LockQueueMasterLock].Next = NULL;
Prcb->LockQueue[LockQueueMasterLock].Lock = &CcMasterSpinLock;
Prcb->LockQueue[LockQueueVacbLock].Next = NULL;
Prcb->LockQueue[LockQueueVacbLock].Lock = &CcVacbSpinLock;
Prcb->LockQueue[LockQueueWorkQueueLock].Next = NULL;
Prcb->LockQueue[LockQueueWorkQueueLock].Lock = &CcWorkQueueSpinLock;
Prcb->LockQueue[LockQueueNonPagedPoolLock].Next = NULL;
Prcb->LockQueue[LockQueueNonPagedPoolLock].Lock = &NonPagedPoolLock;
Prcb->LockQueue[LockQueueMmNonPagedPoolLock].Next = NULL;
Prcb->LockQueue[LockQueueMmNonPagedPoolLock].Lock = &MmNonPagedPoolLock;
Prcb->LockQueue[LockQueueIoCancelLock].Next = NULL;
Prcb->LockQueue[LockQueueIoCancelLock].Lock = &IopCancelSpinLock;
Prcb->LockQueue[LockQueueIoVpbLock].Next = NULL;
Prcb->LockQueue[LockQueueIoVpbLock].Lock = &IopVpbSpinLock;
Prcb->LockQueue[LockQueueIoDatabaseLock].Next = NULL;
Prcb->LockQueue[LockQueueIoDatabaseLock].Lock = &IopDatabaseLock;
Prcb->LockQueue[LockQueueIoCompletionLock].Next = NULL;
Prcb->LockQueue[LockQueueIoCompletionLock].Lock = &IopCompletionLock;
Prcb->LockQueue[LockQueueNtfsStructLock].Next = NULL;
Prcb->LockQueue[LockQueueNtfsStructLock].Lock = &NtfsStructLock;
Prcb->LockQueue[LockQueueAfdWorkQueueLock].Next = NULL;
Prcb->LockQueue[LockQueueAfdWorkQueueLock].Lock = &AfdWorkQueueSpinLock;
Prcb->LockQueue[LockQueueUnusedSpare16].Next = NULL;
Prcb->LockQueue[LockQueueUnusedSpare16].Lock = NULL;
for (i = LockQueueTimerTableLock; i < LockQueueMaximumLock; i++)
{
KeInitializeSpinLock(&KiTimerTableLock[i - 16]);
Prcb->LockQueue[i].Next = NULL;
Prcb->LockQueue[i].Lock = &KiTimerTableLock[i - 16];
}
/* Check if this is the boot CPU */
if (!Number)
{
/* Initialize the lock themselves */
KeInitializeSpinLock(&KiDispatcherLock);
KeInitializeSpinLock(&KiReverseStallIpiLock);
KeInitializeSpinLock(&MmPfnLock);
KeInitializeSpinLock(&MmSystemSpaceLock);
KeInitializeSpinLock(&CcBcbSpinLock);
KeInitializeSpinLock(&CcMasterSpinLock);
KeInitializeSpinLock(&CcVacbSpinLock);
KeInitializeSpinLock(&CcWorkQueueSpinLock);
KeInitializeSpinLock(&IopCancelSpinLock);
KeInitializeSpinLock(&IopCompletionLock);
KeInitializeSpinLock(&IopDatabaseLock);
KeInitializeSpinLock(&IopVpbSpinLock);
KeInitializeSpinLock(&NonPagedPoolLock);
KeInitializeSpinLock(&MmNonPagedPoolLock);
KeInitializeSpinLock(&NtfsStructLock);
KeInitializeSpinLock(&AfdWorkQueueSpinLock);
}
}
VOID
NTAPI
KeInit1(VOID)
{
PKIPCR KPCR;
PKPRCB Prcb;
BOOLEAN NpxPresent;
ULONG FeatureBits;
extern USHORT KiBootGdt[];
extern KTSS KiBootTss;
/* Initialize the PCR */
KPCR = (PKIPCR)KPCR_BASE;
Prcb = &KPCR->PrcbData;
memset(KPCR, 0, PAGE_SIZE);
KPCR->Self = (PKPCR)KPCR;
KPCR->Prcb = &KPCR->PrcbData;
KPCR->Irql = SYNCH_LEVEL;
KPCR->NtTib.Self = &KPCR->NtTib;
KPCR->NtTib.ExceptionList = (PVOID)-1;
KPCR->GDT = KiBootGdt;
KPCR->IDT = KiIdt;
KPCR->TSS = &KiBootTss;
KPCR->Number = 0;
KPCR->SetMember = 1 << 0;
KeActiveProcessors = 1 << 0;
KPCR->PrcbData.SetMember = 1 << 0;
KiPcrInitDone = 1;
/*
* Low-level GDT, TSS and LDT Setup, most of which Freeldr should have done
* instead, and we should only add some extra information. This would be
* required for future NTLDR compatibility.
*/
KiInitializeGdt(NULL);
Ki386BootInitializeTSS();
Ki386InitializeLdt();
KeInitExceptions();
KeInitInterrupts();
/* Detect and set the CPU Type */
KiSetProcessorType();
/* Set CR0 features based on detected CPU */
KiSetCR0Bits();
/* 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(0x5D, 0x386, 0, 0, 0);
/* Get the processor features for the CPU */
FeatureBits = KiGetFeatureBits();
/* Save feature bits */
Prcb->FeatureBits = FeatureBits;
/* Get cache line information for this CPU */
KiGetCacheInformation();
/* Initialize spinlocks and DPC data */
KiInitSpinLocks(Prcb, 0);
/* 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 = 0;
KeProcessorLevel = (USHORT)Prcb->CpuType;
if (Prcb->CpuID) KeProcessorRevision = Prcb->CpuStep;
KeFeatureBits = FeatureBits;
KeI386FxsrPresent = (KeFeatureBits & KF_FXSR) ? TRUE : FALSE;
KeI386XMMIPresent = (KeFeatureBits & KF_XMMI) ? TRUE : FALSE;
/* Check if Fxsr was found */
if (KeI386FxsrPresent)
@ -85,167 +245,8 @@ KiCheckFPU(VOID)
/* FIXME: Implement and enable XMM Page Zeroing for Mm */
}
}
}
static VOID INIT_FUNCTION
Ki386GetCpuId(VOID)
{
ULONG OrigFlags, Flags, FinalFlags;
ULONG MaxCpuidLevel;
ULONG Dummy, Eax, Ecx, Edx;
PKIPCR Pcr = (PKIPCR)KeGetCurrentKPCR();
Ke386CpuidFlags2 = Ke386CpuidExFlags = 0;
Ke386CacheAlignment = 32;
/* Try to toggle the id bit in eflags. */
Ke386SaveFlags(OrigFlags);
Flags = OrigFlags ^ X86_EFLAGS_ID;
Ke386RestoreFlags(Flags);
Ke386SaveFlags(FinalFlags);
Pcr->PrcbData.LogicalProcessorsPerPhysicalProcessor = 1;
Pcr->PrcbData.InitialApicId = 0xff;
if ((OrigFlags & X86_EFLAGS_ID) == (FinalFlags & X86_EFLAGS_ID))
{
/* No cpuid supported. */
Pcr->PrcbData.CpuID = FALSE;
Pcr->PrcbData.CpuType = 3;
return;
}
Pcr->PrcbData.CpuID = TRUE;
/* Get the vendor name and the maximum cpuid level supported. */
Ki386Cpuid(0, &MaxCpuidLevel, (PULONG)&Pcr->PrcbData.VendorString[0], (PULONG)&Pcr->PrcbData.VendorString[8], (PULONG)&Pcr->PrcbData.VendorString[4]);
if (MaxCpuidLevel > 0)
{
/* Get the feature flags. */
Ki386Cpuid(1, &Eax, &Ke386CpuidExMisc, &Ke386CpuidFlags2, &Pcr->PrcbData.FeatureBits);
DPRINT ("Model: %x\n", (Eax & 0xf00) == 0xf00 ? ((Eax >> 4) & 0xf) | ((Eax >> 12) & 0xf0) : (Eax >> 4) & 0xf);
DPRINT ("Family: %x\n", (Eax & 0xf00) == 0xf00 ? ((Eax >> 8) & 0xf) + ((Eax >> 20) & 0xff) : (Eax >> 8) & 0xf);
/* Get the cache alignment, if it is available */
if (Pcr->PrcbData.FeatureBits & (1<<19))
{
Ke386CacheAlignment = ((Ke386CpuidExMisc >> 8) & 0xff) * 8;
}
Pcr->PrcbData.CpuType = (Eax >> 8) & 0xf;
Pcr->PrcbData.CpuStep = (Eax & 0xf) | ((Eax << 4) & 0xf00);
Pcr->PrcbData.InitialApicId = (Ke386CpuidExMisc >> 24) & 0xff;
/* detect Hyper-Threading on Pentium 4 CPUs or later */
if ((Pcr->PrcbData.CpuType == 0xf || (Eax & 0x0f00000)) &&
!strncmp(Pcr->PrcbData.VendorString, "GenuineIntel", 12) &&
Pcr->PrcbData.FeatureBits & X86_FEATURE_HT)
{
Pcr->PrcbData.LogicalProcessorsPerPhysicalProcessor = (Ke386CpuidExMisc >> 16) & 0xff;
}
}
else
{
Pcr->PrcbData.CpuType = 4;
}
/* Get the maximum extended cpuid level supported. */
Ki386Cpuid(0x80000000, &MaxCpuidLevel, &Dummy, &Dummy, &Dummy);
if (MaxCpuidLevel > 0)
{
/* Get the extended feature flags. */
Ki386Cpuid(0x80000001, &Dummy, &Dummy, &Dummy, &Ke386CpuidExFlags);
}
/* Get the model name. */
if (MaxCpuidLevel >= 0x80000004)
{
PULONG v = (PULONG)Ke386CpuidModel;
Ki386Cpuid(0x80000002, v, v + 1, v + 2, v + 3);
Ki386Cpuid(0x80000003, v + 4, v + 5, v + 6, v + 7);
Ki386Cpuid(0x80000004, v + 8, v + 9, v + 10, v + 11);
}
/* Get the L1 cache size */
if (MaxCpuidLevel >= 0x80000005)
{
Ki386Cpuid(0x80000005, &Dummy, &Dummy, &Ecx, &Edx);
Ke386L1CacheSize = (Ecx >> 24)+(Edx >> 24);
if ((Ecx & 0xff) > 0)
{
Ke386CacheAlignment = Ecx & 0xff;
}
}
/* Get the L2 cache size */
if (MaxCpuidLevel >= 0x80000006)
{
Ki386Cpuid(0x80000006, &Dummy, &Dummy, &Ecx, &Dummy);
Pcr->SecondLevelCacheSize = Ecx >> 16;
}
}
VOID
INIT_FUNCTION
NTAPI
KeInit1(PCHAR CommandLine, PULONG LastKernelAddress)
{
PKIPCR KPCR;
BOOLEAN Pae = FALSE;
BOOLEAN NoExecute = FALSE;
PCHAR p1, p2;
extern USHORT KiBootGdt[];
extern KTSS KiBootTss;
/*
* Initialize the initial PCR region. We can't allocate a page
* with MmAllocPage() here because MmInit1() has not yet been
* called, so we use a predefined page in low memory
*/
KPCR = (PKIPCR)KPCR_BASE;
memset(KPCR, 0, PAGE_SIZE);
KPCR->Self = (PKPCR)KPCR;
KPCR->Prcb = &KPCR->PrcbData;
KPCR->Irql = SYNCH_LEVEL;
KPCR->NtTib.Self = &KPCR->NtTib;
KPCR->GDT = KiBootGdt;
KPCR->IDT = KiIdt;
KPCR->TSS = &KiBootTss;
KPCR->Number = 0;
KPCR->SetMember = 1 << 0;
KeActiveProcessors = 1 << 0;
KPCR->PrcbData.SetMember = 1 << 0;
KiPcrInitDone = 1;
PcrsAllocated++;
KiInitializeGdt (NULL);
Ki386BootInitializeTSS();
Ki386InitializeLdt();
/* Get processor information. */
Ki386GetCpuId();
/* Check FPU/MMX/SSE support. */
KiCheckFPU();
/* Mark the end of the exception handler list */
KPCR->NtTib.ExceptionList = (PVOID)-1;
KeInitDpc(KPCR->Prcb);
InitializeListHead(&KPCR->PrcbData.WaitListHead);
KeInitExceptions ();
KeInitInterrupts ();
KeActiveProcessors |= 1 << 0;
/* Set Node Data */
KeNodeBlock[0] = &KiNode0;
KPCR->PrcbData.ParentNode = KeNodeBlock[0];
KeNodeBlock[0]->ProcessorMask = KPCR->PrcbData.SetMember;
if (KPCR->PrcbData.FeatureBits & X86_FEATURE_PGE)
if (KeFeatureBits & KF_GLOBAL_PAGE)
{
ULONG Flags;
/* Enable global pages */
@ -256,32 +257,7 @@ KeInit1(PCHAR CommandLine, PULONG LastKernelAddress)
Ke386RestoreFlags(Flags);
}
/* Search for pae and noexecute */
p1 = (PCHAR)KeLoaderBlock.CommandLine;
while(*p1 && (p2 = strchr(p1, '/')))
{
p2++;
if (!_strnicmp(p2, "PAE", 3))
{
if (p2[3] == ' ' || p2[3] == 0)
{
p2 += 3;
Pae = TRUE;
}
}
else if (!_strnicmp(p2, "NOEXECUTE", 9))
{
if (p2[9] == ' ' || p2[9] == '=' || p2[9] == 0)
{
p2 += 9;
NoExecute = TRUE;
}
}
p1 = p2;
}
Ke386Pae = Ke386GetCr4() & X86_CR4_PAE ? TRUE : FALSE;
if (KPCR->PrcbData.FeatureBits & X86_FEATURE_SYSCALL)
if (KeFeatureBits & KF_FAST_SYSCALL)
{
extern void KiFastCallEntry(void);
@ -294,7 +270,7 @@ KeInit1(PCHAR CommandLine, PULONG LastKernelAddress)
}
/* Does the CPU Support 'prefetchnta' (SSE) */
if(KPCR->PrcbData.FeatureBits & X86_FEATURE_SSE)
if(KeFeatureBits & KF_XMMI)
{
ULONG Protect;
@ -312,164 +288,40 @@ NTAPI
KeInit2(VOID)
{
ULONG Protect;
PKIPCR Pcr = (PKIPCR)KeGetCurrentKPCR();
PKIPCR Pcr = (PKIPCR)KeGetPcr();
PKPRCB Prcb = Pcr->Prcb;
KiInitializeBugCheck();
KeInitializeDispatcher();
KiInitializeSystemClock();
if (Pcr->PrcbData.FeatureBits & X86_FEATURE_PAE)
{
DPRINT("CPU supports PAE mode\n");
if (Ke386Pae)
{
DPRINT("CPU runs in PAE mode\n");
if (Ke386NoExecute)
{
DPRINT("NoExecute is enabled\n");
}
}
else
{
DPRINT("CPU doesn't run in PAE mode\n");
}
}
if ((Pcr->PrcbData.FeatureBits & (X86_FEATURE_FXSR | X86_FEATURE_MMX | X86_FEATURE_SSE | X86_FEATURE_SSE2)) ||
(Ke386CpuidFlags2 & X86_EXT_FEATURE_SSE3))
{
DPRINT("CPU supports" "%s%s%s%s%s" ".\n",
((Pcr->PrcbData.FeatureBits & X86_FEATURE_FXSR) ? " FXSR" : ""),
((Pcr->PrcbData.FeatureBits & X86_FEATURE_MMX) ? " MMX" : ""),
((Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE) ? " SSE" : ""),
((Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE2) ? " SSE2" : ""),
((Ke386CpuidFlags2 & X86_EXT_FEATURE_SSE3) ? " SSE3" : ""));
}
if (Ke386GetCr4() & X86_CR4_OSFXSR)
{
DPRINT("SSE enabled.\n");
}
if (Ke386GetCr4() & X86_CR4_OSXMMEXCPT)
{
DPRINT("Unmasked SIMD exceptions enabled.\n");
}
if (Pcr->PrcbData.VendorString[0])
{
DPRINT("CPU Vendor: %s\n", Pcr->PrcbData.VendorString);
}
if (Ke386CpuidModel[0])
{
DPRINT("CPU Model: %s\n", Ke386CpuidModel);
}
DPRINT("Ke386CacheAlignment: %d\n", Ke386CacheAlignment);
if (Ke386L1CacheSize)
{
DPRINT("Ke386L1CacheSize: %dkB\n", Ke386L1CacheSize);
}
if (Pcr->SecondLevelCacheSize)
{
DPRINT("Ke386L2CacheSize: %dkB\n", Pcr->SecondLevelCacheSize);
}
DPRINT1("CPU Detection Complete.\n"
"CPUID: %lx\n"
"Step : %lx\n"
"Type : %lx\n"
"ID : %s\n"
"FPU : %lx\n"
"XMMI : %lx\n"
"Fxsr : %lx\n"
"Feat : %lx\n"
"Ftrs : %lx\n"
"Cache: %lx\n"
"CR0 : %lx\n"
"CR4 : %lx\n",
Prcb->CpuID,
Prcb->CpuStep,
Prcb->CpuType,
Prcb->VendorString,
KeI386NpxPresent,
KeI386XMMIPresent,
KeI386FxsrPresent,
Prcb->FeatureBits,
KeFeatureBits,
Pcr->SecondLevelCacheSize,
Ke386GetCr0(),
Ke386GetCr4());
/* Set IDT to writable */
Protect = MmGetPageProtect(NULL, (PVOID)KiIdt);
MmSetPageProtect(NULL, (PVOID)KiIdt, Protect | PAGE_IS_WRITABLE);
}
VOID INIT_FUNCTION
Ki386SetProcessorFeatures(VOID)
{
PKIPCR Pcr = (PKIPCR)KeGetCurrentKPCR();
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName =
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Kernel");
UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"FastSystemCallDisable");
HANDLE KeyHandle;
ULONG ResultLength;
struct
{
KEY_VALUE_PARTIAL_INFORMATION Info;
UCHAR Buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
Data[0]) + sizeof(ULONG)];
} ValueData;
NTSTATUS Status;
ULONG FastSystemCallDisable = 0;
SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = FALSE;
SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] = FALSE;
SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] =
(Pcr->PrcbData.FeatureBits & X86_FEATURE_CX8) ? TRUE : FALSE;
SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
(Pcr->PrcbData.FeatureBits & X86_FEATURE_MMX) ? TRUE : FALSE;
SharedUserData->ProcessorFeatures[PF_PPC_MOVEMEM_64BIT_OK] = FALSE;
SharedUserData->ProcessorFeatures[PF_ALPHA_BYTE_INSTRUCTIONS] = FALSE;
SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
(Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE) ? TRUE : FALSE;
SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
(Ke386CpuidExFlags & X86_EXT_FEATURE_3DNOW) ? TRUE : FALSE;
SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] =
(Pcr->PrcbData.FeatureBits & X86_FEATURE_TSC) ? TRUE : FALSE;
SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = Ke386Pae;
SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
(Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE2) ? TRUE : FALSE;
/* Does the CPU Support Fast System Call? */
if (Pcr->PrcbData.FeatureBits & X86_FEATURE_SYSCALL) {
/* FIXME: Check for Family == 6, Model < 3 and Stepping < 3 and disable */
/* Make sure it's not disabled in registry */
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&KeyHandle,
KEY_QUERY_VALUE,
&ObjectAttributes);
if (NT_SUCCESS(Status)) {
/* Read the Value then Close the Key */
Status = ZwQueryValueKey(KeyHandle,
&ValueName,
KeyValuePartialInformation,
&ValueData,
sizeof(ValueData),
&ResultLength);
if (NT_SUCCESS(Status))
{
if (ResultLength == sizeof(ValueData) &&
ValueData.Info.Type == REG_DWORD)
{
FastSystemCallDisable = *(PULONG)ValueData.Info.Data != 0;
}
ZwClose(KeyHandle);
}
}
} else {
/* Disable SYSENTER/SYSEXIT, because the CPU doesn't support it */
FastSystemCallDisable = 1;
}
if (FastSystemCallDisable) {
/* Use INT2E */
const unsigned char Entry[7] = {0x8D, 0x54, 0x24, 0x08, /* lea 0x8(%esp),%edx */
0xCD, 0x2E, /* int 0x2e */
0xC3}; /* ret */
memcpy(&SharedUserData->SystemCall, Entry, sizeof(Entry));
} else {
/* Use SYSENTER */
const unsigned char Entry[5] = {0x8B, 0xD4, /* movl %esp,%edx */
0x0F, 0x34, /* sysenter */
0xC3}; /* ret */
memcpy(&SharedUserData->SystemCall, Entry, sizeof(Entry));
/* Enable SYSENTER/SYSEXIT */
KiFastSystemCallDisable = 0;
}
}

View file

@ -74,6 +74,4 @@ _NtProcessStartup:
/* Call the main kernel initialization */
pushl %edx
pushl %ecx
call __main
call _KiRosPrepareForSystemStartup@4

View file

@ -90,6 +90,12 @@ KiSystemStartup(BOOLEAN BootProcessor)
{
DPRINT("KiSystemStartup(%d)\n", BootProcessor);
/* Initialize the Debugger */
KdInitSystem (0, &KeLoaderBlock);
/* Initialize HAL */
HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
/* Initialize the Processor with HAL */
HalInitializeProcessor(KeNumberProcessors, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
@ -124,18 +130,9 @@ KiSystemStartup(BOOLEAN BootProcessor)
for(;;);
}
/*
* FUNCTION: Called by the boot loader to start the kernel
* ARGUMENTS:
* LoaderBlock = Pointer to boot parameters initialized by the boot
* loader
* NOTE: The boot parameters are stored in low memory which will become
* invalid after the memory managment is initialized so we make a local copy.
*/
VOID
INIT_FUNCTION
_main(ULONG MultiBootMagic,
PROS_LOADER_PARAMETER_BLOCK _LoaderBlock)
NTAPI
KiRosPrepareForSystemStartup(PROS_LOADER_PARAMETER_BLOCK LoaderBlock)
{
ULONG i;
ULONG size;
@ -147,18 +144,52 @@ _main(ULONG MultiBootMagic,
CHAR* s;
/* Copy the Loader Block Data locally since Low-Memory will be wiped */
memcpy(&KeLoaderBlock, _LoaderBlock, sizeof(ROS_LOADER_PARAMETER_BLOCK));
memcpy(&KeLoaderBlock, LoaderBlock, sizeof(ROS_LOADER_PARAMETER_BLOCK));
memcpy(&KeLoaderModules[1],
(PVOID)KeLoaderBlock.ModsAddr,
sizeof(LOADER_MODULE) * KeLoaderBlock.ModsCount);
KeLoaderBlock.ModsCount++;
KeLoaderBlock.ModsAddr = (ULONG)&KeLoaderModules;
/* Check for BIOS memory map */
KeMemoryMapRangeCount = 0;
if (KeLoaderBlock.Flags & MB_FLAGS_MMAP_INFO)
{
/* We have a memory map from the nice BIOS */
size = *((PULONG)(KeLoaderBlock.MmapAddr - sizeof(ULONG)));
i = 0;
/* Map it until we run out of size */
while (i < KeLoaderBlock.MmapLength)
{
/* Copy into the Kernel Memory Map */
memcpy (&KeMemoryMap[KeMemoryMapRangeCount],
(PVOID)(KeLoaderBlock.MmapAddr + i),
sizeof(ADDRESS_RANGE));
/* Increase Memory Map Count */
KeMemoryMapRangeCount++;
/* Increase Size */
i += size;
}
/* Save data */
KeLoaderBlock.MmapLength = KeMemoryMapRangeCount * sizeof(ADDRESS_RANGE);
KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap;
}
else
{
/* Nothing from BIOS */
KeLoaderBlock.MmapLength = 0;
KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap;
}
/* Save the Base Address */
MmSystemRangeStart = (PVOID)KeLoaderBlock.KernelBase;
/* Set the Command Line */
strcpy(KeLoaderCommandLine, (PCHAR)_LoaderBlock->CommandLine);
strcpy(KeLoaderCommandLine, (PCHAR)LoaderBlock->CommandLine);
KeLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine;
/* Write the first Module (the Kernel) */
@ -174,15 +205,15 @@ _main(ULONG MultiBootMagic,
KeLoaderModules[0].ModEnd = KeLoaderModules[0].ModStart + PAGE_ROUND_UP((ULONG)OptHead->SizeOfImage);
/* Create a block for each module */
for (i = 1; i < KeLoaderBlock.ModsCount; i++) {
for (i = 1; i < KeLoaderBlock.ModsCount; i++)
{
/* Check if we have to copy the path or not */
if ((s = strrchr((PCHAR)KeLoaderModules[i].String, '/')) != 0) {
if ((s = strrchr((PCHAR)KeLoaderModules[i].String, '/')) != 0)
{
strcpy(KeLoaderModuleStrings[i], s + 1);
} else {
}
else
{
strcpy(KeLoaderModuleStrings[i], (PCHAR)KeLoaderModules[i].String);
}
@ -205,9 +236,6 @@ _main(ULONG MultiBootMagic,
/* Choose last module address as the final kernel address */
LastKernelAddress = PAGE_ROUND_UP(KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd);
/* Low level architecture specific initialization */
KeInit1((PCHAR)KeLoaderBlock.CommandLine, &LastKernelAddress);
/* Select the HAL Base */
HalBase = KeLoaderModules[1].ModStart;
@ -238,6 +266,9 @@ _main(ULONG MultiBootMagic,
/* Increase the last kernel address with the size of HAL */
LastKernelAddress += PAGE_ROUND_UP(DriverSize);
/* FIXME: We need to do this in KiSystemStartup! */
KeInit1();
/* Load the Kernel with the PE Loader */
LdrSafePEProcessModule((PVOID)KERNEL_BASE,
(PVOID)KERNEL_BASE,
@ -248,45 +279,6 @@ _main(ULONG MultiBootMagic,
FirstKrnlPhysAddr = KeLoaderModules[0].ModStart - KERNEL_BASE + 0x200000;
LastKrnlPhysAddr = LastKernelAddress - KERNEL_BASE + 0x200000;
KeMemoryMapRangeCount = 0;
if (KeLoaderBlock.Flags & MB_FLAGS_MMAP_INFO) {
/* We have a memory map from the nice BIOS */
size = *((PULONG)(KeLoaderBlock.MmapAddr - sizeof(ULONG)));
i = 0;
/* Map it until we run out of size */
while (i < KeLoaderBlock.MmapLength) {
/* Copy into the Kernel Memory Map */
memcpy (&KeMemoryMap[KeMemoryMapRangeCount],
(PVOID)(KeLoaderBlock.MmapAddr + i),
sizeof(ADDRESS_RANGE));
/* Increase Memory Map Count */
KeMemoryMapRangeCount++;
/* Increase Size */
i += size;
}
/* Save data */
KeLoaderBlock.MmapLength = KeMemoryMapRangeCount * sizeof(ADDRESS_RANGE);
KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap;
} else {
/* Nothing from BIOS */
KeLoaderBlock.MmapLength = 0;
KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap;
}
/* Initialize the Debugger */
KdInitSystem (0, &KeLoaderBlock);
/* Initialize HAL */
HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
/* Do general System Startup */
KiSystemStartup(1);
}

View file

@ -27,7 +27,7 @@
<if property="ARCH" value="i386">
<directory name="i386">
<file first="true">main_asm.S</file>
<file>cpu.S</file>
<file>cpu.c</file>
<file>ctxswitch.S</file>
<file>clock.S</file>
<file>exp.c</file>

View file

@ -320,6 +320,48 @@ PoInit(PROS_LOADER_PARAMETER_BLOCK LoaderBlock,
}
}
VOID
NTAPI
PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
{
DPRINT1("PerfIdle function: %p\n", PowerState);
}
VOID
NTAPI
PopPerfIdleDpc(IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
/* Call the Perf Idle function */
PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
}
VOID
FASTCALL
PopIdle0(IN PKPRCB Prcb)
{
DPRINT1("Idle function: %p\n", Prcb);
}
VOID
NTAPI
PoInitializePrcb(IN PKPRCB Prcb)
{
/* Initialize the Power State */
RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
Prcb->PowerState.CurrentThrottle = 100;
Prcb->PowerState.CurrentThrottleIndex = 0;
Prcb->PowerState.IdleFunction = PopIdle0;
/* Initialize the Perf DPC and Timer */
KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
//KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
}
/*
* @unimplemented
*/

View file

@ -76,7 +76,7 @@ KeI386VdmInitialize(VOID)
if (!NT_SUCCESS(Status))
{
/* Not present, so check if the CPU supports VME */
if (KeGetPcr()->Prcb->FeatureBits & X86_FEATURE_VME)
if (KeGetPcr()->Prcb->FeatureBits & KF_V86_VIS)
{
/* Enable them. FIXME: Use IPI */
Ki386VdmEnablePentiumExtentions();