Merge trunk head (r43756)
[reactos.git] / reactos / ntoskrnl / mm / sysldr.c
index f7b4342..3030199 100644 (file)
-/*\r
-* PROJECT:         ReactOS Kernel\r
-* LICENSE:         GPL - See COPYING in the top level directory\r
-* FILE:            ntoskrnl/mm/sysldr.c\r
-* PURPOSE:         Contains the Kernel Loader (SYSLDR) for loading PE files.\r
-* PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)\r
-*/\r
-\r
-/* INCLUDES ******************************************************************/\r
-\r
-#include <ntoskrnl.h>\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-/* GCC's incompetence strikes again */\r
-__inline\r
-VOID\r
-sprintf_nt(IN PCHAR Buffer,\r
-           IN PCHAR Format,\r
-           IN ...)\r
-{\r
-    va_list ap;\r
-    va_start(ap, Format);\r
-    vsprintf(Buffer, Format, ap);\r
-    va_end(ap);\r
-}\r
-\r
-/* GLOBALS *******************************************************************/\r
-\r
-LIST_ENTRY PsLoadedModuleList;\r
-KSPIN_LOCK PsLoadedModuleSpinLock;\r
-ULONG_PTR PsNtosImageBase;\r
-KMUTANT MmSystemLoadLock;\r
-extern ULONG NtGlobalFlag;\r
-\r
-/* FUNCTIONS *****************************************************************/\r
-\r
-PVOID\r
-NTAPI\r
-MiCacheImageSymbols(IN PVOID BaseAddress)\r
-{\r
-    ULONG DebugSize;\r
-    PVOID DebugDirectory = NULL;\r
-    PAGED_CODE();\r
-\r
-    /* Make sure it's safe to access the image */\r
-    _SEH2_TRY\r
-    {\r
-        /* Get the debug directory */\r
-        DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress,\r
-                                                      TRUE,\r
-                                                      IMAGE_DIRECTORY_ENTRY_DEBUG,\r
-                                                      &DebugSize);\r
-    }\r
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)\r
-    {\r
-        /* Nothing */\r
-    }\r
-    _SEH2_END;\r
-\r
-    /* Return the directory */\r
-    return DebugDirectory;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-MiFreeBootDriverMemory(PVOID BaseAddress,\r
-                       ULONG Length)\r
-{\r
-    ULONG i;\r
-\r
-    /* Loop each page */\r
-    for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)\r
-    {\r
-        /* Free the page */\r
-        MmDeleteVirtualMapping(NULL,\r
-                               (PVOID)((ULONG_PTR)BaseAddress + i * PAGE_SIZE),\r
-                               TRUE,\r
-                               NULL,\r
-                               NULL);\r
-    }\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MiLoadImageSection(IN OUT PVOID *SectionPtr,\r
-                   OUT PVOID *ImageBase,\r
-                   IN PUNICODE_STRING FileName,\r
-                   IN BOOLEAN SessionLoad,\r
-                   IN PLDR_DATA_TABLE_ENTRY LdrEntry)\r
-{\r
-    PROS_SECTION_OBJECT Section = *SectionPtr;\r
-    NTSTATUS Status;\r
-    PEPROCESS Process;\r
-    PVOID Base = NULL;\r
-    SIZE_T ViewSize = 0;\r
-    KAPC_STATE ApcState;\r
-    LARGE_INTEGER SectionOffset = {{0, 0}};\r
-    BOOLEAN LoadSymbols = FALSE;\r
-    ULONG DriverSize;\r
-    PVOID DriverBase;\r
-    PAGED_CODE();\r
-\r
-    /* Detect session load */\r
-    if (SessionLoad)\r
-    {\r
-        /* Fail */\r
-        DPRINT1("Session loading not yet supported!\n");\r
-        while (TRUE);\r
-    }\r
-\r
-    /* Not session load, shouldn't have an entry */\r
-    ASSERT(LdrEntry == NULL);\r
-\r
-    /* Attach to the system process */\r
-    KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);\r
-\r
-    /* Check if we need to load symbols */\r
-    if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)\r
-    {\r
-        /* Yes we do */\r
-        LoadSymbols = TRUE;\r
-        NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;\r
-    }\r
-\r
-    /* Map the driver */\r
-    Process = PsGetCurrentProcess();\r
-    Status = MmMapViewOfSection(Section,\r
-                                Process,\r
-                                &Base,\r
-                                0,\r
-                                0,\r
-                                &SectionOffset,\r
-                                &ViewSize,\r
-                                ViewUnmap,\r
-                                0,\r
-                                PAGE_EXECUTE);\r
-\r
-    /* Re-enable the flag */\r
-    if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;\r
-\r
-    /* Check if we failed with distinguished status code */\r
-    if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)\r
-    {\r
-        /* Change it to something more generic */\r
-        Status = STATUS_INVALID_IMAGE_FORMAT;\r
-    }\r
-\r
-    /* Now check if we failed */\r
-    if (!NT_SUCCESS(Status))\r
-    {\r
-        /* Detach and return */\r
-        KeUnstackDetachProcess(&ApcState);\r
-        return Status;\r
-    }\r
-\r
-    /* Get the driver size */\r
-    DriverSize = Section->ImageSection->ImageSize;\r
-\r
-    /*  Allocate a virtual section for the module  */\r
-    DriverBase = MmAllocateSection(DriverSize, NULL);\r
-    *ImageBase = DriverBase;\r
-\r
-    /* Copy the image */\r
-    RtlCopyMemory(DriverBase, Base, DriverSize);\r
-\r
-    /* Now unmap the view */\r
-    Status = MmUnmapViewOfSection(Process, Base);\r
-    ASSERT(NT_SUCCESS(Status));\r
-\r
-    /* Detach and return status */\r
-    KeUnstackDetachProcess(&ApcState);\r
-    return Status;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MiDereferenceImports(IN PLOAD_IMPORTS ImportList)\r
-{\r
-    SIZE_T i;\r
-\r
-    /* Check if there's no imports or if we're a boot driver */\r
-    if ((ImportList == (PVOID)-1) ||\r
-        (ImportList == (PVOID)-2) ||\r
-        (ImportList->Count == 0))\r
-    {\r
-        /* Then there's nothing to do */\r
-        return STATUS_SUCCESS;\r
-    }\r
-\r
-    /* Otherwise, FIXME */\r
-    DPRINT1("%u imports not dereferenced!\n", ImportList->Count);\r
-    for (i = 0; i < ImportList->Count; i++)\r
-    {\r
-        DPRINT1("%wZ <%wZ>\n", &ImportList->Entry[i]->FullDllName, &ImportList->Entry[i]->BaseDllName);\r
-    }\r
-    return STATUS_UNSUCCESSFUL;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)\r
-{\r
-    PAGED_CODE();\r
-\r
-    /* Check if there's no imports or we're a boot driver or only one entry */\r
-    if ((LdrEntry->LoadedImports == (PVOID)-1) ||\r
-        (LdrEntry->LoadedImports == (PVOID)-2) ||\r
-        ((ULONG_PTR)LdrEntry->LoadedImports & 1))\r
-    {\r
-        /* Nothing to do */\r
-        return;\r
-    }\r
-\r
-    /* Otherwise, free the import list */\r
-    ExFreePool(LdrEntry->LoadedImports);\r
-}\r
-\r
-PVOID\r
-NTAPI\r
-MiFindExportedRoutineByName(IN PVOID DllBase,\r
-                            IN PANSI_STRING ExportName)\r
-{\r
-    PULONG NameTable;\r
-    PUSHORT OrdinalTable;\r
-    PIMAGE_EXPORT_DIRECTORY ExportDirectory;\r
-    LONG Low = 0, Mid = 0, High, Ret;\r
-    USHORT Ordinal;\r
-    PVOID Function;\r
-    ULONG ExportSize;\r
-    PULONG ExportTable;\r
-    PAGED_CODE();\r
-\r
-    /* Get the export directory */\r
-    ExportDirectory = RtlImageDirectoryEntryToData(DllBase,\r
-                                                   TRUE,\r
-                                                   IMAGE_DIRECTORY_ENTRY_EXPORT,\r
-                                                   &ExportSize);\r
-    if (!ExportDirectory) return NULL;\r
-\r
-    /* Setup name tables */\r
-    NameTable = (PULONG)((ULONG_PTR)DllBase +\r
-                         ExportDirectory->AddressOfNames);\r
-    OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +\r
-                             ExportDirectory->AddressOfNameOrdinals);\r
-\r
-    /* Do a binary search */\r
-    High = ExportDirectory->NumberOfNames - 1;\r
-    while (High >= Low)\r
-    {\r
-        /* Get new middle value */\r
-        Mid = (Low + High) >> 1;\r
-\r
-        /* Compare name */\r
-        Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);\r
-        if (Ret < 0)\r
-        {\r
-            /* Update high */\r
-            High = Mid - 1;\r
-        }\r
-        else if (Ret > 0)\r
-        {\r
-            /* Update low */\r
-            Low = Mid + 1;\r
-        }\r
-        else\r
-        {\r
-            /* We got it */\r
-            break;\r
-        }\r
-    }\r
-\r
-    /* Check if we couldn't find it */\r
-    if (High < Low) return NULL;\r
-\r
-    /* Otherwise, this is the ordinal */\r
-    Ordinal = OrdinalTable[Mid];\r
-\r
-    /* Resolve the address and write it */\r
-    ExportTable = (PULONG)((ULONG_PTR)DllBase +\r
-                           ExportDirectory->AddressOfFunctions);\r
-    Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);\r
-\r
-    /* We found it! */\r
-    ASSERT(!(Function > (PVOID)ExportDirectory) &&\r
-           (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));\r
-    return Function;\r
-}\r
-\r
-PVOID\r
-NTAPI\r
-MiLocateExportName(IN PVOID DllBase,\r
-                   IN PCHAR ExportName)\r
-{\r
-    PULONG NameTable;\r
-    PUSHORT OrdinalTable;\r
-    PIMAGE_EXPORT_DIRECTORY ExportDirectory;\r
-    LONG Low = 0, Mid = 0, High, Ret;\r
-    USHORT Ordinal;\r
-    PVOID Function;\r
-    ULONG ExportSize;\r
-    PULONG ExportTable;\r
-    PAGED_CODE();\r
-\r
-    /* Get the export directory */\r
-    ExportDirectory = RtlImageDirectoryEntryToData(DllBase,\r
-                                                   TRUE,\r
-                                                   IMAGE_DIRECTORY_ENTRY_EXPORT,\r
-                                                   &ExportSize);\r
-    if (!ExportDirectory) return NULL;\r
-\r
-    /* Setup name tables */\r
-    NameTable = (PULONG)((ULONG_PTR)DllBase +\r
-                         ExportDirectory->AddressOfNames);\r
-    OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +\r
-                             ExportDirectory->AddressOfNameOrdinals);\r
-\r
-    /* Do a binary search */\r
-    High = ExportDirectory->NumberOfNames - 1;\r
-    while (High >= Low)\r
-    {\r
-        /* Get new middle value */\r
-        Mid = (Low + High) >> 1;\r
-\r
-        /* Compare name */\r
-        Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);\r
-        if (Ret < 0)\r
-        {\r
-            /* Update high */\r
-            High = Mid - 1;\r
-        }\r
-        else if (Ret > 0)\r
-        {\r
-            /* Update low */\r
-            Low = Mid + 1;\r
-        }\r
-        else\r
-        {\r
-            /* We got it */\r
-            break;\r
-        }\r
-    }\r
-\r
-    /* Check if we couldn't find it */\r
-    if (High < Low) return NULL;\r
-\r
-    /* Otherwise, this is the ordinal */\r
-    Ordinal = OrdinalTable[Mid];\r
-\r
-    /* Resolve the address and write it */\r
-    ExportTable = (PULONG)((ULONG_PTR)DllBase +\r
-                           ExportDirectory->AddressOfFunctions);\r
-    Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);\r
-\r
-    /* Check if the function is actually a forwarder */\r
-    if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&\r
-        ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))\r
-    {\r
-        /* It is, fail */\r
-        return NULL;\r
-    }\r
-\r
-    /* We found it */\r
-    return Function;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,\r
-                    IN PLIST_ENTRY ListHead)\r
-{\r
-    UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(\r
-        L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");\r
-    PMM_DLL_INITIALIZE DllInit;\r
-    UNICODE_STRING RegPath, ImportName;\r
-    NTSTATUS Status;\r
-\r
-    /* Try to see if the image exports a DllInitialize routine */\r
-    DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,\r
-                                                     "DllInitialize");\r
-    if (!DllInit) return STATUS_SUCCESS;\r
-\r
-    /* Do a temporary copy of BaseDllName called ImportName\r
-     * because we'll alter the length of the string\r
-     */\r
-    ImportName.Length = LdrEntry->BaseDllName.Length;\r
-    ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;\r
-    ImportName.Buffer = LdrEntry->BaseDllName.Buffer;\r
-\r
-    /* Obtain the path to this dll's service in the registry */\r
-    RegPath.MaximumLength = ServicesKeyName.Length +\r
-        ImportName.Length + sizeof(UNICODE_NULL);\r
-    RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,\r
-                                           RegPath.MaximumLength,\r
-                                           TAG_LDR_WSTR);\r
-\r
-    /* Check if this allocation was unsuccessful */\r
-    if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;\r
-\r
-    /* Build and append the service name itself */\r
-    RegPath.Length = ServicesKeyName.Length;\r
-    RtlCopyMemory(RegPath.Buffer,\r
-                  ServicesKeyName.Buffer,\r
-                  ServicesKeyName.Length);\r
-\r
-    /* Check if there is a dot in the filename */\r
-    if (wcschr(ImportName.Buffer, L'.'))\r
-    {\r
-        /* Remove the extension */\r
-        ImportName.Length = (wcschr(ImportName.Buffer, L'.') -\r
-            ImportName.Buffer) * sizeof(WCHAR);\r
-    }\r
-\r
-    /* Append service name (the basename without extension) */\r
-    RtlAppendUnicodeStringToString(&RegPath, &ImportName);\r
-\r
-    /* Now call the DllInit func */\r
-    DPRINT("Calling DllInit(%wZ)\n", &RegPath);\r
-    Status = DllInit(&RegPath);\r
-\r
-    /* Clean up */\r
-    ExFreePool(RegPath.Buffer);\r
-\r
-    /* Return status value which DllInitialize returned */\r
-    return Status;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,\r
-                     IN BOOLEAN Insert)\r
-{\r
-    KIRQL OldIrql;\r
-\r
-    /* Acquire the lock */\r
-    KeAcquireSpinLock(&PsLoadedModuleSpinLock, &OldIrql);\r
-\r
-    /* Insert or remove from the list */\r
-    Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :\r
-             RemoveEntryList(&LdrEntry->InLoadOrderLinks);\r
-\r
-    /* Release the lock */\r
-    KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);\r
-}\r
-\r
-VOID\r
-NTAPI\r
-MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,\r
-               IN PVOID OldBase,\r
-               IN PVOID NewBase,\r
-               IN ULONG Size)\r
-{\r
-    ULONG_PTR OldBaseTop, Delta;\r
-    PLDR_DATA_TABLE_ENTRY LdrEntry;\r
-    PLIST_ENTRY NextEntry;\r
-    ULONG ImportSize;\r
-    PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;\r
-    PULONG ImageThunk;\r
-\r
-    /* Calculate the top and delta */\r
-    OldBaseTop = (ULONG_PTR)OldBase + Size - 1;\r
-    Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;\r
-\r
-    /* Loop the loader block */\r
-    for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;\r
-         NextEntry != &LoaderBlock->LoadOrderListHead;\r
-         NextEntry = NextEntry->Flink)\r
-    {\r
-        /* Get the loader entry */\r
-        LdrEntry = CONTAINING_RECORD(NextEntry,\r
-                                     LDR_DATA_TABLE_ENTRY,\r
-                                     InLoadOrderLinks);\r
-\r
-        /* Get the import table */\r
-        ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,\r
-                                                        TRUE,\r
-                                                        IMAGE_DIRECTORY_ENTRY_IMPORT,\r
-                                                        &ImportSize);\r
-        if (!ImportDescriptor) continue;\r
-\r
-        /* Make sure we have an IAT */\r
-        DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);\r
-        while ((ImportDescriptor->Name) &&\r
-               (ImportDescriptor->OriginalFirstThunk))\r
-        {\r
-            /* Get the image thunk */\r
-            ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +\r
-                                 ImportDescriptor->FirstThunk);\r
-            while (*ImageThunk)\r
-            {\r
-                /* Check if it's within this module */\r
-                if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))\r
-                {\r
-                    /* Relocate it */\r
-                    DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",\r
-                            ImageThunk, *ImageThunk, *ImageThunk + Delta);\r
-                    *ImageThunk += Delta;\r
-                }\r
-\r
-                /* Go to the next thunk */\r
-                ImageThunk++;\r
-            }\r
-\r
-            /* Go to the next import */\r
-            ImportDescriptor++;\r
-        }\r
-    }\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MiSnapThunk(IN PVOID DllBase,\r
-            IN PVOID ImageBase,\r
-            IN PIMAGE_THUNK_DATA Name,\r
-            IN PIMAGE_THUNK_DATA Address,\r
-            IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,\r
-            IN ULONG ExportSize,\r
-            IN BOOLEAN SnapForwarder,\r
-            OUT PCHAR *MissingApi)\r
-{\r
-    BOOLEAN IsOrdinal;\r
-    USHORT Ordinal;\r
-    PULONG NameTable;\r
-    PUSHORT OrdinalTable;\r
-    PIMAGE_IMPORT_BY_NAME NameImport;\r
-    USHORT Hint;\r
-    ULONG Low = 0, Mid = 0, High;\r
-    LONG Ret;\r
-    NTSTATUS Status;\r
-    PCHAR MissingForwarder;\r
-    CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];\r
-    PULONG ExportTable;\r
-    ANSI_STRING DllName;\r
-    UNICODE_STRING ForwarderName;\r
-    PLIST_ENTRY NextEntry;\r
-    PLDR_DATA_TABLE_ENTRY LdrEntry;\r
-    ULONG ForwardExportSize;\r
-    PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;\r
-    PIMAGE_IMPORT_BY_NAME ForwardName;\r
-    ULONG ForwardLength;\r
-    IMAGE_THUNK_DATA ForwardThunk;\r
-    PAGED_CODE();\r
-\r
-    /* Check if this is an ordinal */\r
-    IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);\r
-    if ((IsOrdinal) && !(SnapForwarder))\r
-    {\r
-        /* Get the ordinal number and set it as missing */\r
-        Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -\r
-                           ExportDirectory->Base);\r
-        *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;\r
-    }\r
-    else\r
-    {\r
-        /* Get the VA if we don't have to snap */\r
-        if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;\r
-        NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;\r
-\r
-        /* Copy the procedure name */\r
-        strncpy(*MissingApi,\r
-                (PCHAR)&NameImport->Name[0],\r
-                MAXIMUM_FILENAME_LENGTH - 1);\r
-\r
-        /* Setup name tables */\r
-        DPRINT("Import name: %s\n", NameImport->Name);\r
-        NameTable = (PULONG)((ULONG_PTR)DllBase +\r
-                             ExportDirectory->AddressOfNames);\r
-        OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +\r
-                                 ExportDirectory->AddressOfNameOrdinals);\r
-\r
-        /* Get the hint and check if it's valid */\r
-        Hint = NameImport->Hint;\r
-        if ((Hint < ExportDirectory->NumberOfNames) &&\r
-            !(strcmp((PCHAR) NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))\r
-        {\r
-            /* We have a match, get the ordinal number from here */\r
-            Ordinal = OrdinalTable[Hint];\r
-        }\r
-        else\r
-        {\r
-            /* Do a binary search */\r
-            High = ExportDirectory->NumberOfNames - 1;\r
-            while (High >= Low)\r
-            {\r
-                /* Get new middle value */\r
-                Mid = (Low + High) >> 1;\r
-\r
-                /* Compare name */\r
-                Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);\r
-                if (Ret < 0)\r
-                {\r
-                    /* Update high */\r
-                    High = Mid - 1;\r
-                }\r
-                else if (Ret > 0)\r
-                {\r
-                    /* Update low */\r
-                    Low = Mid + 1;\r
-                }\r
-                else\r
-                {\r
-                    /* We got it */\r
-                    break;\r
-                }\r
-            }\r
-\r
-            /* Check if we couldn't find it */\r
-            if (High < Low) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;\r
-\r
-            /* Otherwise, this is the ordinal */\r
-            Ordinal = OrdinalTable[Mid];\r
-        }\r
-    }\r
-\r
-    /* Check if the ordinal is invalid */\r
-    if (Ordinal >= ExportDirectory->NumberOfFunctions)\r
-    {\r
-        /* Fail */\r
-        Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;\r
-    }\r
-    else\r
-    {\r
-        /* In case the forwarder is missing */\r
-        MissingForwarder = NameBuffer;\r
-\r
-        /* Resolve the address and write it */\r
-        ExportTable = (PULONG)((ULONG_PTR)DllBase +\r
-                               ExportDirectory->AddressOfFunctions);\r
-        Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];\r
-\r
-        /* Assume success from now on */\r
-        Status = STATUS_SUCCESS;\r
-\r
-        /* Check if the function is actually a forwarder */\r
-        if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&\r
-            (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))\r
-        {\r
-            /* Now assume failure in case the forwarder doesn't exist */\r
-            Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;\r
-\r
-            /* Build the forwarder name */\r
-            DllName.Buffer = (PCHAR)Address->u1.Function;\r
-            DllName.Length = strchr(DllName.Buffer, '.') -\r
-                             DllName.Buffer +\r
-                             sizeof(ANSI_NULL);\r
-            DllName.MaximumLength = DllName.Length;\r
-\r
-            /* Convert it */\r
-            if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,\r
-                                                         &DllName,\r
-                                                         TRUE)))\r
-            {\r
-                /* We failed, just return an error */\r
-                return Status;\r
-            }\r
-\r
-            /* Loop the module list */\r
-            NextEntry = PsLoadedModuleList.Flink;\r
-            while (NextEntry != &PsLoadedModuleList)\r
-            {\r
-                /* Get the loader entry */\r
-                LdrEntry = CONTAINING_RECORD(NextEntry,\r
-                                             LDR_DATA_TABLE_ENTRY,\r
-                                             InLoadOrderLinks);\r
-\r
-                /* Check if it matches */\r
-                if (RtlPrefixString((PSTRING)&ForwarderName,\r
-                                    (PSTRING)&LdrEntry->BaseDllName,\r
-                                    TRUE))\r
-                {\r
-                    /* Get the forwarder export directory */\r
-                    ForwardExportDirectory =\r
-                        RtlImageDirectoryEntryToData(LdrEntry->DllBase,\r
-                                                     TRUE,\r
-                                                     IMAGE_DIRECTORY_ENTRY_EXPORT,\r
-                                                     &ForwardExportSize);\r
-                    if (!ForwardExportDirectory) break;\r
-\r
-                    /* Allocate a name entry */\r
-                    ForwardLength = strlen(DllName.Buffer + DllName.Length) +\r
-                                    sizeof(ANSI_NULL);\r
-                    ForwardName = ExAllocatePoolWithTag(PagedPool,\r
-                                                        sizeof(*ForwardName) +\r
-                                                        ForwardLength,\r
-                                                        TAG_LDR_WSTR);\r
-                    if (!ForwardName) break;\r
-\r
-                    /* Copy the data */\r
-                    RtlCopyMemory(&ForwardName->Name[0],\r
-                                  DllName.Buffer + DllName.Length,\r
-                                  ForwardLength);\r
-                    ForwardName->Hint = 0;\r
-\r
-                    /* Set the new address */\r
-                    ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName;\r
-\r
-                    /* Snap the forwarder */\r
-                    Status = MiSnapThunk(LdrEntry->DllBase,\r
-                                         ImageBase,\r
-                                         &ForwardThunk,\r
-                                         &ForwardThunk,\r
-                                         ForwardExportDirectory,\r
-                                         ForwardExportSize,\r
-                                         TRUE,\r
-                                         &MissingForwarder);\r
-\r
-                    /* Free the forwarder name and set the thunk */\r
-                    ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR);\r
-                    Address->u1 = ForwardThunk.u1;\r
-                    break;\r
-                }\r
-\r
-                /* Go to the next entry */\r
-                NextEntry = NextEntry->Flink;\r
-            }\r
-\r
-            /* Free the name */\r
-            RtlFreeUnicodeString(&ForwarderName);\r
-        }\r
-    }\r
-\r
-    /* Return status */\r
-    return Status;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MmUnloadSystemImage(IN PVOID ImageHandle)\r
-{\r
-    PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;\r
-    PVOID BaseAddress = LdrEntry->DllBase;\r
-    NTSTATUS Status;\r
-    ANSI_STRING TempName;\r
-    BOOLEAN HadEntry = FALSE;\r
-\r
-    /* Acquire the loader lock */\r
-    KeEnterCriticalRegion();\r
-    KeWaitForSingleObject(&MmSystemLoadLock,\r
-                          WrVirtualMemory,\r
-                          KernelMode,\r
-                          FALSE,\r
-                          NULL);\r
-\r
-    /* Check if this driver was loaded at boot and didn't get imports parsed */\r
-    if (LdrEntry->LoadedImports == (PVOID)-1) goto Done;\r
-\r
-    /* We should still be alive */\r
-    ASSERT(LdrEntry->LoadCount != 0);\r
-    LdrEntry->LoadCount--;\r
-\r
-    /* Check if we're still loaded */\r
-    if (LdrEntry->LoadCount) goto Done;\r
-\r
-    /* We should cleanup... are symbols loaded */\r
-    if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)\r
-    {\r
-        /* Create the ANSI name */\r
-        Status = RtlUnicodeStringToAnsiString(&TempName,\r
-                                              &LdrEntry->BaseDllName,\r
-                                              TRUE);\r
-        if (NT_SUCCESS(Status))\r
-        {\r
-            /* Unload the symbols */\r
-            DbgUnLoadImageSymbols(&TempName, BaseAddress, -1);\r
-            RtlFreeAnsiString(&TempName);\r
-        }\r
-    }\r
-\r
-    /* FIXME: Free the driver */\r
-    //MmFreeSection(LdrEntry->DllBase);\r
-\r
-    /* Check if we're linked in */\r
-    if (LdrEntry->InLoadOrderLinks.Flink)\r
-    {\r
-        /* Remove us */\r
-        MiProcessLoaderEntry(LdrEntry, FALSE);\r
-        HadEntry = TRUE;\r
-    }\r
-\r
-    /* Dereference and clear the imports */\r
-    MiDereferenceImports(LdrEntry->LoadedImports);\r
-    MiClearImports(LdrEntry);\r
-\r
-    /* Check if the entry needs to go away */\r
-    if (HadEntry)\r
-    {\r
-        /* Check if it had a name */\r
-        if (LdrEntry->FullDllName.Buffer)\r
-        {\r
-            /* Free it */\r
-            ExFreePool(LdrEntry->FullDllName.Buffer);\r
-        }\r
-\r
-        /* Check if we had a section */\r
-        if (LdrEntry->SectionPointer)\r
-        {\r
-            /* Dereference it */\r
-            ObDereferenceObject(LdrEntry->SectionPointer);\r
-        }\r
-\r
-        /* Free the entry */\r
-        ExFreePool(LdrEntry);\r
-    }\r
-\r
-    /* Release the system lock and return */\r
-Done:\r
-    KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);\r
-    KeLeaveCriticalRegion();\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MiResolveImageReferences(IN PVOID ImageBase,\r
-                         IN PUNICODE_STRING ImageFileDirectory,\r
-                         IN PUNICODE_STRING NamePrefix OPTIONAL,\r
-                         OUT PCHAR *MissingApi,\r
-                         OUT PWCHAR *MissingDriver,\r
-                         OUT PLOAD_IMPORTS *LoadImports)\r
-{\r
-    PCHAR MissingApiBuffer = *MissingApi, ImportName;\r
-    PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;\r
-    ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;\r
-    PLOAD_IMPORTS LoadedImports, NewImports;\r
-    ULONG GdiLink, NormalLink, i;\r
-    BOOLEAN ReferenceNeeded, Loaded;\r
-    ANSI_STRING TempString;\r
-    UNICODE_STRING NameString, DllName;\r
-    PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;\r
-    PVOID ImportBase, DllBase;\r
-    PLIST_ENTRY NextEntry;\r
-    PIMAGE_EXPORT_DIRECTORY ExportDirectory;\r
-    NTSTATUS Status;\r
-    PIMAGE_THUNK_DATA OrigThunk, FirstThunk;\r
-    PAGED_CODE();\r
-    DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",\r
-           __FUNCTION__, ImageBase, ImageFileDirectory);\r
-\r
-    /* Assume no imports */\r
-    *LoadImports = (PVOID)-2;\r
-\r
-    /* Get the import descriptor */\r
-    ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,\r
-                                                    TRUE,\r
-                                                    IMAGE_DIRECTORY_ENTRY_IMPORT,\r
-                                                    &ImportSize);\r
-    if (!ImportDescriptor) return STATUS_SUCCESS;\r
-\r
-    /* Loop all imports to count them */\r
-    for (CurrentImport = ImportDescriptor;\r
-         (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);\r
-         CurrentImport++)\r
-    {\r
-        /* One more */\r
-        ImportCount++;\r
-    }\r
-\r
-    /* Make sure we have non-zero imports */\r
-    if (ImportCount)\r
-    {\r
-        /* Calculate and allocate the list we'll need */\r
-        LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);\r
-        LoadedImports = ExAllocatePoolWithTag(PagedPool,\r
-                                              LoadedImportsSize,\r
-                                              TAG_LDR_WSTR);\r
-        if (LoadedImports)\r
-        {\r
-            /* Zero it */\r
-            RtlZeroMemory(LoadedImports, LoadedImportsSize);\r
-        }\r
-    }\r
-    else\r
-    {\r
-        /* No table */\r
-        LoadedImports = NULL;\r
-    }\r
-\r
-    /* Reset the import count and loop descriptors again */\r
-    ImportCount = GdiLink = NormalLink = 0;\r
-    while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))\r
-    {\r
-        /* Get the name */\r
-        ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);\r
-\r
-        /* Check if this is a GDI driver */\r
-        GdiLink = GdiLink |\r
-                  !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));\r
-\r
-        /* We can also allow dxapi */\r
-        NormalLink = NormalLink |\r
-                     ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&\r
-                      (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)));\r
-\r
-        /* Check if this is a valid GDI driver */\r
-        if ((GdiLink) && (NormalLink))\r
-        {\r
-            /* It's not, it's importing stuff it shouldn't be! */\r
-            MiDereferenceImports(LoadedImports);\r
-            if (LoadedImports) ExFreePool(LoadedImports);\r
-            return STATUS_PROCEDURE_NOT_FOUND;\r
-        }\r
-\r
-        /* Check if this is a "core" import, which doesn't get referenced */\r
-        if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||\r
-            !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||\r
-            !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))\r
-        {\r
-            /* Don't reference this */\r
-            ReferenceNeeded = FALSE;\r
-        }\r
-        else\r
-        {\r
-            /* Reference these modules */\r
-            ReferenceNeeded = TRUE;\r
-        }\r
-\r
-        /* Now setup a unicode string for the import */\r
-        RtlInitAnsiString(&TempString, ImportName);\r
-        Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);\r
-        if (!NT_SUCCESS(Status))\r
-        {\r
-            /* Failed */\r
-            MiDereferenceImports(LoadedImports);\r
-            if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
-            return Status;\r
-        }\r
-\r
-        /* We don't support name prefixes yet */\r
-        if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");\r
-\r
-        /* Remember that we haven't loaded the import at this point */\r
-CheckDllState:\r
-        Loaded = FALSE;\r
-        ImportBase = NULL;\r
-\r
-        /* Loop the driver list */\r
-        NextEntry = PsLoadedModuleList.Flink;\r
-        while (NextEntry != &PsLoadedModuleList)\r
-        {\r
-            /* Get the loader entry and compare the name */\r
-            LdrEntry = CONTAINING_RECORD(NextEntry,\r
-                                         LDR_DATA_TABLE_ENTRY,\r
-                                         InLoadOrderLinks);\r
-            if (RtlEqualUnicodeString(&NameString,\r
-                                      &LdrEntry->BaseDllName,\r
-                                      TRUE))\r
-            {\r
-                /* Get the base address */\r
-                ImportBase = LdrEntry->DllBase;\r
-\r
-                /* Check if we haven't loaded yet, and we need references */\r
-                if (!(Loaded) && (ReferenceNeeded))\r
-                {\r
-                    /* Make sure we're not already loading */\r
-                    if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))\r
-                    {\r
-                        /* Increase the load count */\r
-                        LdrEntry->LoadCount++;\r
-                    }\r
-                }\r
-\r
-                /* Done, break out */\r
-                break;\r
-            }\r
-\r
-            /* Go to the next entry */\r
-            NextEntry = NextEntry->Flink;\r
-        }\r
-\r
-        /* Check if we haven't loaded the import yet */\r
-        if (!ImportBase)\r
-        {\r
-            /* Setup the import DLL name */\r
-            DllName.MaximumLength = NameString.Length +\r
-                                    ImageFileDirectory->Length +\r
-                                    sizeof(UNICODE_NULL);\r
-            DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,\r
-                                                   DllName.MaximumLength,\r
-                                                   TAG_LDR_WSTR);\r
-            if (DllName.Buffer)\r
-            {\r
-                /* Setup the base length and copy it */\r
-                DllName.Length = ImageFileDirectory->Length;\r
-                RtlCopyMemory(DllName.Buffer,\r
-                              ImageFileDirectory->Buffer,\r
-                              ImageFileDirectory->Length);\r
-\r
-                /* Now add the import name and null-terminate it */\r
-                RtlAppendStringToString((PSTRING)&DllName,\r
-                                        (PSTRING)&NameString);\r
-                DllName.Buffer[(DllName.MaximumLength - 1) / 2] = UNICODE_NULL;\r
-\r
-                /* Load the image */\r
-                Status = MmLoadSystemImage(&DllName,\r
-                                           NamePrefix,\r
-                                           NULL,\r
-                                           0,\r
-                                           (PVOID)&DllEntry,\r
-                                           &DllBase);\r
-                if (NT_SUCCESS(Status))\r
-                {\r
-                    /* We can free the DLL Name */\r
-                    ExFreePool(DllName.Buffer);\r
-                }\r
-                else\r
-                {\r
-                    /* Fill out the information for the error */\r
-                    *MissingDriver = DllName.Buffer;\r
-                    *(PULONG)MissingDriver |= 1;\r
-                    *MissingApi = NULL;\r
-                }\r
-            }\r
-            else\r
-            {\r
-                /* We're out of resources */\r
-                Status = STATUS_INSUFFICIENT_RESOURCES;\r
-            }\r
-\r
-            /* Check if we're OK until now */\r
-            if (NT_SUCCESS(Status))\r
-            {\r
-                /* We're now loaded */\r
-                Loaded = TRUE;\r
-\r
-                /* Sanity check */\r
-                ASSERT(DllBase = DllEntry->DllBase);\r
-\r
-                /* Call the initialization routines */\r
-                Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);\r
-                if (!NT_SUCCESS(Status))\r
-                {\r
-                    /* We failed, unload the image */\r
-                    MmUnloadSystemImage(DllEntry);\r
-                    while (TRUE);\r
-                    Loaded = FALSE;\r
-                }\r
-            }\r
-\r
-            /* Check if we failed by here */\r
-            if (!NT_SUCCESS(Status))\r
-            {\r
-                /* Cleanup and return */\r
-                RtlFreeUnicodeString(&NameString);\r
-                MiDereferenceImports(LoadedImports);\r
-                if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
-                return Status;\r
-            }\r
-\r
-            /* Loop again to make sure that everything is OK */\r
-            goto CheckDllState;\r
-        }\r
-\r
-        /* Check if we're support to reference this import */\r
-        if ((ReferenceNeeded) && (LoadedImports))\r
-        {\r
-            /* Make sure we're not already loading */\r
-            if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))\r
-            {\r
-                /* Add the entry */\r
-                LoadedImports->Entry[LoadedImports->Count] = LdrEntry;\r
-                LoadedImports->Count++;\r
-            }\r
-        }\r
-\r
-        /* Free the import name */\r
-        RtlFreeUnicodeString(&NameString);\r
-\r
-        /* Set the missing driver name and get the export directory */\r
-        *MissingDriver = LdrEntry->BaseDllName.Buffer;\r
-        ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,\r
-                                                       TRUE,\r
-                                                       IMAGE_DIRECTORY_ENTRY_EXPORT,\r
-                                                       &ExportSize);\r
-        if (!ExportDirectory)\r
-        {\r
-            /* Cleanup and return */\r
-            MiDereferenceImports(LoadedImports);\r
-            if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
-            return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;\r
-        }\r
-\r
-        /* Make sure we have an IAT */\r
-        if (ImportDescriptor->OriginalFirstThunk)\r
-        {\r
-            /* Get the first thunks */\r
-            OrigThunk = (PVOID)((ULONG_PTR)ImageBase +\r
-                                ImportDescriptor->OriginalFirstThunk);\r
-            FirstThunk = (PVOID)((ULONG_PTR)ImageBase +\r
-                                 ImportDescriptor->FirstThunk);\r
-\r
-            /* Loop the IAT */\r
-            while (OrigThunk->u1.AddressOfData)\r
-            {\r
-                /* Snap thunk */\r
-                Status = MiSnapThunk(ImportBase,\r
-                                     ImageBase,\r
-                                     OrigThunk++,\r
-                                     FirstThunk++,\r
-                                     ExportDirectory,\r
-                                     ExportSize,\r
-                                     FALSE,\r
-                                     MissingApi);\r
-                if (!NT_SUCCESS(Status))\r
-                {\r
-                    /* Cleanup and return */\r
-                    MiDereferenceImports(LoadedImports);\r
-                    if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
-                    return Status;\r
-                }\r
-\r
-                /* Reset the buffer */\r
-                *MissingApi = MissingApiBuffer;\r
-            }\r
-        }\r
-\r
-        /* Go to the next import */\r
-        ImportDescriptor++;\r
-    }\r
-\r
-    /* Check if we have an import list */\r
-    if (LoadedImports)\r
-    {\r
-        /* Reset the count again, and loop entries*/\r
-        ImportCount = 0;\r
-        for (i = 0; i < LoadedImports->Count; i++)\r
-        {\r
-            if (LoadedImports->Entry[i])\r
-            {\r
-                /* Got an entry, OR it with 1 in case it's the single entry */\r
-                ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 1);\r
-                ImportCount++;\r
-            }\r
-        }\r
-\r
-        /* Check if we had no imports */\r
-        if (!ImportCount)\r
-        {\r
-            /* Free the list and set it to no imports */\r
-            ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
-            LoadedImports = (PVOID)-2;\r
-        }\r
-        else if (ImportCount == 1)\r
-        {\r
-            /* Just one entry, we can free the table and only use our entry */\r
-            ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
-            LoadedImports = (PLOAD_IMPORTS)ImportEntry;\r
-        }\r
-        else if (ImportCount != LoadedImports->Count)\r
-        {\r
-            /* Allocate a new list */\r
-            LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);\r
-            NewImports = ExAllocatePoolWithTag(PagedPool,\r
-                                               LoadedImportsSize,\r
-                                               TAG_LDR_WSTR);\r
-            if (NewImports)\r
-            {\r
-                /* Set count */\r
-                NewImports->Count = 0;\r
-\r
-                /* Loop all the imports */\r
-                for (i = 0; i < LoadedImports->Count; i++)\r
-                {\r
-                    /* Make sure it's valid */\r
-                    if (LoadedImports->Entry[i])\r
-                    {\r
-                        /* Copy it */\r
-                        NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];\r
-                        NewImports->Count++;\r
-                    }\r
-                }\r
-\r
-                /* Free the old copy */\r
-                ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);\r
-                LoadedImports = NewImports;\r
-            }\r
-        }\r
-\r
-        /* Return the list */\r
-        *LoadImports = LoadedImports;\r
-    }\r
-\r
-    /* Return success */\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)\r
-{\r
-    PLIST_ENTRY NextEntry;\r
-    ULONG i = 0;\r
-    PIMAGE_NT_HEADERS NtHeader;\r
-    PLDR_DATA_TABLE_ENTRY LdrEntry;\r
-    PIMAGE_FILE_HEADER FileHeader;\r
-    BOOLEAN ValidRelocs;\r
-    PIMAGE_DATA_DIRECTORY DataDirectory;\r
-    PVOID DllBase, NewImageAddress;\r
-    NTSTATUS Status;\r
-\r
-    /* Loop driver list */\r
-    for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;\r
-         NextEntry != &LoaderBlock->LoadOrderListHead;\r
-         NextEntry = NextEntry->Flink)\r
-    {\r
-        /* Get the loader entry and NT header */\r
-        LdrEntry = CONTAINING_RECORD(NextEntry,\r
-                                     LDR_DATA_TABLE_ENTRY,\r
-                                     InLoadOrderLinks);\r
-        NtHeader = RtlImageNtHeader(LdrEntry->DllBase);\r
-\r
-        /* Debug info */\r
-        DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",\r
-                LdrEntry->DllBase,\r
-                (ULONG_PTR)LdrEntry->DllBase+ LdrEntry->SizeOfImage,\r
-                &LdrEntry->FullDllName);\r
-\r
-        /* Skip kernel and HAL */\r
-        /* ROS HACK: Skip BOOTVID/KDCOM too */\r
-        i++;\r
-        if (i <= 4) continue;\r
-\r
-        /* Skip non-drivers */\r
-        if (!NtHeader) continue;\r
-\r
-        /* Get the file header and make sure we can relocate */\r
-        FileHeader = &NtHeader->FileHeader;\r
-        if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;\r
-        if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <\r
-            IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;\r
-\r
-        /* Everything made sense until now, check the relocation section too */\r
-        DataDirectory = &NtHeader->OptionalHeader.\r
-                        DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
-        if (!DataDirectory->VirtualAddress)\r
-        {\r
-            /* We don't really have relocations */\r
-            ValidRelocs = FALSE;\r
-        }\r
-        else\r
-        {\r
-            /* Make sure the size is valid */\r
-            if ((DataDirectory->VirtualAddress + DataDirectory->Size) >\r
-                LdrEntry->SizeOfImage)\r
-            {\r
-                /* They're not, skip */\r
-                continue;\r
-            }\r
-\r
-            /* We have relocations */\r
-            ValidRelocs = TRUE;\r
-        }\r
-\r
-        /* Remember the original address */\r
-        DllBase = LdrEntry->DllBase;\r
-\r
-        /*  Allocate a virtual section for the module  */\r
-        NewImageAddress = MmAllocateSection(LdrEntry->SizeOfImage, NULL);\r
-        if (!NewImageAddress)\r
-        {\r
-            /* Shouldn't happen */\r
-            DPRINT1("[Mm0]: Couldn't allocate driver section!\n");\r
-            while (TRUE);\r
-        }\r
-\r
-        /* Sanity check */\r
-        DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);\r
-        ASSERT(ExpInitializationPhase == 0);\r
-\r
-        /* Now copy the entire driver over */\r
-        RtlCopyMemory(NewImageAddress, DllBase, LdrEntry->SizeOfImage);\r
-\r
-        /* Sanity check */\r
-        ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);\r
-\r
-        /* Set the image base to the address where the loader put it */\r
-        NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;\r
-        NtHeader = RtlImageNtHeader(NewImageAddress);\r
-        NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;\r
-\r
-        /* Check if we had relocations */\r
-        if (ValidRelocs)\r
-        {\r
-            /* Relocate the image */\r
-            Status = LdrRelocateImageWithBias(NewImageAddress,\r
-                                              0,\r
-                                              "SYSLDR",\r
-                                              STATUS_SUCCESS,\r
-                                              STATUS_CONFLICTING_ADDRESSES,\r
-                                              STATUS_INVALID_IMAGE_FORMAT);\r
-            if (!NT_SUCCESS(Status))\r
-            {\r
-                /* This shouldn't happen */\r
-                DPRINT1("Relocations failed!\n");\r
-                while (TRUE);\r
-            }\r
-        }\r
-\r
-        /* Update the loader entry */\r
-        LdrEntry->DllBase = NewImageAddress;\r
-\r
-        /* Update the thunks */\r
-        DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);\r
-        MiUpdateThunks(LoaderBlock,\r
-                       DllBase,\r
-                       NewImageAddress,\r
-                       LdrEntry->SizeOfImage);\r
-\r
-        /* Update the loader entry */\r
-        LdrEntry->Flags |= 0x01000000;\r
-        LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +\r
-                                NtHeader->OptionalHeader.AddressOfEntryPoint);\r
-        LdrEntry->SizeOfImage = LdrEntry->SizeOfImage;\r
-\r
-        /* Free the old copy */\r
-        MiFreeBootDriverMemory(DllBase, LdrEntry->SizeOfImage);\r
-    }\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)\r
-{\r
-    PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;\r
-    PLIST_ENTRY ListHead, NextEntry;\r
-    ULONG EntrySize;\r
-\r
-    /* Setup the loaded module list and lock */\r
-    KeInitializeSpinLock(&PsLoadedModuleSpinLock);\r
-    InitializeListHead(&PsLoadedModuleList);\r
-\r
-    /* Get loop variables and the kernel entry */\r
-    ListHead = &LoaderBlock->LoadOrderListHead;\r
-    NextEntry = ListHead->Flink;\r
-    LdrEntry = CONTAINING_RECORD(NextEntry,\r
-                                 LDR_DATA_TABLE_ENTRY,\r
-                                 InLoadOrderLinks);\r
-    PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;\r
-\r
-    /* Loop the loader block */\r
-    while (NextEntry != ListHead)\r
-    {\r
-        /* Get the loader entry */\r
-        LdrEntry = CONTAINING_RECORD(NextEntry,\r
-                                     LDR_DATA_TABLE_ENTRY,\r
-                                     InLoadOrderLinks);\r
-\r
-        /* FIXME: ROS HACK. Make sure this is a driver */\r
-        if (!RtlImageNtHeader(LdrEntry->DllBase))\r
-        {\r
-            /* Skip this entry */\r
-            NextEntry= NextEntry->Flink;\r
-            continue;\r
-        }\r
-\r
-        /* Calculate the size we'll need and allocate a copy */\r
-        EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +\r
-                    LdrEntry->BaseDllName.MaximumLength +\r
-                    sizeof(UNICODE_NULL);\r
-        NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);\r
-        if (!NewEntry) return FALSE;\r
-\r
-        /* Copy the entry over */\r
-        *NewEntry = *LdrEntry;\r
-\r
-        /* Allocate the name */\r
-        NewEntry->FullDllName.Buffer =\r
-            ExAllocatePoolWithTag(PagedPool,\r
-                                  LdrEntry->FullDllName.MaximumLength +\r
-                                  sizeof(UNICODE_NULL),\r
-                                  TAG_LDR_WSTR);\r
-        if (!NewEntry->FullDllName.Buffer) return FALSE;\r
-\r
-        /* Set the base name */\r
-        NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);\r
-\r
-        /* Copy the full and base name */\r
-        RtlCopyMemory(NewEntry->FullDllName.Buffer,\r
-                      LdrEntry->FullDllName.Buffer,\r
-                      LdrEntry->FullDllName.MaximumLength);\r
-        RtlCopyMemory(NewEntry->BaseDllName.Buffer,\r
-                      LdrEntry->BaseDllName.Buffer,\r
-                      LdrEntry->BaseDllName.MaximumLength);\r
-\r
-        /* Null-terminate the base name */\r
-        NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /\r
-                                     sizeof(WCHAR)] = UNICODE_NULL;\r
-\r
-        /* Insert the entry into the list */\r
-        InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);\r
-        NextEntry = NextEntry->Flink;\r
-    }\r
-\r
-    /* Build the import lists for the boot drivers */\r
-    //MiBuildImportsForBootDrivers();\r
-\r
-    /* We're done */\r
-    return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)\r
-{\r
-    PIMAGE_NT_HEADERS NtHeader;\r
-    PAGED_CODE();\r
-\r
-    /* Get NT Headers */\r
-    NtHeader = RtlImageNtHeader(BaseAddress);\r
-    if (NtHeader)\r
-    {\r
-        /* Check if this image is only safe for UP while we have 2+ CPUs */\r
-        if ((KeNumberProcessors > 1) &&\r
-            (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))\r
-        {\r
-            /* Fail */\r
-            return FALSE;\r
-        }\r
-    }\r
-\r
-    /* Otherwise, it's safe */\r
-    return TRUE;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MmCheckSystemImage(IN HANDLE ImageHandle,\r
-                   IN BOOLEAN PurgeSection)\r
-{\r
-    NTSTATUS Status;\r
-    HANDLE SectionHandle;\r
-    PVOID ViewBase = NULL;\r
-    SIZE_T ViewSize = 0;\r
-    IO_STATUS_BLOCK IoStatusBlock;\r
-    FILE_STANDARD_INFORMATION FileStandardInfo;\r
-    KAPC_STATE ApcState;\r
-    PAGED_CODE();\r
-\r
-    /* Create a section for the DLL */\r
-    Status = ZwCreateSection(&SectionHandle,\r
-                             SECTION_MAP_EXECUTE,\r
-                             NULL,\r
-                             NULL,\r
-                             PAGE_EXECUTE,\r
-                             SEC_COMMIT,\r
-                             ImageHandle);\r
-    if (!NT_SUCCESS(Status)) return Status;\r
-\r
-    /* Make sure we're in the system process */\r
-    KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);\r
-\r
-    /* Map it */\r
-    Status = ZwMapViewOfSection(SectionHandle,\r
-                                NtCurrentProcess(),\r
-                                &ViewBase,\r
-                                0,\r
-                                0,\r
-                                NULL,\r
-                                &ViewSize,\r
-                                ViewShare,\r
-                                0,\r
-                                PAGE_EXECUTE);\r
-    if (!NT_SUCCESS(Status))\r
-    {\r
-        /* We failed, close the handle and return */\r
-        KeUnstackDetachProcess(&ApcState);\r
-        ZwClose(SectionHandle);\r
-        return Status;\r
-    }\r
-\r
-    /* Now query image information */\r
-    Status = ZwQueryInformationFile(ImageHandle,\r
-                                    &IoStatusBlock,\r
-                                    &FileStandardInfo,\r
-                                    sizeof(FileStandardInfo),\r
-                                    FileStandardInformation);\r
-    if ( NT_SUCCESS(Status) )\r
-    {\r
-        /* First, verify the checksum */\r
-        if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,\r
-                                                 FileStandardInfo.\r
-                                                 EndOfFile.LowPart,\r
-                                                 FileStandardInfo.\r
-                                                 EndOfFile.LowPart))\r
-        {\r
-            /* Set checksum failure */\r
-            Status = STATUS_IMAGE_CHECKSUM_MISMATCH;\r
-        }\r
-\r
-        /* Check that it's a valid SMP image if we have more then one CPU */\r
-        if (!MmVerifyImageIsOkForMpUse(ViewBase))\r
-        {\r
-            /* Otherwise it's not the right image */\r
-            Status = STATUS_IMAGE_MP_UP_MISMATCH;\r
-        }\r
-    }\r
-\r
-    /* Unmap the section, close the handle, and return status */\r
-    ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);\r
-    KeUnstackDetachProcess(&ApcState);\r
-    ZwClose(SectionHandle);\r
-    return Status;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-MmLoadSystemImage(IN PUNICODE_STRING FileName,\r
-                  IN PUNICODE_STRING NamePrefix OPTIONAL,\r
-                  IN PUNICODE_STRING LoadedName OPTIONAL,\r
-                  IN ULONG Flags,\r
-                  OUT PVOID *ModuleObject,\r
-                  OUT PVOID *ImageBaseAddress)\r
-{\r
-    PVOID ModuleLoadBase = NULL;\r
-    NTSTATUS Status;\r
-    HANDLE FileHandle = NULL;\r
-    OBJECT_ATTRIBUTES ObjectAttributes;\r
-    IO_STATUS_BLOCK IoStatusBlock;\r
-    PIMAGE_NT_HEADERS NtHeader;\r
-    UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;\r
-    PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;\r
-    ULONG EntrySize, DriverSize;\r
-    PLOAD_IMPORTS LoadedImports = (PVOID)-2;\r
-    PCHAR MissingApiName, Buffer;\r
-    PWCHAR MissingDriverName;\r
-    HANDLE SectionHandle;\r
-    ACCESS_MASK DesiredAccess;\r
-    PVOID Section = NULL;\r
-    BOOLEAN LockOwned = FALSE;\r
-    PLIST_ENTRY NextEntry;\r
-    IMAGE_INFO ImageInfo;\r
-    ANSI_STRING AnsiTemp;\r
-    PAGED_CODE();\r
-\r
-    /* Detect session-load */\r
-    if (Flags)\r
-    {\r
-        /* Sanity checks */\r
-        ASSERT(NamePrefix == NULL);\r
-        ASSERT(LoadedName == NULL);\r
-\r
-        /* Make sure the process is in session too */\r
-        if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;\r
-    }\r
-\r
-    if (ModuleObject) *ModuleObject = NULL;\r
-    if (ImageBaseAddress) *ImageBaseAddress = NULL;\r
-\r
-    /* Allocate a buffer we'll use for names */\r
-    Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);\r
-    if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;\r
-\r
-    /* Check for a separator */\r
-    if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)\r
-    {\r
-        PWCHAR p;\r
-        ULONG BaseLength;\r
-\r
-        /* Loop the path until we get to the base name */\r
-        p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];\r
-        while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;\r
-\r
-        /* Get the length */\r
-        BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);\r
-        BaseLength *= sizeof(WCHAR);\r
-\r
-        /* Setup the string */\r
-        BaseName.Length = (USHORT)BaseLength;\r
-        BaseName.Buffer = p;\r
-    }\r
-    else\r
-    {\r
-        /* Otherwise, we already have a base name */\r
-        BaseName.Length = FileName->Length;\r
-        BaseName.Buffer = FileName->Buffer;\r
-    }\r
-\r
-    /* Setup the maximum length */\r
-    BaseName.MaximumLength = BaseName.Length;\r
-\r
-    /* Now compute the base directory */\r
-    BaseDirectory = *FileName;\r
-    BaseDirectory.Length -= BaseName.Length;\r
-    BaseDirectory.MaximumLength = BaseDirectory.Length;\r
-\r
-    /* And the prefix, which for now is just the name itself */\r
-    PrefixName = *FileName;\r
-\r
-    /* Check if we have a prefix */\r
-    if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");\r
-\r
-    /* Check if we already have a name, use it instead */\r
-    if (LoadedName) BaseName = *LoadedName;\r
-\r
-    /* Acquire the load lock */\r
-LoaderScan:\r
-    ASSERT(LockOwned == FALSE);\r
-    LockOwned = TRUE;\r
-    KeEnterCriticalRegion();\r
-    KeWaitForSingleObject(&MmSystemLoadLock,\r
-                          WrVirtualMemory,\r
-                          KernelMode,\r
-                          FALSE,\r
-                          NULL);\r
-\r
-    /* Scan the module list */\r
-    NextEntry = PsLoadedModuleList.Flink;\r
-    while (NextEntry != &PsLoadedModuleList)\r
-    {\r
-        /* Get the entry and compare the names */\r
-        LdrEntry = CONTAINING_RECORD(NextEntry,\r
-                                     LDR_DATA_TABLE_ENTRY,\r
-                                     InLoadOrderLinks);\r
-        if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))\r
-        {\r
-            /* Found it, break out */\r
-            break;\r
-        }\r
-\r
-        /* Keep scanning */\r
-        NextEntry = NextEntry->Flink;\r
-    }\r
-\r
-    /* Check if we found the image */\r
-    if (NextEntry != &PsLoadedModuleList)\r
-    {\r
-        /* Check if we had already mapped a section */\r
-        if (Section)\r
-        {\r
-            /* Dereference and clear */\r
-            ObDereferenceObject(Section);\r
-            Section = NULL;\r
-        }\r
-\r
-        /* Check if this was supposed to be a session load */\r
-        if (!Flags)\r
-        {\r
-            /* It wasn't, so just return the data */\r
-            if (ModuleObject) *ModuleObject = LdrEntry;\r
-            if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;\r
-            Status = STATUS_IMAGE_ALREADY_LOADED;\r
-        }\r
-        else\r
-        {\r
-            /* We don't support session loading yet */\r
-            DPRINT1("Unsupported Session-Load!\n");\r
-            while (TRUE);\r
-        }\r
-\r
-        /* Do cleanup */\r
-        goto Quickie;\r
-    }\r
-    else if (!Section)\r
-    {\r
-        /* It wasn't loaded, and we didn't have a previous attempt */\r
-        KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);\r
-        KeLeaveCriticalRegion();\r
-        LockOwned = FALSE;\r
-\r
-        /* Check if KD is enabled */\r
-        if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))\r
-        {\r
-            /* FIXME: Attempt to get image from KD */\r
-        }\r
-\r
-        /* We don't have a valid entry */\r
-        LdrEntry = NULL;\r
-\r
-        /* Setup image attributes */\r
-        InitializeObjectAttributes(&ObjectAttributes,\r
-                                   FileName,\r
-                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,\r
-                                   NULL,\r
-                                   NULL);\r
-\r
-        /* Open the image */\r
-        Status = ZwOpenFile(&FileHandle,\r
-                            FILE_EXECUTE,\r
-                            &ObjectAttributes,\r
-                            &IoStatusBlock,\r
-                            FILE_SHARE_READ | FILE_SHARE_DELETE,\r
-                            0);\r
-        if (!NT_SUCCESS(Status)) goto Quickie;\r
-\r
-        /* Validate it */\r
-        Status = MmCheckSystemImage(FileHandle, FALSE);\r
-        if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||\r
-            (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||\r
-            (Status == STATUS_INVALID_IMAGE_FORMAT))\r
-        {\r
-            /* Fail loading */\r
-            goto Quickie;\r
-        }\r
-\r
-        /* Check if this is a session-load */\r
-        if (Flags)\r
-        {\r
-            /* Then we only need read and execute */\r
-            DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;\r
-        }\r
-        else\r
-        {\r
-            /* Otherwise, we can allow write access */\r
-            DesiredAccess = SECTION_ALL_ACCESS;\r
-        }\r
-\r
-        /* Initialize the attributes for the section */\r
-        InitializeObjectAttributes(&ObjectAttributes,\r
-                                   NULL,\r
-                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,\r
-                                   NULL,\r
-                                   NULL);\r
-\r
-        /* Create the section */\r
-        Status = ZwCreateSection(&SectionHandle,\r
-                                 DesiredAccess,\r
-                                 &ObjectAttributes,\r
-                                 NULL,\r
-                                 PAGE_EXECUTE,\r
-                                 SEC_IMAGE,\r
-                                 FileHandle);\r
-        if (!NT_SUCCESS(Status)) goto Quickie;\r
-\r
-        /* Now get the section pointer */\r
-        Status = ObReferenceObjectByHandle(SectionHandle,\r
-                                           SECTION_MAP_EXECUTE,\r
-                                           MmSectionObjectType,\r
-                                           KernelMode,\r
-                                           &Section,\r
-                                           NULL);\r
-        ZwClose(SectionHandle);\r
-        if (!NT_SUCCESS(Status)) goto Quickie;\r
-\r
-        /* Check if this was supposed to be a session-load */\r
-        if (Flags)\r
-        {\r
-            /* We don't support session loading yet */\r
-            DPRINT1("Unsupported Session-Load!\n");\r
-            while (TRUE);\r
-        }\r
-\r
-        /* Check the loader list again, we should end up in the path below */\r
-        goto LoaderScan;\r
-    }\r
-    else\r
-    {\r
-        /* We don't have a valid entry */\r
-        LdrEntry = NULL;\r
-    }\r
-\r
-    /* Load the image */\r
-    Status = MiLoadImageSection(&Section,\r
-                                &ModuleLoadBase,\r
-                                FileName,\r
-                                FALSE,\r
-                                NULL);\r
-    ASSERT(Status != STATUS_ALREADY_COMMITTED);\r
-\r
-    /* Get the size of the driver */\r
-    DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;\r
-\r
-    /* Make sure we're not being loaded into session space */\r
-    if (!Flags)\r
-    {\r
-        /* Check for success */\r
-        if (NT_SUCCESS(Status))\r
-        {\r
-            /* FIXME: Support large pages for drivers */\r
-        }\r
-\r
-        /* Dereference the section */\r
-        ObDereferenceObject(Section);\r
-        Section = NULL;\r
-    }\r
-\r
-    /* Get the NT Header */\r
-    NtHeader = RtlImageNtHeader(ModuleLoadBase);\r
-\r
-    /* Relocate the driver */\r
-    Status = LdrRelocateImageWithBias(ModuleLoadBase,\r
-                                      0,\r
-                                      "SYSLDR",\r
-                                      STATUS_SUCCESS,\r
-                                      STATUS_CONFLICTING_ADDRESSES,\r
-                                      STATUS_INVALID_IMAGE_FORMAT);\r
-    if (!NT_SUCCESS(Status)) goto Quickie;\r
-\r
-    /* Calculate the size we'll need for the entry and allocate it */\r
-    EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +\r
-                BaseName.Length +\r
-                sizeof(UNICODE_NULL);\r
-\r
-    /* Allocate the entry */\r
-    LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);\r
-    if (!LdrEntry)\r
-    {\r
-        /* Fail */\r
-        Status = STATUS_INSUFFICIENT_RESOURCES;\r
-        goto Quickie;\r
-    }\r
-\r
-    /* Setup the entry */\r
-    LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;\r
-    LdrEntry->LoadCount = 1;\r
-    LdrEntry->LoadedImports = LoadedImports;\r
-    LdrEntry->PatchInformation = NULL;\r
-\r
-    /* Check the version */\r
-    if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&\r
-        (NtHeader->OptionalHeader.MajorImageVersion >= 5))\r
-    {\r
-        /* Mark this image as a native image */\r
-        LdrEntry->Flags |= 0x80000000;\r
-    }\r
-\r
-    /* Setup the rest of the entry */\r
-    LdrEntry->DllBase = ModuleLoadBase;\r
-    LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +\r
-                                   NtHeader->OptionalHeader.AddressOfEntryPoint);\r
-    LdrEntry->SizeOfImage = DriverSize;\r
-    LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;\r
-    LdrEntry->SectionPointer = Section;\r
-\r
-    /* Now write the DLL name */\r
-    LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);\r
-    LdrEntry->BaseDllName.Length = BaseName.Length;\r
-    LdrEntry->BaseDllName.MaximumLength = BaseName.Length;\r
-\r
-    /* Copy and null-terminate it */\r
-    RtlCopyMemory(LdrEntry->BaseDllName.Buffer,\r
-                  BaseName.Buffer,\r
-                  BaseName.Length);\r
-    LdrEntry->BaseDllName.Buffer[BaseName.Length / 2] = UNICODE_NULL;\r
-\r
-    /* Now allocate the full name */\r
-    LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,\r
-                                                         PrefixName.Length +\r
-                                                         sizeof(UNICODE_NULL),\r
-                                                         TAG_LDR_WSTR);\r
-    if (!LdrEntry->FullDllName.Buffer)\r
-    {\r
-        /* Don't fail, just set it to zero */\r
-        LdrEntry->FullDllName.Length = 0;\r
-        LdrEntry->FullDllName.MaximumLength = 0;\r
-    }\r
-    else\r
-    {\r
-        /* Set it up */\r
-        LdrEntry->FullDllName.Length = PrefixName.Length;\r
-        LdrEntry->FullDllName.MaximumLength = PrefixName.Length;\r
-\r
-        /* Copy and null-terminate */\r
-        RtlCopyMemory(LdrEntry->FullDllName.Buffer,\r
-                      PrefixName.Buffer,\r
-                      PrefixName.Length);\r
-        LdrEntry->FullDllName.Buffer[PrefixName.Length / 2] = UNICODE_NULL;\r
-    }\r
-\r
-    /* Add the entry */\r
-    MiProcessLoaderEntry(LdrEntry, TRUE);\r
-\r
-    /* Resolve imports */\r
-    MissingApiName = Buffer;\r
-    Status = MiResolveImageReferences(ModuleLoadBase,\r
-                                      &BaseDirectory,\r
-                                      NULL,\r
-                                      &MissingApiName,\r
-                                      &MissingDriverName,\r
-                                      &LoadedImports);\r
-    if (!NT_SUCCESS(Status))\r
-    {\r
-        /* Fail */\r
-        MiProcessLoaderEntry(LdrEntry, FALSE);\r
-\r
-        /* Check if we need to free the name */\r
-        if (LdrEntry->FullDllName.Buffer)\r
-        {\r
-            /* Free it */\r
-            ExFreePool(LdrEntry->FullDllName.Buffer);\r
-        }\r
-\r
-        /* Free the entry itself */\r
-        ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);\r
-        LdrEntry = NULL;\r
-        goto Quickie;\r
-    }\r
-\r
-    /* Update the loader entry */\r
-    LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |\r
-                        LDRP_ENTRY_PROCESSED |\r
-                        LDRP_MM_LOADED);\r
-    LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;\r
-    LdrEntry->LoadedImports = LoadedImports;\r
-\r
-    /* FIXME: Apply driver verifier */\r
-\r
-    /* FIXME: Write-protect the system image */\r
-\r
-    /* Check if notifications are enabled */\r
-    if (PsImageNotifyEnabled)\r
-    {\r
-        /* Fill out the notification data */\r
-        ImageInfo.Properties = 0;\r
-        ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;\r
-        ImageInfo.SystemModeImage = TRUE;\r
-        ImageInfo.ImageSize = LdrEntry->SizeOfImage;\r
-        ImageInfo.ImageBase = LdrEntry->DllBase;\r
-        ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;\r
-\r
-        /* Send the notification */\r
-        PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);\r
-    }\r
-\r
-    /* Check if there's symbols */\r
-#ifdef KDBG\r
-    /* If KDBG is defined, then we always have symbols */\r
-    if (TRUE)\r
-#else\r
-    if (MiCacheImageSymbols(LdrEntry->DllBase))\r
-#endif\r
-    {\r
-        /* Check if the system root is present */\r
-        if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&\r
-            !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))\r
-        {\r
-            /* Add the system root */\r
-            UnicodeTemp = PrefixName;\r
-            UnicodeTemp.Buffer += 11;\r
-            UnicodeTemp.Length -= (11 * sizeof(WCHAR));\r
-            sprintf_nt(Buffer,\r
-                       "%ws%wZ",\r
-                       &SharedUserData->NtSystemRoot[2],\r
-                       &UnicodeTemp);\r
-        }\r
-        else\r
-        {\r
-            /* Build the name */\r
-            sprintf_nt(Buffer, "%wZ", &BaseName);\r
-        }\r
-\r
-        /* Setup the ansi string */\r
-        RtlInitString(&AnsiTemp, Buffer);\r
-\r
-        /* Notify the debugger */\r
-        DbgLoadImageSymbols(&AnsiTemp, LdrEntry->DllBase, -1);\r
-        LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;\r
-    }\r
-\r
-    /* FIXME: Page the driver */\r
-    ASSERT(Section == NULL);\r
-\r
-    /* Return pointers */\r
-    if (ModuleObject) *ModuleObject = LdrEntry;\r
-    if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;\r
-\r
-Quickie:\r
-    /* If we have a file handle, close it */\r
-    if (FileHandle) ZwClose(FileHandle);\r
-\r
-    /* Check if we have the lock acquired */\r
-    if (LockOwned)\r
-    {\r
-        /* Release the lock */\r
-        KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);\r
-        KeLeaveCriticalRegion();\r
-        LockOwned = FALSE;\r
-    }\r
-\r
-    /* Check if we had a prefix */\r
-    if (NamePrefix) ExFreePool(PrefixName.Buffer);\r
-\r
-    /* Free the name buffer and return status */\r
-    ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);\r
-    return Status;\r
-}\r
-\r
-/*\r
- * @implemented\r
- */\r
-PVOID\r
-NTAPI\r
-MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)\r
-{\r
-    PVOID ProcAddress = NULL;\r
-    ANSI_STRING AnsiRoutineName;\r
-    NTSTATUS Status;\r
-    PLIST_ENTRY NextEntry;\r
-    extern LIST_ENTRY PsLoadedModuleList;\r
-    PLDR_DATA_TABLE_ENTRY LdrEntry;\r
-    BOOLEAN Found = FALSE;\r
-    UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");\r
-    UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");\r
-    ULONG Modules = 0;\r
-\r
-    /* Convert routine to ansi name */\r
-    Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,\r
-                                          SystemRoutineName,\r
-                                          TRUE);\r
-    if (!NT_SUCCESS(Status)) return NULL;\r
-\r
-    /* Lock the list */\r
-    KeEnterCriticalRegion();\r
-\r
-    /* Loop the loaded module list */\r
-    NextEntry = PsLoadedModuleList.Flink;\r
-    while (NextEntry != &PsLoadedModuleList)\r
-    {\r
-        /* Get the entry */\r
-        LdrEntry = CONTAINING_RECORD(NextEntry,\r
-                                     LDR_DATA_TABLE_ENTRY,\r
-                                     InLoadOrderLinks);\r
-\r
-        /* Check if it's the kernel or HAL */\r
-        if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))\r
-        {\r
-            /* Found it */\r
-            Found = TRUE;\r
-            Modules++;\r
-        }\r
-        else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))\r
-        {\r
-            /* Found it */\r
-            Found = TRUE;\r
-            Modules++;\r
-        }\r
-\r
-        /* Check if we found a valid binary */\r
-        if (Found)\r
-        {\r
-            /* Find the procedure name */\r
-            ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,\r
-                                                      &AnsiRoutineName);\r
-\r
-            /* Break out if we found it or if we already tried both modules */\r
-            if (ProcAddress) break;\r
-            if (Modules == 2) break;\r
-        }\r
-\r
-        /* Keep looping */\r
-        NextEntry = NextEntry->Flink;\r
-    }\r
-\r
-    /* Release the lock */\r
-    KeLeaveCriticalRegion();\r
-\r
-    /* Free the string and return */\r
-    RtlFreeAnsiString(&AnsiRoutineName);\r
-    return ProcAddress;\r
-}\r
-\r
+/*
+* PROJECT:         ReactOS Kernel
+* LICENSE:         GPL - See COPYING in the top level directory
+* FILE:            ntoskrnl/mm/sysldr.c
+* PURPOSE:         Contains the Kernel Loader (SYSLDR) for loading PE files.
+* PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+*/
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* GCC's incompetence strikes again */
+__inline
+VOID
+sprintf_nt(IN PCHAR Buffer,
+           IN PCHAR Format,
+           IN ...)
+{
+    va_list ap;
+    va_start(ap, Format);
+    vsprintf(Buffer, Format, ap);
+    va_end(ap);
+}
+
+/* GLOBALS *******************************************************************/
+
+LIST_ENTRY PsLoadedModuleList;
+KSPIN_LOCK PsLoadedModuleSpinLock;
+ULONG_PTR PsNtosImageBase;
+KMUTANT MmSystemLoadLock;
+extern ULONG NtGlobalFlag;
+
+/* FUNCTIONS *****************************************************************/
+
+PVOID
+NTAPI
+MiCacheImageSymbols(IN PVOID BaseAddress)
+{
+    ULONG DebugSize;
+    PVOID DebugDirectory = NULL;
+    PAGED_CODE();
+
+    /* Make sure it's safe to access the image */
+    _SEH2_TRY
+    {
+        /* Get the debug directory */
+        DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress,
+                                                      TRUE,
+                                                      IMAGE_DIRECTORY_ENTRY_DEBUG,
+                                                      &DebugSize);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        /* Nothing */
+    }
+    _SEH2_END;
+
+    /* Return the directory */
+    return DebugDirectory;
+}
+
+VOID
+NTAPI
+MiFreeBootDriverMemory(PVOID BaseAddress,
+                       ULONG Length)
+{
+    ULONG i;
+
+    /* Loop each page */
+    for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
+    {
+        /* Free the page */
+        MmDeleteVirtualMapping(NULL,
+                               (PVOID)((ULONG_PTR)BaseAddress + i * PAGE_SIZE),
+                               TRUE,
+                               NULL,
+                               NULL);
+    }
+}
+
+NTSTATUS
+NTAPI
+MiLoadImageSection(IN OUT PVOID *SectionPtr,
+                   OUT PVOID *ImageBase,
+                   IN PUNICODE_STRING FileName,
+                   IN BOOLEAN SessionLoad,
+                   IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+    PROS_SECTION_OBJECT Section = *SectionPtr;
+    NTSTATUS Status;
+    PEPROCESS Process;
+    PVOID Base = NULL;
+    SIZE_T ViewSize = 0;
+    KAPC_STATE ApcState;
+    LARGE_INTEGER SectionOffset = {{0, 0}};
+    BOOLEAN LoadSymbols = FALSE;
+    ULONG DriverSize;
+    PVOID DriverBase;
+    PAGED_CODE();
+
+    /* Detect session load */
+    if (SessionLoad)
+    {
+        /* Fail */
+        DPRINT1("Session loading not yet supported!\n");
+        while (TRUE);
+    }
+
+    /* Not session load, shouldn't have an entry */
+    ASSERT(LdrEntry == NULL);
+
+    /* Attach to the system process */
+    KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
+
+    /* Check if we need to load symbols */
+    if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)
+    {
+        /* Yes we do */
+        LoadSymbols = TRUE;
+        NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
+    }
+
+    /* Map the driver */
+    Process = PsGetCurrentProcess();
+    Status = MmMapViewOfSection(Section,
+                                Process,
+                                &Base,
+                                0,
+                                0,
+                                &SectionOffset,
+                                &ViewSize,
+                                ViewUnmap,
+                                0,
+                                PAGE_EXECUTE);
+
+    /* Re-enable the flag */
+    if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
+
+    /* Check if we failed with distinguished status code */
+    if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
+    {
+        /* Change it to something more generic */
+        Status = STATUS_INVALID_IMAGE_FORMAT;
+    }
+
+    /* Now check if we failed */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Detach and return */
+        KeUnstackDetachProcess(&ApcState);
+        return Status;
+    }
+
+    /* Get the driver size */
+    DriverSize = Section->ImageSection->ImageSize;
+
+    /*  Allocate a virtual section for the module  */
+    DriverBase = MmAllocateSection(DriverSize, NULL);
+    *ImageBase = DriverBase;
+
+    /* Copy the image */
+    RtlCopyMemory(DriverBase, Base, DriverSize);
+
+    /* Now unmap the view */
+    Status = MmUnmapViewOfSection(Process, Base);
+    ASSERT(NT_SUCCESS(Status));
+
+    /* Detach and return status */
+    KeUnstackDetachProcess(&ApcState);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
+{
+    SIZE_T i;
+
+    /* Check if there's no imports or if we're a boot driver */
+    if ((ImportList == (PVOID)-1) ||
+        (ImportList == (PVOID)-2) ||
+        (ImportList->Count == 0))
+    {
+        /* Then there's nothing to do */
+        return STATUS_SUCCESS;
+    }
+
+    /* Otherwise, FIXME */
+    DPRINT1("%u imports not dereferenced!\n", ImportList->Count);
+    for (i = 0; i < ImportList->Count; i++)
+    {
+        DPRINT1("%wZ <%wZ>\n", &ImportList->Entry[i]->FullDllName, &ImportList->Entry[i]->BaseDllName);
+    }
+    return STATUS_UNSUCCESSFUL;
+}
+
+VOID
+NTAPI
+MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+    PAGED_CODE();
+
+    /* Check if there's no imports or we're a boot driver or only one entry */
+    if ((LdrEntry->LoadedImports == (PVOID)-1) ||
+        (LdrEntry->LoadedImports == (PVOID)-2) ||
+        ((ULONG_PTR)LdrEntry->LoadedImports & 1))
+    {
+        /* Nothing to do */
+        return;
+    }
+
+    /* Otherwise, free the import list */
+    ExFreePool(LdrEntry->LoadedImports);
+}
+
+PVOID
+NTAPI
+MiFindExportedRoutineByName(IN PVOID DllBase,
+                            IN PANSI_STRING ExportName)
+{
+    PULONG NameTable;
+    PUSHORT OrdinalTable;
+    PIMAGE_EXPORT_DIRECTORY ExportDirectory;
+    LONG Low = 0, Mid = 0, High, Ret;
+    USHORT Ordinal;
+    PVOID Function;
+    ULONG ExportSize;
+    PULONG ExportTable;
+    PAGED_CODE();
+
+    /* Get the export directory */
+    ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
+                                                   TRUE,
+                                                   IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                                   &ExportSize);
+    if (!ExportDirectory) return NULL;
+
+    /* Setup name tables */
+    NameTable = (PULONG)((ULONG_PTR)DllBase +
+                         ExportDirectory->AddressOfNames);
+    OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
+                             ExportDirectory->AddressOfNameOrdinals);
+
+    /* Do a binary search */
+    High = ExportDirectory->NumberOfNames - 1;
+    while (High >= Low)
+    {
+        /* Get new middle value */
+        Mid = (Low + High) >> 1;
+
+        /* Compare name */
+        Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);
+        if (Ret < 0)
+        {
+            /* Update high */
+            High = Mid - 1;
+        }
+        else if (Ret > 0)
+        {
+            /* Update low */
+            Low = Mid + 1;
+        }
+        else
+        {
+            /* We got it */
+            break;
+        }
+    }
+
+    /* Check if we couldn't find it */
+    if (High < Low) return NULL;
+
+    /* Otherwise, this is the ordinal */
+    Ordinal = OrdinalTable[Mid];
+
+    /* Resolve the address and write it */
+    ExportTable = (PULONG)((ULONG_PTR)DllBase +
+                           ExportDirectory->AddressOfFunctions);
+    Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
+
+    /* We found it! */
+    ASSERT(!(Function > (PVOID)ExportDirectory) &&
+           (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));
+    return Function;
+}
+
+PVOID
+NTAPI
+MiLocateExportName(IN PVOID DllBase,
+                   IN PCHAR ExportName)
+{
+    PULONG NameTable;
+    PUSHORT OrdinalTable;
+    PIMAGE_EXPORT_DIRECTORY ExportDirectory;
+    LONG Low = 0, Mid = 0, High, Ret;
+    USHORT Ordinal;
+    PVOID Function;
+    ULONG ExportSize;
+    PULONG ExportTable;
+    PAGED_CODE();
+
+    /* Get the export directory */
+    ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
+                                                   TRUE,
+                                                   IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                                   &ExportSize);
+    if (!ExportDirectory) return NULL;
+
+    /* Setup name tables */
+    NameTable = (PULONG)((ULONG_PTR)DllBase +
+                         ExportDirectory->AddressOfNames);
+    OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
+                             ExportDirectory->AddressOfNameOrdinals);
+
+    /* Do a binary search */
+    High = ExportDirectory->NumberOfNames - 1;
+    while (High >= Low)
+    {
+        /* Get new middle value */
+        Mid = (Low + High) >> 1;
+
+        /* Compare name */
+        Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);
+        if (Ret < 0)
+        {
+            /* Update high */
+            High = Mid - 1;
+        }
+        else if (Ret > 0)
+        {
+            /* Update low */
+            Low = Mid + 1;
+        }
+        else
+        {
+            /* We got it */
+            break;
+        }
+    }
+
+    /* Check if we couldn't find it */
+    if (High < Low) return NULL;
+
+    /* Otherwise, this is the ordinal */
+    Ordinal = OrdinalTable[Mid];
+
+    /* Resolve the address and write it */
+    ExportTable = (PULONG)((ULONG_PTR)DllBase +
+                           ExportDirectory->AddressOfFunctions);
+    Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
+
+    /* Check if the function is actually a forwarder */
+    if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
+        ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
+    {
+        /* It is, fail */
+        return NULL;
+    }
+
+    /* We found it */
+    return Function;
+}
+
+NTSTATUS
+NTAPI
+MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
+                    IN PLIST_ENTRY ListHead)
+{
+    UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(
+        L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
+    PMM_DLL_INITIALIZE DllInit;
+    UNICODE_STRING RegPath, ImportName;
+    NTSTATUS Status;
+
+    /* Try to see if the image exports a DllInitialize routine */
+    DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
+                                                     "DllInitialize");
+    if (!DllInit) return STATUS_SUCCESS;
+
+    /* Do a temporary copy of BaseDllName called ImportName
+     * because we'll alter the length of the string
+     */
+    ImportName.Length = LdrEntry->BaseDllName.Length;
+    ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;
+    ImportName.Buffer = LdrEntry->BaseDllName.Buffer;
+
+    /* Obtain the path to this dll's service in the registry */
+    RegPath.MaximumLength = ServicesKeyName.Length +
+        ImportName.Length + sizeof(UNICODE_NULL);
+    RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
+                                           RegPath.MaximumLength,
+                                           TAG_LDR_WSTR);
+
+    /* Check if this allocation was unsuccessful */
+    if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* Build and append the service name itself */
+    RegPath.Length = ServicesKeyName.Length;
+    RtlCopyMemory(RegPath.Buffer,
+                  ServicesKeyName.Buffer,
+                  ServicesKeyName.Length);
+
+    /* Check if there is a dot in the filename */
+    if (wcschr(ImportName.Buffer, L'.'))
+    {
+        /* Remove the extension */
+        ImportName.Length = (wcschr(ImportName.Buffer, L'.') -
+            ImportName.Buffer) * sizeof(WCHAR);
+    }
+
+    /* Append service name (the basename without extension) */
+    RtlAppendUnicodeStringToString(&RegPath, &ImportName);
+
+    /* Now call the DllInit func */
+    DPRINT("Calling DllInit(%wZ)\n", &RegPath);
+    Status = DllInit(&RegPath);
+
+    /* Clean up */
+    ExFreePool(RegPath.Buffer);
+
+    /* Return status value which DllInitialize returned */
+    return Status;
+}
+
+VOID
+NTAPI
+MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
+                     IN BOOLEAN Insert)
+{
+    KIRQL OldIrql;
+
+    /* Acquire the lock */
+    KeAcquireSpinLock(&PsLoadedModuleSpinLock, &OldIrql);
+
+    /* Insert or remove from the list */
+    Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :
+             RemoveEntryList(&LdrEntry->InLoadOrderLinks);
+
+    /* Release the lock */
+    KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
+}
+
+VOID
+NTAPI
+MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+               IN PVOID OldBase,
+               IN PVOID NewBase,
+               IN ULONG Size)
+{
+    ULONG_PTR OldBaseTop, Delta;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    PLIST_ENTRY NextEntry;
+    ULONG ImportSize;
+    PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
+    PULONG ImageThunk;
+
+    /* Calculate the top and delta */
+    OldBaseTop = (ULONG_PTR)OldBase + Size - 1;
+    Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;
+
+    /* Loop the loader block */
+    for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
+         NextEntry != &LoaderBlock->LoadOrderListHead;
+         NextEntry = NextEntry->Flink)
+    {
+        /* Get the loader entry */
+        LdrEntry = CONTAINING_RECORD(NextEntry,
+                                     LDR_DATA_TABLE_ENTRY,
+                                     InLoadOrderLinks);
+
+        /* Get the import table */
+        ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
+                                                        TRUE,
+                                                        IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                                        &ImportSize);
+        if (!ImportDescriptor) continue;
+
+        /* Make sure we have an IAT */
+        DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
+        while ((ImportDescriptor->Name) &&
+               (ImportDescriptor->OriginalFirstThunk))
+        {
+            /* Get the image thunk */
+            ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
+                                 ImportDescriptor->FirstThunk);
+            while (*ImageThunk)
+            {
+                /* Check if it's within this module */
+                if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
+                {
+                    /* Relocate it */
+                    DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
+                            ImageThunk, *ImageThunk, *ImageThunk + Delta);
+                    *ImageThunk += Delta;
+                }
+
+                /* Go to the next thunk */
+                ImageThunk++;
+            }
+
+            /* Go to the next import */
+            ImportDescriptor++;
+        }
+    }
+}
+
+NTSTATUS
+NTAPI
+MiSnapThunk(IN PVOID DllBase,
+            IN PVOID ImageBase,
+            IN PIMAGE_THUNK_DATA Name,
+            IN PIMAGE_THUNK_DATA Address,
+            IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
+            IN ULONG ExportSize,
+            IN BOOLEAN SnapForwarder,
+            OUT PCHAR *MissingApi)
+{
+    BOOLEAN IsOrdinal;
+    USHORT Ordinal;
+    PULONG NameTable;
+    PUSHORT OrdinalTable;
+    PIMAGE_IMPORT_BY_NAME NameImport;
+    USHORT Hint;
+    ULONG Low = 0, Mid = 0, High;
+    LONG Ret;
+    NTSTATUS Status;
+    PCHAR MissingForwarder;
+    CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];
+    PULONG ExportTable;
+    ANSI_STRING DllName;
+    UNICODE_STRING ForwarderName;
+    PLIST_ENTRY NextEntry;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    ULONG ForwardExportSize;
+    PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;
+    PIMAGE_IMPORT_BY_NAME ForwardName;
+    ULONG ForwardLength;
+    IMAGE_THUNK_DATA ForwardThunk;
+    PAGED_CODE();
+
+    /* Check if this is an ordinal */
+    IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);
+    if ((IsOrdinal) && !(SnapForwarder))
+    {
+        /* Get the ordinal number and set it as missing */
+        Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -
+                           ExportDirectory->Base);
+        *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;
+    }
+    else
+    {
+        /* Get the VA if we don't have to snap */
+        if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;
+        NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;
+
+        /* Copy the procedure name */
+        strncpy(*MissingApi,
+                (PCHAR)&NameImport->Name[0],
+                MAXIMUM_FILENAME_LENGTH - 1);
+
+        /* Setup name tables */
+        DPRINT("Import name: %s\n", NameImport->Name);
+        NameTable = (PULONG)((ULONG_PTR)DllBase +
+                             ExportDirectory->AddressOfNames);
+        OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
+                                 ExportDirectory->AddressOfNameOrdinals);
+
+        /* Get the hint and check if it's valid */
+        Hint = NameImport->Hint;
+        if ((Hint < ExportDirectory->NumberOfNames) &&
+            !(strcmp((PCHAR) NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))
+        {
+            /* We have a match, get the ordinal number from here */
+            Ordinal = OrdinalTable[Hint];
+        }
+        else
+        {
+            /* Do a binary search */
+            High = ExportDirectory->NumberOfNames - 1;
+            while (High >= Low)
+            {
+                /* Get new middle value */
+                Mid = (Low + High) >> 1;
+
+                /* Compare name */
+                Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);
+                if (Ret < 0)
+                {
+                    /* Update high */
+                    High = Mid - 1;
+                }
+                else if (Ret > 0)
+                {
+                    /* Update low */
+                    Low = Mid + 1;
+                }
+                else
+                {
+                    /* We got it */
+                    break;
+                }
+            }
+
+            /* Check if we couldn't find it */
+            if (High < Low) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
+
+            /* Otherwise, this is the ordinal */
+            Ordinal = OrdinalTable[Mid];
+        }
+    }
+
+    /* Check if the ordinal is invalid */
+    if (Ordinal >= ExportDirectory->NumberOfFunctions)
+    {
+        /* Fail */
+        Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
+    }
+    else
+    {
+        /* In case the forwarder is missing */
+        MissingForwarder = NameBuffer;
+
+        /* Resolve the address and write it */
+        ExportTable = (PULONG)((ULONG_PTR)DllBase +
+                               ExportDirectory->AddressOfFunctions);
+        Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];
+
+        /* Assume success from now on */
+        Status = STATUS_SUCCESS;
+
+        /* Check if the function is actually a forwarder */
+        if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&
+            (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
+        {
+            /* Now assume failure in case the forwarder doesn't exist */
+            Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
+
+            /* Build the forwarder name */
+            DllName.Buffer = (PCHAR)Address->u1.Function;
+            DllName.Length = strchr(DllName.Buffer, '.') -
+                             DllName.Buffer +
+                             sizeof(ANSI_NULL);
+            DllName.MaximumLength = DllName.Length;
+
+            /* Convert it */
+            if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,
+                                                         &DllName,
+                                                         TRUE)))
+            {
+                /* We failed, just return an error */
+                return Status;
+            }
+
+            /* Loop the module list */
+            NextEntry = PsLoadedModuleList.Flink;
+            while (NextEntry != &PsLoadedModuleList)
+            {
+                /* Get the loader entry */
+                LdrEntry = CONTAINING_RECORD(NextEntry,
+                                             LDR_DATA_TABLE_ENTRY,
+                                             InLoadOrderLinks);
+
+                /* Check if it matches */
+                if (RtlPrefixString((PSTRING)&ForwarderName,
+                                    (PSTRING)&LdrEntry->BaseDllName,
+                                    TRUE))
+                {
+                    /* Get the forwarder export directory */
+                    ForwardExportDirectory =
+                        RtlImageDirectoryEntryToData(LdrEntry->DllBase,
+                                                     TRUE,
+                                                     IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                                     &ForwardExportSize);
+                    if (!ForwardExportDirectory) break;
+
+                    /* Allocate a name entry */
+                    ForwardLength = strlen(DllName.Buffer + DllName.Length) +
+                                    sizeof(ANSI_NULL);
+                    ForwardName = ExAllocatePoolWithTag(PagedPool,
+                                                        sizeof(*ForwardName) +
+                                                        ForwardLength,
+                                                        TAG_LDR_WSTR);
+                    if (!ForwardName) break;
+
+                    /* Copy the data */
+                    RtlCopyMemory(&ForwardName->Name[0],
+                                  DllName.Buffer + DllName.Length,
+                                  ForwardLength);
+                    ForwardName->Hint = 0;
+
+                    /* Set the new address */
+                    ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName;
+
+                    /* Snap the forwarder */
+                    Status = MiSnapThunk(LdrEntry->DllBase,
+                                         ImageBase,
+                                         &ForwardThunk,
+                                         &ForwardThunk,
+                                         ForwardExportDirectory,
+                                         ForwardExportSize,
+                                         TRUE,
+                                         &MissingForwarder);
+
+                    /* Free the forwarder name and set the thunk */
+                    ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR);
+                    Address->u1 = ForwardThunk.u1;
+                    break;
+                }
+
+                /* Go to the next entry */
+                NextEntry = NextEntry->Flink;
+            }
+
+            /* Free the name */
+            RtlFreeUnicodeString(&ForwarderName);
+        }
+    }
+
+    /* Return status */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+MmUnloadSystemImage(IN PVOID ImageHandle)
+{
+    PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;
+    PVOID BaseAddress = LdrEntry->DllBase;
+    NTSTATUS Status;
+    STRING TempName;
+    BOOLEAN HadEntry = FALSE;
+
+    /* Acquire the loader lock */
+    KeEnterCriticalRegion();
+    KeWaitForSingleObject(&MmSystemLoadLock,
+                          WrVirtualMemory,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    /* Check if this driver was loaded at boot and didn't get imports parsed */
+    if (LdrEntry->LoadedImports == (PVOID)-1) goto Done;
+
+    /* We should still be alive */
+    ASSERT(LdrEntry->LoadCount != 0);
+    LdrEntry->LoadCount--;
+
+    /* Check if we're still loaded */
+    if (LdrEntry->LoadCount) goto Done;
+
+    /* We should cleanup... are symbols loaded */
+    if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)
+    {
+        /* Create the ANSI name */
+        Status = RtlUnicodeStringToAnsiString(&TempName,
+                                              &LdrEntry->BaseDllName,
+                                              TRUE);
+        if (NT_SUCCESS(Status))
+        {
+            /* Unload the symbols */
+            DbgUnLoadImageSymbols(&TempName,
+                                  BaseAddress,
+                                  (ULONG_PTR)ZwCurrentProcess());
+            RtlFreeAnsiString(&TempName);
+        }
+    }
+
+    /* FIXME: Free the driver */
+    //MmFreeSection(LdrEntry->DllBase);
+
+    /* Check if we're linked in */
+    if (LdrEntry->InLoadOrderLinks.Flink)
+    {
+        /* Remove us */
+        MiProcessLoaderEntry(LdrEntry, FALSE);
+        HadEntry = TRUE;
+    }
+
+    /* Dereference and clear the imports */
+    MiDereferenceImports(LdrEntry->LoadedImports);
+    MiClearImports(LdrEntry);
+
+    /* Check if the entry needs to go away */
+    if (HadEntry)
+    {
+        /* Check if it had a name */
+        if (LdrEntry->FullDllName.Buffer)
+        {
+            /* Free it */
+            ExFreePool(LdrEntry->FullDllName.Buffer);
+        }
+
+        /* Check if we had a section */
+        if (LdrEntry->SectionPointer)
+        {
+            /* Dereference it */
+            ObDereferenceObject(LdrEntry->SectionPointer);
+        }
+
+        /* Free the entry */
+        ExFreePool(LdrEntry);
+    }
+
+    /* Release the system lock and return */
+Done:
+    KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
+    KeLeaveCriticalRegion();
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MiResolveImageReferences(IN PVOID ImageBase,
+                         IN PUNICODE_STRING ImageFileDirectory,
+                         IN PUNICODE_STRING NamePrefix OPTIONAL,
+                         OUT PCHAR *MissingApi,
+                         OUT PWCHAR *MissingDriver,
+                         OUT PLOAD_IMPORTS *LoadImports)
+{
+    PCHAR MissingApiBuffer = *MissingApi, ImportName;
+    PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
+    ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
+    PLOAD_IMPORTS LoadedImports, NewImports;
+    ULONG GdiLink, NormalLink, i;
+    BOOLEAN ReferenceNeeded, Loaded;
+    ANSI_STRING TempString;
+    UNICODE_STRING NameString, DllName;
+    PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;
+    PVOID ImportBase, DllBase;
+    PLIST_ENTRY NextEntry;
+    PIMAGE_EXPORT_DIRECTORY ExportDirectory;
+    NTSTATUS Status;
+    PIMAGE_THUNK_DATA OrigThunk, FirstThunk;
+    PAGED_CODE();
+    DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
+           __FUNCTION__, ImageBase, ImageFileDirectory);
+
+    /* Assume no imports */
+    *LoadImports = (PVOID)-2;
+
+    /* Get the import descriptor */
+    ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,
+                                                    TRUE,
+                                                    IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                                    &ImportSize);
+    if (!ImportDescriptor) return STATUS_SUCCESS;
+
+    /* Loop all imports to count them */
+    for (CurrentImport = ImportDescriptor;
+         (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);
+         CurrentImport++)
+    {
+        /* One more */
+        ImportCount++;
+    }
+
+    /* Make sure we have non-zero imports */
+    if (ImportCount)
+    {
+        /* Calculate and allocate the list we'll need */
+        LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
+        LoadedImports = ExAllocatePoolWithTag(PagedPool,
+                                              LoadedImportsSize,
+                                              TAG_LDR_WSTR);
+        if (LoadedImports)
+        {
+            /* Zero it */
+            RtlZeroMemory(LoadedImports, LoadedImportsSize);
+        }
+    }
+    else
+    {
+        /* No table */
+        LoadedImports = NULL;
+    }
+
+    /* Reset the import count and loop descriptors again */
+    ImportCount = GdiLink = NormalLink = 0;
+    while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))
+    {
+        /* Get the name */
+        ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);
+
+        /* Check if this is a GDI driver */
+        GdiLink = GdiLink |
+                  !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));
+
+        /* We can also allow dxapi */
+        NormalLink = NormalLink |
+                     ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&
+                      (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)));
+
+        /* Check if this is a valid GDI driver */
+        if ((GdiLink) && (NormalLink))
+        {
+            /* It's not, it's importing stuff it shouldn't be! */
+            MiDereferenceImports(LoadedImports);
+            if (LoadedImports) ExFreePool(LoadedImports);
+            return STATUS_PROCEDURE_NOT_FOUND;
+        }
+
+        /* Check if this is a "core" import, which doesn't get referenced */
+        if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
+            !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||
+            !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))
+        {
+            /* Don't reference this */
+            ReferenceNeeded = FALSE;
+        }
+        else
+        {
+            /* Reference these modules */
+            ReferenceNeeded = TRUE;
+        }
+
+        /* Now setup a unicode string for the import */
+        RtlInitAnsiString(&TempString, ImportName);
+        Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Failed */
+            MiDereferenceImports(LoadedImports);
+            if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+            return Status;
+        }
+
+        /* We don't support name prefixes yet */
+        if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");
+
+        /* Remember that we haven't loaded the import at this point */
+CheckDllState:
+        Loaded = FALSE;
+        ImportBase = NULL;
+
+        /* Loop the driver list */
+        NextEntry = PsLoadedModuleList.Flink;
+        while (NextEntry != &PsLoadedModuleList)
+        {
+            /* Get the loader entry and compare the name */
+            LdrEntry = CONTAINING_RECORD(NextEntry,
+                                         LDR_DATA_TABLE_ENTRY,
+                                         InLoadOrderLinks);
+            if (RtlEqualUnicodeString(&NameString,
+                                      &LdrEntry->BaseDllName,
+                                      TRUE))
+            {
+                /* Get the base address */
+                ImportBase = LdrEntry->DllBase;
+
+                /* Check if we haven't loaded yet, and we need references */
+                if (!(Loaded) && (ReferenceNeeded))
+                {
+                    /* Make sure we're not already loading */
+                    if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
+                    {
+                        /* Increase the load count */
+                        LdrEntry->LoadCount++;
+                    }
+                }
+
+                /* Done, break out */
+                break;
+            }
+
+            /* Go to the next entry */
+            NextEntry = NextEntry->Flink;
+        }
+
+        /* Check if we haven't loaded the import yet */
+        if (!ImportBase)
+        {
+            /* Setup the import DLL name */
+            DllName.MaximumLength = NameString.Length +
+                                    ImageFileDirectory->Length +
+                                    sizeof(UNICODE_NULL);
+            DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
+                                                   DllName.MaximumLength,
+                                                   TAG_LDR_WSTR);
+            if (DllName.Buffer)
+            {
+                /* Setup the base length and copy it */
+                DllName.Length = ImageFileDirectory->Length;
+                RtlCopyMemory(DllName.Buffer,
+                              ImageFileDirectory->Buffer,
+                              ImageFileDirectory->Length);
+
+                /* Now add the import name and null-terminate it */
+                RtlAppendStringToString((PSTRING)&DllName,
+                                        (PSTRING)&NameString);
+                DllName.Buffer[(DllName.MaximumLength - 1) / 2] = UNICODE_NULL;
+
+                /* Load the image */
+                Status = MmLoadSystemImage(&DllName,
+                                           NamePrefix,
+                                           NULL,
+                                           0,
+                                           (PVOID)&DllEntry,
+                                           &DllBase);
+                if (NT_SUCCESS(Status))
+                {
+                    /* We can free the DLL Name */
+                    ExFreePool(DllName.Buffer);
+                }
+                else
+                {
+                    /* Fill out the information for the error */
+                    *MissingDriver = DllName.Buffer;
+                    *(PULONG)MissingDriver |= 1;
+                    *MissingApi = NULL;
+                }
+            }
+            else
+            {
+                /* We're out of resources */
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+            }
+
+            /* Check if we're OK until now */
+            if (NT_SUCCESS(Status))
+            {
+                /* We're now loaded */
+                Loaded = TRUE;
+
+                /* Sanity check */
+                ASSERT(DllBase = DllEntry->DllBase);
+
+                /* Call the initialization routines */
+                Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
+                if (!NT_SUCCESS(Status))
+                {
+                    /* We failed, unload the image */
+                    MmUnloadSystemImage(DllEntry);
+                    while (TRUE);
+                    Loaded = FALSE;
+                }
+            }
+
+            /* Check if we failed by here */
+            if (!NT_SUCCESS(Status))
+            {
+                /* Cleanup and return */
+                RtlFreeUnicodeString(&NameString);
+                MiDereferenceImports(LoadedImports);
+                if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+                return Status;
+            }
+
+            /* Loop again to make sure that everything is OK */
+            goto CheckDllState;
+        }
+
+        /* Check if we're support to reference this import */
+        if ((ReferenceNeeded) && (LoadedImports))
+        {
+            /* Make sure we're not already loading */
+            if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
+            {
+                /* Add the entry */
+                LoadedImports->Entry[LoadedImports->Count] = LdrEntry;
+                LoadedImports->Count++;
+            }
+        }
+
+        /* Free the import name */
+        RtlFreeUnicodeString(&NameString);
+
+        /* Set the missing driver name and get the export directory */
+        *MissingDriver = LdrEntry->BaseDllName.Buffer;
+        ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,
+                                                       TRUE,
+                                                       IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                                       &ExportSize);
+        if (!ExportDirectory)
+        {
+            /* Cleanup and return */
+            MiDereferenceImports(LoadedImports);
+            if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+            return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
+        }
+
+        /* Make sure we have an IAT */
+        if (ImportDescriptor->OriginalFirstThunk)
+        {
+            /* Get the first thunks */
+            OrigThunk = (PVOID)((ULONG_PTR)ImageBase +
+                                ImportDescriptor->OriginalFirstThunk);
+            FirstThunk = (PVOID)((ULONG_PTR)ImageBase +
+                                 ImportDescriptor->FirstThunk);
+
+            /* Loop the IAT */
+            while (OrigThunk->u1.AddressOfData)
+            {
+                /* Snap thunk */
+                Status = MiSnapThunk(ImportBase,
+                                     ImageBase,
+                                     OrigThunk++,
+                                     FirstThunk++,
+                                     ExportDirectory,
+                                     ExportSize,
+                                     FALSE,
+                                     MissingApi);
+                if (!NT_SUCCESS(Status))
+                {
+                    /* Cleanup and return */
+                    MiDereferenceImports(LoadedImports);
+                    if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+                    return Status;
+                }
+
+                /* Reset the buffer */
+                *MissingApi = MissingApiBuffer;
+            }
+        }
+
+        /* Go to the next import */
+        ImportDescriptor++;
+    }
+
+    /* Check if we have an import list */
+    if (LoadedImports)
+    {
+        /* Reset the count again, and loop entries*/
+        ImportCount = 0;
+        for (i = 0; i < LoadedImports->Count; i++)
+        {
+            if (LoadedImports->Entry[i])
+            {
+                /* Got an entry, OR it with 1 in case it's the single entry */
+                ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 1);
+                ImportCount++;
+            }
+        }
+
+        /* Check if we had no imports */
+        if (!ImportCount)
+        {
+            /* Free the list and set it to no imports */
+            ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+            LoadedImports = (PVOID)-2;
+        }
+        else if (ImportCount == 1)
+        {
+            /* Just one entry, we can free the table and only use our entry */
+            ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+            LoadedImports = (PLOAD_IMPORTS)ImportEntry;
+        }
+        else if (ImportCount != LoadedImports->Count)
+        {
+            /* Allocate a new list */
+            LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
+            NewImports = ExAllocatePoolWithTag(PagedPool,
+                                               LoadedImportsSize,
+                                               TAG_LDR_WSTR);
+            if (NewImports)
+            {
+                /* Set count */
+                NewImports->Count = 0;
+
+                /* Loop all the imports */
+                for (i = 0; i < LoadedImports->Count; i++)
+                {
+                    /* Make sure it's valid */
+                    if (LoadedImports->Entry[i])
+                    {
+                        /* Copy it */
+                        NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];
+                        NewImports->Count++;
+                    }
+                }
+
+                /* Free the old copy */
+                ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
+                LoadedImports = NewImports;
+            }
+        }
+
+        /* Return the list */
+        *LoadImports = LoadedImports;
+    }
+
+    /* Return success */
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+    PLIST_ENTRY NextEntry;
+    ULONG i = 0;
+    PIMAGE_NT_HEADERS NtHeader;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    PIMAGE_FILE_HEADER FileHeader;
+    BOOLEAN ValidRelocs;
+    PIMAGE_DATA_DIRECTORY DataDirectory;
+    PVOID DllBase, NewImageAddress;
+    NTSTATUS Status;
+
+    /* Loop driver list */
+    for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
+         NextEntry != &LoaderBlock->LoadOrderListHead;
+         NextEntry = NextEntry->Flink)
+    {
+        /* Get the loader entry and NT header */
+        LdrEntry = CONTAINING_RECORD(NextEntry,
+                                     LDR_DATA_TABLE_ENTRY,
+                                     InLoadOrderLinks);
+        NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
+
+        /* Debug info */
+        DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
+                LdrEntry->DllBase,
+                (ULONG_PTR)LdrEntry->DllBase+ LdrEntry->SizeOfImage,
+                &LdrEntry->FullDllName);
+
+        /* Skip kernel and HAL */
+        /* ROS HACK: Skip BOOTVID/KDCOM too */
+        i++;
+        if (i <= 4) continue;
+
+        /* Skip non-drivers */
+        if (!NtHeader) continue;
+
+        /* Get the file header and make sure we can relocate */
+        FileHeader = &NtHeader->FileHeader;
+        if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
+        if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
+            IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
+
+        /* Everything made sense until now, check the relocation section too */
+        DataDirectory = &NtHeader->OptionalHeader.
+                        DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+        if (!DataDirectory->VirtualAddress)
+        {
+            /* We don't really have relocations */
+            ValidRelocs = FALSE;
+        }
+        else
+        {
+            /* Make sure the size is valid */
+            if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
+                LdrEntry->SizeOfImage)
+            {
+                /* They're not, skip */
+                continue;
+            }
+
+            /* We have relocations */
+            ValidRelocs = TRUE;
+        }
+
+        /* Remember the original address */
+        DllBase = LdrEntry->DllBase;
+
+        /*  Allocate a virtual section for the module  */
+        NewImageAddress = MmAllocateSection(LdrEntry->SizeOfImage, NULL);
+        if (!NewImageAddress)
+        {
+            /* Shouldn't happen */
+            DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
+            while (TRUE);
+        }
+
+        /* Sanity check */
+        DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
+        ASSERT(ExpInitializationPhase == 0);
+
+        /* Now copy the entire driver over */
+        RtlCopyMemory(NewImageAddress, DllBase, LdrEntry->SizeOfImage);
+
+        /* Sanity check */
+        ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
+
+        /* Set the image base to the address where the loader put it */
+        NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
+        NtHeader = RtlImageNtHeader(NewImageAddress);
+        NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
+
+        /* Check if we had relocations */
+        if (ValidRelocs)
+        {
+            /* Relocate the image */
+            Status = LdrRelocateImageWithBias(NewImageAddress,
+                                              0,
+                                              "SYSLDR",
+                                              STATUS_SUCCESS,
+                                              STATUS_CONFLICTING_ADDRESSES,
+                                              STATUS_INVALID_IMAGE_FORMAT);
+            if (!NT_SUCCESS(Status))
+            {
+                /* This shouldn't happen */
+                DPRINT1("Relocations failed!\n");
+                while (TRUE);
+            }
+        }
+
+        /* Update the loader entry */
+        LdrEntry->DllBase = NewImageAddress;
+
+        /* Update the thunks */
+        DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
+        MiUpdateThunks(LoaderBlock,
+                       DllBase,
+                       NewImageAddress,
+                       LdrEntry->SizeOfImage);
+
+        /* Update the loader entry */
+        LdrEntry->Flags |= 0x01000000;
+        LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
+                                NtHeader->OptionalHeader.AddressOfEntryPoint);
+        LdrEntry->SizeOfImage = LdrEntry->SizeOfImage;
+
+        /* Free the old copy */
+        MiFreeBootDriverMemory(DllBase, LdrEntry->SizeOfImage);
+    }
+}
+
+BOOLEAN
+NTAPI
+MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+    PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
+    PLIST_ENTRY ListHead, NextEntry;
+    ULONG EntrySize;
+
+    /* Setup the loaded module list and lock */
+    KeInitializeSpinLock(&PsLoadedModuleSpinLock);
+    InitializeListHead(&PsLoadedModuleList);
+
+    /* Get loop variables and the kernel entry */
+    ListHead = &LoaderBlock->LoadOrderListHead;
+    NextEntry = ListHead->Flink;
+    LdrEntry = CONTAINING_RECORD(NextEntry,
+                                 LDR_DATA_TABLE_ENTRY,
+                                 InLoadOrderLinks);
+    PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
+
+    /* Loop the loader block */
+    while (NextEntry != ListHead)
+    {
+        /* Get the loader entry */
+        LdrEntry = CONTAINING_RECORD(NextEntry,
+                                     LDR_DATA_TABLE_ENTRY,
+                                     InLoadOrderLinks);
+
+        /* FIXME: ROS HACK. Make sure this is a driver */
+        if (!RtlImageNtHeader(LdrEntry->DllBase))
+        {
+            /* Skip this entry */
+            NextEntry= NextEntry->Flink;
+            continue;
+        }
+
+        /* Calculate the size we'll need and allocate a copy */
+        EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
+                    LdrEntry->BaseDllName.MaximumLength +
+                    sizeof(UNICODE_NULL);
+        NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);
+        if (!NewEntry) return FALSE;
+
+        /* Copy the entry over */
+        *NewEntry = *LdrEntry;
+
+        /* Allocate the name */
+        NewEntry->FullDllName.Buffer =
+            ExAllocatePoolWithTag(PagedPool,
+                                  LdrEntry->FullDllName.MaximumLength +
+                                  sizeof(UNICODE_NULL),
+                                  TAG_LDR_WSTR);
+        if (!NewEntry->FullDllName.Buffer) return FALSE;
+
+        /* Set the base name */
+        NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
+
+        /* Copy the full and base name */
+        RtlCopyMemory(NewEntry->FullDllName.Buffer,
+                      LdrEntry->FullDllName.Buffer,
+                      LdrEntry->FullDllName.MaximumLength);
+        RtlCopyMemory(NewEntry->BaseDllName.Buffer,
+                      LdrEntry->BaseDllName.Buffer,
+                      LdrEntry->BaseDllName.MaximumLength);
+
+        /* Null-terminate the base name */
+        NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
+                                     sizeof(WCHAR)] = UNICODE_NULL;
+
+        /* Insert the entry into the list */
+        InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Build the import lists for the boot drivers */
+    //MiBuildImportsForBootDrivers();
+
+    /* We're done */
+    return TRUE;
+}
+
+BOOLEAN
+NTAPI
+MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)
+{
+    PIMAGE_NT_HEADERS NtHeader;
+    PAGED_CODE();
+
+    /* Get NT Headers */
+    NtHeader = RtlImageNtHeader(BaseAddress);
+    if (NtHeader)
+    {
+        /* Check if this image is only safe for UP while we have 2+ CPUs */
+        if ((KeNumberProcessors > 1) &&
+            (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))
+        {
+            /* Fail */
+            return FALSE;
+        }
+    }
+
+    /* Otherwise, it's safe */
+    return TRUE;
+}
+
+NTSTATUS
+NTAPI
+MmCheckSystemImage(IN HANDLE ImageHandle,
+                   IN BOOLEAN PurgeSection)
+{
+    NTSTATUS Status;
+    HANDLE SectionHandle;
+    PVOID ViewBase = NULL;
+    SIZE_T ViewSize = 0;
+    IO_STATUS_BLOCK IoStatusBlock;
+    FILE_STANDARD_INFORMATION FileStandardInfo;
+    KAPC_STATE ApcState;
+    PAGED_CODE();
+
+    /* Create a section for the DLL */
+    Status = ZwCreateSection(&SectionHandle,
+                             SECTION_MAP_EXECUTE,
+                             NULL,
+                             NULL,
+                             PAGE_EXECUTE,
+                             SEC_COMMIT,
+                             ImageHandle);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Make sure we're in the system process */
+    KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
+
+    /* Map it */
+    Status = ZwMapViewOfSection(SectionHandle,
+                                NtCurrentProcess(),
+                                &ViewBase,
+                                0,
+                                0,
+                                NULL,
+                                &ViewSize,
+                                ViewShare,
+                                0,
+                                PAGE_EXECUTE);
+    if (!NT_SUCCESS(Status))
+    {
+        /* We failed, close the handle and return */
+        KeUnstackDetachProcess(&ApcState);
+        ZwClose(SectionHandle);
+        return Status;
+    }
+
+    /* Now query image information */
+    Status = ZwQueryInformationFile(ImageHandle,
+                                    &IoStatusBlock,
+                                    &FileStandardInfo,
+                                    sizeof(FileStandardInfo),
+                                    FileStandardInformation);
+    if ( NT_SUCCESS(Status) )
+    {
+        /* First, verify the checksum */
+        if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,
+                                                 FileStandardInfo.
+                                                 EndOfFile.LowPart,
+                                                 FileStandardInfo.
+                                                 EndOfFile.LowPart))
+        {
+            /* Set checksum failure */
+            Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
+        }
+
+        /* Check that it's a valid SMP image if we have more then one CPU */
+        if (!MmVerifyImageIsOkForMpUse(ViewBase))
+        {
+            /* Otherwise it's not the right image */
+            Status = STATUS_IMAGE_MP_UP_MISMATCH;
+        }
+    }
+
+    /* Unmap the section, close the handle, and return status */
+    ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);
+    KeUnstackDetachProcess(&ApcState);
+    ZwClose(SectionHandle);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+MmLoadSystemImage(IN PUNICODE_STRING FileName,
+                  IN PUNICODE_STRING NamePrefix OPTIONAL,
+                  IN PUNICODE_STRING LoadedName OPTIONAL,
+                  IN ULONG Flags,
+                  OUT PVOID *ModuleObject,
+                  OUT PVOID *ImageBaseAddress)
+{
+    PVOID ModuleLoadBase = NULL;
+    NTSTATUS Status;
+    HANDLE FileHandle = NULL;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PIMAGE_NT_HEADERS NtHeader;
+    UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;
+    PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
+    ULONG EntrySize, DriverSize;
+    PLOAD_IMPORTS LoadedImports = (PVOID)-2;
+    PCHAR MissingApiName, Buffer;
+    PWCHAR MissingDriverName;
+    HANDLE SectionHandle;
+    ACCESS_MASK DesiredAccess;
+    PVOID Section = NULL;
+    BOOLEAN LockOwned = FALSE;
+    PLIST_ENTRY NextEntry;
+    IMAGE_INFO ImageInfo;
+    STRING AnsiTemp;
+    PAGED_CODE();
+
+    /* Detect session-load */
+    if (Flags)
+    {
+        /* Sanity checks */
+        ASSERT(NamePrefix == NULL);
+        ASSERT(LoadedName == NULL);
+
+        /* Make sure the process is in session too */
+        if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
+    }
+
+    if (ModuleObject) *ModuleObject = NULL;
+    if (ImageBaseAddress) *ImageBaseAddress = NULL;
+
+    /* Allocate a buffer we'll use for names */
+    Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
+    if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* Check for a separator */
+    if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
+    {
+        PWCHAR p;
+        ULONG BaseLength;
+
+        /* Loop the path until we get to the base name */
+        p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
+        while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
+
+        /* Get the length */
+        BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
+        BaseLength *= sizeof(WCHAR);
+
+        /* Setup the string */
+        BaseName.Length = (USHORT)BaseLength;
+        BaseName.Buffer = p;
+    }
+    else
+    {
+        /* Otherwise, we already have a base name */
+        BaseName.Length = FileName->Length;
+        BaseName.Buffer = FileName->Buffer;
+    }
+
+    /* Setup the maximum length */
+    BaseName.MaximumLength = BaseName.Length;
+
+    /* Now compute the base directory */
+    BaseDirectory = *FileName;
+    BaseDirectory.Length -= BaseName.Length;
+    BaseDirectory.MaximumLength = BaseDirectory.Length;
+
+    /* And the prefix, which for now is just the name itself */
+    PrefixName = *FileName;
+
+    /* Check if we have a prefix */
+    if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");
+
+    /* Check if we already have a name, use it instead */
+    if (LoadedName) BaseName = *LoadedName;
+
+    /* Acquire the load lock */
+LoaderScan:
+    ASSERT(LockOwned == FALSE);
+    LockOwned = TRUE;
+    KeEnterCriticalRegion();
+    KeWaitForSingleObject(&MmSystemLoadLock,
+                          WrVirtualMemory,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    /* Scan the module list */
+    NextEntry = PsLoadedModuleList.Flink;
+    while (NextEntry != &PsLoadedModuleList)
+    {
+        /* Get the entry and compare the names */
+        LdrEntry = CONTAINING_RECORD(NextEntry,
+                                     LDR_DATA_TABLE_ENTRY,
+                                     InLoadOrderLinks);
+        if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))
+        {
+            /* Found it, break out */
+            break;
+        }
+
+        /* Keep scanning */
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Check if we found the image */
+    if (NextEntry != &PsLoadedModuleList)
+    {
+        /* Check if we had already mapped a section */
+        if (Section)
+        {
+            /* Dereference and clear */
+            ObDereferenceObject(Section);
+            Section = NULL;
+        }
+
+        /* Check if this was supposed to be a session load */
+        if (!Flags)
+        {
+            /* It wasn't, so just return the data */
+            if (ModuleObject) *ModuleObject = LdrEntry;
+            if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;
+            Status = STATUS_IMAGE_ALREADY_LOADED;
+        }
+        else
+        {
+            /* We don't support session loading yet */
+            DPRINT1("Unsupported Session-Load!\n");
+            while (TRUE);
+        }
+
+        /* Do cleanup */
+        goto Quickie;
+    }
+    else if (!Section)
+    {
+        /* It wasn't loaded, and we didn't have a previous attempt */
+        KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
+        KeLeaveCriticalRegion();
+        LockOwned = FALSE;
+
+        /* Check if KD is enabled */
+        if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))
+        {
+            /* FIXME: Attempt to get image from KD */
+        }
+
+        /* We don't have a valid entry */
+        LdrEntry = NULL;
+
+        /* Setup image attributes */
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   FileName,
+                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                                   NULL,
+                                   NULL);
+
+        /* Open the image */
+        Status = ZwOpenFile(&FileHandle,
+                            FILE_EXECUTE,
+                            &ObjectAttributes,
+                            &IoStatusBlock,
+                            FILE_SHARE_READ | FILE_SHARE_DELETE,
+                            0);
+        if (!NT_SUCCESS(Status)) goto Quickie;
+
+        /* Validate it */
+        Status = MmCheckSystemImage(FileHandle, FALSE);
+        if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||
+            (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||
+            (Status == STATUS_INVALID_IMAGE_FORMAT))
+        {
+            /* Fail loading */
+            goto Quickie;
+        }
+
+        /* Check if this is a session-load */
+        if (Flags)
+        {
+            /* Then we only need read and execute */
+            DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;
+        }
+        else
+        {
+            /* Otherwise, we can allow write access */
+            DesiredAccess = SECTION_ALL_ACCESS;
+        }
+
+        /* Initialize the attributes for the section */
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   NULL,
+                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                                   NULL,
+                                   NULL);
+
+        /* Create the section */
+        Status = ZwCreateSection(&SectionHandle,
+                                 DesiredAccess,
+                                 &ObjectAttributes,
+                                 NULL,
+                                 PAGE_EXECUTE,
+                                 SEC_IMAGE,
+                                 FileHandle);
+        if (!NT_SUCCESS(Status)) goto Quickie;
+
+        /* Now get the section pointer */
+        Status = ObReferenceObjectByHandle(SectionHandle,
+                                           SECTION_MAP_EXECUTE,
+                                           MmSectionObjectType,
+                                           KernelMode,
+                                           &Section,
+                                           NULL);
+        ZwClose(SectionHandle);
+        if (!NT_SUCCESS(Status)) goto Quickie;
+
+        /* Check if this was supposed to be a session-load */
+        if (Flags)
+        {
+            /* We don't support session loading yet */
+            DPRINT1("Unsupported Session-Load!\n");
+            while (TRUE);
+        }
+
+        /* Check the loader list again, we should end up in the path below */
+        goto LoaderScan;
+    }
+    else
+    {
+        /* We don't have a valid entry */
+        LdrEntry = NULL;
+    }
+
+    /* Load the image */
+    Status = MiLoadImageSection(&Section,
+                                &ModuleLoadBase,
+                                FileName,
+                                FALSE,
+                                NULL);
+    ASSERT(Status != STATUS_ALREADY_COMMITTED);
+
+    /* Get the size of the driver */
+    DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
+
+    /* Make sure we're not being loaded into session space */
+    if (!Flags)
+    {
+        /* Check for success */
+        if (NT_SUCCESS(Status))
+        {
+            /* FIXME: Support large pages for drivers */
+        }
+
+        /* Dereference the section */
+        ObDereferenceObject(Section);
+        Section = NULL;
+    }
+
+    /* Get the NT Header */
+    NtHeader = RtlImageNtHeader(ModuleLoadBase);
+
+    /* Relocate the driver */
+    Status = LdrRelocateImageWithBias(ModuleLoadBase,
+                                      0,
+                                      "SYSLDR",
+                                      STATUS_SUCCESS,
+                                      STATUS_CONFLICTING_ADDRESSES,
+                                      STATUS_INVALID_IMAGE_FORMAT);
+    if (!NT_SUCCESS(Status)) goto Quickie;
+
+    /* Calculate the size we'll need for the entry and allocate it */
+    EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
+                BaseName.Length +
+                sizeof(UNICODE_NULL);
+
+    /* Allocate the entry */
+    LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
+    if (!LdrEntry)
+    {
+        /* Fail */
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Quickie;
+    }
+
+    /* Setup the entry */
+    LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
+    LdrEntry->LoadCount = 1;
+    LdrEntry->LoadedImports = LoadedImports;
+    LdrEntry->PatchInformation = NULL;
+
+    /* Check the version */
+    if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
+        (NtHeader->OptionalHeader.MajorImageVersion >= 5))
+    {
+        /* Mark this image as a native image */
+        LdrEntry->Flags |= 0x80000000;
+    }
+
+    /* Setup the rest of the entry */
+    LdrEntry->DllBase = ModuleLoadBase;
+    LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +
+                                   NtHeader->OptionalHeader.AddressOfEntryPoint);
+    LdrEntry->SizeOfImage = DriverSize;
+    LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
+    LdrEntry->SectionPointer = Section;
+
+    /* Now write the DLL name */
+    LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
+    LdrEntry->BaseDllName.Length = BaseName.Length;
+    LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
+
+    /* Copy and null-terminate it */
+    RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
+                  BaseName.Buffer,
+                  BaseName.Length);
+    LdrEntry->BaseDllName.Buffer[BaseName.Length / 2] = UNICODE_NULL;
+
+    /* Now allocate the full name */
+    LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
+                                                         PrefixName.Length +
+                                                         sizeof(UNICODE_NULL),
+                                                         TAG_LDR_WSTR);
+    if (!LdrEntry->FullDllName.Buffer)
+    {
+        /* Don't fail, just set it to zero */
+        LdrEntry->FullDllName.Length = 0;
+        LdrEntry->FullDllName.MaximumLength = 0;
+    }
+    else
+    {
+        /* Set it up */
+        LdrEntry->FullDllName.Length = PrefixName.Length;
+        LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
+
+        /* Copy and null-terminate */
+        RtlCopyMemory(LdrEntry->FullDllName.Buffer,
+                      PrefixName.Buffer,
+                      PrefixName.Length);
+        LdrEntry->FullDllName.Buffer[PrefixName.Length / 2] = UNICODE_NULL;
+    }
+
+    /* Add the entry */
+    MiProcessLoaderEntry(LdrEntry, TRUE);
+
+    /* Resolve imports */
+    MissingApiName = Buffer;
+    Status = MiResolveImageReferences(ModuleLoadBase,
+                                      &BaseDirectory,
+                                      NULL,
+                                      &MissingApiName,
+                                      &MissingDriverName,
+                                      &LoadedImports);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Fail */
+        MiProcessLoaderEntry(LdrEntry, FALSE);
+
+        /* Check if we need to free the name */
+        if (LdrEntry->FullDllName.Buffer)
+        {
+            /* Free it */
+            ExFreePool(LdrEntry->FullDllName.Buffer);
+        }
+
+        /* Free the entry itself */
+        ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
+        LdrEntry = NULL;
+        goto Quickie;
+    }
+
+    /* Update the loader entry */
+    LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |
+                        LDRP_ENTRY_PROCESSED |
+                        LDRP_MM_LOADED);
+    LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
+    LdrEntry->LoadedImports = LoadedImports;
+
+    /* FIXME: Apply driver verifier */
+
+    /* FIXME: Write-protect the system image */
+
+    /* Check if notifications are enabled */
+    if (PsImageNotifyEnabled)
+    {
+        /* Fill out the notification data */
+        ImageInfo.Properties = 0;
+        ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
+        ImageInfo.SystemModeImage = TRUE;
+        ImageInfo.ImageSize = LdrEntry->SizeOfImage;
+        ImageInfo.ImageBase = LdrEntry->DllBase;
+        ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;
+
+        /* Send the notification */
+        PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);
+    }
+
+    /* Check if there's symbols */
+#ifdef KDBG
+    /* If KDBG is defined, then we always have symbols */
+    if (TRUE)
+#else
+    if (MiCacheImageSymbols(LdrEntry->DllBase))
+#endif
+    {
+        /* Check if the system root is present */
+        if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&
+            !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))
+        {
+            /* Add the system root */
+            UnicodeTemp = PrefixName;
+            UnicodeTemp.Buffer += 11;
+            UnicodeTemp.Length -= (11 * sizeof(WCHAR));
+            sprintf_nt(Buffer,
+                       "%ws%wZ",
+                       &SharedUserData->NtSystemRoot[2],
+                       &UnicodeTemp);
+        }
+        else
+        {
+            /* Build the name */
+            sprintf_nt(Buffer, "%wZ", &BaseName);
+        }
+
+        /* Setup the ansi string */
+        RtlInitString(&AnsiTemp, Buffer);
+
+        /* Notify the debugger */
+        DbgLoadImageSymbols(&AnsiTemp,
+                            LdrEntry->DllBase,
+                            (ULONG_PTR)ZwCurrentProcess());
+        LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
+    }
+
+    /* FIXME: Page the driver */
+    ASSERT(Section == NULL);
+
+    /* Return pointers */
+    if (ModuleObject) *ModuleObject = LdrEntry;
+    if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;
+
+Quickie:
+    /* If we have a file handle, close it */
+    if (FileHandle) ZwClose(FileHandle);
+
+    /* Check if we have the lock acquired */
+    if (LockOwned)
+    {
+        /* Release the lock */
+        KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
+        KeLeaveCriticalRegion();
+        LockOwned = FALSE;
+    }
+
+    /* Check if we had a prefix */
+    if (NamePrefix) ExFreePool(PrefixName.Buffer);
+
+    /* Free the name buffer and return status */
+    ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+PVOID
+NTAPI
+MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
+{
+    PVOID ProcAddress = NULL;
+    ANSI_STRING AnsiRoutineName;
+    NTSTATUS Status;
+    PLIST_ENTRY NextEntry;
+    extern LIST_ENTRY PsLoadedModuleList;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    BOOLEAN Found = FALSE;
+    UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
+    UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
+    ULONG Modules = 0;
+
+    /* Convert routine to ansi name */
+    Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,
+                                          SystemRoutineName,
+                                          TRUE);
+    if (!NT_SUCCESS(Status)) return NULL;
+
+    /* Lock the list */
+    KeEnterCriticalRegion();
+
+    /* Loop the loaded module list */
+    NextEntry = PsLoadedModuleList.Flink;
+    while (NextEntry != &PsLoadedModuleList)
+    {
+        /* Get the entry */
+        LdrEntry = CONTAINING_RECORD(NextEntry,
+                                     LDR_DATA_TABLE_ENTRY,
+                                     InLoadOrderLinks);
+
+        /* Check if it's the kernel or HAL */
+        if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
+        {
+            /* Found it */
+            Found = TRUE;
+            Modules++;
+        }
+        else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
+        {
+            /* Found it */
+            Found = TRUE;
+            Modules++;
+        }
+
+        /* Check if we found a valid binary */
+        if (Found)
+        {
+            /* Find the procedure name */
+            ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,
+                                                      &AnsiRoutineName);
+
+            /* Break out if we found it or if we already tried both modules */
+            if (ProcAddress) break;
+            if (Modules == 2) break;
+        }
+
+        /* Keep looping */
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Release the lock */
+    KeLeaveCriticalRegion();
+
+    /* Free the string and return */
+    RtlFreeAnsiString(&AnsiRoutineName);
+    return ProcAddress;
+}
+