PMMPTE PointerPte, LastPte;
PVOID DriverBase;
MMPTE TempPte;
+ KIRQL OldIrql;
+ PFN_NUMBER PageFrameIndex;
PAGED_CODE();
/* Detect session load */
if (SessionLoad)
{
/* Fail */
- DPRINT1("Session loading not yet supported!\n");
- while (TRUE);
+ UNIMPLEMENTED_DBGBREAK("Session loading not yet supported!\n");
+ return STATUS_NOT_IMPLEMENTED;
}
/* Not session load, shouldn't have an entry */
}
/* Reserve system PTEs needed */
- PteCount = ROUND_TO_PAGES(Section->ImageSection->ImageSize) >> PAGE_SHIFT;
+ PteCount = ROUND_TO_PAGES(Section->ImageSection->ImageInformation.ImageFileSize) >> PAGE_SHIFT;
PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
if (!PointerPte)
{
*ImageBase = DriverBase;
DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName, DriverBase, PteCount);
- /* Loop the new driver PTEs */
- TempPte = ValidKernelPte;
- while (PointerPte < LastPte)
- {
- /* Allocate a page */
- MI_SET_USAGE(MI_USAGE_DRIVER_PAGE);
+ /* Lock the PFN database */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Some debug stuff */
+ MI_SET_USAGE(MI_USAGE_DRIVER_PAGE);
#if MI_TRACE_PFNS
+ if (FileName->Buffer)
+ {
PWCHAR pos = NULL;
ULONG len = 0;
- if (FileName->Buffer)
- {
- pos = wcsrchr(FileName->Buffer, '\\');
- len = wcslen(pos) * sizeof(WCHAR);
- if (pos) snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos);
- }
+ pos = wcsrchr(FileName->Buffer, '\\');
+ len = wcslen(pos) * sizeof(WCHAR);
+ if (pos) snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos);
+ }
#endif
- TempPte.u.Hard.PageFrameNumber = MiAllocatePfn(PointerPte, MM_EXECUTE);
- /* Write it */
+ /* Loop the new driver PTEs */
+ TempPte = ValidKernelPte;
+ while (PointerPte < LastPte)
+ {
+ /* Make sure the PTE is not valid for whatever reason */
+ ASSERT(PointerPte->u.Hard.Valid == 0);
+
+ /* Grab a page */
+ PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
+
+ /* Initialize its PFN entry */
+ MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
+
+ /* Write the PTE */
+ TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
MI_WRITE_VALID_PTE(PointerPte, TempPte);
/* Move on */
PointerPte++;
}
+ /* Release the PFN lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
/* Copy the image */
RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT);
OldIrql = KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock);
/* Insert or remove from the list */
- Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :
- RemoveEntryList(&LdrEntry->InLoadOrderLinks);
+ if (Insert)
+ InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks);
+ else
+ RemoveEntryList(&LdrEntry->InLoadOrderLinks);
/* Release locks */
KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
InLoadOrderLinks);
/* Check if it matches */
- if (RtlPrefixString((PSTRING)&ForwarderName,
- (PSTRING)&LdrEntry->BaseDllName,
- TRUE))
+ if (RtlPrefixUnicodeString(&ForwarderName,
+ &LdrEntry->BaseDllName,
+ TRUE))
{
/* Get the forwarder export directory */
ForwardExportDirectory =
/* Unload the symbols */
DbgUnLoadImageSymbols(&TempName,
BaseAddress,
- (ULONG_PTR)ZwCurrentProcess());
+ (ULONG_PTR)PsGetCurrentProcessId());
RtlFreeAnsiString(&TempName);
}
}
OUT PWCHAR *MissingDriver,
OUT PLOAD_IMPORTS *LoadImports)
{
+ static UNICODE_STRING DriversFolderName = RTL_CONSTANT_STRING(L"drivers\\");
PCHAR MissingApiBuffer = *MissingApi, ImportName;
PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
__FUNCTION__, ImageBase, ImageFileDirectory);
+ /* No name string buffer yet */
+ NameString.Buffer = NULL;
+
/* Assume no imports */
*LoadImports = MM_SYSLDR_NO_IMPORTS;
if ((GdiLink) && (NormalLink))
{
/* It's not, it's importing stuff it shouldn't be! */
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
- return STATUS_PROCEDURE_NOT_FOUND;
+ Status = STATUS_PROCEDURE_NOT_FOUND;
+ goto Failure;
}
/* Check for user-mode printer or video card drivers, which don't belong */
!(_strnicmp(ImportName, "gdi32", sizeof("gdi32") - 1)))
{
/* This is not kernel code */
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
- return STATUS_PROCEDURE_NOT_FOUND;
+ Status = STATUS_PROCEDURE_NOT_FOUND;
+ goto Failure;
}
/* Check if this is a "core" import, which doesn't get referenced */
if (!NT_SUCCESS(Status))
{
/* Failed */
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
- return Status;
+ goto Failure;
}
/* We don't support name prefixes yet */
DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
DllName.MaximumLength,
TAG_LDR_WSTR);
- if (DllName.Buffer)
- {
- /* Setup the base length and copy it */
- DllName.Length = ImageFileDirectory->Length;
- RtlCopyMemory(DllName.Buffer,
- ImageFileDirectory->Buffer,
- ImageFileDirectory->Length);
-
- /* Now add the import name and null-terminate it */
- RtlAppendUnicodeStringToString(&DllName,
- &NameString);
- DllName.Buffer[DllName.Length / 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 */
- ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR);
- }
- else
- {
- /* Fill out the information for the error */
- *MissingDriver = DllName.Buffer;
- *(PULONG)MissingDriver |= 1;
- *MissingApi = NULL;
-
- DPRINT1("Failed to load dependency: %wZ\n", &DllName);
- }
- }
- else
+ if (!DllName.Buffer)
{
/* We're out of resources */
Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Failure;
}
- /* Check if we're OK until now */
- if (NT_SUCCESS(Status))
+ /* Add the import name to the base directory */
+ RtlCopyUnicodeString(&DllName, ImageFileDirectory);
+ RtlAppendUnicodeStringToString(&DllName,
+ &NameString);
+
+ /* Load the image */
+ Status = MmLoadSystemImage(&DllName,
+ NamePrefix,
+ NULL,
+ FALSE,
+ (PVOID *)&DllEntry,
+ &DllBase);
+
+ /* win32k / GDI drivers can also import from system32 folder */
+ if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) &&
+ (MI_IS_SESSION_ADDRESS(ImageBase) || 1)) // HACK
{
- /* We're now loaded */
- Loaded = TRUE;
+ /* Free the old name buffer */
+ ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR);
- /* Sanity check */
- ASSERT(DllBase == DllEntry->DllBase);
+ /* Calculate size for a string the adds 'drivers\' */
+ DllName.MaximumLength += DriversFolderName.Length;
- /* Call the initialization routines */
- Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
- if (!NT_SUCCESS(Status))
+ /* Allocate the new buffer */
+ DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
+ DllName.MaximumLength,
+ TAG_LDR_WSTR);
+ if (!DllName.Buffer)
{
- /* We failed, unload the image */
- MmUnloadSystemImage(DllEntry);
- DPRINT1("MmCallDllInitialize failed with status 0x%x\n", Status);
- while (TRUE);
- Loaded = FALSE;
+ /* We're out of resources */
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Failure;
}
+
+ /* Copy image directory and append 'drivers\' folder name */
+ RtlCopyUnicodeString(&DllName, ImageFileDirectory);
+ RtlAppendUnicodeStringToString(&DllName, &DriversFolderName);
+
+ /* Now add the import name */
+ RtlAppendUnicodeStringToString(&DllName, &NameString);
+
+ /* Try once again to load the image */
+ Status = MmLoadSystemImage(&DllName,
+ NamePrefix,
+ NULL,
+ FALSE,
+ (PVOID *)&DllEntry,
+ &DllBase);
}
- /* Check if we failed by here */
if (!NT_SUCCESS(Status))
{
+ /* Fill out the information for the error */
+ *MissingDriver = DllName.Buffer;
+ *(PULONG)MissingDriver |= 1;
+ *MissingApi = NULL;
+
+ DPRINT1("Failed to load dependency: %wZ\n", &DllName);
+
+ /* Don't free the name */
+ DllName.Buffer = NULL;
+
/* Cleanup and return */
- RtlFreeUnicodeString(&NameString);
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
- return Status;
+ goto Failure;
+ }
+
+ /* We can free the DLL Name */
+ ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR);
+ DllName.Buffer = NULL;
+
+ /* 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);
+ ERROR_DBGBREAK("MmCallDllInitialize failed with status 0x%x\n", Status);
+ Loaded = FALSE;
}
/* Loop again to make sure that everything is OK */
if (!ExportDirectory)
{
/* Cleanup and return */
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver);
- return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
+ Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
+ goto Failure;
}
/* Make sure we have an IAT */
if (!NT_SUCCESS(Status))
{
/* Cleanup and return */
- MiDereferenceImports(LoadedImports);
- if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
- return Status;
+ goto Failure;
}
/* Reset the buffer */
/* Return success */
return STATUS_SUCCESS;
+
+Failure:
+
+ /* Cleanup and return */
+ RtlFreeUnicodeString(&NameString);
+
+ if (LoadedImports)
+ {
+ MiDereferenceImports(LoadedImports);
+ ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
+ }
+
+ return Status;
}
VOID
LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
DllBase = (ULONG_PTR)LdrEntry->DllBase;
+ /* Only process boot loaded images. Other drivers are processed by
+ MmFreeDriverInitialization */
+ if (LdrEntry->Flags & LDRP_MM_LOADED)
+ {
+ /* Keep going */
+ NextEntry = NextEntry->Flink;
+ continue;
+ }
+
/* Get the NT header */
NtHeader = RtlImageNtHeader((PVOID)DllBase);
if (!NtHeader)
ULONG i;
PIMAGE_NT_HEADERS NtHeader;
PIMAGE_SECTION_HEADER Section, DiscardSection;
- ULONG PagesDeleted;
/* Get the base address and the page count */
DllBase = LdrEntry->DllBase;
if (!PageCount) return;
/* Delete this many PTEs */
- PagesDeleted = MiDeleteSystemPageableVm(StartPte, PageCount, 0, NULL);
+ MiDeleteSystemPageableVm(StartPte, PageCount, 0, NULL);
}
VOID
if (!PointerPte)
{
/* Shouldn't happen */
- DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
- while (TRUE);
+ ERROR_FATAL("[Mm0]: Couldn't allocate driver section!\n");
+ return;
}
/* This is the new virtual address for the module */
if (!NT_SUCCESS(Status))
{
/* This shouldn't happen */
- DPRINT1("Relocations failed!\n");
- while (TRUE);
+ ERROR_FATAL("Relocations failed!\n");
+ return;
}
}
}
else
{
- /* No referencing needed */
- LdrEntry->LoadCount = 0;
+ /* Add a reference for all other modules as well */
+ LdrEntry->LoadCount = 1;
}
/* Remember this came from the loader */
if (*ImageThunk)
{
/* Should not be happening */
- DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
- LdrEntry, ImageThunk, *ImageThunk);
- ASSERT(FALSE);
+ ERROR_FATAL("Broken IAT entry for %p at %p (%lx)\n",
+ LdrEntry, ImageThunk, *ImageThunk);
}
/* Reset if we hit this */
else
{
/* Not supported */
- DPRINT1("Session drivers not supported\n");
- ASSERT(FALSE);
+ UNIMPLEMENTED_DBGBREAK("Session drivers not supported\n");
}
/* These are the only protection masks we care about */
PMMPFN Pfn1;
PAGED_CODE();
+ /* The page fault handler is broken and doesn't page back in! */
+ DPRINT1("WARNING: MiSetPagingOfDriver() called, but paging is broken! ignoring!\n");
+ return;
+
/* Get the driver's base address */
ImageBase = MiPteToAddress(PointerPte);
ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase) == FALSE);
else
{
/* We don't support session loading yet */
- DPRINT1("Unsupported Session-Load!\n");
- while (TRUE);
+ UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
+ Status = STATUS_NOT_IMPLEMENTED;
}
/* Do cleanup */
if (Flags)
{
/* We don't support session loading yet */
- DPRINT1("Unsupported Session-Load!\n");
- while (TRUE);
+ UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
+ goto Quickie;
}
/* Check the loader list again, we should end up in the path below */
ASSERT(Status != STATUS_ALREADY_COMMITTED);
/* Get the size of the driver */
- DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
+ DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageInformation.ImageFileSize;
/* Make sure we're not being loaded into session space */
if (!Flags)
/* Resolve imports */
MissingApiName = Buffer;
+ MissingDriverName = NULL;
Status = MiResolveImageReferences(ModuleLoadBase,
&BaseDirectory,
NULL,
&LoadedImports);
if (!NT_SUCCESS(Status))
{
+ BOOLEAN NeedToFreeString = FALSE;
+
+ /* If the lowest bit is set to 1, this is a hint that we need to free */
+ if (*(ULONG_PTR*)&MissingDriverName & 1)
+ {
+ NeedToFreeString = TRUE;
+ *(ULONG_PTR*)&MissingDriverName &= ~1;
+ }
+
DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status);
+ DPRINT1(" Missing driver '%ls', missing API '%s'\n",
+ MissingDriverName, MissingApiName);
+
+ if (NeedToFreeString)
+ {
+ ExFreePoolWithTag(MissingDriverName, TAG_LDR_WSTR);
+ }
/* Fail */
MiProcessLoaderEntry(LdrEntry, FALSE);
/* Notify the debugger */
DbgLoadImageSymbols(&AnsiTemp,
LdrEntry->DllBase,
- (ULONG_PTR)ZwCurrentProcess());
+ (ULONG_PTR)PsGetCurrentProcessId());
LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
}