Sync to trunk head (r42241)
[reactos.git] / reactos / ntoskrnl / ke / freeldr.c
index 714bc78..d135743 100644 (file)
 /* INCLUDES *****************************************************************/
 
 #include <ntoskrnl.h>
-
-#define NDEBUG
+//#define NDEBUG
 #include <debug.h>
 
+#ifdef _M_PPC
+#include <ppcmmu/mmu.h>
+#define KERNEL_RVA(x) RVA(x,0x80800000)
+#define KERNEL_DESCRIPTOR_PAGE(x) (((ULONG_PTR)(x) + KernelBase) >> PAGE_SHIFT)
+#else
+#define KERNEL_RVA(x) RVA(x,KSEG0_BASE)
+#define KERNEL_DESCRIPTOR_PAGE(x) (((ULONG_PTR)(x) & ~KSEG0_BASE) >> PAGE_SHIFT)
+#endif
+
+typedef struct _BIOS_MEMORY_DESCRIPTOR
+{
+    ULONG BlockBase;
+    ULONG BlockSize;
+} BIOS_MEMORY_DESCRIPTOR, *PBIOS_MEMORY_DESCRIPTOR;
+
 /* GLOBALS *******************************************************************/
 
-/* FreeLDR Module Data */
-LOADER_MODULE KeLoaderModules[64];
-ULONG KeLoaderModuleCount;
-static CHAR KeLoaderModuleStrings[64][256];
+/* Function pointer for early debug prints */
+ULONG (*FrLdrDbgPrint)(const char *Format, ...);
 
-/* FreeLDR Memory Data */
+/* FreeLDR Loader Data */
+PROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock;
+BOOLEAN AcpiTableDetected = FALSE;
 ADDRESS_RANGE KeMemoryMap[64];
 ULONG KeMemoryMapRangeCount;
-ULONG_PTR MmFreeLdrFirstKrnlPhysAddr, MmFreeLdrLastKrnlPhysAddr;
-ULONG_PTR MmFreeLdrLastKernelAddress;
-ULONG MmFreeLdrMemHigher;
-ULONG MmFreeLdrPageDirectoryEnd;
 
-/* FreeLDR Loader Data */
-ROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock;
-static CHAR KeLoaderCommandLine[256];
-BOOLEAN AcpiTableDetected;
-
-/* FreeLDR PE Hack Data */
-extern LDR_DATA_TABLE_ENTRY HalModuleObject;
-
-/* NT Loader Data */
-LOADER_PARAMETER_BLOCK BldrLoaderBlock;
-LOADER_PARAMETER_EXTENSION BldrExtensionBlock;
-CHAR BldrCommandLine[256];
-CHAR BldrArcBootPath[64];
-CHAR BldrArcHalPath[64];
-CHAR BldrNtHalPath[64];
-CHAR BldrNtBootPath[64];
-LDR_DATA_TABLE_ENTRY BldrModules[64];
-MEMORY_ALLOCATION_DESCRIPTOR BldrMemoryDescriptors[64];
-WCHAR BldrModuleStrings[64][260];
-NLS_DATA_BLOCK BldrNlsDataBlock;
-SETUP_LOADER_BLOCK BldrSetupBlock;
-struct _boot_infos_t *BootInfo;
+/* NT Loader Module/Descriptor Count */
+ULONG BldrCurrentMd;
+ULONG BldrCurrentMod;
+
+/* NT Loader Data. Eats up about 100KB! */
+LOADER_PARAMETER_BLOCK BldrLoaderBlock;                 // 0x0000
+LOADER_PARAMETER_EXTENSION BldrExtensionBlock;          // 0x0060
+CHAR BldrCommandLine[256];                              // 0x00DC
+CHAR BldrArcBootPath[64];                               // 0x01DC
+CHAR BldrArcHalPath[64];                                // 0x021C
+CHAR BldrNtHalPath[64];                                 // 0x025C
+CHAR BldrNtBootPath[64];                                // 0x029C
+LDR_DATA_TABLE_ENTRY BldrModules[64];                   // 0x02DC
+MEMORY_ALLOCATION_DESCRIPTOR BldrMemoryDescriptors[60]; // 0x14DC
+WCHAR BldrModuleStrings[64][260];                       // 0x19DC
+WCHAR BldrModuleStringsFull[64][260];                   // 0x9BDC
+NLS_DATA_BLOCK BldrNlsDataBlock;                        // 0x11DDC
+SETUP_LOADER_BLOCK BldrSetupBlock;                      // 0x11DE8
+ARC_DISK_INFORMATION BldrArcDiskInfo;                   // 0x12134
+CHAR BldrArcNames[32][256];                             // 0x1213C
+ARC_DISK_SIGNATURE BldrDiskInfo[32];                    // 0x1413C
+CHAR BldrArcHwBuffer[16 * 1024];                        // 0x1843C
+
+/* BIOS Memory Map */
+BIOS_MEMORY_DESCRIPTOR BiosMemoryDescriptors[16] = { { 0, 0 }, };
+PBIOS_MEMORY_DESCRIPTOR BiosMemoryDescriptorList = BiosMemoryDescriptors;
+
+/* ARC Memory Map */
+ULONG NumberDescriptors = 0;
+MEMORY_DESCRIPTOR MDArray[60] = { { 0, 0, 0 }, };
 
-#ifdef _M_PPC
-#include "font.h"
-boot_infos_t PpcEarlybootInfo;
+/* FUNCTIONS *****************************************************************/
+
+PMEMORY_ALLOCATION_DESCRIPTOR
+NTAPI
+KiRosGetMdFromArray(VOID)
+{
+    /* Return the next MD from the list, but make sure we don't overflow */
+    if (BldrCurrentMd > 60) ASSERT(FALSE);
+    return &BldrMemoryDescriptors[BldrCurrentMd++];
+}
+
+VOID
+NTAPI
+KiRosAddBiosBlock(ULONG Address,
+                  ULONG Size)
+{
+    PBIOS_MEMORY_DESCRIPTOR BiosBlock = BiosMemoryDescriptorList;
+
+    /* Loop our BIOS Memory Descriptor List */
+    while (BiosBlock->BlockSize > 0)
+    {
+        /* Check if we've found a matching head block */
+        if (Address + Size == BiosBlock->BlockBase)
+        {
+            /* Simply enlarge and rebase it */
+            BiosBlock->BlockBase = Address;
+            BiosBlock->BlockSize += Size;
+            break;
+        }
+
+        /* Check if we've found a matching tail block */
+        if (Address == (BiosBlock->BlockBase + BiosBlock->BlockSize))
+        {
+            /* Simply enlarge it */
+            BiosBlock->BlockSize += Size;
+            break;
+        }
+
+        /* Nothing suitable found, try the next block */
+        BiosBlock++;
+    }
+
+    /* No usable blocks found, found a free block instead */
+    if (!BiosBlock->BlockSize)
+    {
+        /* Write our data */
+        BiosBlock->BlockBase = Address;
+        BiosBlock->BlockSize = Size;
+
+        /* Create a new block and mark it as the end of the array */
+        BiosBlock++;
+        BiosBlock->BlockBase = BiosBlock->BlockSize = 0L;
+    }
+}
+
+VOID
+NTAPI
+KiRosBuildBiosMemoryMap(VOID)
+{
+    ULONG BlockBegin, BlockEnd;
+    ULONG j;
+
+    /* Loop the BIOS Memory Map */
+    for (j = 0; j < KeMemoryMapRangeCount; j++)
+    {
+        /* Get the start and end addresses */
+        BlockBegin = KeMemoryMap[j].BaseAddrLow;
+        BlockEnd = KeMemoryMap[j].BaseAddrLow + KeMemoryMap[j].LengthLow - 1;
+
+        /* Make sure this isn't a > 4GB descriptor */
+        if (!KeMemoryMap[j].BaseAddrHigh)
+        {
+            /* Make sure we don't overflow */
+            if (BlockEnd < BlockBegin) BlockEnd = 0xFFFFFFFF;
+
+            /* Check if this is free memory */
+            if (KeMemoryMap[j].Type == 1)
+            {
+                /* Add it to our BIOS descriptors */
+                KiRosAddBiosBlock(BlockBegin, BlockEnd - BlockBegin + 1);
+            }
+        }
+    }
+}
+
+NTSTATUS
+NTAPI
+KiRosAllocateArcDescriptor(IN ULONG PageBegin,
+                           IN ULONG PageEnd,
+                           IN MEMORY_TYPE MemoryType)
+{
+    ULONG i;
+
+    /* Loop all our descriptors */
+    for (i = 0; i < NumberDescriptors; i++)
+    {
+        /* Attempt to fing a free block that describes our region */
+        if ((MDArray[i].MemoryType == MemoryFree) &&
+            (MDArray[i].BasePage <= PageBegin) &&
+            (MDArray[i].BasePage + MDArray[i].PageCount > PageBegin) &&
+            (MDArray[i].BasePage + MDArray[i].PageCount >= PageEnd))
+        {
+            /* Found one! */
+            break;
+        }
+    }
+
+    /* Check if we found no free blocks, and fail if so */
+    if (i == NumberDescriptors) return ENOMEM;
+
+    /* Check if the block has our base address */
+    if (MDArray[i].BasePage == PageBegin)
+    {
+        /* Check if it also has our ending address */
+        if ((MDArray[i].BasePage + MDArray[i].PageCount) == PageEnd)
+        {
+            /* Then convert this region into our new memory type */
+            MDArray[i].MemoryType = MemoryType;
+        }
+        else
+        {
+            /* Otherwise, make sure we have enough descriptors */
+            if (NumberDescriptors == 60) return ENOMEM;
+
+            /* Cut this descriptor short */
+            MDArray[i].BasePage = PageEnd;
+            MDArray[i].PageCount -= (PageEnd - PageBegin);
+
+            /* And allocate a new descriptor for our memory range */
+            MDArray[NumberDescriptors].BasePage = PageBegin;
+            MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
+            MDArray[NumberDescriptors].MemoryType = MemoryType;
+            NumberDescriptors++;
+        }
+    }
+    else if ((MDArray[i].BasePage + MDArray[i].PageCount) == PageEnd)
+    {
+        /* This block has our end address, make sure we have a free block */
+        if (NumberDescriptors == 60) return ENOMEM;
+
+        /* Rebase this descriptor */
+        MDArray[i].PageCount = PageBegin - MDArray[i].BasePage;
+
+        /* And allocate a new descriptor for our memory range */
+        MDArray[NumberDescriptors].BasePage = PageBegin;
+        MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
+        MDArray[NumberDescriptors].MemoryType = MemoryType;
+        NumberDescriptors++;
+    }
+    else
+    {
+        /* We'll need two descriptors, make sure they're available */
+        if ((NumberDescriptors + 1) >= 60) return ENOMEM;
+
+        /* Allocate a free memory descriptor for what follows us */
+        MDArray[NumberDescriptors].BasePage = PageEnd;
+        MDArray[NumberDescriptors].PageCount = MDArray[i].PageCount -
+                                               (PageEnd - MDArray[i].BasePage);
+        MDArray[NumberDescriptors].MemoryType = MemoryFree;
+        NumberDescriptors++;
+
+        /* Cut down the current free descriptor */
+        MDArray[i].PageCount = PageBegin - MDArray[i].BasePage;
+
+        /* Allocate a new memory descriptor for our memory range */
+        MDArray[NumberDescriptors].BasePage = PageBegin;
+        MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
+        MDArray[NumberDescriptors].MemoryType = MemoryType;
+        NumberDescriptors++;
+    }
+
+    /* Everything went well */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+KiRosConfigureArcDescriptor(IN ULONG PageBegin,
+                            IN ULONG PageEnd,
+                            IN TYPE_OF_MEMORY MemoryType)
+{
+    ULONG i;
+    ULONG BlockBegin, BlockEnd;
+    MEMORY_TYPE BlockType;
+    BOOLEAN Combined = FALSE;
+
+    /* If this descriptor seems bogus, just return */
+    if (PageEnd <= PageBegin) return STATUS_SUCCESS;
+
+    /* Loop every ARC descriptor, trying to find one we can modify */
+    for (i = 0; i < NumberDescriptors; i++)
+    {
+        /* Get its settings */
+        BlockBegin = MDArray[i].BasePage;
+        BlockEnd = MDArray[i].BasePage + MDArray[i].PageCount;
+        BlockType = MDArray[i].MemoryType;
+
+        /* Check if we can fit inside this block */
+        if (BlockBegin < PageBegin)
+        {
+            /* Check if we are larger then it */
+            if ((BlockEnd > PageBegin) && (BlockEnd <= PageEnd))
+            {
+                /* Make it end where we start */
+                BlockEnd = PageBegin;
+            }
+
+            /* Check if it ends after we do */
+            if (BlockEnd > PageEnd)
+            {
+                /* Make sure we can allocate a descriptor */
+                if (NumberDescriptors == 60) return ENOMEM;
+
+                /* Create a descriptor for whatever memory we're not part of */
+                MDArray[NumberDescriptors].MemoryType = BlockType;
+                MDArray[NumberDescriptors].BasePage = PageEnd;
+                MDArray[NumberDescriptors].PageCount  = BlockEnd - PageEnd;
+                NumberDescriptors++;
+
+                /* The next block ending is now where we begin */
+                BlockEnd = PageBegin;
+            }
+        }
+        else
+        {
+            /* Check if the blog begins inside our range */
+            if (BlockBegin < PageEnd)
+            {
+                /* Check if it ends before we do */
+                if (BlockEnd < PageEnd)
+                {
+                    /* Then make it disappear */
+                    BlockEnd = BlockBegin;
+                }
+                else
+                {
+                    /* Otherwise make it start where we end */
+                    BlockBegin = PageEnd;
+                }
+            }
+        }
+
+        /* Check if the block matches us, and we haven't tried combining yet */
+        if (((TYPE_OF_MEMORY)BlockType == MemoryType) && !(Combined))
+        {
+            /* Check if it starts where we end */
+            if (BlockBegin == PageEnd)
+            {
+                /* Make it start with us, and combine us */
+                BlockBegin = PageBegin;
+                Combined = TRUE;
+            }
+            else if (BlockEnd == PageBegin)
+            {
+                /* Otherwise, it ends where we begin, combine its ending */
+                BlockEnd = PageEnd;
+                Combined = TRUE;
+            }
+        }
+
+        /* Check the original block data matches with what we came up with */
+        if ((MDArray[i].BasePage == BlockBegin) &&
+            (MDArray[i].PageCount == BlockEnd - BlockBegin))
+        {
+            /* Then skip it */
+            continue;
+        }
+
+        /* Otherwise, set our new settings for this block */
+        MDArray[i].BasePage  = BlockBegin;
+        MDArray[i].PageCount = BlockEnd - BlockBegin;
+
+        /* Check if we are killing the block */
+        if (BlockBegin == BlockEnd)
+        {
+            /* Delete this block and restart the loop properly */
+            NumberDescriptors--;
+            if (i < NumberDescriptors) MDArray[i] = MDArray[NumberDescriptors];
+            i--;
+        }
+    }
+
+    /* If we got here without combining, we need to allocate a new block */
+    if (!(Combined) && (MemoryType < LoaderMaximum))
+    {
+        /* Make sure there's enough descriptors */
+        if (NumberDescriptors == 60) return ENOMEM;
+
+        /* Allocate a new block with our data */
+        MDArray[NumberDescriptors].MemoryType = MemoryType;
+        MDArray[NumberDescriptors].BasePage = PageBegin;
+        MDArray[NumberDescriptors].PageCount  = PageEnd - PageBegin;
+        NumberDescriptors++;
+    }
+
+    /* Changes complete, return success */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+KiRosBuildOsMemoryMap(VOID)
+{
+    PBIOS_MEMORY_DESCRIPTOR MdBlock;
+    ULONG BlockStart, BlockEnd, BiasedStart, BiasedEnd, PageStart, PageEnd;
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG BiosPage = 0xA0;
+
+    /* Loop the BIOS Memory Descriptor List */
+    MdBlock = BiosMemoryDescriptorList;
+    while (MdBlock->BlockSize)
+    {
+        /* Get the statrt and end addresses */
+        BlockStart = MdBlock->BlockBase;
+        BlockEnd = BlockStart + MdBlock->BlockSize - 1;
+
+        /* Align them to page boundaries */
+        BiasedStart = BlockStart & (PAGE_SIZE - 1);
+        if (BiasedStart) BlockStart = BlockStart + PAGE_SIZE - BiasedStart;
+        BiasedEnd = (BlockEnd + 1) & (ULONG)(PAGE_SIZE - 1);
+        if (BiasedEnd) BlockEnd -= BiasedEnd;
+
+        /* Get the actual page numbers */
+        PageStart = BlockStart >> PAGE_SHIFT;
+        PageEnd = (BlockEnd + 1) >> PAGE_SHIFT;
+
+        /* If we're starting at page 0, then put the BIOS page at the end */
+        if (!PageStart) BiosPage = PageEnd;
+
+        /* Check if we did any alignment */
+        if (BiasedStart)
+        {
+            /* Mark that region as reserved */
+            Status = KiRosConfigureArcDescriptor(PageStart - 1,
+                                                 PageStart,
+                                                 MemorySpecialMemory);
+            if (Status != STATUS_SUCCESS) break;
+        }
+
+        /* Check if we did any alignment */
+        if (BiasedEnd)
+        {
+            /* Mark that region as reserved */
+            Status = KiRosConfigureArcDescriptor(PageEnd - 1,
+                                                 PageEnd,
+                                                 MemorySpecialMemory);
+            if (Status != STATUS_SUCCESS) break;
+
+            /* If the bios page was the last page, use the next one instead */
+            if (BiosPage == PageEnd) BiosPage += 1;
+        }
+
+        /* Check if the page is below the 16MB Memory hole */
+        if (PageEnd <= 0xFC0)
+        {
+            /* It is, mark the memory a free */
+            Status = KiRosConfigureArcDescriptor(PageStart,
+                                                 PageEnd,
+                                                 LoaderFree);
+        }
+        else if (PageStart >= 0x1000)
+        {
+            /* It's over 16MB, so that memory gets marked as reserve */
+            Status = KiRosConfigureArcDescriptor(PageStart,
+                                                 PageEnd,
+                                                 LoaderFree);
+        }
+        else
+        {
+            /* Check if it starts below the memory hole */
+            if (PageStart < 0xFC0)
+            {
+                /* Mark that part as free */
+                Status = KiRosConfigureArcDescriptor(PageStart,
+                                                     0xFC0,
+                                                     MemoryFree);
+                if (Status != STATUS_SUCCESS) break;
+
+                /* And update the page start for the code below */
+                PageStart = 0xFC0;
+            }
+
+            /* Any code in the memory hole region ends up as reserve */
+            Status = KiRosConfigureArcDescriptor(PageStart,
+                                                 PageEnd,
+                                                 LoaderFree);
+        }
+
+        /* If we failed, break out, otherwise, go to the next BIOS block */
+        if (Status != STATUS_SUCCESS) break;
+        MdBlock++;
+    }
+
+    /* If anything failed until now, return error code */
+    if (Status != STATUS_SUCCESS) return Status;
+
+#ifdef _M_IX86
+    /* Set the top 16MB region as reserved */
+    Status = KiRosConfigureArcDescriptor(0xFC0, 0x1000, MemorySpecialMemory);
+    if (Status != STATUS_SUCCESS) return Status;
+
+    /* Setup the BIOS region as reserved */
+    KiRosConfigureArcDescriptor(0xA0, 0x100, LoaderMaximum);
+    KiRosConfigureArcDescriptor(BiosPage, 0x100, MemoryFirmwarePermanent);
+
+    /* Build an entry for the IVT */
+    Status = KiRosAllocateArcDescriptor(0, 1, MemoryFirmwarePermanent);
+    if (Status != STATUS_SUCCESS) return Status;
 #endif
 
-#define KSEG0_BASE 0x80000000
+    /* Build an entry for the KPCR and KUSER_SHARED_DATA */
+    Status = KiRosAllocateArcDescriptor(1, 3, LoaderStartupPcrPage);
+    if (Status != STATUS_SUCCESS) return Status;
+
+    /* Build an entry for the PDE and return the status */
+    Status = KiRosAllocateArcDescriptor(KeRosLoaderBlock->
+                                        PageDirectoryStart >> PAGE_SHIFT,
+                                        KeRosLoaderBlock->
+                                        PageDirectoryEnd >> PAGE_SHIFT,
+                                        LoaderMemoryData);
+    return Status;
+}
 
-/* FUNCTIONS *****************************************************************/
+VOID
+NTAPI
+KiRosBuildReservedMemoryMap(VOID)
+{
+    ULONG j;
+    ULONG BlockBegin, BlockEnd, BiasedPage;
+
+    /* Loop the BIOS Memory Map */
+    for (j = 0; j < KeMemoryMapRangeCount; j++)
+    {
+        /* Get the start and end addresses */
+        BlockBegin = KeMemoryMap[j].BaseAddrLow;
+        BlockEnd = BlockBegin + KeMemoryMap[j].LengthLow - 1;
+
+        /* Make sure it wasn't a > 4GB descriptor */
+        if (!KeMemoryMap[j].BaseAddrHigh)
+        {
+            /* Make sure it doesn't overflow */
+            if (BlockEnd < BlockBegin) BlockEnd = 0xFFFFFFFF;
+
+            /* Check if this was free memory */
+            if (KeMemoryMap[j].Type == 1)
+            {
+                /* Get the page-aligned addresses */
+                BiasedPage = BlockBegin & (PAGE_SIZE - 1);
+                BlockBegin >>= PAGE_SHIFT;
+                if (BiasedPage) BlockBegin++;
+                BlockEnd = (BlockEnd >> PAGE_SHIFT) + 1;
+
+                /* Check if the block is within the 16MB memory hole */
+                if ((BlockBegin < 0xFC0) && (BlockEnd >= 0xFC0))
+                {
+                    /* Don't allow it to cross this boundary */
+                    BlockBegin = 0xFC0;
+                }
+
+                /* Check if the boundary is across 16MB */
+                if ((BlockEnd > 0xFFF) && (BlockBegin <= 0xFFF))
+                {
+                    /* Don't let it cross */
+                    BlockEnd = 0xFFF;
+                }
+
+                /* Check if the block describes the memory hole */
+                if ((BlockBegin >= 0xFC0) && (BlockEnd <= 0xFFF))
+                {
+                    /* Set this region as temporary */
+                    KiRosConfigureArcDescriptor(BlockBegin,
+                                                BlockEnd,
+                                                MemoryFirmwareTemporary);
+                }
+            }
+            else
+            {
+                /* Get the page-aligned addresses */
+                BlockBegin >>= PAGE_SHIFT;
+                BiasedPage = (BlockEnd + 1) & (PAGE_SIZE - 1);
+                BlockEnd >>= PAGE_SHIFT;
+                if (BiasedPage) BlockEnd++;
+
+                /* Set this memory as reserved */
+                KiRosConfigureArcDescriptor(BlockBegin,
+                                            BlockEnd + 1,
+                                            MemorySpecialMemory);
+            }
+        }
+    }
+}
+
+VOID
+NTAPI
+KiRosInsertNtDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
+{
+    PLIST_ENTRY ListHead, PreviousEntry, NextEntry;
+    PMEMORY_ALLOCATION_DESCRIPTOR Descriptor = NULL, NextDescriptor = NULL;
+
+    /* Loop the memory descriptor list */
+    ListHead = &KeLoaderBlock->MemoryDescriptorListHead;
+    PreviousEntry = ListHead;
+    NextEntry = ListHead->Flink;
+    while (NextEntry != ListHead)
+    {
+        /* Get the current descriptor and check if it's below ours */
+        NextDescriptor = CONTAINING_RECORD(NextEntry,
+                                           MEMORY_ALLOCATION_DESCRIPTOR,
+                                           ListEntry);
+        if (NewDescriptor->BasePage < NextDescriptor->BasePage) break;
+
+        /* It isn't, save the previous entry and descriptor, and try again */
+        PreviousEntry = NextEntry;
+        Descriptor = NextDescriptor;
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* So we found the right spot to insert. Is this free memory? */
+    if (NewDescriptor->MemoryType != LoaderFree)
+    {
+        /* It isn't, so insert us before the last descriptor */
+        InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
+    }
+    else
+    {
+        /* We're free memory. Check if the entry we found is also free memory */
+        if ((PreviousEntry != ListHead) &&
+            ((Descriptor->MemoryType == LoaderFree) ||
+             (Descriptor->MemoryType == LoaderReserve)) &&
+            ((Descriptor->BasePage + Descriptor->PageCount) ==
+              NewDescriptor->BasePage))
+        {
+            /* It's free memory, and we're right after it. Enlarge that block */
+            Descriptor->PageCount += NewDescriptor->PageCount;
+            NewDescriptor = Descriptor;
+        }
+        else
+        {
+            /* Our range scan't be combined, so just insert us separately */
+            InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
+        }
+
+        /* Check if we merged with an existing free memory block */
+        if ((NextEntry != ListHead) &&
+            ((NextDescriptor->MemoryType == LoaderFree) ||
+             (NextDescriptor->MemoryType == LoaderReserve)) &&
+            ((NewDescriptor->BasePage + NewDescriptor->PageCount) ==
+              NextDescriptor->BasePage))
+        {
+            /* Update our own block */
+            NewDescriptor->PageCount += NextDescriptor->PageCount;
+
+            /* Remove the next block */
+            RemoveEntryList(&NextDescriptor->ListEntry);
+        }
+    }
+}
+
+NTSTATUS
+NTAPI
+KiRosBuildNtDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
+                       IN MEMORY_TYPE MemoryType,
+                       IN ULONG BasePage,
+                       IN ULONG PageCount)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR Descriptor, NextDescriptor = NULL;
+    LONG Delta;
+    TYPE_OF_MEMORY CurrentType;
+    BOOLEAN UseNext;
+
+    /* Check how many pages we'll be consuming */
+    Delta = BasePage - MemoryDescriptor->BasePage;
+    if (!(Delta) && (PageCount == MemoryDescriptor->PageCount))
+    {
+        /* We can simply convert the current descriptor into our new type */
+        MemoryDescriptor->MemoryType = MemoryType;
+    }
+    else
+    {
+        /* Get the current memory type of the descriptor, and reserve it */
+        CurrentType = MemoryDescriptor->MemoryType;
+        MemoryDescriptor->MemoryType = LoaderSpecialMemory;
+
+        /* Check if we'll need another descriptor for what's left of memory */
+        UseNext = ((BasePage != MemoryDescriptor->BasePage) &&
+                   (Delta + PageCount != MemoryDescriptor->PageCount));
+
+        /* Get a descriptor */
+        Descriptor = KiRosGetMdFromArray();
+        if (!Descriptor) return STATUS_INSUFFICIENT_RESOURCES;
+
+        /* Check if we are using another descriptor */
+        if (UseNext)
+        {
+            /* Allocate that one too */
+            NextDescriptor = KiRosGetMdFromArray();
+            if (!NextDescriptor) return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        /* Build the descriptor we got */
+        Descriptor->MemoryType = MemoryType;
+        Descriptor->BasePage = BasePage;
+        Descriptor->PageCount = PageCount;
+
+        /* Check if we're starting at the same place as the old one */
+        if (BasePage == MemoryDescriptor->BasePage)
+        {
+            /* Simply decrease the old descriptor and rebase it */
+            MemoryDescriptor->BasePage += PageCount;
+            MemoryDescriptor->PageCount -= PageCount;
+            MemoryDescriptor->MemoryType = CurrentType;
+        }
+        else if (Delta + PageCount == MemoryDescriptor->PageCount)
+        {
+            /* We finish where the old one did, shorten it */
+            MemoryDescriptor->PageCount -= PageCount;
+            MemoryDescriptor->MemoryType = CurrentType;
+        }
+        else
+        {
+            /* We're inside the current block, mark our free region */
+            NextDescriptor->MemoryType = LoaderFree;
+            NextDescriptor->BasePage = BasePage + PageCount;
+            NextDescriptor->PageCount = MemoryDescriptor->PageCount -
+                                        (PageCount + Delta);
+
+            /* And cut down the current descriptor */
+            MemoryDescriptor->PageCount = Delta;
+            MemoryDescriptor->MemoryType = CurrentType;
+
+            /* Finally, insert our new free descriptor into the list */
+            KiRosInsertNtDescriptor(NextDescriptor);
+        }
+
+        /* Insert the descriptor we allocated */
+        KiRosInsertNtDescriptor(Descriptor);
+    }
+
+    /* Return success */
+    return STATUS_SUCCESS;
+}
+
+PMEMORY_ALLOCATION_DESCRIPTOR
+NTAPI
+KiRosFindNtDescriptor(IN ULONG BasePage)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR MdBlock = NULL;
+    PLIST_ENTRY NextEntry, ListHead;
+
+    /* Scan the memory descriptor list */
+    ListHead = &KeLoaderBlock->MemoryDescriptorListHead;
+    NextEntry = ListHead->Flink;
+    while (NextEntry != ListHead)
+    {
+        /* Get the current descriptor */
+        MdBlock = CONTAINING_RECORD(NextEntry,
+                                    MEMORY_ALLOCATION_DESCRIPTOR,
+                                    ListEntry);
+
+        /* Check if it can contain our memory range */
+        if ((MdBlock->BasePage <= BasePage) &&
+            (MdBlock->BasePage + MdBlock->PageCount > BasePage))
+        {
+            /* It can, break out */
+            break;
+        }
+
+        /* Go to the next descriptor */
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Return the descriptor we found, if any */
+    return MdBlock;
+}
+
+NTSTATUS
+NTAPI
+KiRosAllocateNtDescriptor(IN TYPE_OF_MEMORY MemoryType,
+                          IN ULONG BasePage,
+                          IN ULONG PageCount,
+                          IN ULONG Alignment,
+                          OUT PULONG ReturnedBase)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
+    ULONG AlignedBase, AlignedLimit;
+    PMEMORY_ALLOCATION_DESCRIPTOR ActiveMdBlock;
+    ULONG ActiveAlignedBase = 0;
+    PLIST_ENTRY NextEntry, ListHead;
+
+    /* If no information was given, make some assumptions */
+    if (!Alignment) Alignment = 1;
+    if (!PageCount) PageCount = 1;
+
+    /* Start looking for a matching descvriptor */
+    do
+    {
+        /* Calculate the limit of the range */
+        AlignedLimit = PageCount + BasePage;
+
+        /* Find a descriptor that already contains our base address */
+        MdBlock = KiRosFindNtDescriptor(BasePage);
+
+        if (MdBlock)
+        {
+            /* If it contains our limit as well, break out early */
+            if ((MdBlock->PageCount + MdBlock->BasePage) >= AlignedLimit) break;
+        }
+
+        /* Loop the memory list */
+        ActiveMdBlock = NULL;
+        ListHead = &KeLoaderBlock->MemoryDescriptorListHead;
+        NextEntry = ListHead->Flink;
+        while (NextEntry != ListHead)
+        {
+            /* Get the current descriptors */
+            MdBlock = CONTAINING_RECORD(NextEntry,
+                                        MEMORY_ALLOCATION_DESCRIPTOR,
+                                        ListEntry);
+
+            /* Align the base address and our limit */
+            AlignedBase = (MdBlock->BasePage + (Alignment - 1)) &~ Alignment;
+            AlignedLimit = MdBlock->PageCount -
+                           AlignedBase +
+                           MdBlock->BasePage;
+
+            /* Check if this is a free block that can satisfy us */
+            if ((MdBlock->MemoryType == LoaderFree) &&
+                (AlignedLimit <= MdBlock->PageCount) &&
+                (PageCount <= AlignedLimit))
+            {
+                /* It is, stop searching */
+                ActiveMdBlock = MdBlock;
+                ActiveAlignedBase = AlignedBase;
+                break;
+            }
+
+            /* Try the next block */
+            NextEntry = NextEntry->Flink;
+        }
+
+        /* See if we came up with an adequate block */
+        if (ActiveMdBlock)
+        {
+            /* Generate a descriptor in it */
+            *ReturnedBase = AlignedBase;
+            return KiRosBuildNtDescriptor(ActiveMdBlock,
+                                          MemoryType,
+                                          ActiveAlignedBase,
+                                          PageCount);
+        }
+    } while (TRUE);
+
+    /* We found a matching block, generate a descriptor with it */
+    *ReturnedBase = BasePage;
+    return KiRosBuildNtDescriptor(MdBlock, MemoryType, BasePage, PageCount);
+}
+
+NTSTATUS
+NTAPI
+KiRosBuildArcMemoryList(VOID)
+{
+    PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+    MEMORY_DESCRIPTOR *Memory;
+    ULONG i;
+
+    /* Loop all BIOS Memory Descriptors */
+    for (i = 0; i < NumberDescriptors; i++)
+    {
+        /* Get the current descriptor */
+        Memory = &MDArray[i];
+
+        /* Allocate an NT Memory Descriptor */
+        Descriptor = KiRosGetMdFromArray();
+        if (!Descriptor) return ENOMEM;
+
+        /* Copy the memory type */
+        Descriptor->MemoryType = Memory->MemoryType;
+        if (Memory->MemoryType == MemoryFreeContiguous)
+        {
+            /* Convert this to free */
+            Descriptor->MemoryType = LoaderFree;
+        }
+        else if (Memory->MemoryType == MemorySpecialMemory)
+        {
+            /* Convert this to special memory */
+            Descriptor->MemoryType = LoaderSpecialMemory;
+        }
+
+        /* Copy the range data */
+        Descriptor->BasePage = Memory->BasePage;
+        Descriptor->PageCount = Memory->PageCount;
+
+        /* Insert the descriptor */
+        if (Descriptor->PageCount) KiRosInsertNtDescriptor(Descriptor);
+    }
+
+    /* All went well */
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+KiRosFixupComponentTree(IN PCONFIGURATION_COMPONENT_DATA p,
+                        IN ULONG_PTR i)
+{
+    PCONFIGURATION_COMPONENT pp;
+
+    /* Loop each entry */
+    while (p)
+    {
+        /* Grab the component entry */
+        pp = &p->ComponentEntry;
+        
+        /* Fixup the pointers */
+        if (pp->Identifier) pp->Identifier = (PVOID)((ULONG_PTR)pp->Identifier + i);
+        if (p->ConfigurationData) p->ConfigurationData = (PVOID)((ULONG_PTR)p->ConfigurationData + i);
+        if (p->Parent) p->Parent = (PVOID)((ULONG_PTR)p->Parent + i);
+        if (p->Sibling) p->Sibling = (PVOID)((ULONG_PTR)p->Sibling + i);
+        if (p->Child) p->Child = (PVOID)((ULONG_PTR)p->Child + i);
+        
+        /* Check if we have a child */
+        if (p->Child) KiRosFixupComponentTree(p->Child, i);
+        
+        /* Get to the next entry */
+        p = p->Sibling;
+    }
+}
 
 VOID
 NTAPI
@@ -67,27 +904,36 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock,
 {
     PLOADER_PARAMETER_BLOCK LoaderBlock;
     PLDR_DATA_TABLE_ENTRY LdrEntry;
-    PMEMORY_ALLOCATION_DESCRIPTOR MdEntry;
-    PLOADER_MODULE RosEntry;
+    PLOADER_MODULE RosEntry = NULL;
     ULONG i, j, ModSize;
     PVOID ModStart;
     PCHAR DriverName;
     PCHAR BootPath, HalPath;
     CHAR CommandLine[256];
+    PARC_DISK_SIGNATURE RosDiskInfo, ArcDiskInfo;
+    PIMAGE_NT_HEADERS NtHeader;
+    WCHAR PathToDrivers[] = L"\\SystemRoot\\System32\\drivers\\";
+    WCHAR PathToSystem32[] = L"\\SystemRoot\\System32\\";
+    WCHAR PathSetup[] = L"\\SystemRoot\\";
+    CHAR DriverNameLow[256];
+    ULONG Base;
+#ifdef _M_PPC
+    ULONG KernelBase = RosLoaderBlock->ModsAddr[0].ModStart;
+#endif
 
     /* First get some kernel-loader globals */
     AcpiTableDetected = (RosLoaderBlock->Flags & MB_FLAGS_ACPI_TABLE) ? TRUE : FALSE;
-    MmFreeLdrMemHigher = RosLoaderBlock->MemHigher;
-    MmFreeLdrPageDirectoryEnd = RosLoaderBlock->PageDirectoryEnd;
-    KeLoaderModuleCount = RosLoaderBlock->ModsCount;
 
     /* Set the NT Loader block and initialize it */
-    *NtLoaderBlock = LoaderBlock = &BldrLoaderBlock;
+    *NtLoaderBlock = KeLoaderBlock = LoaderBlock = &BldrLoaderBlock;
     RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
 
     /* Set the NLS Data block */
     LoaderBlock->NlsData = &BldrNlsDataBlock;
 
+    /* Set the ARC Data block */
+    LoaderBlock->ArcDiskInformation = &BldrArcDiskInfo;
+
     /* Assume this is from FreeLDR's SetupLdr */
     LoaderBlock->SetupLdrBlock = &BldrSetupBlock;
 
@@ -95,57 +941,73 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock,
     InitializeListHead(&LoaderBlock->LoadOrderListHead);
     InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);
     InitializeListHead(&LoaderBlock->BootDriverListHead);
+    InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
+
+    /* Build the free memory map, which uses BIOS Descriptors */
+    KiRosBuildBiosMemoryMap();
+
+    /* Build entries for ReactOS memory ranges, which uses ARC Descriptors */
+    KiRosBuildOsMemoryMap();
+
+#if defined(_M_IX86) || defined(_M_AMD64)
+    /* Build entries for the reserved map, which uses ARC Descriptors */
+    KiRosBuildReservedMemoryMap();
+#endif
+
+    /* Now convert the BIOS and ARC Descriptors into NT Memory Descirptors */
+    KiRosBuildArcMemoryList();
 
     /* Loop boot driver list */
-    for (i = 0; i < KeLoaderModuleCount; i++)
+    for (i = 0; i < RosLoaderBlock->ModsCount; i++)
     {
         /* Get the ROS loader entry */
-        RosEntry = &KeLoaderModules[i];
+        RosEntry = &RosLoaderBlock->ModsAddr[i];
         DriverName = (PCHAR)RosEntry->String;
         ModStart = (PVOID)RosEntry->ModStart;
         ModSize = RosEntry->ModEnd - (ULONG_PTR)ModStart;
 
+#ifdef _M_PPC
+        ModStart -= KernelBase;
+#endif
+
         /* Check if this is any of the NLS files */
         if (!_stricmp(DriverName, "ansi.nls"))
         {
             /* ANSI Code page */
-            LoaderBlock->NlsData->AnsiCodePageData = ModStart;
+            LoaderBlock->NlsData->AnsiCodePageData = KERNEL_RVA(ModStart);
 
             /* Create an MD for it */
-            MdEntry = &BldrMemoryDescriptors[i];
-            MdEntry->MemoryType = LoaderNlsData;
-            MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT;
-            MdEntry->PageCount = ModSize >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderNlsData,
+                                      KERNEL_DESCRIPTOR_PAGE(ModStart),
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
             continue;
         }
         else if (!_stricmp(DriverName, "oem.nls"))
         {
             /* OEM Code page */
-            LoaderBlock->NlsData->OemCodePageData = ModStart;
+            LoaderBlock->NlsData->OemCodePageData = KERNEL_RVA(ModStart);
 
             /* Create an MD for it */
-            MdEntry = &BldrMemoryDescriptors[i];
-            MdEntry->MemoryType = LoaderNlsData;
-            MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT;
-            MdEntry->PageCount = ModSize >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderNlsData,
+                                      KERNEL_DESCRIPTOR_PAGE(ModStart),
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
             continue;
         }
         else if (!_stricmp(DriverName, "casemap.nls"))
         {
             /* Unicode Code page */
-            LoaderBlock->NlsData->UnicodeCodePageData = ModStart;
+            LoaderBlock->NlsData->UnicodeCodePageData = KERNEL_RVA(ModStart);
 
             /* Create an MD for it */
-            MdEntry = &BldrMemoryDescriptors[i];
-            MdEntry->MemoryType = LoaderNlsData;
-            MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT;
-            MdEntry->PageCount = ModSize >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderNlsData,
+                                      KERNEL_DESCRIPTOR_PAGE(ModStart),
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
             continue;
         }
 
@@ -154,19 +1016,18 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock,
             !(_stricmp(DriverName, "system.hiv")))
         {
             /* Save registry data */
-            LoaderBlock->RegistryBase = ModStart;
+            LoaderBlock->RegistryBase = KERNEL_RVA(ModStart);
             LoaderBlock->RegistryLength = ModSize;
 
             /* Disable setup mode */
             LoaderBlock->SetupLdrBlock = NULL;
 
             /* Create an MD for it */
-            MdEntry = &BldrMemoryDescriptors[i];
-            MdEntry->MemoryType = LoaderRegistryData;
-            MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT;
-            MdEntry->PageCount = ModSize >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderRegistryData,
+                                      KERNEL_DESCRIPTOR_PAGE(ModStart),
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
             continue;
         }
 
@@ -175,15 +1036,51 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock,
             !(_stricmp(DriverName, "hardware.hiv")))
         {
             /* Create an MD for it */
-            MdEntry = &BldrMemoryDescriptors[i];
-            MdEntry->MemoryType = LoaderRegistryData;
-            MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT;
-            MdEntry->PageCount = ModSize >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
+            KiRosAllocateNtDescriptor(LoaderRegistryData,
+                                      KERNEL_DESCRIPTOR_PAGE(ModStart),
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
             continue;
         }
 
+        /* Check if this is the kernel */
+        if (!(_stricmp(DriverName, "ntoskrnl.exe")))
+        {
+            /* Create an MD for it */
+            KiRosAllocateNtDescriptor(LoaderSystemCode,
+                                      KERNEL_DESCRIPTOR_PAGE(ModStart),
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
+        }
+        else if (!(_stricmp(DriverName, "hal.dll")))
+        {
+            /* Create an MD for the HAL */
+            KiRosAllocateNtDescriptor(LoaderHalCode,
+                                      KERNEL_DESCRIPTOR_PAGE(ModStart),
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
+        }
+        else
+        {
+            /* Create an MD for any driver */
+            KiRosAllocateNtDescriptor(LoaderBootDriver,
+                                      KERNEL_DESCRIPTOR_PAGE(ModStart),
+                                      (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
+                                      0,
+                                      &Base);
+        }
+
+#ifdef _M_PPC
+        ModStart += 0x80800000;
+#endif
+
+        /* Lowercase the drivername so we can check its extension later */
+        strcpy(DriverNameLow, DriverName);
+        _strlwr(DriverNameLow);
+
         /* Setup the loader entry */
         LdrEntry = &BldrModules[i];
         RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
@@ -196,12 +1093,46 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock,
 
         /* Setup driver name */
         RtlInitUnicodeString(&LdrEntry->BaseDllName, BldrModuleStrings[i]);
-        RtlInitUnicodeString(&LdrEntry->FullDllName, BldrModuleStrings[i]);
+
+        /* Construct a correct full name */
+        BldrModuleStringsFull[i][0] = 0;
+        LdrEntry->FullDllName.MaximumLength = 260 * sizeof(WCHAR);
+        LdrEntry->FullDllName.Length = 0;
+        LdrEntry->FullDllName.Buffer = BldrModuleStringsFull[i];
+
+        /* Guess the path */
+        if (LoaderBlock->SetupLdrBlock)
+        {
+            UNICODE_STRING TempString;
+            RtlInitUnicodeString(&TempString, PathSetup);
+            RtlAppendUnicodeStringToString(&LdrEntry->FullDllName, &TempString);
+        }
+        else if (strstr(DriverNameLow, ".dll") || strstr(DriverNameLow, ".exe"))
+        {
+            UNICODE_STRING TempString;
+            RtlInitUnicodeString(&TempString, PathToSystem32);
+            RtlAppendUnicodeStringToString(&LdrEntry->FullDllName, &TempString);
+        }
+        else /* .sys */
+        {
+            UNICODE_STRING TempString;
+            RtlInitUnicodeString(&TempString, PathToDrivers);
+            RtlAppendUnicodeStringToString(&LdrEntry->FullDllName, &TempString);
+        }
+
+        /* Append base name of the driver */
+        RtlAppendUnicodeStringToString(&LdrEntry->FullDllName, &LdrEntry->BaseDllName);
 
         /* Copy data from Freeldr Module Entry */
         LdrEntry->DllBase = ModStart;
         LdrEntry->SizeOfImage = ModSize;
 
+        /* Copy additional data */
+        NtHeader = RtlImageNtHeader(ModStart);
+        LdrEntry->EntryPoint = RVA(ModStart,
+                                   NtHeader->
+                                   OptionalHeader.AddressOfEntryPoint);
+
         /* Initialize other data */
         LdrEntry->LoadCount = 1;
         LdrEntry->Flags = LDRP_IMAGE_DLL |
@@ -211,46 +1142,34 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock,
         /* Insert it into the loader block */
         InsertTailList(&LoaderBlock->LoadOrderListHead,
                        &LdrEntry->InLoadOrderLinks);
-
-        /* Check if this is the kernel */
-        if (!(_stricmp(DriverName, "ntoskrnl.exe")))
-        {
-            /* Create an MD for it */
-            MdEntry = &BldrMemoryDescriptors[i];
-            MdEntry->MemoryType = LoaderSystemCode;
-            MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT;
-            MdEntry->PageCount = ModSize >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
-        }
-        else if (!(_stricmp(DriverName, "hal.dll")))
-        {
-            /* The HAL actually gets loaded somewhere else */
-            ModStart = HalModuleObject.DllBase;
-
-            /* Create an MD for the HAL */
-            MdEntry = &BldrMemoryDescriptors[i];
-            MdEntry->MemoryType = LoaderHalCode;
-            MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT;
-            MdEntry->PageCount = ModSize >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
-        }
-        else
-        {
-            /* Create an MD for any driver */
-            MdEntry = &BldrMemoryDescriptors[i];
-            MdEntry->MemoryType = LoaderBootDriver;
-            MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT;
-            MdEntry->PageCount = ModSize >> PAGE_SHIFT;
-            InsertTailList(&LoaderBlock->MemoryDescriptorListHead,
-                           &MdEntry->ListEntry);
-        }
+    }
+    
+    /* Now mark the remainder of the FreeLDR 6MB area as "in use" */
+    KiRosAllocateNtDescriptor(LoaderMemoryData,
+                              KERNEL_DESCRIPTOR_PAGE(RosEntry->ModEnd),
+                              KERNEL_DESCRIPTOR_PAGE((RosLoaderBlock->KernelBase + 0x600000)) -
+                              KERNEL_DESCRIPTOR_PAGE(RosEntry->ModEnd),
+                              0,
+                              &Base);
+    
+    //
+    // Check if we have a ramdisk
+    //
+    if ((RosLoaderBlock->RdAddr) && (RosLoaderBlock->RdLength))
+    {
+        //
+        // Build a descriptor for it
+        //
+        KiRosAllocateNtDescriptor(LoaderXIPRom,
+                                  KERNEL_DESCRIPTOR_PAGE(RosLoaderBlock->RdAddr),
+                                  (RosLoaderBlock->RdLength + PAGE_SIZE - 1) >> PAGE_SHIFT,
+                                  0,
+                                  &Base);
     }
 
     /* Setup command line */
     LoaderBlock->LoadOptions = BldrCommandLine;
-    strcpy(BldrCommandLine, KeLoaderCommandLine);
+    strcpy(BldrCommandLine, RosLoaderBlock->CommandLine);
 
     /* Setup the extension block */
     LoaderBlock->Extension = &BldrExtensionBlock;
@@ -258,11 +1177,23 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock,
     LoaderBlock->Extension->MajorVersion = 5;
     LoaderBlock->Extension->MinorVersion = 2;
 
+
+// FIXME FIXME FIXME NOW!!!!
+
+    /* FreeLDR hackllocates 1536 static pages for the initial boot images */
+    LoaderBlock->Extension->LoaderPagesSpanned = 1536 * PAGE_SIZE;
+
+    /* ReactOS always boots the kernel at 0x80800000 (just like NT 5.2) */
+    LoaderBlock->Extension->LoaderPagesSpanned += 0x80800000 - KSEG0_BASE;
+
+    /* Now convert to pages */
+    LoaderBlock->Extension->LoaderPagesSpanned /= PAGE_SIZE;
+
     /* Now setup the setup block if we have one */
     if (LoaderBlock->SetupLdrBlock)
     {
         /* All we'll setup right now is the flag for text-mode setup */
-        LoaderBlock->SetupLdrBlock->Flags = 1;
+        LoaderBlock->SetupLdrBlock->Flags = SETUPLDR_TEXT_MODE;
     }
 
     /* Make a copy of the command line */
@@ -294,44 +1225,57 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock,
     /* Parse it and change every slash to a space */
     BootPath = LoaderBlock->LoadOptions;
     do {if (*BootPath == '/') *BootPath = ' ';} while (*BootPath++);
+
+    /* Now let's loop ARC disk information */
+    for (i = 0; i < RosLoaderBlock->DrivesCount; i++)
+    {
+        /* Get the ROS loader entry */
+        RosDiskInfo = &RosLoaderBlock->DrivesAddr[i];
+
+        /* Get the ARC structure */
+        ArcDiskInfo = &BldrDiskInfo[i];
+
+        /* Copy the data over */
+        ArcDiskInfo->Signature = RosDiskInfo->Signature;
+        ArcDiskInfo->CheckSum = RosDiskInfo->CheckSum;
+
+        /* Copy the ARC Name */
+        strcpy(BldrArcNames[i], RosDiskInfo->ArcName);
+        ArcDiskInfo->ArcName = BldrArcNames[i];
+
+        /* Insert into the list */
+        InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead,
+                       &ArcDiskInfo->ListEntry);
+    }
+
+    /* Copy the ARC Hardware Tree */
+    RtlCopyMemory(BldrArcHwBuffer, (PVOID)RosLoaderBlock->ArchExtra, 16 * 1024);
+    LoaderBlock->ConfigurationRoot = (PVOID)BldrArcHwBuffer;
+
+    /* Apply fixups */
+    KiRosFixupComponentTree(LoaderBlock->ConfigurationRoot,
+                            (ULONG_PTR)BldrArcHwBuffer -
+                            RosLoaderBlock->ArchExtra);
 }
 
+VOID
+NTAPI
+KiSetupSyscallHandler();
+
 VOID
 FASTCALL
 KiRosPrepareForSystemStartup(IN ULONG Dummy,
                              IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock)
 {
-    ULONG i;
-    ULONG size;
-    ULONG StartKernelBase;
-    ULONG HalBase;
-    ULONG DriverBase;
-    ULONG DriverSize;
     PLOADER_PARAMETER_BLOCK NtLoaderBlock;
-    CHAR* s;
-#ifdef _M_IX86
+    ULONG size, i = 0, *ent;
+#if defined(_M_IX86)
     PKTSS Tss;
     PKGDTENTRY TssEntry;
-#endif
-#ifdef _M_PPC
-    { 
-       __asm__("ori 0,0,0");
-       char *nk = "ntoskrnl is here";
-       boot_infos_t *XBootInfo = (boot_infos_t *)LoaderBlock->ArchExtra;
-       memcpy(&PpcEarlybootInfo, XBootInfo, sizeof(PpcEarlybootInfo));
-       PpcEarlybootInfo.dispFont = BootDigits;
-       BootInfo = (struct _boot_infos_t *)&PpcEarlybootInfo;
-       DrawNumber(BootInfo, 0x1234abcd, 10, 100);
-       DrawNumber(BootInfo, (ULONG)nk, 10 , 150);
-       DrawString(BootInfo, nk, 100, 150);
-       __asm__("ori 0,0,0");
-    }
-#endif
 
-#ifdef _M_IX86
     /* Load the GDT and IDT */
-    Ke386SetGlobalDescriptorTable(KiGdtDescriptor);
-    Ke386SetInterruptDescriptorTable(KiIdtDescriptor);
+    Ke386SetGlobalDescriptorTable(*(PKDESCRIPTOR)&KiGdtDescriptor.Limit);
+    Ke386SetInterruptDescriptorTable(*(PKDESCRIPTOR)&KiIdtDescriptor.Limit);
 
     /* Initialize the boot TSS */
     Tss = &KiBootTss;
@@ -344,30 +1288,39 @@ KiRosPrepareForSystemStartup(IN ULONG Dummy,
     TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24);
 #endif
 
-    DrawNumber(BootInfo, 0xb0071f03, 190, 90);
-    DrawNumber(BootInfo, (ULONG)BootInfo, 190, 100);
+#if defined(_M_PPC)
+    // Zero bats.  We might have residual bats set that will interfere with
+    // our mapping of ofwldr.
+    for (i = 0; i < 4; i++)
+    {
+        SetBat(i, 0, 0, 0); SetBat(i, 1, 0, 0);
+    }
+    KiSetupSyscallHandler();
+    DbgPrint("Kernel Power (%08x)\n", LoaderBlock);
+    DbgPrint("ArchExtra (%08x)!\n", LoaderBlock->ArchExtra);
+#endif
+
+    /* Save pointer to ROS Block */
+    KeRosLoaderBlock = LoaderBlock;
 
-    /* Copy the Loader Block Data locally since Low-Memory will be wiped */
-    memcpy(&KeRosLoaderBlock, LoaderBlock, sizeof(ROS_LOADER_PARAMETER_BLOCK));
-    memcpy(&KeLoaderModules[0],
-           (PVOID)KeRosLoaderBlock.ModsAddr,
-           sizeof(LOADER_MODULE) * KeRosLoaderBlock.ModsCount);
-    KeRosLoaderBlock.ModsAddr = (ULONG)&KeLoaderModules;
+    /* Get debugging function */
+    FrLdrDbgPrint = LoaderBlock->FrLdrDbgPrint;
 
-    /* Check for BIOS memory map */
+    /* Save memory manager data */
     KeMemoryMapRangeCount = 0;
-    if (KeRosLoaderBlock.Flags & MB_FLAGS_MMAP_INFO)
+    if (LoaderBlock->Flags & MB_FLAGS_MMAP_INFO)
     {
         /* We have a memory map from the nice BIOS */
-        size = *((PULONG)(KeRosLoaderBlock.MmapAddr - sizeof(ULONG)));
+        ent = ((PULONG)(LoaderBlock->MmapAddr - sizeof(ULONG))); // FIXME: this is ugly
+        size = *ent;
         i = 0;
 
         /* Map it until we run out of size */
-        while (i < KeRosLoaderBlock.MmapLength)
+        while (i < LoaderBlock->MmapLength)
         {
             /* Copy into the Kernel Memory Map */
             memcpy (&KeMemoryMap[KeMemoryMapRangeCount],
-                    (PVOID)(KeRosLoaderBlock.MmapAddr + i),
+                    (PVOID)(LoaderBlock->MmapAddr + i),
                     sizeof(ADDRESS_RANGE));
 
             /* Increase Memory Map Count */
@@ -378,139 +1331,25 @@ KiRosPrepareForSystemStartup(IN ULONG Dummy,
         }
 
         /* Save data */
-        KeRosLoaderBlock.MmapLength = KeMemoryMapRangeCount *
-                                   sizeof(ADDRESS_RANGE);
-        KeRosLoaderBlock.MmapAddr = (ULONG)KeMemoryMap;
+        LoaderBlock->MmapLength = KeMemoryMapRangeCount * sizeof(ADDRESS_RANGE);
+        LoaderBlock->MmapAddr = (ULONG_PTR)KeMemoryMap;
     }
     else
     {
         /* Nothing from BIOS */
-        KeRosLoaderBlock.MmapLength = 0;
-        KeRosLoaderBlock.MmapAddr = (ULONG)KeMemoryMap;
+        LoaderBlock->MmapLength = 0;
+        LoaderBlock->MmapAddr = (ULONG_PTR)KeMemoryMap;
     }
 
-    /* Save the Base Address */
-    MmSystemRangeStart = (PVOID)KeRosLoaderBlock.KernelBase;
-
-    /* Set the Command Line */
-    strcpy(KeLoaderCommandLine, (PCHAR)LoaderBlock->CommandLine);
-    KeRosLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine;
-
-    /* Get the address of ntoskrnl in openfirmware memory */
-    StartKernelBase = KeLoaderModules[0].ModStart;
-
-    /* Create a block for each module */
-    for (i = 0; i < KeRosLoaderBlock.ModsCount; i++)
-    {
-        /* Check if we have to copy the path or not */
-        if ((s = strrchr((PCHAR)KeLoaderModules[i].String, '/')) != 0)
-        {
-            strcpy(KeLoaderModuleStrings[i], s + 1);
-        }
-        else
-        {
-            strcpy(KeLoaderModuleStrings[i], (PCHAR)KeLoaderModules[i].String);
-        }
-
-#ifdef _M_PPC
-       if(i == 0) {
-           DrawNumber(BootInfo, KeLoaderModules[i].ModStart, 10, 200);
-           DrawNumber(BootInfo, KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart, 100, 200);
-           DrawNumber(BootInfo, KeLoaderModules[i].ModEnd, 190, 200);
-           DrawNumber(BootInfo, KeLoaderModules[i+1].ModStart, 10, 210);
-           DrawNumber(BootInfo, KeLoaderModules[i+1].ModEnd - KeLoaderModules[i+1].ModStart, 100, 210);
-           DrawNumber(BootInfo, KeLoaderModules[i+1].ModEnd, 190, 210);
-       }
-       KeLoaderModules[i].ModStart += KSEG0_BASE - StartKernelBase;
-       KeLoaderModules[i].ModEnd   += KSEG0_BASE - StartKernelBase;
-#else
-        /* Substract the base Address in Physical Memory */
-        KeLoaderModules[i].ModStart -= 0x200000;
-
-        /* Add the Kernel Base Address in Virtual Memory */
-        KeLoaderModules[i].ModStart += KSEG0_BASE;
-
-        /* Substract the base Address in Physical Memory */
-        KeLoaderModules[i].ModEnd -= 0x200000;
-
-        /* Add the Kernel Base Address in Virtual Memory */
-        KeLoaderModules[i].ModEnd += KSEG0_BASE;
-#endif
-
-        /* Select the proper String */
-        KeLoaderModules[i].String = (ULONG)KeLoaderModuleStrings[i];
-    }
-
-    /* Choose last module address as the final kernel address */
-    MmFreeLdrLastKernelAddress =
-        PAGE_ROUND_UP(KeLoaderModules[KeRosLoaderBlock.ModsCount - 1].ModEnd);
-
-#ifndef _M_PPC
-    /* Select the HAL Base */
-    HalBase = KeLoaderModules[1].ModStart;
-
-    /* Choose Driver Base */
-    DriverBase = MmFreeLdrLastKernelAddress;
-    LdrHalBase = (ULONG_PTR)DriverBase;
-#else
-    HalBase = KeLoaderModules[1].ModStart;
-    DriverBase = MmFreeLdrLastKernelAddress;
-    LdrHalBase = KeLoaderModules[1].ModStart;
-#endif
-
-    /* Initialize Module Management */
-    LdrInitModuleManagement((PVOID)KeLoaderModules[0].ModStart);
-
-    /* Load HAL.DLL with the PE Loader */
-    LdrSafePEProcessModule((PVOID)HalBase,
-                            (PVOID)DriverBase,
-                            (PVOID)KeLoaderModules[0].ModStart,
-                            &DriverSize);
-
-    //
-    //
-    // HACK HACK HACK WHEN WILL YOU PEOPLE FIX FREELDR?!?!?!
-    // FREELDR SENDS US AN ***INVALID*** HAL PE HEADER!!!
-    // WE READ IT IN LdrInitModuleManagement ABOVE!!!
-    // WE SET .SizeOfImage TO A *GARBAGE* VALUE!!!
-    //
-    // This dirty hack fixes it, and should make symbol lookup work too.
-    //
-    HalModuleObject.SizeOfImage =  RtlImageNtHeader((PVOID)HalModuleObject.
-                                                    DllBase)->
-                                                    OptionalHeader.SizeOfImage;
-
-    /* Increase the last kernel address with the size of HAL */
-    MmFreeLdrLastKernelAddress += PAGE_ROUND_UP(DriverSize);
-
-#ifdef _M_IX86
-    /* Now select the final beginning and ending Kernel Addresses */
-    MmFreeLdrFirstKrnlPhysAddr = KeLoaderModules[0].ModStart -
-                                 KSEG0_BASE + 0x200000;
-    MmFreeLdrLastKrnlPhysAddr = MmFreeLdrLastKernelAddress -
-                                KSEG0_BASE + 0x200000;
-#endif
-
-    /* Setup the IDT */
-    KeInitExceptions(); // ONCE HACK BELOW IS GONE, MOVE TO KISYSTEMSTARTUP!
-    KeInitInterrupts(); // ROS HACK DEPRECATED SOON BY NEW HAL
-
-    /* Load the Kernel with the PE Loader */
-    LdrSafePEProcessModule((PVOID)KeLoaderModules[0].ModStart,
-                           (PVOID)KeLoaderModules[0].ModStart,
-                           (PVOID)DriverBase,
-                           &DriverSize);
+    /* Convert the loader block */
+    KiRosFrldrLpbToNtLpb(KeRosLoaderBlock, &NtLoaderBlock);
 
-    /* Sets up the VDM Data */
-#ifdef _M_IX86
-    NtEarlyInitVdm();
+#if defined(_M_PPC)
+    DbgPrint("Finished KiRosFrldrLpbToNtLpb\n");
 #endif
 
-    /* Convert the loader block */
-    KiRosFrldrLpbToNtLpb(&KeRosLoaderBlock, &NtLoaderBlock);
-
     /* Do general System Startup */
-    KiSystemStartup(NtLoaderBlock);
+    KiSystemStartupReal(NtLoaderBlock);
 }
 
 /* EOF */