ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

sysldr.c
Go to the documentation of this file.
00001 /*
00002 * PROJECT:         ReactOS Kernel
00003 * LICENSE:         BSD - See COPYING.ARM in the top level directory
00004 * FILE:            ntoskrnl/mm/ARM3/sysldr.c
00005 * PURPOSE:         Contains the Kernel Loader (SYSLDR) for loading PE files.
00006 * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007 *                  ReactOS Portable Systems Group
00008 */
00009 
00010 /* INCLUDES *******************************************************************/
00011 
00012 #include <ntoskrnl.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 #define MODULE_INVOLVED_IN_ARM3
00017 #include "../ARM3/miarm.h"
00018 
00019 /* GCC's incompetence strikes again */
00020 __inline
00021 VOID
00022 sprintf_nt(IN PCHAR Buffer,
00023            IN PCHAR Format,
00024            IN ...)
00025 {
00026     va_list ap;
00027     va_start(ap, Format);
00028     vsprintf(Buffer, Format, ap);
00029     va_end(ap);
00030 }
00031 
00032 /* GLOBALS ********************************************************************/
00033 
00034 LIST_ENTRY PsLoadedModuleList;
00035 LIST_ENTRY MmLoadedUserImageList;
00036 KSPIN_LOCK PsLoadedModuleSpinLock;
00037 ERESOURCE PsLoadedModuleResource;
00038 ULONG_PTR PsNtosImageBase;
00039 KMUTANT MmSystemLoadLock;
00040 
00041 PFN_NUMBER MmTotalSystemDriverPages;
00042 
00043 PVOID MmUnloadedDrivers;
00044 PVOID MmLastUnloadedDrivers;
00045 
00046 BOOLEAN MmMakeLowMemory;
00047 BOOLEAN MmEnforceWriteProtection = TRUE;
00048 
00049 PMMPTE MiKernelResourceStartPte, MiKernelResourceEndPte;
00050 ULONG_PTR ExPoolCodeStart, ExPoolCodeEnd, MmPoolCodeStart, MmPoolCodeEnd;
00051 ULONG_PTR MmPteCodeStart, MmPteCodeEnd;
00052 
00053 /* FUNCTIONS ******************************************************************/
00054 
00055 PVOID
00056 NTAPI
00057 MiCacheImageSymbols(IN PVOID BaseAddress)
00058 {
00059     ULONG DebugSize;
00060     PVOID DebugDirectory = NULL;
00061     PAGED_CODE();
00062 
00063     /* Make sure it's safe to access the image */
00064     _SEH2_TRY
00065     {
00066         /* Get the debug directory */
00067         DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress,
00068                                                       TRUE,
00069                                                       IMAGE_DIRECTORY_ENTRY_DEBUG,
00070                                                       &DebugSize);
00071     }
00072     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00073     {
00074         /* Nothing */
00075     }
00076     _SEH2_END;
00077 
00078     /* Return the directory */
00079     return DebugDirectory;
00080 }
00081 
00082 NTSTATUS
00083 NTAPI
00084 MiLoadImageSection(IN OUT PVOID *SectionPtr,
00085                    OUT PVOID *ImageBase,
00086                    IN PUNICODE_STRING FileName,
00087                    IN BOOLEAN SessionLoad,
00088                    IN PLDR_DATA_TABLE_ENTRY LdrEntry)
00089 {
00090     PROS_SECTION_OBJECT Section = *SectionPtr;
00091     NTSTATUS Status;
00092     PEPROCESS Process;
00093     PVOID Base = NULL;
00094     SIZE_T ViewSize = 0;
00095     KAPC_STATE ApcState;
00096     LARGE_INTEGER SectionOffset = {{0, 0}};
00097     BOOLEAN LoadSymbols = FALSE;
00098     PFN_COUNT PteCount;
00099     PMMPTE PointerPte, LastPte;
00100     PVOID DriverBase;
00101     MMPTE TempPte;
00102     PAGED_CODE();
00103 
00104     /* Detect session load */
00105     if (SessionLoad)
00106     {
00107         /* Fail */
00108         DPRINT1("Session loading not yet supported!\n");
00109         while (TRUE);
00110     }
00111 
00112     /* Not session load, shouldn't have an entry */
00113     ASSERT(LdrEntry == NULL);
00114 
00115     /* Attach to the system process */
00116     KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
00117 
00118     /* Check if we need to load symbols */
00119     if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)
00120     {
00121         /* Yes we do */
00122         LoadSymbols = TRUE;
00123         NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
00124     }
00125 
00126     /* Map the driver */
00127     Process = PsGetCurrentProcess();
00128     Status = MmMapViewOfSection(Section,
00129                                 Process,
00130                                 &Base,
00131                                 0,
00132                                 0,
00133                                 &SectionOffset,
00134                                 &ViewSize,
00135                                 ViewUnmap,
00136                                 0,
00137                                 PAGE_EXECUTE);
00138 
00139     /* Re-enable the flag */
00140     if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
00141 
00142     /* Check if we failed with distinguished status code */
00143     if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
00144     {
00145         /* Change it to something more generic */
00146         Status = STATUS_INVALID_IMAGE_FORMAT;
00147     }
00148 
00149     /* Now check if we failed */
00150     if (!NT_SUCCESS(Status))
00151     {
00152         /* Detach and return */
00153         DPRINT1("MmMapViewOfSection failed with status 0x%x\n", Status);
00154         KeUnstackDetachProcess(&ApcState);
00155         return Status;
00156     }
00157 
00158     /* Reserve system PTEs needed */
00159     PteCount = ROUND_TO_PAGES(Section->ImageSection->ImageSize) >> PAGE_SHIFT;
00160     PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
00161     if (!PointerPte)
00162     {
00163         DPRINT1("MiReserveSystemPtes failed\n");
00164         KeUnstackDetachProcess(&ApcState);
00165         return STATUS_INSUFFICIENT_RESOURCES;
00166     }
00167 
00168     /* New driver base */
00169     LastPte = PointerPte + PteCount;
00170     DriverBase = MiPteToAddress(PointerPte);
00171 
00172     /* The driver is here */
00173     *ImageBase = DriverBase;
00174     DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName, DriverBase, PteCount);
00175 
00176     /* Loop the new driver PTEs */
00177     TempPte = ValidKernelPte;
00178     while (PointerPte < LastPte)
00179     {
00180         /* Allocate a page */
00181         MI_SET_USAGE(MI_USAGE_DRIVER_PAGE);
00182 #if MI_TRACE_PFNS
00183         PWCHAR pos = NULL;
00184         ULONG len = 0;
00185         if (FileName->Buffer)
00186         {
00187             pos = wcsrchr(FileName->Buffer, '\\');
00188             len = wcslen(pos) * sizeof(WCHAR);
00189             if (pos) snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos);
00190         }
00191 #endif
00192         TempPte.u.Hard.PageFrameNumber = MiAllocatePfn(PointerPte, MM_EXECUTE);
00193 
00194         /* Write it */
00195         MI_WRITE_VALID_PTE(PointerPte, TempPte);
00196 
00197         /* Move on */
00198         PointerPte++;
00199     }
00200 
00201     /* Copy the image */
00202     RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT);
00203 
00204     /* Now unmap the view */
00205     Status = MmUnmapViewOfSection(Process, Base);
00206     ASSERT(NT_SUCCESS(Status));
00207 
00208     /* Detach and return status */
00209     KeUnstackDetachProcess(&ApcState);
00210     return Status;
00211 }
00212 
00213 PVOID
00214 NTAPI
00215 MiLocateExportName(IN PVOID DllBase,
00216                    IN PCHAR ExportName)
00217 {
00218     PULONG NameTable;
00219     PUSHORT OrdinalTable;
00220     PIMAGE_EXPORT_DIRECTORY ExportDirectory;
00221     LONG Low = 0, Mid = 0, High, Ret;
00222     USHORT Ordinal;
00223     PVOID Function;
00224     ULONG ExportSize;
00225     PULONG ExportTable;
00226     PAGED_CODE();
00227 
00228     /* Get the export directory */
00229     ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
00230                                                    TRUE,
00231                                                    IMAGE_DIRECTORY_ENTRY_EXPORT,
00232                                                    &ExportSize);
00233     if (!ExportDirectory) return NULL;
00234 
00235     /* Setup name tables */
00236     NameTable = (PULONG)((ULONG_PTR)DllBase +
00237                          ExportDirectory->AddressOfNames);
00238     OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
00239                              ExportDirectory->AddressOfNameOrdinals);
00240 
00241     /* Do a binary search */
00242     High = ExportDirectory->NumberOfNames - 1;
00243     while (High >= Low)
00244     {
00245         /* Get new middle value */
00246         Mid = (Low + High) >> 1;
00247 
00248         /* Compare name */
00249         Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);
00250         if (Ret < 0)
00251         {
00252             /* Update high */
00253             High = Mid - 1;
00254         }
00255         else if (Ret > 0)
00256         {
00257             /* Update low */
00258             Low = Mid + 1;
00259         }
00260         else
00261         {
00262             /* We got it */
00263             break;
00264         }
00265     }
00266 
00267     /* Check if we couldn't find it */
00268     if (High < Low) return NULL;
00269 
00270     /* Otherwise, this is the ordinal */
00271     Ordinal = OrdinalTable[Mid];
00272 
00273     /* Resolve the address and write it */
00274     ExportTable = (PULONG)((ULONG_PTR)DllBase +
00275                            ExportDirectory->AddressOfFunctions);
00276     Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
00277 
00278     /* Check if the function is actually a forwarder */
00279     if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
00280         ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
00281     {
00282         /* It is, fail */
00283         return NULL;
00284     }
00285 
00286     /* We found it */
00287     return Function;
00288 }
00289 
00290 NTSTATUS
00291 NTAPI
00292 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
00293                     IN PLIST_ENTRY ListHead)
00294 {
00295     UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(
00296         L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
00297     PMM_DLL_INITIALIZE DllInit;
00298     UNICODE_STRING RegPath, ImportName;
00299     NTSTATUS Status;
00300 
00301     /* Try to see if the image exports a DllInitialize routine */
00302     DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
00303                                                      "DllInitialize");
00304     if (!DllInit) return STATUS_SUCCESS;
00305 
00306     /* Do a temporary copy of BaseDllName called ImportName
00307      * because we'll alter the length of the string
00308      */
00309     ImportName.Length = LdrEntry->BaseDllName.Length;
00310     ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;
00311     ImportName.Buffer = LdrEntry->BaseDllName.Buffer;
00312 
00313     /* Obtain the path to this dll's service in the registry */
00314     RegPath.MaximumLength = ServicesKeyName.Length +
00315         ImportName.Length + sizeof(UNICODE_NULL);
00316     RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
00317                                            RegPath.MaximumLength,
00318                                            TAG_LDR_WSTR);
00319 
00320     /* Check if this allocation was unsuccessful */
00321     if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
00322 
00323     /* Build and append the service name itself */
00324     RegPath.Length = ServicesKeyName.Length;
00325     RtlCopyMemory(RegPath.Buffer,
00326                   ServicesKeyName.Buffer,
00327                   ServicesKeyName.Length);
00328 
00329     /* Check if there is a dot in the filename */
00330     if (wcschr(ImportName.Buffer, L'.'))
00331     {
00332         /* Remove the extension */
00333         ImportName.Length = (USHORT)(wcschr(ImportName.Buffer, L'.') -
00334             ImportName.Buffer) * sizeof(WCHAR);
00335     }
00336 
00337     /* Append service name (the basename without extension) */
00338     RtlAppendUnicodeStringToString(&RegPath, &ImportName);
00339 
00340     /* Now call the DllInit func */
00341     DPRINT("Calling DllInit(%wZ)\n", &RegPath);
00342     Status = DllInit(&RegPath);
00343 
00344     /* Clean up */
00345     ExFreePoolWithTag(RegPath.Buffer, TAG_LDR_WSTR);
00346 
00347     /* Return status value which DllInitialize returned */
00348     return Status;
00349 }
00350 
00351 BOOLEAN
00352 NTAPI
00353 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
00354 {
00355     NTSTATUS Status;
00356     PMM_DLL_UNLOAD Func;
00357     PAGED_CODE();
00358 
00359     /* Get the unload routine */
00360     Func = (PMM_DLL_UNLOAD)MiLocateExportName(LdrEntry->DllBase, "DllUnload");
00361     if (!Func) return FALSE;
00362 
00363     /* Call it and check for success */
00364     Status = Func();
00365     if (!NT_SUCCESS(Status)) return FALSE;
00366 
00367     /* Lie about the load count so we can unload the image */
00368     ASSERT(LdrEntry->LoadCount == 0);
00369     LdrEntry->LoadCount = 1;
00370 
00371     /* Unload it and return true */
00372     MmUnloadSystemImage(LdrEntry);
00373     return TRUE;
00374 }
00375 
00376 NTSTATUS
00377 NTAPI
00378 MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
00379 {
00380     SIZE_T i;
00381     LOAD_IMPORTS SingleEntry;
00382     PLDR_DATA_TABLE_ENTRY LdrEntry;
00383     PVOID CurrentImports;
00384     PAGED_CODE();
00385 
00386     /* Check if there's no imports or if we're a boot driver */
00387     if ((ImportList == MM_SYSLDR_NO_IMPORTS) ||
00388         (ImportList == MM_SYSLDR_BOOT_LOADED) ||
00389         (ImportList->Count == 0))
00390     {
00391         /* Then there's nothing to do */
00392         return STATUS_SUCCESS;
00393     }
00394 
00395     /* Check for single-entry */
00396     if ((ULONG_PTR)ImportList & MM_SYSLDR_SINGLE_ENTRY)
00397     {
00398         /* Set it up */
00399         SingleEntry.Count = 1;
00400         SingleEntry.Entry[0] = (PVOID)((ULONG_PTR)ImportList &~ MM_SYSLDR_SINGLE_ENTRY);
00401 
00402         /* Use this as the import list */
00403         ImportList = &SingleEntry;
00404     }
00405 
00406     /* Loop the import list */
00407     for (i = 0; (i < ImportList->Count) && (ImportList->Entry[i]); i++)
00408     {
00409         /* Get the entry */
00410         LdrEntry = ImportList->Entry[i];
00411         DPRINT1("%wZ <%wZ>\n", &LdrEntry->FullDllName, &LdrEntry->BaseDllName);
00412 
00413         /* Skip boot loaded images */
00414         if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) continue;
00415 
00416         /* Dereference the entry */
00417         ASSERT(LdrEntry->LoadCount >= 1);
00418         if (!--LdrEntry->LoadCount)
00419         {
00420             /* Save the import data in case unload fails */
00421             CurrentImports = LdrEntry->LoadedImports;
00422 
00423             /* This is the last entry */
00424             LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
00425             if (MiCallDllUnloadAndUnloadDll(LdrEntry))
00426             {
00427                 /* Unloading worked, parse this DLL's imports too */
00428                 MiDereferenceImports(CurrentImports);
00429 
00430                 /* Check if we had valid imports */
00431                 if ((CurrentImports != MM_SYSLDR_BOOT_LOADED) ||
00432                     (CurrentImports != MM_SYSLDR_NO_IMPORTS) ||
00433                     !((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY))
00434                 {
00435                     /* Free them */
00436                     ExFreePoolWithTag(CurrentImports, TAG_LDR_IMPORTS);
00437                 }
00438             }
00439             else
00440             {
00441                 /* Unload failed, restore imports */
00442                 LdrEntry->LoadedImports = CurrentImports;
00443             }
00444         }
00445     }
00446 
00447     /* Done */
00448     return STATUS_SUCCESS;
00449 }
00450 
00451 VOID
00452 NTAPI
00453 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
00454 {
00455     PAGED_CODE();
00456 
00457     /* Check if there's no imports or we're a boot driver or only one entry */
00458     if ((LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) ||
00459         (LdrEntry->LoadedImports == MM_SYSLDR_NO_IMPORTS) ||
00460         ((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY))
00461     {
00462         /* Nothing to do */
00463         return;
00464     }
00465 
00466     /* Otherwise, free the import list */
00467     ExFreePoolWithTag(LdrEntry->LoadedImports, TAG_LDR_IMPORTS);
00468     LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
00469 }
00470 
00471 PVOID
00472 NTAPI
00473 MiFindExportedRoutineByName(IN PVOID DllBase,
00474                             IN PANSI_STRING ExportName)
00475 {
00476     PULONG NameTable;
00477     PUSHORT OrdinalTable;
00478     PIMAGE_EXPORT_DIRECTORY ExportDirectory;
00479     LONG Low = 0, Mid = 0, High, Ret;
00480     USHORT Ordinal;
00481     PVOID Function;
00482     ULONG ExportSize;
00483     PULONG ExportTable;
00484     PAGED_CODE();
00485 
00486     /* Get the export directory */
00487     ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
00488                                                    TRUE,
00489                                                    IMAGE_DIRECTORY_ENTRY_EXPORT,
00490                                                    &ExportSize);
00491     if (!ExportDirectory) return NULL;
00492 
00493     /* Setup name tables */
00494     NameTable = (PULONG)((ULONG_PTR)DllBase +
00495                          ExportDirectory->AddressOfNames);
00496     OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
00497                              ExportDirectory->AddressOfNameOrdinals);
00498 
00499     /* Do a binary search */
00500     High = ExportDirectory->NumberOfNames - 1;
00501     while (High >= Low)
00502     {
00503         /* Get new middle value */
00504         Mid = (Low + High) >> 1;
00505 
00506         /* Compare name */
00507         Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);
00508         if (Ret < 0)
00509         {
00510             /* Update high */
00511             High = Mid - 1;
00512         }
00513         else if (Ret > 0)
00514         {
00515             /* Update low */
00516             Low = Mid + 1;
00517         }
00518         else
00519         {
00520             /* We got it */
00521             break;
00522         }
00523     }
00524 
00525     /* Check if we couldn't find it */
00526     if (High < Low) return NULL;
00527 
00528     /* Otherwise, this is the ordinal */
00529     Ordinal = OrdinalTable[Mid];
00530 
00531     /* Validate the ordinal */
00532     if (Ordinal >= ExportDirectory->NumberOfFunctions) return NULL;
00533 
00534     /* Resolve the address and write it */
00535     ExportTable = (PULONG)((ULONG_PTR)DllBase +
00536                            ExportDirectory->AddressOfFunctions);
00537     Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
00538 
00539     /* We found it! */
00540     ASSERT(!(Function > (PVOID)ExportDirectory) &&
00541            (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));
00542     return Function;
00543 }
00544 
00545 VOID
00546 NTAPI
00547 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
00548                      IN BOOLEAN Insert)
00549 {
00550     KIRQL OldIrql;
00551 
00552     /* Acquire module list lock */
00553     KeEnterCriticalRegion();
00554     ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
00555 
00556     /* Acquire the spinlock too as we will insert or remove the entry */
00557     OldIrql = KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock);
00558 
00559     /* Insert or remove from the list */
00560     Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :
00561              RemoveEntryList(&LdrEntry->InLoadOrderLinks);
00562 
00563     /* Release locks */
00564     KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
00565     ExReleaseResourceLite(&PsLoadedModuleResource);
00566     KeLeaveCriticalRegion();
00567 }
00568 
00569 VOID
00570 NTAPI
00571 INIT_FUNCTION
00572 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
00573                IN PVOID OldBase,
00574                IN PVOID NewBase,
00575                IN ULONG Size)
00576 {
00577     ULONG_PTR OldBaseTop, Delta;
00578     PLDR_DATA_TABLE_ENTRY LdrEntry;
00579     PLIST_ENTRY NextEntry;
00580     ULONG ImportSize;
00581     //
00582     // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
00583     // since a real version of Windows would fail at this point, but they seem
00584     // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
00585     // a feature which isn't even used by Windows. Priorities, priorities...
00586     // Please note that Microsoft WDK EULA and license prohibits using
00587     // the information contained within it for the generation of "non-Windows"
00588     // drivers, which is precisely what LD will generate, since an LD driver
00589     // will not load on Windows.
00590     //
00591 #ifdef _WORKING_LINKER_
00592     ULONG i;
00593 #endif
00594     PULONG_PTR ImageThunk;
00595     PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
00596 
00597     /* Calculate the top and delta */
00598     OldBaseTop = (ULONG_PTR)OldBase + Size - 1;
00599     Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;
00600 
00601     /* Loop the loader block */
00602     for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
00603          NextEntry != &LoaderBlock->LoadOrderListHead;
00604          NextEntry = NextEntry->Flink)
00605     {
00606         /* Get the loader entry */
00607         LdrEntry = CONTAINING_RECORD(NextEntry,
00608                                      LDR_DATA_TABLE_ENTRY,
00609                                      InLoadOrderLinks);
00610 #ifdef _WORKING_LINKER_
00611         /* Get the IAT */
00612         ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
00613                                                   TRUE,
00614                                                   IMAGE_DIRECTORY_ENTRY_IAT,
00615                                                   &ImportSize);
00616         if (!ImageThunk) continue;
00617 
00618         /* Make sure we have an IAT */
00619         DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
00620         for (i = 0; i < ImportSize; i++, ImageThunk++)
00621         {
00622             /* Check if it's within this module */
00623             if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
00624             {
00625                 /* Relocate it */
00626                 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
00627                         ImageThunk, *ImageThunk, *ImageThunk + Delta);
00628                 *ImageThunk += Delta;
00629             }
00630         }
00631 #else
00632         /* Get the import table */
00633         ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
00634                                                         TRUE,
00635                                                         IMAGE_DIRECTORY_ENTRY_IMPORT,
00636                                                         &ImportSize);
00637         if (!ImportDescriptor) continue;
00638 
00639         /* Make sure we have an IAT */
00640         DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
00641         while ((ImportDescriptor->Name) &&
00642                (ImportDescriptor->OriginalFirstThunk))
00643         {
00644             /* Get the image thunk */
00645             ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
00646                                  ImportDescriptor->FirstThunk);
00647             while (*ImageThunk)
00648             {
00649                 /* Check if it's within this module */
00650                 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
00651                 {
00652                     /* Relocate it */
00653                     DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
00654                             ImageThunk, *ImageThunk, *ImageThunk + Delta);
00655                     *ImageThunk += Delta;
00656                 }
00657 
00658                 /* Go to the next thunk */
00659                 ImageThunk++;
00660             }
00661 
00662             /* Go to the next import */
00663             ImportDescriptor++;
00664         }
00665 #endif
00666     }
00667 }
00668 
00669 NTSTATUS
00670 NTAPI
00671 MiSnapThunk(IN PVOID DllBase,
00672             IN PVOID ImageBase,
00673             IN PIMAGE_THUNK_DATA Name,
00674             IN PIMAGE_THUNK_DATA Address,
00675             IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
00676             IN ULONG ExportSize,
00677             IN BOOLEAN SnapForwarder,
00678             OUT PCHAR *MissingApi)
00679 {
00680     BOOLEAN IsOrdinal;
00681     USHORT Ordinal;
00682     PULONG NameTable;
00683     PUSHORT OrdinalTable;
00684     PIMAGE_IMPORT_BY_NAME NameImport;
00685     USHORT Hint;
00686     ULONG Low = 0, Mid = 0, High;
00687     LONG Ret;
00688     NTSTATUS Status;
00689     PCHAR MissingForwarder;
00690     CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];
00691     PULONG ExportTable;
00692     ANSI_STRING DllName;
00693     UNICODE_STRING ForwarderName;
00694     PLIST_ENTRY NextEntry;
00695     PLDR_DATA_TABLE_ENTRY LdrEntry;
00696     ULONG ForwardExportSize;
00697     PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;
00698     PIMAGE_IMPORT_BY_NAME ForwardName;
00699     SIZE_T ForwardLength;
00700     IMAGE_THUNK_DATA ForwardThunk;
00701     PAGED_CODE();
00702 
00703     /* Check if this is an ordinal */
00704     IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);
00705     if ((IsOrdinal) && !(SnapForwarder))
00706     {
00707         /* Get the ordinal number and set it as missing */
00708         Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -
00709                            ExportDirectory->Base);
00710         *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;
00711     }
00712     else
00713     {
00714         /* Get the VA if we don't have to snap */
00715         if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;
00716         NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;
00717 
00718         /* Copy the procedure name */
00719         RtlStringCbCopyA(*MissingApi,
00720                          MAXIMUM_FILENAME_LENGTH,
00721                          (PCHAR)&NameImport->Name[0]);
00722 
00723         /* Setup name tables */
00724         DPRINT("Import name: %s\n", NameImport->Name);
00725         NameTable = (PULONG)((ULONG_PTR)DllBase +
00726                              ExportDirectory->AddressOfNames);
00727         OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
00728                                  ExportDirectory->AddressOfNameOrdinals);
00729 
00730         /* Get the hint and check if it's valid */
00731         Hint = NameImport->Hint;
00732         if ((Hint < ExportDirectory->NumberOfNames) &&
00733             !(strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))
00734         {
00735             /* We have a match, get the ordinal number from here */
00736             Ordinal = OrdinalTable[Hint];
00737         }
00738         else
00739         {
00740             /* Do a binary search */
00741             High = ExportDirectory->NumberOfNames - 1;
00742             while (High >= Low)
00743             {
00744                 /* Get new middle value */
00745                 Mid = (Low + High) >> 1;
00746 
00747                 /* Compare name */
00748                 Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);
00749                 if (Ret < 0)
00750                 {
00751                     /* Update high */
00752                     High = Mid - 1;
00753                 }
00754                 else if (Ret > 0)
00755                 {
00756                     /* Update low */
00757                     Low = Mid + 1;
00758                 }
00759                 else
00760                 {
00761                     /* We got it */
00762                     break;
00763                 }
00764             }
00765 
00766             /* Check if we couldn't find it */
00767             if (High < Low)
00768             {
00769                 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport->Name);
00770                 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
00771             }
00772 
00773             /* Otherwise, this is the ordinal */
00774             Ordinal = OrdinalTable[Mid];
00775         }
00776     }
00777 
00778     /* Check if the ordinal is invalid */
00779     if (Ordinal >= ExportDirectory->NumberOfFunctions)
00780     {
00781         /* Fail */
00782         Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
00783     }
00784     else
00785     {
00786         /* In case the forwarder is missing */
00787         MissingForwarder = NameBuffer;
00788 
00789         /* Resolve the address and write it */
00790         ExportTable = (PULONG)((ULONG_PTR)DllBase +
00791                                ExportDirectory->AddressOfFunctions);
00792         Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];
00793 
00794         /* Assume success from now on */
00795         Status = STATUS_SUCCESS;
00796 
00797         /* Check if the function is actually a forwarder */
00798         if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&
00799             (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
00800         {
00801             /* Now assume failure in case the forwarder doesn't exist */
00802             Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
00803 
00804             /* Build the forwarder name */
00805             DllName.Buffer = (PCHAR)Address->u1.Function;
00806             DllName.Length = (USHORT)(strchr(DllName.Buffer, '.') -
00807                                       DllName.Buffer) +
00808                                       sizeof(ANSI_NULL);
00809             DllName.MaximumLength = DllName.Length;
00810 
00811             /* Convert it */
00812             if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,
00813                                                          &DllName,
00814                                                          TRUE)))
00815             {
00816                 /* We failed, just return an error */
00817                 return Status;
00818             }
00819 
00820             /* Loop the module list */
00821             NextEntry = PsLoadedModuleList.Flink;
00822             while (NextEntry != &PsLoadedModuleList)
00823             {
00824                 /* Get the loader entry */
00825                 LdrEntry = CONTAINING_RECORD(NextEntry,
00826                                              LDR_DATA_TABLE_ENTRY,
00827                                              InLoadOrderLinks);
00828 
00829                 /* Check if it matches */
00830                 if (RtlPrefixString((PSTRING)&ForwarderName,
00831                                     (PSTRING)&LdrEntry->BaseDllName,
00832                                     TRUE))
00833                 {
00834                     /* Get the forwarder export directory */
00835                     ForwardExportDirectory =
00836                         RtlImageDirectoryEntryToData(LdrEntry->DllBase,
00837                                                      TRUE,
00838                                                      IMAGE_DIRECTORY_ENTRY_EXPORT,
00839                                                      &ForwardExportSize);
00840                     if (!ForwardExportDirectory) break;
00841 
00842                     /* Allocate a name entry */
00843                     ForwardLength = strlen(DllName.Buffer + DllName.Length) +
00844                                     sizeof(ANSI_NULL);
00845                     ForwardName = ExAllocatePoolWithTag(PagedPool,
00846                                                         sizeof(*ForwardName) +
00847                                                         ForwardLength,
00848                                                         TAG_LDR_WSTR);
00849                     if (!ForwardName) break;
00850 
00851                     /* Copy the data */
00852                     RtlCopyMemory(&ForwardName->Name[0],
00853                                   DllName.Buffer + DllName.Length,
00854                                   ForwardLength);
00855                     ForwardName->Hint = 0;
00856 
00857                     /* Set the new address */
00858                     ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName;
00859 
00860                     /* Snap the forwarder */
00861                     Status = MiSnapThunk(LdrEntry->DllBase,
00862                                          ImageBase,
00863                                          &ForwardThunk,
00864                                          &ForwardThunk,
00865                                          ForwardExportDirectory,
00866                                          ForwardExportSize,
00867                                          TRUE,
00868                                          &MissingForwarder);
00869 
00870                     /* Free the forwarder name and set the thunk */
00871                     ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR);
00872                     Address->u1 = ForwardThunk.u1;
00873                     break;
00874                 }
00875 
00876                 /* Go to the next entry */
00877                 NextEntry = NextEntry->Flink;
00878             }
00879 
00880             /* Free the name */
00881             RtlFreeUnicodeString(&ForwarderName);
00882         }
00883     }
00884 
00885     /* Return status */
00886     return Status;
00887 }
00888 
00889 NTSTATUS
00890 NTAPI
00891 MmUnloadSystemImage(IN PVOID ImageHandle)
00892 {
00893     PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;
00894     PVOID BaseAddress = LdrEntry->DllBase;
00895     NTSTATUS Status;
00896     STRING TempName;
00897     BOOLEAN HadEntry = FALSE;
00898 
00899     /* Acquire the loader lock */
00900     KeEnterCriticalRegion();
00901     KeWaitForSingleObject(&MmSystemLoadLock,
00902                           WrVirtualMemory,
00903                           KernelMode,
00904                           FALSE,
00905                           NULL);
00906 
00907     /* Check if this driver was loaded at boot and didn't get imports parsed */
00908     if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) goto Done;
00909 
00910     /* We should still be alive */
00911     ASSERT(LdrEntry->LoadCount != 0);
00912     LdrEntry->LoadCount--;
00913 
00914     /* Check if we're still loaded */
00915     if (LdrEntry->LoadCount) goto Done;
00916 
00917     /* We should cleanup... are symbols loaded */
00918     if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)
00919     {
00920         /* Create the ANSI name */
00921         Status = RtlUnicodeStringToAnsiString(&TempName,
00922                                               &LdrEntry->BaseDllName,
00923                                               TRUE);
00924         if (NT_SUCCESS(Status))
00925         {
00926             /* Unload the symbols */
00927             DbgUnLoadImageSymbols(&TempName,
00928                                   BaseAddress,
00929                                   (ULONG_PTR)ZwCurrentProcess());
00930             RtlFreeAnsiString(&TempName);
00931         }
00932     }
00933 
00934     /* FIXME: Free the driver */
00935     DPRINT1("Leaking driver: %wZ\n", &LdrEntry->BaseDllName);
00936     //MmFreeSection(LdrEntry->DllBase);
00937 
00938     /* Check if we're linked in */
00939     if (LdrEntry->InLoadOrderLinks.Flink)
00940     {
00941         /* Remove us */
00942         MiProcessLoaderEntry(LdrEntry, FALSE);
00943         HadEntry = TRUE;
00944     }
00945 
00946     /* Dereference and clear the imports */
00947     MiDereferenceImports(LdrEntry->LoadedImports);
00948     MiClearImports(LdrEntry);
00949 
00950     /* Check if the entry needs to go away */
00951     if (HadEntry)
00952     {
00953         /* Check if it had a name */
00954         if (LdrEntry->FullDllName.Buffer)
00955         {
00956             /* Free it */
00957             ExFreePoolWithTag(LdrEntry->FullDllName.Buffer, TAG_LDR_WSTR);
00958         }
00959 
00960         /* Check if we had a section */
00961         if (LdrEntry->SectionPointer)
00962         {
00963             /* Dereference it */
00964             ObDereferenceObject(LdrEntry->SectionPointer);
00965         }
00966 
00967         /* Free the entry */
00968         ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
00969     }
00970 
00971     /* Release the system lock and return */
00972 Done:
00973     KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
00974     KeLeaveCriticalRegion();
00975     return STATUS_SUCCESS;
00976 }
00977 
00978 NTSTATUS
00979 NTAPI
00980 MiResolveImageReferences(IN PVOID ImageBase,
00981                          IN PUNICODE_STRING ImageFileDirectory,
00982                          IN PUNICODE_STRING NamePrefix OPTIONAL,
00983                          OUT PCHAR *MissingApi,
00984                          OUT PWCHAR *MissingDriver,
00985                          OUT PLOAD_IMPORTS *LoadImports)
00986 {
00987     PCHAR MissingApiBuffer = *MissingApi, ImportName;
00988     PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
00989     ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
00990     PLOAD_IMPORTS LoadedImports, NewImports;
00991     ULONG GdiLink, NormalLink, i;
00992     BOOLEAN ReferenceNeeded, Loaded;
00993     ANSI_STRING TempString;
00994     UNICODE_STRING NameString, DllName;
00995     PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;
00996     PVOID ImportBase, DllBase;
00997     PLIST_ENTRY NextEntry;
00998     PIMAGE_EXPORT_DIRECTORY ExportDirectory;
00999     NTSTATUS Status;
01000     PIMAGE_THUNK_DATA OrigThunk, FirstThunk;
01001     PAGED_CODE();
01002     DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
01003            __FUNCTION__, ImageBase, ImageFileDirectory);
01004 
01005     /* Assume no imports */
01006     *LoadImports = MM_SYSLDR_NO_IMPORTS;
01007 
01008     /* Get the import descriptor */
01009     ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,
01010                                                     TRUE,
01011                                                     IMAGE_DIRECTORY_ENTRY_IMPORT,
01012                                                     &ImportSize);
01013     if (!ImportDescriptor) return STATUS_SUCCESS;
01014 
01015     /* Loop all imports to count them */
01016     for (CurrentImport = ImportDescriptor;
01017          (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);
01018          CurrentImport++)
01019     {
01020         /* One more */
01021         ImportCount++;
01022     }
01023 
01024     /* Make sure we have non-zero imports */
01025     if (ImportCount)
01026     {
01027         /* Calculate and allocate the list we'll need */
01028         LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
01029         LoadedImports = ExAllocatePoolWithTag(PagedPool,
01030                                               LoadedImportsSize,
01031                                               TAG_LDR_IMPORTS);
01032         if (LoadedImports)
01033         {
01034             /* Zero it */
01035             RtlZeroMemory(LoadedImports, LoadedImportsSize);
01036             LoadedImports->Count = ImportCount;
01037         }
01038     }
01039     else
01040     {
01041         /* No table */
01042         LoadedImports = NULL;
01043     }
01044 
01045     /* Reset the import count and loop descriptors again */
01046     ImportCount = GdiLink = NormalLink = 0;
01047     while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))
01048     {
01049         /* Get the name */
01050         ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);
01051 
01052         /* Check if this is a GDI driver */
01053         GdiLink = GdiLink |
01054                   !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));
01055 
01056         /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
01057         NormalLink = NormalLink |
01058                      ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&
01059                       (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)) &&
01060                       (_strnicmp(ImportName, "coverage", sizeof("coverage") - 1)) &&
01061                       (_strnicmp(ImportName, "irt", sizeof("irt") - 1)));
01062 
01063         /* Check if this is a valid GDI driver */
01064         if ((GdiLink) && (NormalLink))
01065         {
01066             /* It's not, it's importing stuff it shouldn't be! */
01067             MiDereferenceImports(LoadedImports);
01068             if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
01069             return STATUS_PROCEDURE_NOT_FOUND;
01070         }
01071 
01072         /* Check for user-mode printer or video card drivers, which don't belong */
01073         if (!(_strnicmp(ImportName, "ntdll", sizeof("ntdll") - 1)) ||
01074             !(_strnicmp(ImportName, "winsrv", sizeof("winsrv") - 1)) ||
01075             !(_strnicmp(ImportName, "advapi32", sizeof("advapi32") - 1)) ||
01076             !(_strnicmp(ImportName, "kernel32", sizeof("kernel32") - 1)) ||
01077             !(_strnicmp(ImportName, "user32", sizeof("user32") - 1)) ||
01078             !(_strnicmp(ImportName, "gdi32", sizeof("gdi32") - 1)))
01079         {
01080             /* This is not kernel code */
01081             MiDereferenceImports(LoadedImports);
01082             if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
01083             return STATUS_PROCEDURE_NOT_FOUND;
01084         }
01085 
01086         /* Check if this is a "core" import, which doesn't get referenced */
01087         if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
01088             !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||
01089             !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))
01090         {
01091             /* Don't reference this */
01092             ReferenceNeeded = FALSE;
01093         }
01094         else
01095         {
01096             /* Reference these modules */
01097             ReferenceNeeded = TRUE;
01098         }
01099 
01100         /* Now setup a unicode string for the import */
01101         RtlInitAnsiString(&TempString, ImportName);
01102         Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);
01103         if (!NT_SUCCESS(Status))
01104         {
01105             /* Failed */
01106             MiDereferenceImports(LoadedImports);
01107             if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
01108             return Status;
01109         }
01110 
01111         /* We don't support name prefixes yet */
01112         if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");
01113 
01114         /* Remember that we haven't loaded the import at this point */
01115 CheckDllState:
01116         Loaded = FALSE;
01117         ImportBase = NULL;
01118 
01119         /* Loop the driver list */
01120         NextEntry = PsLoadedModuleList.Flink;
01121         while (NextEntry != &PsLoadedModuleList)
01122         {
01123             /* Get the loader entry and compare the name */
01124             LdrEntry = CONTAINING_RECORD(NextEntry,
01125                                          LDR_DATA_TABLE_ENTRY,
01126                                          InLoadOrderLinks);
01127             if (RtlEqualUnicodeString(&NameString,
01128                                       &LdrEntry->BaseDllName,
01129                                       TRUE))
01130             {
01131                 /* Get the base address */
01132                 ImportBase = LdrEntry->DllBase;
01133 
01134                 /* Check if we haven't loaded yet, and we need references */
01135                 if (!(Loaded) && (ReferenceNeeded))
01136                 {
01137                     /* Make sure we're not already loading */
01138                     if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
01139                     {
01140                         /* Increase the load count */
01141                         LdrEntry->LoadCount++;
01142                     }
01143                 }
01144 
01145                 /* Done, break out */
01146                 break;
01147             }
01148 
01149             /* Go to the next entry */
01150             NextEntry = NextEntry->Flink;
01151         }
01152 
01153         /* Check if we haven't loaded the import yet */
01154         if (!ImportBase)
01155         {
01156             /* Setup the import DLL name */
01157             DllName.MaximumLength = NameString.Length +
01158                                     ImageFileDirectory->Length +
01159                                     sizeof(UNICODE_NULL);
01160             DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
01161                                                    DllName.MaximumLength,
01162                                                    TAG_LDR_WSTR);
01163             if (DllName.Buffer)
01164             {
01165                 /* Setup the base length and copy it */
01166                 DllName.Length = ImageFileDirectory->Length;
01167                 RtlCopyMemory(DllName.Buffer,
01168                               ImageFileDirectory->Buffer,
01169                               ImageFileDirectory->Length);
01170 
01171                 /* Now add the import name and null-terminate it */
01172                 RtlAppendUnicodeStringToString(&DllName,
01173                                                &NameString);
01174                 DllName.Buffer[DllName.Length / sizeof(WCHAR)] = UNICODE_NULL;
01175 
01176                 /* Load the image */
01177                 Status = MmLoadSystemImage(&DllName,
01178                                            NamePrefix,
01179                                            NULL,
01180                                            FALSE,
01181                                            (PVOID)&DllEntry,
01182                                            &DllBase);
01183                 if (NT_SUCCESS(Status))
01184                 {
01185                     /* We can free the DLL Name */
01186                     ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR);
01187                 }
01188                 else
01189                 {
01190                     /* Fill out the information for the error */
01191                     *MissingDriver = DllName.Buffer;
01192                     *(PULONG)MissingDriver |= 1;
01193                     *MissingApi = NULL;
01194 
01195                     DPRINT1("Failed to load dependency: %wZ\n", &DllName);
01196                 }
01197             }
01198             else
01199             {
01200                 /* We're out of resources */
01201                 Status = STATUS_INSUFFICIENT_RESOURCES;
01202             }
01203 
01204             /* Check if we're OK until now */
01205             if (NT_SUCCESS(Status))
01206             {
01207                 /* We're now loaded */
01208                 Loaded = TRUE;
01209 
01210                 /* Sanity check */
01211                 ASSERT(DllBase == DllEntry->DllBase);
01212 
01213                 /* Call the initialization routines */
01214                 Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
01215                 if (!NT_SUCCESS(Status))
01216                 {
01217                     /* We failed, unload the image */
01218                     MmUnloadSystemImage(DllEntry);
01219                     DPRINT1("MmCallDllInitialize failed with status 0x%x\n", Status);
01220                     while (TRUE);
01221                     Loaded = FALSE;
01222                 }
01223             }
01224 
01225             /* Check if we failed by here */
01226             if (!NT_SUCCESS(Status))
01227             {
01228                 /* Cleanup and return */
01229                 RtlFreeUnicodeString(&NameString);
01230                 MiDereferenceImports(LoadedImports);
01231                 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
01232                 return Status;
01233             }
01234 
01235             /* Loop again to make sure that everything is OK */
01236             goto CheckDllState;
01237         }
01238 
01239         /* Check if we're support to reference this import */
01240         if ((ReferenceNeeded) && (LoadedImports))
01241         {
01242             /* Make sure we're not already loading */
01243             if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
01244             {
01245                 /* Add the entry */
01246                 LoadedImports->Entry[ImportCount] = LdrEntry;
01247                 ImportCount++;
01248             }
01249         }
01250 
01251         /* Free the import name */
01252         RtlFreeUnicodeString(&NameString);
01253 
01254         /* Set the missing driver name and get the export directory */
01255         *MissingDriver = LdrEntry->BaseDllName.Buffer;
01256         ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,
01257                                                        TRUE,
01258                                                        IMAGE_DIRECTORY_ENTRY_EXPORT,
01259                                                        &ExportSize);
01260         if (!ExportDirectory)
01261         {
01262             /* Cleanup and return */
01263             MiDereferenceImports(LoadedImports);
01264             if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
01265             DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver);
01266             return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
01267         }
01268 
01269         /* Make sure we have an IAT */
01270         if (ImportDescriptor->OriginalFirstThunk)
01271         {
01272             /* Get the first thunks */
01273             OrigThunk = (PVOID)((ULONG_PTR)ImageBase +
01274                                 ImportDescriptor->OriginalFirstThunk);
01275             FirstThunk = (PVOID)((ULONG_PTR)ImageBase +
01276                                  ImportDescriptor->FirstThunk);
01277 
01278             /* Loop the IAT */
01279             while (OrigThunk->u1.AddressOfData)
01280             {
01281                 /* Snap thunk */
01282                 Status = MiSnapThunk(ImportBase,
01283                                      ImageBase,
01284                                      OrigThunk++,
01285                                      FirstThunk++,
01286                                      ExportDirectory,
01287                                      ExportSize,
01288                                      FALSE,
01289                                      MissingApi);
01290                 if (!NT_SUCCESS(Status))
01291                 {
01292                     /* Cleanup and return */
01293                     MiDereferenceImports(LoadedImports);
01294                     if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
01295                     return Status;
01296                 }
01297 
01298                 /* Reset the buffer */
01299                 *MissingApi = MissingApiBuffer;
01300             }
01301         }
01302 
01303         /* Go to the next import */
01304         ImportDescriptor++;
01305     }
01306 
01307     /* Check if we have an import list */
01308     if (LoadedImports)
01309     {
01310         /* Reset the count again, and loop entries */
01311         ImportCount = 0;
01312         for (i = 0; i < LoadedImports->Count; i++)
01313         {
01314             if (LoadedImports->Entry[i])
01315             {
01316                 /* Got an entry, OR it with 1 in case it's the single entry */
01317                 ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] |
01318                                       MM_SYSLDR_SINGLE_ENTRY);
01319                 ImportCount++;
01320             }
01321         }
01322 
01323         /* Check if we had no imports */
01324         if (!ImportCount)
01325         {
01326             /* Free the list and set it to no imports */
01327             ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
01328             LoadedImports = MM_SYSLDR_NO_IMPORTS;
01329         }
01330         else if (ImportCount == 1)
01331         {
01332             /* Just one entry, we can free the table and only use our entry */
01333             ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
01334             LoadedImports = (PLOAD_IMPORTS)ImportEntry;
01335         }
01336         else if (ImportCount != LoadedImports->Count)
01337         {
01338             /* Allocate a new list */
01339             LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
01340             NewImports = ExAllocatePoolWithTag(PagedPool,
01341                                                LoadedImportsSize,
01342                                                TAG_LDR_IMPORTS);
01343             if (NewImports)
01344             {
01345                 /* Set count */
01346                 NewImports->Count = 0;
01347 
01348                 /* Loop all the imports */
01349                 for (i = 0; i < LoadedImports->Count; i++)
01350                 {
01351                     /* Make sure it's valid */
01352                     if (LoadedImports->Entry[i])
01353                     {
01354                         /* Copy it */
01355                         NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];
01356                         NewImports->Count++;
01357                     }
01358                 }
01359 
01360                 /* Free the old copy */
01361                 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
01362                 LoadedImports = NewImports;
01363             }
01364         }
01365 
01366         /* Return the list */
01367         *LoadImports = LoadedImports;
01368     }
01369 
01370     /* Return success */
01371     return STATUS_SUCCESS;
01372 }
01373 
01374 VOID
01375 NTAPI
01376 MiFreeInitializationCode(IN PVOID InitStart,
01377                          IN PVOID InitEnd)
01378 {
01379     PMMPTE PointerPte;
01380     PFN_NUMBER PagesFreed;
01381 
01382     /* Get the start PTE */
01383     PointerPte = MiAddressToPte(InitStart);
01384     ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart) == FALSE);
01385 
01386     /*  Compute the number of pages we expect to free */
01387     PagesFreed = (PFN_NUMBER)(MiAddressToPte(InitEnd) - PointerPte + 1);
01388     
01389     /* Try to actually free them */
01390     PagesFreed = MiDeleteSystemPageableVm(PointerPte,
01391                                           PagesFreed,
01392                                           0,
01393                                           NULL);
01394 }
01395 
01396 VOID
01397 NTAPI
01398 INIT_FUNCTION
01399 MiFindInitializationCode(OUT PVOID *StartVa,
01400                          OUT PVOID *EndVa)
01401 {
01402     ULONG Size, SectionCount, Alignment;
01403     PLDR_DATA_TABLE_ENTRY LdrEntry;
01404     ULONG_PTR DllBase, InitStart, InitEnd, ImageEnd, InitCode;
01405     PLIST_ENTRY NextEntry;
01406     PIMAGE_NT_HEADERS NtHeader;
01407     PIMAGE_SECTION_HEADER Section, LastSection;
01408     BOOLEAN InitFound;
01409     
01410     /* So we don't free our own code yet */
01411     InitCode = (ULONG_PTR)&MiFindInitializationCode;
01412 
01413     /* Assume failure */
01414     *StartVa = NULL;
01415 
01416     /* Enter a critical region while we loop the list */
01417     KeEnterCriticalRegion();
01418 
01419     /* Loop all loaded modules */
01420     NextEntry = PsLoadedModuleList.Flink;
01421     while (NextEntry != &PsLoadedModuleList)
01422     {
01423         /* Get the loader entry and its DLL base */
01424         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
01425         DllBase = (ULONG_PTR)LdrEntry->DllBase;
01426         
01427         /* Get the NT header */
01428         NtHeader = RtlImageNtHeader((PVOID)DllBase);
01429         if (!NtHeader)
01430         {
01431             /* Keep going */
01432             NextEntry = NextEntry->Flink;
01433             continue;
01434         }
01435 
01436         /* Get the first section, the section count, and scan them all */
01437         Section = IMAGE_FIRST_SECTION(NtHeader);
01438         SectionCount = NtHeader->FileHeader.NumberOfSections;
01439         InitStart = 0;
01440         while (SectionCount > 0)
01441         {
01442             /* Assume failure */
01443             InitFound = FALSE;
01444 
01445             /* Is this the INIT section or a discardable section? */
01446             if ((*(PULONG)Section->Name == 'TINI') ||
01447                 ((Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)))
01448             {
01449                 /* Remember this */
01450                 InitFound = TRUE;
01451             }
01452 
01453             if (InitFound)
01454             {
01455                 /* Pick the biggest size -- either raw or virtual */
01456                 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
01457                 
01458                 /* Read the section alignment */
01459                 Alignment = NtHeader->OptionalHeader.SectionAlignment;
01460 
01461                 /* Align the start and end addresses appropriately */
01462                 InitStart = DllBase + Section->VirtualAddress;
01463                 InitEnd = ((Alignment + InitStart + Size - 2) & 0xFFFFF000) - 1;                        
01464                 InitStart = (InitStart + (PAGE_SIZE - 1)) & 0xFFFFF000;
01465 
01466                 /* Have we reached the last section? */
01467                 if (SectionCount == 1)
01468                 {
01469                     /* Remember this */
01470                     LastSection = Section;
01471                 }
01472                 else
01473                 {
01474                     /* We have not, loop all the sections */
01475                     LastSection = NULL;
01476                     do
01477                     {
01478                         /* Keep going until we find a non-discardable section range */
01479                         SectionCount--;
01480                         Section++;
01481                         if (Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
01482                         {
01483                             /* Discardable, so record it, then keep going */
01484                             LastSection = Section;
01485                         }
01486                         else
01487                         {
01488                             /* Non-contigous discard flag, or no flag, break out */
01489                             break;
01490                         }
01491                     }
01492                     while (SectionCount > 1);
01493                 }
01494 
01495                 /* Have we found a discardable or init section? */
01496                 if (LastSection)
01497                 {
01498                     /* Pick the biggest size -- either raw or virtual */
01499                     Size = max(LastSection->SizeOfRawData, LastSection->Misc.VirtualSize);
01500 
01501                     /* Use this as the end of the section address */
01502                     InitEnd = DllBase + LastSection->VirtualAddress + Size - 1;
01503 
01504                     /* Have we reached the last section yet? */
01505                     if (SectionCount != 1)
01506                     {
01507                         /* Then align this accross the session boundary */
01508                         InitEnd = ((Alignment + InitEnd - 1) & 0XFFFFF000) - 1;
01509                     }
01510                 }
01511 
01512                 /* Make sure we don't let the init section go past the image */
01513                 ImageEnd = DllBase + LdrEntry->SizeOfImage;
01514                 if (InitEnd > ImageEnd) InitEnd = (ImageEnd - 1) | (PAGE_SIZE - 1);
01515 
01516                 /* Make sure we have a valid, non-zero init section */
01517                 if (InitStart <= InitEnd)
01518                 {
01519                     /* Make sure we are not within this code itself */
01520                     if ((InitCode >= InitStart) && (InitCode <= InitEnd))
01521                     {
01522                         /* Return it, we can't free ourselves now */
01523                         ASSERT(*StartVa == 0);
01524                         *StartVa = (PVOID)InitStart;
01525                         *EndVa = (PVOID)InitEnd;
01526                     }
01527                     else
01528                     {
01529                         /* This isn't us -- go ahead and free it */
01530                         ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID)InitStart) == FALSE);
01531                         MiFreeInitializationCode((PVOID)InitStart, (PVOID)InitEnd);
01532                     }
01533                 }
01534             }
01535             
01536             /* Move to the next section */
01537             SectionCount--;
01538             Section++;
01539         }
01540         
01541         /* Move to the next module */
01542         NextEntry = NextEntry->Flink;
01543     }
01544 
01545     /* Leave the critical region and return */
01546     KeLeaveCriticalRegion();
01547 }
01548 
01549 /* 
01550  * Note: This function assumes that all discardable sections are at the end of
01551  * the PE file. It searches backwards until it finds the non-discardable section
01552  */
01553 VOID
01554 NTAPI
01555 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
01556 {
01557     PMMPTE StartPte, EndPte;
01558     PFN_NUMBER PageCount;
01559     PVOID DllBase;
01560     ULONG i;
01561     PIMAGE_NT_HEADERS NtHeader;
01562     PIMAGE_SECTION_HEADER Section, DiscardSection;
01563     ULONG PagesDeleted;
01564 
01565     /* Get the base address and the page count */
01566     DllBase = LdrEntry->DllBase;
01567     PageCount = LdrEntry->SizeOfImage >> PAGE_SHIFT;
01568 
01569     /* Get the last PTE in this image */
01570     EndPte = MiAddressToPte(DllBase) + PageCount;
01571 
01572     /* Get the NT header */
01573     NtHeader = RtlImageNtHeader(DllBase);
01574     if (!NtHeader) return;
01575 
01576     /* Get the last section and loop each section backwards */
01577     Section = IMAGE_FIRST_SECTION(NtHeader) + NtHeader->FileHeader.NumberOfSections;
01578     DiscardSection = NULL;
01579     for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
01580     {
01581         /* Go back a section and check if it's discardable */
01582         Section--;
01583         if (Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
01584         {
01585             /* It is, select it for freeing */
01586             DiscardSection = Section;
01587         }
01588         else
01589         {
01590             /* No more discardable sections exist, bail out */
01591             break;
01592         }
01593     }
01594 
01595     /* Bail out if there's nothing to free */
01596     if (!DiscardSection) return;
01597 
01598     /* Push the DLL base to the first disacrable section, and get its PTE */
01599     DllBase = (PVOID)ROUND_TO_PAGES((ULONG_PTR)DllBase + DiscardSection->VirtualAddress);
01600     ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase) == FALSE);
01601     StartPte = MiAddressToPte(DllBase);
01602 
01603     /* Check how many pages to free total */
01604     PageCount = (PFN_NUMBER)(EndPte - StartPte);
01605     if (!PageCount) return;
01606 
01607     /* Delete this many PTEs */
01608     PagesDeleted = MiDeleteSystemPageableVm(StartPte, PageCount, 0, NULL);
01609 }
01610 
01611 VOID
01612 NTAPI
01613 INIT_FUNCTION
01614 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
01615 {
01616     PLIST_ENTRY NextEntry;
01617     ULONG i = 0;
01618     PIMAGE_NT_HEADERS NtHeader;
01619     PLDR_DATA_TABLE_ENTRY LdrEntry;
01620     PIMAGE_FILE_HEADER FileHeader;
01621     BOOLEAN ValidRelocs;
01622     PIMAGE_DATA_DIRECTORY DataDirectory;
01623     PVOID DllBase, NewImageAddress;
01624     NTSTATUS Status;
01625     PMMPTE PointerPte, StartPte, LastPte;
01626     PFN_COUNT PteCount;
01627     PMMPFN Pfn1;
01628     MMPTE TempPte, OldPte;
01629 
01630     /* Loop driver list */
01631     for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
01632          NextEntry != &LoaderBlock->LoadOrderListHead;
01633          NextEntry = NextEntry->Flink)
01634     {
01635         /* Get the loader entry and NT header */
01636         LdrEntry = CONTAINING_RECORD(NextEntry,
01637                                      LDR_DATA_TABLE_ENTRY,
01638                                      InLoadOrderLinks);
01639         NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
01640 
01641         /* Debug info */
01642         DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
01643                 LdrEntry->DllBase,
01644                 (ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage,
01645                 &LdrEntry->FullDllName);
01646 
01647         /* Get the first PTE and the number of PTEs we'll need */
01648         PointerPte = StartPte = MiAddressToPte(LdrEntry->DllBase);
01649         PteCount = ROUND_TO_PAGES(LdrEntry->SizeOfImage) >> PAGE_SHIFT;
01650         LastPte = StartPte + PteCount;
01651 
01652 #if MI_TRACE_PFNS
01653         /* Loop the PTEs */
01654         while (PointerPte < LastPte)
01655         {
01656             ULONG len;
01657             ASSERT(PointerPte->u.Hard.Valid == 1);
01658             Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
01659             len = wcslen(LdrEntry->BaseDllName.Buffer) * sizeof(WCHAR);
01660             snprintf(Pfn1->ProcessName, min(16, len), "%S", LdrEntry->BaseDllName.Buffer);
01661             PointerPte++;
01662         }
01663 #endif
01664         /* Skip kernel and HAL */
01665         /* ROS HACK: Skip BOOTVID/KDCOM too */
01666         i++;
01667         if (i <= 4) continue;
01668 
01669         /* Skip non-drivers */
01670         if (!NtHeader) continue;
01671 
01672         /* Get the file header and make sure we can relocate */
01673         FileHeader = &NtHeader->FileHeader;
01674         if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
01675         if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
01676             IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
01677 
01678         /* Everything made sense until now, check the relocation section too */
01679         DataDirectory = &NtHeader->OptionalHeader.
01680                         DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
01681         if (!DataDirectory->VirtualAddress)
01682         {
01683             /* We don't really have relocations */
01684             ValidRelocs = FALSE;
01685         }
01686         else
01687         {
01688             /* Make sure the size is valid */
01689             if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
01690                 LdrEntry->SizeOfImage)
01691             {
01692                 /* They're not, skip */
01693                 continue;
01694             }
01695 
01696             /* We have relocations */
01697             ValidRelocs = TRUE;
01698         }
01699 
01700         /* Remember the original address */
01701         DllBase = LdrEntry->DllBase;
01702 
01703         /* Loop the PTEs */
01704         PointerPte = StartPte;
01705         while (PointerPte < LastPte)
01706         {
01707             /* Mark the page modified in the PFN database */
01708             ASSERT(PointerPte->u.Hard.Valid == 1);
01709             Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
01710             ASSERT(Pfn1->u3.e1.Rom == 0);
01711             Pfn1->u3.e1.Modified = TRUE;
01712 
01713             /* Next */
01714             PointerPte++;
01715         }
01716 
01717         /* Now reserve system PTEs for the image */
01718         PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
01719         if (!PointerPte)
01720         {
01721             /* Shouldn't happen */
01722             DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
01723             while (TRUE);
01724         }
01725 
01726         /* This is the new virtual address for the module */
01727         LastPte = PointerPte + PteCount;
01728         NewImageAddress = MiPteToAddress(PointerPte);
01729 
01730         /* Sanity check */
01731         DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
01732         ASSERT(ExpInitializationPhase == 0);
01733 
01734         /* Loop the new driver PTEs */
01735         TempPte = ValidKernelPte;
01736         while (PointerPte < LastPte)
01737         {
01738             /* Copy the old data */
01739             OldPte = *StartPte;
01740             ASSERT(OldPte.u.Hard.Valid == 1);
01741 
01742             /* Set page number from the loader's memory */
01743             TempPte.u.Hard.PageFrameNumber = OldPte.u.Hard.PageFrameNumber;
01744 
01745             /* Write it */
01746             MI_WRITE_VALID_PTE(PointerPte, TempPte);
01747 
01748             /* Move on */
01749             PointerPte++;
01750             StartPte++;
01751         }
01752 
01753         /* Update position */
01754         PointerPte -= PteCount;
01755 
01756         /* Sanity check */
01757         ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
01758 
01759         /* Set the image base to the address where the loader put it */
01760         NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
01761 
01762         /* Check if we had relocations */
01763         if (ValidRelocs)
01764         {
01765             /* Relocate the image */
01766             Status = LdrRelocateImageWithBias(NewImageAddress,
01767                                               0,
01768                                               "SYSLDR",
01769                                               STATUS_SUCCESS,
01770                                               STATUS_CONFLICTING_ADDRESSES,
01771                                               STATUS_INVALID_IMAGE_FORMAT);
01772             if (!NT_SUCCESS(Status))
01773             {
01774                 /* This shouldn't happen */
01775                 DPRINT1("Relocations failed!\n");
01776                 while (TRUE);
01777             }
01778         }
01779 
01780         /* Update the loader entry */
01781         LdrEntry->DllBase = NewImageAddress;
01782 
01783         /* Update the thunks */
01784         DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
01785         MiUpdateThunks(LoaderBlock,
01786                        DllBase,
01787                        NewImageAddress,
01788                        LdrEntry->SizeOfImage);
01789 
01790         /* Update the loader entry */
01791         LdrEntry->Flags |= LDRP_SYSTEM_MAPPED;
01792         LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
01793                                 NtHeader->OptionalHeader.AddressOfEntryPoint);
01794         LdrEntry->SizeOfImage = PteCount << PAGE_SHIFT;
01795 
01796         /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
01797     }
01798 }
01799 
01800 NTSTATUS
01801 NTAPI
01802 INIT_FUNCTION
01803 MiBuildImportsForBootDrivers(VOID)
01804 {
01805     PLIST_ENTRY NextEntry, NextEntry2;
01806     PLDR_DATA_TABLE_ENTRY LdrEntry, KernelEntry, HalEntry, LdrEntry2, LastEntry;
01807     PLDR_DATA_TABLE_ENTRY* EntryArray;
01808     UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
01809     UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
01810     PLOAD_IMPORTS LoadedImports;
01811     ULONG LoadedImportsSize, ImportSize;
01812     PULONG_PTR ImageThunk;
01813     ULONG_PTR DllBase, DllEnd;
01814     ULONG Modules = 0, i, j = 0;
01815     PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
01816 
01817     /* Initialize variables */
01818     KernelEntry = HalEntry = LastEntry = NULL;
01819 
01820     /* Loop the loaded module list... we are early enough that no lock is needed */
01821     NextEntry = PsLoadedModuleList.Flink;
01822     while (NextEntry != &PsLoadedModuleList)
01823     {
01824         /* Get the entry */
01825         LdrEntry = CONTAINING_RECORD(NextEntry,
01826                                      LDR_DATA_TABLE_ENTRY,
01827                                      InLoadOrderLinks);
01828 
01829         /* Check if it's the kernel or HAL */
01830         if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
01831         {
01832             /* Found it */
01833             KernelEntry = LdrEntry;
01834         }
01835         else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
01836         {
01837             /* Found it */
01838             HalEntry = LdrEntry;
01839         }
01840 
01841         /* Check if this is a driver DLL */
01842         if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
01843         {
01844             /* Check if this is the HAL or kernel */
01845             if ((LdrEntry == HalEntry) || (LdrEntry == KernelEntry))
01846             {
01847                 /* Add a reference */
01848                 LdrEntry->LoadCount = 1;
01849             }
01850             else
01851             {
01852                 /* No referencing needed */
01853                 LdrEntry->LoadCount = 0;
01854             }
01855         }
01856         else
01857         {
01858             /* No referencing needed */
01859             LdrEntry->LoadCount = 0;
01860         }
01861 
01862         /* Remember this came from the loader */
01863         LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
01864 
01865         /* Keep looping */
01866         NextEntry = NextEntry->Flink;
01867         Modules++;
01868     }
01869 
01870     /* We must have at least found the kernel and HAL */
01871     if (!(HalEntry) || (!KernelEntry)) return STATUS_NOT_FOUND;
01872 
01873     /* Allocate the list */
01874     EntryArray = ExAllocatePoolWithTag(PagedPool, Modules * sizeof(PVOID), TAG_LDR_IMPORTS);
01875     if (!EntryArray) return STATUS_INSUFFICIENT_RESOURCES;
01876 
01877     /* Loop the loaded module list again */
01878     NextEntry = PsLoadedModuleList.Flink;
01879     while (NextEntry != &PsLoadedModuleList)
01880     {
01881         /* Get the entry */
01882         LdrEntry = CONTAINING_RECORD(NextEntry,
01883                                      LDR_DATA_TABLE_ENTRY,
01884                                      InLoadOrderLinks);
01885 #ifdef _WORKING_LOADER_
01886         /* Get its imports */
01887         ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
01888                                                   TRUE,
01889                                                   IMAGE_DIRECTORY_ENTRY_IAT,
01890                                                   &ImportSize);
01891         if (!ImageThunk)
01892 #else
01893         /* Get its imports */
01894         ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
01895                                                         TRUE,
01896                                                         IMAGE_DIRECTORY_ENTRY_IMPORT,
01897                                                         &ImportSize);
01898         if (!ImportDescriptor)
01899 #endif
01900         {
01901             /* None present */
01902             LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
01903             NextEntry = NextEntry->Flink;
01904             continue;
01905         }
01906 
01907         /* Clear the list and count the number of IAT thunks */
01908         RtlZeroMemory(EntryArray, Modules * sizeof(PVOID));
01909 #ifdef _WORKING_LOADER_
01910         ImportSize /= sizeof(ULONG_PTR);
01911 
01912         /* Scan the thunks */
01913         for (i = 0, DllBase = 0, DllEnd = 0; i < ImportSize; i++, ImageThunk++)
01914 #else
01915         DllBase = DllEnd = i = 0;
01916         while ((ImportDescriptor->Name) &&
01917                (ImportDescriptor->OriginalFirstThunk))
01918         {
01919             /* Get the image thunk */
01920             ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
01921                                  ImportDescriptor->FirstThunk);
01922             while (*ImageThunk)
01923 #endif
01924             {
01925             /* Do we already have an address? */
01926             if (DllBase)
01927             {
01928                 /* Is the thunk in the same address? */
01929                 if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd))
01930                 {
01931                     /* Skip it, we already have a reference for it */
01932                     ASSERT(EntryArray[j]);
01933                     ImageThunk++;
01934                     continue;
01935                 }
01936             }
01937 
01938             /* Loop the loaded module list to locate this address owner */
01939             j = 0;
01940             NextEntry2 = PsLoadedModuleList.Flink;
01941             while (NextEntry2 != &PsLoadedModuleList)
01942             {
01943                 /* Get the entry */
01944                 LdrEntry2 = CONTAINING_RECORD(NextEntry2,
01945                                               LDR_DATA_TABLE_ENTRY,
01946                                               InLoadOrderLinks);
01947 
01948                 /* Get the address range for this module */
01949                 DllBase = (ULONG_PTR)LdrEntry2->DllBase;
01950                 DllEnd = DllBase + LdrEntry2->SizeOfImage;
01951 
01952                 /* Check if this IAT entry matches it */
01953                 if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd))
01954                 {
01955                     /* Save it */
01956                     //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
01957                     EntryArray[j] = LdrEntry2;
01958                     break;
01959                 }
01960 
01961                 /* Keep searching */
01962                 NextEntry2 = NextEntry2->Flink;
01963                 j++;
01964             }
01965 
01966             /* Do we have a thunk outside the range? */
01967             if ((*ImageThunk < DllBase) || (*ImageThunk >= DllEnd))
01968             {
01969                 /* Could be 0... */
01970                 if (*ImageThunk)
01971                 {
01972                     /* Should not be happening */
01973                     DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
01974                             LdrEntry, ImageThunk, *ImageThunk);
01975                     ASSERT(FALSE);
01976                 }
01977 
01978                 /* Reset if we hit this */
01979                 DllBase = 0;
01980             }
01981 #ifndef _WORKING_LOADER_
01982             ImageThunk++;
01983             }
01984 
01985             i++;
01986             ImportDescriptor++;
01987 #endif
01988         }
01989 
01990         /* Now scan how many imports we really have */
01991         for (i = 0, ImportSize = 0; i < Modules; i++)
01992         {
01993             /* Skip HAL and kernel */
01994             if ((EntryArray[i]) &&
01995                 (EntryArray[i] != HalEntry) &&
01996                 (EntryArray[i] != KernelEntry))
01997             {
01998                 /* A valid reference */
01999                 LastEntry = EntryArray[i];
02000                 ImportSize++;
02001             }
02002         }
02003 
02004         /* Do we have any imports after all? */
02005         if (!ImportSize)
02006         {
02007             /* No */
02008             LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
02009         }
02010         else if (ImportSize == 1)
02011         {
02012             /* A single entry import */
02013             LdrEntry->LoadedImports = (PVOID)((ULONG_PTR)LastEntry | MM_SYSLDR_SINGLE_ENTRY);
02014             LastEntry->LoadCount++;
02015         }
02016         else
02017         {
02018             /* We need an import table */
02019             LoadedImportsSize = ImportSize * sizeof(PVOID) + sizeof(SIZE_T);
02020             LoadedImports = ExAllocatePoolWithTag(PagedPool,
02021                                                   LoadedImportsSize,
02022                                                   TAG_LDR_IMPORTS);
02023             ASSERT(LoadedImports);
02024 
02025             /* Save the count */
02026             LoadedImports->Count = ImportSize;
02027 
02028             /* Now copy all imports */
02029             for (i = 0, j = 0; i < Modules; i++)
02030             {
02031                 /* Skip HAL and kernel */
02032                 if ((EntryArray[i]) &&
02033                     (EntryArray[i] != HalEntry) &&
02034                     (EntryArray[i] != KernelEntry))
02035                 {
02036                     /* A valid reference */
02037                     //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
02038                     LoadedImports->Entry[j] = EntryArray[i];
02039                     EntryArray[i]->LoadCount++;
02040                     j++;
02041                 }
02042             }
02043 
02044             /* Should had as many entries as we expected */
02045             ASSERT(j == ImportSize);
02046             LdrEntry->LoadedImports = LoadedImports;
02047         }
02048 
02049         /* Next */
02050         NextEntry = NextEntry->Flink;
02051     }
02052 
02053     /* Free the initial array */
02054     ExFreePoolWithTag(EntryArray, TAG_LDR_IMPORTS);
02055 
02056     /* FIXME: Might not need to keep the HAL/Kernel imports around */
02057 
02058     /* Kernel and HAL are loaded at boot */
02059     KernelEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
02060     HalEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
02061 
02062     /* All worked well */
02063     return STATUS_SUCCESS;
02064 }
02065 
02066 VOID
02067 NTAPI
02068 INIT_FUNCTION
02069 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
02070 {
02071     ULONG_PTR DllBase;
02072     PIMAGE_NT_HEADERS NtHeaders;
02073     PIMAGE_SECTION_HEADER SectionHeader;
02074     ULONG Sections, Size;
02075 
02076     /* Get the kernel section header */
02077     DllBase = (ULONG_PTR)LdrEntry->DllBase;
02078     NtHeaders = RtlImageNtHeader((PVOID)DllBase);
02079     SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
02080 
02081     /* Loop all the sections */
02082     Sections = NtHeaders->FileHeader.NumberOfSections;
02083     while (Sections)
02084     {
02085         /* Grab the size of the section */
02086         Size = max(SectionHeader->SizeOfRawData, SectionHeader->Misc.VirtualSize);
02087 
02088         /* Check for .RSRC section */
02089         if (*(PULONG)SectionHeader->Name == 'rsr.')
02090         {
02091             /* Remember the PTEs so we can modify them later */
02092             MiKernelResourceStartPte = MiAddressToPte(DllBase +
02093                                                       SectionHeader->VirtualAddress);
02094             MiKernelResourceEndPte = MiKernelResourceStartPte +
02095                                      BYTES_TO_PAGES(SectionHeader->VirtualAddress + Size);
02096         }
02097         else if (*(PULONG)SectionHeader->Name == 'LOOP')
02098         {
02099             /* POOLCODE vs. POOLMI */
02100             if (*(PULONG)&SectionHeader->Name[4] == 'EDOC')
02101             {
02102                 /* Found Ex* Pool code */
02103                 ExPoolCodeStart = DllBase + SectionHeader->VirtualAddress;
02104                 ExPoolCodeEnd = ExPoolCodeStart + Size;
02105             }
02106             else if (*(PUSHORT)&SectionHeader->Name[4] == 'MI')
02107             {
02108                 /* Found Mm* Pool code */
02109                 MmPoolCodeStart = DllBase + SectionHeader->VirtualAddress;
02110                 MmPoolCodeEnd = ExPoolCodeStart + Size;
02111             }
02112         }
02113         else if ((*(PULONG)SectionHeader->Name == 'YSIM') &&
02114                  (*(PULONG)&SectionHeader->Name[4] == 'ETPS'))
02115         {
02116             /* Found MISYSPTE (Mm System PTE code)*/
02117             MmPteCodeStart = DllBase + SectionHeader->VirtualAddress;
02118             MmPteCodeEnd = ExPoolCodeStart + Size;
02119         }
02120 
02121         /* Keep going */
02122         Sections--;
02123         SectionHeader++;
02124     }
02125 }
02126 
02127 BOOLEAN
02128 NTAPI
02129 INIT_FUNCTION
02130 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
02131 {
02132     PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
02133     PLIST_ENTRY ListHead, NextEntry;
02134     ULONG EntrySize;
02135 
02136     /* Setup the loaded module list and locks */
02137     ExInitializeResourceLite(&PsLoadedModuleResource);
02138     KeInitializeSpinLock(&PsLoadedModuleSpinLock);
02139     InitializeListHead(&PsLoadedModuleList);
02140 
02141     /* Get loop variables and the kernel entry */
02142     ListHead = &LoaderBlock->LoadOrderListHead;
02143     NextEntry = ListHead->Flink;
02144     LdrEntry = CONTAINING_RECORD(NextEntry,
02145                                  LDR_DATA_TABLE_ENTRY,
02146                                  InLoadOrderLinks);
02147     PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
02148 
02149     /* Locate resource section, pool code, and system pte code */
02150     MiLocateKernelSections(LdrEntry);
02151 
02152     /* Loop the loader block */
02153     while (NextEntry != ListHead)
02154     {
02155         /* Get the loader entry */
02156         LdrEntry = CONTAINING_RECORD(NextEntry,
02157                                      LDR_DATA_TABLE_ENTRY,
02158                                      InLoadOrderLinks);
02159 
02160         /* FIXME: ROS HACK. Make sure this is a driver */
02161         if (!RtlImageNtHeader(LdrEntry->DllBase))
02162         {
02163             /* Skip this entry */
02164             NextEntry = NextEntry->Flink;
02165             continue;
02166         }
02167 
02168         /* Calculate the size we'll need and allocate a copy */
02169         EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
02170                     LdrEntry->BaseDllName.MaximumLength +
02171                     sizeof(UNICODE_NULL);
02172         NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
02173         if (!NewEntry) return FALSE;
02174 
02175         /* Copy the entry over */
02176         *NewEntry = *LdrEntry;
02177 
02178         /* Allocate the name */
02179         NewEntry->FullDllName.Buffer =
02180             ExAllocatePoolWithTag(PagedPool,
02181                                   LdrEntry->FullDllName.MaximumLength +
02182                                   sizeof(UNICODE_NULL),
02183                                   TAG_LDR_WSTR);
02184         if (!NewEntry->FullDllName.Buffer) return FALSE;
02185 
02186         /* Set the base name */
02187         NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
02188 
02189         /* Copy the full and base name */
02190         RtlCopyMemory(NewEntry->FullDllName.Buffer,
02191                       LdrEntry->FullDllName.Buffer,
02192                       LdrEntry->FullDllName.MaximumLength);
02193         RtlCopyMemory(NewEntry->BaseDllName.Buffer,
02194                       LdrEntry->BaseDllName.Buffer,
02195                       LdrEntry->BaseDllName.MaximumLength);
02196 
02197         /* Null-terminate the base name */
02198         NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
02199                                      sizeof(WCHAR)] = UNICODE_NULL;
02200 
02201         /* Insert the entry into the list */
02202         InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
02203         NextEntry = NextEntry->Flink;
02204     }
02205 
02206     /* Build the import lists for the boot drivers */
02207     MiBuildImportsForBootDrivers();
02208 
02209     /* We're done */
02210     return TRUE;
02211 }
02212 
02213 LOGICAL
02214 NTAPI
02215 MiUseLargeDriverPage(IN ULONG NumberOfPtes,
02216                      IN OUT PVOID *ImageBaseAddress,
02217                      IN PUNICODE_STRING BaseImageName,
02218                      IN BOOLEAN BootDriver)
02219 {
02220     PLIST_ENTRY NextEntry;
02221     BOOLEAN DriverFound = FALSE;
02222     PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry;
02223     ASSERT(KeGetCurrentIrql () <= APC_LEVEL);
02224     ASSERT(*ImageBaseAddress >= MmSystemRangeStart);
02225 
02226 #ifdef _X86_
02227     if (!(KeFeatureBits & KF_LARGE_PAGE)) return FALSE;
02228     if (!(__readcr4() & CR4_PSE)) return FALSE;
02229 #endif
02230 
02231     /* Make sure there's enough system PTEs for a large page driver */
02232     if (MmTotalFreeSystemPtes[SystemPteSpace] < (16 * (PDE_MAPPED_VA >> PAGE_SHIFT)))
02233     {
02234         return FALSE;
02235     }
02236 
02237     /* This happens if the registry key had a "*" (wildcard) in it */
02238     if (MiLargePageAllDrivers == 0)
02239     {
02240         /* It didn't, so scan the list */
02241         NextEntry = MiLargePageDriverList.Flink;
02242         while (NextEntry != &MiLargePageDriverList)
02243         {
02244             /* Check if the driver name matches */
02245             LargePageDriverEntry = CONTAINING_RECORD(NextEntry,
02246                                                      MI_LARGE_PAGE_DRIVER_ENTRY,
02247                                                      Links);
02248             if (RtlEqualUnicodeString(BaseImageName,
02249                                       &LargePageDriverEntry->BaseName,
02250                                       TRUE))
02251             {
02252                 /* Enable large pages for this driver */
02253                 DriverFound = TRUE;
02254                 break;
02255             }
02256 
02257             /* Keep trying */
02258             NextEntry = NextEntry->Flink;
02259         }
02260 
02261         /* If we didn't find the driver, it doesn't need large pages */
02262         if (DriverFound == FALSE) return FALSE;
02263     }
02264 
02265     /* Nothing to do yet */
02266     DPRINT1("Large pages not supported!\n");
02267     return FALSE;
02268 }
02269 
02270 ULONG
02271 NTAPI
02272 MiComputeDriverProtection(IN BOOLEAN SessionSpace,
02273                           IN ULONG SectionProtection)
02274 {
02275     ULONG Protection = MM_ZERO_ACCESS;
02276 
02277     /* Check if the caller gave anything */
02278     if (SectionProtection)
02279     {
02280         /* Always turn on execute access */
02281         SectionProtection |= IMAGE_SCN_MEM_EXECUTE;
02282 
02283         /* Check if the registry setting is on or not */
02284         if (!MmEnforceWriteProtection)
02285         {
02286             /* Turn on write access too */
02287             SectionProtection |= (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE);
02288         }
02289     }
02290 
02291     /* Convert to internal PTE flags */
02292     if (SectionProtection & IMAGE_SCN_MEM_EXECUTE) Protection |= MM_EXECUTE;
02293     if (SectionProtection & IMAGE_SCN_MEM_READ) Protection |= MM_READONLY;
02294 
02295     /* Check for write access */
02296     if (SectionProtection & IMAGE_SCN_MEM_WRITE)
02297     {
02298         /* Session space is not supported */
02299         if (SessionSpace)
02300         {
02301             DPRINT1("Session drivers not supported\n");
02302             ASSERT(SessionSpace == FALSE);
02303         }
02304         else
02305         {
02306             /* Convert to internal PTE flag */
02307             Protection = (Protection & MM_EXECUTE) ? MM_EXECUTE_READWRITE : MM_READWRITE;
02308         }
02309     }
02310 
02311     /* If there's no access at all by now, convert to internal no access flag */
02312     if (Protection == MM_ZERO_ACCESS) Protection = MM_NOACCESS;
02313 
02314     /* Return the computed PTE protection */
02315     return Protection;
02316 }
02317 
02318 VOID
02319 NTAPI
02320 MiSetSystemCodeProtection(IN PMMPTE FirstPte,
02321                           IN PMMPTE LastPte,
02322                           IN ULONG ProtectionMask)
02323 {
02324     /* I'm afraid to introduce regressions at the moment... */
02325     return;
02326 }
02327 
02328 VOID
02329 NTAPI
02330 MiWriteProtectSystemImage(IN PVOID ImageBase)
02331 {
02332     PIMAGE_NT_HEADERS NtHeaders;
02333     PIMAGE_SECTION_HEADER Section;
02334     PFN_NUMBER DriverPages;
02335     ULONG CurrentProtection, SectionProtection, CombinedProtection = 0, ProtectionMask;
02336     ULONG Sections, Size;
02337     ULONG_PTR BaseAddress, CurrentAddress;
02338     PMMPTE PointerPte, StartPte, LastPte, CurrentPte, ComboPte = NULL;
02339     ULONG CurrentMask, CombinedMask = 0;
02340     PAGED_CODE();
02341 
02342     /* No need to write protect physical memory-backed drivers (large pages) */
02343     if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return;
02344 
02345     /* Get the image headers */
02346     NtHeaders = RtlImageNtHeader(ImageBase);
02347     if (!NtHeaders) return;
02348 
02349     /* Check if this is a session driver or not */
02350     if (!MI_IS_SESSION_ADDRESS(ImageBase))
02351     {
02352         /* Don't touch NT4 drivers */
02353         if (NtHeaders->OptionalHeader.MajorOperatingSystemVersion < 5) return;
02354         if (NtHeaders->OptionalHeader.MajorImageVersion < 5) return;
02355     }
02356     else
02357     {
02358         /* Not supported */
02359         DPRINT1("Session drivers not supported\n");
02360         ASSERT(FALSE);
02361     }
02362 
02363     /* These are the only protection masks we care about */
02364     ProtectionMask = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
02365 
02366     /* Calculate the number of pages this driver is occupying */
02367     DriverPages = BYTES_TO_PAGES(NtHeaders->OptionalHeader.SizeOfImage);
02368 
02369     /* Get the number of sections and the first section header */
02370     Sections = NtHeaders->FileHeader.NumberOfSections;
02371     ASSERT(Sections != 0);
02372     Section = IMAGE_FIRST_SECTION(NtHeaders);
02373 
02374     /* Loop all the sections */
02375     CurrentAddress = (ULONG_PTR)ImageBase;
02376     while (Sections)
02377     {
02378         /* Get the section size */
02379         Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
02380 
02381         /* Get its virtual address */
02382         BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress;
02383         if (BaseAddress < CurrentAddress)
02384         {
02385             /* Windows doesn't like these */
02386             DPRINT1("Badly linked image!\n");
02387             return;
02388         }
02389 
02390         /* Remember the current address */
02391         CurrentAddress = BaseAddress + Size - 1;
02392 
02393         /* Next */
02394         Sections--;
02395         Section++;
02396     }
02397 
02398     /* Get the number of sections and the first section header */
02399     Sections = NtHeaders->FileHeader.NumberOfSections;
02400     ASSERT(Sections != 0);
02401     Section = IMAGE_FIRST_SECTION(NtHeaders);
02402 
02403     /* Set the address at the end to initialize the loop */
02404     CurrentAddress = (ULONG_PTR)Section + Sections - 1;
02405     CurrentProtection = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
02406 
02407     /* Set the PTE points for the image, and loop its sections */
02408     StartPte = MiAddressToPte(ImageBase);
02409     LastPte = StartPte + DriverPages;
02410     while (Sections)
02411     {
02412         /* Get the section size */
02413         Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
02414 
02415         /* Get its virtual address and PTE */
02416         BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress;
02417         PointerPte = MiAddressToPte(BaseAddress);
02418 
02419         /* Check if we were already protecting a run, and found a new run */
02420         if ((ComboPte) && (PointerPte > ComboPte))
02421         {
02422             /* Compute protection */
02423             CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection);
02424 
02425             /* Set it */
02426             MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask);
02427 
02428             /* Check for overlap */
02429             if (ComboPte == StartPte) StartPte++;
02430 
02431             /* One done, reset variables */
02432             ComboPte = NULL;
02433             CombinedProtection = 0;
02434         }
02435 
02436         /* Break out when needed */
02437         if (PointerPte >= LastPte) break;
02438 
02439         /* Get the requested protection from the image header */
02440         SectionProtection = Section->Characteristics & ProtectionMask;
02441         if (SectionProtection == CurrentProtection)
02442         {
02443             /* Same protection, so merge the request */
02444             CurrentAddress = BaseAddress + Size - 1;
02445 
02446             /* Next */
02447             Sections--;
02448             Section++;
02449             continue;
02450         }
02451 
02452         /* This is now a new section, so close up the old one */
02453         CurrentPte = MiAddressToPte(CurrentAddress);
02454 
02455         /* Check for overlap */
02456         if (CurrentPte == PointerPte)
02457         {
02458             /* Skip the last PTE, since it overlaps with us */
02459             CurrentPte--;
02460 
02461             /* And set the PTE we will merge with */
02462             ASSERT((ComboPte == NULL) || (ComboPte == PointerPte));
02463             ComboPte = PointerPte;
02464 
02465             /* Get the most flexible protection by merging both */
02466             CombinedMask |= (SectionProtection | CurrentProtection);
02467         }
02468 
02469         /* Loop any PTEs left */
02470         if (CurrentPte >= StartPte)
02471         {
02472             /* Sanity check */
02473             ASSERT(StartPte < LastPte);
02474 
02475             /* Make sure we don't overflow past the last PTE in the driver */
02476             if (CurrentPte >= LastPte) CurrentPte = LastPte - 1;
02477             ASSERT(CurrentPte >= StartPte);
02478 
02479             /* Compute the protection and set it */
02480             CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection);
02481             MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask);
02482         }
02483 
02484         /* Set new state */
02485         StartPte = PointerPte;
02486         CurrentAddress = BaseAddress + Size - 1;
02487         CurrentProtection = SectionProtection;
02488 
02489         /* Next */
02490         Sections--;
02491         Section++;
02492     }
02493 
02494     /* Is there a leftover section to merge? */
02495     if (ComboPte)
02496     {
02497         /* Compute and set the protection */
02498         CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection);
02499         MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask);
02500 
02501         /* Handle overlap */
02502         if (ComboPte == StartPte) StartPte++;
02503     }
02504 
02505     /* Finally, handle the last section */
02506     CurrentPte = MiAddressToPte(CurrentAddress);
02507     if ((StartPte < LastPte) && (CurrentPte >= StartPte))
02508     {
02509         /* Handle overlap */
02510         if (CurrentPte >= LastPte) CurrentPte = LastPte - 1;
02511         ASSERT(CurrentPte >= StartPte);
02512 
02513         /* Compute and set the protection */
02514         CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection);
02515         MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask);
02516     }
02517 }
02518 
02519 VOID
02520 NTAPI
02521 MiSetPagingOfDriver(IN PMMPTE PointerPte,
02522                     IN PMMPTE LastPte)
02523 {
02524     PVOID ImageBase;
02525     PETHREAD CurrentThread = PsGetCurrentThread();
02526     PFN_COUNT PageCount = 0;
02527     PFN_NUMBER PageFrameIndex;
02528     PMMPFN Pfn1;
02529     PAGED_CODE();
02530 
02531     /* Get the driver's base address */
02532     ImageBase = MiPteToAddress(PointerPte);
02533     ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase) == FALSE);
02534 
02535     /* If this is a large page, it's stuck in physical memory */
02536     if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return;
02537 
02538     /* Lock the working set */
02539     MiLockWorkingSet(CurrentThread, &MmSystemCacheWs);
02540 
02541     /* Loop the PTEs */
02542     while (PointerPte <= LastPte)
02543     {
02544         /* Check for valid PTE */
02545         if (PointerPte->u.Hard.Valid == 1)
02546         {
02547             PageFrameIndex = PFN_FROM_PTE(PointerPte);
02548             Pfn1 = MiGetPfnEntry(PageFrameIndex);
02549             ASSERT(Pfn1->u2.ShareCount == 1);
02550 
02551             /* No working sets in ReactOS yet */
02552             PageCount++;
02553         }
02554 
02555         ImageBase = (PVOID)((ULONG_PTR)ImageBase + PAGE_SIZE);
02556         PointerPte++;
02557     }
02558 
02559     /* Release the working set */
02560     MiUnlockWorkingSet(CurrentThread, &MmSystemCacheWs);
02561 
02562     /* Do we have any driver pages? */
02563     if (PageCount)
02564     {
02565         /* Update counters */
02566         InterlockedExchangeAdd((PLONG)&MmTotalSystemDriverPages, PageCount);
02567     }
02568 }
02569 
02570 VOID
02571 NTAPI
02572 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
02573 {
02574     ULONG_PTR ImageBase;
02575     PIMAGE_NT_HEADERS NtHeaders;
02576     ULONG Sections, Alignment, Size;
02577     PIMAGE_SECTION_HEADER Section;
02578     PMMPTE PointerPte = NULL, LastPte = NULL;
02579     if (MmDisablePagingExecutive) return;
02580 
02581     /* Get the driver base address and its NT header */
02582     ImageBase = (ULONG_PTR)LdrEntry->DllBase;
02583     NtHeaders = RtlImageNtHeader((PVOID)ImageBase);
02584     if (!NtHeaders) return;
02585 
02586     /* Get the sections and their alignment */
02587     Sections = NtHeaders->FileHeader.NumberOfSections;
02588     Alignment = NtHeaders->OptionalHeader.SectionAlignment - 1;
02589 
02590     /* Loop each section */
02591     Section = IMAGE_FIRST_SECTION(NtHeaders);
02592     while (Sections)
02593     {
02594         /* Find PAGE or .edata */
02595         if ((*(PULONG)Section->Name == 'EGAP') ||
02596             (*(PULONG)Section->Name == 'ade.'))
02597         {
02598             /* Had we already done some work? */
02599             if (!PointerPte)
02600             {
02601                 /* Nope, setup the first PTE address */
02602                 PointerPte = MiAddressToPte(ROUND_TO_PAGES(ImageBase +
02603                                                            Section->
02604                                                            VirtualAddress));
02605             }
02606 
02607             /* Compute the size */
02608             Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
02609 
02610             /* Find the last PTE that maps this section */
02611             LastPte = MiAddressToPte(ImageBase +
02612                                      Section->VirtualAddress +
02613                                      Alignment +
02614                                      Size -
02615                                      PAGE_SIZE);
02616         }
02617         else
02618         {
02619             /* Had we found a section before? */
02620             if (PointerPte)
02621             {
02622                 /* Mark it as pageable */
02623                 MiSetPagingOfDriver(PointerPte, LastPte);
02624                 PointerPte = NULL;
02625             }
02626         }
02627 
02628         /* Keep searching */
02629         Sections--;
02630         Section++;
02631     }
02632 
02633     /* Handle the straggler */
02634     if (PointerPte) MiSetPagingOfDriver(PointerPte, LastPte);
02635 }
02636 
02637 BOOLEAN
02638 NTAPI
02639 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)
02640 {
02641     PIMAGE_NT_HEADERS NtHeader;
02642     PAGED_CODE();
02643 
02644     /* Get NT Headers */
02645     NtHeader = RtlImageNtHeader(BaseAddress);
02646     if (NtHeader)
02647     {
02648         /* Check if this image is only safe for UP while we have 2+ CPUs */
02649         if ((KeNumberProcessors > 1) &&
02650             (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))
02651         {
02652             /* Fail */
02653             return FALSE;
02654         }
02655     }
02656 
02657     /* Otherwise, it's safe */
02658     return TRUE;
02659 }
02660 
02661 NTSTATUS
02662 NTAPI
02663 MmCheckSystemImage(IN HANDLE ImageHandle,
02664                    IN BOOLEAN PurgeSection)
02665 {
02666     NTSTATUS Status;
02667     HANDLE SectionHandle;
02668     PVOID ViewBase = NULL;
02669     SIZE_T ViewSize = 0;
02670     IO_STATUS_BLOCK IoStatusBlock;
02671     FILE_STANDARD_INFORMATION FileStandardInfo;
02672     KAPC_STATE ApcState;
02673     PIMAGE_NT_HEADERS NtHeaders;
02674     OBJECT_ATTRIBUTES ObjectAttributes;
02675     PAGED_CODE();
02676 
02677     /* Setup the object attributes */
02678     InitializeObjectAttributes(&ObjectAttributes,
02679                                NULL,
02680                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
02681                                NULL,
02682                                NULL);
02683 
02684     /* Create a section for the DLL */
02685     Status = ZwCreateSection(&SectionHandle,
02686                              SECTION_MAP_EXECUTE,
02687                              &ObjectAttributes,
02688                              NULL,
02689                              PAGE_EXECUTE,
02690                              SEC_IMAGE,
02691                              ImageHandle);
02692     if (!NT_SUCCESS(Status))
02693     {
02694         DPRINT1("ZwCreateSection failed with status 0x%x\n", Status);
02695         return Status;
02696     }
02697 
02698     /* Make sure we're in the system process */
02699     KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
02700 
02701     /* Map it */
02702     Status = ZwMapViewOfSection(SectionHandle,
02703                                 NtCurrentProcess(),
02704                                 &ViewBase,
02705                                 0,
02706                                 0,
02707                                 NULL,
02708                                 &ViewSize,
02709                                 ViewShare,
02710                                 0,
02711                                 PAGE_EXECUTE);
02712     if (!NT_SUCCESS(Status))
02713     {
02714         /* We failed, close the handle and return */
02715         DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status);
02716         KeUnstackDetachProcess(&ApcState);
02717         ZwClose(SectionHandle);
02718         return Status;
02719     }
02720 
02721     /* Now query image information */
02722     Status = ZwQueryInformationFile(ImageHandle,
02723                                     &IoStatusBlock,
02724                                     &FileStandardInfo,
02725                                     sizeof(FileStandardInfo),
02726                                     FileStandardInformation);
02727     if (NT_SUCCESS(Status))
02728     {
02729         /* First, verify the checksum */
02730         if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,
02731                                                  ViewSize,
02732                                                  FileStandardInfo.
02733                                                  EndOfFile.LowPart))
02734         {
02735             /* Set checksum failure */
02736             Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
02737             goto Fail;
02738         }
02739 
02740         /* Make sure it's a real image */
02741         NtHeaders = RtlImageNtHeader(ViewBase);
02742         if (!NtHeaders)
02743         {
02744             /* Set checksum failure */
02745             Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
02746             goto Fail;
02747         }
02748 
02749         /* Make sure it's for the correct architecture */
02750         if ((NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_NATIVE) ||
02751             (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC))
02752         {
02753             /* Set protection failure */
02754             Status = STATUS_INVALID_IMAGE_PROTECT;
02755             goto Fail;
02756         }
02757 
02758         /* Check that it's a valid SMP image if we have more then one CPU */
02759         if (!MmVerifyImageIsOkForMpUse(ViewBase))
02760         {
02761             /* Otherwise it's not the right image */
02762             Status = STATUS_IMAGE_MP_UP_MISMATCH;
02763         }
02764     }
02765 
02766     /* Unmap the section, close the handle, and return status */
02767 Fail:
02768     ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);
02769     KeUnstackDetachProcess(&ApcState);
02770     ZwClose(SectionHandle);
02771     return Status;
02772 }
02773 
02774 NTSTATUS
02775 NTAPI
02776 MmLoadSystemImage(IN PUNICODE_STRING FileName,
02777                   IN PUNICODE_STRING NamePrefix OPTIONAL,
02778                   IN PUNICODE_STRING LoadedName OPTIONAL,
02779                   IN ULONG Flags,
02780                   OUT PVOID *ModuleObject,
02781                   OUT PVOID *ImageBaseAddress)
02782 {
02783     PVOID ModuleLoadBase = NULL;
02784     NTSTATUS Status;
02785     HANDLE FileHandle = NULL;
02786     OBJECT_ATTRIBUTES ObjectAttributes;
02787     IO_STATUS_BLOCK IoStatusBlock;
02788     PIMAGE_NT_HEADERS NtHeader;
02789     UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;
02790     PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
02791     ULONG EntrySize, DriverSize;
02792     PLOAD_IMPORTS LoadedImports = MM_SYSLDR_NO_IMPORTS;
02793     PCHAR MissingApiName, Buffer;
02794     PWCHAR MissingDriverName;
02795     HANDLE SectionHandle;
02796     ACCESS_MASK DesiredAccess;
02797     PVOID Section = NULL;
02798     BOOLEAN LockOwned = FALSE;
02799     PLIST_ENTRY NextEntry;
02800     IMAGE_INFO ImageInfo;
02801     STRING AnsiTemp;
02802     PAGED_CODE();
02803 
02804     /* Detect session-load */
02805     if (Flags)
02806     {
02807         /* Sanity checks */
02808         ASSERT(NamePrefix == NULL);
02809         ASSERT(LoadedName == NULL);
02810 
02811         /* Make sure the process is in session too */
02812         if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
02813     }
02814 
02815     /* Allocate a buffer we'll use for names */
02816     Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
02817     if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
02818 
02819     /* Check for a separator */
02820     if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
02821     {
02822         PWCHAR p;
02823         ULONG BaseLength;
02824 
02825         /* Loop the path until we get to the base name */
02826         p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
02827         while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
02828 
02829         /* Get the length */
02830         BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
02831         BaseLength *= sizeof(WCHAR);
02832 
02833         /* Setup the string */
02834         BaseName.Length = (USHORT)BaseLength;
02835         BaseName.Buffer = p;
02836     }
02837     else
02838     {
02839         /* Otherwise, we already have a base name */
02840         BaseName.Length = FileName->Length;
02841         BaseName.Buffer = FileName->Buffer;
02842     }
02843 
02844     /* Setup the maximum length */
02845     BaseName.MaximumLength = BaseName.Length;
02846 
02847     /* Now compute the base directory */
02848     BaseDirectory = *FileName;
02849     BaseDirectory.Length -= BaseName.Length;
02850     BaseDirectory.MaximumLength = BaseDirectory.Length;
02851 
02852     /* And the prefix, which for now is just the name itself */
02853     PrefixName = *FileName;
02854 
02855     /* Check if we have a prefix */
02856     if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");
02857 
02858     /* Check if we already have a name, use it instead */
02859     if (LoadedName) BaseName = *LoadedName;
02860 
02861     /* Check for loader snap debugging */
02862     if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS)
02863     {
02864         /* Print out standard string */
02865         DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
02866                 &PrefixName, &BaseName, Flags ? "in session space" : "");
02867     }
02868 
02869     /* Acquire the load lock */
02870 LoaderScan:
02871     ASSERT(LockOwned == FALSE);
02872     LockOwned = TRUE;
02873     KeEnterCriticalRegion();
02874     KeWaitForSingleObject(&MmSystemLoadLock,
02875                           WrVirtualMemory,
02876                           KernelMode,
02877                           FALSE,
02878                           NULL);
02879 
02880     /* Scan the module list */
02881     NextEntry = PsLoadedModuleList.Flink;
02882     while (NextEntry != &PsLoadedModuleList)
02883     {
02884         /* Get the entry and compare the names */
02885         LdrEntry = CONTAINING_RECORD(NextEntry,
02886                                      LDR_DATA_TABLE_ENTRY,
02887                                      InLoadOrderLinks);
02888         if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))
02889         {
02890             /* Found it, break out */
02891             break;
02892         }
02893 
02894         /* Keep scanning */
02895         NextEntry = NextEntry->Flink;
02896     }
02897 
02898     /* Check if we found the image */
02899     if (NextEntry != &PsLoadedModuleList)
02900     {
02901         /* Check if we had already mapped a section */
02902         if (Section)
02903         {
02904             /* Dereference and clear */
02905             ObDereferenceObject(Section);
02906             Section = NULL;
02907         }
02908 
02909         /* Check if this was supposed to be a session load */
02910         if (!Flags)
02911         {
02912             /* It wasn't, so just return the data */
02913             *ModuleObject = LdrEntry;
02914             *ImageBaseAddress = LdrEntry->DllBase;
02915             Status = STATUS_IMAGE_ALREADY_LOADED;
02916         }
02917         else
02918         {
02919             /* We don't support session loading yet */
02920             DPRINT1("Unsupported Session-Load!\n");
02921             while (TRUE);
02922         }
02923 
02924         /* Do cleanup */
02925         goto Quickie;
02926     }
02927     else if (!Section)
02928     {
02929         /* It wasn't loaded, and we didn't have a previous attempt */
02930         KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
02931         KeLeaveCriticalRegion();
02932         LockOwned = FALSE;
02933 
02934         /* Check if KD is enabled */
02935         if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))
02936         {
02937             /* FIXME: Attempt to get image from KD */
02938         }
02939 
02940         /* We don't have a valid entry */
02941         LdrEntry = NULL;
02942 
02943         /* Setup image attributes */
02944         InitializeObjectAttributes(&ObjectAttributes,
02945                                    FileName,
02946                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
02947                                    NULL,
02948                                    NULL);
02949 
02950         /* Open the image */
02951         Status = ZwOpenFile(&FileHandle,
02952                             FILE_EXECUTE,
02953                             &ObjectAttributes,
02954                             &IoStatusBlock,
02955                             FILE_SHARE_READ | FILE_SHARE_DELETE,
02956                             0);
02957         if (!NT_SUCCESS(Status))
02958         {
02959             DPRINT1("ZwOpenFile failed with status 0x%x\n", Status);
02960             goto Quickie;
02961         }
02962 
02963         /* Validate it */
02964         Status = MmCheckSystemImage(FileHandle, FALSE);
02965         if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||
02966             (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||
02967             (Status == STATUS_INVALID_IMAGE_PROTECT))
02968         {
02969             /* Fail loading */
02970             goto Quickie;
02971         }
02972 
02973         /* Check if this is a session-load */
02974         if (Flags)
02975         {
02976             /* Then we only need read and execute */
02977             DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;
02978         }
02979         else
02980         {
02981             /* Otherwise, we can allow write access */
02982             DesiredAccess = SECTION_ALL_ACCESS;
02983         }
02984 
02985         /* Initialize the attributes for the section */
02986         InitializeObjectAttributes(&ObjectAttributes,
02987                                    NULL,
02988                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
02989                                    NULL,
02990                                    NULL);
02991 
02992         /* Create the section */
02993         Status = ZwCreateSection(&SectionHandle,
02994                                  DesiredAccess,
02995                                  &ObjectAttributes,
02996                                  NULL,
02997                                  PAGE_EXECUTE,
02998                                  SEC_IMAGE,
02999                                  FileHandle);
03000         if (!NT_SUCCESS(Status))
03001         {
03002             DPRINT1("ZwCreateSection failed with status 0x%x\n", Status);
03003             goto Quickie;
03004         }
03005 
03006         /* Now get the section pointer */
03007         Status = ObReferenceObjectByHandle(SectionHandle,
03008                                            SECTION_MAP_EXECUTE,
03009                                            MmSectionObjectType,
03010                                            KernelMode,
03011                                            &Section,
03012                                            NULL);
03013         ZwClose(SectionHandle);
03014         if (!NT_SUCCESS(Status)) goto Quickie;
03015 
03016         /* Check if this was supposed to be a session-load */
03017         if (Flags)
03018         {
03019             /* We don't support session loading yet */
03020             DPRINT1("Unsupported Session-Load!\n");
03021             while (TRUE);
03022         }
03023 
03024         /* Check the loader list again, we should end up in the path below */
03025         goto LoaderScan;
03026     }
03027     else
03028     {
03029         /* We don't have a valid entry */
03030         LdrEntry = NULL;
03031     }
03032 
03033     /* Load the image */
03034     Status = MiLoadImageSection(&Section,
03035                                 &ModuleLoadBase,
03036                                 FileName,
03037                                 FALSE,
03038                                 NULL);
03039     ASSERT(Status != STATUS_ALREADY_COMMITTED);
03040 
03041     /* Get the size of the driver */
03042     DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
03043 
03044     /* Make sure we're not being loaded into session space */
03045     if (!Flags)
03046     {
03047         /* Check for success */
03048         if (NT_SUCCESS(Status))
03049         {
03050             /* Support large pages for drivers */
03051             MiUseLargeDriverPage(DriverSize / PAGE_SIZE,
03052                                  &ModuleLoadBase,
03053                                  &BaseName,
03054                                  TRUE);
03055         }
03056 
03057         /* Dereference the section */
03058         ObDereferenceObject(Section);
03059         Section = NULL;
03060     }
03061 
03062     /* Check for failure of the load earlier */
03063     if (!NT_SUCCESS(Status))
03064     {
03065         DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status);
03066         goto Quickie;
03067     }
03068 
03069     /* Relocate the driver */
03070     Status = LdrRelocateImageWithBias(ModuleLoadBase,
03071                                       0,
03072                                       "SYSLDR",
03073                                       STATUS_SUCCESS,
03074                                       STATUS_CONFLICTING_ADDRESSES,
03075                                       STATUS_INVALID_IMAGE_FORMAT);
03076     if (!NT_SUCCESS(Status))
03077     {
03078         DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status);
03079         goto Quickie;
03080     }
03081 
03082     /* Get the NT Header */
03083     NtHeader = RtlImageNtHeader(ModuleLoadBase);
03084 
03085     /* Calculate the size we'll need for the entry and allocate it */
03086     EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
03087                 BaseName.Length +
03088                 sizeof(UNICODE_NULL);
03089 
03090     /* Allocate the entry */
03091     LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
03092     if (!LdrEntry)
03093     {
03094         /* Fail */
03095         Status = STATUS_INSUFFICIENT_RESOURCES;
03096         goto Quickie;
03097     }
03098 
03099     /* Setup the entry */
03100     LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
03101     LdrEntry->LoadCount = 1;
03102     LdrEntry->LoadedImports = LoadedImports;
03103     LdrEntry->PatchInformation = NULL;
03104 
03105     /* Check the version */
03106     if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
03107         (NtHeader->OptionalHeader.MajorImageVersion >= 5))
03108     {
03109         /* Mark this image as a native image */
03110         LdrEntry->Flags |= LDRP_ENTRY_NATIVE;
03111     }
03112 
03113     /* Setup the rest of the entry */
03114     LdrEntry->DllBase = ModuleLoadBase;
03115     LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +
03116                                    NtHeader->OptionalHeader.AddressOfEntryPoint);
03117     LdrEntry->SizeOfImage = DriverSize;
03118     LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
03119     LdrEntry->SectionPointer = Section;
03120 
03121     /* Now write the DLL name */
03122     LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
03123     LdrEntry->BaseDllName.Length = BaseName.Length;
03124     LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
03125 
03126     /* Copy and null-terminate it */
03127     RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
03128                   BaseName.Buffer,
03129                   BaseName.Length);
03130     LdrEntry->BaseDllName.Buffer[BaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
03131 
03132     /* Now allocate the full name */
03133     LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
03134                                                          PrefixName.Length +
03135                                                          sizeof(UNICODE_NULL),
03136                                                          TAG_LDR_WSTR);
03137     if (!LdrEntry->FullDllName.Buffer)
03138     {
03139         /* Don't fail, just set it to zero */
03140         LdrEntry->FullDllName.Length = 0;
03141         LdrEntry->FullDllName.MaximumLength = 0;
03142     }
03143     else
03144     {
03145         /* Set it up */
03146         LdrEntry->FullDllName.Length = PrefixName.Length;
03147         LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
03148 
03149         /* Copy and null-terminate */
03150         RtlCopyMemory(LdrEntry->FullDllName.Buffer,
03151                       PrefixName.Buffer,
03152                       PrefixName.Length);
03153         LdrEntry->FullDllName.Buffer[PrefixName.Length / sizeof(WCHAR)] = UNICODE_NULL;
03154     }
03155 
03156     /* Add the entry */
03157     MiProcessLoaderEntry(LdrEntry, TRUE);
03158 
03159     /* Resolve imports */
03160     MissingApiName = Buffer;
03161     Status = MiResolveImageReferences(ModuleLoadBase,
03162                                       &BaseDirectory,
03163                                       NULL,
03164                                       &MissingApiName,
03165                                       &MissingDriverName,
03166                                       &LoadedImports);
03167     if (!NT_SUCCESS(Status))
03168     {
03169         DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status);
03170 
03171         /* Fail */
03172         MiProcessLoaderEntry(LdrEntry, FALSE);
03173 
03174         /* Check if we need to free the name */
03175         if (LdrEntry->FullDllName.Buffer)
03176         {
03177             /* Free it */
03178             ExFreePoolWithTag(LdrEntry->FullDllName.Buffer, TAG_LDR_WSTR);
03179         }
03180 
03181         /* Free the entry itself */
03182         ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
03183         LdrEntry = NULL;
03184         goto Quickie;
03185     }
03186 
03187     /* Update the loader entry */
03188     LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |
03189                         LDRP_ENTRY_PROCESSED |
03190                         LDRP_MM_LOADED);
03191     LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
03192     LdrEntry->LoadedImports = LoadedImports;
03193 
03194     /* FIXME: Call driver verifier's loader function */
03195 
03196     /* Write-protect the system image */
03197     MiWriteProtectSystemImage(LdrEntry->DllBase);
03198 
03199     /* Check if notifications are enabled */
03200     if (PsImageNotifyEnabled)
03201     {
03202         /* Fill out the notification data */
03203         ImageInfo.Properties = 0;
03204         ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
03205         ImageInfo.SystemModeImage = TRUE;
03206         ImageInfo.ImageSize = LdrEntry->SizeOfImage;
03207         ImageInfo.ImageBase = LdrEntry->DllBase;
03208         ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;
03209 
03210         /* Send the notification */
03211         PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);
03212     }
03213 
03214 #if defined(KDBG) || defined(_WINKD_)
03215     /* MiCacheImageSymbols doesn't detect rossym */
03216     if (TRUE)
03217 #else
03218     /* Check if there's symbols */
03219     if (MiCacheImageSymbols(LdrEntry->DllBase))
03220 #endif
03221     {
03222         /* Check if the system root is present */
03223         if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&
03224             !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))
03225         {
03226             /* Add the system root */
03227             UnicodeTemp = PrefixName;
03228             UnicodeTemp.Buffer += 11;
03229             UnicodeTemp.Length -= (11 * sizeof(WCHAR));
03230             sprintf_nt(Buffer,
03231                        "%ws%wZ",
03232                        &SharedUserData->NtSystemRoot[2],
03233                        &UnicodeTemp);
03234         }
03235         else
03236         {
03237             /* Build the name */
03238             sprintf_nt(Buffer, "%wZ", &BaseName);
03239         }
03240 
03241         /* Setup the ansi string */
03242         RtlInitString(&AnsiTemp, Buffer);
03243 
03244         /* Notify the debugger */
03245         DbgLoadImageSymbols(&AnsiTemp,
03246                             LdrEntry->DllBase,
03247                             (ULONG_PTR)ZwCurrentProcess());
03248         LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
03249     }
03250 
03251     /* Page the driver */
03252     ASSERT(Section == NULL);
03253     MiEnablePagingOfDriver(LdrEntry);
03254 
03255     /* Return pointers */
03256     *ModuleObject = LdrEntry;
03257     *ImageBaseAddress = LdrEntry->DllBase;
03258 
03259 Quickie:
03260     /* Check if we have the lock acquired */
03261     if (LockOwned)
03262     {
03263         /* Release the lock */
03264         KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
03265         KeLeaveCriticalRegion();
03266         LockOwned = FALSE;
03267     }
03268 
03269     /* If we have a file handle, close it */
03270     if (FileHandle) ZwClose(FileHandle);
03271 
03272     /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
03273     /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
03274 
03275     /* Free the name buffer and return status */
03276     ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
03277     return Status;
03278 }
03279 
03280 PLDR_DATA_TABLE_ENTRY
03281 NTAPI
03282 MiLookupDataTableEntry(IN PVOID Address)
03283 {
03284     PLDR_DATA_TABLE_ENTRY LdrEntry, FoundEntry = NULL;
03285     PLIST_ENTRY NextEntry;
03286     PAGED_CODE();
03287 
03288     /* Loop entries */
03289     NextEntry = PsLoadedModuleList.Flink;
03290     do
03291     {
03292         /* Get the loader entry */
03293         LdrEntry =  CONTAINING_RECORD(NextEntry,
03294                                       LDR_DATA_TABLE_ENTRY,
03295                                       InLoadOrderLinks);
03296 
03297         /* Check if the address matches */
03298         if ((Address >= LdrEntry->DllBase) &&
03299             (Address < (PVOID)((ULONG_PTR)LdrEntry->DllBase +
03300                                LdrEntry->SizeOfImage)))
03301         {
03302             /* Found a match */
03303             FoundEntry = LdrEntry;
03304             break;
03305         }
03306 
03307         /* Move on */
03308         NextEntry = NextEntry->Flink;
03309     } while(NextEntry != &PsLoadedModuleList);
03310 
03311     /* Return the entry */
03312     return FoundEntry;
03313 }
03314 
03315 /* PUBLIC FUNCTIONS ***********************************************************/
03316 
03317 /*
03318  * @implemented
03319  */
03320 PVOID
03321 NTAPI
03322 MmPageEntireDriver(IN PVOID AddressWithinSection)
03323 {
03324     PMMPTE StartPte, EndPte;
03325     PLDR_DATA_TABLE_ENTRY LdrEntry;
03326     PAGED_CODE();
03327 
03328     /* Get the loader entry */
03329     LdrEntry = MiLookupDataTableEntry(AddressWithinSection);
03330     if (!LdrEntry) return NULL;
03331 
03332     /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
03333     if ((MmDisablePagingExecutive) || (LdrEntry->SectionPointer))
03334     {
03335         /* Don't do anything, just return the base address */
03336         return LdrEntry->DllBase;
03337     }
03338 
03339     /* Wait for active DPCs to finish before we page out the driver */
03340     KeFlushQueuedDpcs();
03341 
03342     /* Get the PTE range for the whole driver image */
03343     StartPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase);
03344     EndPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage);
03345 
03346     /* Enable paging for the PTE range */
03347     ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection) == FALSE);
03348     MiSetPagingOfDriver(StartPte, EndPte);
03349 
03350     /* Return the base address */
03351     return LdrEntry->DllBase;
03352 }
03353 
03354 /*
03355  * @unimplemented
03356  */
03357 VOID
03358 NTAPI
03359 MmResetDriverPaging(IN PVOID AddressWithinSection)
03360 {
03361     UNIMPLEMENTED;
03362 }
03363 
03364 /*
03365  * @implemented
03366  */
03367 PVOID
03368 NTAPI
03369 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
03370 {
03371     PVOID ProcAddress = NULL;
03372     ANSI_STRING AnsiRoutineName;
03373     NTSTATUS Status;
03374     PLIST_ENTRY NextEntry;
03375     PLDR_DATA_TABLE_ENTRY LdrEntry;
03376     BOOLEAN Found = FALSE;
03377     UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
03378     UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
03379     ULONG Modules = 0;
03380 
03381     /* Convert routine to ansi name */
03382     Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,
03383                                           SystemRoutineName,
03384                                           TRUE);
03385     if (!NT_SUCCESS(Status)) return NULL;
03386 
03387     /* Lock the list */
03388     KeEnterCriticalRegion();
03389     ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE);
03390 
03391     /* Loop the loaded module list */
03392     NextEntry = PsLoadedModuleList.Flink;
03393     while (NextEntry != &PsLoadedModuleList)
03394     {
03395         /* Get the entry */
03396         LdrEntry = CONTAINING_RECORD(NextEntry,
03397                                      LDR_DATA_TABLE_ENTRY,
03398                                      InLoadOrderLinks);
03399 
03400         /* Check if it's the kernel or HAL */
03401         if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
03402         {
03403             /* Found it */
03404             Found = TRUE;
03405             Modules++;
03406         }
03407         else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
03408         {
03409             /* Found it */
03410             Found = TRUE;
03411             Modules++;
03412         }
03413 
03414         /* Check if we found a valid binary */
03415         if (Found)
03416         {
03417             /* Find the procedure name */
03418             ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,
03419                                                       &AnsiRoutineName);
03420 
03421             /* Break out if we found it or if we already tried both modules */
03422             if (ProcAddress) break;
03423             if (Modules == 2) break;
03424         }
03425 
03426         /* Keep looping */
03427         NextEntry = NextEntry->Flink;
03428     }
03429 
03430     /* Release the lock */
03431     ExReleaseResourceLite(&PsLoadedModuleResource);
03432     KeLeaveCriticalRegion();
03433 
03434     /* Free the string and return */
03435     RtlFreeAnsiString(&AnsiRoutineName);
03436     return ProcAddress;
03437 }
03438 

Generated on Sat May 26 2012 04:36:25 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.