[NTOSKRNL/AMD64]
[reactos.git] / reactos / ntoskrnl / ke / amd64 / kiinit.c
index d270463..f065ac8 100644 (file)
@@ -70,6 +70,15 @@ KiInitMachineDependent(VOID)
         DPRINT1("PAT support detected but not yet taken advantage of!\n");
     }
 
+        /* Allocate the IOPM save area. */
+//        Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
+//                                                  PAGE_SIZE * 2,
+//                                                  TAG('K', 'e', ' ', ' '));
+//        if (!Ki386IopmSaveArea)
+//        {
+//            /* Bugcheck. We need this for V86/VDM support. */
+//            KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
+//        }
 
 }
 
@@ -110,7 +119,7 @@ KiInitializePcr(IN PKIPCR Pcr,
 
     /* Set the Processor Number and current Processor Mask */
     Pcr->Prcb.Number = (UCHAR)ProcessorNumber;
-    Pcr->Prcb.SetMember = 1 << ProcessorNumber;
+    Pcr->Prcb.SetMember = 1ULL << ProcessorNumber;
 
     /* Get GDT and IDT descriptors */
     __sgdt(&GdtDescriptor.Limit);
@@ -147,14 +156,20 @@ KiInitializePcr(IN PKIPCR Pcr,
     Pcr->Irql = PASSIVE_LEVEL;
     KeSetCurrentIrql(PASSIVE_LEVEL);
 
+    /* Set GS base */
+    __writemsr(X86_MSR_GSBASE, (ULONG64)Pcr);
+    __writemsr(X86_MSR_KERNEL_GSBASE, (ULONG64)Pcr);
 }
 
 VOID
 NTAPI
-KiInitializeCpuFeatures(ULONG Cpu)
+KiInitializeCpu(PKPRCB Prcb)
 {
     ULONG FeatureBits;
 
+    /* Detect and set the CPU Type */
+    KiSetProcessorType();
+
     /* Get the processor features for this CPU */
     FeatureBits = KiGetFeatureBits();
 
@@ -172,7 +187,7 @@ KiInitializeCpuFeatures(ULONG Cpu)
     FeatureBits |= KF_NX_ENABLED;
 
     /* Save feature bits */
-    KeGetCurrentPrcb()->FeatureBits = FeatureBits;
+    Prcb->FeatureBits = FeatureBits;
 
     /* Enable fx save restore support */
     __writecr4(__readcr4() | CR4_FXSR);
@@ -188,170 +203,139 @@ KiInitializeCpuFeatures(ULONG Cpu)
 
     /* Disable x87 fpu exceptions */
     __writecr0(__readcr0() & ~CR0_NE);
-    
+
+    /* LDT is unused */
+    __lldt(0);
 }
 
 VOID
-NTAPI
-KiInitializeKernel(IN PKPROCESS InitProcess,
-                   IN PKTHREAD InitThread,
-                   IN PVOID IdleStack,
-                   IN PKPRCB Prcb,
-                   IN CCHAR Number,
-                   IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+FASTCALL
+KiInitializeTss(IN PKTSS64 Tss,
+                IN UINT64 Stack)
 {
-    ULONG PageDirectory[2];
-    PVOID DpcStack;
+    PKGDTENTRY64 TssEntry;
 
-    /* Detect and set the CPU Type */
-    KiSetProcessorType();
+    /* Get pointer to the GDT entry */
+    TssEntry = KiGetGdtEntry(KeGetPcr()->GdtBase, KGDT64_SYS_TSS);
 
-    /* Initialize the Power Management Support for this PRCB */
-//    PoInitializePrcb(Prcb);
+    /* Initialize the GDT entry */
+    KiInitGdtEntry(TssEntry, (ULONG64)Tss, sizeof(KTSS64), AMD64_TSS, 0);
 
-    /* Save CPU state */
-    KiSaveProcessorControlState(&Prcb->ProcessorState);
+    /* Zero out the TSS */
+    RtlZeroMemory(Tss, sizeof(KTSS64));
 
-    /* Get cache line information for this CPU */
-    KiGetCacheInformation();
+    /* FIXME: I/O Map? */
+    Tss->IoMapBase = 0x68;
 
-    /* Initialize spinlocks and DPC data */
-    KiInitSpinLocks(Prcb, Number);
+    /* Setup ring 0 stack pointer */
+    Tss->Rsp0 = Stack;
 
-    /* Check if this is the Boot CPU */
-    if (Number == 0)
-    {
-        /* Set Node Data */
-        KeNodeBlock[0] = &KiNode0;
-        Prcb->ParentNode = KeNodeBlock[0];
-        KeNodeBlock[0]->ProcessorMask = Prcb->SetMember;
-
-        /* Set boot-level flags */
-        KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
-        KeProcessorLevel = (USHORT)Prcb->CpuType;
-        if (Prcb->CpuID) KeProcessorRevision = Prcb->CpuStep;
-
-        /* Set the current MP Master KPRCB to the Boot PRCB */
-        Prcb->MultiThreadSetMaster = Prcb;
-
-        /* Lower to APC_LEVEL */
-        KeLowerIrql(APC_LEVEL);
-
-        /* Initialize some spinlocks */
-        KeInitializeSpinLock(&KiFreezeExecutionLock);
-
-        /* Initialize portable parts of the OS */
-        KiInitSystem();
-
-        /* Initialize the Idle Process and the Process Listhead */
-        InitializeListHead(&KiProcessListHead);
-        PageDirectory[0] = 0;
-        PageDirectory[1] = 0;
-        KeInitializeProcess(InitProcess,
-                            0,
-                            0xFFFFFFFF,
-                            PageDirectory,
-                            FALSE);
-        InitProcess->QuantumReset = MAXCHAR;
-    }
-    else
-    {
-        /* FIXME */
-        DPRINT1("SMP Boot support not yet present\n");
-    }
+    /* Setup a stack for Double Fault Traps */
+    Tss->Ist[1] = (ULONG64)KiDoubleFaultStack;
+
+    /* Setup a stack for CheckAbort Traps */
+    Tss->Ist[2] = (ULONG64)KiDoubleFaultStack;
 
-    /* HACK for MmUpdatePageDir */
-    ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess;
-
-    /* Setup the Idle Thread */
-    KeInitializeThread(InitProcess,
-                       InitThread,
-                       NULL,
-                       NULL,
-                       NULL,
-                       NULL,
-                       NULL,
-                       IdleStack);
-
-    InitThread->NextProcessor = Number;
-    InitThread->Priority = HIGH_PRIORITY;
-    InitThread->State = Running;
-    InitThread->Affinity = 1 << Number;
-    InitThread->WaitIrql = DISPATCH_LEVEL;
-    InitProcess->ActiveProcessors = 1 << Number;
+    /* 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_MMX_INSTRUCTIONS_AVAILABLE] =
-        (KeFeatureBits & KF_MMX) ? TRUE: FALSE;
-    SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] =
-        (KeFeatureBits & KF_CMPXCHG8B) ? TRUE: FALSE;
+        (Prcb->FeatureBits & KF_MMX) ? TRUE: FALSE;
+    SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
     SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
-        ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI)) ? TRUE: FALSE;
+        ((Prcb->FeatureBits & KF_FXSR) && (Prcb->FeatureBits & KF_XMMI)) ? TRUE: FALSE;
     SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
-        ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI64)) ? TRUE: FALSE;
+        ((Prcb->FeatureBits & KF_FXSR) && (Prcb->FeatureBits & KF_XMMI64)) ? TRUE: FALSE;
     SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
-        (KeFeatureBits & KF_3DNOW) ? TRUE: FALSE;
-    SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] =
-        (KeFeatureBits & KF_RDTSC) ? TRUE: FALSE;
+        (Prcb->FeatureBits & KF_3DNOW) ? TRUE: FALSE;
+    SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE;
 
-    /* Set up the thread-related fields in the PRCB */
-    Prcb->CurrentThread = InitThread;
-    Prcb->NextThread = NULL;
-    Prcb->IdleThread = InitThread;
+    /* Set the default NX policy (opt-in) */
+    SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN;
 
-    /* Initialize the Kernel Executive */
-    ExpInitializeExecutive(Number, LoaderBlock);
-
-    /* Only do this on the boot CPU */
-    if (Number == 0)
+    /* 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")))
     {
-        /* Calculate the time reciprocal */
-        KiTimeIncrementReciprocal =
-            KiComputeReciprocal(KeMaximumIncrement,
-                                &KiTimeIncrementShiftCount);
+        /* Set disabled mode */
+        SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSOFF;
+        Prcb->FeatureBits |= KF_NX_DISABLED;
+    }
 
-        /* Update DPC Values in case they got updated by the executive */
-        Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
-        Prcb->MinimumDpcRate = KiMinimumDpcRate;
-        Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
+}
 
-        /* Allocate the DPC Stack */
-        DpcStack = MmCreateKernelStack(FALSE, 0);
-        if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);
-        Prcb->DpcStack = DpcStack;
+static LDR_DATA_TABLE_ENTRY LdrCoreEntries[3];
 
-        /* Allocate the IOPM save area. */
-//        Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
-//                                                  PAGE_SIZE * 2,
-//                                                  TAG('K', 'e', ' ', ' '));
-//        if (!Ki386IopmSaveArea)
-//        {
-//            /* Bugcheck. We need this for V86/VDM support. */
-//            KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
-//        }
-    }
+void
+KiInitModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    PLIST_ENTRY Entry;
+    ULONG i;
 
-    /* Raise to Dispatch */
-    KfRaiseIrql(DISPATCH_LEVEL);
+    /* Initialize the list head */
+    InitializeListHead(&PsLoadedModuleList);
 
-    /* Set the Idle Priority to 0. This will jump into Phase 1 */
-    KeSetPriorityThread(InitThread, 0);
+    /* 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);
 
-    /* If there's no thread scheduled, put this CPU in the Idle summary */
-    KiAcquirePrcbLock(Prcb);
-    if (!Prcb->NextThread) KiIdleSummary |= 1 << Number;
-    KiReleasePrcbLock(Prcb);
+        /* Copy the entry */
+        LdrCoreEntries[i] = *LdrEntry;
 
-    /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
-    KfRaiseIrql(HIGH_LEVEL);
-    LoaderBlock->Prcb = 0;
+        /* Insert the copy into the list */
+        InsertTailList(&PsLoadedModuleList, &LdrCoreEntries[i].InLoadOrderLinks);
+    }
 }
 
 VOID
 NTAPI
 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
 {
-    ULONG Cpu;
+    CCHAR Cpu;
     PKTHREAD InitialThread;
     ULONG64 InitialStack;
     PKIPCR Pcr;
@@ -367,11 +351,12 @@ KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
     KeLoaderBlock = LoaderBlock;
 
     /* Get the current CPU number */
-    Cpu = KeNumberProcessors++; // FIXME
+    Cpu = (CCHAR)KeNumberProcessors++; // FIXME
 
     /* LoaderBlock initialization for Cpu 0 */
     if (Cpu == 0)
     {
+        FrLdrDbgPrint("LoaderBlock->Prcb=%p\n", LoaderBlock->Prcb);
         /* Set the initial stack, idle thread and process */
         LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack;
         LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread;
@@ -385,13 +370,6 @@ KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
     /* Set the PRCB for this Processor */
     KiProcessorBlock[Cpu] = &Pcr->Prcb;
 
-    /* Set GS base */
-    __writemsr(X86_MSR_GSBASE, (ULONG64)Pcr);
-    __writemsr(X86_MSR_KERNEL_GSBASE, (ULONG64)Pcr);
-
-    /* LDT is unused */
-    __lldt(0);
-
     /* Align stack to 16 bytes */
     LoaderBlock->KernelStack &= ~(16 - 1);
 
@@ -399,9 +377,6 @@ KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
     InitialStack = LoaderBlock->KernelStack; // Checkme
     InitialThread = (PKTHREAD)LoaderBlock->Thread;
 
-    /* Clean the APC List Head */
-    InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]);
-
     /* Set us as the current process */
     InitialThread->ApcState.Process = (PVOID)LoaderBlock->Process;
 
@@ -409,34 +384,34 @@ KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
     KiInitializePcr(Pcr, Cpu, InitialThread, (PVOID)KiDoubleFaultStack);
 
     /* Initialize the CPU features */
-    KiInitializeCpuFeatures(Cpu);
+    KiInitializeCpu(&Pcr->Prcb);
 
     /* 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();
 
-        /* HACK: misuse this function to pass a function pointer to kdcom */
-        KdDebuggerInitialize1((PVOID)FrLdrDbgPrint);
-
-        /* Initialize debugging system */
+         /* Initialize debugging system */
         KdInitSystem(0, KeLoaderBlock);
 
         /* Check for break-in */
         if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
 
         /* Hack! Wait for the debugger! */
-#ifdef _WINKD_
+#ifdef _WINKD_x
         while (!KdPollBreakIn());
         DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
 #endif
     }
 
-    DPRINT("Pcr = %p, Gdt = %p, Idt = %p, Tss = %p\n",
+    DPRINT1("Pcr = %p, Gdt = %p, Idt = %p, Tss = %p\n",
            Pcr, Pcr->GdtBase, Pcr->IdtBase, Pcr->TssBase);
 
     /* Acquire lock */
@@ -444,13 +419,13 @@ KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
     {
         /* Loop until lock is free */
         while ((*(volatile KSPIN_LOCK*)&KiFreezeExecutionLock) & 1);
-    } 
+    }
 
     /* Initialize the Processor with HAL */
     HalInitializeProcessor(Cpu, KeLoaderBlock);
 
     /* Set processor as active */
-    KeActiveProcessors |= 1 << Cpu;
+    KeActiveProcessors |= 1ULL << Cpu;
 
     /* Release lock */
     InterlockedAnd64((PLONG64)&KiFreezeExecutionLock, 0);
@@ -458,45 +433,10 @@ KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
     /* 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 */
-    KiSetupStackAndInitializeKernel(&KiInitialProcess.Pcb,
-                                    InitialThread,
-                                    (PVOID)InitialStack,
-                                    &Pcr->Prcb,
-                                    (CCHAR)Cpu,
-                                    KeLoaderBlock);
+    KiSwitchToBootStack(InitialStack & ~3);
 }
 
-
-VOID
-NTAPI
-KiInitializeKernelAndGotoIdleLoop(IN PKPROCESS InitProcess,
-                                  IN PKTHREAD InitThread,
-                                  IN PVOID IdleStack,
-                                  IN PKPRCB Prcb,
-                                  IN CCHAR Number,
-                                  IN PLOADER_PARAMETER_BLOCK LoaderBlock)
-{
-//    DbgBreakPointWithStatus(0);
-
-    /* Initialize kernel */
-    KiInitializeKernel(InitProcess,
-                       InitThread,
-                       IdleStack,
-                       Prcb,
-                       Number,
-                       KeLoaderBlock);
-
-    /* Set the priority of this thread to 0 */
-    InitThread->Priority = 0;
-
-    /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
-    _enable();
-    KeLowerIrql(DISPATCH_LEVEL);
-
-    /* Set the right wait IRQL */
-    InitThread->WaitIrql = DISPATCH_LEVEL;
-
-    /* Jump into the idle loop */
-    KiIdleLoop();
-}