/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/ke/i386/kiinit.c
+ * FILE: ntoskrnl/ke/amd64/kiinit.c
* PURPOSE: Kernel Initialization for x86 CPUs
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Timo Kreuzer (timo.kreuzer@reactos.org)
#include <debug.h>
#define REQUIRED_FEATURE_BITS (KF_RDTSC|KF_CR4|KF_CMPXCHG8B|KF_XMMI|KF_XMMI64| \
- KF_NX_BIT)
+ KF_LARGE_PAGE|KF_FAST_SYSCALL|KF_GLOBAL_PAGE| \
+ KF_CMOV|KF_PAT|KF_MMX|KF_FXSR|KF_NX_BIT|KF_MTRR)
/* GLOBALS *******************************************************************/
KIPCR KiInitialPcr;
/* Boot and double-fault/NMI/DPC stack */
-UCHAR DECLSPEC_ALIGN(16) P0BootStackData[KERNEL_STACK_SIZE] = {0};
-UCHAR DECLSPEC_ALIGN(16) KiDoubleFaultStackData[KERNEL_STACK_SIZE] = {0};
-ULONG_PTR P0BootStack = (ULONG_PTR)&P0BootStackData[KERNEL_STACK_SIZE];
-ULONG_PTR KiDoubleFaultStack = (ULONG_PTR)&KiDoubleFaultStackData[KERNEL_STACK_SIZE];
+UCHAR DECLSPEC_ALIGN(16) KiP0BootStackData[KERNEL_STACK_SIZE] = {0};
+UCHAR DECLSPEC_ALIGN(16) KiP0DoubleFaultStackData[KERNEL_STACK_SIZE] = {0};
+PVOID KiP0BootStack = &KiP0BootStackData[KERNEL_STACK_SIZE];
+PVOID KiP0DoubleFaultStack = &KiP0DoubleFaultStackData[KERNEL_STACK_SIZE];
+
+ULONGLONG BootCycles, BootCyclesEnd;
void KiInitializeSegments();
void KiSystemCallEntry64();
/* FUNCTIONS *****************************************************************/
+CODE_SEG("INIT")
VOID
NTAPI
KiInitMachineDependent(VOID)
DPRINT("PAT support detected but not yet taken advantage of!\n");
}
- /* Allocate the IOPM save area. */
+// /* Allocate the IOPM save area */
// Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
-// PAGE_SIZE * 2,
-// TAG('K', 'e', ' ', ' '));
+// IOPM_SIZE,
+// ' eK');
// if (!Ki386IopmSaveArea)
// {
// /* Bugcheck. We need this for V86/VDM support. */
-// KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
+// KeBugCheckEx(NO_PAGES_AVAILABLE, 2, IOPM_SIZE, 0, 0);
// }
}
+static
VOID
-NTAPI
-KiInitializePcr(IN PKIPCR Pcr,
- IN ULONG ProcessorNumber,
- IN PKTHREAD IdleThread,
- IN PVOID DpcStack)
+KiInitializePcr(
+ _Out_ PKIPCR Pcr,
+ _In_ ULONG ProcessorNumber,
+ _In_ PKGDTENTRY64 GdtBase,
+ _In_ PKIDTENTRY64 IdtBase,
+ _In_ PKTSS64 TssBase,
+ _In_ PKTHREAD IdleThread,
+ _In_ PVOID DpcStack)
{
- KDESCRIPTOR GdtDescriptor = {{0},0,0}, IdtDescriptor = {{0},0,0};
- PKGDTENTRY64 TssEntry;
- USHORT Tr = 0;
-
/* Zero out the PCR */
RtlZeroMemory(Pcr, sizeof(KIPCR));
Pcr->MinorVersion = PCR_MINOR_VERSION;
/* Set the PRCB Version */
- Pcr->Prcb.MajorVersion = 1;
- Pcr->Prcb.MinorVersion = 1;
+ Pcr->Prcb.MajorVersion = PRCB_MAJOR_VERSION;
+ Pcr->Prcb.MinorVersion = PRCB_MINOR_VERSION;
/* Set the Build Type */
Pcr->Prcb.BuildType = 0;
Pcr->Prcb.Number = (UCHAR)ProcessorNumber;
Pcr->Prcb.SetMember = 1ULL << ProcessorNumber;
- /* Get GDT and IDT descriptors */
- __sgdt(&GdtDescriptor.Limit);
- __sidt(&IdtDescriptor.Limit);
- Pcr->GdtBase = (PVOID)GdtDescriptor.Base;
- Pcr->IdtBase = (PKIDTENTRY)IdtDescriptor.Base;
-
- /* Get TSS Selector */
- __str(&Tr);
- ASSERT(Tr == KGDT64_SYS_TSS);
+ /* Set GDT and IDT base */
+ Pcr->GdtBase = GdtBase;
+ Pcr->IdtBase = IdtBase;
- /* Get TSS Entry */
- TssEntry = KiGetGdtEntry(Pcr->GdtBase, Tr);
-
- /* Get the KTSS itself */
- Pcr->TssBase = KiGetGdtDescriptorBase(TssEntry);
+ /* Set TssBase */
+ Pcr->TssBase = TssBase;
Pcr->Prcb.RspBase = Pcr->TssBase->Rsp0; // FIXME
Pcr->Prcb.ProcessorState.SpecialRegisters.KernelDr6 = 0;
Pcr->Prcb.ProcessorState.SpecialRegisters.KernelDr7 = 0;
+ /* Initialize MXCSR (all exceptions masked) */
+ Pcr->Prcb.MxCsr = INITIAL_MXCSR;
+
/* Set the Current Thread */
Pcr->Prcb.CurrentThread = IdleThread;
/* Start us out at PASSIVE_LEVEL */
Pcr->Irql = PASSIVE_LEVEL;
- KeSetCurrentIrql(PASSIVE_LEVEL);
}
VOID
NTAPI
KiInitializeCpu(PKIPCR Pcr)
{
- ULONG FeatureBits;
+ ULONG64 Pat;
+ ULONG64 FeatureBits;
/* Initialize gs */
KiInitializeSegments();
FeatureBits |= KF_NX_ENABLED;
/* Save feature bits */
- Pcr->Prcb.FeatureBits = FeatureBits;
+ Pcr->Prcb.FeatureBits = (ULONG)FeatureBits;
+ Pcr->Prcb.FeatureBitsHigh = FeatureBits >> 32;
/* Enable fx save restore support */
__writecr4(__readcr4() | CR4_FXSR);
__writemsr(MSR_LSTAR, (ULONG64)KiSystemCallEntry64);
__writemsr(MSR_CSTAR, (ULONG64)KiSystemCallEntry32);
- __writemsr(MSR_STAR, ((ULONG64)KGDT64_R0_CODE << 32) |
- ((ULONG64)(KGDT64_R3_CMCODE|RPL_MASK) << 48));
+ __writemsr(MSR_STAR, ((ULONG64)KGDT64_R0_CODE << 32) |
+ ((ULONG64)(KGDT64_R3_CMCODE|RPL_MASK) << 48));
/* Set the flags to be cleared when doing a syscall */
__writemsr(MSR_SYSCALL_MASK, EFLAGS_IF_MASK | EFLAGS_TF | EFLAGS_DF);
- /* Enable syscall instruction */
- __writemsr(MSR_EFER, __readmsr(MSR_EFER) | MSR_SCE);
+ /* Enable syscall instruction and no-execute support */
+ __writemsr(MSR_EFER, __readmsr(MSR_EFER) | MSR_SCE | MSR_NXE);
+
+ /* Initialize the PAT */
+ Pat = (PAT_WB << 0) | (PAT_WC << 8) | (PAT_UCM << 16) | (PAT_UC << 24) |
+ (PAT_WB << 32) | (PAT_WC << 40) | (PAT_UCM << 48) | (PAT_UC << 56);
+ __writemsr(MSR_PAT, Pat);
+
+ /* Initialize MXCSR */
+ _mm_setcsr(INITIAL_MXCSR);
+
+ KeSetCurrentIrql(PASSIVE_LEVEL);
}
+static
VOID
-FASTCALL
-KiInitializeTss(IN PKTSS64 Tss,
- IN UINT64 Stack)
+KiInitializeTss(
+ _In_ PKIPCR Pcr,
+ _Out_ PKTSS64 Tss,
+ _In_ PVOID InitialStack,
+ _In_ PVOID DoubleFaultStack,
+ _In_ PVOID NmiStack)
{
PKGDTENTRY64 TssEntry;
/* Get pointer to the GDT entry */
- TssEntry = KiGetGdtEntry(KeGetPcr()->GdtBase, KGDT64_SYS_TSS);
+ TssEntry = KiGetGdtEntry(Pcr->GdtBase, KGDT64_SYS_TSS);
/* Initialize the GDT entry */
KiInitGdtEntry(TssEntry, (ULONG64)Tss, sizeof(KTSS64), AMD64_TSS, 0);
Tss->IoMapBase = 0x68;
/* Setup ring 0 stack pointer */
- Tss->Rsp0 = Stack;
+ Tss->Rsp0 = (ULONG64)InitialStack;
/* Setup a stack for Double Fault Traps */
- Tss->Ist[1] = (ULONG64)KiDoubleFaultStack;
+ Tss->Ist[1] = (ULONG64)DoubleFaultStack;
/* Setup a stack for CheckAbort Traps */
- Tss->Ist[2] = (ULONG64)KiDoubleFaultStack;
+ Tss->Ist[2] = (ULONG64)DoubleFaultStack;
/* Setup a stack for NMI Traps */
- Tss->Ist[3] = (ULONG64)KiDoubleFaultStack;
+ Tss->Ist[3] = (ULONG64)NmiStack;
+}
+
+CODE_SEG("INIT")
+VOID
+KiInitializeProcessorBootStructures(
+ _In_ ULONG ProcessorNumber,
+ _Out_ PKIPCR Pcr,
+ _In_ PKGDTENTRY64 GdtBase,
+ _In_ PKIDTENTRY64 IdtBase,
+ _In_ PKTSS64 TssBase,
+ _In_ PKTHREAD IdleThread,
+ _In_ PVOID KernelStack,
+ _In_ PVOID DpcStack,
+ _In_ PVOID DoubleFaultStack,
+ _In_ PVOID NmiStack)
+{
+ /* Initialize the PCR */
+ KiInitializePcr(Pcr,
+ ProcessorNumber,
+ GdtBase,
+ IdtBase,
+ TssBase,
+ IdleThread,
+ DpcStack);
+
+
+ /* Setup the TSS descriptor and entries */
+ KiInitializeTss(Pcr,
+ TssBase,
+ KernelStack,
+ DoubleFaultStack,
+ NmiStack);
+}
+
+CODE_SEG("INIT")
+static
+VOID
+KiInitializeP0BootStructures(
+ _Inout_ PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+ KDESCRIPTOR GdtDescriptor = {{0},0,0}, IdtDescriptor = {{0},0,0};
+ PKGDTENTRY64 TssEntry;
+ PKTSS64 TssBase;
+
+ /* Set the initial stack, idle thread and process for processor 0 */
+ LoaderBlock->KernelStack = (ULONG_PTR)KiP0BootStack;
+ LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread;
+ LoaderBlock->Process = (ULONG_PTR)&KiInitialProcess.Pcb;
+ LoaderBlock->Prcb = (ULONG_PTR)&KiInitialPcr.Prcb;
+
+ /* Get GDT and IDT descriptors */
+ __sgdt(&GdtDescriptor.Limit);
+ __sidt(&IdtDescriptor.Limit);
- /* Load the task register */
- __ltr(KGDT64_SYS_TSS);
+ /* Get the boot TSS from the GDT */
+ TssEntry = KiGetGdtEntry(GdtDescriptor.Base, KGDT64_SYS_TSS);
+ TssBase = KiGetGdtDescriptorBase(TssEntry);
+
+ /* Initialize PCR and TSS */
+ KiInitializeProcessorBootStructures(0,
+ &KiInitialPcr,
+ GdtDescriptor.Base,
+ IdtDescriptor.Base,
+ TssBase,
+ &KiInitialThread.Tcb,
+ KiP0BootStack,
+ KiP0DoubleFaultStack,
+ KiP0DoubleFaultStack,
+ KiP0DoubleFaultStack);
}
+CODE_SEG("INIT")
VOID
NTAPI
-INIT_FUNCTION
KiInitializeKernelMachineDependent(
IN PKPRCB Prcb,
IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
+ ULONG64 FeatureBits;
+
/* Set boot-level flags */
KeI386CpuType = Prcb->CpuType;
KeI386CpuStep = Prcb->CpuStep;
KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
KeProcessorLevel = (USHORT)Prcb->CpuType;
- if (Prcb->CpuID) KeProcessorRevision = Prcb->CpuStep;
+ if (Prcb->CpuID)
+ KeProcessorRevision = Prcb->CpuStep;
+
+ FeatureBits = Prcb->FeatureBits | (ULONG64)Prcb->FeatureBitsHigh << 32;
/* Set basic CPU Features that user mode can read */
- SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
- (Prcb->FeatureBits & KF_MMX) ? TRUE: FALSE;
+ SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = FALSE;
+ SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] = FALSE;
SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
+ SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
+ (FeatureBits & KF_MMX) ? TRUE : FALSE;
SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
- ((Prcb->FeatureBits & KF_FXSR) && (Prcb->FeatureBits & KF_XMMI)) ? TRUE: FALSE;
- SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
- ((Prcb->FeatureBits & KF_FXSR) && (Prcb->FeatureBits & KF_XMMI64)) ? TRUE: FALSE;
+ ((FeatureBits & KF_FXSR) && (FeatureBits & KF_XMMI)) ? TRUE : FALSE;
SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
- (Prcb->FeatureBits & KF_3DNOW) ? TRUE: FALSE;
+ (FeatureBits & KF_3DNOW) ? TRUE : FALSE;
SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE;
+ SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = TRUE; // ???
+ SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
+ ((FeatureBits & KF_FXSR) && (FeatureBits & KF_XMMI64)) ? TRUE : FALSE;
+ SharedUserData->ProcessorFeatures[PF_SSE_DAZ_MODE_AVAILABLE] = FALSE; // ???
+ SharedUserData->ProcessorFeatures[PF_NX_ENABLED] = TRUE;
+ SharedUserData->ProcessorFeatures[PF_SSE3_INSTRUCTIONS_AVAILABLE] =
+ (FeatureBits & KF_SSE3) ? TRUE : FALSE;
+ SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128] =
+ (FeatureBits & KF_CMPXCHG16B) ? TRUE : FALSE;
+ SharedUserData->ProcessorFeatures[PF_COMPARE64_EXCHANGE128] = FALSE; // ???
+ SharedUserData->ProcessorFeatures[PF_CHANNELS_ENABLED] = FALSE; // ???
+ SharedUserData->ProcessorFeatures[PF_XSAVE_ENABLED] = FALSE; // FIXME
+ SharedUserData->ProcessorFeatures[PF_SECOND_LEVEL_ADDRESS_TRANSLATION] =
+ (FeatureBits & KF_SLAT) ? TRUE : FALSE;
+ SharedUserData->ProcessorFeatures[PF_VIRT_FIRMWARE_ENABLED] =
+ (FeatureBits & KF_VIRT_FIRMWARE_ENABLED) ? TRUE : FALSE;
+ SharedUserData->ProcessorFeatures[PF_RDWRFSGSBASE_AVAILABLE] =
+ (FeatureBits & KF_RDWRFSGSBASE) ? TRUE : FALSE;
+ SharedUserData->ProcessorFeatures[PF_FASTFAIL_AVAILABLE] = TRUE;
+ SharedUserData->ProcessorFeatures[PF_RDRAND_INSTRUCTION_AVAILABLE] =
+ (FeatureBits & KF_RDRAND) ? TRUE : FALSE;
+ SharedUserData->ProcessorFeatures[PF_RDTSCP_INSTRUCTION_AVAILABLE] =
+ (FeatureBits & KF_RDTSCP) ? TRUE : FALSE;
+ SharedUserData->ProcessorFeatures[PF_RDPID_INSTRUCTION_AVAILABLE] = FALSE; // ???
+ SharedUserData->ProcessorFeatures[PF_SSSE3_INSTRUCTIONS_AVAILABLE] =
+ (FeatureBits & KF_SSSE3) ? TRUE : FALSE;
+ SharedUserData->ProcessorFeatures[PF_SSE4_1_INSTRUCTIONS_AVAILABLE] =
+ (FeatureBits & KF_SSE4_1) ? TRUE : FALSE;
+ SharedUserData->ProcessorFeatures[PF_SSE4_2_INSTRUCTIONS_AVAILABLE] =
+ (FeatureBits & KF_SSE4_2) ? TRUE : FALSE;
+ SharedUserData->ProcessorFeatures[PF_AVX_INSTRUCTIONS_AVAILABLE] = FALSE; // FIXME
+ SharedUserData->ProcessorFeatures[PF_AVX2_INSTRUCTIONS_AVAILABLE] = FALSE; // FIXME
+ SharedUserData->ProcessorFeatures[PF_AVX512F_INSTRUCTIONS_AVAILABLE] = FALSE; // FIXME
/* Set the default NX policy (opt-in) */
SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN;
Prcb->FeatureBits |= KF_NX_DISABLED;
}
+#if DBG
+ /* Print applied kernel features/policies and boot CPU features */
+ KiReportCpuFeatures(Prcb);
+#endif
}
static LDR_DATA_TABLE_ENTRY LdrCoreEntries[3];
}
}
+CODE_SEG("INIT")
+DECLSPEC_NORETURN
VOID
NTAPI
KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
ULONG64 InitialStack;
PKIPCR Pcr;
+ /* Boot cycles timestamp */
+ BootCycles = __rdtsc();
+
/* HACK */
FrLdrDbgPrint = LoaderBlock->u.I386.CommonDataArea;
//FrLdrDbgPrint("Hello from KiSystemStartup!!!\n");
- /* Save the loader block */
- KeLoaderBlock = LoaderBlock;
-
/* Get the current CPU number */
- Cpu = (CCHAR)KeNumberProcessors++; // FIXME
+ Cpu = KeNumberProcessors++; // FIXME
/* LoaderBlock initialization for Cpu 0 */
if (Cpu == 0)
{
- /* Set the initial stack, idle thread and process */
- LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack;
- LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread;
- LoaderBlock->Process = (ULONG_PTR)&KiInitialProcess.Pcb;
- LoaderBlock->Prcb = (ULONG_PTR)&KiInitialPcr.Prcb;
+ /* Save the loader block */
+ KeLoaderBlock = LoaderBlock;
+
+ /* Prepare LoaderBlock, PCR, TSS with the P0 boot data */
+ KiInitializeP0BootStructures(LoaderBlock);
}
/* Get Pcr from loader block */
/* Set us as the current process */
InitialThread->ApcState.Process = (PVOID)LoaderBlock->Process;
- /* Initialize the PCR */
- KiInitializePcr(Pcr, Cpu, InitialThread, (PVOID)KiDoubleFaultStack);
-
/* Initialize the CPU features */
KiInitializeCpu(Pcr);
/* Initialize the module list (ntos, hal, kdcom) */
KiInitModuleList(LoaderBlock);
- /* Setup the TSS descriptors and entries */
- KiInitializeTss(Pcr->TssBase, InitialStack);
-
/* Setup the IDT */
KeInitExceptions();