Merge freeldr from amd64 branch:
[reactos.git] / reactos / boot / freeldr / freeldr / arch / amd64 / loader.c
index adb50e9..59a78aa 100644 (file)
@@ -1,7 +1,6 @@
 /*
  *  FreeLoader
- *  Copyright (C) 1998-2003  Brian Palmer  <brianp@sginet.com>
- *  Copyright (C) 2005       Alex Ionescu  <alex@relsoft.net>
+ *  Copyright (C) 2008 - 2009 Timo Kreuzer (timo.kreuzer@reactor.org)
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 
 #define NDEBUG
 #include <debug.h>
-#undef DbgPrint
 
 /* Page Directory and Tables for non-PAE Systems */
-extern PAGE_DIRECTORY_X86 startup_pagedirectory;
-extern PAGE_DIRECTORY_X86 lowmem_pagetable;
-extern PAGE_DIRECTORY_X86 kernel_pagetable;
-extern PAGE_DIRECTORY_X86 hyperspace_pagetable;
-extern PAGE_DIRECTORY_X86 apic_pagetable;
-extern PAGE_DIRECTORY_X86 kpcr_pagetable;
-extern PAGE_DIRECTORY_X86 kuser_pagetable;
+extern ULONG_PTR NextModuleBase;
 extern ULONG_PTR KernelBase;
+ULONG_PTR GdtBase, IdtBase, TssBase;
 extern ROS_KERNEL_ENTRY_POINT KernelEntryPoint;
+
+PPAGE_DIRECTORY_AMD64 pPML4;
+PVOID pIdt, pGdt;
+
 /* FUNCTIONS *****************************************************************/
 
+void
+EnableA20()
+{
+    /* Already done */
+}
+
+void
+DumpLoaderBlock()
+{
+       DbgPrint("LoaderBlock @ %p.\n", &LoaderBlock);
+       DbgPrint("Flags = 0x%x.\n", LoaderBlock.Flags);
+       DbgPrint("MemLower = 0x%p.\n", (PVOID)LoaderBlock.MemLower);
+       DbgPrint("MemHigher = 0x%p.\n", (PVOID)LoaderBlock.MemHigher);
+       DbgPrint("BootDevice = 0x%x.\n", LoaderBlock.BootDevice);
+       DbgPrint("CommandLine = %s.\n", LoaderBlock.CommandLine);
+       DbgPrint("ModsCount = 0x%x.\n", LoaderBlock.ModsCount);
+       DbgPrint("ModsAddr = 0x%p.\n", LoaderBlock.ModsAddr);
+       DbgPrint("Syms = 0x%s.\n", LoaderBlock.Syms);
+       DbgPrint("MmapLength = 0x%x.\n", LoaderBlock.MmapLength);
+       DbgPrint("MmapAddr = 0x%p.\n", (PVOID)LoaderBlock.MmapAddr);
+       DbgPrint("RdLength = 0x%x.\n", LoaderBlock.RdLength);
+       DbgPrint("RdAddr = 0x%p.\n", (PVOID)LoaderBlock.RdAddr);
+       DbgPrint("DrivesCount = 0x%x.\n", LoaderBlock.DrivesCount);
+       DbgPrint("DrivesAddr = 0x%p.\n", (PVOID)LoaderBlock.DrivesAddr);
+       DbgPrint("ConfigTable = 0x%x.\n", LoaderBlock.ConfigTable);
+       DbgPrint("BootLoaderName = 0x%x.\n", LoaderBlock.BootLoaderName);
+       DbgPrint("PageDirectoryStart = 0x%p.\n", (PVOID)LoaderBlock.PageDirectoryStart);
+       DbgPrint("PageDirectoryEnd = 0x%p.\n", (PVOID)LoaderBlock.PageDirectoryEnd);
+       DbgPrint("KernelBase = 0x%p.\n", (PVOID)LoaderBlock.KernelBase);
+       DbgPrint("ArchExtra = 0x%p.\n", (PVOID)LoaderBlock.ArchExtra);
+
+}
+
 /*++
  * FrLdrStartup
  * INTERNAL
@@ -56,57 +86,100 @@ VOID
 NTAPI
 FrLdrStartup(ULONG Magic)
 {
-    ASSERT(FALSE);
-#if 0
-    /* Disable Interrupts */
-    _disable();
+       /* Disable Interrupts */
+       _disable();
 
-    /* Re-initalize EFLAGS */
-    Ke386EraseFlags();
+       /* Re-initalize EFLAGS */
+       KeAmd64EraseFlags();
 
-    /* Initialize the page directory */
-    FrLdrSetupPageDirectory();
+       /* Initialize the page directory */
+       FrLdrSetupPageDirectory();
+
+       /* Set the new PML4 */
+       __writecr3((ULONGLONG)pPML4);
+
+       FrLdrSetupGdtIdt();
+
+       LoaderBlock.FrLdrDbgPrint = DbgPrint;
+
+//     DumpLoaderBlock();
+
+       DbgPrint("Jumping to kernel @ %p.\n", KernelEntryPoint);
+
+       /* Jump to Kernel */
+       (*KernelEntryPoint)(Magic, &LoaderBlock);
 
-    /* Initialize Paging, Write-Protection and Load NTOSKRNL */
-    FrLdrSetupPae(Magic);
-#endif
 }
 
-/*++
- * FrLdrSetupPae
- * INTERNAL
- *
- *     Configures PAE on a MP System, and sets the PDBR if it's supported, or if
- *     the system is UP.
- *
- * Params:
- *     Magic - Multiboot Magic
- *
- * Returns:
- *     None.
- *
- * Remarks:
- *     None.
- *
- *--*/
-VOID
-FASTCALL
-FrLdrSetupPae(ULONG Magic)
+PPAGE_DIRECTORY_AMD64
+FrLdrGetOrCreatePageDir(PPAGE_DIRECTORY_AMD64 pDir, ULONG Index)
+{
+       PPAGE_DIRECTORY_AMD64 pSubDir;
+
+       if (!pDir)
+               return NULL;
+
+       if (!pDir->Pde[Index].Valid)
+       {
+               pSubDir = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
+               if (!pSubDir)
+                       return NULL;
+               RtlZeroMemory(pSubDir, PAGE_SIZE);
+               pDir->Pde[Index].PageFrameNumber = PtrToPfn(pSubDir);
+               pDir->Pde[Index].Valid = 1;
+               pDir->Pde[Index].Write = 1;
+       }
+       else
+       {
+               pSubDir = (PPAGE_DIRECTORY_AMD64)((ULONGLONG)(pDir->Pde[Index].PageFrameNumber) * PAGE_SIZE);
+       }
+       return pSubDir;
+}
+
+BOOLEAN
+FrLdrMapSinglePage(ULONGLONG VirtualAddress, ULONGLONG PhysicalAddress)
 {
-#if 0
-    ULONG_PTR PageDirectoryBaseAddress = (ULONG_PTR)&startup_pagedirectory;
+       PPAGE_DIRECTORY_AMD64 pDir3, pDir2, pDir1;
+       ULONG Index;
 
-    /* Set the PDBR */
-    __writecr3(PageDirectoryBaseAddress);
+       pDir3 = FrLdrGetOrCreatePageDir(pPML4, VAtoPXI(VirtualAddress));
+       pDir2 = FrLdrGetOrCreatePageDir(pDir3, VAtoPPI(VirtualAddress));
+       pDir1 = FrLdrGetOrCreatePageDir(pDir2, VAtoPDI(VirtualAddress));
 
-    /* Enable Paging and Write Protect*/
-    __writecr0(__readcr0() | X86_CR0_PG | X86_CR0_WP);
+       if (!pDir1)
+               return FALSE;
 
-    /* Jump to Kernel */
-    (*KernelEntryPoint)(Magic, &LoaderBlock);
-#endif
+       Index = VAtoPTI(VirtualAddress);
+       if (pDir1->Pde[Index].Valid)
+       {
+               return FALSE;
+       }
+
+       pDir1->Pde[Index].Valid = 1;
+       pDir1->Pde[Index].Write = 1;
+       pDir1->Pde[Index].PageFrameNumber = PhysicalAddress / PAGE_SIZE;
+
+       return TRUE;
 }
 
+ULONG
+FrLdrMapRangeOfPages(ULONGLONG VirtualAddress, ULONGLONG PhysicalAddress, ULONG cPages)
+{
+       ULONG i;
+
+       for (i = 0; i < cPages; i++)
+       {
+               if (!FrLdrMapSinglePage(VirtualAddress, PhysicalAddress))
+               {
+                       return i;
+               }
+               VirtualAddress += PAGE_SIZE;
+               PhysicalAddress += PAGE_SIZE;
+       }
+       return i;
+}
+
+
 /*++
  * FrLdrSetupPageDirectory
  * INTERNAL
@@ -118,99 +191,117 @@ FrLdrSetupPae(ULONG Magic)
  *
  * Returns:
  *     None.
- *
- * Remarks:
- *     We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
- *     As such, please note that PageFrameNumber == PageEntryNumber.
- *
  *--*/
 VOID
 FASTCALL
 FrLdrSetupPageDirectory(VOID)
 {
-#if 0
-    PPAGE_DIRECTORY_X86 PageDir;
-    ULONG KernelPageTableIndex;
-    ULONG i;
-
-    /* Get the Kernel Table Index */
-    KernelPageTableIndex = KernelBase >> PDE_SHIFT;
-
-    /* Get the Startup Page Directory */
-    PageDir = (PPAGE_DIRECTORY_X86)&startup_pagedirectory;
-
-    /* Set up the Low Memory PDE */
-    PageDir->Pde[LowMemPageTableIndex].Valid = 1;
-    PageDir->Pde[LowMemPageTableIndex].Write = 1;
-    PageDir->Pde[LowMemPageTableIndex].PageFrameNumber = PaPtrToPfn(lowmem_pagetable);
-
-    /* Set up the Kernel PDEs */
-    PageDir->Pde[KernelPageTableIndex].Valid = 1;
-    PageDir->Pde[KernelPageTableIndex].Write = 1;
-    PageDir->Pde[KernelPageTableIndex].PageFrameNumber = PaPtrToPfn(kernel_pagetable);
-    PageDir->Pde[KernelPageTableIndex + 1].Valid = 1;
-    PageDir->Pde[KernelPageTableIndex + 1].Write = 1;
-    PageDir->Pde[KernelPageTableIndex + 1].PageFrameNumber = PaPtrToPfn(kernel_pagetable + 4096);
-
-    /* Set up the Startup PDE */
-    PageDir->Pde[StartupPageTableIndex].Valid = 1;
-    PageDir->Pde[StartupPageTableIndex].Write = 1;
-    PageDir->Pde[StartupPageTableIndex].PageFrameNumber = PaPtrToPfn(startup_pagedirectory);
-
-    /* Set up the Hyperspace PDE */
-    PageDir->Pde[HyperspacePageTableIndex].Valid = 1;
-    PageDir->Pde[HyperspacePageTableIndex].Write = 1;
-    PageDir->Pde[HyperspacePageTableIndex].PageFrameNumber = PaPtrToPfn(hyperspace_pagetable);
-
-    /* Set up the HAL PDE */
-    PageDir->Pde[HalPageTableIndex].Valid = 1;
-    PageDir->Pde[HalPageTableIndex].Write = 1;
-    PageDir->Pde[HalPageTableIndex].PageFrameNumber = PaPtrToPfn(apic_pagetable);
-
-    /* Set up Low Memory PTEs */
-    PageDir = (PPAGE_DIRECTORY_X86)&lowmem_pagetable;
-    for (i=0; i<1024; i++)
-    {
-        PageDir->Pde[i].Valid = 1;
-        PageDir->Pde[i].Write = 1;
-        PageDir->Pde[i].Owner = 1;
-        PageDir->Pde[i].PageFrameNumber = PaToPfn(i * PAGE_SIZE);
-    }
-
-    /* Set up Kernel PTEs */
-    PageDir = (PPAGE_DIRECTORY_X86)&kernel_pagetable;
-    for (i=0; i<1536; i++)
-    {
-        PageDir->Pde[i].Valid = 1;
-        PageDir->Pde[i].Write = 1;
-        PageDir->Pde[i].PageFrameNumber = PaToPfn(KERNEL_BASE_PHYS + i * PAGE_SIZE);
-    }
-
-    /* Setup APIC Base */
-    PageDir = (PPAGE_DIRECTORY_X86)&apic_pagetable;
-    PageDir->Pde[0].Valid = 1;
-    PageDir->Pde[0].Write = 1;
-    PageDir->Pde[0].CacheDisable = 1;
-    PageDir->Pde[0].WriteThrough = 1;
-    PageDir->Pde[0].PageFrameNumber = PaToPfn(HAL_BASE);
-    PageDir->Pde[0x200].Valid = 1;
-    PageDir->Pde[0x200].Write = 1;
-    PageDir->Pde[0x200].CacheDisable = 1;
-    PageDir->Pde[0x200].WriteThrough = 1;
-    PageDir->Pde[0x200].PageFrameNumber = PaToPfn(HAL_BASE + KERNEL_BASE_PHYS);
-
-    /* Setup KUSER_SHARED_DATA Base */
-    PageDir->Pde[0x1F0].Valid = 1;
-    PageDir->Pde[0x1F0].Write = 1;
-    PageDir->Pde[0x1F0].PageFrameNumber = 2;
-
-    /* Setup KPCR Base*/
-    PageDir->Pde[0x1FF].Valid = 1;
-    PageDir->Pde[0x1FF].Write = 1;
-    PageDir->Pde[0x1FF].PageFrameNumber = 1;
-
-    /* Zero shared data */
-    RtlZeroMemory((PVOID)(2 << MM_PAGE_SHIFT), PAGE_SIZE);
-#endif
+       ULONG KernelPages;
+       PVOID UserSharedData;
+
+       /* Allocate a Page for the PML4 */
+       pPML4 = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
+
+       ASSERT(pPML4);
+
+       /* The page tables are located at 0xfffff68000000000 
+        * We create a recursive self mapping through all 4 levels at 
+        * virtual address 0xfffff6fb7dbedf68 */
+       pPML4->Pde[VAtoPXI(PXE_BASE)].Valid = 1;
+       pPML4->Pde[VAtoPXI(PXE_BASE)].Write = 1;
+       pPML4->Pde[VAtoPXI(PXE_BASE)].PageFrameNumber = PtrToPfn(pPML4);
+
+       /* Setup low memory pages */
+       if (FrLdrMapRangeOfPages(0, 0, 1024) < 1024)
+       {
+               DbgPrint("Could not map low memory pages.\n");
+       }
+
+       /* Setup kernel pages */
+       KernelPages = (ROUND_TO_PAGES(NextModuleBase - KERNEL_BASE_PHYS) / PAGE_SIZE);
+       if (FrLdrMapRangeOfPages(KernelBase, KERNEL_BASE_PHYS, KernelPages) != KernelPages)
+       {
+               DbgPrint("Could not map %d kernel pages.\n", KernelPages);
+       }
+
+       /* Setup a page for the idt */
+       pIdt = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
+       IdtBase = KernelBase + KernelPages * PAGE_SIZE;
+       if (!FrLdrMapSinglePage(IdtBase, (ULONGLONG)pIdt))
+       {
+               DbgPrint("Could not map idt page.\n", KernelPages);
+       }
+
+       /* Setup a page for the gdt & tss */
+       pGdt = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
+       GdtBase = IdtBase + PAGE_SIZE;
+       TssBase = GdtBase + 20 * sizeof(ULONG64); // FIXME: don't hardcode
+       if (!FrLdrMapSinglePage(GdtBase, (ULONGLONG)pGdt))
+       {
+               DbgPrint("Could not map gdt page.\n", KernelPages);
+       }
+
+       /* Setup KUSER_SHARED_DATA page */
+       UserSharedData = MmAllocateMemoryWithType(PAGE_SIZE, LoaderSpecialMemory);
+       if (!FrLdrMapSinglePage(KI_USER_SHARED_DATA, (ULONG64)UserSharedData))
+       {
+               DbgPrint("Could not map KUSER_SHARED_DATA page.\n", KernelPages);
+       }
+
+       /* Map APIC page */
+       if (!FrLdrMapSinglePage(APIC_BASE, APIC_PHYS_BASE))
+       {
+               DbgPrint("Could not map APIC page.\n");
+       }
+
 }
 
+VOID
+FrLdrSetupGdtIdt()
+{
+       PKGDTENTRY64 Entry;
+       KDESCRIPTOR Desc;
+
+       RtlZeroMemory(pGdt, PAGE_SIZE);
+
+       /* Setup KGDT_64_R0_CODE */
+       Entry = KiGetGdtEntry(pGdt, KGDT_64_R0_CODE);
+       *(PULONG64)Entry = 0x00209b0000000000ULL;
+
+       /* Setup KGDT_64_R0_SS */
+       Entry = KiGetGdtEntry(pGdt, KGDT_64_R0_SS);
+       *(PULONG64)Entry = 0x00cf93000000ffffULL;
+
+       /* Setup KGDT_64_DATA */
+       Entry = KiGetGdtEntry(pGdt, KGDT_64_DATA);
+       *(PULONG64)Entry = 0x00cff3000000ffffULL;
+
+       /* Setup KGDT_64_R3_CODE */
+       Entry = KiGetGdtEntry(pGdt, KGDT_64_R3_CODE);
+       *(PULONG64)Entry = 0x0020fb0000000000ULL;
+
+       /* Setup KGDT_32_R3_TEB */
+       Entry = KiGetGdtEntry(pGdt, KGDT_32_R3_TEB);
+       *(PULONG64)Entry = 0xff40f3fd50003c00ULL;
+
+       /* Setup TSS entry */
+       Entry = KiGetGdtEntry(pGdt, KGDT_TSS);
+       KiInitGdtEntry(Entry, TssBase, sizeof(KTSS), I386_TSS, 0);
+
+       /* Setup the gdt descriptor */
+       Desc.Limit = 12 * sizeof(ULONG64) - 1;
+       Desc.Base = (PVOID)GdtBase;
+
+       /* Set the new Gdt */
+       __lgdt(&Desc.Limit);
+       DbgPrint("Gdtr.Base = %p\n", Desc.Base);
+
+       /* Setup the idt descriptor */
+       Desc.Limit = 12 * sizeof(ULONG64) - 1;
+       Desc.Base = (PVOID)IdtBase;
+
+       /* Set the new Idt */
+       __lidt(&Desc.Limit);
+       DbgPrint("Idtr.Base = %p\n", Desc.Base);
+
+}