+++ /dev/null
-/*
-* PROJECT: ReactOS Kernel
-* LICENSE: GPL - See COPYING in the top level directory
-* FILE: ntoskrnl/mm/sysldr.c
-* PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files.
-* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
-* ReactOS Portable Systems Group
-*/
-
-/* INCLUDES *******************************************************************/
-
-#include <ntoskrnl.h>
-#define NDEBUG
-#include <debug.h>
-
-#line 16 "ARMĀ³::LOADER"
-#define MODULE_INVOLVED_IN_ARM3
-#include "./ARM3/miarm.h"
-
-/* GCC's incompetence strikes again */
-__inline
-VOID
-sprintf_nt(IN PCHAR Buffer,
- IN PCHAR Format,
- IN ...)
-{
- va_list ap;
- va_start(ap, Format);
- vsprintf(Buffer, Format, ap);
- va_end(ap);
-}
-
-/* GLOBALS ********************************************************************/
-
-LIST_ENTRY PsLoadedModuleList;
-LIST_ENTRY MmLoadedUserImageList;
-KSPIN_LOCK PsLoadedModuleSpinLock;
-ERESOURCE PsLoadedModuleResource;
-ULONG_PTR PsNtosImageBase;
-KMUTANT MmSystemLoadLock;
-
-PFN_NUMBER MmTotalSystemDriverPages;
-
-PVOID MmUnloadedDrivers;
-PVOID MmLastUnloadedDrivers;
-
-BOOLEAN MmMakeLowMemory;
-BOOLEAN MmEnforceWriteProtection = TRUE;
-
-PMMPTE MiKernelResourceStartPte, MiKernelResourceEndPte;
-ULONG_PTR ExPoolCodeStart, ExPoolCodeEnd, MmPoolCodeStart, MmPoolCodeEnd;
-ULONG_PTR MmPteCodeStart, MmPteCodeEnd;
-
-/* FUNCTIONS ******************************************************************/
-
-PVOID
-NTAPI
-MiCacheImageSymbols(IN PVOID BaseAddress)
-{
- ULONG DebugSize;
- PVOID DebugDirectory = NULL;
- PAGED_CODE();
-
- /* Make sure it's safe to access the image */
- _SEH2_TRY
- {
- /* Get the debug directory */
- DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_DEBUG,
- &DebugSize);
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- /* Nothing */
- }
- _SEH2_END;
-
- /* Return the directory */
- return DebugDirectory;
-}
-
-NTSTATUS
-NTAPI
-MiLoadImageSection(IN OUT PVOID *SectionPtr,
- OUT PVOID *ImageBase,
- IN PUNICODE_STRING FileName,
- IN BOOLEAN SessionLoad,
- IN PLDR_DATA_TABLE_ENTRY LdrEntry)
-{
- PROS_SECTION_OBJECT Section = *SectionPtr;
- NTSTATUS Status;
- PEPROCESS Process;
- PVOID Base = NULL;
- SIZE_T ViewSize = 0;
- KAPC_STATE ApcState;
- LARGE_INTEGER SectionOffset = {{0, 0}};
- BOOLEAN LoadSymbols = FALSE;
- PFN_NUMBER PteCount;
- PMMPTE PointerPte, LastPte;
- PVOID DriverBase;
- MMPTE TempPte;
- PAGED_CODE();
-
- /* Detect session load */
- if (SessionLoad)
- {
- /* Fail */
- DPRINT1("Session loading not yet supported!\n");
- while (TRUE);
- }
-
- /* Not session load, shouldn't have an entry */
- ASSERT(LdrEntry == NULL);
-
- /* Attach to the system process */
- KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
-
- /* Check if we need to load symbols */
- if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)
- {
- /* Yes we do */
- LoadSymbols = TRUE;
- NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
- }
-
- /* Map the driver */
- Process = PsGetCurrentProcess();
- Status = MmMapViewOfSection(Section,
- Process,
- &Base,
- 0,
- 0,
- &SectionOffset,
- &ViewSize,
- ViewUnmap,
- 0,
- PAGE_EXECUTE);
-
- /* Re-enable the flag */
- if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
-
- /* Check if we failed with distinguished status code */
- if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
- {
- /* Change it to something more generic */
- Status = STATUS_INVALID_IMAGE_FORMAT;
- }
-
- /* Now check if we failed */
- if (!NT_SUCCESS(Status))
- {
- /* Detach and return */
- KeUnstackDetachProcess(&ApcState);
- return Status;
- }
-
- /* Reserve system PTEs needed */
- PteCount = ROUND_TO_PAGES(Section->ImageSection->ImageSize) >> PAGE_SHIFT;
- PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
- if (!PointerPte) return STATUS_INSUFFICIENT_RESOURCES;
-
- /* New driver base */
- LastPte = PointerPte + PteCount;
- DriverBase = MiPteToAddress(PointerPte);
-
- /* The driver is here */
- *ImageBase = DriverBase;
-
- /* Loop the new driver PTEs */
- TempPte = ValidKernelPte;
- while (PointerPte < LastPte)
- {
- /* Allocate a page */
- TempPte.u.Hard.PageFrameNumber = MiAllocatePfn(PointerPte, MM_EXECUTE);
-
- /* Write it */
- ASSERT(PointerPte->u.Hard.Valid == 0);
- ASSERT(TempPte.u.Hard.Valid == 1);
- *PointerPte = TempPte;
-
- /* Move on */
- PointerPte++;
- }
-
- /* Copy the image */
- RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT);
-
- /* Now unmap the view */
- Status = MmUnmapViewOfSection(Process, Base);
- ASSERT(NT_SUCCESS(Status));
-
- /* Detach and return status */
- KeUnstackDetachProcess(&ApcState);
- return Status;
-}
-
-PVOID
-NTAPI
-MiLocateExportName(IN PVOID DllBase,
- IN PCHAR ExportName)
-{
- PULONG NameTable;
- PUSHORT OrdinalTable;
- PIMAGE_EXPORT_DIRECTORY ExportDirectory;
- LONG Low = 0, Mid = 0, High, Ret;
- USHORT Ordinal;
- PVOID Function;
- ULONG ExportSize;
- PULONG ExportTable;
- PAGED_CODE();
-
- /* Get the export directory */
- ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_EXPORT,
- &ExportSize);
- if (!ExportDirectory) return NULL;
-
- /* Setup name tables */
- NameTable = (PULONG)((ULONG_PTR)DllBase +
- ExportDirectory->AddressOfNames);
- OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
- ExportDirectory->AddressOfNameOrdinals);
-
- /* Do a binary search */
- High = ExportDirectory->NumberOfNames - 1;
- while (High >= Low)
- {
- /* Get new middle value */
- Mid = (Low + High) >> 1;
-
- /* Compare name */
- Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);
- if (Ret < 0)
- {
- /* Update high */
- High = Mid - 1;
- }
- else if (Ret > 0)
- {
- /* Update low */
- Low = Mid + 1;
- }
- else
- {
- /* We got it */
- break;
- }
- }
-
- /* Check if we couldn't find it */
- if (High < Low) return NULL;
-
- /* Otherwise, this is the ordinal */
- Ordinal = OrdinalTable[Mid];
-
- /* Resolve the address and write it */
- ExportTable = (PULONG)((ULONG_PTR)DllBase +
- ExportDirectory->AddressOfFunctions);
- Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
-
- /* Check if the function is actually a forwarder */
- if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
- ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
- {
- /* It is, fail */
- return NULL;
- }
-
- /* We found it */
- return Function;
-}
-
-NTSTATUS
-NTAPI
-MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
- IN PLIST_ENTRY ListHead)
-{
- UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(
- L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
- PMM_DLL_INITIALIZE DllInit;
- UNICODE_STRING RegPath, ImportName;
- NTSTATUS Status;
-
- /* Try to see if the image exports a DllInitialize routine */
- DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
- "DllInitialize");
- if (!DllInit) return STATUS_SUCCESS;
-
- /* Do a temporary copy of BaseDllName called ImportName
- * because we'll alter the length of the string
- */
- ImportName.Length = LdrEntry->BaseDllName.Length;
- ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;
- ImportName.Buffer = LdrEntry->BaseDllName.Buffer;
-
- /* Obtain the path to this dll's service in the registry */
- RegPath.MaximumLength = ServicesKeyName.Length +
- ImportName.Length + sizeof(UNICODE_NULL);
- RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
- RegPath.MaximumLength,
- TAG_LDR_WSTR);
-
- /* Check if this allocation was unsuccessful */
- if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
-
- /* Build and append the service name itself */
- RegPath.Length = ServicesKeyName.Length;
- RtlCopyMemory(RegPath.Buffer,
- ServicesKeyName.Buffer,
- ServicesKeyName.Length);
-
- /* Check if there is a dot in the filename */
- if (wcschr(ImportName.Buffer, L'.'))
- {
- /* Remove the extension */
- ImportName.Length = (wcschr(ImportName.Buffer, L'.') -
- ImportName.Buffer) * sizeof(WCHAR);
- }
-
- /* Append service name (the basename without extension) */
- RtlAppendUnicodeStringToString(&RegPath, &ImportName);
-
- /* Now call the DllInit func */
- DPRINT("Calling DllInit(%wZ)\n", &RegPath);
- Status = DllInit(&RegPath);
-
- /* Clean up */
- ExFreePool(RegPath.Buffer);
-
- /* Return status value which DllInitialize returned */
- return Status;
-}
-
-BOOLEAN
-NTAPI
-MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
-{
- NTSTATUS Status;
- PMM_DLL_UNLOAD Func;
- PAGED_CODE();
-
- /* Get the unload routine */
- Func = (PMM_DLL_UNLOAD)MiLocateExportName(LdrEntry->DllBase, "DllUnload");
- if (!Func) return FALSE;
-
- /* Call it and check for success */
- Status = Func();
- if (!NT_SUCCESS(Status)) return FALSE;
-
- /* Lie about the load count so we can unload the image */
- ASSERT(LdrEntry->LoadCount == 0);
- LdrEntry->LoadCount = 1;
-
- /* Unload it and return true */
- MmUnloadSystemImage(LdrEntry);
- return TRUE;
-}
-
-NTSTATUS
-NTAPI
-MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
-{
- SIZE_T i;
- LOAD_IMPORTS SingleEntry;
- PLDR_DATA_TABLE_ENTRY LdrEntry;
- PVOID CurrentImports;
- PAGED_CODE();
-
- /* Check if there's no imports or if we're a boot driver */
- if ((ImportList == MM_SYSLDR_NO_IMPORTS) ||
- (ImportList == MM_SYSLDR_BOOT_LOADED) ||
- (ImportList->Count == 0))
- {
- /* Then there's nothing to do */
- return STATUS_SUCCESS;
- }
-
- /* Check for single-entry */
- if ((ULONG_PTR)ImportList & MM_SYSLDR_SINGLE_ENTRY)
- {
- /* Set it up */
- SingleEntry.Count = 1;
- SingleEntry.Entry[0] = (PVOID)((ULONG_PTR)ImportList &~ MM_SYSLDR_SINGLE_ENTRY);
-
- /* Use this as the import list */
- ImportList = &SingleEntry;
- }
-
- /* Loop the import list */
- for (i = 0; (i < ImportList->Count) && (ImportList->Entry[i]); i++)
- {
- /* Get the entry */
- LdrEntry = ImportList->Entry[i];
- DPRINT1("%wZ <%wZ>\n", &LdrEntry->FullDllName, &LdrEntry->BaseDllName);
-
- /* Skip boot loaded images */
- if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) continue;
-
- /* Dereference the entry */
- ASSERT(LdrEntry->LoadCount >= 1);
- if (!--LdrEntry->LoadCount)
- {
- /* Save the import data in case unload fails */
- CurrentImports = LdrEntry->LoadedImports;
-
- /* This is the last entry */
- LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
- if (MiCallDllUnloadAndUnloadDll(LdrEntry))
- {
- /* Unloading worked, parse this DLL's imports too */
- MiDereferenceImports(CurrentImports);
-
- /* Check if we had valid imports */
- if ((CurrentImports != MM_SYSLDR_BOOT_LOADED) ||
- (CurrentImports != MM_SYSLDR_NO_IMPORTS) ||
- !((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY))
- {
- /* Free them */
- ExFreePool(CurrentImports);
- }
- }
- else
- {
- /* Unload failed, restore imports */
- LdrEntry->LoadedImports = CurrentImports;
- }
- }
- }
-
- /* Done */
- return STATUS_SUCCESS;
-}
-
-VOID
-NTAPI
-MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
-{
- PAGED_CODE();
-
- /* Check if there's no imports or we're a boot driver or only one entry */
- if ((LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) ||
- (LdrEntry->LoadedImports == MM_SYSLDR_NO_IMPORTS) ||
- ((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY))
- {
- /* Nothing to do */
- return;
- }
-
- /* Otherwise, free the import list */
- ExFreePool(LdrEntry->LoadedImports);
- LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
-}
-
-PVOID
-NTAPI
-MiFindExportedRoutineByName(IN PVOID DllBase,
- IN PANSI_STRING ExportName)
-{
- PULONG NameTable;
- PUSHORT OrdinalTable;
- PIMAGE_EXPORT_DIRECTORY ExportDirectory;
- LONG Low = 0, Mid = 0, High, Ret;
- USHORT Ordinal;
- PVOID Function;
- ULONG ExportSize;
- PULONG ExportTable;
- PAGED_CODE();
-
- /* Get the export directory */
- ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_EXPORT,
- &ExportSize);
- if (!ExportDirectory) return NULL;
-
- /* Setup name tables */
- NameTable = (PULONG)((ULONG_PTR)DllBase +
- ExportDirectory->AddressOfNames);
- OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
- ExportDirectory->AddressOfNameOrdinals);
-
- /* Do a binary search */
- High = ExportDirectory->NumberOfNames - 1;
- while (High >= Low)
- {
- /* Get new middle value */
- Mid = (Low + High) >> 1;
-
- /* Compare name */
- Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);
- if (Ret < 0)
- {
- /* Update high */
- High = Mid - 1;
- }
- else if (Ret > 0)
- {
- /* Update low */
- Low = Mid + 1;
- }
- else
- {
- /* We got it */
- break;
- }
- }
-
- /* Check if we couldn't find it */
- if (High < Low) return NULL;
-
- /* Otherwise, this is the ordinal */
- Ordinal = OrdinalTable[Mid];
-
- /* Validate the ordinal */
- if (Ordinal >= ExportDirectory->NumberOfFunctions) return NULL;
-
- /* Resolve the address and write it */
- ExportTable = (PULONG)((ULONG_PTR)DllBase +
- ExportDirectory->AddressOfFunctions);
- Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
-
- /* We found it! */
- ASSERT(!(Function > (PVOID)ExportDirectory) &&
- (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));
- return Function;
-}
-
-VOID
-NTAPI
-MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
- IN BOOLEAN Insert)
-{
- KIRQL OldIrql;
-
- /* Acquire module list lock */
- KeEnterCriticalRegion();
- ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
-
- /* Acquire the spinlock too as we will insert or remove the entry */
- OldIrql = KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock);
-
- /* Insert or remove from the list */
- Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :
- RemoveEntryList(&LdrEntry->InLoadOrderLinks);
-
- /* Release locks */
- KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
- ExReleaseResourceLite(&PsLoadedModuleResource);
- KeLeaveCriticalRegion();
-}
-
-VOID
-NTAPI
-MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
- IN PVOID OldBase,
- IN PVOID NewBase,
- IN ULONG Size)
-{
- ULONG_PTR OldBaseTop, Delta;
- PLDR_DATA_TABLE_ENTRY LdrEntry;
- PLIST_ENTRY NextEntry;
- ULONG ImportSize, i;
- PULONG_PTR ImageThunk;
- PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
-
- /* Calculate the top and delta */
- OldBaseTop = (ULONG_PTR)OldBase + Size - 1;
- Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;
-
- /* Loop the loader block */
- for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
- NextEntry != &LoaderBlock->LoadOrderListHead;
- NextEntry = NextEntry->Flink)
- {
- /* Get the loader entry */
- LdrEntry = CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
-#ifdef _WORKING_LINKER_
- /* Get the IAT */
- ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_IAT,
- &ImportSize);
- if (!ImageThunk) continue;
-
- /* Make sure we have an IAT */
- DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
- for (i = 0; i < ImportSize; i++, ImageThunk++)
- {
- /* Check if it's within this module */
- if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
- {
- /* Relocate it */
- DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
- ImageThunk, *ImageThunk, *ImageThunk + Delta);
- *ImageThunk += Delta;
- }
- }
-#else
- /* Get the import table */
- i = ImportSize;
- ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_IMPORT,
- &ImportSize);
- if (!ImportDescriptor) continue;
-
- /* Make sure we have an IAT */
- DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
- while ((ImportDescriptor->Name) &&
- (ImportDescriptor->OriginalFirstThunk))
- {
- /* Get the image thunk */
- ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
- ImportDescriptor->FirstThunk);
- while (*ImageThunk)
- {
- /* Check if it's within this module */
- if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
- {
- /* Relocate it */
- DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
- ImageThunk, *ImageThunk, *ImageThunk + Delta);
- *ImageThunk += Delta;
- }
-
- /* Go to the next thunk */
- ImageThunk++;
- }
-
- /* Go to the next import */
- ImportDescriptor++;
- }
-#endif
- }
-}
-
-NTSTATUS
-NTAPI
-MiSnapThunk(IN PVOID DllBase,
- IN PVOID ImageBase,
- IN PIMAGE_THUNK_DATA Name,
- IN PIMAGE_THUNK_DATA Address,
- IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
- IN ULONG ExportSize,
- IN BOOLEAN SnapForwarder,
- OUT PCHAR *MissingApi)
-{
- BOOLEAN IsOrdinal;
- USHORT Ordinal;
- PULONG NameTable;
- PUSHORT OrdinalTable;
- PIMAGE_IMPORT_BY_NAME NameImport;
- USHORT Hint;
- ULONG Low = 0, Mid = 0, High;
- LONG Ret;
- NTSTATUS Status;
- PCHAR MissingForwarder;
- CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];
- PULONG ExportTable;
- ANSI_STRING DllName;
- UNICODE_STRING ForwarderName;
- PLIST_ENTRY NextEntry;
- PLDR_DATA_TABLE_ENTRY LdrEntry;
- ULONG ForwardExportSize;
- PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;
- PIMAGE_IMPORT_BY_NAME ForwardName;
- ULONG ForwardLength;
- IMAGE_THUNK_DATA ForwardThunk;
- PAGED_CODE();
-
- /* Check if this is an ordinal */
- IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);
- if ((IsOrdinal) && !(SnapForwarder))
- {
- /* Get the ordinal number and set it as missing */
- Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -
- ExportDirectory->Base);
- *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;
- }
- else
- {
- /* Get the VA if we don't have to snap */
- if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;
- NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;
-
- /* Copy the procedure name */
- strncpy(*MissingApi,
- (PCHAR)&NameImport->Name[0],
- MAXIMUM_FILENAME_LENGTH - 1);
-
- /* Setup name tables */
- DPRINT("Import name: %s\n", NameImport->Name);
- NameTable = (PULONG)((ULONG_PTR)DllBase +
- ExportDirectory->AddressOfNames);
- OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
- ExportDirectory->AddressOfNameOrdinals);
-
- /* Get the hint and check if it's valid */
- Hint = NameImport->Hint;
- if ((Hint < ExportDirectory->NumberOfNames) &&
- !(strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))
- {
- /* We have a match, get the ordinal number from here */
- Ordinal = OrdinalTable[Hint];
- }
- else
- {
- /* Do a binary search */
- High = ExportDirectory->NumberOfNames - 1;
- while (High >= Low)
- {
- /* Get new middle value */
- Mid = (Low + High) >> 1;
-
- /* Compare name */
- Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);
- if (Ret < 0)
- {
- /* Update high */
- High = Mid - 1;
- }
- else if (Ret > 0)
- {
- /* Update low */
- Low = Mid + 1;
- }
- else
- {
- /* We got it */
- break;
- }
- }
-
- /* Check if we couldn't find it */
- if (High < Low) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
-
- /* Otherwise, this is the ordinal */
- Ordinal = OrdinalTable[Mid];
- }
- }
-
- /* Check if the ordinal is invalid */
- if (Ordinal >= ExportDirectory->NumberOfFunctions)
- {
- /* Fail */
- Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
- }
- else
- {
- /* In case the forwarder is missing */
- MissingForwarder = NameBuffer;
-
- /* Resolve the address and write it */
- ExportTable = (PULONG)((ULONG_PTR)DllBase +
- ExportDirectory->AddressOfFunctions);
- Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];
-
- /* Assume success from now on */
- Status = STATUS_SUCCESS;
-
- /* Check if the function is actually a forwarder */
- if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&
- (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
- {
- /* Now assume failure in case the forwarder doesn't exist */
- Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
-
- /* Build the forwarder name */
- DllName.Buffer = (PCHAR)Address->u1.Function;
- DllName.Length = strchr(DllName.Buffer, '.') -
- DllName.Buffer +
- sizeof(ANSI_NULL);
- DllName.MaximumLength = DllName.Length;
-
- /* Convert it */
- if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,
- &DllName,
- TRUE)))
- {
- /* We failed, just return an error */
- return Status;
- }
-
- /* Loop the module list */
- NextEntry = PsLoadedModuleList.Flink;
- while (NextEntry != &PsLoadedModuleList)
- {
- /* Get the loader entry */
- LdrEntry = CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
-
- /* Check if it matches */
- if (RtlPrefixString((PSTRING)&ForwarderName,
- (PSTRING)&LdrEntry->BaseDllName,
- TRUE))
- {
- /* Get the forwarder export directory */
- ForwardExportDirectory =
- RtlImageDirectoryEntryToData(LdrEntry->DllBase,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_EXPORT,
- &ForwardExportSize);
- if (!ForwardExportDirectory) break;
-
- /* Allocate a name entry */
- ForwardLength = strlen(DllName.Buffer + DllName.Length) +
- sizeof(ANSI_NULL);
- ForwardName = ExAllocatePoolWithTag(PagedPool,
- sizeof(*ForwardName) +
- ForwardLength,
- TAG_LDR_WSTR);
- if (!ForwardName) break;
-
- /* Copy the data */
- RtlCopyMemory(&ForwardName->Name[0],
- DllName.Buffer + DllName.Length,
- ForwardLength);
- ForwardName->Hint = 0;
-
- /* Set the new address */
- ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName;
-
- /* Snap the forwarder */
- Status = MiSnapThunk(LdrEntry->DllBase,
- ImageBase,
- &ForwardThunk,
- &ForwardThunk,
- ForwardExportDirectory,
- ForwardExportSize,
- TRUE,
- &MissingForwarder);
-
- /* Free the forwarder name and set the thunk */
- ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR);
- Address->u1 = ForwardThunk.u1;
- break;
- }
-
- /* Go to the next entry */
- NextEntry = NextEntry->Flink;
- }
-
- /* Free the name */
- RtlFreeUnicodeString(&ForwarderName);
- }
- }
-
- /* Return status */
- return Status;
-}
-
-NTSTATUS
-NTAPI
-MmUnloadSystemImage(IN PVOID ImageHandle)
-{
- PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;
- PVOID BaseAddress = LdrEntry->DllBase;
- NTSTATUS Status;
- STRING TempName;
- BOOLEAN HadEntry = FALSE;
-
- /* Acquire the loader lock */
- KeEnterCriticalRegion();
- KeWaitForSingleObject(&MmSystemLoadLock,
- WrVirtualMemory,
- KernelMode,
- FALSE,
- NULL);
-
- /* Check if this driver was loaded at boot and didn't get imports parsed */
- if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) goto Done;
-
- /* We should still be alive */
- ASSERT(LdrEntry->LoadCount != 0);
- LdrEntry->LoadCount--;
-
- /* Check if we're still loaded */
- if (LdrEntry->LoadCount) goto Done;
-
- /* We should cleanup... are symbols loaded */
- if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)
- {
- /* Create the ANSI name */
- Status = RtlUnicodeStringToAnsiString(&TempName,
- &LdrEntry->BaseDllName,
- TRUE);
- if (NT_SUCCESS(Status))
- {
- /* Unload the symbols */
- DbgUnLoadImageSymbols(&TempName,
- BaseAddress,
- (ULONG_PTR)ZwCurrentProcess());
- RtlFreeAnsiString(&TempName);
- }
- }
-
- /* FIXME: Free the driver */
- DPRINT1("Leaking driver: %wZ\n", &LdrEntry->BaseDllName);
- //MmFreeSection(LdrEntry->DllBase);
-
- /* Check if we're linked in */
- if (LdrEntry->InLoadOrderLinks.Flink)
- {
- /* Remove us */
- MiProcessLoaderEntry(LdrEntry, FALSE);
- HadEntry = TRUE;
- }
-
- /* Dereference and clear the imports */
- MiDereferenceImports(LdrEntry->LoadedImports);
- MiClearImports(LdrEntry);
-
- /* Check if the entry needs to go away */
- if (HadEntry)
- {
- /* Check if it had a name */
- if (LdrEntry->FullDllName.Buffer)
- {
- /* Free it */
- ExFreePool(LdrEntry->FullDllName.Buffer);
- }
-
- /* Check if we had a section */
- if (LdrEntry->SectionPointer)
- {
- /* Dereference it */
- ObDereferenceObject(LdrEntry->SectionPointer);
- }
-
- /* Free the entry */
- ExFreePool(LdrEntry);
- }
-
- /* Release the system lock and return */
-Done:
- KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
- KeLeaveCriticalRegion();
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-MiResolveImageReferences(IN PVOID ImageBase,
- IN PUNICODE_STRING ImageFileDirectory,
- IN PUNICODE_STRING NamePrefix OPTIONAL,
- OUT PCHAR *MissingApi,
- OUT PWCHAR *MissingDriver,
- OUT PLOAD_IMPORTS *LoadImports)
-{
- PCHAR MissingApiBuffer = *MissingApi, ImportName;
- PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
- ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
- PLOAD_IMPORTS LoadedImports, NewImports;
- ULONG GdiLink, NormalLink, i;
- BOOLEAN ReferenceNeeded, Loaded;
- ANSI_STRING TempString;
- UNICODE_STRING NameString, DllName;
- PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;
- PVOID ImportBase, DllBase;
- PLIST_ENTRY NextEntry;
- PIMAGE_EXPORT_DIRECTORY ExportDirectory;
- NTSTATUS Status;
- PIMAGE_THUNK_DATA OrigThunk, FirstThunk;
- PAGED_CODE();
- DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
- __FUNCTION__, ImageBase, ImageFileDirectory);
-
- /* Assume no imports */
- *LoadImports = MM_SYSLDR_NO_IMPORTS;
-
- /* Get the import descriptor */
- ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_IMPORT,
- &ImportSize);
- if (!ImportDescriptor) return STATUS_SUCCESS;
-
- /* Loop all imports to count them */
- for (CurrentImport = ImportDescriptor;
- (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);
- CurrentImport++)
- {
- /* One more */
- ImportCount++;
- }
-
- /* Make sure we have non-zero imports */
- if (ImportCount)
- {
- /* Calculate and allocate the list we'll need */
- LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
- LoadedImports = ExAllocatePoolWithTag(PagedPool,
- LoadedImportsSize,
- 'TDmM');
- if (LoadedImports)
- {
- /* Zero it */
- RtlZeroMemory(LoadedImports, LoadedImportsSize);
- LoadedImports->Count = ImportCount;
- }
- }
- else
- {
- /* No table */
- LoadedImports = NULL;
- }
-
- /* Reset the import count and loop descriptors again */
- ImportCount = GdiLink = NormalLink = 0;
- while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))
- {
- /* Get the name */
- ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);
-
- /* Check if this is a GDI driver */
- GdiLink = GdiLink |
- !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));
-
- /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
- NormalLink = NormalLink |
- ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&
- (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)) &&
- (_strnicmp(ImportName, "coverage", sizeof("coverage") - 1)) &&
- (_strnicmp(ImportName, "irt", sizeof("irt") - 1)));
-
- /* Check if this is a valid GDI driver */
- if ((GdiLink) && (NormalLink))
- {
- /* It's not, it's importing stuff it shouldn't be! */
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePool(LoadedImports);
- return STATUS_PROCEDURE_NOT_FOUND;
- }
-
- /* Check for user-mode printer or video card drivers, which don't belong */
- if (!(_strnicmp(ImportName, "ntdll", sizeof("ntdll") - 1)) ||
- !(_strnicmp(ImportName, "winsrv", sizeof("winsrv") - 1)) ||
- !(_strnicmp(ImportName, "advapi32", sizeof("advapi32") - 1)) ||
- !(_strnicmp(ImportName, "kernel32", sizeof("kernel32") - 1)) ||
- !(_strnicmp(ImportName, "user32", sizeof("user32") - 1)) ||
- !(_strnicmp(ImportName, "gdi32", sizeof("gdi32") - 1)))
- {
- /* This is not kernel code */
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePool(LoadedImports);
- return STATUS_PROCEDURE_NOT_FOUND;
- }
-
- /* Check if this is a "core" import, which doesn't get referenced */
- if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
- !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||
- !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))
- {
- /* Don't reference this */
- ReferenceNeeded = FALSE;
- }
- else
- {
- /* Reference these modules */
- ReferenceNeeded = TRUE;
- }
-
- /* Now setup a unicode string for the import */
- RtlInitAnsiString(&TempString, ImportName);
- Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);
- if (!NT_SUCCESS(Status))
- {
- /* Failed */
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
- return Status;
- }
-
- /* We don't support name prefixes yet */
- if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");
-
- /* Remember that we haven't loaded the import at this point */
-CheckDllState:
- Loaded = FALSE;
- ImportBase = NULL;
-
- /* Loop the driver list */
- NextEntry = PsLoadedModuleList.Flink;
- while (NextEntry != &PsLoadedModuleList)
- {
- /* Get the loader entry and compare the name */
- LdrEntry = CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
- if (RtlEqualUnicodeString(&NameString,
- &LdrEntry->BaseDllName,
- TRUE))
- {
- /* Get the base address */
- ImportBase = LdrEntry->DllBase;
-
- /* Check if we haven't loaded yet, and we need references */
- if (!(Loaded) && (ReferenceNeeded))
- {
- /* Make sure we're not already loading */
- if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
- {
- /* Increase the load count */
- LdrEntry->LoadCount++;
- }
- }
-
- /* Done, break out */
- break;
- }
-
- /* Go to the next entry */
- NextEntry = NextEntry->Flink;
- }
-
- /* Check if we haven't loaded the import yet */
- if (!ImportBase)
- {
- /* Setup the import DLL name */
- DllName.MaximumLength = NameString.Length +
- ImageFileDirectory->Length +
- sizeof(UNICODE_NULL);
- DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
- DllName.MaximumLength,
- 'TDmM');
- if (DllName.Buffer)
- {
- /* Setup the base length and copy it */
- DllName.Length = ImageFileDirectory->Length;
- RtlCopyMemory(DllName.Buffer,
- ImageFileDirectory->Buffer,
- ImageFileDirectory->Length);
-
- /* Now add the import name and null-terminate it */
- RtlAppendStringToString((PSTRING)&DllName,
- (PSTRING)&NameString);
- DllName.Buffer[(DllName.MaximumLength - 1) / sizeof(WCHAR)] = UNICODE_NULL;
-
- /* Load the image */
- Status = MmLoadSystemImage(&DllName,
- NamePrefix,
- NULL,
- FALSE,
- (PVOID)&DllEntry,
- &DllBase);
- if (NT_SUCCESS(Status))
- {
- /* We can free the DLL Name */
- ExFreePool(DllName.Buffer);
- }
- else
- {
- /* Fill out the information for the error */
- *MissingDriver = DllName.Buffer;
- *(PULONG)MissingDriver |= 1;
- *MissingApi = NULL;
- }
- }
- else
- {
- /* We're out of resources */
- Status = STATUS_INSUFFICIENT_RESOURCES;
- }
-
- /* Check if we're OK until now */
- if (NT_SUCCESS(Status))
- {
- /* We're now loaded */
- Loaded = TRUE;
-
- /* Sanity check */
- ASSERT(DllBase = DllEntry->DllBase);
-
- /* Call the initialization routines */
- Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
- if (!NT_SUCCESS(Status))
- {
- /* We failed, unload the image */
- MmUnloadSystemImage(DllEntry);
- while (TRUE);
- Loaded = FALSE;
- }
- }
-
- /* Check if we failed by here */
- if (!NT_SUCCESS(Status))
- {
- /* Cleanup and return */
- RtlFreeUnicodeString(&NameString);
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
- return Status;
- }
-
- /* Loop again to make sure that everything is OK */
- goto CheckDllState;
- }
-
- /* Check if we're support to reference this import */
- if ((ReferenceNeeded) && (LoadedImports))
- {
- /* Make sure we're not already loading */
- if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
- {
- /* Add the entry */
- LoadedImports->Entry[ImportCount] = LdrEntry;
- ImportCount++;
- }
- }
-
- /* Free the import name */
- RtlFreeUnicodeString(&NameString);
-
- /* Set the missing driver name and get the export directory */
- *MissingDriver = LdrEntry->BaseDllName.Buffer;
- ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_EXPORT,
- &ExportSize);
- if (!ExportDirectory)
- {
- /* Cleanup and return */
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
- return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
- }
-
- /* Make sure we have an IAT */
- if (ImportDescriptor->OriginalFirstThunk)
- {
- /* Get the first thunks */
- OrigThunk = (PVOID)((ULONG_PTR)ImageBase +
- ImportDescriptor->OriginalFirstThunk);
- FirstThunk = (PVOID)((ULONG_PTR)ImageBase +
- ImportDescriptor->FirstThunk);
-
- /* Loop the IAT */
- while (OrigThunk->u1.AddressOfData)
- {
- /* Snap thunk */
- Status = MiSnapThunk(ImportBase,
- ImageBase,
- OrigThunk++,
- FirstThunk++,
- ExportDirectory,
- ExportSize,
- FALSE,
- MissingApi);
- if (!NT_SUCCESS(Status))
- {
- /* Cleanup and return */
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
- return Status;
- }
-
- /* Reset the buffer */
- *MissingApi = MissingApiBuffer;
- }
- }
-
- /* Go to the next import */
- ImportDescriptor++;
- }
-
- /* Check if we have an import list */
- if (LoadedImports)
- {
- /* Reset the count again, and loop entries*/
- ImportCount = 0;
- for (i = 0; i < LoadedImports->Count; i++)
- {
- if (LoadedImports->Entry[i])
- {
- /* Got an entry, OR it with 1 in case it's the single entry */
- ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] |
- MM_SYSLDR_SINGLE_ENTRY);
- ImportCount++;
- }
- }
-
- /* Check if we had no imports */
- if (!ImportCount)
- {
- /* Free the list and set it to no imports */
- ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
- LoadedImports = MM_SYSLDR_NO_IMPORTS;
- }
- else if (ImportCount == 1)
- {
- /* Just one entry, we can free the table and only use our entry */
- ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
- LoadedImports = (PLOAD_IMPORTS)ImportEntry;
- }
- else if (ImportCount != LoadedImports->Count)
- {
- /* Allocate a new list */
- LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
- NewImports = ExAllocatePoolWithTag(PagedPool,
- LoadedImportsSize,
- 'TDmM');
- if (NewImports)
- {
- /* Set count */
- NewImports->Count = 0;
-
- /* Loop all the imports */
- for (i = 0; i < LoadedImports->Count; i++)
- {
- /* Make sure it's valid */
- if (LoadedImports->Entry[i])
- {
- /* Copy it */
- NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];
- NewImports->Count++;
- }
- }
-
- /* Free the old copy */
- ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
- LoadedImports = NewImports;
- }
- }
-
- /* Return the list */
- *LoadImports = LoadedImports;
- }
-
- /* Return success */
- return STATUS_SUCCESS;
-}
-
-VOID
-NTAPI
-MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
-{
- PLIST_ENTRY NextEntry;
- ULONG i = 0;
- PIMAGE_NT_HEADERS NtHeader;
- PLDR_DATA_TABLE_ENTRY LdrEntry;
- PIMAGE_FILE_HEADER FileHeader;
- BOOLEAN ValidRelocs;
- PIMAGE_DATA_DIRECTORY DataDirectory;
- PVOID DllBase, NewImageAddress;
- NTSTATUS Status;
- PMMPTE PointerPte, StartPte, LastPte;
- PFN_NUMBER PteCount;
- PMMPFN Pfn1;
- MMPTE TempPte, OldPte;
-
- /* Loop driver list */
- for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
- NextEntry != &LoaderBlock->LoadOrderListHead;
- NextEntry = NextEntry->Flink)
- {
- /* Get the loader entry and NT header */
- LdrEntry = CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
- NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
-
- /* Debug info */
- DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
- LdrEntry->DllBase,
- (ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage,
- &LdrEntry->FullDllName);
-
- /* Skip kernel and HAL */
- /* ROS HACK: Skip BOOTVID/KDCOM too */
- i++;
- if (i <= 4) continue;
-
- /* Skip non-drivers */
- if (!NtHeader) continue;
-
- /* Get the file header and make sure we can relocate */
- FileHeader = &NtHeader->FileHeader;
- if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
- if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
- IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
-
- /* Everything made sense until now, check the relocation section too */
- DataDirectory = &NtHeader->OptionalHeader.
- DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
- if (!DataDirectory->VirtualAddress)
- {
- /* We don't really have relocations */
- ValidRelocs = FALSE;
- }
- else
- {
- /* Make sure the size is valid */
- if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
- LdrEntry->SizeOfImage)
- {
- /* They're not, skip */
- continue;
- }
-
- /* We have relocations */
- ValidRelocs = TRUE;
- }
-
- /* Remember the original address */
- DllBase = LdrEntry->DllBase;
-
- /* Get the first PTE and the number of PTEs we'll need */
- PointerPte = StartPte = MiAddressToPte(LdrEntry->DllBase);
- PteCount = ROUND_TO_PAGES(LdrEntry->SizeOfImage) >> PAGE_SHIFT;
- LastPte = StartPte + PteCount;
-
- /* Loop the PTEs */
- while (PointerPte < LastPte)
- {
- /* Mark the page modified in the PFN database */
- ASSERT(PointerPte->u.Hard.Valid == 1);
- Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
- ASSERT(Pfn1->u3.e1.Rom == 0);
- Pfn1->u3.e1.Modified = TRUE;
-
- /* Next */
- PointerPte++;
- }
-
- /* Now reserve system PTEs for the image */
- PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
- if (!PointerPte)
- {
- /* Shouldn't happen */
- DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
- while (TRUE);
- }
-
- /* This is the new virtual address for the module */
- LastPte = PointerPte + PteCount;
- NewImageAddress = MiPteToAddress(PointerPte);
-
- /* Sanity check */
- DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
- ASSERT(ExpInitializationPhase == 0);
-
- /* Loop the new driver PTEs */
- TempPte = ValidKernelPte;
- while (PointerPte < LastPte)
- {
- /* Copy the old data */
- OldPte = *StartPte;
- ASSERT(OldPte.u.Hard.Valid == 1);
-
- /* Set page number from the loader's memory */
- TempPte.u.Hard.PageFrameNumber = OldPte.u.Hard.PageFrameNumber;
-
- /* Write it */
- ASSERT(PointerPte->u.Hard.Valid == 0);
- ASSERT(TempPte.u.Hard.Valid == 1);
- *PointerPte = TempPte;
-
- /* Move on */
- PointerPte++;
- StartPte++;
- }
-
- /* Update position */
- PointerPte -= PteCount;
-
- /* Sanity check */
- ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
-
- /* Set the image base to the address where the loader put it */
- NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
-
- /* Check if we had relocations */
- if (ValidRelocs)
- {
- /* Relocate the image */
- Status = LdrRelocateImageWithBias(NewImageAddress,
- 0,
- "SYSLDR",
- STATUS_SUCCESS,
- STATUS_CONFLICTING_ADDRESSES,
- STATUS_INVALID_IMAGE_FORMAT);
- if (!NT_SUCCESS(Status))
- {
- /* This shouldn't happen */
- DPRINT1("Relocations failed!\n");
- while (TRUE);
- }
- }
-
- /* Update the loader entry */
- LdrEntry->DllBase = NewImageAddress;
-
- /* Update the thunks */
- DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
- MiUpdateThunks(LoaderBlock,
- DllBase,
- NewImageAddress,
- LdrEntry->SizeOfImage);
-
- /* Update the loader entry */
- LdrEntry->Flags |= LDRP_SYSTEM_MAPPED;
- LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
- NtHeader->OptionalHeader.AddressOfEntryPoint);
- LdrEntry->SizeOfImage = PteCount << PAGE_SHIFT;
-
- /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
- }
-}
-
-NTSTATUS
-NTAPI
-MiBuildImportsForBootDrivers(VOID)
-{
- PLIST_ENTRY NextEntry, NextEntry2;
- PLDR_DATA_TABLE_ENTRY LdrEntry, KernelEntry, HalEntry, LdrEntry2, LastEntry;
- PLDR_DATA_TABLE_ENTRY* EntryArray;
- UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
- UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
- PLOAD_IMPORTS LoadedImports;
- ULONG LoadedImportsSize, ImportSize;
- PULONG_PTR ImageThunk;
- ULONG_PTR DllBase, DllEnd;
- ULONG Modules = 0, i, j = 0;
- PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
-
- /* Initialize variables */
- KernelEntry = HalEntry = LastEntry = NULL;
-
- /* Loop the loaded module list... we are early enough that no lock is needed */
- NextEntry = PsLoadedModuleList.Flink;
- while (NextEntry != &PsLoadedModuleList)
- {
- /* Get the entry */
- LdrEntry = CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
-
- /* Check if it's the kernel or HAL */
- if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
- {
- /* Found it */
- KernelEntry = LdrEntry;
- }
- else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
- {
- /* Found it */
- HalEntry = LdrEntry;
- }
-
- /* Check if this is a driver DLL */
- if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
- {
- /* Check if this is the HAL or kernel */
- if ((LdrEntry == HalEntry) || (LdrEntry == KernelEntry))
- {
- /* Add a reference */
- LdrEntry->LoadCount = 1;
- }
- else
- {
- /* No referencing needed */
- LdrEntry->LoadCount = 0;
- }
- }
- else
- {
- /* No referencing needed */
- LdrEntry->LoadCount = 0;
- }
-
- /* Remember this came from the loader */
- LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
-
- /* Keep looping */
- NextEntry = NextEntry->Flink;
- Modules++;
- }
-
- /* We must have at least found the kernel and HAL */
- if (!(HalEntry) || (!KernelEntry)) return STATUS_NOT_FOUND;
-
- /* Allocate the list */
- EntryArray = ExAllocatePoolWithTag(PagedPool, Modules * sizeof(PVOID), 'TDmM');
- if (!EntryArray) return STATUS_INSUFFICIENT_RESOURCES;
-
- /* Loop the loaded module list again */
- NextEntry = PsLoadedModuleList.Flink;
- while (NextEntry != &PsLoadedModuleList)
- {
- /* Get the entry */
- LdrEntry = CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
-#ifdef _WORKING_LOADER_
- /* Get its imports */
- ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_IAT,
- &ImportSize);
- if (!ImageThunk)
-#else
- /* Get its imports */
- ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_IMPORT,
- &ImportSize);
- if (!ImportDescriptor)
-#endif
- {
- /* None present */
- LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
- NextEntry = NextEntry->Flink;
- continue;
- }
-
- /* Clear the list and count the number of IAT thunks */
- RtlZeroMemory(EntryArray, Modules * sizeof(PVOID));
-#ifdef _WORKING_LOADER_
- ImportSize /= sizeof(ULONG_PTR);
-
- /* Scan the thunks */
- for (i = 0, DllBase = 0, DllEnd = 0; i < ImportSize; i++, ImageThunk++)
-#else
- i = DllBase = DllEnd = 0;
- while ((ImportDescriptor->Name) &&
- (ImportDescriptor->OriginalFirstThunk))
- {
- /* Get the image thunk */
- ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
- ImportDescriptor->FirstThunk);
- while (*ImageThunk)
-#endif
- {
- /* Do we already have an address? */
- if (DllBase)
- {
- /* Is the thunk in the same address? */
- if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd))
- {
- /* Skip it, we already have a reference for it */
- ASSERT(EntryArray[j]);
- ImageThunk++;
- continue;
- }
- }
-
- /* Loop the loaded module list to locate this address owner */
- j = 0;
- NextEntry2 = PsLoadedModuleList.Flink;
- while (NextEntry2 != &PsLoadedModuleList)
- {
- /* Get the entry */
- LdrEntry2 = CONTAINING_RECORD(NextEntry2,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
-
- /* Get the address range for this module */
- DllBase = (ULONG_PTR)LdrEntry2->DllBase;
- DllEnd = DllBase + LdrEntry2->SizeOfImage;
-
- /* Check if this IAT entry matches it */
- if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd))
- {
- /* Save it */
- //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
- EntryArray[j] = LdrEntry2;
- break;
- }
-
- /* Keep searching */
- NextEntry2 = NextEntry2->Flink;
- j++;
- }
-
- /* Do we have a thunk outside the range? */
- if ((*ImageThunk < DllBase) || (*ImageThunk >= DllEnd))
- {
- /* Could be 0... */
- if (*ImageThunk)
- {
- /* Should not be happening */
- DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
- LdrEntry, ImageThunk, *ImageThunk);
- ASSERT(FALSE);
- }
-
- /* Reset if we hit this */
- DllBase = 0;
- }
-#ifndef _WORKING_LOADER_
- ImageThunk++;
- }
-
- i++;
- ImportDescriptor++;
-#endif
- }
-
- /* Now scan how many imports we really have */
- for (i = 0, ImportSize = 0; i < Modules; i++)
- {
- /* Skip HAL and kernel */
- if ((EntryArray[i]) &&
- (EntryArray[i] != HalEntry) &&
- (EntryArray[i] != KernelEntry))
- {
- /* A valid reference */
- LastEntry = EntryArray[i];
- ImportSize++;
- }
- }
-
- /* Do we have any imports after all? */
- if (!ImportSize)
- {
- /* No */
- LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
- }
- else if (ImportSize == 1)
- {
- /* A single entry import */
- LdrEntry->LoadedImports = (PVOID)((ULONG_PTR)LastEntry | MM_SYSLDR_SINGLE_ENTRY);
- LastEntry->LoadCount++;
- }
- else
- {
- /* We need an import table */
- LoadedImportsSize = ImportSize * sizeof(PVOID) + sizeof(SIZE_T);
- LoadedImports = ExAllocatePoolWithTag(PagedPool,
- LoadedImportsSize,
- 'TDmM');
- ASSERT(LoadedImports);
-
- /* Save the count */
- LoadedImports->Count = ImportSize;
-
- /* Now copy all imports */
- for (i = 0, j = 0; i < Modules; i++)
- {
- /* Skip HAL and kernel */
- if ((EntryArray[i]) &&
- (EntryArray[i] != HalEntry) &&
- (EntryArray[i] != KernelEntry))
- {
- /* A valid reference */
- //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
- LoadedImports->Entry[j] = EntryArray[i];
- EntryArray[i]->LoadCount++;
- j++;
- }
- }
-
- /* Should had as many entries as we expected */
- ASSERT(j == ImportSize);
- LdrEntry->LoadedImports = LoadedImports;
- }
-
- /* Next */
- NextEntry = NextEntry->Flink;
- }
-
- /* Free the initial array */
- ExFreePool(EntryArray);
-
- /* FIXME: Might not need to keep the HAL/Kernel imports around */
-
- /* Kernel and HAL are loaded at boot */
- KernelEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
- HalEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
-
- /* All worked well */
- return STATUS_SUCCESS;
-}
-
-VOID
-NTAPI
-MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
-{
- ULONG_PTR DllBase;
- PIMAGE_NT_HEADERS NtHeaders;
- PIMAGE_SECTION_HEADER SectionHeader;
- ULONG Sections, Size;
-
- /* Get the kernel section header */
- DllBase = (ULONG_PTR)LdrEntry->DllBase;
- NtHeaders = RtlImageNtHeader((PVOID)DllBase);
- SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
-
- /* Loop all the sections */
- Sections = NtHeaders->FileHeader.NumberOfSections;
- while (Sections)
- {
- /* Grab the size of the section */
- Size = max(SectionHeader->SizeOfRawData, SectionHeader->Misc.VirtualSize);
-
- /* Check for .RSRC section */
- if (*(PULONG)SectionHeader->Name == 'rsr.')
- {
- /* Remember the PTEs so we can modify them later */
- MiKernelResourceStartPte = MiAddressToPte(DllBase +
- SectionHeader->VirtualAddress);
- MiKernelResourceEndPte = MiKernelResourceStartPte +
- BYTES_TO_PAGES(SectionHeader->VirtualAddress + Size);
- }
- else if (*(PULONG)SectionHeader->Name == 'LOOP')
- {
- /* POOLCODE vs. POOLMI */
- if (*(PULONG)&SectionHeader->Name[4] == 'EDOC')
- {
- /* Found Ex* Pool code */
- ExPoolCodeStart = DllBase + SectionHeader->VirtualAddress;
- ExPoolCodeEnd = ExPoolCodeStart + Size;
- }
- else if (*(PUSHORT)&SectionHeader->Name[4] == 'MI')
- {
- /* Found Mm* Pool code */
- MmPoolCodeStart = DllBase + SectionHeader->VirtualAddress;
- MmPoolCodeEnd = ExPoolCodeStart + Size;
- }
- }
- else if ((*(PULONG)SectionHeader->Name == 'YSIM') &&
- (*(PULONG)&SectionHeader->Name[4] == 'ETPS'))
- {
- /* Found MISYSPTE (Mm System PTE code)*/
- MmPteCodeStart = DllBase + SectionHeader->VirtualAddress;
- MmPteCodeEnd = ExPoolCodeStart + Size;
- }
-
- /* Keep going */
- Sections--;
- SectionHeader++;
- }
-}
-
-BOOLEAN
-NTAPI
-MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
-{
- PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
- PLIST_ENTRY ListHead, NextEntry;
- ULONG EntrySize;
-
- /* Setup the loaded module list and locks */
- ExInitializeResourceLite(&PsLoadedModuleResource);
- KeInitializeSpinLock(&PsLoadedModuleSpinLock);
- InitializeListHead(&PsLoadedModuleList);
-
- /* Get loop variables and the kernel entry */
- ListHead = &LoaderBlock->LoadOrderListHead;
- NextEntry = ListHead->Flink;
- LdrEntry = CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
- PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
-
- /* Locate resource section, pool code, and system pte code */
- MiLocateKernelSections(LdrEntry);
-
- /* Loop the loader block */
- while (NextEntry != ListHead)
- {
- /* Get the loader entry */
- LdrEntry = CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
-
- /* FIXME: ROS HACK. Make sure this is a driver */
- if (!RtlImageNtHeader(LdrEntry->DllBase))
- {
- /* Skip this entry */
- NextEntry = NextEntry->Flink;
- continue;
- }
-
- /* Calculate the size we'll need and allocate a copy */
- EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
- LdrEntry->BaseDllName.MaximumLength +
- sizeof(UNICODE_NULL);
- NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);
- if (!NewEntry) return FALSE;
-
- /* Copy the entry over */
- *NewEntry = *LdrEntry;
-
- /* Allocate the name */
- NewEntry->FullDllName.Buffer =
- ExAllocatePoolWithTag(PagedPool,
- LdrEntry->FullDllName.MaximumLength +
- sizeof(UNICODE_NULL),
- TAG_LDR_WSTR);
- if (!NewEntry->FullDllName.Buffer) return FALSE;
-
- /* Set the base name */
- NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
-
- /* Copy the full and base name */
- RtlCopyMemory(NewEntry->FullDllName.Buffer,
- LdrEntry->FullDllName.Buffer,
- LdrEntry->FullDllName.MaximumLength);
- RtlCopyMemory(NewEntry->BaseDllName.Buffer,
- LdrEntry->BaseDllName.Buffer,
- LdrEntry->BaseDllName.MaximumLength);
-
- /* Null-terminate the base name */
- NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
- sizeof(WCHAR)] = UNICODE_NULL;
-
- /* Insert the entry into the list */
- InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
- NextEntry = NextEntry->Flink;
- }
-
- /* Build the import lists for the boot drivers */
- MiBuildImportsForBootDrivers();
-
- /* We're done */
- return TRUE;
-}
-
-LOGICAL
-NTAPI
-MiUseLargeDriverPage(IN ULONG NumberOfPtes,
- IN OUT PVOID *ImageBaseAddress,
- IN PUNICODE_STRING BaseImageName,
- IN BOOLEAN BootDriver)
-{
- PLIST_ENTRY NextEntry;
- BOOLEAN DriverFound = FALSE;
- PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry;
- ASSERT(KeGetCurrentIrql () <= APC_LEVEL);
- ASSERT(*ImageBaseAddress >= MmSystemRangeStart);
-
-#ifdef _X86_
- if (!(KeFeatureBits & KF_LARGE_PAGE)) return FALSE;
- if (!(__readcr4() & CR4_PSE)) return FALSE;
-#endif
-
- /* Make sure there's enough system PTEs for a large page driver */
- if (MmTotalFreeSystemPtes[SystemPteSpace] < (16 * (PDE_MAPPED_VA >> PAGE_SHIFT)))
- {
- return FALSE;
- }
-
- /* This happens if the registry key had a "*" (wildcard) in it */
- if (MiLargePageAllDrivers == 0)
- {
- /* It didn't, so scan the list */
- NextEntry = MiLargePageDriverList.Flink;
- while (NextEntry != &MiLargePageDriverList)
- {
- /* Check if the driver name matches */
- LargePageDriverEntry = CONTAINING_RECORD(NextEntry,
- MI_LARGE_PAGE_DRIVER_ENTRY,
- Links);
- if (RtlEqualUnicodeString(BaseImageName,
- &LargePageDriverEntry->BaseName,
- TRUE))
- {
- /* Enable large pages for this driver */
- DriverFound = TRUE;
- break;
- }
-
- /* Keep trying */
- NextEntry = NextEntry->Flink;
- }
-
- /* If we didn't find the driver, it doesn't need large pages */
- if (DriverFound == FALSE) return FALSE;
- }
-
- /* Nothing to do yet */
- DPRINT1("Large pages not supported!\n");
- return FALSE;
-}
-
-ULONG
-NTAPI
-MiComputeDriverProtection(IN BOOLEAN SessionSpace,
- IN ULONG SectionProtection)
-{
- ULONG Protection = MM_ZERO_ACCESS;
-
- /* Check if the caller gave anything */
- if (SectionProtection)
- {
- /* Always turn on execute access */
- SectionProtection |= IMAGE_SCN_MEM_EXECUTE;
-
- /* Check if the registry setting is on or not */
- if (!MmEnforceWriteProtection)
- {
- /* Turn on write access too */
- SectionProtection |= (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE);
- }
- }
-
- /* Convert to internal PTE flags */
- if (SectionProtection & IMAGE_SCN_MEM_EXECUTE) Protection |= MM_EXECUTE;
- if (SectionProtection & IMAGE_SCN_MEM_READ) Protection |= MM_READONLY;
-
- /* Check for write access */
- if (SectionProtection & IMAGE_SCN_MEM_WRITE)
- {
- /* Session space is not supported */
- if (SessionSpace)
- {
- DPRINT1("Session drivers not supported\n");
- ASSERT(SessionSpace == FALSE);
- }
- else
- {
- /* Convert to internal PTE flag */
- Protection = (Protection & MM_EXECUTE) ? MM_EXECUTE_READWRITE : MM_READWRITE;
- }
- }
-
- /* If there's no access at all by now, convert to internal no access flag */
- if (Protection == MM_ZERO_ACCESS) Protection = MM_NOACCESS;
-
- /* Return the computed PTE protection */
- return Protection;
-}
-
-VOID
-NTAPI
-MiSetSystemCodeProtection(IN PMMPTE FirstPte,
- IN PMMPTE LastPte,
- IN ULONG ProtectionMask)
-{
- /* I'm afraid to introduce regressions at the moment... */
- return;
-}
-
-VOID
-NTAPI
-MiWriteProtectSystemImage(IN PVOID ImageBase)
-{
- PIMAGE_NT_HEADERS NtHeaders;
- PIMAGE_SECTION_HEADER Section;
- PFN_NUMBER DriverPages;
- ULONG CurrentProtection, SectionProtection, CombinedProtection, ProtectionMask;
- ULONG Sections, Size;
- ULONG_PTR BaseAddress, CurrentAddress;
- PMMPTE PointerPte, StartPte, LastPte, CurrentPte, ComboPte = NULL;
- ULONG CurrentMask, CombinedMask = 0;
- PAGED_CODE();
-
- /* No need to write protect physical memory-backed drivers (large pages) */
- if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return;
-
- /* Get the image headers */
- NtHeaders = RtlImageNtHeader(ImageBase);
- if (!NtHeaders) return;
-
- /* Check if this is a session driver or not */
- if (!MI_IS_SESSION_ADDRESS(ImageBase))
- {
- /* Don't touch NT4 drivers */
- if (NtHeaders->OptionalHeader.MajorOperatingSystemVersion < 5) return;
- if (NtHeaders->OptionalHeader.MajorImageVersion < 5) return;
- }
- else
- {
- /* Not supported */
- DPRINT1("Session drivers not supported\n");
- ASSERT(FALSE);
- }
-
- /* These are the only protection masks we care about */
- ProtectionMask = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
-
- /* Calculate the number of pages this driver is occupying */
- DriverPages = BYTES_TO_PAGES(NtHeaders->OptionalHeader.SizeOfImage);
-
- /* Get the number of sections and the first section header */
- Sections = NtHeaders->FileHeader.NumberOfSections;
- ASSERT(Sections != 0);
- Section = IMAGE_FIRST_SECTION(NtHeaders);
-
- /* Loop all the sections */
- CurrentAddress = (ULONG_PTR)ImageBase;
- while (Sections)
- {
- /* Get the section size */
- Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
-
- /* Get its virtual address */
- BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress;
- if (BaseAddress < CurrentAddress)
- {
- /* Windows doesn't like these */
- DPRINT1("Badly linked image!\n");
- return;
- }
-
- /* Remember the current address */
- CurrentAddress = BaseAddress + Size - 1;
-
- /* Next */
- Sections--;
- Section++;
- }
-
- /* Get the number of sections and the first section header */
- Sections = NtHeaders->FileHeader.NumberOfSections;
- ASSERT(Sections != 0);
- Section = IMAGE_FIRST_SECTION(NtHeaders);
-
- /* Set the address at the end to initialize the loop */
- CurrentAddress = (ULONG_PTR)Section + Sections - 1;
- CurrentProtection = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
-
- /* Set the PTE points for the image, and loop its sections */
- StartPte = MiAddressToPte(ImageBase);
- LastPte = StartPte + DriverPages;
- while (Sections)
- {
- /* Get the section size */
- Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
-
- /* Get its virtual address and PTE */
- BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress;
- PointerPte = MiAddressToPte(BaseAddress);
-
- /* Check if we were already protecting a run, and found a new run */
- if ((ComboPte) && (PointerPte > ComboPte))
- {
- /* Compute protection */
- CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection);
-
- /* Set it */
- MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask);
-
- /* Check for overlap */
- if (ComboPte == StartPte) StartPte++;
-
- /* One done, reset variables */
- ComboPte = NULL;
- CombinedProtection = 0;
- }
-
- /* Break out when needed */
- if (PointerPte >= LastPte) break;
-
- /* Get the requested protection from the image header */
- SectionProtection = Section->Characteristics & ProtectionMask;
- if (SectionProtection == CurrentProtection)
- {
- /* Same protection, so merge the request */
- CurrentAddress = BaseAddress + Size - 1;
-
- /* Next */
- Sections--;
- Section++;
- continue;
- }
-
- /* This is now a new section, so close up the old one */
- CurrentPte = MiAddressToPte(CurrentAddress);
-
- /* Check for overlap */
- if (CurrentPte == PointerPte)
- {
- /* Skip the last PTE, since it overlaps with us */
- CurrentPte--;
-
- /* And set the PTE we will merge with */
- ASSERT((ComboPte == NULL) || (ComboPte == PointerPte));
- ComboPte = PointerPte;
-
- /* Get the most flexible protection by merging both */
- CombinedMask |= (SectionProtection | CurrentProtection);
- }
-
- /* Loop any PTEs left */
- if (CurrentPte >= StartPte)
- {
- /* Sanity check */
- ASSERT(StartPte < LastPte);
-
- /* Make sure we don't overflow past the last PTE in the driver */
- if (CurrentPte >= LastPte) CurrentPte = LastPte - 1;
- ASSERT(CurrentPte >= StartPte);
-
- /* Compute the protection and set it */
- CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection);
- MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask);
- }
-
- /* Set new state */
- StartPte = PointerPte;
- CurrentAddress = BaseAddress + Size - 1;
- CurrentProtection = SectionProtection;
-
- /* Next */
- Sections--;
- Section++;
- }
-
- /* Is there a leftover section to merge? */
- if (ComboPte)
- {
- /* Compute and set the protection */
- CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection);
- MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask);
-
- /* Handle overlap */
- if (ComboPte == StartPte) StartPte++;
- }
-
- /* Finally, handle the last section */
- CurrentPte = MiPteToAddress(CurrentAddress);
- if ((StartPte < LastPte) && (CurrentPte >= StartPte))
- {
- /* Handle overlap */
- if (CurrentPte >= LastPte) CurrentPte = LastPte - 1;
- ASSERT(CurrentPte >= StartPte);
-
- /* Compute and set the protection */
- CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection);
- MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask);
- }
-}
-
-VOID
-NTAPI
-MiSetPagingOfDriver(IN PMMPTE PointerPte,
- IN PMMPTE LastPte)
-{
- PVOID ImageBase;
- PETHREAD CurrentThread;
- PFN_NUMBER PageCount = 0, PageFrameIndex;
- PMMPFN Pfn1;
- PAGED_CODE();
-
- /* Get the driver's base address */
- ImageBase = MiPteToAddress(PointerPte);
- ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase) == FALSE);
-
- /* If this is a large page, it's stuck in physical memory */
- if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return;
-
- /* We should lock the system working set -- we don't have one yet, so just be consistent */
- CurrentThread = PsGetCurrentThread();
- KeEnterGuardedRegion();
- ASSERT((CurrentThread->OwnsSystemWorkingSetExclusive == 0) &&
- (CurrentThread->OwnsSystemWorkingSetShared == 0));
- CurrentThread->OwnsSystemWorkingSetExclusive = 1;
-
- /* Loop the PTEs */
- while (PointerPte <= LastPte)
- {
- /* Check for valid PTE */
- if (PointerPte->u.Hard.Valid == 1)
- {
- PageFrameIndex = PFN_FROM_PTE(PointerPte);
- Pfn1 = MiGetPfnEntry(PageFrameIndex);
- ASSERT(Pfn1->u2.ShareCount == 1);
-
- /* No working sets in ReactOS yet */
- PageCount++;
- }
-
- ImageBase = (PVOID)((ULONG_PTR)ImageBase + PAGE_SIZE);
- PointerPte++;
- }
-
- /* Release the working set "lock" */
- ASSERT(KeAreAllApcsDisabled() == TRUE);
- CurrentThread->OwnsSystemWorkingSetExclusive = 0;
- KeLeaveGuardedRegion();
-
- /* Do we have any driver pages? */
- if (PageCount)
- {
- /* Update counters */
- InterlockedExchangeAdd((PLONG)&MmTotalSystemDriverPages, PageCount);
- }
-}
-
-VOID
-NTAPI
-MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
-{
- ULONG_PTR ImageBase;
- PIMAGE_NT_HEADERS NtHeaders;
- ULONG Sections, Alignment, Size;
- PIMAGE_SECTION_HEADER Section;
- PMMPTE PointerPte = NULL, LastPte = NULL;
- if (MmDisablePagingExecutive) return;
-
- /* Get the driver base address and its NT header */
- ImageBase = (ULONG_PTR)LdrEntry->DllBase;
- NtHeaders = RtlImageNtHeader((PVOID)ImageBase);
- if (!NtHeaders) return;
-
- /* Get the sections and their alignment */
- Sections = NtHeaders->FileHeader.NumberOfSections;
- Alignment = NtHeaders->OptionalHeader.SectionAlignment - 1;
-
- /* Loop each section */
- Section = IMAGE_FIRST_SECTION(NtHeaders);
- while (Sections)
- {
- /* Find PAGE or .edata */
- if ((*(PULONG)Section->Name == 'EGAP') ||
- (*(PULONG)Section->Name == 'ade.'))
- {
- /* Had we already done some work? */
- if (!PointerPte)
- {
- /* Nope, setup the first PTE address */
- PointerPte = MiAddressToPte(ROUND_TO_PAGES(ImageBase +
- Section->
- VirtualAddress));
- }
-
- /* Compute the size */
- Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
-
- /* Find the last PTE that maps this section */
- LastPte = MiAddressToPte(ImageBase +
- Section->VirtualAddress +
- Alignment +
- Size -
- PAGE_SIZE);
- }
- else
- {
- /* Had we found a section before? */
- if (PointerPte)
- {
- /* Mark it as pageable */
- MiSetPagingOfDriver(PointerPte, LastPte);
- PointerPte = NULL;
- }
- }
-
- /* Keep searching */
- Sections--;
- Section++;
- }
-
- /* Handle the straggler */
- if (PointerPte) MiSetPagingOfDriver(PointerPte, LastPte);
-}
-
-BOOLEAN
-NTAPI
-MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)
-{
- PIMAGE_NT_HEADERS NtHeader;
- PAGED_CODE();
-
- /* Get NT Headers */
- NtHeader = RtlImageNtHeader(BaseAddress);
- if (NtHeader)
- {
- /* Check if this image is only safe for UP while we have 2+ CPUs */
- if ((KeNumberProcessors > 1) &&
- (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))
- {
- /* Fail */
- return FALSE;
- }
- }
-
- /* Otherwise, it's safe */
- return TRUE;
-}
-
-NTSTATUS
-NTAPI
-MmCheckSystemImage(IN HANDLE ImageHandle,
- IN BOOLEAN PurgeSection)
-{
- NTSTATUS Status;
- HANDLE SectionHandle;
- PVOID ViewBase = NULL;
- SIZE_T ViewSize = 0;
- IO_STATUS_BLOCK IoStatusBlock;
- FILE_STANDARD_INFORMATION FileStandardInfo;
- KAPC_STATE ApcState;
- PIMAGE_NT_HEADERS NtHeaders;
- OBJECT_ATTRIBUTES ObjectAttributes;
- PAGED_CODE();
-
- /* Setup the object attributes */
- InitializeObjectAttributes(&ObjectAttributes,
- NULL,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- NULL,
- NULL);
-
- /* Create a section for the DLL */
- Status = ZwCreateSection(&SectionHandle,
- SECTION_MAP_EXECUTE,
- &ObjectAttributes,
- NULL,
- PAGE_EXECUTE,
- SEC_IMAGE,
- ImageHandle);
- if (!NT_SUCCESS(Status)) return Status;
-
- /* Make sure we're in the system process */
- KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
-
- /* Map it */
- Status = ZwMapViewOfSection(SectionHandle,
- NtCurrentProcess(),
- &ViewBase,
- 0,
- 0,
- NULL,
- &ViewSize,
- ViewShare,
- 0,
- PAGE_EXECUTE);
- if (!NT_SUCCESS(Status))
- {
- /* We failed, close the handle and return */
- KeUnstackDetachProcess(&ApcState);
- ZwClose(SectionHandle);
- return Status;
- }
-
- /* Now query image information */
- Status = ZwQueryInformationFile(ImageHandle,
- &IoStatusBlock,
- &FileStandardInfo,
- sizeof(FileStandardInfo),
- FileStandardInformation);
- if (NT_SUCCESS(Status))
- {
- /* First, verify the checksum */
- if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,
- ViewSize,
- FileStandardInfo.
- EndOfFile.LowPart))
- {
- /* Set checksum failure */
- Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
- goto Fail;
- }
-
- /* Make sure it's a real image */
- NtHeaders = RtlImageNtHeader(ViewBase);
- if (!NtHeaders)
- {
- /* Set checksum failure */
- Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
- goto Fail;
- }
-
- /* Make sure it's for the correct architecture */
- if ((NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_NATIVE) ||
- (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC))
- {
- /* Set protection failure */
- Status = STATUS_INVALID_IMAGE_PROTECT;
- goto Fail;
- }
-
- /* Check that it's a valid SMP image if we have more then one CPU */
- if (!MmVerifyImageIsOkForMpUse(ViewBase))
- {
- /* Otherwise it's not the right image */
- Status = STATUS_IMAGE_MP_UP_MISMATCH;
- }
- }
-
- /* Unmap the section, close the handle, and return status */
-Fail:
- ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);
- KeUnstackDetachProcess(&ApcState);
- ZwClose(SectionHandle);
- return Status;
-}
-
-NTSTATUS
-NTAPI
-MmLoadSystemImage(IN PUNICODE_STRING FileName,
- IN PUNICODE_STRING NamePrefix OPTIONAL,
- IN PUNICODE_STRING LoadedName OPTIONAL,
- IN ULONG Flags,
- OUT PVOID *ModuleObject,
- OUT PVOID *ImageBaseAddress)
-{
- PVOID ModuleLoadBase = NULL;
- NTSTATUS Status;
- HANDLE FileHandle = NULL;
- OBJECT_ATTRIBUTES ObjectAttributes;
- IO_STATUS_BLOCK IoStatusBlock;
- PIMAGE_NT_HEADERS NtHeader;
- UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;
- PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
- ULONG EntrySize, DriverSize;
- PLOAD_IMPORTS LoadedImports = MM_SYSLDR_NO_IMPORTS;
- PCHAR MissingApiName, Buffer;
- PWCHAR MissingDriverName;
- HANDLE SectionHandle;
- ACCESS_MASK DesiredAccess;
- PVOID Section = NULL;
- BOOLEAN LockOwned = FALSE;
- PLIST_ENTRY NextEntry;
- IMAGE_INFO ImageInfo;
- STRING AnsiTemp;
- PAGED_CODE();
-
- /* Detect session-load */
- if (Flags)
- {
- /* Sanity checks */
- ASSERT(NamePrefix == NULL);
- ASSERT(LoadedName == NULL);
-
- /* Make sure the process is in session too */
- if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
- }
-
- /* Allocate a buffer we'll use for names */
- Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, 'nLmM');
- if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
-
- /* Check for a separator */
- if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
- {
- PWCHAR p;
- ULONG BaseLength;
-
- /* Loop the path until we get to the base name */
- p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
- while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
-
- /* Get the length */
- BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
- BaseLength *= sizeof(WCHAR);
-
- /* Setup the string */
- BaseName.Length = (USHORT)BaseLength;
- BaseName.Buffer = p;
- }
- else
- {
- /* Otherwise, we already have a base name */
- BaseName.Length = FileName->Length;
- BaseName.Buffer = FileName->Buffer;
- }
-
- /* Setup the maximum length */
- BaseName.MaximumLength = BaseName.Length;
-
- /* Now compute the base directory */
- BaseDirectory = *FileName;
- BaseDirectory.Length -= BaseName.Length;
- BaseDirectory.MaximumLength = BaseDirectory.Length;
-
- /* And the prefix, which for now is just the name itself */
- PrefixName = *FileName;
-
- /* Check if we have a prefix */
- if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");
-
- /* Check if we already have a name, use it instead */
- if (LoadedName) BaseName = *LoadedName;
-
- /* Check for loader snap debugging */
- if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS)
- {
- /* Print out standard string */
- DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
- &PrefixName, &BaseName, Flags ? "in session space" : "");
- }
-
- /* Acquire the load lock */
-LoaderScan:
- ASSERT(LockOwned == FALSE);
- LockOwned = TRUE;
- KeEnterCriticalRegion();
- KeWaitForSingleObject(&MmSystemLoadLock,
- WrVirtualMemory,
- KernelMode,
- FALSE,
- NULL);
-
- /* Scan the module list */
- NextEntry = PsLoadedModuleList.Flink;
- while (NextEntry != &PsLoadedModuleList)
- {
- /* Get the entry and compare the names */
- LdrEntry = CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
- if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))
- {
- /* Found it, break out */
- break;
- }
-
- /* Keep scanning */
- NextEntry = NextEntry->Flink;
- }
-
- /* Check if we found the image */
- if (NextEntry != &PsLoadedModuleList)
- {
- /* Check if we had already mapped a section */
- if (Section)
- {
- /* Dereference and clear */
- ObDereferenceObject(Section);
- Section = NULL;
- }
-
- /* Check if this was supposed to be a session load */
- if (!Flags)
- {
- /* It wasn't, so just return the data */
- *ModuleObject = LdrEntry;
- *ImageBaseAddress = LdrEntry->DllBase;
- Status = STATUS_IMAGE_ALREADY_LOADED;
- }
- else
- {
- /* We don't support session loading yet */
- DPRINT1("Unsupported Session-Load!\n");
- while (TRUE);
- }
-
- /* Do cleanup */
- goto Quickie;
- }
- else if (!Section)
- {
- /* It wasn't loaded, and we didn't have a previous attempt */
- KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
- KeLeaveCriticalRegion();
- LockOwned = FALSE;
-
- /* Check if KD is enabled */
- if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))
- {
- /* FIXME: Attempt to get image from KD */
- }
-
- /* We don't have a valid entry */
- LdrEntry = NULL;
-
- /* Setup image attributes */
- InitializeObjectAttributes(&ObjectAttributes,
- FileName,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- NULL,
- NULL);
-
- /* Open the image */
- Status = ZwOpenFile(&FileHandle,
- FILE_EXECUTE,
- &ObjectAttributes,
- &IoStatusBlock,
- FILE_SHARE_READ | FILE_SHARE_DELETE,
- 0);
- if (!NT_SUCCESS(Status)) goto Quickie;
-
- /* Validate it */
- Status = MmCheckSystemImage(FileHandle, FALSE);
- if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||
- (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||
- (Status == STATUS_INVALID_IMAGE_PROTECT))
- {
- /* Fail loading */
- goto Quickie;
- }
-
- /* Check if this is a session-load */
- if (Flags)
- {
- /* Then we only need read and execute */
- DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;
- }
- else
- {
- /* Otherwise, we can allow write access */
- DesiredAccess = SECTION_ALL_ACCESS;
- }
-
- /* Initialize the attributes for the section */
- InitializeObjectAttributes(&ObjectAttributes,
- NULL,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- NULL,
- NULL);
-
- /* Create the section */
- Status = ZwCreateSection(&SectionHandle,
- DesiredAccess,
- &ObjectAttributes,
- NULL,
- PAGE_EXECUTE,
- SEC_IMAGE,
- FileHandle);
- if (!NT_SUCCESS(Status)) goto Quickie;
-
- /* Now get the section pointer */
- Status = ObReferenceObjectByHandle(SectionHandle,
- SECTION_MAP_EXECUTE,
- MmSectionObjectType,
- KernelMode,
- &Section,
- NULL);
- ZwClose(SectionHandle);
- if (!NT_SUCCESS(Status)) goto Quickie;
-
- /* Check if this was supposed to be a session-load */
- if (Flags)
- {
- /* We don't support session loading yet */
- DPRINT1("Unsupported Session-Load!\n");
- while (TRUE);
- }
-
- /* Check the loader list again, we should end up in the path below */
- goto LoaderScan;
- }
- else
- {
- /* We don't have a valid entry */
- LdrEntry = NULL;
- }
-
- /* Load the image */
- Status = MiLoadImageSection(&Section,
- &ModuleLoadBase,
- FileName,
- FALSE,
- NULL);
- ASSERT(Status != STATUS_ALREADY_COMMITTED);
-
- /* Get the size of the driver */
- DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
-
- /* Make sure we're not being loaded into session space */
- if (!Flags)
- {
- /* Check for success */
- if (NT_SUCCESS(Status))
- {
- /* Support large pages for drivers */
- MiUseLargeDriverPage(DriverSize / PAGE_SIZE,
- &ModuleLoadBase,
- &BaseName,
- TRUE);
- }
-
- /* Dereference the section */
- ObDereferenceObject(Section);
- Section = NULL;
- }
-
- /* Check for failure of the load earlier */
- if (!NT_SUCCESS(Status)) goto Quickie;
-
- /* Relocate the driver */
- Status = LdrRelocateImageWithBias(ModuleLoadBase,
- 0,
- "SYSLDR",
- STATUS_SUCCESS,
- STATUS_CONFLICTING_ADDRESSES,
- STATUS_INVALID_IMAGE_FORMAT);
- if (!NT_SUCCESS(Status)) goto Quickie;
-
-
- /* Get the NT Header */
- NtHeader = RtlImageNtHeader(ModuleLoadBase);
-
- /* Calculate the size we'll need for the entry and allocate it */
- EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
- BaseName.Length +
- sizeof(UNICODE_NULL);
-
- /* Allocate the entry */
- LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
- if (!LdrEntry)
- {
- /* Fail */
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto Quickie;
- }
-
- /* Setup the entry */
- LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
- LdrEntry->LoadCount = 1;
- LdrEntry->LoadedImports = LoadedImports;
- LdrEntry->PatchInformation = NULL;
-
- /* Check the version */
- if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
- (NtHeader->OptionalHeader.MajorImageVersion >= 5))
- {
- /* Mark this image as a native image */
- LdrEntry->Flags |= LDRP_ENTRY_NATIVE;
- }
-
- /* Setup the rest of the entry */
- LdrEntry->DllBase = ModuleLoadBase;
- LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +
- NtHeader->OptionalHeader.AddressOfEntryPoint);
- LdrEntry->SizeOfImage = DriverSize;
- LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
- LdrEntry->SectionPointer = Section;
-
- /* Now write the DLL name */
- LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
- LdrEntry->BaseDllName.Length = BaseName.Length;
- LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
-
- /* Copy and null-terminate it */
- RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
- BaseName.Buffer,
- BaseName.Length);
- LdrEntry->BaseDllName.Buffer[BaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
-
- /* Now allocate the full name */
- LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
- PrefixName.Length +
- sizeof(UNICODE_NULL),
- TAG_LDR_WSTR);
- if (!LdrEntry->FullDllName.Buffer)
- {
- /* Don't fail, just set it to zero */
- LdrEntry->FullDllName.Length = 0;
- LdrEntry->FullDllName.MaximumLength = 0;
- }
- else
- {
- /* Set it up */
- LdrEntry->FullDllName.Length = PrefixName.Length;
- LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
-
- /* Copy and null-terminate */
- RtlCopyMemory(LdrEntry->FullDllName.Buffer,
- PrefixName.Buffer,
- PrefixName.Length);
- LdrEntry->FullDllName.Buffer[PrefixName.Length / sizeof(WCHAR)] = UNICODE_NULL;
- }
-
- /* Add the entry */
- MiProcessLoaderEntry(LdrEntry, TRUE);
-
- /* Resolve imports */
- MissingApiName = Buffer;
- Status = MiResolveImageReferences(ModuleLoadBase,
- &BaseDirectory,
- NULL,
- &MissingApiName,
- &MissingDriverName,
- &LoadedImports);
- if (!NT_SUCCESS(Status))
- {
- /* Fail */
- MiProcessLoaderEntry(LdrEntry, FALSE);
-
- /* Check if we need to free the name */
- if (LdrEntry->FullDllName.Buffer)
- {
- /* Free it */
- ExFreePool(LdrEntry->FullDllName.Buffer);
- }
-
- /* Free the entry itself */
- ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
- LdrEntry = NULL;
- goto Quickie;
- }
-
- /* Update the loader entry */
- LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |
- LDRP_ENTRY_PROCESSED |
- LDRP_MM_LOADED);
- LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
- LdrEntry->LoadedImports = LoadedImports;
-
- /* FIXME: Call driver verifier's loader function */
-
- /* Write-protect the system image */
- MiWriteProtectSystemImage(LdrEntry->DllBase);
-
- /* Check if notifications are enabled */
- if (PsImageNotifyEnabled)
- {
- /* Fill out the notification data */
- ImageInfo.Properties = 0;
- ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
- ImageInfo.SystemModeImage = TRUE;
- ImageInfo.ImageSize = LdrEntry->SizeOfImage;
- ImageInfo.ImageBase = LdrEntry->DllBase;
- ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;
-
- /* Send the notification */
- PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);
- }
-
-#if defined(KDBG) || defined(_WINKD_)
- /* MiCacheImageSymbols doesn't detect rossym */
- if (TRUE)
-#else
- /* Check if there's symbols */
- if (MiCacheImageSymbols(LdrEntry->DllBase))
-#endif
- {
- /* Check if the system root is present */
- if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&
- !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))
- {
- /* Add the system root */
- UnicodeTemp = PrefixName;
- UnicodeTemp.Buffer += 11;
- UnicodeTemp.Length -= (11 * sizeof(WCHAR));
- sprintf_nt(Buffer,
- "%ws%wZ",
- &SharedUserData->NtSystemRoot[2],
- &UnicodeTemp);
- }
- else
- {
- /* Build the name */
- sprintf_nt(Buffer, "%wZ", &BaseName);
- }
-
- /* Setup the ansi string */
- RtlInitString(&AnsiTemp, Buffer);
-
- /* Notify the debugger */
- DbgLoadImageSymbols(&AnsiTemp,
- LdrEntry->DllBase,
- (ULONG_PTR)ZwCurrentProcess());
- LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
- }
-
- /* Page the driver */
- ASSERT(Section == NULL);
- MiEnablePagingOfDriver(LdrEntry);
-
- /* Return pointers */
- *ModuleObject = LdrEntry;
- *ImageBaseAddress = LdrEntry->DllBase;
-
-Quickie:
- /* Check if we have the lock acquired */
- if (LockOwned)
- {
- /* Release the lock */
- KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
- KeLeaveCriticalRegion();
- LockOwned = FALSE;
- }
-
- /* If we have a file handle, close it */
- if (FileHandle) ZwClose(FileHandle);
-
- /* Check if we had a prefix */
- if (NamePrefix) ExFreePool(PrefixName.Buffer);
-
- /* Free the name buffer and return status */
- ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
- return Status;
-}
-
-PLDR_DATA_TABLE_ENTRY
-NTAPI
-MiLookupDataTableEntry(IN PVOID Address)
-{
- PLDR_DATA_TABLE_ENTRY LdrEntry, FoundEntry = NULL;
- PLIST_ENTRY NextEntry;
- PAGED_CODE();
-
- /* Loop entries */
- NextEntry = PsLoadedModuleList.Flink;
- do
- {
- /* Get the loader entry */
- LdrEntry = CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
-
- /* Check if the address matches */
- if ((Address >= LdrEntry->DllBase) &&
- (Address < (PVOID)((ULONG_PTR)LdrEntry->DllBase +
- LdrEntry->SizeOfImage)))
- {
- /* Found a match */
- FoundEntry = LdrEntry;
- break;
- }
-
- /* Move on */
- NextEntry = NextEntry->Flink;
- } while(NextEntry != &PsLoadedModuleList);
-
- /* Return the entry */
- return FoundEntry;
-}
-
-/* PUBLIC FUNCTIONS ***********************************************************/
-
-/*
- * @implemented
- */
-PVOID
-NTAPI
-MmPageEntireDriver(IN PVOID AddressWithinSection)
-{
- PMMPTE StartPte, EndPte;
- PLDR_DATA_TABLE_ENTRY LdrEntry;
- PAGED_CODE();
-
- /* Get the loader entry */
- LdrEntry = MiLookupDataTableEntry(AddressWithinSection);
- if (!LdrEntry) return NULL;
-
- /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
- if ((MmDisablePagingExecutive) || (LdrEntry->SectionPointer))
- {
- /* Don't do anything, just return the base address */
- return LdrEntry->DllBase;
- }
-
- /* Wait for active DPCs to finish before we page out the driver */
- KeFlushQueuedDpcs();
-
- /* Get the PTE range for the whole driver image */
- StartPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase);
- EndPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage);
-
- /* Enable paging for the PTE range */
- ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection) == FALSE);
- MiSetPagingOfDriver(StartPte, EndPte);
-
- /* Return the base address */
- return LdrEntry->DllBase;
-}
-
-/*
- * @unimplemented
- */
-VOID
-NTAPI
-MmResetDriverPaging(IN PVOID AddressWithinSection)
-{
- UNIMPLEMENTED;
-}
-
-/*
- * @implemented
- */
-PVOID
-NTAPI
-MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
-{
- PVOID ProcAddress = NULL;
- ANSI_STRING AnsiRoutineName;
- NTSTATUS Status;
- PLIST_ENTRY NextEntry;
- PLDR_DATA_TABLE_ENTRY LdrEntry;
- BOOLEAN Found = FALSE;
- UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
- UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
- ULONG Modules = 0;
-
- /* Convert routine to ansi name */
- Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,
- SystemRoutineName,
- TRUE);
- if (!NT_SUCCESS(Status)) return NULL;
-
- /* Lock the list */
- KeEnterCriticalRegion();
- ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE);
-
- /* Loop the loaded module list */
- NextEntry = PsLoadedModuleList.Flink;
- while (NextEntry != &PsLoadedModuleList)
- {
- /* Get the entry */
- LdrEntry = CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
-
- /* Check if it's the kernel or HAL */
- if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
- {
- /* Found it */
- Found = TRUE;
- Modules++;
- }
- else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
- {
- /* Found it */
- Found = TRUE;
- Modules++;
- }
-
- /* Check if we found a valid binary */
- if (Found)
- {
- /* Find the procedure name */
- ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,
- &AnsiRoutineName);
-
- /* Break out if we found it or if we already tried both modules */
- if (ProcAddress) break;
- if (Modules == 2) break;
- }
-
- /* Keep looping */
- NextEntry = NextEntry->Flink;
- }
-
- /* Release the lock */
- ExReleaseResourceLite(&PsLoadedModuleResource);
- KeLeaveCriticalRegion();
-
- /* Free the string and return */
- RtlFreeAnsiString(&AnsiRoutineName);
- return ProcAddress;
-}
-