2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/sysldr.c
5 * PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * ReactOS Portable Systems Group
10 /* INCLUDES *******************************************************************/
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
19 /* GCC's incompetence strikes again */
22 sprintf_nt(IN PCHAR Buffer
,
28 vsprintf(Buffer
, Format
, ap
);
32 /* GLOBALS ********************************************************************/
34 LIST_ENTRY PsLoadedModuleList
;
35 LIST_ENTRY MmLoadedUserImageList
;
36 KSPIN_LOCK PsLoadedModuleSpinLock
;
37 ERESOURCE PsLoadedModuleResource
;
38 ULONG_PTR PsNtosImageBase
;
39 KMUTANT MmSystemLoadLock
;
41 PFN_NUMBER MmTotalSystemDriverPages
;
43 PVOID MmUnloadedDrivers
;
44 PVOID MmLastUnloadedDrivers
;
46 BOOLEAN MmMakeLowMemory
;
47 BOOLEAN MmEnforceWriteProtection
= TRUE
;
49 PMMPTE MiKernelResourceStartPte
, MiKernelResourceEndPte
;
50 ULONG_PTR ExPoolCodeStart
, ExPoolCodeEnd
, MmPoolCodeStart
, MmPoolCodeEnd
;
51 ULONG_PTR MmPteCodeStart
, MmPteCodeEnd
;
53 /* FUNCTIONS ******************************************************************/
57 MiCacheImageSymbols(IN PVOID BaseAddress
)
60 PVOID DebugDirectory
= NULL
;
63 /* Make sure it's safe to access the image */
66 /* Get the debug directory */
67 DebugDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
69 IMAGE_DIRECTORY_ENTRY_DEBUG
,
72 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
78 /* Return the directory */
79 return DebugDirectory
;
84 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
86 IN PUNICODE_STRING FileName
,
87 IN BOOLEAN SessionLoad
,
88 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
90 PROS_SECTION_OBJECT Section
= *SectionPtr
;
96 LARGE_INTEGER SectionOffset
= {{0, 0}};
97 BOOLEAN LoadSymbols
= FALSE
;
99 PMMPTE PointerPte
, LastPte
;
104 /* Detect session load */
108 UNIMPLEMENTED_DBGBREAK("Session loading not yet supported!\n");
109 return STATUS_NOT_IMPLEMENTED
;
112 /* Not session load, shouldn't have an entry */
113 ASSERT(LdrEntry
== NULL
);
115 /* Attach to the system process */
116 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
118 /* Check if we need to load symbols */
119 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
123 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
127 Process
= PsGetCurrentProcess();
128 Status
= MmMapViewOfSection(Section
,
139 /* Re-enable the flag */
140 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
142 /* Check if we failed with distinguished status code */
143 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
145 /* Change it to something more generic */
146 Status
= STATUS_INVALID_IMAGE_FORMAT
;
149 /* Now check if we failed */
150 if (!NT_SUCCESS(Status
))
152 /* Detach and return */
153 DPRINT1("MmMapViewOfSection failed with status 0x%x\n", Status
);
154 KeUnstackDetachProcess(&ApcState
);
158 /* Reserve system PTEs needed */
159 PteCount
= ROUND_TO_PAGES(Section
->ImageSection
->ImageInformation
.ImageFileSize
) >> PAGE_SHIFT
;
160 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
163 DPRINT1("MiReserveSystemPtes failed\n");
164 KeUnstackDetachProcess(&ApcState
);
165 return STATUS_INSUFFICIENT_RESOURCES
;
168 /* New driver base */
169 LastPte
= PointerPte
+ PteCount
;
170 DriverBase
= MiPteToAddress(PointerPte
);
172 /* The driver is here */
173 *ImageBase
= DriverBase
;
174 DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName
, DriverBase
, PteCount
);
176 /* Loop the new driver PTEs */
177 TempPte
= ValidKernelPte
;
178 while (PointerPte
< LastPte
)
180 /* Allocate a page */
181 MI_SET_USAGE(MI_USAGE_DRIVER_PAGE
);
185 if (FileName
->Buffer
)
187 pos
= wcsrchr(FileName
->Buffer
, '\\');
188 len
= wcslen(pos
) * sizeof(WCHAR
);
189 if (pos
) snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%S", pos
);
192 TempPte
.u
.Hard
.PageFrameNumber
= MiAllocatePfn(PointerPte
, MM_EXECUTE
);
195 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
202 RtlCopyMemory(DriverBase
, Base
, PteCount
<< PAGE_SHIFT
);
204 /* Now unmap the view */
205 Status
= MmUnmapViewOfSection(Process
, Base
);
206 ASSERT(NT_SUCCESS(Status
));
208 /* Detach and return status */
209 KeUnstackDetachProcess(&ApcState
);
215 MiLocateExportName(IN PVOID DllBase
,
219 PUSHORT OrdinalTable
;
220 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
221 LONG Low
= 0, Mid
= 0, High
, Ret
;
228 /* Get the export directory */
229 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
231 IMAGE_DIRECTORY_ENTRY_EXPORT
,
233 if (!ExportDirectory
) return NULL
;
235 /* Setup name tables */
236 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
237 ExportDirectory
->AddressOfNames
);
238 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
239 ExportDirectory
->AddressOfNameOrdinals
);
241 /* Do a binary search */
242 High
= ExportDirectory
->NumberOfNames
- 1;
245 /* Get new middle value */
246 Mid
= (Low
+ High
) >> 1;
249 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
267 /* Check if we couldn't find it */
268 if (High
< Low
) return NULL
;
270 /* Otherwise, this is the ordinal */
271 Ordinal
= OrdinalTable
[Mid
];
273 /* Resolve the address and write it */
274 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
275 ExportDirectory
->AddressOfFunctions
);
276 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
278 /* Check if the function is actually a forwarder */
279 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
280 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
292 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
293 IN PLIST_ENTRY ListHead
)
295 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
296 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
297 PMM_DLL_INITIALIZE DllInit
;
298 UNICODE_STRING RegPath
, ImportName
;
301 /* Try to see if the image exports a DllInitialize routine */
302 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
304 if (!DllInit
) return STATUS_SUCCESS
;
306 /* Do a temporary copy of BaseDllName called ImportName
307 * because we'll alter the length of the string
309 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
310 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
311 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
313 /* Obtain the path to this dll's service in the registry */
314 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
315 ImportName
.Length
+ sizeof(UNICODE_NULL
);
316 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
317 RegPath
.MaximumLength
,
320 /* Check if this allocation was unsuccessful */
321 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
323 /* Build and append the service name itself */
324 RegPath
.Length
= ServicesKeyName
.Length
;
325 RtlCopyMemory(RegPath
.Buffer
,
326 ServicesKeyName
.Buffer
,
327 ServicesKeyName
.Length
);
329 /* Check if there is a dot in the filename */
330 if (wcschr(ImportName
.Buffer
, L
'.'))
332 /* Remove the extension */
333 ImportName
.Length
= (USHORT
)(wcschr(ImportName
.Buffer
, L
'.') -
334 ImportName
.Buffer
) * sizeof(WCHAR
);
337 /* Append service name (the basename without extension) */
338 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
340 /* Now call the DllInit func */
341 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
342 Status
= DllInit(&RegPath
);
345 ExFreePoolWithTag(RegPath
.Buffer
, TAG_LDR_WSTR
);
347 /* Return status value which DllInitialize returned */
353 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
359 /* Get the unload routine */
360 Func
= (PMM_DLL_UNLOAD
)MiLocateExportName(LdrEntry
->DllBase
, "DllUnload");
361 if (!Func
) return FALSE
;
363 /* Call it and check for success */
365 if (!NT_SUCCESS(Status
)) return FALSE
;
367 /* Lie about the load count so we can unload the image */
368 ASSERT(LdrEntry
->LoadCount
== 0);
369 LdrEntry
->LoadCount
= 1;
371 /* Unload it and return true */
372 MmUnloadSystemImage(LdrEntry
);
378 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
381 LOAD_IMPORTS SingleEntry
;
382 PLDR_DATA_TABLE_ENTRY LdrEntry
;
383 PVOID CurrentImports
;
386 /* Check if there's no imports or if we're a boot driver */
387 if ((ImportList
== MM_SYSLDR_NO_IMPORTS
) ||
388 (ImportList
== MM_SYSLDR_BOOT_LOADED
) ||
389 (ImportList
->Count
== 0))
391 /* Then there's nothing to do */
392 return STATUS_SUCCESS
;
395 /* Check for single-entry */
396 if ((ULONG_PTR
)ImportList
& MM_SYSLDR_SINGLE_ENTRY
)
399 SingleEntry
.Count
= 1;
400 SingleEntry
.Entry
[0] = (PVOID
)((ULONG_PTR
)ImportList
&~ MM_SYSLDR_SINGLE_ENTRY
);
402 /* Use this as the import list */
403 ImportList
= &SingleEntry
;
406 /* Loop the import list */
407 for (i
= 0; (i
< ImportList
->Count
) && (ImportList
->Entry
[i
]); i
++)
410 LdrEntry
= ImportList
->Entry
[i
];
411 DPRINT1("%wZ <%wZ>\n", &LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
413 /* Skip boot loaded images */
414 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) continue;
416 /* Dereference the entry */
417 ASSERT(LdrEntry
->LoadCount
>= 1);
418 if (!--LdrEntry
->LoadCount
)
420 /* Save the import data in case unload fails */
421 CurrentImports
= LdrEntry
->LoadedImports
;
423 /* This is the last entry */
424 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
425 if (MiCallDllUnloadAndUnloadDll(LdrEntry
))
427 /* Unloading worked, parse this DLL's imports too */
428 MiDereferenceImports(CurrentImports
);
430 /* Check if we had valid imports */
431 if ((CurrentImports
!= MM_SYSLDR_BOOT_LOADED
) ||
432 (CurrentImports
!= MM_SYSLDR_NO_IMPORTS
) ||
433 !((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
436 ExFreePoolWithTag(CurrentImports
, TAG_LDR_IMPORTS
);
441 /* Unload failed, restore imports */
442 LdrEntry
->LoadedImports
= CurrentImports
;
448 return STATUS_SUCCESS
;
453 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
457 /* Check if there's no imports or we're a boot driver or only one entry */
458 if ((LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) ||
459 (LdrEntry
->LoadedImports
== MM_SYSLDR_NO_IMPORTS
) ||
460 ((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
466 /* Otherwise, free the import list */
467 ExFreePoolWithTag(LdrEntry
->LoadedImports
, TAG_LDR_IMPORTS
);
468 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
473 MiFindExportedRoutineByName(IN PVOID DllBase
,
474 IN PANSI_STRING ExportName
)
477 PUSHORT OrdinalTable
;
478 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
479 LONG Low
= 0, Mid
= 0, High
, Ret
;
486 /* Get the export directory */
487 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
489 IMAGE_DIRECTORY_ENTRY_EXPORT
,
491 if (!ExportDirectory
) return NULL
;
493 /* Setup name tables */
494 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
495 ExportDirectory
->AddressOfNames
);
496 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
497 ExportDirectory
->AddressOfNameOrdinals
);
499 /* Do a binary search */
500 High
= ExportDirectory
->NumberOfNames
- 1;
503 /* Get new middle value */
504 Mid
= (Low
+ High
) >> 1;
507 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
525 /* Check if we couldn't find it */
526 if (High
< Low
) return NULL
;
528 /* Otherwise, this is the ordinal */
529 Ordinal
= OrdinalTable
[Mid
];
531 /* Validate the ordinal */
532 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
) return NULL
;
534 /* Resolve the address and write it */
535 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
536 ExportDirectory
->AddressOfFunctions
);
537 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
540 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
541 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
547 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
552 /* Acquire module list lock */
553 KeEnterCriticalRegion();
554 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
556 /* Acquire the spinlock too as we will insert or remove the entry */
557 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
559 /* Insert or remove from the list */
561 InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
);
563 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
566 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
567 ExReleaseResourceLite(&PsLoadedModuleResource
);
568 KeLeaveCriticalRegion();
574 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
579 ULONG_PTR OldBaseTop
, Delta
;
580 PLDR_DATA_TABLE_ENTRY LdrEntry
;
581 PLIST_ENTRY NextEntry
;
584 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
585 // since a real version of Windows would fail at this point, but they seem
586 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
587 // a feature which isn't even used by Windows. Priorities, priorities...
588 // Please note that Microsoft WDK EULA and license prohibits using
589 // the information contained within it for the generation of "non-Windows"
590 // drivers, which is precisely what LD will generate, since an LD driver
591 // will not load on Windows.
593 #ifdef _WORKING_LINKER_
596 PULONG_PTR ImageThunk
;
597 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
599 /* Calculate the top and delta */
600 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
601 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
603 /* Loop the loader block */
604 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
605 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
606 NextEntry
= NextEntry
->Flink
)
608 /* Get the loader entry */
609 LdrEntry
= CONTAINING_RECORD(NextEntry
,
610 LDR_DATA_TABLE_ENTRY
,
612 #ifdef _WORKING_LINKER_
614 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
616 IMAGE_DIRECTORY_ENTRY_IAT
,
618 if (!ImageThunk
) continue;
620 /* Make sure we have an IAT */
621 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
622 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
624 /* Check if it's within this module */
625 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
628 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
629 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
630 *ImageThunk
+= Delta
;
634 /* Get the import table */
635 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
637 IMAGE_DIRECTORY_ENTRY_IMPORT
,
639 if (!ImportDescriptor
) continue;
641 /* Make sure we have an IAT */
642 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
643 while ((ImportDescriptor
->Name
) &&
644 (ImportDescriptor
->OriginalFirstThunk
))
646 /* Get the image thunk */
647 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
648 ImportDescriptor
->FirstThunk
);
651 /* Check if it's within this module */
652 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
655 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
656 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
657 *ImageThunk
+= Delta
;
660 /* Go to the next thunk */
664 /* Go to the next import */
673 MiSnapThunk(IN PVOID DllBase
,
675 IN PIMAGE_THUNK_DATA Name
,
676 IN PIMAGE_THUNK_DATA Address
,
677 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
679 IN BOOLEAN SnapForwarder
,
680 OUT PCHAR
*MissingApi
)
685 PUSHORT OrdinalTable
;
686 PIMAGE_IMPORT_BY_NAME NameImport
;
688 ULONG Low
= 0, Mid
= 0, High
;
691 PCHAR MissingForwarder
;
692 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
695 UNICODE_STRING ForwarderName
;
696 PLIST_ENTRY NextEntry
;
697 PLDR_DATA_TABLE_ENTRY LdrEntry
;
698 ULONG ForwardExportSize
;
699 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
700 PIMAGE_IMPORT_BY_NAME ForwardName
;
701 SIZE_T ForwardLength
;
702 IMAGE_THUNK_DATA ForwardThunk
;
705 /* Check if this is an ordinal */
706 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
707 if ((IsOrdinal
) && !(SnapForwarder
))
709 /* Get the ordinal number and set it as missing */
710 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
711 ExportDirectory
->Base
);
712 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
716 /* Get the VA if we don't have to snap */
717 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
718 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
720 /* Copy the procedure name */
721 RtlStringCbCopyA(*MissingApi
,
722 MAXIMUM_FILENAME_LENGTH
,
723 (PCHAR
)&NameImport
->Name
[0]);
725 /* Setup name tables */
726 DPRINT("Import name: %s\n", NameImport
->Name
);
727 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
728 ExportDirectory
->AddressOfNames
);
729 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
730 ExportDirectory
->AddressOfNameOrdinals
);
732 /* Get the hint and check if it's valid */
733 Hint
= NameImport
->Hint
;
734 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
735 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
737 /* We have a match, get the ordinal number from here */
738 Ordinal
= OrdinalTable
[Hint
];
742 /* Do a binary search */
743 High
= ExportDirectory
->NumberOfNames
- 1;
746 /* Get new middle value */
747 Mid
= (Low
+ High
) >> 1;
750 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
768 /* Check if we couldn't find it */
771 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport
->Name
);
772 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
775 /* Otherwise, this is the ordinal */
776 Ordinal
= OrdinalTable
[Mid
];
780 /* Check if the ordinal is invalid */
781 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
784 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
788 /* In case the forwarder is missing */
789 MissingForwarder
= NameBuffer
;
791 /* Resolve the address and write it */
792 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
793 ExportDirectory
->AddressOfFunctions
);
794 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
796 /* Assume success from now on */
797 Status
= STATUS_SUCCESS
;
799 /* Check if the function is actually a forwarder */
800 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
801 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
803 /* Now assume failure in case the forwarder doesn't exist */
804 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
806 /* Build the forwarder name */
807 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
808 DllName
.Length
= (USHORT
)(strchr(DllName
.Buffer
, '.') -
811 DllName
.MaximumLength
= DllName
.Length
;
814 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
818 /* We failed, just return an error */
822 /* Loop the module list */
823 NextEntry
= PsLoadedModuleList
.Flink
;
824 while (NextEntry
!= &PsLoadedModuleList
)
826 /* Get the loader entry */
827 LdrEntry
= CONTAINING_RECORD(NextEntry
,
828 LDR_DATA_TABLE_ENTRY
,
831 /* Check if it matches */
832 if (RtlPrefixUnicodeString(&ForwarderName
,
833 &LdrEntry
->BaseDllName
,
836 /* Get the forwarder export directory */
837 ForwardExportDirectory
=
838 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
840 IMAGE_DIRECTORY_ENTRY_EXPORT
,
842 if (!ForwardExportDirectory
) break;
844 /* Allocate a name entry */
845 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
847 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
848 sizeof(*ForwardName
) +
851 if (!ForwardName
) break;
854 RtlCopyMemory(&ForwardName
->Name
[0],
855 DllName
.Buffer
+ DllName
.Length
,
857 ForwardName
->Hint
= 0;
859 /* Set the new address */
860 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
862 /* Snap the forwarder */
863 Status
= MiSnapThunk(LdrEntry
->DllBase
,
867 ForwardExportDirectory
,
872 /* Free the forwarder name and set the thunk */
873 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
874 Address
->u1
= ForwardThunk
.u1
;
878 /* Go to the next entry */
879 NextEntry
= NextEntry
->Flink
;
883 RtlFreeUnicodeString(&ForwarderName
);
893 MmUnloadSystemImage(IN PVOID ImageHandle
)
895 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
896 PVOID BaseAddress
= LdrEntry
->DllBase
;
899 BOOLEAN HadEntry
= FALSE
;
901 /* Acquire the loader lock */
902 KeEnterCriticalRegion();
903 KeWaitForSingleObject(&MmSystemLoadLock
,
909 /* Check if this driver was loaded at boot and didn't get imports parsed */
910 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
912 /* We should still be alive */
913 ASSERT(LdrEntry
->LoadCount
!= 0);
914 LdrEntry
->LoadCount
--;
916 /* Check if we're still loaded */
917 if (LdrEntry
->LoadCount
) goto Done
;
919 /* We should cleanup... are symbols loaded */
920 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
922 /* Create the ANSI name */
923 Status
= RtlUnicodeStringToAnsiString(&TempName
,
924 &LdrEntry
->BaseDllName
,
926 if (NT_SUCCESS(Status
))
928 /* Unload the symbols */
929 DbgUnLoadImageSymbols(&TempName
,
931 (ULONG_PTR
)ZwCurrentProcess());
932 RtlFreeAnsiString(&TempName
);
936 /* FIXME: Free the driver */
937 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
938 //MmFreeSection(LdrEntry->DllBase);
940 /* Check if we're linked in */
941 if (LdrEntry
->InLoadOrderLinks
.Flink
)
944 MiProcessLoaderEntry(LdrEntry
, FALSE
);
948 /* Dereference and clear the imports */
949 MiDereferenceImports(LdrEntry
->LoadedImports
);
950 MiClearImports(LdrEntry
);
952 /* Check if the entry needs to go away */
955 /* Check if it had a name */
956 if (LdrEntry
->FullDllName
.Buffer
)
959 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
962 /* Check if we had a section */
963 if (LdrEntry
->SectionPointer
)
966 ObDereferenceObject(LdrEntry
->SectionPointer
);
970 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
973 /* Release the system lock and return */
975 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
976 KeLeaveCriticalRegion();
977 return STATUS_SUCCESS
;
982 MiResolveImageReferences(IN PVOID ImageBase
,
983 IN PUNICODE_STRING ImageFileDirectory
,
984 IN PUNICODE_STRING NamePrefix OPTIONAL
,
985 OUT PCHAR
*MissingApi
,
986 OUT PWCHAR
*MissingDriver
,
987 OUT PLOAD_IMPORTS
*LoadImports
)
989 static UNICODE_STRING DriversFolderName
= RTL_CONSTANT_STRING(L
"drivers\\");
990 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
991 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
992 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
993 PLOAD_IMPORTS LoadedImports
, NewImports
;
994 ULONG GdiLink
, NormalLink
, i
;
995 BOOLEAN ReferenceNeeded
, Loaded
;
996 ANSI_STRING TempString
;
997 UNICODE_STRING NameString
, DllName
;
998 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
999 PVOID ImportBase
, DllBase
;
1000 PLIST_ENTRY NextEntry
;
1001 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
1003 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
1005 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
1006 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
1008 /* No name string buffer yet */
1009 NameString
.Buffer
= NULL
;
1011 /* Assume no imports */
1012 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
1014 /* Get the import descriptor */
1015 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
1017 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1019 if (!ImportDescriptor
) return STATUS_SUCCESS
;
1021 /* Loop all imports to count them */
1022 for (CurrentImport
= ImportDescriptor
;
1023 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
1030 /* Make sure we have non-zero imports */
1033 /* Calculate and allocate the list we'll need */
1034 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1035 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1041 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1042 LoadedImports
->Count
= ImportCount
;
1048 LoadedImports
= NULL
;
1051 /* Reset the import count and loop descriptors again */
1052 ImportCount
= GdiLink
= NormalLink
= 0;
1053 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1056 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1058 /* Check if this is a GDI driver */
1060 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1062 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1063 NormalLink
= NormalLink
|
1064 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1065 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1066 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1067 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1069 /* Check if this is a valid GDI driver */
1070 if ((GdiLink
) && (NormalLink
))
1072 /* It's not, it's importing stuff it shouldn't be! */
1073 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1077 /* Check for user-mode printer or video card drivers, which don't belong */
1078 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1079 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1080 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1081 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1082 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1083 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1085 /* This is not kernel code */
1086 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1090 /* Check if this is a "core" import, which doesn't get referenced */
1091 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1092 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1093 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1095 /* Don't reference this */
1096 ReferenceNeeded
= FALSE
;
1100 /* Reference these modules */
1101 ReferenceNeeded
= TRUE
;
1104 /* Now setup a unicode string for the import */
1105 RtlInitAnsiString(&TempString
, ImportName
);
1106 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1107 if (!NT_SUCCESS(Status
))
1113 /* We don't support name prefixes yet */
1114 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1116 /* Remember that we haven't loaded the import at this point */
1121 /* Loop the driver list */
1122 NextEntry
= PsLoadedModuleList
.Flink
;
1123 while (NextEntry
!= &PsLoadedModuleList
)
1125 /* Get the loader entry and compare the name */
1126 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1127 LDR_DATA_TABLE_ENTRY
,
1129 if (RtlEqualUnicodeString(&NameString
,
1130 &LdrEntry
->BaseDllName
,
1133 /* Get the base address */
1134 ImportBase
= LdrEntry
->DllBase
;
1136 /* Check if we haven't loaded yet, and we need references */
1137 if (!(Loaded
) && (ReferenceNeeded
))
1139 /* Make sure we're not already loading */
1140 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1142 /* Increase the load count */
1143 LdrEntry
->LoadCount
++;
1147 /* Done, break out */
1151 /* Go to the next entry */
1152 NextEntry
= NextEntry
->Flink
;
1155 /* Check if we haven't loaded the import yet */
1158 /* Setup the import DLL name */
1159 DllName
.MaximumLength
= NameString
.Length
+
1160 ImageFileDirectory
->Length
+
1161 sizeof(UNICODE_NULL
);
1162 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1163 DllName
.MaximumLength
,
1165 if (!DllName
.Buffer
)
1167 /* We're out of resources */
1168 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1172 /* Add the import name to the base directory */
1173 RtlCopyUnicodeString(&DllName
, ImageFileDirectory
);
1174 RtlAppendUnicodeStringToString(&DllName
,
1177 /* Load the image */
1178 Status
= MmLoadSystemImage(&DllName
,
1185 /* win32k / GDI drivers can also import from system32 folder */
1186 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) &&
1187 (MI_IS_SESSION_ADDRESS(ImageBase
) || 1)) // HACK
1189 /* Free the old name buffer */
1190 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1192 /* Calculate size for a string the adds 'drivers\' */
1193 DllName
.MaximumLength
+= DriversFolderName
.Length
;
1195 /* Allocate the new buffer */
1196 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1197 DllName
.MaximumLength
,
1199 if (!DllName
.Buffer
)
1201 /* We're out of resources */
1202 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1206 /* Copy image directory and append 'drivers\' folder name */
1207 RtlCopyUnicodeString(&DllName
, ImageFileDirectory
);
1208 RtlAppendUnicodeStringToString(&DllName
, &DriversFolderName
);
1210 /* Now add the import name */
1211 RtlAppendUnicodeStringToString(&DllName
, &NameString
);
1213 /* Try once again to load the image */
1214 Status
= MmLoadSystemImage(&DllName
,
1222 if (!NT_SUCCESS(Status
))
1224 /* Fill out the information for the error */
1225 *MissingDriver
= DllName
.Buffer
;
1226 *(PULONG
)MissingDriver
|= 1;
1229 DPRINT1("Failed to load dependency: %wZ\n", &DllName
);
1231 /* Don't free the name */
1232 DllName
.Buffer
= NULL
;
1234 /* Cleanup and return */
1238 /* We can free the DLL Name */
1239 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1240 DllName
.Buffer
= NULL
;
1242 /* We're now loaded */
1246 ASSERT(DllBase
== DllEntry
->DllBase
);
1248 /* Call the initialization routines */
1249 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1250 if (!NT_SUCCESS(Status
))
1252 /* We failed, unload the image */
1253 MmUnloadSystemImage(DllEntry
);
1254 ERROR_DBGBREAK("MmCallDllInitialize failed with status 0x%x\n", Status
);
1258 /* Loop again to make sure that everything is OK */
1262 /* Check if we're support to reference this import */
1263 if ((ReferenceNeeded
) && (LoadedImports
))
1265 /* Make sure we're not already loading */
1266 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1269 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1274 /* Free the import name */
1275 RtlFreeUnicodeString(&NameString
);
1277 /* Set the missing driver name and get the export directory */
1278 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1279 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1281 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1283 if (!ExportDirectory
)
1285 /* Cleanup and return */
1286 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver
);
1287 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1291 /* Make sure we have an IAT */
1292 if (ImportDescriptor
->OriginalFirstThunk
)
1294 /* Get the first thunks */
1295 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1296 ImportDescriptor
->OriginalFirstThunk
);
1297 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1298 ImportDescriptor
->FirstThunk
);
1301 while (OrigThunk
->u1
.AddressOfData
)
1304 Status
= MiSnapThunk(ImportBase
,
1312 if (!NT_SUCCESS(Status
))
1314 /* Cleanup and return */
1318 /* Reset the buffer */
1319 *MissingApi
= MissingApiBuffer
;
1323 /* Go to the next import */
1327 /* Check if we have an import list */
1330 /* Reset the count again, and loop entries */
1332 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1334 if (LoadedImports
->Entry
[i
])
1336 /* Got an entry, OR it with 1 in case it's the single entry */
1337 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1338 MM_SYSLDR_SINGLE_ENTRY
);
1343 /* Check if we had no imports */
1346 /* Free the list and set it to no imports */
1347 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1348 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1350 else if (ImportCount
== 1)
1352 /* Just one entry, we can free the table and only use our entry */
1353 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1354 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1356 else if (ImportCount
!= LoadedImports
->Count
)
1358 /* Allocate a new list */
1359 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1360 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1366 NewImports
->Count
= 0;
1368 /* Loop all the imports */
1369 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1371 /* Make sure it's valid */
1372 if (LoadedImports
->Entry
[i
])
1375 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1376 NewImports
->Count
++;
1380 /* Free the old copy */
1381 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1382 LoadedImports
= NewImports
;
1386 /* Return the list */
1387 *LoadImports
= LoadedImports
;
1390 /* Return success */
1391 return STATUS_SUCCESS
;
1395 /* Cleanup and return */
1396 RtlFreeUnicodeString(&NameString
);
1400 MiDereferenceImports(LoadedImports
);
1401 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1409 MiFreeInitializationCode(IN PVOID InitStart
,
1413 PFN_NUMBER PagesFreed
;
1415 /* Get the start PTE */
1416 PointerPte
= MiAddressToPte(InitStart
);
1417 ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart
) == FALSE
);
1419 /* Compute the number of pages we expect to free */
1420 PagesFreed
= (PFN_NUMBER
)(MiAddressToPte(InitEnd
) - PointerPte
+ 1);
1422 /* Try to actually free them */
1423 PagesFreed
= MiDeleteSystemPageableVm(PointerPte
,
1432 MiFindInitializationCode(OUT PVOID
*StartVa
,
1435 ULONG Size
, SectionCount
, Alignment
;
1436 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1437 ULONG_PTR DllBase
, InitStart
, InitEnd
, ImageEnd
, InitCode
;
1438 PLIST_ENTRY NextEntry
;
1439 PIMAGE_NT_HEADERS NtHeader
;
1440 PIMAGE_SECTION_HEADER Section
, LastSection
;
1443 /* So we don't free our own code yet */
1444 InitCode
= (ULONG_PTR
)&MiFindInitializationCode
;
1446 /* Assume failure */
1449 /* Enter a critical region while we loop the list */
1450 KeEnterCriticalRegion();
1452 /* Loop all loaded modules */
1453 NextEntry
= PsLoadedModuleList
.Flink
;
1454 while (NextEntry
!= &PsLoadedModuleList
)
1456 /* Get the loader entry and its DLL base */
1457 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1458 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1460 /* Only process boot loaded images. Other drivers are processed by
1461 MmFreeDriverInitialization */
1462 if (LdrEntry
->Flags
& LDRP_MM_LOADED
)
1465 NextEntry
= NextEntry
->Flink
;
1469 /* Get the NT header */
1470 NtHeader
= RtlImageNtHeader((PVOID
)DllBase
);
1474 NextEntry
= NextEntry
->Flink
;
1478 /* Get the first section, the section count, and scan them all */
1479 Section
= IMAGE_FIRST_SECTION(NtHeader
);
1480 SectionCount
= NtHeader
->FileHeader
.NumberOfSections
;
1482 while (SectionCount
> 0)
1484 /* Assume failure */
1487 /* Is this the INIT section or a discardable section? */
1488 if ((*(PULONG
)Section
->Name
== 'TINI') ||
1489 ((Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)))
1497 /* Pick the biggest size -- either raw or virtual */
1498 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
1500 /* Read the section alignment */
1501 Alignment
= NtHeader
->OptionalHeader
.SectionAlignment
;
1503 /* Align the start and end addresses appropriately */
1504 InitStart
= DllBase
+ Section
->VirtualAddress
;
1505 InitEnd
= ((Alignment
+ InitStart
+ Size
- 2) & 0xFFFFF000) - 1;
1506 InitStart
= (InitStart
+ (PAGE_SIZE
- 1)) & 0xFFFFF000;
1508 /* Have we reached the last section? */
1509 if (SectionCount
== 1)
1512 LastSection
= Section
;
1516 /* We have not, loop all the sections */
1520 /* Keep going until we find a non-discardable section range */
1523 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1525 /* Discardable, so record it, then keep going */
1526 LastSection
= Section
;
1530 /* Non-contigous discard flag, or no flag, break out */
1534 while (SectionCount
> 1);
1537 /* Have we found a discardable or init section? */
1540 /* Pick the biggest size -- either raw or virtual */
1541 Size
= max(LastSection
->SizeOfRawData
, LastSection
->Misc
.VirtualSize
);
1543 /* Use this as the end of the section address */
1544 InitEnd
= DllBase
+ LastSection
->VirtualAddress
+ Size
- 1;
1546 /* Have we reached the last section yet? */
1547 if (SectionCount
!= 1)
1549 /* Then align this accross the session boundary */
1550 InitEnd
= ((Alignment
+ InitEnd
- 1) & 0XFFFFF000) - 1;
1554 /* Make sure we don't let the init section go past the image */
1555 ImageEnd
= DllBase
+ LdrEntry
->SizeOfImage
;
1556 if (InitEnd
> ImageEnd
) InitEnd
= (ImageEnd
- 1) | (PAGE_SIZE
- 1);
1558 /* Make sure we have a valid, non-zero init section */
1559 if (InitStart
<= InitEnd
)
1561 /* Make sure we are not within this code itself */
1562 if ((InitCode
>= InitStart
) && (InitCode
<= InitEnd
))
1564 /* Return it, we can't free ourselves now */
1565 ASSERT(*StartVa
== 0);
1566 *StartVa
= (PVOID
)InitStart
;
1567 *EndVa
= (PVOID
)InitEnd
;
1571 /* This isn't us -- go ahead and free it */
1572 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID
)InitStart
) == FALSE
);
1573 MiFreeInitializationCode((PVOID
)InitStart
, (PVOID
)InitEnd
);
1578 /* Move to the next section */
1583 /* Move to the next module */
1584 NextEntry
= NextEntry
->Flink
;
1587 /* Leave the critical region and return */
1588 KeLeaveCriticalRegion();
1592 * Note: This function assumes that all discardable sections are at the end of
1593 * the PE file. It searches backwards until it finds the non-discardable section
1597 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1599 PMMPTE StartPte
, EndPte
;
1600 PFN_NUMBER PageCount
;
1603 PIMAGE_NT_HEADERS NtHeader
;
1604 PIMAGE_SECTION_HEADER Section
, DiscardSection
;
1606 /* Get the base address and the page count */
1607 DllBase
= LdrEntry
->DllBase
;
1608 PageCount
= LdrEntry
->SizeOfImage
>> PAGE_SHIFT
;
1610 /* Get the last PTE in this image */
1611 EndPte
= MiAddressToPte(DllBase
) + PageCount
;
1613 /* Get the NT header */
1614 NtHeader
= RtlImageNtHeader(DllBase
);
1615 if (!NtHeader
) return;
1617 /* Get the last section and loop each section backwards */
1618 Section
= IMAGE_FIRST_SECTION(NtHeader
) + NtHeader
->FileHeader
.NumberOfSections
;
1619 DiscardSection
= NULL
;
1620 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
1622 /* Go back a section and check if it's discardable */
1624 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1626 /* It is, select it for freeing */
1627 DiscardSection
= Section
;
1631 /* No more discardable sections exist, bail out */
1636 /* Bail out if there's nothing to free */
1637 if (!DiscardSection
) return;
1639 /* Push the DLL base to the first disacrable section, and get its PTE */
1640 DllBase
= (PVOID
)ROUND_TO_PAGES((ULONG_PTR
)DllBase
+ DiscardSection
->VirtualAddress
);
1641 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase
) == FALSE
);
1642 StartPte
= MiAddressToPte(DllBase
);
1644 /* Check how many pages to free total */
1645 PageCount
= (PFN_NUMBER
)(EndPte
- StartPte
);
1646 if (!PageCount
) return;
1648 /* Delete this many PTEs */
1649 MiDeleteSystemPageableVm(StartPte
, PageCount
, 0, NULL
);
1655 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1657 PLIST_ENTRY NextEntry
;
1659 PIMAGE_NT_HEADERS NtHeader
;
1660 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1661 PIMAGE_FILE_HEADER FileHeader
;
1662 BOOLEAN ValidRelocs
;
1663 PIMAGE_DATA_DIRECTORY DataDirectory
;
1664 PVOID DllBase
, NewImageAddress
;
1666 PMMPTE PointerPte
, StartPte
, LastPte
;
1669 MMPTE TempPte
, OldPte
;
1671 /* Loop driver list */
1672 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1673 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1674 NextEntry
= NextEntry
->Flink
)
1676 /* Get the loader entry and NT header */
1677 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1678 LDR_DATA_TABLE_ENTRY
,
1680 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1683 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1685 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1686 &LdrEntry
->FullDllName
);
1688 /* Get the first PTE and the number of PTEs we'll need */
1689 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1690 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1691 LastPte
= StartPte
+ PteCount
;
1695 while (PointerPte
< LastPte
)
1698 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1699 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1700 len
= wcslen(LdrEntry
->BaseDllName
.Buffer
) * sizeof(WCHAR
);
1701 snprintf(Pfn1
->ProcessName
, min(16, len
), "%S", LdrEntry
->BaseDllName
.Buffer
);
1705 /* Skip kernel and HAL */
1706 /* ROS HACK: Skip BOOTVID/KDCOM too */
1708 if (i
<= 4) continue;
1710 /* Skip non-drivers */
1711 if (!NtHeader
) continue;
1713 /* Get the file header and make sure we can relocate */
1714 FileHeader
= &NtHeader
->FileHeader
;
1715 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1716 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1717 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1719 /* Everything made sense until now, check the relocation section too */
1720 DataDirectory
= &NtHeader
->OptionalHeader
.
1721 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1722 if (!DataDirectory
->VirtualAddress
)
1724 /* We don't really have relocations */
1725 ValidRelocs
= FALSE
;
1729 /* Make sure the size is valid */
1730 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1731 LdrEntry
->SizeOfImage
)
1733 /* They're not, skip */
1737 /* We have relocations */
1741 /* Remember the original address */
1742 DllBase
= LdrEntry
->DllBase
;
1745 PointerPte
= StartPte
;
1746 while (PointerPte
< LastPte
)
1748 /* Mark the page modified in the PFN database */
1749 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1750 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1751 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1752 Pfn1
->u3
.e1
.Modified
= TRUE
;
1758 /* Now reserve system PTEs for the image */
1759 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1762 /* Shouldn't happen */
1763 ERROR_FATAL("[Mm0]: Couldn't allocate driver section!\n");
1767 /* This is the new virtual address for the module */
1768 LastPte
= PointerPte
+ PteCount
;
1769 NewImageAddress
= MiPteToAddress(PointerPte
);
1772 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1773 ASSERT(ExpInitializationPhase
== 0);
1775 /* Loop the new driver PTEs */
1776 TempPte
= ValidKernelPte
;
1777 while (PointerPte
< LastPte
)
1779 /* Copy the old data */
1781 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1783 /* Set page number from the loader's memory */
1784 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1787 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1794 /* Update position */
1795 PointerPte
-= PteCount
;
1798 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1800 /* Set the image base to the address where the loader put it */
1801 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1803 /* Check if we had relocations */
1806 /* Relocate the image */
1807 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1811 STATUS_CONFLICTING_ADDRESSES
,
1812 STATUS_INVALID_IMAGE_FORMAT
);
1813 if (!NT_SUCCESS(Status
))
1815 /* This shouldn't happen */
1816 ERROR_FATAL("Relocations failed!\n");
1821 /* Update the loader entry */
1822 LdrEntry
->DllBase
= NewImageAddress
;
1824 /* Update the thunks */
1825 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1826 MiUpdateThunks(LoaderBlock
,
1829 LdrEntry
->SizeOfImage
);
1831 /* Update the loader entry */
1832 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1833 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1834 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1835 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1837 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1844 MiBuildImportsForBootDrivers(VOID
)
1846 PLIST_ENTRY NextEntry
, NextEntry2
;
1847 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1848 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1849 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1850 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1851 PLOAD_IMPORTS LoadedImports
;
1852 ULONG LoadedImportsSize
, ImportSize
;
1853 PULONG_PTR ImageThunk
;
1854 ULONG_PTR DllBase
, DllEnd
;
1855 ULONG Modules
= 0, i
, j
= 0;
1856 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1858 /* Initialize variables */
1859 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1861 /* Loop the loaded module list... we are early enough that no lock is needed */
1862 NextEntry
= PsLoadedModuleList
.Flink
;
1863 while (NextEntry
!= &PsLoadedModuleList
)
1866 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1867 LDR_DATA_TABLE_ENTRY
,
1870 /* Check if it's the kernel or HAL */
1871 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1874 KernelEntry
= LdrEntry
;
1876 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1879 HalEntry
= LdrEntry
;
1882 /* Check if this is a driver DLL */
1883 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1885 /* Check if this is the HAL or kernel */
1886 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1888 /* Add a reference */
1889 LdrEntry
->LoadCount
= 1;
1893 /* No referencing needed */
1894 LdrEntry
->LoadCount
= 0;
1899 /* Add a reference for all other modules as well */
1900 LdrEntry
->LoadCount
= 1;
1903 /* Remember this came from the loader */
1904 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1907 NextEntry
= NextEntry
->Flink
;
1911 /* We must have at least found the kernel and HAL */
1912 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1914 /* Allocate the list */
1915 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), TAG_LDR_IMPORTS
);
1916 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1918 /* Loop the loaded module list again */
1919 NextEntry
= PsLoadedModuleList
.Flink
;
1920 while (NextEntry
!= &PsLoadedModuleList
)
1923 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1924 LDR_DATA_TABLE_ENTRY
,
1926 #ifdef _WORKING_LOADER_
1927 /* Get its imports */
1928 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1930 IMAGE_DIRECTORY_ENTRY_IAT
,
1934 /* Get its imports */
1935 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1937 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1939 if (!ImportDescriptor
)
1943 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1944 NextEntry
= NextEntry
->Flink
;
1948 /* Clear the list and count the number of IAT thunks */
1949 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1950 #ifdef _WORKING_LOADER_
1951 ImportSize
/= sizeof(ULONG_PTR
);
1953 /* Scan the thunks */
1954 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1956 DllBase
= DllEnd
= i
= 0;
1957 while ((ImportDescriptor
->Name
) &&
1958 (ImportDescriptor
->OriginalFirstThunk
))
1960 /* Get the image thunk */
1961 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1962 ImportDescriptor
->FirstThunk
);
1966 /* Do we already have an address? */
1969 /* Is the thunk in the same address? */
1970 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1972 /* Skip it, we already have a reference for it */
1973 ASSERT(EntryArray
[j
]);
1979 /* Loop the loaded module list to locate this address owner */
1981 NextEntry2
= PsLoadedModuleList
.Flink
;
1982 while (NextEntry2
!= &PsLoadedModuleList
)
1985 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
1986 LDR_DATA_TABLE_ENTRY
,
1989 /* Get the address range for this module */
1990 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
1991 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
1993 /* Check if this IAT entry matches it */
1994 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1997 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
1998 EntryArray
[j
] = LdrEntry2
;
2002 /* Keep searching */
2003 NextEntry2
= NextEntry2
->Flink
;
2007 /* Do we have a thunk outside the range? */
2008 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
2013 /* Should not be happening */
2014 ERROR_FATAL("Broken IAT entry for %p at %p (%lx)\n",
2015 LdrEntry
, ImageThunk
, *ImageThunk
);
2018 /* Reset if we hit this */
2021 #ifndef _WORKING_LOADER_
2030 /* Now scan how many imports we really have */
2031 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
2033 /* Skip HAL and kernel */
2034 if ((EntryArray
[i
]) &&
2035 (EntryArray
[i
] != HalEntry
) &&
2036 (EntryArray
[i
] != KernelEntry
))
2038 /* A valid reference */
2039 LastEntry
= EntryArray
[i
];
2044 /* Do we have any imports after all? */
2048 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2050 else if (ImportSize
== 1)
2052 /* A single entry import */
2053 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
2054 LastEntry
->LoadCount
++;
2058 /* We need an import table */
2059 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
2060 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
2063 ASSERT(LoadedImports
);
2065 /* Save the count */
2066 LoadedImports
->Count
= ImportSize
;
2068 /* Now copy all imports */
2069 for (i
= 0, j
= 0; i
< Modules
; i
++)
2071 /* Skip HAL and kernel */
2072 if ((EntryArray
[i
]) &&
2073 (EntryArray
[i
] != HalEntry
) &&
2074 (EntryArray
[i
] != KernelEntry
))
2076 /* A valid reference */
2077 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
2078 LoadedImports
->Entry
[j
] = EntryArray
[i
];
2079 EntryArray
[i
]->LoadCount
++;
2084 /* Should had as many entries as we expected */
2085 ASSERT(j
== ImportSize
);
2086 LdrEntry
->LoadedImports
= LoadedImports
;
2090 NextEntry
= NextEntry
->Flink
;
2093 /* Free the initial array */
2094 ExFreePoolWithTag(EntryArray
, TAG_LDR_IMPORTS
);
2096 /* FIXME: Might not need to keep the HAL/Kernel imports around */
2098 /* Kernel and HAL are loaded at boot */
2099 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2100 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2102 /* All worked well */
2103 return STATUS_SUCCESS
;
2109 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2112 PIMAGE_NT_HEADERS NtHeaders
;
2113 PIMAGE_SECTION_HEADER SectionHeader
;
2114 ULONG Sections
, Size
;
2116 /* Get the kernel section header */
2117 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2118 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
2119 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
2121 /* Loop all the sections */
2122 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2125 /* Grab the size of the section */
2126 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
2128 /* Check for .RSRC section */
2129 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
2131 /* Remember the PTEs so we can modify them later */
2132 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
2133 SectionHeader
->VirtualAddress
);
2134 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
2135 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
2137 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
2139 /* POOLCODE vs. POOLMI */
2140 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
2142 /* Found Ex* Pool code */
2143 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2144 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2146 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
2148 /* Found Mm* Pool code */
2149 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2150 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2153 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
2154 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
2156 /* Found MISYSPTE (Mm System PTE code)*/
2157 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2158 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
2170 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
2172 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
2173 PLIST_ENTRY ListHead
, NextEntry
;
2176 /* Setup the loaded module list and locks */
2177 ExInitializeResourceLite(&PsLoadedModuleResource
);
2178 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
2179 InitializeListHead(&PsLoadedModuleList
);
2181 /* Get loop variables and the kernel entry */
2182 ListHead
= &LoaderBlock
->LoadOrderListHead
;
2183 NextEntry
= ListHead
->Flink
;
2184 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2185 LDR_DATA_TABLE_ENTRY
,
2187 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2189 /* Locate resource section, pool code, and system pte code */
2190 MiLocateKernelSections(LdrEntry
);
2192 /* Loop the loader block */
2193 while (NextEntry
!= ListHead
)
2195 /* Get the loader entry */
2196 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2197 LDR_DATA_TABLE_ENTRY
,
2200 /* FIXME: ROS HACK. Make sure this is a driver */
2201 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
2203 /* Skip this entry */
2204 NextEntry
= NextEntry
->Flink
;
2208 /* Calculate the size we'll need and allocate a copy */
2209 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2210 LdrEntry
->BaseDllName
.MaximumLength
+
2211 sizeof(UNICODE_NULL
);
2212 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2213 if (!NewEntry
) return FALSE
;
2215 /* Copy the entry over */
2216 *NewEntry
= *LdrEntry
;
2218 /* Allocate the name */
2219 NewEntry
->FullDllName
.Buffer
=
2220 ExAllocatePoolWithTag(PagedPool
,
2221 LdrEntry
->FullDllName
.MaximumLength
+
2222 sizeof(UNICODE_NULL
),
2224 if (!NewEntry
->FullDllName
.Buffer
)
2226 ExFreePoolWithTag(NewEntry
, TAG_MODULE_OBJECT
);
2230 /* Set the base name */
2231 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
2233 /* Copy the full and base name */
2234 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
2235 LdrEntry
->FullDllName
.Buffer
,
2236 LdrEntry
->FullDllName
.MaximumLength
);
2237 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
2238 LdrEntry
->BaseDllName
.Buffer
,
2239 LdrEntry
->BaseDllName
.MaximumLength
);
2241 /* Null-terminate the base name */
2242 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
2243 sizeof(WCHAR
)] = UNICODE_NULL
;
2245 /* Insert the entry into the list */
2246 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
2247 NextEntry
= NextEntry
->Flink
;
2250 /* Build the import lists for the boot drivers */
2251 MiBuildImportsForBootDrivers();
2259 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
2260 IN OUT PVOID
*ImageBaseAddress
,
2261 IN PUNICODE_STRING BaseImageName
,
2262 IN BOOLEAN BootDriver
)
2264 PLIST_ENTRY NextEntry
;
2265 BOOLEAN DriverFound
= FALSE
;
2266 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
2267 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
2268 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
2271 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
2272 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
2275 /* Make sure there's enough system PTEs for a large page driver */
2276 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
2281 /* This happens if the registry key had a "*" (wildcard) in it */
2282 if (MiLargePageAllDrivers
== 0)
2284 /* It didn't, so scan the list */
2285 NextEntry
= MiLargePageDriverList
.Flink
;
2286 while (NextEntry
!= &MiLargePageDriverList
)
2288 /* Check if the driver name matches */
2289 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
2290 MI_LARGE_PAGE_DRIVER_ENTRY
,
2292 if (RtlEqualUnicodeString(BaseImageName
,
2293 &LargePageDriverEntry
->BaseName
,
2296 /* Enable large pages for this driver */
2302 NextEntry
= NextEntry
->Flink
;
2305 /* If we didn't find the driver, it doesn't need large pages */
2306 if (DriverFound
== FALSE
) return FALSE
;
2309 /* Nothing to do yet */
2310 DPRINT1("Large pages not supported!\n");
2316 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
2317 IN ULONG SectionProtection
)
2319 ULONG Protection
= MM_ZERO_ACCESS
;
2321 /* Check if the caller gave anything */
2322 if (SectionProtection
)
2324 /* Always turn on execute access */
2325 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
2327 /* Check if the registry setting is on or not */
2328 if (!MmEnforceWriteProtection
)
2330 /* Turn on write access too */
2331 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
2335 /* Convert to internal PTE flags */
2336 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
2337 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
2339 /* Check for write access */
2340 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
2342 /* Session space is not supported */
2345 DPRINT1("Session drivers not supported\n");
2346 ASSERT(SessionSpace
== FALSE
);
2350 /* Convert to internal PTE flag */
2351 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
2355 /* If there's no access at all by now, convert to internal no access flag */
2356 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
2358 /* Return the computed PTE protection */
2364 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
2366 IN ULONG ProtectionMask
)
2368 /* I'm afraid to introduce regressions at the moment... */
2374 MiWriteProtectSystemImage(IN PVOID ImageBase
)
2376 PIMAGE_NT_HEADERS NtHeaders
;
2377 PIMAGE_SECTION_HEADER Section
;
2378 PFN_NUMBER DriverPages
;
2379 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
= 0, ProtectionMask
;
2380 ULONG Sections
, Size
;
2381 ULONG_PTR BaseAddress
, CurrentAddress
;
2382 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
2383 ULONG CurrentMask
, CombinedMask
= 0;
2386 /* No need to write protect physical memory-backed drivers (large pages) */
2387 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2389 /* Get the image headers */
2390 NtHeaders
= RtlImageNtHeader(ImageBase
);
2391 if (!NtHeaders
) return;
2393 /* Check if this is a session driver or not */
2394 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
2396 /* Don't touch NT4 drivers */
2397 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
2398 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
2403 UNIMPLEMENTED_DBGBREAK("Session drivers not supported\n");
2406 /* These are the only protection masks we care about */
2407 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
2409 /* Calculate the number of pages this driver is occupying */
2410 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
2412 /* Get the number of sections and the first section header */
2413 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2414 ASSERT(Sections
!= 0);
2415 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2417 /* Loop all the sections */
2418 CurrentAddress
= (ULONG_PTR
)ImageBase
;
2421 /* Get the section size */
2422 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2424 /* Get its virtual address */
2425 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2426 if (BaseAddress
< CurrentAddress
)
2428 /* Windows doesn't like these */
2429 DPRINT1("Badly linked image!\n");
2433 /* Remember the current address */
2434 CurrentAddress
= BaseAddress
+ Size
- 1;
2441 /* Get the number of sections and the first section header */
2442 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2443 ASSERT(Sections
!= 0);
2444 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2446 /* Set the address at the end to initialize the loop */
2447 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
2448 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
2450 /* Set the PTE points for the image, and loop its sections */
2451 StartPte
= MiAddressToPte(ImageBase
);
2452 LastPte
= StartPte
+ DriverPages
;
2455 /* Get the section size */
2456 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2458 /* Get its virtual address and PTE */
2459 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2460 PointerPte
= MiAddressToPte(BaseAddress
);
2462 /* Check if we were already protecting a run, and found a new run */
2463 if ((ComboPte
) && (PointerPte
> ComboPte
))
2465 /* Compute protection */
2466 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2469 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2471 /* Check for overlap */
2472 if (ComboPte
== StartPte
) StartPte
++;
2474 /* One done, reset variables */
2476 CombinedProtection
= 0;
2479 /* Break out when needed */
2480 if (PointerPte
>= LastPte
) break;
2482 /* Get the requested protection from the image header */
2483 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
2484 if (SectionProtection
== CurrentProtection
)
2486 /* Same protection, so merge the request */
2487 CurrentAddress
= BaseAddress
+ Size
- 1;
2495 /* This is now a new section, so close up the old one */
2496 CurrentPte
= MiAddressToPte(CurrentAddress
);
2498 /* Check for overlap */
2499 if (CurrentPte
== PointerPte
)
2501 /* Skip the last PTE, since it overlaps with us */
2504 /* And set the PTE we will merge with */
2505 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
2506 ComboPte
= PointerPte
;
2508 /* Get the most flexible protection by merging both */
2509 CombinedMask
|= (SectionProtection
| CurrentProtection
);
2512 /* Loop any PTEs left */
2513 if (CurrentPte
>= StartPte
)
2516 ASSERT(StartPte
< LastPte
);
2518 /* Make sure we don't overflow past the last PTE in the driver */
2519 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2520 ASSERT(CurrentPte
>= StartPte
);
2522 /* Compute the protection and set it */
2523 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2524 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2528 StartPte
= PointerPte
;
2529 CurrentAddress
= BaseAddress
+ Size
- 1;
2530 CurrentProtection
= SectionProtection
;
2537 /* Is there a leftover section to merge? */
2540 /* Compute and set the protection */
2541 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2542 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2544 /* Handle overlap */
2545 if (ComboPte
== StartPte
) StartPte
++;
2548 /* Finally, handle the last section */
2549 CurrentPte
= MiAddressToPte(CurrentAddress
);
2550 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
2552 /* Handle overlap */
2553 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2554 ASSERT(CurrentPte
>= StartPte
);
2556 /* Compute and set the protection */
2557 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2558 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2564 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2568 PETHREAD CurrentThread
= PsGetCurrentThread();
2569 PFN_COUNT PageCount
= 0;
2570 PFN_NUMBER PageFrameIndex
;
2574 /* The page fault handler is broken and doesn't page back in! */
2575 DPRINT1("WARNING: MiSetPagingOfDriver() called, but paging is broken! ignoring!\n");
2578 /* Get the driver's base address */
2579 ImageBase
= MiPteToAddress(PointerPte
);
2580 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2582 /* If this is a large page, it's stuck in physical memory */
2583 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2585 /* Lock the working set */
2586 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2589 while (PointerPte
<= LastPte
)
2591 /* Check for valid PTE */
2592 if (PointerPte
->u
.Hard
.Valid
== 1)
2594 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2595 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2596 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2598 /* No working sets in ReactOS yet */
2602 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2606 /* Release the working set */
2607 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2609 /* Do we have any driver pages? */
2612 /* Update counters */
2613 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2619 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2621 ULONG_PTR ImageBase
;
2622 PIMAGE_NT_HEADERS NtHeaders
;
2623 ULONG Sections
, Alignment
, Size
;
2624 PIMAGE_SECTION_HEADER Section
;
2625 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2626 if (MmDisablePagingExecutive
) return;
2628 /* Get the driver base address and its NT header */
2629 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2630 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2631 if (!NtHeaders
) return;
2633 /* Get the sections and their alignment */
2634 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2635 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2637 /* Loop each section */
2638 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2641 /* Find PAGE or .edata */
2642 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2643 (*(PULONG
)Section
->Name
== 'ade.'))
2645 /* Had we already done some work? */
2648 /* Nope, setup the first PTE address */
2649 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2654 /* Compute the size */
2655 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2657 /* Find the last PTE that maps this section */
2658 LastPte
= MiAddressToPte(ImageBase
+
2659 Section
->VirtualAddress
+
2666 /* Had we found a section before? */
2669 /* Mark it as pageable */
2670 MiSetPagingOfDriver(PointerPte
, LastPte
);
2675 /* Keep searching */
2680 /* Handle the straggler */
2681 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2686 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2688 PIMAGE_NT_HEADERS NtHeader
;
2691 /* Get NT Headers */
2692 NtHeader
= RtlImageNtHeader(BaseAddress
);
2695 /* Check if this image is only safe for UP while we have 2+ CPUs */
2696 if ((KeNumberProcessors
> 1) &&
2697 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2704 /* Otherwise, it's safe */
2710 MmCheckSystemImage(IN HANDLE ImageHandle
,
2711 IN BOOLEAN PurgeSection
)
2714 HANDLE SectionHandle
;
2715 PVOID ViewBase
= NULL
;
2716 SIZE_T ViewSize
= 0;
2717 IO_STATUS_BLOCK IoStatusBlock
;
2718 FILE_STANDARD_INFORMATION FileStandardInfo
;
2719 KAPC_STATE ApcState
;
2720 PIMAGE_NT_HEADERS NtHeaders
;
2721 OBJECT_ATTRIBUTES ObjectAttributes
;
2724 /* Setup the object attributes */
2725 InitializeObjectAttributes(&ObjectAttributes
,
2727 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2731 /* Create a section for the DLL */
2732 Status
= ZwCreateSection(&SectionHandle
,
2733 SECTION_MAP_EXECUTE
,
2739 if (!NT_SUCCESS(Status
))
2741 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2745 /* Make sure we're in the system process */
2746 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2749 Status
= ZwMapViewOfSection(SectionHandle
,
2759 if (!NT_SUCCESS(Status
))
2761 /* We failed, close the handle and return */
2762 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status
);
2763 KeUnstackDetachProcess(&ApcState
);
2764 ZwClose(SectionHandle
);
2768 /* Now query image information */
2769 Status
= ZwQueryInformationFile(ImageHandle
,
2772 sizeof(FileStandardInfo
),
2773 FileStandardInformation
);
2774 if (NT_SUCCESS(Status
))
2776 /* First, verify the checksum */
2777 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2782 /* Set checksum failure */
2783 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2787 /* Make sure it's a real image */
2788 NtHeaders
= RtlImageNtHeader(ViewBase
);
2791 /* Set checksum failure */
2792 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2796 /* Make sure it's for the correct architecture */
2797 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2798 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2800 /* Set protection failure */
2801 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2805 /* Check that it's a valid SMP image if we have more then one CPU */
2806 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2808 /* Otherwise it's not the right image */
2809 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2813 /* Unmap the section, close the handle, and return status */
2815 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2816 KeUnstackDetachProcess(&ApcState
);
2817 ZwClose(SectionHandle
);
2823 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2824 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2825 IN PUNICODE_STRING LoadedName OPTIONAL
,
2827 OUT PVOID
*ModuleObject
,
2828 OUT PVOID
*ImageBaseAddress
)
2830 PVOID ModuleLoadBase
= NULL
;
2832 HANDLE FileHandle
= NULL
;
2833 OBJECT_ATTRIBUTES ObjectAttributes
;
2834 IO_STATUS_BLOCK IoStatusBlock
;
2835 PIMAGE_NT_HEADERS NtHeader
;
2836 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2837 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2838 ULONG EntrySize
, DriverSize
;
2839 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2840 PCHAR MissingApiName
, Buffer
;
2841 PWCHAR MissingDriverName
;
2842 HANDLE SectionHandle
;
2843 ACCESS_MASK DesiredAccess
;
2844 PVOID Section
= NULL
;
2845 BOOLEAN LockOwned
= FALSE
;
2846 PLIST_ENTRY NextEntry
;
2847 IMAGE_INFO ImageInfo
;
2851 /* Detect session-load */
2855 ASSERT(NamePrefix
== NULL
);
2856 ASSERT(LoadedName
== NULL
);
2858 /* Make sure the process is in session too */
2859 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2862 /* Allocate a buffer we'll use for names */
2863 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
2864 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2866 /* Check for a separator */
2867 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2872 /* Loop the path until we get to the base name */
2873 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2874 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2876 /* Get the length */
2877 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2878 BaseLength
*= sizeof(WCHAR
);
2880 /* Setup the string */
2881 BaseName
.Length
= (USHORT
)BaseLength
;
2882 BaseName
.Buffer
= p
;
2886 /* Otherwise, we already have a base name */
2887 BaseName
.Length
= FileName
->Length
;
2888 BaseName
.Buffer
= FileName
->Buffer
;
2891 /* Setup the maximum length */
2892 BaseName
.MaximumLength
= BaseName
.Length
;
2894 /* Now compute the base directory */
2895 BaseDirectory
= *FileName
;
2896 BaseDirectory
.Length
-= BaseName
.Length
;
2897 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2899 /* And the prefix, which for now is just the name itself */
2900 PrefixName
= *FileName
;
2902 /* Check if we have a prefix */
2903 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2905 /* Check if we already have a name, use it instead */
2906 if (LoadedName
) BaseName
= *LoadedName
;
2908 /* Check for loader snap debugging */
2909 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2911 /* Print out standard string */
2912 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2913 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2916 /* Acquire the load lock */
2918 ASSERT(LockOwned
== FALSE
);
2920 KeEnterCriticalRegion();
2921 KeWaitForSingleObject(&MmSystemLoadLock
,
2927 /* Scan the module list */
2928 NextEntry
= PsLoadedModuleList
.Flink
;
2929 while (NextEntry
!= &PsLoadedModuleList
)
2931 /* Get the entry and compare the names */
2932 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2933 LDR_DATA_TABLE_ENTRY
,
2935 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2937 /* Found it, break out */
2942 NextEntry
= NextEntry
->Flink
;
2945 /* Check if we found the image */
2946 if (NextEntry
!= &PsLoadedModuleList
)
2948 /* Check if we had already mapped a section */
2951 /* Dereference and clear */
2952 ObDereferenceObject(Section
);
2956 /* Check if this was supposed to be a session load */
2959 /* It wasn't, so just return the data */
2960 *ModuleObject
= LdrEntry
;
2961 *ImageBaseAddress
= LdrEntry
->DllBase
;
2962 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2966 /* We don't support session loading yet */
2967 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
2968 Status
= STATUS_NOT_IMPLEMENTED
;
2976 /* It wasn't loaded, and we didn't have a previous attempt */
2977 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2978 KeLeaveCriticalRegion();
2981 /* Check if KD is enabled */
2982 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2984 /* FIXME: Attempt to get image from KD */
2987 /* We don't have a valid entry */
2990 /* Setup image attributes */
2991 InitializeObjectAttributes(&ObjectAttributes
,
2993 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2997 /* Open the image */
2998 Status
= ZwOpenFile(&FileHandle
,
3002 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
3004 if (!NT_SUCCESS(Status
))
3006 DPRINT1("ZwOpenFile failed for '%wZ' with status 0x%x\n",
3012 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
3013 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
3014 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
3015 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
3021 /* Check if this is a session-load */
3024 /* Then we only need read and execute */
3025 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
3029 /* Otherwise, we can allow write access */
3030 DesiredAccess
= SECTION_ALL_ACCESS
;
3033 /* Initialize the attributes for the section */
3034 InitializeObjectAttributes(&ObjectAttributes
,
3036 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3040 /* Create the section */
3041 Status
= ZwCreateSection(&SectionHandle
,
3048 if (!NT_SUCCESS(Status
))
3050 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
3054 /* Now get the section pointer */
3055 Status
= ObReferenceObjectByHandle(SectionHandle
,
3056 SECTION_MAP_EXECUTE
,
3057 MmSectionObjectType
,
3061 ZwClose(SectionHandle
);
3062 if (!NT_SUCCESS(Status
)) goto Quickie
;
3064 /* Check if this was supposed to be a session-load */
3067 /* We don't support session loading yet */
3068 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
3072 /* Check the loader list again, we should end up in the path below */
3077 /* We don't have a valid entry */
3081 /* Load the image */
3082 Status
= MiLoadImageSection(&Section
,
3087 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
3089 /* Get the size of the driver */
3090 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageInformation
.ImageFileSize
;
3092 /* Make sure we're not being loaded into session space */
3095 /* Check for success */
3096 if (NT_SUCCESS(Status
))
3098 /* Support large pages for drivers */
3099 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
3105 /* Dereference the section */
3106 ObDereferenceObject(Section
);
3110 /* Check for failure of the load earlier */
3111 if (!NT_SUCCESS(Status
))
3113 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status
);
3117 /* Relocate the driver */
3118 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
3122 STATUS_CONFLICTING_ADDRESSES
,
3123 STATUS_INVALID_IMAGE_FORMAT
);
3124 if (!NT_SUCCESS(Status
))
3126 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status
);
3130 /* Get the NT Header */
3131 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
3133 /* Calculate the size we'll need for the entry and allocate it */
3134 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
3136 sizeof(UNICODE_NULL
);
3138 /* Allocate the entry */
3139 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
3143 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3147 /* Setup the entry */
3148 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
3149 LdrEntry
->LoadCount
= 1;
3150 LdrEntry
->LoadedImports
= LoadedImports
;
3151 LdrEntry
->PatchInformation
= NULL
;
3153 /* Check the version */
3154 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
3155 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
3157 /* Mark this image as a native image */
3158 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
3161 /* Setup the rest of the entry */
3162 LdrEntry
->DllBase
= ModuleLoadBase
;
3163 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
3164 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
3165 LdrEntry
->SizeOfImage
= DriverSize
;
3166 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
3167 LdrEntry
->SectionPointer
= Section
;
3169 /* Now write the DLL name */
3170 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
3171 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
3172 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
3174 /* Copy and null-terminate it */
3175 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
3178 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3180 /* Now allocate the full name */
3181 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
3183 sizeof(UNICODE_NULL
),
3185 if (!LdrEntry
->FullDllName
.Buffer
)
3187 /* Don't fail, just set it to zero */
3188 LdrEntry
->FullDllName
.Length
= 0;
3189 LdrEntry
->FullDllName
.MaximumLength
= 0;
3194 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
3195 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
3197 /* Copy and null-terminate */
3198 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
3201 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3205 MiProcessLoaderEntry(LdrEntry
, TRUE
);
3207 /* Resolve imports */
3208 MissingApiName
= Buffer
;
3209 MissingDriverName
= NULL
;
3210 Status
= MiResolveImageReferences(ModuleLoadBase
,
3216 if (!NT_SUCCESS(Status
))
3218 BOOLEAN NeedToFreeString
= FALSE
;
3220 /* If the lowest bit is set to 1, this is a hint that we need to free */
3221 if (*(ULONG_PTR
*)&MissingDriverName
& 1)
3223 NeedToFreeString
= TRUE
;
3224 *(ULONG_PTR
*)&MissingDriverName
&= ~1;
3227 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status
);
3228 DPRINT1(" Missing driver '%ls', missing API '%s'\n",
3229 MissingDriverName
, MissingApiName
);
3231 if (NeedToFreeString
)
3233 ExFreePoolWithTag(MissingDriverName
, TAG_LDR_WSTR
);
3237 MiProcessLoaderEntry(LdrEntry
, FALSE
);
3239 /* Check if we need to free the name */
3240 if (LdrEntry
->FullDllName
.Buffer
)
3243 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
3246 /* Free the entry itself */
3247 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
3252 /* Update the loader entry */
3253 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
3254 LDRP_ENTRY_PROCESSED
|
3256 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
3257 LdrEntry
->LoadedImports
= LoadedImports
;
3259 /* FIXME: Call driver verifier's loader function */
3261 /* Write-protect the system image */
3262 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
3264 /* Check if notifications are enabled */
3265 if (PsImageNotifyEnabled
)
3267 /* Fill out the notification data */
3268 ImageInfo
.Properties
= 0;
3269 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
3270 ImageInfo
.SystemModeImage
= TRUE
;
3271 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
3272 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
3273 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
3275 /* Send the notification */
3276 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
3279 #if defined(KDBG) || defined(_WINKD_)
3280 /* MiCacheImageSymbols doesn't detect rossym */
3283 /* Check if there's symbols */
3284 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
3287 /* Check if the system root is present */
3288 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
3289 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
3291 /* Add the system root */
3292 UnicodeTemp
= PrefixName
;
3293 UnicodeTemp
.Buffer
+= 11;
3294 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
3297 &SharedUserData
->NtSystemRoot
[2],
3302 /* Build the name */
3303 sprintf_nt(Buffer
, "%wZ", &BaseName
);
3306 /* Setup the ansi string */
3307 RtlInitString(&AnsiTemp
, Buffer
);
3309 /* Notify the debugger */
3310 DbgLoadImageSymbols(&AnsiTemp
,
3312 (ULONG_PTR
)ZwCurrentProcess());
3313 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
3316 /* Page the driver */
3317 ASSERT(Section
== NULL
);
3318 MiEnablePagingOfDriver(LdrEntry
);
3320 /* Return pointers */
3321 *ModuleObject
= LdrEntry
;
3322 *ImageBaseAddress
= LdrEntry
->DllBase
;
3325 /* Check if we have the lock acquired */
3328 /* Release the lock */
3329 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
3330 KeLeaveCriticalRegion();
3334 /* If we have a file handle, close it */
3335 if (FileHandle
) ZwClose(FileHandle
);
3337 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3338 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3340 /* Free the name buffer and return status */
3341 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
3345 PLDR_DATA_TABLE_ENTRY
3347 MiLookupDataTableEntry(IN PVOID Address
)
3349 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
3350 PLIST_ENTRY NextEntry
;
3354 NextEntry
= PsLoadedModuleList
.Flink
;
3357 /* Get the loader entry */
3358 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3359 LDR_DATA_TABLE_ENTRY
,
3362 /* Check if the address matches */
3363 if ((Address
>= LdrEntry
->DllBase
) &&
3364 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3365 LdrEntry
->SizeOfImage
)))
3368 FoundEntry
= LdrEntry
;
3373 NextEntry
= NextEntry
->Flink
;
3374 } while(NextEntry
!= &PsLoadedModuleList
);
3376 /* Return the entry */
3380 /* PUBLIC FUNCTIONS ***********************************************************/
3387 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3389 PMMPTE StartPte
, EndPte
;
3390 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3393 /* Get the loader entry */
3394 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3395 if (!LdrEntry
) return NULL
;
3397 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3398 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3400 /* Don't do anything, just return the base address */
3401 return LdrEntry
->DllBase
;
3404 /* Wait for active DPCs to finish before we page out the driver */
3405 KeFlushQueuedDpcs();
3407 /* Get the PTE range for the whole driver image */
3408 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3409 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3411 /* Enable paging for the PTE range */
3412 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3413 MiSetPagingOfDriver(StartPte
, EndPte
);
3415 /* Return the base address */
3416 return LdrEntry
->DllBase
;
3424 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3434 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3436 PVOID ProcAddress
= NULL
;
3437 ANSI_STRING AnsiRoutineName
;
3439 PLIST_ENTRY NextEntry
;
3440 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3441 BOOLEAN Found
= FALSE
;
3442 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3443 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3446 /* Convert routine to ansi name */
3447 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3450 if (!NT_SUCCESS(Status
)) return NULL
;
3453 KeEnterCriticalRegion();
3454 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3456 /* Loop the loaded module list */
3457 NextEntry
= PsLoadedModuleList
.Flink
;
3458 while (NextEntry
!= &PsLoadedModuleList
)
3461 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3462 LDR_DATA_TABLE_ENTRY
,
3465 /* Check if it's the kernel or HAL */
3466 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3472 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3479 /* Check if we found a valid binary */
3482 /* Find the procedure name */
3483 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3486 /* Break out if we found it or if we already tried both modules */
3487 if (ProcAddress
) break;
3488 if (Modules
== 2) break;
3492 NextEntry
= NextEntry
->Flink
;
3495 /* Release the lock */
3496 ExReleaseResourceLite(&PsLoadedModuleResource
);
3497 KeLeaveCriticalRegion();
3499 /* Free the string and return */
3500 RtlFreeAnsiString(&AnsiRoutineName
);