[FREELDR] Merge boot-drive and partition functionalities together (#6760)
[reactos.git] / ntoskrnl / ke / amd64 / kiinit.c
index e298635..54d4d13 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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)
@@ -15,7 +15,7 @@
 
 #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_CMOV|KF_PAT|KF_MMX|KF_FXSR|KF_NX_BIT|KF_MTRR)
 
 /* GLOBALS *******************************************************************/
 
@@ -29,10 +29,12 @@ 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];
+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();
@@ -40,6 +42,7 @@ void KiSystemCallEntry32();
 
 /* FUNCTIONS *****************************************************************/
 
+CODE_SEG("INIT")
 VOID
 NTAPI
 KiInitMachineDependent(VOID)
@@ -72,29 +75,29 @@ 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));
 
@@ -107,8 +110,8 @@ KiInitializePcr(IN PKIPCR Pcr,
     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;
@@ -123,21 +126,12 @@ KiInitializePcr(IN PKIPCR Pcr,
     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
 
@@ -151,12 +145,14 @@ KiInitializePcr(IN PKIPCR Pcr,
     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
@@ -164,7 +160,7 @@ NTAPI
 KiInitializeCpu(PKIPCR Pcr)
 {
     ULONG64 Pat;
-    ULONG FeatureBits;
+    ULONG64 FeatureBits;
 
     /* Initialize gs */
     KiInitializeSegments();
@@ -193,7 +189,8 @@ KiInitializeCpu(PKIPCR Pcr)
     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);
@@ -230,17 +227,26 @@ KiInitializeCpu(PKIPCR Pcr)
     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);
@@ -252,46 +258,150 @@ KiInitializeTss(IN PKTSS64 Tss,
     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;
+}
 
-    /* Load the task register */
-    __ltr(KGDT64_SYS_TSS);
+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);
+
+    /* 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;
@@ -323,6 +433,10 @@ KiInitializeKernelMachineDependent(
         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];
@@ -355,6 +469,8 @@ KiInitModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
     }
 }
 
+CODE_SEG("INIT")
+DECLSPEC_NORETURN
 VOID
 NTAPI
 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
@@ -364,24 +480,24 @@ 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 */
@@ -400,9 +516,6 @@ KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
     /* 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);
 
@@ -412,9 +525,6 @@ KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
         /* Initialize the module list (ntos, hal, kdcom) */
         KiInitModuleList(LoaderBlock);
 
-        /* Setup the TSS descriptors and entries */
-        KiInitializeTss(Pcr->TssBase, InitialStack);
-
         /* Setup the IDT */
         KeInitExceptions();