mirror of
https://github.com/reactos/reactos.git
synced 2024-11-18 13:01:40 +00:00
467 lines
14 KiB
C
467 lines
14 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* 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)
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#define REQUIRED_FEATURE_BITS (KF_RDTSC|KF_CR4|KF_CMPXCHG8B|KF_XMMI|KF_XMMI64| \
|
|
KF_LARGE_PAGE|KF_FAST_SYSCALL|KF_GLOBAL_PAGE| \
|
|
KF_CMOV|KF_PAT|KF_MMX|KF_FXSR|KF_NX_BIT|KF_MTRR)
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
/* Function pointer for early debug prints */
|
|
ULONG (*FrLdrDbgPrint)(const char *Format, ...);
|
|
|
|
/* Spinlocks used only on X86 */
|
|
KSPIN_LOCK KiFreezeExecutionLock;
|
|
|
|
|
|
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];
|
|
|
|
void KiInitializeSegments();
|
|
void KiSystemCallEntry64();
|
|
void KiSystemCallEntry32();
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
INIT_FUNCTION
|
|
VOID
|
|
NTAPI
|
|
KiInitMachineDependent(VOID)
|
|
{
|
|
/* Check for large page support */
|
|
if (KeFeatureBits & KF_LARGE_PAGE)
|
|
{
|
|
/* FIXME: Support this */
|
|
DPRINT("Large Page support detected but not yet taken advantage of!\n");
|
|
}
|
|
|
|
/* Check for global page support */
|
|
if (KeFeatureBits & KF_GLOBAL_PAGE)
|
|
{
|
|
/* FIXME: Support this */
|
|
DPRINT("Global Page support detected but not yet taken advantage of!\n");
|
|
}
|
|
|
|
/* Check if we have MTRR */
|
|
if (KeFeatureBits & KF_MTRR)
|
|
{
|
|
/* FIXME: Support this */
|
|
DPRINT("MTRR support detected but not yet taken advantage of!\n");
|
|
}
|
|
|
|
/* Check for PAT and/or MTRR support */
|
|
if (KeFeatureBits & KF_PAT)
|
|
{
|
|
/* FIXME: Support this */
|
|
DPRINT("PAT support detected but not yet taken advantage of!\n");
|
|
}
|
|
|
|
// /* Allocate the IOPM save area */
|
|
// Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
|
|
// IOPM_SIZE,
|
|
// ' eK');
|
|
// if (!Ki386IopmSaveArea)
|
|
// {
|
|
// /* Bugcheck. We need this for V86/VDM support. */
|
|
// KeBugCheckEx(NO_PAGES_AVAILABLE, 2, IOPM_SIZE, 0, 0);
|
|
// }
|
|
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KiInitializePcr(IN PKIPCR Pcr,
|
|
IN ULONG ProcessorNumber,
|
|
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));
|
|
|
|
/* Set pointers to ourselves */
|
|
Pcr->Self = (PKPCR)Pcr;
|
|
Pcr->CurrentPrcb = &Pcr->Prcb;
|
|
|
|
/* Set the PCR Version */
|
|
Pcr->MajorVersion = PCR_MAJOR_VERSION;
|
|
Pcr->MinorVersion = PCR_MINOR_VERSION;
|
|
|
|
/* Set the PRCB Version */
|
|
Pcr->Prcb.MajorVersion = 1;
|
|
Pcr->Prcb.MinorVersion = 1;
|
|
|
|
/* Set the Build Type */
|
|
Pcr->Prcb.BuildType = 0;
|
|
#ifndef CONFIG_SMP
|
|
Pcr->Prcb.BuildType |= PRCB_BUILD_UNIPROCESSOR;
|
|
#endif
|
|
#if DBG
|
|
Pcr->Prcb.BuildType |= PRCB_BUILD_DEBUG;
|
|
#endif
|
|
|
|
/* Set the Processor Number and current Processor Mask */
|
|
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);
|
|
|
|
/* Get TSS Entry */
|
|
TssEntry = KiGetGdtEntry(Pcr->GdtBase, Tr);
|
|
|
|
/* Get the KTSS itself */
|
|
Pcr->TssBase = KiGetGdtDescriptorBase(TssEntry);
|
|
|
|
Pcr->Prcb.RspBase = Pcr->TssBase->Rsp0; // FIXME
|
|
|
|
/* Set DPC Stack */
|
|
Pcr->Prcb.DpcStack = DpcStack;
|
|
|
|
/* Setup the processor set */
|
|
Pcr->Prcb.MultiThreadProcessorSet = Pcr->Prcb.SetMember;
|
|
|
|
/* Clear DR6/7 to cleanup bootloader debugging */
|
|
Pcr->Prcb.ProcessorState.SpecialRegisters.KernelDr6 = 0;
|
|
Pcr->Prcb.ProcessorState.SpecialRegisters.KernelDr7 = 0;
|
|
|
|
/* 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)
|
|
{
|
|
ULONG64 Pat;
|
|
ULONG FeatureBits;
|
|
|
|
/* Initialize gs */
|
|
KiInitializeSegments();
|
|
|
|
/* Set GS base */
|
|
__writemsr(MSR_GS_BASE, (ULONG64)Pcr);
|
|
__writemsr(MSR_GS_SWAP, (ULONG64)Pcr);
|
|
|
|
/* Detect and set the CPU Type */
|
|
KiSetProcessorType();
|
|
|
|
/* Get the processor features for this CPU */
|
|
FeatureBits = KiGetFeatureBits();
|
|
|
|
/* Check if we support all needed features */
|
|
if ((FeatureBits & REQUIRED_FEATURE_BITS) != REQUIRED_FEATURE_BITS)
|
|
{
|
|
/* If not, bugcheck system */
|
|
FrLdrDbgPrint("CPU doesn't have needed features! Has: 0x%x, required: 0x%x\n",
|
|
FeatureBits, REQUIRED_FEATURE_BITS);
|
|
KeBugCheck(0);
|
|
}
|
|
|
|
/* Set DEP to always on */
|
|
SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON;
|
|
FeatureBits |= KF_NX_ENABLED;
|
|
|
|
/* Save feature bits */
|
|
Pcr->Prcb.FeatureBits = FeatureBits;
|
|
|
|
/* Enable fx save restore support */
|
|
__writecr4(__readcr4() | CR4_FXSR);
|
|
|
|
/* Enable XMMI exceptions */
|
|
__writecr4(__readcr4() | CR4_XMMEXCPT);
|
|
|
|
/* Enable Write-Protection */
|
|
__writecr0(__readcr0() | CR0_WP);
|
|
|
|
/* Disable fpu monitoring */
|
|
__writecr0(__readcr0() & ~CR0_MP);
|
|
|
|
/* Disable x87 fpu exceptions */
|
|
__writecr0(__readcr0() & ~CR0_NE);
|
|
|
|
/* LDT is unused */
|
|
__lldt(0);
|
|
|
|
/* Set the systemcall entry points */
|
|
__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));
|
|
|
|
/* Set the flags to be cleared when doing a syscall */
|
|
__writemsr(MSR_SYSCALL_MASK, EFLAGS_IF_MASK | EFLAGS_TF | EFLAGS_DF);
|
|
|
|
/* 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);
|
|
}
|
|
|
|
VOID
|
|
FASTCALL
|
|
KiInitializeTss(IN PKTSS64 Tss,
|
|
IN UINT64 Stack)
|
|
{
|
|
PKGDTENTRY64 TssEntry;
|
|
|
|
/* Get pointer to the GDT entry */
|
|
TssEntry = KiGetGdtEntry(KeGetPcr()->GdtBase, KGDT64_SYS_TSS);
|
|
|
|
/* Initialize the GDT entry */
|
|
KiInitGdtEntry(TssEntry, (ULONG64)Tss, sizeof(KTSS64), AMD64_TSS, 0);
|
|
|
|
/* Zero out the TSS */
|
|
RtlZeroMemory(Tss, sizeof(KTSS64));
|
|
|
|
/* FIXME: I/O Map? */
|
|
Tss->IoMapBase = 0x68;
|
|
|
|
/* Setup ring 0 stack pointer */
|
|
Tss->Rsp0 = Stack;
|
|
|
|
/* Setup a stack for Double Fault Traps */
|
|
Tss->Ist[1] = (ULONG64)KiDoubleFaultStack;
|
|
|
|
/* Setup a stack for CheckAbort Traps */
|
|
Tss->Ist[2] = (ULONG64)KiDoubleFaultStack;
|
|
|
|
/* Setup a stack for NMI Traps */
|
|
Tss->Ist[3] = (ULONG64)KiDoubleFaultStack;
|
|
|
|
/* Load the task register */
|
|
__ltr(KGDT64_SYS_TSS);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
INIT_FUNCTION
|
|
KiInitializeKernelMachineDependent(
|
|
IN PKPRCB Prcb,
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
|
{
|
|
/* Set boot-level flags */
|
|
KeI386CpuType = Prcb->CpuType;
|
|
KeI386CpuStep = Prcb->CpuStep;
|
|
KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
|
|
KeProcessorLevel = (USHORT)Prcb->CpuType;
|
|
if (Prcb->CpuID)
|
|
KeProcessorRevision = Prcb->CpuStep;
|
|
|
|
/* Set basic CPU Features that user mode can read */
|
|
SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_PPC_MOVEMEM_64BIT_OK] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = TRUE; // ???
|
|
SharedUserData->ProcessorFeatures[PF_NX_ENABLED] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_FASTFAIL_AVAILABLE] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_XSAVE_ENABLED] = TRUE;
|
|
SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
|
|
(Prcb->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;
|
|
SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
|
|
(Prcb->FeatureBits & KF_3DNOW) ? TRUE: FALSE;
|
|
SharedUserData->ProcessorFeatures[PF_SSE3_INSTRUCTIONS_AVAILABLE] =
|
|
(Prcb->FeatureBits & KF_SSE3) ? TRUE: FALSE;
|
|
SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128] =
|
|
(Prcb->FeatureBits & KF_CMPXCHG16B) ? TRUE: FALSE;
|
|
|
|
/* Set the default NX policy (opt-in) */
|
|
SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN;
|
|
|
|
/* Check if NPX is always on */
|
|
if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSON"))
|
|
{
|
|
/* Set it always on */
|
|
SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON;
|
|
Prcb->FeatureBits |= KF_NX_ENABLED;
|
|
}
|
|
else if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTOUT"))
|
|
{
|
|
/* Set it in opt-out mode */
|
|
SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTOUT;
|
|
Prcb->FeatureBits |= KF_NX_ENABLED;
|
|
}
|
|
else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTIN")) ||
|
|
(strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE")))
|
|
{
|
|
/* Set the feature bits */
|
|
Prcb->FeatureBits |= KF_NX_ENABLED;
|
|
}
|
|
else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSOFF")) ||
|
|
(strstr(KeLoaderBlock->LoadOptions, "EXECUTE")))
|
|
{
|
|
/* Set disabled mode */
|
|
SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSOFF;
|
|
Prcb->FeatureBits |= KF_NX_DISABLED;
|
|
}
|
|
}
|
|
|
|
static LDR_DATA_TABLE_ENTRY LdrCoreEntries[3];
|
|
|
|
void
|
|
KiInitModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
|
{
|
|
PLDR_DATA_TABLE_ENTRY LdrEntry;
|
|
PLIST_ENTRY Entry;
|
|
ULONG i;
|
|
|
|
/* Initialize the list head */
|
|
InitializeListHead(&PsLoadedModuleList);
|
|
|
|
/* Loop the first 3 entries */
|
|
for (Entry = LoaderBlock->LoadOrderListHead.Flink, i = 0;
|
|
Entry != &LoaderBlock->LoadOrderListHead && i < 3;
|
|
Entry = Entry->Flink, i++)
|
|
{
|
|
/* Get the data table entry */
|
|
LdrEntry = CONTAINING_RECORD(Entry,
|
|
LDR_DATA_TABLE_ENTRY,
|
|
InLoadOrderLinks);
|
|
|
|
/* Copy the entry */
|
|
LdrCoreEntries[i] = *LdrEntry;
|
|
|
|
/* Insert the copy into the list */
|
|
InsertTailList(&PsLoadedModuleList, &LdrCoreEntries[i].InLoadOrderLinks);
|
|
}
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
VOID
|
|
NTAPI
|
|
KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
|
{
|
|
CCHAR Cpu;
|
|
PKTHREAD InitialThread;
|
|
ULONG64 InitialStack;
|
|
PKIPCR Pcr;
|
|
|
|
/* HACK */
|
|
FrLdrDbgPrint = LoaderBlock->u.I386.CommonDataArea;
|
|
//FrLdrDbgPrint("Hello from KiSystemStartup!!!\n");
|
|
|
|
/* Save the loader block */
|
|
KeLoaderBlock = LoaderBlock;
|
|
|
|
/* Get the current CPU number */
|
|
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;
|
|
}
|
|
|
|
/* Get Pcr from loader block */
|
|
Pcr = CONTAINING_RECORD(LoaderBlock->Prcb, KIPCR, Prcb);
|
|
|
|
/* Set the PRCB for this Processor */
|
|
KiProcessorBlock[Cpu] = &Pcr->Prcb;
|
|
|
|
/* Align stack to 16 bytes */
|
|
LoaderBlock->KernelStack &= ~(16 - 1);
|
|
|
|
/* Save the initial thread and stack */
|
|
InitialStack = LoaderBlock->KernelStack; // Checkme
|
|
InitialThread = (PKTHREAD)LoaderBlock->Thread;
|
|
|
|
/* 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);
|
|
|
|
/* Initial setup for the boot CPU */
|
|
if (Cpu == 0)
|
|
{
|
|
/* Initialize the module list (ntos, hal, kdcom) */
|
|
KiInitModuleList(LoaderBlock);
|
|
|
|
/* Setup the TSS descriptors and entries */
|
|
KiInitializeTss(Pcr->TssBase, InitialStack);
|
|
|
|
/* Setup the IDT */
|
|
KeInitExceptions();
|
|
|
|
/* Initialize debugging system */
|
|
KdInitSystem(0, KeLoaderBlock);
|
|
|
|
/* Check for break-in */
|
|
if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
|
|
}
|
|
|
|
DPRINT1("Pcr = %p, Gdt = %p, Idt = %p, Tss = %p\n",
|
|
Pcr, Pcr->GdtBase, Pcr->IdtBase, Pcr->TssBase);
|
|
|
|
/* Acquire lock */
|
|
while (InterlockedBitTestAndSet64((PLONG64)&KiFreezeExecutionLock, 0))
|
|
{
|
|
/* Loop until lock is free */
|
|
while ((*(volatile KSPIN_LOCK*)&KiFreezeExecutionLock) & 1);
|
|
}
|
|
|
|
/* Initialize the Processor with HAL */
|
|
HalInitializeProcessor(Cpu, KeLoaderBlock);
|
|
|
|
/* Set processor as active */
|
|
KeActiveProcessors |= 1ULL << Cpu;
|
|
|
|
/* Release lock */
|
|
InterlockedAnd64((PLONG64)&KiFreezeExecutionLock, 0);
|
|
|
|
/* Raise to HIGH_LEVEL */
|
|
KfRaiseIrql(HIGH_LEVEL);
|
|
|
|
/* Machine specific kernel initialization */
|
|
if (Cpu == 0) KiInitializeKernelMachineDependent(&Pcr->Prcb, LoaderBlock);
|
|
|
|
/* Switch to new kernel stack and start kernel bootstrapping */
|
|
KiSwitchToBootStack(InitialStack & ~3);
|
|
}
|
|
|