- Sync up Mm interface with WinLdr branch (introduce the concept of a memory type...
authorAleksey Bragin <aleksey@reactos.org>
Sun, 13 Jan 2008 12:53:49 +0000 (12:53 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Sun, 13 Jan 2008 12:53:49 +0000 (12:53 +0000)
- Copy winldr's files from the branch, with the only #ifdef WHEN_MERGE_COMPLETE hack.

svn path=/trunk/; revision=31755

1  2 
reactos/boot/freeldr/freeldr/arch/i386/loader.c
reactos/boot/freeldr/freeldr/include/mm.h
reactos/boot/freeldr/freeldr/include/winldr.h
reactos/boot/freeldr/freeldr/linuxboot.c
reactos/boot/freeldr/freeldr/mm/meminit.c
reactos/boot/freeldr/freeldr/mm/mm.c
reactos/boot/freeldr/freeldr/windows/conversion.c
reactos/boot/freeldr/freeldr/windows/peloader.c
reactos/boot/freeldr/freeldr/windows/winldr.c
reactos/boot/freeldr/freeldr/windows/wlmemory.c
reactos/boot/freeldr/freeldr/windows/wlregistry.c

index f538c02,0000000..4bd7d07
mode 100644,000000..100644
--- /dev/null
@@@ -1,744 -1,0 +1,744 @@@
-     LoadBase = MmAllocateMemoryAtAddress(DriverSize, LoadBase);
 +/*
 + *  FreeLoader
 + *  Copyright (C) 1998-2003  Brian Palmer  <brianp@sginet.com>
 + *  Copyright (C) 2005       Alex Ionescu  <alex@relsoft.net>
 + *
 + *  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
 + *  the Free Software Foundation; either version 2 of the License, or
 + *  (at your option) any later version.
 + *
 + *  This program is distributed in the hope that it will be useful,
 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + *  GNU General Public License for more details.
 + *
 + *  You should have received a copy of the GNU General Public License
 + *  along with this program; if not, write to the Free Software
 + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + */
 +#define _NTSYSTEM_
 +#include <freeldr.h>
 +
 +#define NDEBUG
 +#include <debug.h>
 +#undef DbgPrint
 +
 +/* Load Address of Next Module */
 +ULONG_PTR NextModuleBase = KERNEL_BASE_PHYS;
 +
 +/* Currently Opened Module */
 +PLOADER_MODULE CurrentModule = NULL;
 +
 +/* Unrelocated Kernel Base in Virtual Memory */
 +ULONG_PTR KernelBase;
 +
 +/* Kernel Entrypoint in Virtual Memory */
 +ROS_KERNEL_ENTRY_POINT KernelEntryPoint;
 +
 +/* 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;
 +
 +PVOID
 +NTAPI
 +LdrPEGetExportByName(PVOID BaseAddress,
 +                     PUCHAR SymbolName,
 +                     USHORT Hint);
 +
 +/* FUNCTIONS *****************************************************************/
 +
 +/*++
 + * FrLdrStartup
 + * INTERNAL
 + *
 + *     Prepares the system for loading the Kernel.
 + *
 + * Params:
 + *     Magic - Multiboot Magic
 + *
 + * Returns:
 + *     None.
 + *
 + * Remarks:
 + *     None.
 + *
 + *--*/
 +VOID
 +NTAPI
 +FrLdrStartup(ULONG Magic)
 +{
 +    /* Disable Interrupts */
 +    _disable();
 +
 +    /* Re-initalize EFLAGS */
 +    Ke386EraseFlags();
 +
 +    /* Initialize the page directory */
 +    FrLdrSetupPageDirectory();
 +
 +    /* Initialize Paging, Write-Protection and Load NTOSKRNL */
 +    FrLdrSetupPae(Magic);
 +}
 +
 +/*++
 + * 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)
 +{
 +    ULONG_PTR PageDirectoryBaseAddress = (ULONG_PTR)&startup_pagedirectory;
 +
 +    /* Set the PDBR */
 +    __writecr3(PageDirectoryBaseAddress);
 +
 +    /* Enable Paging and Write Protect*/
 +    __writecr0(__readcr0() | X86_CR0_PG | X86_CR0_WP);
 +
 +    /* Jump to Kernel */
 +    (*KernelEntryPoint)(Magic, &LoaderBlock);
 +}
 +
 +/*++
 + * FrLdrSetupPageDirectory
 + * INTERNAL
 + *
 + *     Sets up the ReactOS Startup Page Directory.
 + *
 + * Params:
 + *     None.
 + *
 + * 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)
 +{
 +    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;
 +}
 +
 +PLOADER_MODULE
 +NTAPI
 +LdrGetModuleObject(PCHAR ModuleName)
 +{
 +    ULONG i;
 +
 +    for (i = 0; i < LoaderBlock.ModsCount; i++)
 +    {
 +        if (strstr(_strupr((PCHAR)reactos_modules[i].String), _strupr(ModuleName)))
 +        {
 +            return &reactos_modules[i];
 +        }
 +    }
 +
 +    return NULL;
 +}
 +
 +PVOID
 +NTAPI
 +LdrPEFixupForward(IN PCHAR ForwardName)
 +{
 +    CHAR NameBuffer[128];
 +    PCHAR p;
 +    PLOADER_MODULE ModuleObject;
 +
 +    strcpy(NameBuffer, ForwardName);
 +    p = strchr(NameBuffer, '.');
 +    if (p == NULL) return NULL;
 +    *p = 0;
 +
 +    ModuleObject = LdrGetModuleObject(NameBuffer);
 +    if (!ModuleObject)
 +    {
 +        DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
 +        return NULL;
 +    }
 +
 +    return LdrPEGetExportByName((PVOID)ModuleObject->ModStart, (PUCHAR)(p + 1), 0xffff);
 +}
 +
 +PVOID
 +NTAPI
 +LdrPEGetExportByName(PVOID BaseAddress,
 +                     PUCHAR SymbolName,
 +                     USHORT Hint)
 +{
 +    PIMAGE_EXPORT_DIRECTORY ExportDir;
 +    PULONG * ExFunctions;
 +    PULONG * ExNames;
 +    USHORT * ExOrdinals;
 +    PVOID ExName;
 +    ULONG Ordinal;
 +    PVOID Function;
 +    LONG minn, maxn, mid, res;
 +    ULONG ExportDirSize;
 +
 +    /* HAL and NTOS use a virtual address, switch it to physical mode */
 +    if ((ULONG_PTR)BaseAddress & KSEG0_BASE)
 +    {
 +        BaseAddress = RVA(BaseAddress, -KSEG0_BASE);
 +    }
 +
 +    ExportDir = (PIMAGE_EXPORT_DIRECTORY)
 +        RtlImageDirectoryEntryToData(BaseAddress,
 +                                     TRUE,
 +                                     IMAGE_DIRECTORY_ENTRY_EXPORT,
 +                                     &ExportDirSize);
 +    if (!ExportDir)
 +    {
 +        DbgPrint("LdrPEGetExportByName(): no export directory!\n");
 +        return NULL;
 +    }
 +
 +    /* The symbol names may be missing entirely */
 +    if (!ExportDir->AddressOfNames)
 +    {
 +        DbgPrint("LdrPEGetExportByName(): symbol names missing entirely\n");
 +        return NULL;
 +    }
 +
 +    /*
 +    * Get header pointers
 +    */
 +    ExNames = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfNames);
 +    ExOrdinals = (USHORT *)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
 +    ExFunctions = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfFunctions);
 +
 +    /*
 +    * Check the hint first
 +    */
 +    if (Hint < ExportDir->NumberOfNames)
 +    {
 +        ExName = RVA(BaseAddress, ExNames[Hint]);
 +        if (strcmp(ExName, (PCHAR)SymbolName) == 0)
 +        {
 +            Ordinal = ExOrdinals[Hint];
 +            Function = RVA(BaseAddress, ExFunctions[Ordinal]);
 +            if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
 +                (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
 +            {
 +                Function = LdrPEFixupForward((PCHAR)Function);
 +                if (Function == NULL)
 +                {
 +                    DbgPrint("LdrPEGetExportByName(): failed to find %s\n", Function);
 +                }
 +                return Function;
 +            }
 +
 +            if (Function != NULL) return Function;
 +        }
 +    }
 +
 +    /*
 +    * Binary search
 +    */
 +    minn = 0;
 +    maxn = ExportDir->NumberOfNames - 1;
 +    while (minn <= maxn)
 +    {
 +        mid = (minn + maxn) / 2;
 +
 +        ExName = RVA(BaseAddress, ExNames[mid]);
 +        res = strcmp(ExName, (PCHAR)SymbolName);
 +        if (res == 0)
 +        {
 +            Ordinal = ExOrdinals[mid];
 +            Function = RVA(BaseAddress, ExFunctions[Ordinal]);
 +            if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
 +                (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
 +            {
 +                Function = LdrPEFixupForward((PCHAR)Function);
 +                if (Function == NULL)
 +                {
 +                    DbgPrint("1: failed to find %s\n", Function);
 +                }
 +                return Function;
 +            }
 +            if (Function != NULL)
 +            {
 +                return Function;
 +            }
 +        }
 +        else if (res > 0)
 +        {
 +            maxn = mid - 1;
 +        }
 +        else
 +        {
 +            minn = mid + 1;
 +        }
 +    }
 +
 +    ExName = RVA(BaseAddress, ExNames[mid]);
 +    DbgPrint("2: failed to find %s\n",SymbolName);
 +    return (PVOID)NULL;
 +}
 +
 +NTSTATUS
 +NTAPI
 +LdrPEProcessImportDirectoryEntry(PVOID DriverBase,
 +                                 PLOADER_MODULE LoaderModule,
 +                                 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory)
 +{
 +    PVOID* ImportAddressList;
 +    PULONG FunctionNameList;
 +
 +    if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
 +    {
 +        return STATUS_UNSUCCESSFUL;
 +    }
 +
 +    /* Get the import address list. */
 +    ImportAddressList = (PVOID*)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
 +
 +    /* Get the list of functions to import. */
 +    if (ImportModuleDirectory->OriginalFirstThunk != 0)
 +    {
 +        FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->OriginalFirstThunk);
 +    }
 +    else
 +    {
 +        FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
 +    }
 +
 +    /* Walk through function list and fixup addresses. */
 +    while (*FunctionNameList != 0L)
 +    {
 +        if ((*FunctionNameList) & 0x80000000)
 +        {
 +            DbgPrint("Failed to import ordinal from %s\n", LoaderModule->String);
 +            return STATUS_UNSUCCESSFUL;
 +        }
 +        else
 +        {
 +            IMAGE_IMPORT_BY_NAME *pe_name;
 +            pe_name = RVA(DriverBase, *FunctionNameList);
 +            *ImportAddressList = LdrPEGetExportByName((PVOID)LoaderModule->ModStart, pe_name->Name, pe_name->Hint);
 +
 +            /* Fixup the address to be virtual */
 +            *ImportAddressList = RVA(*ImportAddressList, KSEG0_BASE);
 +
 +            //DbgPrint("Looked for: %s and found: %p\n", pe_name->Name, *ImportAddressList);
 +            if ((*ImportAddressList) == NULL)
 +            {
 +                DbgPrint("Failed to import %s from %s\n", pe_name->Name, LoaderModule->String);
 +                return STATUS_UNSUCCESSFUL;
 +            }
 +        }
 +        ImportAddressList++;
 +        FunctionNameList++;
 +    }
 +    return STATUS_SUCCESS;
 +}
 +
 +extern BOOLEAN FrLdrLoadDriver(PCHAR szFileName, INT nPos);
 +
 +NTSTATUS
 +NTAPI
 +LdrPEGetOrLoadModule(IN PCHAR ModuleName,
 +                     IN PCHAR ImportedName,
 +                     IN PLOADER_MODULE* ImportedModule)
 +{
 +    NTSTATUS Status = STATUS_SUCCESS;
 +
 +    *ImportedModule = LdrGetModuleObject(ImportedName);
 +    if (*ImportedModule == NULL)
 +    {
 +      if (!FrLdrLoadDriver(ImportedName, 0))
 +      {
 +          return STATUS_UNSUCCESSFUL;
 +      }
 +      else
 +      {
 +          return LdrPEGetOrLoadModule
 +              (ModuleName, ImportedName, ImportedModule);
 +      }
 +    }
 +
 +    return Status;
 +}
 +
 +NTSTATUS
 +NTAPI
 +LdrPEFixupImports(IN PVOID DllBase,
 +                  IN PCHAR DllName)
 +{
 +    PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
 +    PCHAR ImportedName;
 +    NTSTATUS Status;
 +    PLOADER_MODULE ImportedModule;
 +    ULONG Size;
 +
 +    /*  Process each import module  */
 +    ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
 +        RtlImageDirectoryEntryToData(DllBase,
 +                                     TRUE,
 +                                     IMAGE_DIRECTORY_ENTRY_IMPORT,
 +                                     &Size);
 +    while (ImportModuleDirectory && ImportModuleDirectory->Name)
 +    {
 +        /*  Check to make sure that import lib is kernel  */
 +        ImportedName = (PCHAR) DllBase + ImportModuleDirectory->Name;
 +        //DbgPrint("Processing imports for file: %s into file: %s\n", DllName, ImportedName);
 +
 +        Status = LdrPEGetOrLoadModule(DllName, ImportedName, &ImportedModule);
 +        if (!NT_SUCCESS(Status)) return Status;
 +
 +        Status = LdrPEProcessImportDirectoryEntry(DllBase, ImportedModule, ImportModuleDirectory);
 +        if (!NT_SUCCESS(Status)) return Status;
 +
 +        //DbgPrint("Imports for file: %s into file: %s complete\n", DllName, ImportedName);
 +        ImportModuleDirectory++;
 +    }
 +
 +    return STATUS_SUCCESS;
 +}
 +
 +ULONG
 +NTAPI
 +FrLdrReMapImage(IN PVOID Base,
 +                IN PVOID LoadBase)
 +{
 +    PIMAGE_NT_HEADERS NtHeader;
 +    PIMAGE_SECTION_HEADER Section;
 +    ULONG i, Size, DriverSize = 0;
 +
 +    /* Get the first section */
 +    NtHeader = RtlImageNtHeader(Base);
 +    Section = IMAGE_FIRST_SECTION(NtHeader);
 +
 +    /* Allocate memory for the driver */
 +    DriverSize = NtHeader->OptionalHeader.SizeOfImage;
++    LoadBase = MmAllocateMemoryAtAddress(DriverSize, LoadBase, LoaderSystemCode);
 +    ASSERT(LoadBase);
 +
 +    /* Copy headers over */
 +    RtlMoveMemory(LoadBase, Base, NtHeader->OptionalHeader.SizeOfHeaders);
 +
 +    /*  Copy image sections into virtual section  */
 +    for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
 +    {
 +        /* Get the size of this section and check if it's valid */
 +        Size = Section[i].VirtualAddress + Section[i].Misc.VirtualSize;
 +        if (Size <= DriverSize)
 +        {
 +            if (Section[i].SizeOfRawData)
 +            {
 +                /* Copy the data from the disk to the image */
 +                RtlCopyMemory((PVOID)((ULONG_PTR)LoadBase +
 +                                      Section[i].VirtualAddress),
 +                              (PVOID)((ULONG_PTR)Base +
 +                                      Section[i].PointerToRawData),
 +                              Section[i].Misc.VirtualSize >
 +                              Section[i].SizeOfRawData ?
 +                              Section[i].SizeOfRawData :
 +                              Section[i].Misc.VirtualSize);
 +            }
 +            else
 +            {
 +                /* Clear the BSS area */
 +                RtlZeroMemory((PVOID)((ULONG_PTR)LoadBase +
 +                                      Section[i].VirtualAddress),
 +                              Section[i].Misc.VirtualSize);
 +            }
 +        }
 +    }
 +
 +    /* Return the size of the mapped driver */
 +    return DriverSize;
 +}
 +
 +PVOID
 +NTAPI
 +FrLdrMapImage(IN FILE *Image,
 +              IN PCHAR Name,
 +              IN ULONG ImageType)
 +{
 +    PVOID ImageBase, LoadBase, ReadBuffer;
 +    ULONG ImageId = LoaderBlock.ModsCount;
 +    ULONG ImageSize;
 +    NTSTATUS Status = STATUS_SUCCESS;
 +
 +    /* Try to see, maybe it's loaded already */
 +    if (LdrGetModuleObject(Name) != NULL)
 +    {
 +        /* It's loaded, return NULL. It would be wise to return
 +           correct LoadBase, but it seems to be ignored almost everywhere */
 +        return NULL;
 +    }
 +
 +    /* Set the virtual (image) and physical (load) addresses */
 +    LoadBase = (PVOID)NextModuleBase;
 +    ImageBase = RVA(LoadBase, KSEG0_BASE);
 +
 +    /* Save the Image Size */
 +    ImageSize = FsGetFileSize(Image);
 +
 +    /* Set the file pointer to zero */
 +    FsSetFilePointer(Image, 0);
 +
 +    /* Allocate a temporary buffer for the read */
 +    ReadBuffer = MmAllocateMemory(ImageSize);
 +
 +    /* Load the file image */
 +    FsReadFile(Image, ImageSize, NULL, ReadBuffer);
 +
 +    /* Map it into virtual memory */
 +    ImageSize = FrLdrReMapImage(ReadBuffer, LoadBase);
 +
 +    /* Free the temporary buffer */
 +    MmFreeMemory(ReadBuffer);
 +
 +    /* Calculate Difference between Real Base and Compiled Base*/
 +    Status = LdrRelocateImageWithBias(LoadBase,
 +                                      (ULONG_PTR)ImageBase -
 +                                      (ULONG_PTR)LoadBase,
 +                                      "FreeLdr",
 +                                      STATUS_SUCCESS,
 +                                      STATUS_UNSUCCESSFUL,
 +                                      STATUS_UNSUCCESSFUL);
 +    if (!NT_SUCCESS(Status))
 +    {
 +        /* Fail */
 +        DbgPrint("Failed to relocate image: %s\n", Name);
 +        return NULL;
 +    }
 +
 +    /* Fill out Module Data Structure */
 +    reactos_modules[ImageId].ModStart = (ULONG_PTR)ImageBase;
 +    reactos_modules[ImageId].ModEnd = (ULONG_PTR)ImageBase + ImageSize;
 +    strcpy(reactos_module_strings[ImageId], Name);
 +    reactos_modules[ImageId].String = (ULONG_PTR)reactos_module_strings[ImageId];
 +    LoaderBlock.ModsCount++;
 +
 +    /* Increase the next Load Base */
 +    NextModuleBase = ROUND_UP(NextModuleBase + ImageSize, PAGE_SIZE);
 +
 +    /* Perform import fixups */
 +    if (!NT_SUCCESS(LdrPEFixupImports(LoadBase, Name)))
 +    {
 +        /* Fixup failed, just don't include it in the list */
 +        // NextModuleBase = OldNextModuleBase;
 +        LoaderBlock.ModsCount = ImageId;
 +        return NULL;
 +    }
 +
 +    /* Return the final mapped address */
 +    return LoadBase;
 +}
 +
 +ULONG_PTR
 +NTAPI
 +FrLdrLoadModule(FILE *ModuleImage,
 +                LPCSTR ModuleName,
 +                PULONG ModuleSize)
 +{
 +    ULONG LocalModuleSize;
 +    PLOADER_MODULE ModuleData;
 +    LPSTR NameBuffer;
 +    LPSTR TempName;
 +
 +    /* Get current module data structure and module name string array */
 +    ModuleData = &reactos_modules[LoaderBlock.ModsCount];
 +
 +    /* Get only the Module Name */
 +    do {
 +
 +        TempName = strchr(ModuleName, '\\');
 +
 +        if(TempName) {
 +            ModuleName = TempName + 1;
 +        }
 +
 +    } while(TempName);
 +    NameBuffer = reactos_module_strings[LoaderBlock.ModsCount];
 +
 +    /* Get Module Size */
 +    LocalModuleSize = FsGetFileSize(ModuleImage);
 +
 +    /* Fill out Module Data Structure */
 +    ModuleData->ModStart = NextModuleBase;
 +    ModuleData->ModEnd = NextModuleBase + LocalModuleSize;
 +
 +    /* Save name */
 +    strcpy(NameBuffer, ModuleName);
 +    ModuleData->String = (ULONG_PTR)NameBuffer;
 +
 +    /* Load the file image */
 +    FsReadFile(ModuleImage, LocalModuleSize, NULL, (PVOID)NextModuleBase);
 +
 +    /* Move to next memory block and increase Module Count */
 +    NextModuleBase = ROUND_UP(ModuleData->ModEnd, PAGE_SIZE);
 +    LoaderBlock.ModsCount++;
 +//    DbgPrint("NextBase, ImageSize, ModStart, ModEnd %p %p %p %p\n",
 +  //           NextModuleBase, LocalModuleSize, ModuleData->ModStart, ModuleData->ModEnd);
 +
 +    /* Return Module Size if required */
 +    if (ModuleSize != NULL) {
 +        *ModuleSize = LocalModuleSize;
 +    }
 +
 +    return(ModuleData->ModStart);
 +}
 +
 +ULONG_PTR
 +NTAPI
 +FrLdrCreateModule(LPCSTR ModuleName)
 +{
 +    PLOADER_MODULE ModuleData;
 +    LPSTR NameBuffer;
 +
 +    /* Get current module data structure and module name string array */
 +    ModuleData = &reactos_modules[LoaderBlock.ModsCount];
 +    NameBuffer = reactos_module_strings[LoaderBlock.ModsCount];
 +
 +    /* Set up the structure */
 +    ModuleData->ModStart = NextModuleBase;
 +    ModuleData->ModEnd = -1;
 +
 +    /* Copy the name */
 +    strcpy(NameBuffer, ModuleName);
 +    ModuleData->String = (ULONG_PTR)NameBuffer;
 +
 +    /* Set the current Module */
 +    CurrentModule = ModuleData;
 +
 +    /* Return Module Base Address */
 +    return(ModuleData->ModStart);
 +}
 +
 +BOOLEAN
 +NTAPI
 +FrLdrCloseModule(ULONG_PTR ModuleBase,
 +                 ULONG ModuleSize)
 +{
 +    PLOADER_MODULE ModuleData = CurrentModule;
 +
 +    /* Make sure a module is opened */
 +    if (ModuleData) {
 +
 +        /* Make sure this is the right module and that it hasn't been closed */
 +        if ((ModuleBase == ModuleData->ModStart) && (ModuleData->ModEnd == (ULONG_PTR)-1)) {
 +
 +            /* Close the Module */
 +            ModuleData->ModEnd = ModuleData->ModStart + ModuleSize;
 +
 +            /* Set the next Module Base and increase the number of modules */
 +            NextModuleBase = ROUND_UP(ModuleData->ModEnd, PAGE_SIZE);
 +            LoaderBlock.ModsCount++;
 +
 +            /* Close the currently opened module */
 +            CurrentModule = NULL;
 +
 +            /* Success */
 +            return(TRUE);
 +        }
 +    }
 +
 +    /* Failure path */
 +    return(FALSE);
 +}
index 90c8b3a,0000000..ef8c828
mode 100644,000000..100644
--- /dev/null
@@@ -1,471 -1,0 +1,471 @@@
- VOID MmAllocatePagesInLookupTable(PVOID PageLookupTable, ULONG StartPage, ULONG PageCount)
 +/*
 + *  FreeLoader
 + *  Copyright (C) 1998-2003  Brian Palmer  <brianp@sginet.com>
 + *
 + *  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
 + *  the Free Software Foundation; either version 2 of the License, or
 + *  (at your option) any later version.
 + *
 + *  This program is distributed in the hope that it will be useful,
 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + *  GNU General Public License for more details.
 + *
 + *  You should have received a copy of the GNU General Public License
 + *  along with this program; if not, write to the Free Software
 + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + */
 +
 +#include <freeldr.h>
 +#include <debug.h>
 +
 +#ifdef DBG
 +typedef struct
 +{
 +      ULONG           Type;
 +      UCHAR   TypeString[20];
 +} FREELDR_MEMORY_TYPE, *PFREELDR_MEMORY_TYPE;
 +
 +ULONG                         MemoryTypeCount = 5;
 +FREELDR_MEMORY_TYPE           MemoryTypeArray[] =
 +{
 +      { 0, "Unknown Memory" },
 +      { BiosMemoryUsable, "Usable Memory" },
 +      { BiosMemoryReserved, "Reserved Memory" },
 +      { BiosMemoryAcpiReclaim, "ACPI Reclaim Memory" },
 +      { BiosMemoryAcpiNvs, "ACPI NVS Memory" },
 +};
 +#endif
 +
 +PVOID PageLookupTableAddress = NULL;
 +ULONG         TotalPagesInLookupTable = 0;
 +ULONG         FreePagesInLookupTable = 0;
 +ULONG         LastFreePageHint = 0;
 +
 +BOOLEAN MmInitializeMemoryManager(VOID)
 +{
 +      BIOS_MEMORY_MAP BiosMemoryMap[32];
 +      ULONG           BiosMemoryMapEntryCount;
 +#ifdef DBG
 +      ULONG           Index;
 +#endif
 +
 +      DbgPrint((DPRINT_MEMORY, "Initializing Memory Manager.\n"));
 +
 +      RtlZeroMemory(BiosMemoryMap, sizeof(BIOS_MEMORY_MAP) * 32);
 +
 +      BiosMemoryMapEntryCount = MachGetMemoryMap(BiosMemoryMap, sizeof(BiosMemoryMap) / sizeof(BIOS_MEMORY_MAP));
 +
 +#ifdef DBG
 +      // Dump the system memory map
 +      if (BiosMemoryMapEntryCount != 0)
 +      {
 +              DbgPrint((DPRINT_MEMORY, "System Memory Map (Base Address, Length, Type):\n"));
 +              for (Index=0; Index<BiosMemoryMapEntryCount; Index++)
 +              {
 +                      DbgPrint((DPRINT_MEMORY, "%x%x\t %x%x\t %s\n", BiosMemoryMap[Index].BaseAddress, BiosMemoryMap[Index].Length, MmGetSystemMemoryMapTypeString(BiosMemoryMap[Index].Type)));
 +              }
 +      }
 +#endif
 +
 +      // If we got the system memory map then fixup invalid entries
 +      if (BiosMemoryMapEntryCount != 0)
 +      {
 +              MmFixupSystemMemoryMap(BiosMemoryMap, &BiosMemoryMapEntryCount);
 +      }
 +
 +      // Find address for the page lookup table
 +      TotalPagesInLookupTable = MmGetAddressablePageCountIncludingHoles(BiosMemoryMap, BiosMemoryMapEntryCount);
 +      PageLookupTableAddress = MmFindLocationForPageLookupTable(BiosMemoryMap, BiosMemoryMapEntryCount);
 +      LastFreePageHint = TotalPagesInLookupTable;
 +
 +      if (PageLookupTableAddress == 0)
 +      {
 +              // If we get here then we probably couldn't
 +              // find a contiguous chunk of memory big
 +              // enough to hold the page lookup table
 +              printf("Error initializing memory manager!\n");
 +              return FALSE;
 +      }
 +
 +      // Initialize the page lookup table
 +      MmInitPageLookupTable(PageLookupTableAddress, TotalPagesInLookupTable, BiosMemoryMap, BiosMemoryMapEntryCount);
 +      MmUpdateLastFreePageHint(PageLookupTableAddress, TotalPagesInLookupTable);
 +
 +      FreePagesInLookupTable = MmCountFreePagesInLookupTable(PageLookupTableAddress, TotalPagesInLookupTable);
 +
 +      DbgPrint((DPRINT_MEMORY, "Memory Manager initialized. %d pages available.\n", FreePagesInLookupTable));
 +      return TRUE;
 +}
 +
 +#ifdef DBG
 +PUCHAR MmGetSystemMemoryMapTypeString(ULONG Type)
 +{
 +      ULONG           Index;
 +
 +      for (Index=1; Index<MemoryTypeCount; Index++)
 +      {
 +              if (MemoryTypeArray[Index].Type == Type)
 +              {
 +                      return MemoryTypeArray[Index].TypeString;
 +              }
 +      }
 +
 +      return MemoryTypeArray[0].TypeString;
 +}
 +#endif
 +
 +ULONG MmGetPageNumberFromAddress(PVOID Address)
 +{
 +      return ((ULONG)Address) / MM_PAGE_SIZE;
 +}
 +
 +PVOID MmGetEndAddressOfAnyMemory(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MapCount)
 +{
 +      ULONGLONG               MaxStartAddressSoFar;
 +      ULONGLONG               EndAddressOfMemory;
 +      ULONG           Index;
 +
 +      MaxStartAddressSoFar = 0;
 +      EndAddressOfMemory = 0;
 +      for (Index=0; Index<MapCount; Index++)
 +      {
 +              if (MaxStartAddressSoFar <= BiosMemoryMap[Index].BaseAddress)
 +              {
 +                      MaxStartAddressSoFar = BiosMemoryMap[Index].BaseAddress;
 +                      EndAddressOfMemory = (MaxStartAddressSoFar + BiosMemoryMap[Index].Length);
 +                      if (EndAddressOfMemory > 0xFFFFFFFF)
 +                      {
 +                              EndAddressOfMemory = 0xFFFFFFFF;
 +                      }
 +              }
 +      }
 +
 +      DbgPrint((DPRINT_MEMORY, "MmGetEndAddressOfAnyMemory() returning 0x%x\n", (ULONG)EndAddressOfMemory));
 +
 +      return (PVOID)(ULONG)EndAddressOfMemory;
 +}
 +
 +ULONG MmGetAddressablePageCountIncludingHoles(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MapCount)
 +{
 +      ULONG           PageCount;
 +      ULONGLONG               EndAddress;
 +
 +      EndAddress = (ULONGLONG)(ULONG)MmGetEndAddressOfAnyMemory(BiosMemoryMap, MapCount);
 +
 +      // Since MmGetEndAddressOfAnyMemory() won't
 +      // return addresses higher than 0xFFFFFFFF
 +      // then we need to adjust the end address
 +      // to 0x100000000 so we don't get an
 +      // off-by-one error
 +      if (EndAddress >= 0xFFFFFFFF)
 +      {
 +              EndAddress = 0x100000000LL;
 +
 +              DbgPrint((DPRINT_MEMORY, "MmGetEndAddressOfAnyMemory() returned 0xFFFFFFFF, correcting to be 0x100000000.\n"));
 +      }
 +
 +      PageCount = (EndAddress / MM_PAGE_SIZE);
 +
 +      DbgPrint((DPRINT_MEMORY, "MmGetAddressablePageCountIncludingHoles() returning %d\n", PageCount));
 +
 +      return PageCount;
 +}
 +
 +PVOID MmFindLocationForPageLookupTable(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MapCount)
 +{
 +      ULONG                                   TotalPageCount;
 +      ULONG                                   PageLookupTableSize;
 +      PVOID                           PageLookupTableMemAddress;
 +      int                                     Index;
 +      BIOS_MEMORY_MAP         TempBiosMemoryMap[32];
 +
 +      TotalPageCount = MmGetAddressablePageCountIncludingHoles(BiosMemoryMap, MapCount);
 +      PageLookupTableSize = TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM);
 +      PageLookupTableMemAddress = 0;
 +
 +      RtlCopyMemory(TempBiosMemoryMap, BiosMemoryMap, sizeof(BIOS_MEMORY_MAP) * 32);
 +      MmSortBiosMemoryMap(TempBiosMemoryMap, MapCount);
 +
 +      for (Index=(MapCount-1); Index>=0; Index--)
 +      {
 +              // If this is usable memory with a big enough length
 +              // then we'll put our page lookup table here
 +              if (TempBiosMemoryMap[Index].Type == BiosMemoryUsable && TempBiosMemoryMap[Index].Length >= PageLookupTableSize)
 +              {
 +                      PageLookupTableMemAddress = (PVOID)(ULONG)(TempBiosMemoryMap[Index].BaseAddress + (TempBiosMemoryMap[Index].Length - PageLookupTableSize));
 +                      break;
 +              }
 +      }
 +
 +      DbgPrint((DPRINT_MEMORY, "MmFindLocationForPageLookupTable() returning 0x%x\n", PageLookupTableMemAddress));
 +
 +      return PageLookupTableMemAddress;
 +}
 +
 +VOID MmSortBiosMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MapCount)
 +{
 +      ULONG                                   Index;
 +      ULONG                                   LoopCount;
 +      BIOS_MEMORY_MAP         TempMapItem;
 +
 +      // Loop once for each entry in the memory map minus one
 +      // On each loop iteration go through and sort the memory map
 +      for (LoopCount=0; LoopCount<(MapCount-1); LoopCount++)
 +      {
 +              for (Index=0; Index<(MapCount-1); Index++)
 +              {
 +                      if (BiosMemoryMap[Index].BaseAddress > BiosMemoryMap[Index+1].BaseAddress)
 +                      {
 +                              TempMapItem = BiosMemoryMap[Index];
 +                              BiosMemoryMap[Index] = BiosMemoryMap[Index+1];
 +                              BiosMemoryMap[Index+1] = TempMapItem;
 +                      }
 +              }
 +      }
 +}
 +
 +VOID MmInitPageLookupTable(PVOID PageLookupTable, ULONG TotalPageCount, PBIOS_MEMORY_MAP BiosMemoryMap, ULONG MapCount)
 +{
 +      ULONG           MemoryMapStartPage;
 +      ULONG           MemoryMapEndPage;
 +      ULONG           MemoryMapPageCount;
 +      ULONG           MemoryMapPageAllocated;
 +      ULONG           PageLookupTableStartPage;
 +      ULONG           PageLookupTablePageCount;
 +      ULONG           Index;
 +
 +      DbgPrint((DPRINT_MEMORY, "MmInitPageLookupTable()\n"));
 +
 +      // Mark every page as allocated initially
 +      // We will go through and mark pages again according to the memory map
 +      // But this will mark any holes not described in the map as allocated
 +      MmMarkPagesInLookupTable(PageLookupTable, 0, TotalPageCount, 1);
 +
 +      for (Index=0; Index<MapCount; Index++)
 +      {
 +              MemoryMapStartPage = MmGetPageNumberFromAddress((PVOID)(ULONG)BiosMemoryMap[Index].BaseAddress);
 +              MemoryMapEndPage = MmGetPageNumberFromAddress((PVOID)(ULONG)(BiosMemoryMap[Index].BaseAddress + BiosMemoryMap[Index].Length - 1));
 +              MemoryMapPageCount = (MemoryMapEndPage - MemoryMapStartPage) + 1;
 +              MemoryMapPageAllocated = (BiosMemoryMap[Index].Type == BiosMemoryUsable) ? LoaderFree : LoaderFirmwarePermanent;/*BiosMemoryMap[Index].Type*/;
 +              DbgPrint((DPRINT_MEMORY, "Marking pages as type %d: StartPage: %d PageCount: %d\n", MemoryMapPageAllocated, MemoryMapStartPage, MemoryMapPageCount));
 +              MmMarkPagesInLookupTable(PageLookupTable, MemoryMapStartPage, MemoryMapPageCount, MemoryMapPageAllocated);
 +      }
 +
 +      // Mark the low memory region below 1MB as reserved (256 pages in region)
 +      DbgPrint((DPRINT_MEMORY, "Marking the low 1MB region as reserved.\n"));
 +      MmMarkPagesInLookupTable(PageLookupTable, 0, 256, LoaderFirmwarePermanent);
 +
 +      // Mark the pages that the lookup table occupies as reserved
 +      PageLookupTableStartPage = MmGetPageNumberFromAddress(PageLookupTable);
 +      PageLookupTablePageCount = MmGetPageNumberFromAddress((PVOID)((ULONG_PTR)PageLookupTable + ROUND_UP(TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM), MM_PAGE_SIZE))) - PageLookupTableStartPage;
 +      DbgPrint((DPRINT_MEMORY, "Marking the page lookup table pages as reserved StartPage: %d PageCount: %d\n", PageLookupTableStartPage, PageLookupTablePageCount));
 +      MmMarkPagesInLookupTable(PageLookupTable, PageLookupTableStartPage, PageLookupTablePageCount, LoaderFirmwareTemporary);
 +}
 +
 +VOID MmMarkPagesInLookupTable(PVOID PageLookupTable, ULONG StartPage, ULONG PageCount, TYPE_OF_MEMORY PageAllocated)
 +{
 +      PPAGE_LOOKUP_TABLE_ITEM         RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
 +      ULONG                                                   Index;
 +
 +      for (Index=StartPage; Index<(StartPage+PageCount); Index++)
 +      {
 +              if ((Index <= (StartPage + 16)) || (Index >= (StartPage+PageCount-16)))
 +              {
 +                      DbgPrint((DPRINT_MEMORY, "Index = %d StartPage = %d PageCount = %d\n", Index, StartPage, PageCount));
 +              }
 +              RealPageLookupTable[Index].PageAllocated = PageAllocated;
 +              RealPageLookupTable[Index].PageAllocationLength = (PageAllocated != LoaderFree) ? 1 : 0;
 +      }
 +      DbgPrint((DPRINT_MEMORY, "MmMarkPagesInLookupTable() Done\n"));
 +}
 +
++VOID MmAllocatePagesInLookupTable(PVOID PageLookupTable, ULONG StartPage, ULONG PageCount, TYPE_OF_MEMORY MemoryType)
 +{
 +      PPAGE_LOOKUP_TABLE_ITEM         RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
 +      ULONG                                                   Index;
 +
 +      for (Index=StartPage; Index<(StartPage+PageCount); Index++)
 +      {
 +              RealPageLookupTable[Index].PageAllocated = LoaderSystemCode;
 +              RealPageLookupTable[Index].PageAllocationLength = (Index == StartPage) ? PageCount : 0;
 +      }
 +}
 +
 +ULONG MmCountFreePagesInLookupTable(PVOID PageLookupTable, ULONG TotalPageCount)
 +{
 +      PPAGE_LOOKUP_TABLE_ITEM         RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
 +      ULONG                                                   Index;
 +      ULONG                                                   FreePageCount;
 +
 +      FreePageCount = 0;
 +      for (Index=0; Index<TotalPageCount; Index++)
 +      {
 +              if (RealPageLookupTable[Index].PageAllocated == LoaderFree)
 +              {
 +                      FreePageCount++;
 +              }
 +      }
 +
 +      return FreePageCount;
 +}
 +
 +ULONG MmFindAvailablePages(PVOID PageLookupTable, ULONG TotalPageCount, ULONG PagesNeeded, BOOLEAN FromEnd)
 +{
 +      PPAGE_LOOKUP_TABLE_ITEM         RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
 +      ULONG                                                   AvailablePagesSoFar;
 +      ULONG                                                   Index;
 +
 +      if (LastFreePageHint > TotalPageCount)
 +      {
 +              LastFreePageHint = TotalPageCount;
 +      }
 +
 +      AvailablePagesSoFar = 0;
 +      if (FromEnd)
 +      {
 +              /* Allocate "high" (from end) pages */
 +              for (Index=LastFreePageHint-1; Index>0; Index--)
 +              {
 +                      if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
 +                      {
 +                              AvailablePagesSoFar = 0;
 +                              continue;
 +                      }
 +                      else
 +                      {
 +                              AvailablePagesSoFar++;
 +                      }
 +
 +                      if (AvailablePagesSoFar >= PagesNeeded)
 +                      {
 +                              return Index;
 +                      }
 +              }
 +      }
 +      else
 +      {
 +              DbgPrint((DPRINT_MEMORY, "Alloc low memory, LastFreePageHint %d, TPC %d\n", LastFreePageHint, TotalPageCount));
 +              /* Allocate "low" pages */
 +              for (Index=1; Index < LastFreePageHint; Index++)
 +              {
 +                      if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
 +                      {
 +                              AvailablePagesSoFar = 0;
 +                              continue;
 +                      }
 +                      else
 +                      {
 +                              AvailablePagesSoFar++;
 +                      }
 +
 +                      if (AvailablePagesSoFar >= PagesNeeded)
 +                      {
 +                              return Index - AvailablePagesSoFar + 1;
 +                      }
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +ULONG MmFindAvailablePagesBeforePage(PVOID PageLookupTable, ULONG TotalPageCount, ULONG PagesNeeded, ULONG LastPage)
 +{
 +      PPAGE_LOOKUP_TABLE_ITEM         RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
 +      ULONG                                                   AvailablePagesSoFar;
 +      ULONG                                                   Index;
 +
 +      if (LastPage > TotalPageCount)
 +      {
 +              return MmFindAvailablePages(PageLookupTable, TotalPageCount, PagesNeeded, TRUE);
 +      }
 +
 +      AvailablePagesSoFar = 0;
 +      for (Index=LastPage-1; Index>0; Index--)
 +      {
 +              if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
 +              {
 +                      AvailablePagesSoFar = 0;
 +                      continue;
 +              }
 +              else
 +              {
 +                      AvailablePagesSoFar++;
 +              }
 +
 +              if (AvailablePagesSoFar >= PagesNeeded)
 +              {
 +                      return Index;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +VOID MmFixupSystemMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap, ULONG* MapCount)
 +{
 +      UINT            Index;
 +      UINT            Index2;
 +
 +      // Loop through each entry in the array
 +      for (Index=0; Index<*MapCount; Index++)
 +      {
 +              // If the entry type isn't usable then remove
 +              // it from the memory map (this will help reduce
 +              // the size of our lookup table)
 +              if (BiosMemoryMap[Index].Type != BiosMemoryUsable)
 +              {
 +                      // Slide every entry after this down one
 +                      for (Index2=Index; Index2<(*MapCount - 1); Index2++)
 +                      {
 +                              BiosMemoryMap[Index2] = BiosMemoryMap[Index2 + 1];
 +                      }
 +                      (*MapCount)--;
 +                      Index--;
 +              }
 +      }
 +}
 +
 +VOID MmUpdateLastFreePageHint(PVOID PageLookupTable, ULONG TotalPageCount)
 +{
 +      PPAGE_LOOKUP_TABLE_ITEM         RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
 +      ULONG                                                   Index;
 +
 +      for (Index=TotalPageCount-1; Index>0; Index--)
 +      {
 +              if (RealPageLookupTable[Index].PageAllocated == LoaderFree)
 +              {
 +                      LastFreePageHint = Index + 1;
 +                      break;
 +              }
 +      }
 +}
 +
 +BOOLEAN MmAreMemoryPagesAvailable(PVOID PageLookupTable, ULONG TotalPageCount, PVOID PageAddress, ULONG PageCount)
 +{
 +      PPAGE_LOOKUP_TABLE_ITEM         RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable;
 +      ULONG                                                   StartPage;
 +      ULONG                                                   Index;
 +
 +      StartPage = MmGetPageNumberFromAddress(PageAddress);
 +
 +      // Make sure they aren't trying to go past the
 +      // end of availabe memory
 +      if ((StartPage + PageCount) > TotalPageCount)
 +      {
 +              return FALSE;
 +      }
 +
 +      for (Index=StartPage; Index<(StartPage + PageCount); Index++)
 +      {
 +              // If this page is allocated then there obviously isn't
 +              // memory availabe so return FALSE
 +              if (RealPageLookupTable[Index].PageAllocated != LoaderFree)
 +              {
 +                      return FALSE;
 +              }
 +      }
 +
 +      return TRUE;
 +}
index adee5f7,0000000..94e23f1
mode 100644,000000..100644
--- /dev/null
@@@ -1,495 -1,0 +1,513 @@@
- PVOID MmAllocateMemory(ULONG MemorySize)
 +/*
 + *  FreeLoader
 + *  Copyright (C) 1998-2003  Brian Palmer  <brianp@sginet.com>
 + *
 + *  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
 + *  the Free Software Foundation; either version 2 of the License, or
 + *  (at your option) any later version.
 + *
 + *  This program is distributed in the hope that it will be useful,
 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + *  GNU General Public License for more details.
 + *
 + *  You should have received a copy of the GNU General Public License
 + *  along with this program; if not, write to the Free Software
 + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + */
 +
 +#include <freeldr.h>
 +#include <debug.h>
 +
 +ULONG                 AllocationCount = 0;
 +
 +#ifdef DBG
 +VOID          VerifyHeap(VOID);
 +VOID          DumpMemoryAllocMap(VOID);
 +VOID          IncrementAllocationCount(VOID);
 +VOID          DecrementAllocationCount(VOID);
 +VOID          MemAllocTest(VOID);
 +#endif // DBG
 +
 +/*
 + * Hack alert
 + * Normally, we allocate whole pages. This is ofcourse wastefull for small
 + * allocations (a few bytes). So, for small allocations (smaller than a page)
 + * we sub-allocate. When the first small allocation is done, a page is
 + * requested. We keep a pointer to that page in SubAllocationPage. The alloc
 + * is satisfied by returning a pointer to the beginning of the page. We also
 + * keep track of how many bytes are still available in the page in SubAllocationRest.
 + * When the next small request comes in, we try to allocate it just after the
 + * memory previously allocated. If it won't fit, we allocate a new page and
 + * the whole process starts again.
 + * Note that suballocations are done back-to-back, there's no bookkeeping at all.
 + * That also means that we cannot really free suballocations. So, when a free is
 + * done and it is determined that this might be a free of a sub-allocation, we
 + * just no-op the free.
 + * Perhaps we should use the heap routines from ntdll here.
 + */
 +static PVOID    SubAllocationPage = NULL;
 +static unsigned SubAllocationRest = 0;
 +
 +BOOLEAN AllocateFromEnd = TRUE;
 +
 +VOID MmChangeAllocationPolicy(BOOLEAN PolicyAllocatePagesFromEnd)
 +{
 +      AllocateFromEnd = PolicyAllocatePagesFromEnd;
 +}
 +
-       MmAllocatePagesInLookupTable(PageLookupTableAddress, FirstFreePageFromEnd, PagesNeeded);
++PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType)
 +{
 +      ULONG   PagesNeeded;
 +      ULONG   FirstFreePageFromEnd;
 +      PVOID   MemPointer;
 +
 +      if (MemorySize == 0)
 +      {
 +              DbgPrint((DPRINT_MEMORY, "MmAllocateMemory() called for 0 bytes. Returning NULL.\n"));
 +              UiMessageBoxCritical("Memory allocation failed: MmAllocateMemory() called for 0 bytes.");
 +              return NULL;
 +      }
 +
 +      MemorySize = ROUND_UP(MemorySize, 4);
 +      if (MemorySize <= SubAllocationRest)
 +      {
 +              MemPointer = (PVOID)((ULONG_PTR)SubAllocationPage + MM_PAGE_SIZE - SubAllocationRest);
 +              SubAllocationRest -= MemorySize;
 +              return MemPointer;
 +      }
 +
 +      // Find out how many blocks it will take to
 +      // satisfy this allocation
 +      PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
 +
 +      // If we don't have enough available mem
 +      // then return NULL
 +      if (FreePagesInLookupTable < PagesNeeded)
 +      {
 +              DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount));
 +              UiMessageBoxCritical("Memory allocation failed: out of memory.");
 +              return NULL;
 +      }
 +
 +      FirstFreePageFromEnd = MmFindAvailablePages(PageLookupTableAddress, TotalPagesInLookupTable, PagesNeeded, AllocateFromEnd);
 +
 +      if (FirstFreePageFromEnd == (ULONG)-1)
 +      {
 +              DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount));
 +              UiMessageBoxCritical("Memory allocation failed: out of memory.");
 +              return NULL;
 +      }
 +
- PVOID MmAllocateMemoryAtAddress(ULONG MemorySize, PVOID DesiredAddress)
++      MmAllocatePagesInLookupTable(PageLookupTableAddress, FirstFreePageFromEnd, PagesNeeded, MemoryType);
 +
 +      FreePagesInLookupTable -= PagesNeeded;
 +      MemPointer = (PVOID)(FirstFreePageFromEnd * MM_PAGE_SIZE);
 +
 +      if (MemorySize < MM_PAGE_SIZE)
 +      {
 +              SubAllocationPage = MemPointer;
 +              SubAllocationRest = MM_PAGE_SIZE - MemorySize;
 +      }
 +
 +
 +#ifdef DBG
 +      IncrementAllocationCount();
 +      DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize, PagesNeeded, FirstFreePageFromEnd, AllocationCount));
 +      DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer));
 +      //VerifyHeap();
 +#endif // DBG
 +
 +      // Now return the pointer
 +      return MemPointer;
 +}
 +
-       MmAllocatePagesInLookupTable(PageLookupTableAddress, StartPageNumber, PagesNeeded);
++PVOID MmAllocateMemory(ULONG MemorySize)
++{
++      // Temporary forwarder...
++      return MmAllocateMemoryWithType(MemorySize, LoaderOsloaderHeap);
++}
++
++PVOID MmAllocateMemoryAtAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType)
 +{
 +      ULONG           PagesNeeded;
 +      ULONG           StartPageNumber;
 +      PVOID   MemPointer;
 +
 +      if (MemorySize == 0)
 +      {
 +              DbgPrint((DPRINT_MEMORY, "MmAllocateMemoryAtAddress() called for 0 bytes. Returning NULL.\n"));
 +              UiMessageBoxCritical("Memory allocation failed: MmAllocateMemoryAtAddress() called for 0 bytes.");
 +              return NULL;
 +      }
 +
 +      // Find out how many blocks it will take to
 +      // satisfy this allocation
 +      PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
 +
 +      // Get the starting page number
 +      StartPageNumber = MmGetPageNumberFromAddress(DesiredAddress);
 +
 +      // If we don't have enough available mem
 +      // then return NULL
 +      if (FreePagesInLookupTable < PagesNeeded)
 +      {
 +              DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemoryAtAddress(). "
 +                      "Not enough free memory to allocate %d bytes (requesting %d pages but have only %d). "
 +                      "AllocationCount: %d\n", MemorySize, PagesNeeded, FreePagesInLookupTable, AllocationCount));
 +              UiMessageBoxCritical("Memory allocation failed: out of memory.");
 +              return NULL;
 +      }
 +
 +      if (MmAreMemoryPagesAvailable(PageLookupTableAddress, TotalPagesInLookupTable, DesiredAddress, PagesNeeded) == FALSE)
 +      {
 +              DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemoryAtAddress(). "
 +                      "Not enough free memory to allocate %d bytes at address %p. AllocationCount: %d\n",
 +                      MemorySize, DesiredAddress, AllocationCount));
 +
 +              // Don't tell this to user since caller should try to alloc this memory
 +              // at a different address
 +              //UiMessageBoxCritical("Memory allocation failed: out of memory.");
 +              return NULL;
 +      }
 +
- PVOID MmAllocateHighestMemoryBelowAddress(ULONG MemorySize, PVOID DesiredAddress)
++      MmAllocatePagesInLookupTable(PageLookupTableAddress, StartPageNumber, PagesNeeded, MemoryType);
 +
 +      FreePagesInLookupTable -= PagesNeeded;
 +      MemPointer = (PVOID)(StartPageNumber * MM_PAGE_SIZE);
 +
 +#ifdef DBG
 +      IncrementAllocationCount();
 +      DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize, PagesNeeded, StartPageNumber, AllocationCount));
 +      DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer));
 +      //VerifyHeap();
 +#endif // DBG
 +
 +      // Now return the pointer
 +      return MemPointer;
 +}
 +
-       MmAllocatePagesInLookupTable(PageLookupTableAddress, FirstFreePageFromEnd, PagesNeeded);
++PVOID MmAllocateHighestMemoryBelowAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType)
 +{
 +      ULONG           PagesNeeded;
 +      ULONG           FirstFreePageFromEnd;
 +      ULONG           DesiredAddressPageNumber;
 +      PVOID   MemPointer;
 +
 +      if (MemorySize == 0)
 +      {
 +              DbgPrint((DPRINT_MEMORY, "MmAllocateHighestMemoryBelowAddress() called for 0 bytes. Returning NULL.\n"));
 +              UiMessageBoxCritical("Memory allocation failed: MmAllocateHighestMemoryBelowAddress() called for 0 bytes.");
 +              return NULL;
 +      }
 +
 +      // Find out how many blocks it will take to
 +      // satisfy this allocation
 +      PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
 +
 +      // Get the page number for their desired address
 +      DesiredAddressPageNumber = (ULONG)DesiredAddress / MM_PAGE_SIZE;
 +
 +      // If we don't have enough available mem
 +      // then return NULL
 +      if (FreePagesInLookupTable < PagesNeeded)
 +      {
 +              DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount));
 +              UiMessageBoxCritical("Memory allocation failed: out of memory.");
 +              return NULL;
 +      }
 +
 +      FirstFreePageFromEnd = MmFindAvailablePagesBeforePage(PageLookupTableAddress, TotalPagesInLookupTable, PagesNeeded, DesiredAddressPageNumber);
 +
 +      if (FirstFreePageFromEnd == 0)
 +      {
 +              DbgPrint((DPRINT_MEMORY, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes. AllocationCount: %d\n", MemorySize, AllocationCount));
 +              UiMessageBoxCritical("Memory allocation failed: out of memory.");
 +              return NULL;
 +      }
 +
++      MmAllocatePagesInLookupTable(PageLookupTableAddress, FirstFreePageFromEnd, PagesNeeded, MemoryType);
 +
 +      FreePagesInLookupTable -= PagesNeeded;
 +      MemPointer = (PVOID)(FirstFreePageFromEnd * MM_PAGE_SIZE);
 +
 +#ifdef DBG
 +      IncrementAllocationCount();
 +      DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize, PagesNeeded, FirstFreePageFromEnd, AllocationCount));
 +      DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer));
 +      //VerifyHeap();
 +#endif // DBG
 +
 +      // Now return the pointer
 +      return MemPointer;
 +}
 +
 +VOID MmFreeMemory(PVOID MemoryPointer)
 +{
 +      ULONG                                                   PageNumber;
 +      ULONG                                                   PageCount;
 +      ULONG                                                   Idx;
 +      PPAGE_LOOKUP_TABLE_ITEM         RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress;
 +
 +#ifdef DBG
 +
 +      // Make sure we didn't get a bogus pointer
 +      if (MemoryPointer >= (PVOID)(TotalPagesInLookupTable * MM_PAGE_SIZE))
 +      {
 +              BugCheck((DPRINT_MEMORY, "Bogus memory pointer (0x%x) passed to MmFreeMemory()\n", MemoryPointer));
 +      }
 +#endif // DBG
 +
 +      // Find out the page number of the first
 +      // page of memory they allocated
 +      PageNumber = MmGetPageNumberFromAddress(MemoryPointer);
 +      PageCount = RealPageLookupTable[PageNumber].PageAllocationLength;
 +
 +#ifdef DBG
 +      // Make sure we didn't get a bogus pointer
 +      if ((PageCount < 1) || (PageCount > (TotalPagesInLookupTable - PageNumber)))
 +      {
 +              BugCheck((DPRINT_MEMORY, "Invalid page count in lookup table. PageLookupTable[%d].PageAllocationLength = %d\n", PageNumber, RealPageLookupTable[PageNumber].PageAllocationLength));
 +      }
 +
 +      // Loop through our array check all the pages
 +      // to make sure they are allocated with a length of 0
 +      for (Idx=PageNumber+1; Idx<(PageNumber + PageCount); Idx++)
 +      {
 +              if ((RealPageLookupTable[Idx].PageAllocated == LoaderFree) ||
 +                      (RealPageLookupTable[Idx].PageAllocationLength != 0))
 +              {
 +                      BugCheck((DPRINT_MEMORY, "Invalid page entry in lookup table, PageAllocated should = 1 and PageAllocationLength should = 0 because this is not the first block in the run. PageLookupTable[%d].PageAllocated = %d PageLookupTable[%d].PageAllocationLength = %d\n", PageNumber, RealPageLookupTable[PageNumber].PageAllocated, PageNumber, RealPageLookupTable[PageNumber].PageAllocationLength));
 +              }
 +      }
 +
 +#endif
 +
 +      /* If this allocation is only a single page, it could be a sub-allocated page.
 +       * Just don't free it */
 +      if (1 == PageCount)
 +      {
 +              return;
 +      }
 +
 +      // Loop through our array and mark all the
 +      // blocks as free
 +      for (Idx=PageNumber; Idx<(PageNumber + PageCount); Idx++)
 +      {
 +              RealPageLookupTable[Idx].PageAllocated = LoaderFree;
 +              RealPageLookupTable[Idx].PageAllocationLength = 0;
 +      }
 +
 +      FreePagesInLookupTable += PageCount;
 +
 +#ifdef DBG
 +      DecrementAllocationCount();
 +      DbgPrint((DPRINT_MEMORY, "Freed %d pages of memory starting at page %d. AllocationCount: %d\n", PageCount, PageNumber, AllocationCount));
 +      //VerifyHeap();
 +#endif // DBG
 +}
 +
++PVOID MmHeapAlloc(ULONG MemorySize)
++{
++      // Stub for WinLdr
++      return NULL;
++}
++
++VOID MmHeapFree(PVOID MemoryPointer)
++{
++      // Stub for WinLdr
++}
++
++
 +#ifdef DBG
 +VOID VerifyHeap(VOID)
 +{
 +      ULONG                                                   Idx;
 +      ULONG                                                   Idx2;
 +      ULONG                                                   Count;
 +      PPAGE_LOOKUP_TABLE_ITEM         RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress;
 +
 +      if (DUMP_MEM_MAP_ON_VERIFY)
 +      {
 +              DumpMemoryAllocMap();
 +      }
 +
 +      // Loop through the array and verify that
 +      // everything is kosher
 +      for (Idx=0; Idx<TotalPagesInLookupTable; Idx++)
 +      {
 +              // Check if this block is allocated
 +              if (RealPageLookupTable[Idx].PageAllocated != LoaderFree)
 +              {
 +                      // This is the first block in the run so it
 +                      // had better have a length that is within range
 +                      if ((RealPageLookupTable[Idx].PageAllocationLength < 1) || (RealPageLookupTable[Idx].PageAllocationLength > (TotalPagesInLookupTable - Idx)))
 +                      {
 +                              BugCheck((DPRINT_MEMORY, "Allocation length out of range in heap table. PageLookupTable[Idx].PageAllocationLength = %d\n", RealPageLookupTable[Idx].PageAllocationLength));
 +                      }
 +
 +                      // Now go through and verify that the rest of
 +                      // this run has the blocks marked allocated
 +                      // with a length of zero but don't check the
 +                      // first one because we already did
 +                      Count = RealPageLookupTable[Idx].PageAllocationLength;
 +                      for (Idx2=1; Idx2<Count; Idx2++)
 +                      {
 +                              // Make sure it's allocated
 +                              if (RealPageLookupTable[Idx + Idx2].PageAllocated == LoaderFree)
 +                              {
 +                                      BugCheck((DPRINT_MEMORY, "Lookup table indicates hole in memory allocation. RealPageLookupTable[Idx + Idx2].PageAllocated == 0\n"));
 +                              }
 +
 +                              // Make sure the length is zero
 +                              if (RealPageLookupTable[Idx + Idx2].PageAllocationLength != 0)
 +                              {
 +                                      BugCheck((DPRINT_MEMORY, "Allocation chain has non-zero value in non-first block in lookup table. RealPageLookupTable[Idx + Idx2].PageAllocationLength != 0\n"));
 +                              }
 +                      }
 +
 +                      // Move on to the next run
 +                      Idx += (Count - 1);
 +              }
 +              else
 +              {
 +                      // Nope, not allocated so make sure the length is zero
 +                      if (RealPageLookupTable[Idx].PageAllocationLength != 0)
 +                      {
 +                              BugCheck((DPRINT_MEMORY, "Free block is start of memory allocation. RealPageLookupTable[Idx].PageAllocationLength != 0\n"));
 +                      }
 +              }
 +      }
 +}
 +
 +VOID DumpMemoryAllocMap(VOID)
 +{
 +      ULONG                                                   Idx;
 +      PPAGE_LOOKUP_TABLE_ITEM         RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress;
 +
 +      DbgPrint((DPRINT_MEMORY, "----------- Memory Allocation Bitmap -----------\n"));
 +
 +      for (Idx=0; Idx<TotalPagesInLookupTable; Idx++)
 +      {
 +              if ((Idx % 32) == 0)
 +              {
 +                      DbgPrint((DPRINT_MEMORY, "\n"));
 +                      DbgPrint((DPRINT_MEMORY, "%x:\t", (Idx * MM_PAGE_SIZE)));
 +              }
 +              else if ((Idx % 4) == 0)
 +              {
 +                      DbgPrint((DPRINT_MEMORY, " "));
 +              }
 +
 +              switch (RealPageLookupTable[Idx].PageAllocated)
 +              {
 +              case LoaderFree:
 +                      DbgPrint((DPRINT_MEMORY, "*"));
 +                      break;
 +              case LoaderBad:
 +                      DbgPrint((DPRINT_MEMORY, "-"));
 +                      break;
 +              case LoaderLoadedProgram:
 +                      DbgPrint((DPRINT_MEMORY, "O"));
 +                      break;
 +              case LoaderFirmwareTemporary:
 +                      DbgPrint((DPRINT_MEMORY, "T"));
 +                      break;
 +              case LoaderFirmwarePermanent:
 +                      DbgPrint((DPRINT_MEMORY, "P"));
 +                      break;
 +              case LoaderOsloaderHeap:
 +                      DbgPrint((DPRINT_MEMORY, "H"));
 +                      break;
 +              case LoaderOsloaderStack:
 +                      DbgPrint((DPRINT_MEMORY, "S"));
 +                      break;
 +              case LoaderSystemCode:
 +                      DbgPrint((DPRINT_MEMORY, "K"));
 +                      break;
 +              case LoaderHalCode:
 +                      DbgPrint((DPRINT_MEMORY, "L"));
 +                      break;
 +              case LoaderBootDriver:
 +                      DbgPrint((DPRINT_MEMORY, "B"));
 +                      break;
 +              case LoaderStartupPcrPage:
 +                      DbgPrint((DPRINT_MEMORY, "G"));
 +                      break;
 +              case LoaderRegistryData:
 +                      DbgPrint((DPRINT_MEMORY, "R"));
 +                      break;
 +              case LoaderMemoryData:
 +                      DbgPrint((DPRINT_MEMORY, "M"));
 +                      break;
 +              case LoaderNlsData:
 +                      DbgPrint((DPRINT_MEMORY, "N"));
 +                      break;
 +              case LoaderSpecialMemory:
 +                      DbgPrint((DPRINT_MEMORY, "C"));
 +                      break;
 +              default:
 +                      DbgPrint((DPRINT_MEMORY, "?"));
 +                      break;
 +              }
 +      }
 +
 +      DbgPrint((DPRINT_MEMORY, "\n"));
 +}
 +
 +VOID IncrementAllocationCount(VOID)
 +{
 +      AllocationCount++;
 +}
 +
 +VOID DecrementAllocationCount(VOID)
 +{
 +      AllocationCount--;
 +}
 +
 +VOID MemAllocTest(VOID)
 +{
 +      PVOID   MemPtr1;
 +      PVOID   MemPtr2;
 +      PVOID   MemPtr3;
 +      PVOID   MemPtr4;
 +      PVOID   MemPtr5;
 +
 +      MemPtr1 = MmAllocateMemory(4096);
 +      printf("MemPtr1: 0x%x\n", (int)MemPtr1);
 +      MachConsGetCh();
 +      MemPtr2 = MmAllocateMemory(4096);
 +      printf("MemPtr2: 0x%x\n", (int)MemPtr2);
 +      MachConsGetCh();
 +      MemPtr3 = MmAllocateMemory(4096);
 +      printf("MemPtr3: 0x%x\n", (int)MemPtr3);
 +      DumpMemoryAllocMap();
 +      VerifyHeap();
 +      MachConsGetCh();
 +
 +      MmFreeMemory(MemPtr2);
 +      MachConsGetCh();
 +
 +      MemPtr4 = MmAllocateMemory(2048);
 +      printf("MemPtr4: 0x%x\n", (int)MemPtr4);
 +      MachConsGetCh();
 +      MemPtr5 = MmAllocateMemory(4096);
 +      printf("MemPtr5: 0x%x\n", (int)MemPtr5);
 +      MachConsGetCh();
 +}
 +#endif // DBG
 +
 +ULONG GetSystemMemorySize(VOID)
 +{
 +      return (TotalPagesInLookupTable * MM_PAGE_SIZE);
 +}
 +
 +PPAGE_LOOKUP_TABLE_ITEM MmGetMemoryMap(ULONG *NoEntries)
 +{
 +      PPAGE_LOOKUP_TABLE_ITEM         RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress;
 +
 +      *NoEntries = TotalPagesInLookupTable;
 +
 +      return RealPageLookupTable;
 +}
index d111a45,0000000..2cfb680
mode 100644,000000..100644
--- /dev/null
@@@ -1,587 -1,0 +1,582 @@@
- ARC_DISK_SIGNATURE BldrDiskInfo[32];
- CHAR BldrArcNames[32][256];
 +/*
 + *  FreeLoader
 + *
 + *  Copyright (C) 1998-2003  Brian Palmer    <brianp@sginet.com>
 + *  Copyright (C) 2006       Aleksey Bragin  <aleksey@reactos.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
 + *  the Free Software Foundation; either version 2 of the License, or
 + *  (at your option) any later version.
 + *
 + *  This program is distributed in the hope that it will be useful,
 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + *  GNU General Public License for more details.
 + *
 + *  You should have received a copy of the GNU General Public License
 + *  along with this program; if not, write to the Free Software
 + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + */
 +
 +#include <freeldr.h>
 +
 +#include <ndk/ldrtypes.h>
 +#include <debug.h>
 +
 +//FIXME: Do a better way to retrieve Arc disk information
 +extern ULONG reactos_disk_count;
 +extern ARC_DISK_SIGNATURE reactos_arc_disk_info[];
 +extern char reactos_arc_strings[32][256];
 +
- void InitializeHWConfig(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock)
- {
-       PCONFIGURATION_COMPONENT_DATA ConfigurationRoot;
-       PCONFIGURATION_COMPONENT Component;
-       PCONFIGURATION_COMPONENT_DATA /*CurrentEntry,*/ PreviousEntry, AdapterEntry;
-       BOOLEAN IsNextEntryChild;
-       DbgPrint((DPRINT_WINDOWS, "InitializeHWConfig()\n"));
-       LoaderBlock->ConfigurationRoot = MmAllocateMemory(sizeof(CONFIGURATION_COMPONENT_DATA));
-       RtlZeroMemory(LoaderBlock->ConfigurationRoot, sizeof(CONFIGURATION_COMPONENT_DATA));
-       /* Fill root == SystemClass */
-       ConfigurationRoot = LoaderBlock->ConfigurationRoot;
-       Component = &LoaderBlock->ConfigurationRoot->ComponentEntry;
-       Component->Class = SystemClass;
-       Component->Type = MaximumType;
-       Component->Version = 0; // FIXME: ?
-       Component->Key = 0;
-       Component->AffinityMask = 0;
-       IsNextEntryChild = TRUE;
-       PreviousEntry = ConfigurationRoot;
-       /* Enumerate all PCI buses */
-       AdapterEntry = ConfigurationRoot;
-       /* TODO: Disk Geometry */
-       /* TODO: Keyboard */
-       /* TODO: Serial port */
-       //Config->ConfigurationData = alloc(sizeof(CONFIGURATION_COMPONENT_DATA), EfiLoaderData);
-       /* Convert everything to VA */
-       ConvertConfigToVA(LoaderBlock->ConfigurationRoot);
-       LoaderBlock->ConfigurationRoot = PaToVa(LoaderBlock->ConfigurationRoot);
- }
 +BOOLEAN
 +WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
 +                        IN PCH DllName,
 +                        OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry);
 +
 +// debug stuff
 +VOID DumpMemoryAllocMap(VOID);
 +VOID WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);
 +VOID WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock);
 +VOID WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock);
 +
 +
-       LoaderBlock = MmAllocateMemory(sizeof(LOADER_PARAMETER_BLOCK));
 +// Init "phase 0"
 +VOID
 +AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock)
 +{
 +      PLOADER_PARAMETER_BLOCK LoaderBlock;
 +
 +      /* Allocate and zero-init the LPB */
-       LoaderBlock->NlsData = MmAllocateMemory(sizeof(NLS_DATA_BLOCK));
++      LoaderBlock = MmHeapAlloc(sizeof(LOADER_PARAMETER_BLOCK));
 +      RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
 +
 +      /* Init three critical lists, used right away */
 +      InitializeListHead(&LoaderBlock->LoadOrderListHead);
 +      InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);
 +      InitializeListHead(&LoaderBlock->BootDriverListHead);
 +
 +      /* Alloc space for NLS (it will be converted to VA in WinLdrLoadNLS) */
- WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock)
++      LoaderBlock->NlsData = MmHeapAlloc(sizeof(NLS_DATA_BLOCK));
 +      if (LoaderBlock->NlsData == NULL)
 +      {
 +              UiMessageBox("Failed to allocate memory for NLS table data!");
 +              return;
 +      }
 +      RtlZeroMemory(LoaderBlock->NlsData, sizeof(NLS_DATA_BLOCK));
 +
 +      *OutLoaderBlock = LoaderBlock;
 +}
 +
 +// Init "phase 1"
 +VOID
-       //CHAR  Options[] = "/CRASHDEBUG /DEBUGPORT=COM1 /BAUDRATE=115200";
-       CHAR    Options[] = "/NODEBUG";
-       CHAR    SystemRoot[] = "\\WINNT\\";
-       CHAR    HalPath[] = "\\";
-       CHAR    ArcBoot[] = "multi(0)disk(0)rdisk(1)partition(1)";
-       CHAR    ArcHal[] = "multi(0)disk(0)rdisk(1)partition(1)";
++WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
++                       PCHAR Options,
++                       PCHAR SystemPath,
++                       WORD VersionToBoot)
 +{
-       ULONG i;
++      /* Examples of correct options and paths */
++      //CHAR  Options[] = "/DEBUGPORT=COM1 /BAUDRATE=115200";
++      //CHAR  Options[] = "/NODEBUG";
++      //CHAR  SystemRoot[] = "\\WINNT\\";
++      //CHAR  ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)";
 +
-       LoaderBlock->ArcBootDeviceName = MmAllocateMemory(strlen(ArcBoot)+1);
++      CHAR    HalPath[] = "\\";
++      CHAR    SystemRoot[256];
++      CHAR    ArcBoot[256];
++      ULONG i, PathSeparator;
 +      PLOADER_PARAMETER_EXTENSION Extension;
 +
 +      LoaderBlock->u.I386.CommonDataArea = NULL; // Force No ABIOS support
 +
++      /* Construct SystemRoot and ArcBoot from SystemPath */
++      PathSeparator = strstr(SystemPath, "\\") - SystemPath;
++      strncpy(ArcBoot, SystemPath, PathSeparator);
++      ArcBoot[PathSeparator] = 0;
++      strcpy(SystemRoot, &SystemPath[PathSeparator]);
++      strcat(SystemRoot, "\\");
++
++      DbgPrint((DPRINT_WINDOWS, "ArcBoot: %s\n", ArcBoot));
++      DbgPrint((DPRINT_WINDOWS, "SystemRoot: %s\n", SystemRoot));
++      DbgPrint((DPRINT_WINDOWS, "Options: %s\n", Options));
++
 +      /* Fill Arc BootDevice */
-       /* Fill Arc HalDevice */
-       LoaderBlock->ArcHalDeviceName = MmAllocateMemory(strlen(ArcHal)+1);
-       strcpy(LoaderBlock->ArcHalDeviceName, ArcHal);
++      LoaderBlock->ArcBootDeviceName = MmHeapAlloc(strlen(ArcBoot)+1);
 +      strcpy(LoaderBlock->ArcBootDeviceName, ArcBoot);
 +      LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName);
 +
-       LoaderBlock->NtBootPathName = MmAllocateMemory(strlen(SystemRoot)+1);
++      /* Fill Arc HalDevice, it matches ArcBoot path */
++      LoaderBlock->ArcHalDeviceName = MmHeapAlloc(strlen(ArcBoot)+1);
++      strcpy(LoaderBlock->ArcHalDeviceName, ArcBoot);
 +      LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName);
 +
 +      /* Fill SystemRoot */
-       LoaderBlock->NtHalPathName = MmAllocateMemory(strlen(HalPath)+1);
++      LoaderBlock->NtBootPathName = MmHeapAlloc(strlen(SystemRoot)+1);
 +      strcpy(LoaderBlock->NtBootPathName, SystemRoot);
 +      LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName);
 +
 +      /* Fill NtHalPathName */
-       LoaderBlock->LoadOptions = MmAllocateMemory(strlen(Options)+1);
++      LoaderBlock->NtHalPathName = MmHeapAlloc(strlen(HalPath)+1);
 +      strcpy(LoaderBlock->NtHalPathName, HalPath);
 +      LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName);
 +
 +      /* Fill load options */
-       LoaderBlock->ArcDiskInformation = (PARC_DISK_INFORMATION)MmAllocateMemory(sizeof(ARC_DISK_INFORMATION));
++      LoaderBlock->LoadOptions = MmHeapAlloc(strlen(Options)+1);
 +      strcpy(LoaderBlock->LoadOptions, Options);
 +      LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions);
 +
 +      /* Arc devices */
-               ArcDiskInfo = &BldrDiskInfo[i];
++      LoaderBlock->ArcDiskInformation = (PARC_DISK_INFORMATION)MmHeapAlloc(sizeof(ARC_DISK_INFORMATION));
 +      InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
 +
 +      /* Convert ARC disk information from freeldr to a correct format */
 +      for (i = 0; i < reactos_disk_count; i++)
 +      {
 +              PARC_DISK_SIGNATURE ArcDiskInfo;
 +
 +              /* Get the ARC structure */
-               strcpy(BldrArcNames[i], reactos_arc_disk_info[i].ArcName);
-               ArcDiskInfo->ArcName = BldrArcNames[i];
++              ArcDiskInfo = (PARC_DISK_SIGNATURE)MmHeapAlloc(sizeof(ARC_DISK_SIGNATURE));
++              RtlZeroMemory(ArcDiskInfo, sizeof(ARC_DISK_SIGNATURE));
 +
 +              /* Copy the data over */
 +              ArcDiskInfo->Signature = reactos_arc_disk_info[i].Signature;
 +              ArcDiskInfo->CheckSum = reactos_arc_disk_info[i].CheckSum;
 +
 +              /* Copy the ARC Name */
-       /* Convert the list to virtual address */
++              ArcDiskInfo->ArcName = (PCHAR)MmHeapAlloc(sizeof(CHAR)*256);
++              strcpy(ArcDiskInfo->ArcName, reactos_arc_disk_info[i].ArcName);
++              ArcDiskInfo->ArcName = (PCHAR)PaToVa(ArcDiskInfo->ArcName);
++
++              /* Mark partition table as valid */
++              ArcDiskInfo->ValidPartitionTable = TRUE; 
 +
 +              /* Insert into the list */
 +              InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead,
 +                      &ArcDiskInfo->ListEntry);
 +      }
 +
-       /* Create configuration entries */
-       InitializeHWConfig(LoaderBlock);
++      /* Convert all list's to Virtual address */
++
++      /* Convert the ArcDisks list to virtual address */
 +      List_PaToVa(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
 +      LoaderBlock->ArcDiskInformation = PaToVa(LoaderBlock->ArcDiskInformation);
 +
-       //TODO: !!!
-       /* Convert all list's to Virtual address */
++      /* Convert configuration entries to VA */
++      ConvertConfigToVA(LoaderBlock->ConfigurationRoot);
++      LoaderBlock->ConfigurationRoot = PaToVa(LoaderBlock->ConfigurationRoot);
 +
 +      /* Convert all DTE into virtual addresses */
-       Extension = MmAllocateMemory(sizeof(LOADER_PARAMETER_EXTENSION));
 +      List_PaToVa(&LoaderBlock->LoadOrderListHead);
 +
 +      /* this one will be converted right before switching to
 +         virtual paging mode */
 +      //List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
 +
++      /* Convert list of boot drivers */
 +      List_PaToVa(&LoaderBlock->BootDriverListHead);
 +
 +      /* Initialize Extension now */
-       Extension->MajorVersion = 4;
-       Extension->MinorVersion = 0;
++      Extension = MmHeapAlloc(sizeof(LOADER_PARAMETER_EXTENSION));
 +      if (Extension == NULL)
 +      {
 +              UiMessageBox("Failed to allocate LPB Extension!");
 +              return;
 +      }
 +      RtlZeroMemory(Extension, sizeof(LOADER_PARAMETER_EXTENSION));
 +
++      /* Save size and version information */
 +      Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
-       Pcr = (ULONG_PTR)MmAllocateMemory(2 * MM_PAGE_SIZE);
++      Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8;
++      Extension->MinorVersion = VersionToBoot & 0xFF;
 +
 +
 +      LoaderBlock->Extension = PaToVa(Extension);
 +}
 +
 +// Last step before going virtual
 +void WinLdrSetupForNt(PLOADER_PARAMETER_BLOCK LoaderBlock,
 +                      PVOID *GdtIdt,
 +                      ULONG *PcrBasePage,
 +                      ULONG *TssBasePage)
 +{
 +      ULONG TssSize;
 +      ULONG TssPages;
 +      ULONG_PTR Pcr = 0;
 +      ULONG_PTR Tss = 0;
 +      ULONG BlockSize, NumPages;
 +
 +      LoaderBlock->u.I386.CommonDataArea = NULL;//CommonDataArea;
 +      //LoaderBlock->u.I386.MachineType = MachineType; //FIXME: MachineType?
 +
 +      /* Allocate 2 pages for PCR */
-       Tss = (ULONG_PTR)MmAllocateMemory(TssSize);
++      Pcr = (ULONG_PTR)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE, LoaderStartupPcrPage);
 +      *PcrBasePage = Pcr >> MM_PAGE_SHIFT;
 +
 +      if (Pcr == 0)
 +      {
 +              UiMessageBox("Can't allocate PCR\n");
 +              return;
 +      }
 +
 +      /* Allocate TSS */
 +      TssSize = (sizeof(KTSS) + MM_PAGE_SIZE) & ~(MM_PAGE_SIZE - 1);
 +      TssPages = TssSize / MM_PAGE_SIZE;
 +
-       *GdtIdt = (PKGDTENTRY)MmAllocateMemory(NumPages * MM_PAGE_SIZE);
++      Tss = (ULONG_PTR)MmAllocateMemoryWithType(TssSize, LoaderMemoryData);
 +
 +      *TssBasePage = Tss >> MM_PAGE_SHIFT;
 +
 +      /* Allocate space for new GDT + IDT */
 +      BlockSize = NUM_GDT*sizeof(KGDTENTRY) + NUM_IDT*sizeof(KIDTENTRY);//FIXME: Use GDT/IDT limits here?
 +      NumPages = (BlockSize + MM_PAGE_SIZE - 1) >> MM_PAGE_SHIFT;
-       Status = WinLdrLoadImage(FullPath, &DriverBase);
++      *GdtIdt = (PKGDTENTRY)MmAllocateMemoryWithType(NumPages * MM_PAGE_SIZE, LoaderMemoryData);
 +
 +      if (*GdtIdt == NULL)
 +      {
 +              UiMessageBox("Can't allocate pages for GDT+IDT!\n");
 +              return;
 +      }
 +
 +      /* Zero newly prepared GDT+IDT */
 +      RtlZeroMemory(*GdtIdt, NumPages << MM_PAGE_SHIFT);
 +}
 +
 +BOOLEAN
 +WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock,
 +                       LPSTR BootPath,
 +                       PUNICODE_STRING FilePath,
 +                       ULONG Flags,
 +                       PLDR_DATA_TABLE_ENTRY *DriverDTE)
 +{
 +      CHAR FullPath[1024];
 +      CHAR DriverPath[1024];
 +      CHAR DllName[1024];
 +      PCHAR DriverNamePos;
 +      BOOLEAN Status;
 +      PVOID DriverBase;
 +
 +      // Separate the path to file name and directory path
 +      sprintf(DriverPath, "%wZ", FilePath);
 +      DriverNamePos = strrchr(DriverPath, '\\');
 +      if (DriverNamePos != NULL)
 +      {
 +              // Copy the name
 +              strcpy(DllName, DriverNamePos+1);
 +
 +              // Cut out the name from the path
 +              *(DriverNamePos+1) = 0;
 +      }
 +
 +      DbgPrint((DPRINT_WINDOWS, "DriverPath: %s, DllName: %s, LPB %p\n", DriverPath, DllName, LoaderBlock));
 +
 +
 +      // Check if driver is already loaded
 +      Status = WinLdrCheckForLoadedDll(LoaderBlock, DllName, DriverDTE);
 +      if (Status)
 +      {
 +              // We've got the pointer to its DTE, just return success
 +              return TRUE;
 +      }
 +
 +      // It's not loaded, we have to load it
 +      sprintf(FullPath,"%s%wZ", BootPath, FilePath);
-               //DbgPrint((DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
-               //      BootDriver->DataTableEntry, &BootDriver->RegistryPath));
++      Status = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
 +      if (!Status)
 +              return FALSE;
 +
 +      // Allocate a DTE for it
 +      Status = WinLdrAllocateDataTableEntry(LoaderBlock, DllName, DllName, DriverBase, DriverDTE);
 +      if (!Status)
 +      {
 +              DbgPrint((DPRINT_WINDOWS, "WinLdrAllocateDataTableEntry() failed\n"));
 +              return FALSE;
 +      }
 +
 +      // Modify any flags, if needed
 +      (*DriverDTE)->Flags |= Flags;
 +
 +      // Look for any dependencies it may have, and load them too
 +      sprintf(FullPath,"%s%s", BootPath, DriverPath);
 +      Status = WinLdrScanImportDescriptorTable(LoaderBlock, FullPath, *DriverDTE);
 +      if (!Status)
 +      {
 +              DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable() failed for %s\n",
 +                      FullPath));
 +              return FALSE;
 +      }
 +
 +      return TRUE;
 +}
 +
 +BOOLEAN
 +WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
 +                      LPSTR BootPath)
 +{
 +      PLIST_ENTRY NextBd;
 +      PBOOT_DRIVER_LIST_ENTRY BootDriver;
 +      BOOLEAN Status;
 +
 +      // Walk through the boot drivers list
 +      NextBd = LoaderBlock->BootDriverListHead.Flink;
 +
 +      while (NextBd != &LoaderBlock->BootDriverListHead)
 +      {
 +              BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, ListEntry);
 +
-       CHAR  SystemPath[1024], SearchPath[1024];
-       CHAR  FileName[1024];
-       CHAR  BootPath[256];
++              DbgPrint((DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
++                      BootDriver->DataTableEntry, &BootDriver->RegistryPath));
 +
 +              // Paths are relative (FIXME: Are they always relative?)
 +
 +              // Load it
 +              Status = WinLdrLoadDeviceDriver(LoaderBlock, BootPath, &BootDriver->FilePath,
 +                      0, &BootDriver->DataTableEntry);
 +
 +              // If loading failed - cry loudly
 +              //FIXME: Maybe remove it from the list and try to continue?
 +              if (!Status)
 +              {
 +                      UiMessageBox("Can't load boot driver!");
 +                      return FALSE;
 +              }
 +
++              // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore
++              BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer);
++              BootDriver->DataTableEntry = PaToVa(BootDriver->DataTableEntry);
++
 +              NextBd = BootDriver->ListEntry.Flink;
 +      }
 +
 +      return TRUE;
 +}
 +
 +VOID
 +LoadAndBootWindows(PCSTR OperatingSystemName, WORD OperatingSystemVersion)
 +{
 +      CHAR  MsgBuffer[256];
-       //FIXME: This is needed only for MachHwDetect() which performs registry operations!
-       RegInitializeRegistry();
++      CHAR  SystemPath[512], SearchPath[512];
++      CHAR  FileName[512];
++      CHAR  BootPath[512];
++      CHAR  BootOptions[256];
 +      PVOID NtosBase = NULL, HalBase = NULL, KdComBase = NULL;
 +      BOOLEAN Status;
 +      ULONG SectionId;
 +      ULONG BootDevice;
 +      PLOADER_PARAMETER_BLOCK LoaderBlock, LoaderBlockVA;
 +      KERNEL_ENTRY_POINT KiSystemStartup;
 +      PLDR_DATA_TABLE_ENTRY KernelDTE, HalDTE, KdComDTE = NULL;
 +      // Mm-related things
 +      PVOID GdtIdt;
 +      ULONG PcrBasePage=0;
 +      ULONG TssBasePage=0;
 +
 +      //sprintf(MsgBuffer,"Booting Microsoft(R) Windows(R) OS version '%04x' is not implemented yet", OperatingSystemVersion);
 +      //UiMessageBox(MsgBuffer);
 +
 +      // Open the operating system section
 +      // specified in the .ini file
 +      if (!IniOpenSection(OperatingSystemName, &SectionId))
 +      {
 +              sprintf(MsgBuffer,"Operating System section '%s' not found in freeldr.ini", OperatingSystemName);
 +              UiMessageBox(MsgBuffer);
 +              return;
 +      }
 +
 +      UiDrawBackdrop();
 +      UiDrawStatusText("Detecting Hardware...");
 +      UiDrawProgressBarCenter(1, 100, "Loading Windows...");
 +
-       if (!MachDiskNormalizeSystemPath(SystemPath,
-                                        sizeof(SystemPath)))
 +      /* Make sure the system path is set in the .ini file */
 +      if (!IniReadSettingByName(SectionId, "SystemPath", SystemPath, sizeof(SystemPath)))
 +      {
 +              UiMessageBox("System path not specified for selected operating system.");
 +              return;
 +      }
 +
-       /* Detect hardware */
-       MachHwDetect();
++      /* Read booting options */
++      if (!IniReadSettingByName(SectionId, "Options", BootOptions, sizeof(BootOptions)))
++      {
++              /* Nothing read, make the string empty */
++              strcpy(BootOptions, "");
++      }
++
++      /* Normalize system path */
++      if (!MachDiskNormalizeSystemPath(SystemPath, sizeof(SystemPath)))
 +      {
 +              UiMessageBox("Invalid system path");
 +              return;
 +      }
 +
-       // Allocate and minimalistic-initialize LPB
++      /* Let user know we started loading */
 +      UiDrawStatusText("Loading...");
 +
 +      /* Try to open system drive */
 +      BootDevice = 0xffffffff;
 +      if (!FsOpenSystemVolume(SystemPath, BootPath, &BootDevice))
 +      {
 +              UiMessageBox("Failed to open boot drive.");
 +              return;
 +      }
 +
 +      /* append a backslash */
 +      if ((strlen(BootPath)==0) ||
 +          BootPath[strlen(BootPath)] != '\\')
 +              strcat(BootPath, "\\");
 +
 +      DbgPrint((DPRINT_WINDOWS,"SystemRoot: '%s'\n", BootPath));
 +
-       // Load kernel
++      /* Allocate and minimalistic-initialize LPB */
 +      AllocateAndInitLPB(&LoaderBlock);
 +
-       Status = WinLdrLoadImage(FileName, &NtosBase);
++      /* Detect hardware */
++#if WHEN_MERGE_COMPLETE
++      MachHwDetect(&LoaderBlock->ConfigurationRoot);
++#else
++      MachHwDetect();
++#endif
++
++      /* Load kernel */
 +      strcpy(FileName, BootPath);
 +      strcat(FileName, "SYSTEM32\\NTOSKRNL.EXE");
-       // Load HAL
++      Status = WinLdrLoadImage(FileName, LoaderSystemCode, &NtosBase);
 +      DbgPrint((DPRINT_WINDOWS, "Ntos loaded with status %d at %p\n", Status, NtosBase));
 +
-       Status = WinLdrLoadImage(FileName, &HalBase);
++      /* Load HAL */
 +      strcpy(FileName, BootPath);
 +      strcat(FileName, "SYSTEM32\\HAL.DLL");
-       // Load kernel-debugger support dll
-       if (OperatingSystemVersion > _WIN32_WINNT_NT4)
++      Status = WinLdrLoadImage(FileName, LoaderHalCode, &HalBase);
 +      DbgPrint((DPRINT_WINDOWS, "HAL loaded with status %d at %p\n", Status, HalBase));
 +
-               Status = WinLdrLoadImage(FileName, &KdComBase);
++      /* Load kernel-debugger support dll */
++      if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
 +      {
 +              strcpy(FileName, BootPath);
 +              strcat(FileName, "SYSTEM32\\KDCOM.DLL");
-       // Allocate data table entries for above-loaded modules
++              Status = WinLdrLoadImage(FileName, LoaderBootDriver, &KdComBase);
 +              DbgPrint((DPRINT_WINDOWS, "KdCom loaded with status %d at %p\n", Status, KdComBase));
 +      }
 +
-       if (OperatingSystemVersion > _WIN32_WINNT_NT4)
++      /* Allocate data table entries for above-loaded modules */
 +      WinLdrAllocateDataTableEntry(LoaderBlock, "ntoskrnl.exe",
 +              "WINNT\\SYSTEM32\\NTOSKRNL.EXE", NtosBase, &KernelDTE);
 +      WinLdrAllocateDataTableEntry(LoaderBlock, "hal.dll",
 +              "WINNT\\SYSTEM32\\HAL.DLL", HalBase, &HalDTE);
-       WinLdrInitializePhase1(LoaderBlock);
++      if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
 +      {
 +              WinLdrAllocateDataTableEntry(LoaderBlock, "kdcom.dll",
 +                      "WINNT\\SYSTEM32\\KDCOM.DLL", KdComBase, &KdComDTE);
 +      }
 +
 +      /* Load all referenced DLLs for kernel, HAL and kdcom.dll */
 +      strcpy(SearchPath, BootPath);
 +      strcat(SearchPath, "SYSTEM32\\");
 +      WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, KernelDTE);
 +      WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, HalDTE);
 +      if (KdComDTE)
 +              WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, KdComDTE);
 +
 +      /* Load Hive, and then NLS data, OEM font, and prepare boot drivers list */
 +      Status = WinLdrLoadAndScanSystemHive(LoaderBlock, BootPath);
 +      DbgPrint((DPRINT_WINDOWS, "SYSTEM hive loaded and scanned with status %d\n", Status));
 +
 +      /* Load boot drivers */
 +      Status = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
 +      DbgPrint((DPRINT_WINDOWS, "Boot drivers loaded with status %d\n", Status));
 +
 +      /* Initialize Phase 1 - no drivers loading anymore */
-       /* Save entry-point pointer (VA) */
++      WinLdrInitializePhase1(LoaderBlock, BootOptions, SystemPath, OperatingSystemVersion);
 +
 +      /* Alloc PCR, TSS, do magic things with the GDT/IDT */
 +      WinLdrSetupForNt(LoaderBlock, &GdtIdt, &PcrBasePage, &TssBasePage);
 +
++      /* Save entry-point pointer and Loader block VAs */
 +      KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint;
 +      LoaderBlockVA = PaToVa(LoaderBlock);
 +
++      /* "Stop all motors", change videomode */
++      DiskStopFloppyMotor();
++      MachVideoPrepareForReactOS(FALSE);
++
 +      /* Debugging... */
 +      //DumpMemoryAllocMap();
 +
 +      /* Turn on paging mode of CPU*/
 +      WinLdrTurnOnPaging(LoaderBlock, PcrBasePage, TssBasePage, GdtIdt);
 +
 +      DbgPrint((DPRINT_WINDOWS, "Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",
 +              KiSystemStartup, LoaderBlockVA));
 +
 +      WinLdrpDumpMemoryDescriptors(LoaderBlockVA);
 +      WinLdrpDumpBootDriver(LoaderBlockVA);
 +      WinLdrpDumpArcDisks(LoaderBlockVA);
 +
 +      //FIXME: If I substitute this debugging checkpoint, GCC will "optimize away" the code below
 +      //while (1) {};
 +      /*asm(".intel_syntax noprefix\n");
 +              asm("test1:\n");
 +              asm("jmp test1\n");
 +      asm(".att_syntax\n");*/
 +
++      /* Pass control */
 +      (*KiSystemStartup)(LoaderBlockVA);
 +
 +      return;
 +}
 +
 +VOID
 +WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock)
 +{
 +      PLIST_ENTRY NextMd;
 +      PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
 +
 +      NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
 +
 +      while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
 +      {
 +              MemoryDescriptor = CONTAINING_RECORD(NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
 +
 +              DbgPrint((DPRINT_WINDOWS, "BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage,
 +                      MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType));
 +
 +              NextMd = MemoryDescriptor->ListEntry.Flink;
 +      }
 +}
 +
 +VOID
 +WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock)
 +{
 +      PLIST_ENTRY NextBd;
 +      PBOOT_DRIVER_LIST_ENTRY BootDriver;
 +
 +      NextBd = LoaderBlock->BootDriverListHead.Flink;
 +
 +      while (NextBd != &LoaderBlock->BootDriverListHead)
 +      {
 +              BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, ListEntry);
 +
 +              DbgPrint((DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
 +                      BootDriver->DataTableEntry, &BootDriver->RegistryPath));
 +
 +              NextBd = BootDriver->ListEntry.Flink;
 +      }
 +}
 +
 +VOID
 +WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock)
 +{
 +      PLIST_ENTRY NextBd;
 +      PARC_DISK_SIGNATURE ArcDisk;
 +
 +      NextBd = LoaderBlock->ArcDiskInformation->DiskSignatureListHead.Flink;
 +
 +      while (NextBd != &LoaderBlock->ArcDiskInformation->DiskSignatureListHead)
 +      {
 +              ArcDisk = CONTAINING_RECORD(NextBd, ARC_DISK_SIGNATURE, ListEntry);
 +
 +              DbgPrint((DPRINT_WINDOWS, "ArcDisk %s checksum: 0x%X, signature: 0x%X\n",
 +                      ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature));
 +
 +              NextBd = ArcDisk->ListEntry.Flink;
 +      }
 +}
 +