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 DPRINT1("Session loading not yet supported!\n");
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
->ImageSize
) >> 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 */
560 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
561 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
564 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
565 ExReleaseResourceLite(&PsLoadedModuleResource
);
566 KeLeaveCriticalRegion();
572 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
577 ULONG_PTR OldBaseTop
, Delta
;
578 PLDR_DATA_TABLE_ENTRY LdrEntry
;
579 PLIST_ENTRY NextEntry
;
582 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
583 // since a real version of Windows would fail at this point, but they seem
584 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
585 // a feature which isn't even used by Windows. Priorities, priorities...
586 // Please note that Microsoft WDK EULA and license prohibits using
587 // the information contained within it for the generation of "non-Windows"
588 // drivers, which is precisely what LD will generate, since an LD driver
589 // will not load on Windows.
591 #ifdef _WORKING_LINKER_
594 PULONG_PTR ImageThunk
;
595 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
597 /* Calculate the top and delta */
598 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
599 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
601 /* Loop the loader block */
602 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
603 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
604 NextEntry
= NextEntry
->Flink
)
606 /* Get the loader entry */
607 LdrEntry
= CONTAINING_RECORD(NextEntry
,
608 LDR_DATA_TABLE_ENTRY
,
610 #ifdef _WORKING_LINKER_
612 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
614 IMAGE_DIRECTORY_ENTRY_IAT
,
616 if (!ImageThunk
) continue;
618 /* Make sure we have an IAT */
619 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
620 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
622 /* Check if it's within this module */
623 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
626 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
627 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
628 *ImageThunk
+= Delta
;
632 /* Get the import table */
633 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
635 IMAGE_DIRECTORY_ENTRY_IMPORT
,
637 if (!ImportDescriptor
) continue;
639 /* Make sure we have an IAT */
640 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
641 while ((ImportDescriptor
->Name
) &&
642 (ImportDescriptor
->OriginalFirstThunk
))
644 /* Get the image thunk */
645 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
646 ImportDescriptor
->FirstThunk
);
649 /* Check if it's within this module */
650 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
653 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
654 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
655 *ImageThunk
+= Delta
;
658 /* Go to the next thunk */
662 /* Go to the next import */
671 MiSnapThunk(IN PVOID DllBase
,
673 IN PIMAGE_THUNK_DATA Name
,
674 IN PIMAGE_THUNK_DATA Address
,
675 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
677 IN BOOLEAN SnapForwarder
,
678 OUT PCHAR
*MissingApi
)
683 PUSHORT OrdinalTable
;
684 PIMAGE_IMPORT_BY_NAME NameImport
;
686 ULONG Low
= 0, Mid
= 0, High
;
689 PCHAR MissingForwarder
;
690 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
693 UNICODE_STRING ForwarderName
;
694 PLIST_ENTRY NextEntry
;
695 PLDR_DATA_TABLE_ENTRY LdrEntry
;
696 ULONG ForwardExportSize
;
697 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
698 PIMAGE_IMPORT_BY_NAME ForwardName
;
699 SIZE_T ForwardLength
;
700 IMAGE_THUNK_DATA ForwardThunk
;
703 /* Check if this is an ordinal */
704 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
705 if ((IsOrdinal
) && !(SnapForwarder
))
707 /* Get the ordinal number and set it as missing */
708 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
709 ExportDirectory
->Base
);
710 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
714 /* Get the VA if we don't have to snap */
715 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
716 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
718 /* Copy the procedure name */
719 RtlStringCbCopyA(*MissingApi
,
720 MAXIMUM_FILENAME_LENGTH
,
721 (PCHAR
)&NameImport
->Name
[0]);
723 /* Setup name tables */
724 DPRINT("Import name: %s\n", NameImport
->Name
);
725 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
726 ExportDirectory
->AddressOfNames
);
727 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
728 ExportDirectory
->AddressOfNameOrdinals
);
730 /* Get the hint and check if it's valid */
731 Hint
= NameImport
->Hint
;
732 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
733 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
735 /* We have a match, get the ordinal number from here */
736 Ordinal
= OrdinalTable
[Hint
];
740 /* Do a binary search */
741 High
= ExportDirectory
->NumberOfNames
- 1;
744 /* Get new middle value */
745 Mid
= (Low
+ High
) >> 1;
748 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
766 /* Check if we couldn't find it */
769 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport
->Name
);
770 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
773 /* Otherwise, this is the ordinal */
774 Ordinal
= OrdinalTable
[Mid
];
778 /* Check if the ordinal is invalid */
779 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
782 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
786 /* In case the forwarder is missing */
787 MissingForwarder
= NameBuffer
;
789 /* Resolve the address and write it */
790 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
791 ExportDirectory
->AddressOfFunctions
);
792 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
794 /* Assume success from now on */
795 Status
= STATUS_SUCCESS
;
797 /* Check if the function is actually a forwarder */
798 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
799 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
801 /* Now assume failure in case the forwarder doesn't exist */
802 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
804 /* Build the forwarder name */
805 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
806 DllName
.Length
= (USHORT
)(strchr(DllName
.Buffer
, '.') -
809 DllName
.MaximumLength
= DllName
.Length
;
812 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
816 /* We failed, just return an error */
820 /* Loop the module list */
821 NextEntry
= PsLoadedModuleList
.Flink
;
822 while (NextEntry
!= &PsLoadedModuleList
)
824 /* Get the loader entry */
825 LdrEntry
= CONTAINING_RECORD(NextEntry
,
826 LDR_DATA_TABLE_ENTRY
,
829 /* Check if it matches */
830 if (RtlPrefixString((PSTRING
)&ForwarderName
,
831 (PSTRING
)&LdrEntry
->BaseDllName
,
834 /* Get the forwarder export directory */
835 ForwardExportDirectory
=
836 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
838 IMAGE_DIRECTORY_ENTRY_EXPORT
,
840 if (!ForwardExportDirectory
) break;
842 /* Allocate a name entry */
843 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
845 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
846 sizeof(*ForwardName
) +
849 if (!ForwardName
) break;
852 RtlCopyMemory(&ForwardName
->Name
[0],
853 DllName
.Buffer
+ DllName
.Length
,
855 ForwardName
->Hint
= 0;
857 /* Set the new address */
858 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
860 /* Snap the forwarder */
861 Status
= MiSnapThunk(LdrEntry
->DllBase
,
865 ForwardExportDirectory
,
870 /* Free the forwarder name and set the thunk */
871 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
872 Address
->u1
= ForwardThunk
.u1
;
876 /* Go to the next entry */
877 NextEntry
= NextEntry
->Flink
;
881 RtlFreeUnicodeString(&ForwarderName
);
891 MmUnloadSystemImage(IN PVOID ImageHandle
)
893 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
894 PVOID BaseAddress
= LdrEntry
->DllBase
;
897 BOOLEAN HadEntry
= FALSE
;
899 /* Acquire the loader lock */
900 KeEnterCriticalRegion();
901 KeWaitForSingleObject(&MmSystemLoadLock
,
907 /* Check if this driver was loaded at boot and didn't get imports parsed */
908 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
910 /* We should still be alive */
911 ASSERT(LdrEntry
->LoadCount
!= 0);
912 LdrEntry
->LoadCount
--;
914 /* Check if we're still loaded */
915 if (LdrEntry
->LoadCount
) goto Done
;
917 /* We should cleanup... are symbols loaded */
918 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
920 /* Create the ANSI name */
921 Status
= RtlUnicodeStringToAnsiString(&TempName
,
922 &LdrEntry
->BaseDllName
,
924 if (NT_SUCCESS(Status
))
926 /* Unload the symbols */
927 DbgUnLoadImageSymbols(&TempName
,
929 (ULONG_PTR
)ZwCurrentProcess());
930 RtlFreeAnsiString(&TempName
);
934 /* FIXME: Free the driver */
935 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
936 //MmFreeSection(LdrEntry->DllBase);
938 /* Check if we're linked in */
939 if (LdrEntry
->InLoadOrderLinks
.Flink
)
942 MiProcessLoaderEntry(LdrEntry
, FALSE
);
946 /* Dereference and clear the imports */
947 MiDereferenceImports(LdrEntry
->LoadedImports
);
948 MiClearImports(LdrEntry
);
950 /* Check if the entry needs to go away */
953 /* Check if it had a name */
954 if (LdrEntry
->FullDllName
.Buffer
)
957 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
960 /* Check if we had a section */
961 if (LdrEntry
->SectionPointer
)
964 ObDereferenceObject(LdrEntry
->SectionPointer
);
968 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
971 /* Release the system lock and return */
973 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
974 KeLeaveCriticalRegion();
975 return STATUS_SUCCESS
;
980 MiResolveImageReferences(IN PVOID ImageBase
,
981 IN PUNICODE_STRING ImageFileDirectory
,
982 IN PUNICODE_STRING NamePrefix OPTIONAL
,
983 OUT PCHAR
*MissingApi
,
984 OUT PWCHAR
*MissingDriver
,
985 OUT PLOAD_IMPORTS
*LoadImports
)
987 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
988 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
989 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
990 PLOAD_IMPORTS LoadedImports
, NewImports
;
991 ULONG GdiLink
, NormalLink
, i
;
992 BOOLEAN ReferenceNeeded
, Loaded
;
993 ANSI_STRING TempString
;
994 UNICODE_STRING NameString
, DllName
;
995 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
996 PVOID ImportBase
, DllBase
;
997 PLIST_ENTRY NextEntry
;
998 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
1000 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
1002 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
1003 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
1005 /* Assume no imports */
1006 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
1008 /* Get the import descriptor */
1009 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
1011 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1013 if (!ImportDescriptor
) return STATUS_SUCCESS
;
1015 /* Loop all imports to count them */
1016 for (CurrentImport
= ImportDescriptor
;
1017 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
1024 /* Make sure we have non-zero imports */
1027 /* Calculate and allocate the list we'll need */
1028 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1029 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1035 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1036 LoadedImports
->Count
= ImportCount
;
1042 LoadedImports
= NULL
;
1045 /* Reset the import count and loop descriptors again */
1046 ImportCount
= GdiLink
= NormalLink
= 0;
1047 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1050 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1052 /* Check if this is a GDI driver */
1054 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1056 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1057 NormalLink
= NormalLink
|
1058 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1059 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1060 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1061 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1063 /* Check if this is a valid GDI driver */
1064 if ((GdiLink
) && (NormalLink
))
1066 /* It's not, it's importing stuff it shouldn't be! */
1067 MiDereferenceImports(LoadedImports
);
1068 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1069 return STATUS_PROCEDURE_NOT_FOUND
;
1072 /* Check for user-mode printer or video card drivers, which don't belong */
1073 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1074 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1075 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1076 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1077 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1078 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1080 /* This is not kernel code */
1081 MiDereferenceImports(LoadedImports
);
1082 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1083 return STATUS_PROCEDURE_NOT_FOUND
;
1086 /* Check if this is a "core" import, which doesn't get referenced */
1087 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1088 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1089 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1091 /* Don't reference this */
1092 ReferenceNeeded
= FALSE
;
1096 /* Reference these modules */
1097 ReferenceNeeded
= TRUE
;
1100 /* Now setup a unicode string for the import */
1101 RtlInitAnsiString(&TempString
, ImportName
);
1102 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1103 if (!NT_SUCCESS(Status
))
1106 MiDereferenceImports(LoadedImports
);
1107 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1111 /* We don't support name prefixes yet */
1112 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1114 /* Remember that we haven't loaded the import at this point */
1119 /* Loop the driver list */
1120 NextEntry
= PsLoadedModuleList
.Flink
;
1121 while (NextEntry
!= &PsLoadedModuleList
)
1123 /* Get the loader entry and compare the name */
1124 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1125 LDR_DATA_TABLE_ENTRY
,
1127 if (RtlEqualUnicodeString(&NameString
,
1128 &LdrEntry
->BaseDllName
,
1131 /* Get the base address */
1132 ImportBase
= LdrEntry
->DllBase
;
1134 /* Check if we haven't loaded yet, and we need references */
1135 if (!(Loaded
) && (ReferenceNeeded
))
1137 /* Make sure we're not already loading */
1138 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1140 /* Increase the load count */
1141 LdrEntry
->LoadCount
++;
1145 /* Done, break out */
1149 /* Go to the next entry */
1150 NextEntry
= NextEntry
->Flink
;
1153 /* Check if we haven't loaded the import yet */
1156 /* Setup the import DLL name */
1157 DllName
.MaximumLength
= NameString
.Length
+
1158 ImageFileDirectory
->Length
+
1159 sizeof(UNICODE_NULL
);
1160 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1161 DllName
.MaximumLength
,
1165 /* Setup the base length and copy it */
1166 DllName
.Length
= ImageFileDirectory
->Length
;
1167 RtlCopyMemory(DllName
.Buffer
,
1168 ImageFileDirectory
->Buffer
,
1169 ImageFileDirectory
->Length
);
1171 /* Now add the import name and null-terminate it */
1172 RtlAppendUnicodeStringToString(&DllName
,
1174 DllName
.Buffer
[DllName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1176 /* Load the image */
1177 Status
= MmLoadSystemImage(&DllName
,
1183 if (NT_SUCCESS(Status
))
1185 /* We can free the DLL Name */
1186 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1190 /* Fill out the information for the error */
1191 *MissingDriver
= DllName
.Buffer
;
1192 *(PULONG
)MissingDriver
|= 1;
1195 DPRINT1("Failed to load dependency: %wZ\n", &DllName
);
1200 /* We're out of resources */
1201 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1204 /* Check if we're OK until now */
1205 if (NT_SUCCESS(Status
))
1207 /* We're now loaded */
1211 ASSERT(DllBase
== DllEntry
->DllBase
);
1213 /* Call the initialization routines */
1214 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1215 if (!NT_SUCCESS(Status
))
1217 /* We failed, unload the image */
1218 MmUnloadSystemImage(DllEntry
);
1219 DPRINT1("MmCallDllInitialize failed with status 0x%x\n", Status
);
1225 /* Check if we failed by here */
1226 if (!NT_SUCCESS(Status
))
1228 /* Cleanup and return */
1229 RtlFreeUnicodeString(&NameString
);
1230 MiDereferenceImports(LoadedImports
);
1231 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1235 /* Loop again to make sure that everything is OK */
1239 /* Check if we're support to reference this import */
1240 if ((ReferenceNeeded
) && (LoadedImports
))
1242 /* Make sure we're not already loading */
1243 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1246 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1251 /* Free the import name */
1252 RtlFreeUnicodeString(&NameString
);
1254 /* Set the missing driver name and get the export directory */
1255 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1256 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1258 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1260 if (!ExportDirectory
)
1262 /* Cleanup and return */
1263 MiDereferenceImports(LoadedImports
);
1264 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1265 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver
);
1266 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1269 /* Make sure we have an IAT */
1270 if (ImportDescriptor
->OriginalFirstThunk
)
1272 /* Get the first thunks */
1273 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1274 ImportDescriptor
->OriginalFirstThunk
);
1275 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1276 ImportDescriptor
->FirstThunk
);
1279 while (OrigThunk
->u1
.AddressOfData
)
1282 Status
= MiSnapThunk(ImportBase
,
1290 if (!NT_SUCCESS(Status
))
1292 /* Cleanup and return */
1293 MiDereferenceImports(LoadedImports
);
1294 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1298 /* Reset the buffer */
1299 *MissingApi
= MissingApiBuffer
;
1303 /* Go to the next import */
1307 /* Check if we have an import list */
1310 /* Reset the count again, and loop entries */
1312 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1314 if (LoadedImports
->Entry
[i
])
1316 /* Got an entry, OR it with 1 in case it's the single entry */
1317 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1318 MM_SYSLDR_SINGLE_ENTRY
);
1323 /* Check if we had no imports */
1326 /* Free the list and set it to no imports */
1327 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1328 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1330 else if (ImportCount
== 1)
1332 /* Just one entry, we can free the table and only use our entry */
1333 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1334 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1336 else if (ImportCount
!= LoadedImports
->Count
)
1338 /* Allocate a new list */
1339 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1340 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1346 NewImports
->Count
= 0;
1348 /* Loop all the imports */
1349 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1351 /* Make sure it's valid */
1352 if (LoadedImports
->Entry
[i
])
1355 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1356 NewImports
->Count
++;
1360 /* Free the old copy */
1361 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1362 LoadedImports
= NewImports
;
1366 /* Return the list */
1367 *LoadImports
= LoadedImports
;
1370 /* Return success */
1371 return STATUS_SUCCESS
;
1377 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1379 PLIST_ENTRY NextEntry
;
1381 PIMAGE_NT_HEADERS NtHeader
;
1382 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1383 PIMAGE_FILE_HEADER FileHeader
;
1384 BOOLEAN ValidRelocs
;
1385 PIMAGE_DATA_DIRECTORY DataDirectory
;
1386 PVOID DllBase
, NewImageAddress
;
1388 PMMPTE PointerPte
, StartPte
, LastPte
;
1391 MMPTE TempPte
, OldPte
;
1393 /* Loop driver list */
1394 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1395 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1396 NextEntry
= NextEntry
->Flink
)
1398 /* Get the loader entry and NT header */
1399 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1400 LDR_DATA_TABLE_ENTRY
,
1402 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1405 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1407 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1408 &LdrEntry
->FullDllName
);
1410 /* Get the first PTE and the number of PTEs we'll need */
1411 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1412 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1413 LastPte
= StartPte
+ PteCount
;
1417 while (PointerPte
< LastPte
)
1420 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1421 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1422 len
= wcslen(LdrEntry
->BaseDllName
.Buffer
) * sizeof(WCHAR
);
1423 snprintf(Pfn1
->ProcessName
, min(16, len
), "%S", LdrEntry
->BaseDllName
.Buffer
);
1427 /* Skip kernel and HAL */
1428 /* ROS HACK: Skip BOOTVID/KDCOM too */
1430 if (i
<= 4) continue;
1432 /* Skip non-drivers */
1433 if (!NtHeader
) continue;
1435 /* Get the file header and make sure we can relocate */
1436 FileHeader
= &NtHeader
->FileHeader
;
1437 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1438 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1439 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1441 /* Everything made sense until now, check the relocation section too */
1442 DataDirectory
= &NtHeader
->OptionalHeader
.
1443 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1444 if (!DataDirectory
->VirtualAddress
)
1446 /* We don't really have relocations */
1447 ValidRelocs
= FALSE
;
1451 /* Make sure the size is valid */
1452 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1453 LdrEntry
->SizeOfImage
)
1455 /* They're not, skip */
1459 /* We have relocations */
1463 /* Remember the original address */
1464 DllBase
= LdrEntry
->DllBase
;
1467 PointerPte
= StartPte
;
1468 while (PointerPte
< LastPte
)
1470 /* Mark the page modified in the PFN database */
1471 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1472 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1473 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1474 Pfn1
->u3
.e1
.Modified
= TRUE
;
1480 /* Now reserve system PTEs for the image */
1481 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1484 /* Shouldn't happen */
1485 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1489 /* This is the new virtual address for the module */
1490 LastPte
= PointerPte
+ PteCount
;
1491 NewImageAddress
= MiPteToAddress(PointerPte
);
1494 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1495 ASSERT(ExpInitializationPhase
== 0);
1497 /* Loop the new driver PTEs */
1498 TempPte
= ValidKernelPte
;
1499 while (PointerPte
< LastPte
)
1501 /* Copy the old data */
1503 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1505 /* Set page number from the loader's memory */
1506 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1509 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1516 /* Update position */
1517 PointerPte
-= PteCount
;
1520 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1522 /* Set the image base to the address where the loader put it */
1523 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1525 /* Check if we had relocations */
1528 /* Relocate the image */
1529 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1533 STATUS_CONFLICTING_ADDRESSES
,
1534 STATUS_INVALID_IMAGE_FORMAT
);
1535 if (!NT_SUCCESS(Status
))
1537 /* This shouldn't happen */
1538 DPRINT1("Relocations failed!\n");
1543 /* Update the loader entry */
1544 LdrEntry
->DllBase
= NewImageAddress
;
1546 /* Update the thunks */
1547 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1548 MiUpdateThunks(LoaderBlock
,
1551 LdrEntry
->SizeOfImage
);
1553 /* Update the loader entry */
1554 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1555 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1556 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1557 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1559 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1566 MiBuildImportsForBootDrivers(VOID
)
1568 PLIST_ENTRY NextEntry
, NextEntry2
;
1569 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1570 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1571 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1572 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1573 PLOAD_IMPORTS LoadedImports
;
1574 ULONG LoadedImportsSize
, ImportSize
;
1575 PULONG_PTR ImageThunk
;
1576 ULONG_PTR DllBase
, DllEnd
;
1577 ULONG Modules
= 0, i
, j
= 0;
1578 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1580 /* Initialize variables */
1581 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1583 /* Loop the loaded module list... we are early enough that no lock is needed */
1584 NextEntry
= PsLoadedModuleList
.Flink
;
1585 while (NextEntry
!= &PsLoadedModuleList
)
1588 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1589 LDR_DATA_TABLE_ENTRY
,
1592 /* Check if it's the kernel or HAL */
1593 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1596 KernelEntry
= LdrEntry
;
1598 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1601 HalEntry
= LdrEntry
;
1604 /* Check if this is a driver DLL */
1605 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1607 /* Check if this is the HAL or kernel */
1608 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1610 /* Add a reference */
1611 LdrEntry
->LoadCount
= 1;
1615 /* No referencing needed */
1616 LdrEntry
->LoadCount
= 0;
1621 /* No referencing needed */
1622 LdrEntry
->LoadCount
= 0;
1625 /* Remember this came from the loader */
1626 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1629 NextEntry
= NextEntry
->Flink
;
1633 /* We must have at least found the kernel and HAL */
1634 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1636 /* Allocate the list */
1637 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), TAG_LDR_IMPORTS
);
1638 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1640 /* Loop the loaded module list again */
1641 NextEntry
= PsLoadedModuleList
.Flink
;
1642 while (NextEntry
!= &PsLoadedModuleList
)
1645 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1646 LDR_DATA_TABLE_ENTRY
,
1648 #ifdef _WORKING_LOADER_
1649 /* Get its imports */
1650 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1652 IMAGE_DIRECTORY_ENTRY_IAT
,
1656 /* Get its imports */
1657 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1659 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1661 if (!ImportDescriptor
)
1665 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1666 NextEntry
= NextEntry
->Flink
;
1670 /* Clear the list and count the number of IAT thunks */
1671 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1672 #ifdef _WORKING_LOADER_
1673 ImportSize
/= sizeof(ULONG_PTR
);
1675 /* Scan the thunks */
1676 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1678 DllBase
= DllEnd
= i
= 0;
1679 while ((ImportDescriptor
->Name
) &&
1680 (ImportDescriptor
->OriginalFirstThunk
))
1682 /* Get the image thunk */
1683 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1684 ImportDescriptor
->FirstThunk
);
1688 /* Do we already have an address? */
1691 /* Is the thunk in the same address? */
1692 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1694 /* Skip it, we already have a reference for it */
1695 ASSERT(EntryArray
[j
]);
1701 /* Loop the loaded module list to locate this address owner */
1703 NextEntry2
= PsLoadedModuleList
.Flink
;
1704 while (NextEntry2
!= &PsLoadedModuleList
)
1707 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
1708 LDR_DATA_TABLE_ENTRY
,
1711 /* Get the address range for this module */
1712 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
1713 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
1715 /* Check if this IAT entry matches it */
1716 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1719 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
1720 EntryArray
[j
] = LdrEntry2
;
1724 /* Keep searching */
1725 NextEntry2
= NextEntry2
->Flink
;
1729 /* Do we have a thunk outside the range? */
1730 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
1735 /* Should not be happening */
1736 DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
1737 LdrEntry
, ImageThunk
, *ImageThunk
);
1741 /* Reset if we hit this */
1744 #ifndef _WORKING_LOADER_
1753 /* Now scan how many imports we really have */
1754 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
1756 /* Skip HAL and kernel */
1757 if ((EntryArray
[i
]) &&
1758 (EntryArray
[i
] != HalEntry
) &&
1759 (EntryArray
[i
] != KernelEntry
))
1761 /* A valid reference */
1762 LastEntry
= EntryArray
[i
];
1767 /* Do we have any imports after all? */
1771 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1773 else if (ImportSize
== 1)
1775 /* A single entry import */
1776 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
1777 LastEntry
->LoadCount
++;
1781 /* We need an import table */
1782 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
1783 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1786 ASSERT(LoadedImports
);
1788 /* Save the count */
1789 LoadedImports
->Count
= ImportSize
;
1791 /* Now copy all imports */
1792 for (i
= 0, j
= 0; i
< Modules
; i
++)
1794 /* Skip HAL and kernel */
1795 if ((EntryArray
[i
]) &&
1796 (EntryArray
[i
] != HalEntry
) &&
1797 (EntryArray
[i
] != KernelEntry
))
1799 /* A valid reference */
1800 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
1801 LoadedImports
->Entry
[j
] = EntryArray
[i
];
1802 EntryArray
[i
]->LoadCount
++;
1807 /* Should had as many entries as we expected */
1808 ASSERT(j
== ImportSize
);
1809 LdrEntry
->LoadedImports
= LoadedImports
;
1813 NextEntry
= NextEntry
->Flink
;
1816 /* Free the initial array */
1817 ExFreePoolWithTag(EntryArray
, TAG_LDR_IMPORTS
);
1819 /* FIXME: Might not need to keep the HAL/Kernel imports around */
1821 /* Kernel and HAL are loaded at boot */
1822 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1823 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1825 /* All worked well */
1826 return STATUS_SUCCESS
;
1832 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1835 PIMAGE_NT_HEADERS NtHeaders
;
1836 PIMAGE_SECTION_HEADER SectionHeader
;
1837 ULONG Sections
, Size
;
1839 /* Get the kernel section header */
1840 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1841 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
1842 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
1844 /* Loop all the sections */
1845 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
1848 /* Grab the size of the section */
1849 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
1851 /* Check for .RSRC section */
1852 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
1854 /* Remember the PTEs so we can modify them later */
1855 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
1856 SectionHeader
->VirtualAddress
);
1857 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
1858 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
1860 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
1862 /* POOLCODE vs. POOLMI */
1863 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
1865 /* Found Ex* Pool code */
1866 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1867 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
1869 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
1871 /* Found Mm* Pool code */
1872 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1873 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
1876 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
1877 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
1879 /* Found MISYSPTE (Mm System PTE code)*/
1880 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1881 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
1893 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1895 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1896 PLIST_ENTRY ListHead
, NextEntry
;
1899 /* Setup the loaded module list and locks */
1900 ExInitializeResourceLite(&PsLoadedModuleResource
);
1901 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1902 InitializeListHead(&PsLoadedModuleList
);
1904 /* Get loop variables and the kernel entry */
1905 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1906 NextEntry
= ListHead
->Flink
;
1907 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1908 LDR_DATA_TABLE_ENTRY
,
1910 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1912 /* Locate resource section, pool code, and system pte code */
1913 MiLocateKernelSections(LdrEntry
);
1915 /* Loop the loader block */
1916 while (NextEntry
!= ListHead
)
1918 /* Get the loader entry */
1919 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1920 LDR_DATA_TABLE_ENTRY
,
1923 /* FIXME: ROS HACK. Make sure this is a driver */
1924 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1926 /* Skip this entry */
1927 NextEntry
= NextEntry
->Flink
;
1931 /* Calculate the size we'll need and allocate a copy */
1932 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1933 LdrEntry
->BaseDllName
.MaximumLength
+
1934 sizeof(UNICODE_NULL
);
1935 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1936 if (!NewEntry
) return FALSE
;
1938 /* Copy the entry over */
1939 *NewEntry
= *LdrEntry
;
1941 /* Allocate the name */
1942 NewEntry
->FullDllName
.Buffer
=
1943 ExAllocatePoolWithTag(PagedPool
,
1944 LdrEntry
->FullDllName
.MaximumLength
+
1945 sizeof(UNICODE_NULL
),
1947 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1949 /* Set the base name */
1950 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1952 /* Copy the full and base name */
1953 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1954 LdrEntry
->FullDllName
.Buffer
,
1955 LdrEntry
->FullDllName
.MaximumLength
);
1956 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1957 LdrEntry
->BaseDllName
.Buffer
,
1958 LdrEntry
->BaseDllName
.MaximumLength
);
1960 /* Null-terminate the base name */
1961 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1962 sizeof(WCHAR
)] = UNICODE_NULL
;
1964 /* Insert the entry into the list */
1965 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1966 NextEntry
= NextEntry
->Flink
;
1969 /* Build the import lists for the boot drivers */
1970 MiBuildImportsForBootDrivers();
1978 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
1979 IN OUT PVOID
*ImageBaseAddress
,
1980 IN PUNICODE_STRING BaseImageName
,
1981 IN BOOLEAN BootDriver
)
1983 PLIST_ENTRY NextEntry
;
1984 BOOLEAN DriverFound
= FALSE
;
1985 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
1986 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
1987 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
1990 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
1991 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
1994 /* Make sure there's enough system PTEs for a large page driver */
1995 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
2000 /* This happens if the registry key had a "*" (wildcard) in it */
2001 if (MiLargePageAllDrivers
== 0)
2003 /* It didn't, so scan the list */
2004 NextEntry
= MiLargePageDriverList
.Flink
;
2005 while (NextEntry
!= &MiLargePageDriverList
)
2007 /* Check if the driver name matches */
2008 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
2009 MI_LARGE_PAGE_DRIVER_ENTRY
,
2011 if (RtlEqualUnicodeString(BaseImageName
,
2012 &LargePageDriverEntry
->BaseName
,
2015 /* Enable large pages for this driver */
2021 NextEntry
= NextEntry
->Flink
;
2024 /* If we didn't find the driver, it doesn't need large pages */
2025 if (DriverFound
== FALSE
) return FALSE
;
2028 /* Nothing to do yet */
2029 DPRINT1("Large pages not supported!\n");
2035 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
2036 IN ULONG SectionProtection
)
2038 ULONG Protection
= MM_ZERO_ACCESS
;
2040 /* Check if the caller gave anything */
2041 if (SectionProtection
)
2043 /* Always turn on execute access */
2044 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
2046 /* Check if the registry setting is on or not */
2047 if (!MmEnforceWriteProtection
)
2049 /* Turn on write access too */
2050 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
2054 /* Convert to internal PTE flags */
2055 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
2056 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
2058 /* Check for write access */
2059 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
2061 /* Session space is not supported */
2064 DPRINT1("Session drivers not supported\n");
2065 ASSERT(SessionSpace
== FALSE
);
2069 /* Convert to internal PTE flag */
2070 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
2074 /* If there's no access at all by now, convert to internal no access flag */
2075 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
2077 /* Return the computed PTE protection */
2083 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
2085 IN ULONG ProtectionMask
)
2087 /* I'm afraid to introduce regressions at the moment... */
2093 MiWriteProtectSystemImage(IN PVOID ImageBase
)
2095 PIMAGE_NT_HEADERS NtHeaders
;
2096 PIMAGE_SECTION_HEADER Section
;
2097 PFN_NUMBER DriverPages
;
2098 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
= 0, ProtectionMask
;
2099 ULONG Sections
, Size
;
2100 ULONG_PTR BaseAddress
, CurrentAddress
;
2101 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
2102 ULONG CurrentMask
, CombinedMask
= 0;
2105 /* No need to write protect physical memory-backed drivers (large pages) */
2106 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2108 /* Get the image headers */
2109 NtHeaders
= RtlImageNtHeader(ImageBase
);
2110 if (!NtHeaders
) return;
2112 /* Check if this is a session driver or not */
2113 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
2115 /* Don't touch NT4 drivers */
2116 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
2117 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
2122 DPRINT1("Session drivers not supported\n");
2126 /* These are the only protection masks we care about */
2127 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
2129 /* Calculate the number of pages this driver is occupying */
2130 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
2132 /* Get the number of sections and the first section header */
2133 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2134 ASSERT(Sections
!= 0);
2135 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2137 /* Loop all the sections */
2138 CurrentAddress
= (ULONG_PTR
)ImageBase
;
2141 /* Get the section size */
2142 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2144 /* Get its virtual address */
2145 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2146 if (BaseAddress
< CurrentAddress
)
2148 /* Windows doesn't like these */
2149 DPRINT1("Badly linked image!\n");
2153 /* Remember the current address */
2154 CurrentAddress
= BaseAddress
+ Size
- 1;
2161 /* Get the number of sections and the first section header */
2162 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2163 ASSERT(Sections
!= 0);
2164 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2166 /* Set the address at the end to initialize the loop */
2167 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
2168 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
2170 /* Set the PTE points for the image, and loop its sections */
2171 StartPte
= MiAddressToPte(ImageBase
);
2172 LastPte
= StartPte
+ DriverPages
;
2175 /* Get the section size */
2176 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2178 /* Get its virtual address and PTE */
2179 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2180 PointerPte
= MiAddressToPte(BaseAddress
);
2182 /* Check if we were already protecting a run, and found a new run */
2183 if ((ComboPte
) && (PointerPte
> ComboPte
))
2185 /* Compute protection */
2186 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2189 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2191 /* Check for overlap */
2192 if (ComboPte
== StartPte
) StartPte
++;
2194 /* One done, reset variables */
2196 CombinedProtection
= 0;
2199 /* Break out when needed */
2200 if (PointerPte
>= LastPte
) break;
2202 /* Get the requested protection from the image header */
2203 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
2204 if (SectionProtection
== CurrentProtection
)
2206 /* Same protection, so merge the request */
2207 CurrentAddress
= BaseAddress
+ Size
- 1;
2215 /* This is now a new section, so close up the old one */
2216 CurrentPte
= MiAddressToPte(CurrentAddress
);
2218 /* Check for overlap */
2219 if (CurrentPte
== PointerPte
)
2221 /* Skip the last PTE, since it overlaps with us */
2224 /* And set the PTE we will merge with */
2225 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
2226 ComboPte
= PointerPte
;
2228 /* Get the most flexible protection by merging both */
2229 CombinedMask
|= (SectionProtection
| CurrentProtection
);
2232 /* Loop any PTEs left */
2233 if (CurrentPte
>= StartPte
)
2236 ASSERT(StartPte
< LastPte
);
2238 /* Make sure we don't overflow past the last PTE in the driver */
2239 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2240 ASSERT(CurrentPte
>= StartPte
);
2242 /* Compute the protection and set it */
2243 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2244 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2248 StartPte
= PointerPte
;
2249 CurrentAddress
= BaseAddress
+ Size
- 1;
2250 CurrentProtection
= SectionProtection
;
2257 /* Is there a leftover section to merge? */
2260 /* Compute and set the protection */
2261 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2262 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2264 /* Handle overlap */
2265 if (ComboPte
== StartPte
) StartPte
++;
2268 /* Finally, handle the last section */
2269 CurrentPte
= MiAddressToPte(CurrentAddress
);
2270 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
2272 /* Handle overlap */
2273 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2274 ASSERT(CurrentPte
>= StartPte
);
2276 /* Compute and set the protection */
2277 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2278 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2284 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2288 PETHREAD CurrentThread
= PsGetCurrentThread();
2289 PFN_COUNT PageCount
= 0;
2290 PFN_NUMBER PageFrameIndex
;
2294 /* Get the driver's base address */
2295 ImageBase
= MiPteToAddress(PointerPte
);
2296 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2298 /* If this is a large page, it's stuck in physical memory */
2299 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2301 /* Lock the working set */
2302 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2305 while (PointerPte
<= LastPte
)
2307 /* Check for valid PTE */
2308 if (PointerPte
->u
.Hard
.Valid
== 1)
2310 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2311 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2312 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2314 /* No working sets in ReactOS yet */
2318 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2322 /* Release the working set */
2323 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2325 /* Do we have any driver pages? */
2328 /* Update counters */
2329 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2335 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2337 ULONG_PTR ImageBase
;
2338 PIMAGE_NT_HEADERS NtHeaders
;
2339 ULONG Sections
, Alignment
, Size
;
2340 PIMAGE_SECTION_HEADER Section
;
2341 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2342 if (MmDisablePagingExecutive
) return;
2344 /* Get the driver base address and its NT header */
2345 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2346 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2347 if (!NtHeaders
) return;
2349 /* Get the sections and their alignment */
2350 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2351 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2353 /* Loop each section */
2354 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2357 /* Find PAGE or .edata */
2358 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2359 (*(PULONG
)Section
->Name
== 'ade.'))
2361 /* Had we already done some work? */
2364 /* Nope, setup the first PTE address */
2365 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2370 /* Compute the size */
2371 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2373 /* Find the last PTE that maps this section */
2374 LastPte
= MiAddressToPte(ImageBase
+
2375 Section
->VirtualAddress
+
2382 /* Had we found a section before? */
2385 /* Mark it as pageable */
2386 MiSetPagingOfDriver(PointerPte
, LastPte
);
2391 /* Keep searching */
2396 /* Handle the straggler */
2397 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2402 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2404 PIMAGE_NT_HEADERS NtHeader
;
2407 /* Get NT Headers */
2408 NtHeader
= RtlImageNtHeader(BaseAddress
);
2411 /* Check if this image is only safe for UP while we have 2+ CPUs */
2412 if ((KeNumberProcessors
> 1) &&
2413 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2420 /* Otherwise, it's safe */
2426 MmCheckSystemImage(IN HANDLE ImageHandle
,
2427 IN BOOLEAN PurgeSection
)
2430 HANDLE SectionHandle
;
2431 PVOID ViewBase
= NULL
;
2432 SIZE_T ViewSize
= 0;
2433 IO_STATUS_BLOCK IoStatusBlock
;
2434 FILE_STANDARD_INFORMATION FileStandardInfo
;
2435 KAPC_STATE ApcState
;
2436 PIMAGE_NT_HEADERS NtHeaders
;
2437 OBJECT_ATTRIBUTES ObjectAttributes
;
2440 /* Setup the object attributes */
2441 InitializeObjectAttributes(&ObjectAttributes
,
2443 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2447 /* Create a section for the DLL */
2448 Status
= ZwCreateSection(&SectionHandle
,
2449 SECTION_MAP_EXECUTE
,
2455 if (!NT_SUCCESS(Status
))
2457 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2461 /* Make sure we're in the system process */
2462 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2465 Status
= ZwMapViewOfSection(SectionHandle
,
2475 if (!NT_SUCCESS(Status
))
2477 /* We failed, close the handle and return */
2478 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status
);
2479 KeUnstackDetachProcess(&ApcState
);
2480 ZwClose(SectionHandle
);
2484 /* Now query image information */
2485 Status
= ZwQueryInformationFile(ImageHandle
,
2488 sizeof(FileStandardInfo
),
2489 FileStandardInformation
);
2490 if (NT_SUCCESS(Status
))
2492 /* First, verify the checksum */
2493 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2498 /* Set checksum failure */
2499 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2503 /* Make sure it's a real image */
2504 NtHeaders
= RtlImageNtHeader(ViewBase
);
2507 /* Set checksum failure */
2508 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2512 /* Make sure it's for the correct architecture */
2513 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2514 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2516 /* Set protection failure */
2517 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2521 /* Check that it's a valid SMP image if we have more then one CPU */
2522 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2524 /* Otherwise it's not the right image */
2525 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2529 /* Unmap the section, close the handle, and return status */
2531 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2532 KeUnstackDetachProcess(&ApcState
);
2533 ZwClose(SectionHandle
);
2539 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2540 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2541 IN PUNICODE_STRING LoadedName OPTIONAL
,
2543 OUT PVOID
*ModuleObject
,
2544 OUT PVOID
*ImageBaseAddress
)
2546 PVOID ModuleLoadBase
= NULL
;
2548 HANDLE FileHandle
= NULL
;
2549 OBJECT_ATTRIBUTES ObjectAttributes
;
2550 IO_STATUS_BLOCK IoStatusBlock
;
2551 PIMAGE_NT_HEADERS NtHeader
;
2552 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2553 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2554 ULONG EntrySize
, DriverSize
;
2555 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2556 PCHAR MissingApiName
, Buffer
;
2557 PWCHAR MissingDriverName
;
2558 HANDLE SectionHandle
;
2559 ACCESS_MASK DesiredAccess
;
2560 PVOID Section
= NULL
;
2561 BOOLEAN LockOwned
= FALSE
;
2562 PLIST_ENTRY NextEntry
;
2563 IMAGE_INFO ImageInfo
;
2567 /* Detect session-load */
2571 ASSERT(NamePrefix
== NULL
);
2572 ASSERT(LoadedName
== NULL
);
2574 /* Make sure the process is in session too */
2575 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2578 /* Allocate a buffer we'll use for names */
2579 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
2580 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2582 /* Check for a separator */
2583 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2588 /* Loop the path until we get to the base name */
2589 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2590 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2592 /* Get the length */
2593 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2594 BaseLength
*= sizeof(WCHAR
);
2596 /* Setup the string */
2597 BaseName
.Length
= (USHORT
)BaseLength
;
2598 BaseName
.Buffer
= p
;
2602 /* Otherwise, we already have a base name */
2603 BaseName
.Length
= FileName
->Length
;
2604 BaseName
.Buffer
= FileName
->Buffer
;
2607 /* Setup the maximum length */
2608 BaseName
.MaximumLength
= BaseName
.Length
;
2610 /* Now compute the base directory */
2611 BaseDirectory
= *FileName
;
2612 BaseDirectory
.Length
-= BaseName
.Length
;
2613 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2615 /* And the prefix, which for now is just the name itself */
2616 PrefixName
= *FileName
;
2618 /* Check if we have a prefix */
2619 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2621 /* Check if we already have a name, use it instead */
2622 if (LoadedName
) BaseName
= *LoadedName
;
2624 /* Check for loader snap debugging */
2625 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2627 /* Print out standard string */
2628 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2629 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2632 /* Acquire the load lock */
2634 ASSERT(LockOwned
== FALSE
);
2636 KeEnterCriticalRegion();
2637 KeWaitForSingleObject(&MmSystemLoadLock
,
2643 /* Scan the module list */
2644 NextEntry
= PsLoadedModuleList
.Flink
;
2645 while (NextEntry
!= &PsLoadedModuleList
)
2647 /* Get the entry and compare the names */
2648 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2649 LDR_DATA_TABLE_ENTRY
,
2651 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2653 /* Found it, break out */
2658 NextEntry
= NextEntry
->Flink
;
2661 /* Check if we found the image */
2662 if (NextEntry
!= &PsLoadedModuleList
)
2664 /* Check if we had already mapped a section */
2667 /* Dereference and clear */
2668 ObDereferenceObject(Section
);
2672 /* Check if this was supposed to be a session load */
2675 /* It wasn't, so just return the data */
2676 *ModuleObject
= LdrEntry
;
2677 *ImageBaseAddress
= LdrEntry
->DllBase
;
2678 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2682 /* We don't support session loading yet */
2683 DPRINT1("Unsupported Session-Load!\n");
2692 /* It wasn't loaded, and we didn't have a previous attempt */
2693 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2694 KeLeaveCriticalRegion();
2697 /* Check if KD is enabled */
2698 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2700 /* FIXME: Attempt to get image from KD */
2703 /* We don't have a valid entry */
2706 /* Setup image attributes */
2707 InitializeObjectAttributes(&ObjectAttributes
,
2709 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2713 /* Open the image */
2714 Status
= ZwOpenFile(&FileHandle
,
2718 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2720 if (!NT_SUCCESS(Status
))
2722 DPRINT1("ZwOpenFile failed with status 0x%x\n", Status
);
2727 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
2728 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
2729 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
2730 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
2736 /* Check if this is a session-load */
2739 /* Then we only need read and execute */
2740 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
2744 /* Otherwise, we can allow write access */
2745 DesiredAccess
= SECTION_ALL_ACCESS
;
2748 /* Initialize the attributes for the section */
2749 InitializeObjectAttributes(&ObjectAttributes
,
2751 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2755 /* Create the section */
2756 Status
= ZwCreateSection(&SectionHandle
,
2763 if (!NT_SUCCESS(Status
))
2765 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2769 /* Now get the section pointer */
2770 Status
= ObReferenceObjectByHandle(SectionHandle
,
2771 SECTION_MAP_EXECUTE
,
2772 MmSectionObjectType
,
2776 ZwClose(SectionHandle
);
2777 if (!NT_SUCCESS(Status
)) goto Quickie
;
2779 /* Check if this was supposed to be a session-load */
2782 /* We don't support session loading yet */
2783 DPRINT1("Unsupported Session-Load!\n");
2787 /* Check the loader list again, we should end up in the path below */
2792 /* We don't have a valid entry */
2796 /* Load the image */
2797 Status
= MiLoadImageSection(&Section
,
2802 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
2804 /* Get the size of the driver */
2805 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
2807 /* Make sure we're not being loaded into session space */
2810 /* Check for success */
2811 if (NT_SUCCESS(Status
))
2813 /* Support large pages for drivers */
2814 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
2820 /* Dereference the section */
2821 ObDereferenceObject(Section
);
2825 /* Check for failure of the load earlier */
2826 if (!NT_SUCCESS(Status
))
2828 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status
);
2832 /* Relocate the driver */
2833 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
2837 STATUS_CONFLICTING_ADDRESSES
,
2838 STATUS_INVALID_IMAGE_FORMAT
);
2839 if (!NT_SUCCESS(Status
))
2841 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status
);
2845 /* Get the NT Header */
2846 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
2848 /* Calculate the size we'll need for the entry and allocate it */
2849 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2851 sizeof(UNICODE_NULL
);
2853 /* Allocate the entry */
2854 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2858 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2862 /* Setup the entry */
2863 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
2864 LdrEntry
->LoadCount
= 1;
2865 LdrEntry
->LoadedImports
= LoadedImports
;
2866 LdrEntry
->PatchInformation
= NULL
;
2868 /* Check the version */
2869 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
2870 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
2872 /* Mark this image as a native image */
2873 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
2876 /* Setup the rest of the entry */
2877 LdrEntry
->DllBase
= ModuleLoadBase
;
2878 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
2879 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
2880 LdrEntry
->SizeOfImage
= DriverSize
;
2881 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
2882 LdrEntry
->SectionPointer
= Section
;
2884 /* Now write the DLL name */
2885 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
2886 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
2887 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
2889 /* Copy and null-terminate it */
2890 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
2893 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2895 /* Now allocate the full name */
2896 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
2898 sizeof(UNICODE_NULL
),
2900 if (!LdrEntry
->FullDllName
.Buffer
)
2902 /* Don't fail, just set it to zero */
2903 LdrEntry
->FullDllName
.Length
= 0;
2904 LdrEntry
->FullDllName
.MaximumLength
= 0;
2909 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
2910 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
2912 /* Copy and null-terminate */
2913 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
2916 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2920 MiProcessLoaderEntry(LdrEntry
, TRUE
);
2922 /* Resolve imports */
2923 MissingApiName
= Buffer
;
2924 Status
= MiResolveImageReferences(ModuleLoadBase
,
2930 if (!NT_SUCCESS(Status
))
2932 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status
);
2935 MiProcessLoaderEntry(LdrEntry
, FALSE
);
2937 /* Check if we need to free the name */
2938 if (LdrEntry
->FullDllName
.Buffer
)
2941 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
2944 /* Free the entry itself */
2945 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
2950 /* Update the loader entry */
2951 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
2952 LDRP_ENTRY_PROCESSED
|
2954 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2955 LdrEntry
->LoadedImports
= LoadedImports
;
2957 /* FIXME: Call driver verifier's loader function */
2959 /* Write-protect the system image */
2960 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
2962 /* Check if notifications are enabled */
2963 if (PsImageNotifyEnabled
)
2965 /* Fill out the notification data */
2966 ImageInfo
.Properties
= 0;
2967 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
2968 ImageInfo
.SystemModeImage
= TRUE
;
2969 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
2970 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
2971 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
2973 /* Send the notification */
2974 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
2977 #if defined(KDBG) || defined(_WINKD_)
2978 /* MiCacheImageSymbols doesn't detect rossym */
2981 /* Check if there's symbols */
2982 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
2985 /* Check if the system root is present */
2986 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
2987 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
2989 /* Add the system root */
2990 UnicodeTemp
= PrefixName
;
2991 UnicodeTemp
.Buffer
+= 11;
2992 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
2995 &SharedUserData
->NtSystemRoot
[2],
3000 /* Build the name */
3001 sprintf_nt(Buffer
, "%wZ", &BaseName
);
3004 /* Setup the ansi string */
3005 RtlInitString(&AnsiTemp
, Buffer
);
3007 /* Notify the debugger */
3008 DbgLoadImageSymbols(&AnsiTemp
,
3010 (ULONG_PTR
)ZwCurrentProcess());
3011 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
3014 /* Page the driver */
3015 ASSERT(Section
== NULL
);
3016 MiEnablePagingOfDriver(LdrEntry
);
3018 /* Return pointers */
3019 *ModuleObject
= LdrEntry
;
3020 *ImageBaseAddress
= LdrEntry
->DllBase
;
3023 /* Check if we have the lock acquired */
3026 /* Release the lock */
3027 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
3028 KeLeaveCriticalRegion();
3032 /* If we have a file handle, close it */
3033 if (FileHandle
) ZwClose(FileHandle
);
3035 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3036 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3038 /* Free the name buffer and return status */
3039 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
3043 PLDR_DATA_TABLE_ENTRY
3045 MiLookupDataTableEntry(IN PVOID Address
)
3047 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
3048 PLIST_ENTRY NextEntry
;
3052 NextEntry
= PsLoadedModuleList
.Flink
;
3055 /* Get the loader entry */
3056 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3057 LDR_DATA_TABLE_ENTRY
,
3060 /* Check if the address matches */
3061 if ((Address
>= LdrEntry
->DllBase
) &&
3062 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3063 LdrEntry
->SizeOfImage
)))
3066 FoundEntry
= LdrEntry
;
3071 NextEntry
= NextEntry
->Flink
;
3072 } while(NextEntry
!= &PsLoadedModuleList
);
3074 /* Return the entry */
3078 /* PUBLIC FUNCTIONS ***********************************************************/
3085 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3087 PMMPTE StartPte
, EndPte
;
3088 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3091 /* Get the loader entry */
3092 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3093 if (!LdrEntry
) return NULL
;
3095 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3096 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3098 /* Don't do anything, just return the base address */
3099 return LdrEntry
->DllBase
;
3102 /* Wait for active DPCs to finish before we page out the driver */
3103 KeFlushQueuedDpcs();
3105 /* Get the PTE range for the whole driver image */
3106 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3107 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3109 /* Enable paging for the PTE range */
3110 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3111 MiSetPagingOfDriver(StartPte
, EndPte
);
3113 /* Return the base address */
3114 return LdrEntry
->DllBase
;
3122 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3132 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3134 PVOID ProcAddress
= NULL
;
3135 ANSI_STRING AnsiRoutineName
;
3137 PLIST_ENTRY NextEntry
;
3138 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3139 BOOLEAN Found
= FALSE
;
3140 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3141 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3144 /* Convert routine to ansi name */
3145 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3148 if (!NT_SUCCESS(Status
)) return NULL
;
3151 KeEnterCriticalRegion();
3152 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3154 /* Loop the loaded module list */
3155 NextEntry
= PsLoadedModuleList
.Flink
;
3156 while (NextEntry
!= &PsLoadedModuleList
)
3159 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3160 LDR_DATA_TABLE_ENTRY
,
3163 /* Check if it's the kernel or HAL */
3164 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3170 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3177 /* Check if we found a valid binary */
3180 /* Find the procedure name */
3181 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3184 /* Break out if we found it or if we already tried both modules */
3185 if (ProcAddress
) break;
3186 if (Modules
== 2) break;
3190 NextEntry
= NextEntry
->Flink
;
3193 /* Release the lock */
3194 ExReleaseResourceLite(&PsLoadedModuleResource
);
3195 KeLeaveCriticalRegion();
3197 /* Free the string and return */
3198 RtlFreeAnsiString(&AnsiRoutineName
);