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 #line 16 "ARMĀ³::LOADER"
17 #define MODULE_INVOLVED_IN_ARM3
18 #include "../ARM3/miarm.h"
20 /* GCC's incompetence strikes again */
23 sprintf_nt(IN PCHAR Buffer
,
29 vsprintf(Buffer
, Format
, ap
);
33 /* GLOBALS ********************************************************************/
35 LIST_ENTRY PsLoadedModuleList
;
36 LIST_ENTRY MmLoadedUserImageList
;
37 KSPIN_LOCK PsLoadedModuleSpinLock
;
38 ERESOURCE PsLoadedModuleResource
;
39 ULONG_PTR PsNtosImageBase
;
40 KMUTANT MmSystemLoadLock
;
42 PFN_NUMBER MmTotalSystemDriverPages
;
44 PVOID MmUnloadedDrivers
;
45 PVOID MmLastUnloadedDrivers
;
47 BOOLEAN MmMakeLowMemory
;
48 BOOLEAN MmEnforceWriteProtection
= TRUE
;
50 PMMPTE MiKernelResourceStartPte
, MiKernelResourceEndPte
;
51 ULONG_PTR ExPoolCodeStart
, ExPoolCodeEnd
, MmPoolCodeStart
, MmPoolCodeEnd
;
52 ULONG_PTR MmPteCodeStart
, MmPteCodeEnd
;
54 /* FUNCTIONS ******************************************************************/
58 MiCacheImageSymbols(IN PVOID BaseAddress
)
61 PVOID DebugDirectory
= NULL
;
64 /* Make sure it's safe to access the image */
67 /* Get the debug directory */
68 DebugDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
70 IMAGE_DIRECTORY_ENTRY_DEBUG
,
73 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
79 /* Return the directory */
80 return DebugDirectory
;
85 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
87 IN PUNICODE_STRING FileName
,
88 IN BOOLEAN SessionLoad
,
89 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
91 PROS_SECTION_OBJECT Section
= *SectionPtr
;
97 LARGE_INTEGER SectionOffset
= {{0, 0}};
98 BOOLEAN LoadSymbols
= FALSE
;
100 PMMPTE PointerPte
, LastPte
;
105 /* Detect session load */
109 DPRINT1("Session loading not yet supported!\n");
113 /* Not session load, shouldn't have an entry */
114 ASSERT(LdrEntry
== NULL
);
116 /* Attach to the system process */
117 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
119 /* Check if we need to load symbols */
120 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
124 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
128 Process
= PsGetCurrentProcess();
129 Status
= MmMapViewOfSection(Section
,
140 /* Re-enable the flag */
141 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
143 /* Check if we failed with distinguished status code */
144 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
146 /* Change it to something more generic */
147 Status
= STATUS_INVALID_IMAGE_FORMAT
;
150 /* Now check if we failed */
151 if (!NT_SUCCESS(Status
))
153 /* Detach and return */
154 KeUnstackDetachProcess(&ApcState
);
158 /* Reserve system PTEs needed */
159 PteCount
= ROUND_TO_PAGES(Section
->ImageSection
->ImageSize
) >> PAGE_SHIFT
;
160 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
161 if (!PointerPte
) return STATUS_INSUFFICIENT_RESOURCES
;
163 /* New driver base */
164 LastPte
= PointerPte
+ PteCount
;
165 DriverBase
= MiPteToAddress(PointerPte
);
167 /* The driver is here */
168 *ImageBase
= DriverBase
;
170 /* Loop the new driver PTEs */
171 TempPte
= ValidKernelPte
;
172 while (PointerPte
< LastPte
)
174 /* Allocate a page */
175 TempPte
.u
.Hard
.PageFrameNumber
= MiAllocatePfn(PointerPte
, MM_EXECUTE
);
178 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
185 RtlCopyMemory(DriverBase
, Base
, PteCount
<< PAGE_SHIFT
);
187 /* Now unmap the view */
188 Status
= MmUnmapViewOfSection(Process
, Base
);
189 ASSERT(NT_SUCCESS(Status
));
191 /* Detach and return status */
192 KeUnstackDetachProcess(&ApcState
);
198 MiLocateExportName(IN PVOID DllBase
,
202 PUSHORT OrdinalTable
;
203 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
204 LONG Low
= 0, Mid
= 0, High
, Ret
;
211 /* Get the export directory */
212 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
214 IMAGE_DIRECTORY_ENTRY_EXPORT
,
216 if (!ExportDirectory
) return NULL
;
218 /* Setup name tables */
219 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
220 ExportDirectory
->AddressOfNames
);
221 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
222 ExportDirectory
->AddressOfNameOrdinals
);
224 /* Do a binary search */
225 High
= ExportDirectory
->NumberOfNames
- 1;
228 /* Get new middle value */
229 Mid
= (Low
+ High
) >> 1;
232 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
250 /* Check if we couldn't find it */
251 if (High
< Low
) return NULL
;
253 /* Otherwise, this is the ordinal */
254 Ordinal
= OrdinalTable
[Mid
];
256 /* Resolve the address and write it */
257 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
258 ExportDirectory
->AddressOfFunctions
);
259 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
261 /* Check if the function is actually a forwarder */
262 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
263 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
275 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
276 IN PLIST_ENTRY ListHead
)
278 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
279 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
280 PMM_DLL_INITIALIZE DllInit
;
281 UNICODE_STRING RegPath
, ImportName
;
284 /* Try to see if the image exports a DllInitialize routine */
285 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
287 if (!DllInit
) return STATUS_SUCCESS
;
289 /* Do a temporary copy of BaseDllName called ImportName
290 * because we'll alter the length of the string
292 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
293 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
294 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
296 /* Obtain the path to this dll's service in the registry */
297 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
298 ImportName
.Length
+ sizeof(UNICODE_NULL
);
299 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
300 RegPath
.MaximumLength
,
303 /* Check if this allocation was unsuccessful */
304 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
306 /* Build and append the service name itself */
307 RegPath
.Length
= ServicesKeyName
.Length
;
308 RtlCopyMemory(RegPath
.Buffer
,
309 ServicesKeyName
.Buffer
,
310 ServicesKeyName
.Length
);
312 /* Check if there is a dot in the filename */
313 if (wcschr(ImportName
.Buffer
, L
'.'))
315 /* Remove the extension */
316 ImportName
.Length
= (wcschr(ImportName
.Buffer
, L
'.') -
317 ImportName
.Buffer
) * sizeof(WCHAR
);
320 /* Append service name (the basename without extension) */
321 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
323 /* Now call the DllInit func */
324 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
325 Status
= DllInit(&RegPath
);
328 ExFreePool(RegPath
.Buffer
);
330 /* Return status value which DllInitialize returned */
336 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
342 /* Get the unload routine */
343 Func
= (PMM_DLL_UNLOAD
)MiLocateExportName(LdrEntry
->DllBase
, "DllUnload");
344 if (!Func
) return FALSE
;
346 /* Call it and check for success */
348 if (!NT_SUCCESS(Status
)) return FALSE
;
350 /* Lie about the load count so we can unload the image */
351 ASSERT(LdrEntry
->LoadCount
== 0);
352 LdrEntry
->LoadCount
= 1;
354 /* Unload it and return true */
355 MmUnloadSystemImage(LdrEntry
);
361 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
364 LOAD_IMPORTS SingleEntry
;
365 PLDR_DATA_TABLE_ENTRY LdrEntry
;
366 PVOID CurrentImports
;
369 /* Check if there's no imports or if we're a boot driver */
370 if ((ImportList
== MM_SYSLDR_NO_IMPORTS
) ||
371 (ImportList
== MM_SYSLDR_BOOT_LOADED
) ||
372 (ImportList
->Count
== 0))
374 /* Then there's nothing to do */
375 return STATUS_SUCCESS
;
378 /* Check for single-entry */
379 if ((ULONG_PTR
)ImportList
& MM_SYSLDR_SINGLE_ENTRY
)
382 SingleEntry
.Count
= 1;
383 SingleEntry
.Entry
[0] = (PVOID
)((ULONG_PTR
)ImportList
&~ MM_SYSLDR_SINGLE_ENTRY
);
385 /* Use this as the import list */
386 ImportList
= &SingleEntry
;
389 /* Loop the import list */
390 for (i
= 0; (i
< ImportList
->Count
) && (ImportList
->Entry
[i
]); i
++)
393 LdrEntry
= ImportList
->Entry
[i
];
394 DPRINT1("%wZ <%wZ>\n", &LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
396 /* Skip boot loaded images */
397 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) continue;
399 /* Dereference the entry */
400 ASSERT(LdrEntry
->LoadCount
>= 1);
401 if (!--LdrEntry
->LoadCount
)
403 /* Save the import data in case unload fails */
404 CurrentImports
= LdrEntry
->LoadedImports
;
406 /* This is the last entry */
407 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
408 if (MiCallDllUnloadAndUnloadDll(LdrEntry
))
410 /* Unloading worked, parse this DLL's imports too */
411 MiDereferenceImports(CurrentImports
);
413 /* Check if we had valid imports */
414 if ((CurrentImports
!= MM_SYSLDR_BOOT_LOADED
) ||
415 (CurrentImports
!= MM_SYSLDR_NO_IMPORTS
) ||
416 !((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
419 ExFreePool(CurrentImports
);
424 /* Unload failed, restore imports */
425 LdrEntry
->LoadedImports
= CurrentImports
;
431 return STATUS_SUCCESS
;
436 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
440 /* Check if there's no imports or we're a boot driver or only one entry */
441 if ((LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) ||
442 (LdrEntry
->LoadedImports
== MM_SYSLDR_NO_IMPORTS
) ||
443 ((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
449 /* Otherwise, free the import list */
450 ExFreePool(LdrEntry
->LoadedImports
);
451 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
456 MiFindExportedRoutineByName(IN PVOID DllBase
,
457 IN PANSI_STRING ExportName
)
460 PUSHORT OrdinalTable
;
461 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
462 LONG Low
= 0, Mid
= 0, High
, Ret
;
469 /* Get the export directory */
470 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
472 IMAGE_DIRECTORY_ENTRY_EXPORT
,
474 if (!ExportDirectory
) return NULL
;
476 /* Setup name tables */
477 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
478 ExportDirectory
->AddressOfNames
);
479 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
480 ExportDirectory
->AddressOfNameOrdinals
);
482 /* Do a binary search */
483 High
= ExportDirectory
->NumberOfNames
- 1;
486 /* Get new middle value */
487 Mid
= (Low
+ High
) >> 1;
490 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
508 /* Check if we couldn't find it */
509 if (High
< Low
) return NULL
;
511 /* Otherwise, this is the ordinal */
512 Ordinal
= OrdinalTable
[Mid
];
514 /* Validate the ordinal */
515 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
) return NULL
;
517 /* Resolve the address and write it */
518 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
519 ExportDirectory
->AddressOfFunctions
);
520 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
523 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
524 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
530 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
535 /* Acquire module list lock */
536 KeEnterCriticalRegion();
537 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
539 /* Acquire the spinlock too as we will insert or remove the entry */
540 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
542 /* Insert or remove from the list */
543 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
544 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
547 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
548 ExReleaseResourceLite(&PsLoadedModuleResource
);
549 KeLeaveCriticalRegion();
554 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
559 ULONG_PTR OldBaseTop
, Delta
;
560 PLDR_DATA_TABLE_ENTRY LdrEntry
;
561 PLIST_ENTRY NextEntry
;
564 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
565 // since a real version of Windows would fail at this point, but they seem
566 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
567 // a feature which isn't even used by Windows. Priorities, priorities...
568 // Please note that Microsoft WDK EULA and license prohibits using
569 // the information contained within it for the generation of "non-Windows"
570 // drivers, which is precisely what LD will generate, since an LD driver
571 // will not load on Windows.
573 #ifdef _WORKING_LINKER_
576 PULONG_PTR ImageThunk
;
577 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
579 /* Calculate the top and delta */
580 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
581 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
583 /* Loop the loader block */
584 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
585 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
586 NextEntry
= NextEntry
->Flink
)
588 /* Get the loader entry */
589 LdrEntry
= CONTAINING_RECORD(NextEntry
,
590 LDR_DATA_TABLE_ENTRY
,
592 #ifdef _WORKING_LINKER_
594 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
596 IMAGE_DIRECTORY_ENTRY_IAT
,
598 if (!ImageThunk
) continue;
600 /* Make sure we have an IAT */
601 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
602 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
604 /* Check if it's within this module */
605 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
608 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
609 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
610 *ImageThunk
+= Delta
;
614 /* Get the import table */
615 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
617 IMAGE_DIRECTORY_ENTRY_IMPORT
,
619 if (!ImportDescriptor
) continue;
621 /* Make sure we have an IAT */
622 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
623 while ((ImportDescriptor
->Name
) &&
624 (ImportDescriptor
->OriginalFirstThunk
))
626 /* Get the image thunk */
627 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
628 ImportDescriptor
->FirstThunk
);
631 /* Check if it's within this module */
632 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
635 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
636 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
637 *ImageThunk
+= Delta
;
640 /* Go to the next thunk */
644 /* Go to the next import */
653 MiSnapThunk(IN PVOID DllBase
,
655 IN PIMAGE_THUNK_DATA Name
,
656 IN PIMAGE_THUNK_DATA Address
,
657 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
659 IN BOOLEAN SnapForwarder
,
660 OUT PCHAR
*MissingApi
)
665 PUSHORT OrdinalTable
;
666 PIMAGE_IMPORT_BY_NAME NameImport
;
668 ULONG Low
= 0, Mid
= 0, High
;
671 PCHAR MissingForwarder
;
672 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
675 UNICODE_STRING ForwarderName
;
676 PLIST_ENTRY NextEntry
;
677 PLDR_DATA_TABLE_ENTRY LdrEntry
;
678 ULONG ForwardExportSize
;
679 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
680 PIMAGE_IMPORT_BY_NAME ForwardName
;
682 IMAGE_THUNK_DATA ForwardThunk
;
685 /* Check if this is an ordinal */
686 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
687 if ((IsOrdinal
) && !(SnapForwarder
))
689 /* Get the ordinal number and set it as missing */
690 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
691 ExportDirectory
->Base
);
692 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
696 /* Get the VA if we don't have to snap */
697 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
698 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
700 /* Copy the procedure name */
702 (PCHAR
)&NameImport
->Name
[0],
703 MAXIMUM_FILENAME_LENGTH
- 1);
705 /* Setup name tables */
706 DPRINT("Import name: %s\n", NameImport
->Name
);
707 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
708 ExportDirectory
->AddressOfNames
);
709 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
710 ExportDirectory
->AddressOfNameOrdinals
);
712 /* Get the hint and check if it's valid */
713 Hint
= NameImport
->Hint
;
714 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
715 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
717 /* We have a match, get the ordinal number from here */
718 Ordinal
= OrdinalTable
[Hint
];
722 /* Do a binary search */
723 High
= ExportDirectory
->NumberOfNames
- 1;
726 /* Get new middle value */
727 Mid
= (Low
+ High
) >> 1;
730 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
748 /* Check if we couldn't find it */
751 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport
->Name
);
752 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
755 /* Otherwise, this is the ordinal */
756 Ordinal
= OrdinalTable
[Mid
];
760 /* Check if the ordinal is invalid */
761 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
764 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
768 /* In case the forwarder is missing */
769 MissingForwarder
= NameBuffer
;
771 /* Resolve the address and write it */
772 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
773 ExportDirectory
->AddressOfFunctions
);
774 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
776 /* Assume success from now on */
777 Status
= STATUS_SUCCESS
;
779 /* Check if the function is actually a forwarder */
780 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
781 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
783 /* Now assume failure in case the forwarder doesn't exist */
784 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
786 /* Build the forwarder name */
787 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
788 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
791 DllName
.MaximumLength
= DllName
.Length
;
794 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
798 /* We failed, just return an error */
802 /* Loop the module list */
803 NextEntry
= PsLoadedModuleList
.Flink
;
804 while (NextEntry
!= &PsLoadedModuleList
)
806 /* Get the loader entry */
807 LdrEntry
= CONTAINING_RECORD(NextEntry
,
808 LDR_DATA_TABLE_ENTRY
,
811 /* Check if it matches */
812 if (RtlPrefixString((PSTRING
)&ForwarderName
,
813 (PSTRING
)&LdrEntry
->BaseDllName
,
816 /* Get the forwarder export directory */
817 ForwardExportDirectory
=
818 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
820 IMAGE_DIRECTORY_ENTRY_EXPORT
,
822 if (!ForwardExportDirectory
) break;
824 /* Allocate a name entry */
825 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
827 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
828 sizeof(*ForwardName
) +
831 if (!ForwardName
) break;
834 RtlCopyMemory(&ForwardName
->Name
[0],
835 DllName
.Buffer
+ DllName
.Length
,
837 ForwardName
->Hint
= 0;
839 /* Set the new address */
840 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
842 /* Snap the forwarder */
843 Status
= MiSnapThunk(LdrEntry
->DllBase
,
847 ForwardExportDirectory
,
852 /* Free the forwarder name and set the thunk */
853 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
854 Address
->u1
= ForwardThunk
.u1
;
858 /* Go to the next entry */
859 NextEntry
= NextEntry
->Flink
;
863 RtlFreeUnicodeString(&ForwarderName
);
873 MmUnloadSystemImage(IN PVOID ImageHandle
)
875 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
876 PVOID BaseAddress
= LdrEntry
->DllBase
;
879 BOOLEAN HadEntry
= FALSE
;
881 /* Acquire the loader lock */
882 KeEnterCriticalRegion();
883 KeWaitForSingleObject(&MmSystemLoadLock
,
889 /* Check if this driver was loaded at boot and didn't get imports parsed */
890 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
892 /* We should still be alive */
893 ASSERT(LdrEntry
->LoadCount
!= 0);
894 LdrEntry
->LoadCount
--;
896 /* Check if we're still loaded */
897 if (LdrEntry
->LoadCount
) goto Done
;
899 /* We should cleanup... are symbols loaded */
900 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
902 /* Create the ANSI name */
903 Status
= RtlUnicodeStringToAnsiString(&TempName
,
904 &LdrEntry
->BaseDllName
,
906 if (NT_SUCCESS(Status
))
908 /* Unload the symbols */
909 DbgUnLoadImageSymbols(&TempName
,
911 (ULONG_PTR
)ZwCurrentProcess());
912 RtlFreeAnsiString(&TempName
);
916 /* FIXME: Free the driver */
917 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
918 //MmFreeSection(LdrEntry->DllBase);
920 /* Check if we're linked in */
921 if (LdrEntry
->InLoadOrderLinks
.Flink
)
924 MiProcessLoaderEntry(LdrEntry
, FALSE
);
928 /* Dereference and clear the imports */
929 MiDereferenceImports(LdrEntry
->LoadedImports
);
930 MiClearImports(LdrEntry
);
932 /* Check if the entry needs to go away */
935 /* Check if it had a name */
936 if (LdrEntry
->FullDllName
.Buffer
)
939 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
942 /* Check if we had a section */
943 if (LdrEntry
->SectionPointer
)
946 ObDereferenceObject(LdrEntry
->SectionPointer
);
950 ExFreePool(LdrEntry
);
953 /* Release the system lock and return */
955 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
956 KeLeaveCriticalRegion();
957 return STATUS_SUCCESS
;
962 MiResolveImageReferences(IN PVOID ImageBase
,
963 IN PUNICODE_STRING ImageFileDirectory
,
964 IN PUNICODE_STRING NamePrefix OPTIONAL
,
965 OUT PCHAR
*MissingApi
,
966 OUT PWCHAR
*MissingDriver
,
967 OUT PLOAD_IMPORTS
*LoadImports
)
969 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
970 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
971 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
972 PLOAD_IMPORTS LoadedImports
, NewImports
;
973 ULONG GdiLink
, NormalLink
, i
;
974 BOOLEAN ReferenceNeeded
, Loaded
;
975 ANSI_STRING TempString
;
976 UNICODE_STRING NameString
, DllName
;
977 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
978 PVOID ImportBase
, DllBase
;
979 PLIST_ENTRY NextEntry
;
980 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
982 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
984 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
985 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
987 /* Assume no imports */
988 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
990 /* Get the import descriptor */
991 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
993 IMAGE_DIRECTORY_ENTRY_IMPORT
,
995 if (!ImportDescriptor
) return STATUS_SUCCESS
;
997 /* Loop all imports to count them */
998 for (CurrentImport
= ImportDescriptor
;
999 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
1006 /* Make sure we have non-zero imports */
1009 /* Calculate and allocate the list we'll need */
1010 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1011 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1017 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1018 LoadedImports
->Count
= ImportCount
;
1024 LoadedImports
= NULL
;
1027 /* Reset the import count and loop descriptors again */
1028 ImportCount
= GdiLink
= NormalLink
= 0;
1029 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1032 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1034 /* Check if this is a GDI driver */
1036 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1038 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1039 NormalLink
= NormalLink
|
1040 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1041 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1042 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1043 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1045 /* Check if this is a valid GDI driver */
1046 if ((GdiLink
) && (NormalLink
))
1048 /* It's not, it's importing stuff it shouldn't be! */
1049 MiDereferenceImports(LoadedImports
);
1050 if (LoadedImports
) ExFreePool(LoadedImports
);
1051 return STATUS_PROCEDURE_NOT_FOUND
;
1054 /* Check for user-mode printer or video card drivers, which don't belong */
1055 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1056 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1057 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1058 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1059 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1060 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1062 /* This is not kernel code */
1063 MiDereferenceImports(LoadedImports
);
1064 if (LoadedImports
) ExFreePool(LoadedImports
);
1065 return STATUS_PROCEDURE_NOT_FOUND
;
1068 /* Check if this is a "core" import, which doesn't get referenced */
1069 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1070 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1071 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1073 /* Don't reference this */
1074 ReferenceNeeded
= FALSE
;
1078 /* Reference these modules */
1079 ReferenceNeeded
= TRUE
;
1082 /* Now setup a unicode string for the import */
1083 RtlInitAnsiString(&TempString
, ImportName
);
1084 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1085 if (!NT_SUCCESS(Status
))
1088 MiDereferenceImports(LoadedImports
);
1089 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1093 /* We don't support name prefixes yet */
1094 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1096 /* Remember that we haven't loaded the import at this point */
1101 /* Loop the driver list */
1102 NextEntry
= PsLoadedModuleList
.Flink
;
1103 while (NextEntry
!= &PsLoadedModuleList
)
1105 /* Get the loader entry and compare the name */
1106 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1107 LDR_DATA_TABLE_ENTRY
,
1109 if (RtlEqualUnicodeString(&NameString
,
1110 &LdrEntry
->BaseDllName
,
1113 /* Get the base address */
1114 ImportBase
= LdrEntry
->DllBase
;
1116 /* Check if we haven't loaded yet, and we need references */
1117 if (!(Loaded
) && (ReferenceNeeded
))
1119 /* Make sure we're not already loading */
1120 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1122 /* Increase the load count */
1123 LdrEntry
->LoadCount
++;
1127 /* Done, break out */
1131 /* Go to the next entry */
1132 NextEntry
= NextEntry
->Flink
;
1135 /* Check if we haven't loaded the import yet */
1138 /* Setup the import DLL name */
1139 DllName
.MaximumLength
= NameString
.Length
+
1140 ImageFileDirectory
->Length
+
1141 sizeof(UNICODE_NULL
);
1142 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1143 DllName
.MaximumLength
,
1147 /* Setup the base length and copy it */
1148 DllName
.Length
= ImageFileDirectory
->Length
;
1149 RtlCopyMemory(DllName
.Buffer
,
1150 ImageFileDirectory
->Buffer
,
1151 ImageFileDirectory
->Length
);
1153 /* Now add the import name and null-terminate it */
1154 RtlAppendUnicodeStringToString(&DllName
,
1156 DllName
.Buffer
[DllName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1158 /* Load the image */
1159 Status
= MmLoadSystemImage(&DllName
,
1165 if (NT_SUCCESS(Status
))
1167 /* We can free the DLL Name */
1168 ExFreePool(DllName
.Buffer
);
1172 /* Fill out the information for the error */
1173 *MissingDriver
= DllName
.Buffer
;
1174 *(PULONG
)MissingDriver
|= 1;
1180 /* We're out of resources */
1181 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1184 /* Check if we're OK until now */
1185 if (NT_SUCCESS(Status
))
1187 /* We're now loaded */
1191 ASSERT(DllBase
= DllEntry
->DllBase
);
1193 /* Call the initialization routines */
1194 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1195 if (!NT_SUCCESS(Status
))
1197 /* We failed, unload the image */
1198 MmUnloadSystemImage(DllEntry
);
1204 /* Check if we failed by here */
1205 if (!NT_SUCCESS(Status
))
1207 /* Cleanup and return */
1208 RtlFreeUnicodeString(&NameString
);
1209 MiDereferenceImports(LoadedImports
);
1210 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1214 /* Loop again to make sure that everything is OK */
1218 /* Check if we're support to reference this import */
1219 if ((ReferenceNeeded
) && (LoadedImports
))
1221 /* Make sure we're not already loading */
1222 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1225 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1230 /* Free the import name */
1231 RtlFreeUnicodeString(&NameString
);
1233 /* Set the missing driver name and get the export directory */
1234 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1235 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1237 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1239 if (!ExportDirectory
)
1241 /* Cleanup and return */
1242 MiDereferenceImports(LoadedImports
);
1243 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1244 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver
);
1245 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1248 /* Make sure we have an IAT */
1249 if (ImportDescriptor
->OriginalFirstThunk
)
1251 /* Get the first thunks */
1252 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1253 ImportDescriptor
->OriginalFirstThunk
);
1254 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1255 ImportDescriptor
->FirstThunk
);
1258 while (OrigThunk
->u1
.AddressOfData
)
1261 Status
= MiSnapThunk(ImportBase
,
1269 if (!NT_SUCCESS(Status
))
1271 /* Cleanup and return */
1272 MiDereferenceImports(LoadedImports
);
1273 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1277 /* Reset the buffer */
1278 *MissingApi
= MissingApiBuffer
;
1282 /* Go to the next import */
1286 /* Check if we have an import list */
1289 /* Reset the count again, and loop entries*/
1291 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1293 if (LoadedImports
->Entry
[i
])
1295 /* Got an entry, OR it with 1 in case it's the single entry */
1296 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1297 MM_SYSLDR_SINGLE_ENTRY
);
1302 /* Check if we had no imports */
1305 /* Free the list and set it to no imports */
1306 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1307 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1309 else if (ImportCount
== 1)
1311 /* Just one entry, we can free the table and only use our entry */
1312 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1313 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1315 else if (ImportCount
!= LoadedImports
->Count
)
1317 /* Allocate a new list */
1318 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1319 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1325 NewImports
->Count
= 0;
1327 /* Loop all the imports */
1328 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1330 /* Make sure it's valid */
1331 if (LoadedImports
->Entry
[i
])
1334 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1335 NewImports
->Count
++;
1339 /* Free the old copy */
1340 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1341 LoadedImports
= NewImports
;
1345 /* Return the list */
1346 *LoadImports
= LoadedImports
;
1349 /* Return success */
1350 return STATUS_SUCCESS
;
1355 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1357 PLIST_ENTRY NextEntry
;
1359 PIMAGE_NT_HEADERS NtHeader
;
1360 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1361 PIMAGE_FILE_HEADER FileHeader
;
1362 BOOLEAN ValidRelocs
;
1363 PIMAGE_DATA_DIRECTORY DataDirectory
;
1364 PVOID DllBase
, NewImageAddress
;
1366 PMMPTE PointerPte
, StartPte
, LastPte
;
1367 PFN_NUMBER PteCount
;
1369 MMPTE TempPte
, OldPte
;
1371 /* Loop driver list */
1372 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1373 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1374 NextEntry
= NextEntry
->Flink
)
1376 /* Get the loader entry and NT header */
1377 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1378 LDR_DATA_TABLE_ENTRY
,
1380 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1383 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1385 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1386 &LdrEntry
->FullDllName
);
1388 /* Skip kernel and HAL */
1389 /* ROS HACK: Skip BOOTVID/KDCOM too */
1391 if (i
<= 4) continue;
1393 /* Skip non-drivers */
1394 if (!NtHeader
) continue;
1396 /* Get the file header and make sure we can relocate */
1397 FileHeader
= &NtHeader
->FileHeader
;
1398 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1399 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1400 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1402 /* Everything made sense until now, check the relocation section too */
1403 DataDirectory
= &NtHeader
->OptionalHeader
.
1404 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1405 if (!DataDirectory
->VirtualAddress
)
1407 /* We don't really have relocations */
1408 ValidRelocs
= FALSE
;
1412 /* Make sure the size is valid */
1413 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1414 LdrEntry
->SizeOfImage
)
1416 /* They're not, skip */
1420 /* We have relocations */
1424 /* Remember the original address */
1425 DllBase
= LdrEntry
->DllBase
;
1427 /* Get the first PTE and the number of PTEs we'll need */
1428 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1429 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1430 LastPte
= StartPte
+ PteCount
;
1433 while (PointerPte
< LastPte
)
1435 /* Mark the page modified in the PFN database */
1436 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1437 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1438 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1439 Pfn1
->u3
.e1
.Modified
= TRUE
;
1445 /* Now reserve system PTEs for the image */
1446 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1449 /* Shouldn't happen */
1450 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1454 /* This is the new virtual address for the module */
1455 LastPte
= PointerPte
+ PteCount
;
1456 NewImageAddress
= MiPteToAddress(PointerPte
);
1459 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1460 ASSERT(ExpInitializationPhase
== 0);
1462 /* Loop the new driver PTEs */
1463 TempPte
= ValidKernelPte
;
1464 while (PointerPte
< LastPte
)
1466 /* Copy the old data */
1468 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1470 /* Set page number from the loader's memory */
1471 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1474 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1481 /* Update position */
1482 PointerPte
-= PteCount
;
1485 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1487 /* Set the image base to the address where the loader put it */
1488 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1490 /* Check if we had relocations */
1493 /* Relocate the image */
1494 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1498 STATUS_CONFLICTING_ADDRESSES
,
1499 STATUS_INVALID_IMAGE_FORMAT
);
1500 if (!NT_SUCCESS(Status
))
1502 /* This shouldn't happen */
1503 DPRINT1("Relocations failed!\n");
1508 /* Update the loader entry */
1509 LdrEntry
->DllBase
= NewImageAddress
;
1511 /* Update the thunks */
1512 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1513 MiUpdateThunks(LoaderBlock
,
1516 LdrEntry
->SizeOfImage
);
1518 /* Update the loader entry */
1519 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1520 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1521 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1522 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1524 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1530 MiBuildImportsForBootDrivers(VOID
)
1532 PLIST_ENTRY NextEntry
, NextEntry2
;
1533 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1534 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1535 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1536 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1537 PLOAD_IMPORTS LoadedImports
;
1538 ULONG LoadedImportsSize
, ImportSize
;
1539 PULONG_PTR ImageThunk
;
1540 ULONG_PTR DllBase
, DllEnd
;
1541 ULONG Modules
= 0, i
, j
= 0;
1542 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1544 /* Initialize variables */
1545 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1547 /* Loop the loaded module list... we are early enough that no lock is needed */
1548 NextEntry
= PsLoadedModuleList
.Flink
;
1549 while (NextEntry
!= &PsLoadedModuleList
)
1552 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1553 LDR_DATA_TABLE_ENTRY
,
1556 /* Check if it's the kernel or HAL */
1557 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1560 KernelEntry
= LdrEntry
;
1562 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1565 HalEntry
= LdrEntry
;
1568 /* Check if this is a driver DLL */
1569 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1571 /* Check if this is the HAL or kernel */
1572 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1574 /* Add a reference */
1575 LdrEntry
->LoadCount
= 1;
1579 /* No referencing needed */
1580 LdrEntry
->LoadCount
= 0;
1585 /* No referencing needed */
1586 LdrEntry
->LoadCount
= 0;
1589 /* Remember this came from the loader */
1590 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1593 NextEntry
= NextEntry
->Flink
;
1597 /* We must have at least found the kernel and HAL */
1598 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1600 /* Allocate the list */
1601 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), 'TDmM');
1602 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1604 /* Loop the loaded module list again */
1605 NextEntry
= PsLoadedModuleList
.Flink
;
1606 while (NextEntry
!= &PsLoadedModuleList
)
1609 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1610 LDR_DATA_TABLE_ENTRY
,
1612 #ifdef _WORKING_LOADER_
1613 /* Get its imports */
1614 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1616 IMAGE_DIRECTORY_ENTRY_IAT
,
1620 /* Get its imports */
1621 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1623 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1625 if (!ImportDescriptor
)
1629 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1630 NextEntry
= NextEntry
->Flink
;
1634 /* Clear the list and count the number of IAT thunks */
1635 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1636 #ifdef _WORKING_LOADER_
1637 ImportSize
/= sizeof(ULONG_PTR
);
1639 /* Scan the thunks */
1640 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1642 i
= DllBase
= DllEnd
= 0;
1643 while ((ImportDescriptor
->Name
) &&
1644 (ImportDescriptor
->OriginalFirstThunk
))
1646 /* Get the image thunk */
1647 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1648 ImportDescriptor
->FirstThunk
);
1652 /* Do we already have an address? */
1655 /* Is the thunk in the same address? */
1656 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1658 /* Skip it, we already have a reference for it */
1659 ASSERT(EntryArray
[j
]);
1665 /* Loop the loaded module list to locate this address owner */
1667 NextEntry2
= PsLoadedModuleList
.Flink
;
1668 while (NextEntry2
!= &PsLoadedModuleList
)
1671 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
1672 LDR_DATA_TABLE_ENTRY
,
1675 /* Get the address range for this module */
1676 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
1677 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
1679 /* Check if this IAT entry matches it */
1680 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1683 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
1684 EntryArray
[j
] = LdrEntry2
;
1688 /* Keep searching */
1689 NextEntry2
= NextEntry2
->Flink
;
1693 /* Do we have a thunk outside the range? */
1694 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
1699 /* Should not be happening */
1700 DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
1701 LdrEntry
, ImageThunk
, *ImageThunk
);
1705 /* Reset if we hit this */
1708 #ifndef _WORKING_LOADER_
1717 /* Now scan how many imports we really have */
1718 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
1720 /* Skip HAL and kernel */
1721 if ((EntryArray
[i
]) &&
1722 (EntryArray
[i
] != HalEntry
) &&
1723 (EntryArray
[i
] != KernelEntry
))
1725 /* A valid reference */
1726 LastEntry
= EntryArray
[i
];
1731 /* Do we have any imports after all? */
1735 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1737 else if (ImportSize
== 1)
1739 /* A single entry import */
1740 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
1741 LastEntry
->LoadCount
++;
1745 /* We need an import table */
1746 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
1747 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1750 ASSERT(LoadedImports
);
1752 /* Save the count */
1753 LoadedImports
->Count
= ImportSize
;
1755 /* Now copy all imports */
1756 for (i
= 0, j
= 0; i
< Modules
; i
++)
1758 /* Skip HAL and kernel */
1759 if ((EntryArray
[i
]) &&
1760 (EntryArray
[i
] != HalEntry
) &&
1761 (EntryArray
[i
] != KernelEntry
))
1763 /* A valid reference */
1764 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
1765 LoadedImports
->Entry
[j
] = EntryArray
[i
];
1766 EntryArray
[i
]->LoadCount
++;
1771 /* Should had as many entries as we expected */
1772 ASSERT(j
== ImportSize
);
1773 LdrEntry
->LoadedImports
= LoadedImports
;
1777 NextEntry
= NextEntry
->Flink
;
1780 /* Free the initial array */
1781 ExFreePool(EntryArray
);
1783 /* FIXME: Might not need to keep the HAL/Kernel imports around */
1785 /* Kernel and HAL are loaded at boot */
1786 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1787 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1789 /* All worked well */
1790 return STATUS_SUCCESS
;
1795 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1798 PIMAGE_NT_HEADERS NtHeaders
;
1799 PIMAGE_SECTION_HEADER SectionHeader
;
1800 ULONG Sections
, Size
;
1802 /* Get the kernel section header */
1803 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1804 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
1805 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
1807 /* Loop all the sections */
1808 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
1811 /* Grab the size of the section */
1812 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
1814 /* Check for .RSRC section */
1815 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
1817 /* Remember the PTEs so we can modify them later */
1818 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
1819 SectionHeader
->VirtualAddress
);
1820 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
1821 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
1823 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
1825 /* POOLCODE vs. POOLMI */
1826 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
1828 /* Found Ex* Pool code */
1829 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1830 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
1832 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
1834 /* Found Mm* Pool code */
1835 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1836 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
1839 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
1840 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
1842 /* Found MISYSPTE (Mm System PTE code)*/
1843 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1844 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
1855 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1857 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1858 PLIST_ENTRY ListHead
, NextEntry
;
1861 /* Setup the loaded module list and locks */
1862 ExInitializeResourceLite(&PsLoadedModuleResource
);
1863 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1864 InitializeListHead(&PsLoadedModuleList
);
1866 /* Get loop variables and the kernel entry */
1867 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1868 NextEntry
= ListHead
->Flink
;
1869 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1870 LDR_DATA_TABLE_ENTRY
,
1872 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1874 /* Locate resource section, pool code, and system pte code */
1875 MiLocateKernelSections(LdrEntry
);
1877 /* Loop the loader block */
1878 while (NextEntry
!= ListHead
)
1880 /* Get the loader entry */
1881 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1882 LDR_DATA_TABLE_ENTRY
,
1885 /* FIXME: ROS HACK. Make sure this is a driver */
1886 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1888 /* Skip this entry */
1889 NextEntry
= NextEntry
->Flink
;
1893 /* Calculate the size we'll need and allocate a copy */
1894 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1895 LdrEntry
->BaseDllName
.MaximumLength
+
1896 sizeof(UNICODE_NULL
);
1897 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1898 if (!NewEntry
) return FALSE
;
1900 /* Copy the entry over */
1901 *NewEntry
= *LdrEntry
;
1903 /* Allocate the name */
1904 NewEntry
->FullDllName
.Buffer
=
1905 ExAllocatePoolWithTag(PagedPool
,
1906 LdrEntry
->FullDllName
.MaximumLength
+
1907 sizeof(UNICODE_NULL
),
1909 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1911 /* Set the base name */
1912 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1914 /* Copy the full and base name */
1915 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1916 LdrEntry
->FullDllName
.Buffer
,
1917 LdrEntry
->FullDllName
.MaximumLength
);
1918 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1919 LdrEntry
->BaseDllName
.Buffer
,
1920 LdrEntry
->BaseDllName
.MaximumLength
);
1922 /* Null-terminate the base name */
1923 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1924 sizeof(WCHAR
)] = UNICODE_NULL
;
1926 /* Insert the entry into the list */
1927 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1928 NextEntry
= NextEntry
->Flink
;
1931 /* Build the import lists for the boot drivers */
1932 MiBuildImportsForBootDrivers();
1940 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
1941 IN OUT PVOID
*ImageBaseAddress
,
1942 IN PUNICODE_STRING BaseImageName
,
1943 IN BOOLEAN BootDriver
)
1945 PLIST_ENTRY NextEntry
;
1946 BOOLEAN DriverFound
= FALSE
;
1947 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
1948 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
1949 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
1952 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
1953 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
1956 /* Make sure there's enough system PTEs for a large page driver */
1957 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
1962 /* This happens if the registry key had a "*" (wildcard) in it */
1963 if (MiLargePageAllDrivers
== 0)
1965 /* It didn't, so scan the list */
1966 NextEntry
= MiLargePageDriverList
.Flink
;
1967 while (NextEntry
!= &MiLargePageDriverList
)
1969 /* Check if the driver name matches */
1970 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
1971 MI_LARGE_PAGE_DRIVER_ENTRY
,
1973 if (RtlEqualUnicodeString(BaseImageName
,
1974 &LargePageDriverEntry
->BaseName
,
1977 /* Enable large pages for this driver */
1983 NextEntry
= NextEntry
->Flink
;
1986 /* If we didn't find the driver, it doesn't need large pages */
1987 if (DriverFound
== FALSE
) return FALSE
;
1990 /* Nothing to do yet */
1991 DPRINT1("Large pages not supported!\n");
1997 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
1998 IN ULONG SectionProtection
)
2000 ULONG Protection
= MM_ZERO_ACCESS
;
2002 /* Check if the caller gave anything */
2003 if (SectionProtection
)
2005 /* Always turn on execute access */
2006 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
2008 /* Check if the registry setting is on or not */
2009 if (!MmEnforceWriteProtection
)
2011 /* Turn on write access too */
2012 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
2016 /* Convert to internal PTE flags */
2017 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
2018 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
2020 /* Check for write access */
2021 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
2023 /* Session space is not supported */
2026 DPRINT1("Session drivers not supported\n");
2027 ASSERT(SessionSpace
== FALSE
);
2031 /* Convert to internal PTE flag */
2032 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
2036 /* If there's no access at all by now, convert to internal no access flag */
2037 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
2039 /* Return the computed PTE protection */
2045 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
2047 IN ULONG ProtectionMask
)
2049 /* I'm afraid to introduce regressions at the moment... */
2055 MiWriteProtectSystemImage(IN PVOID ImageBase
)
2057 PIMAGE_NT_HEADERS NtHeaders
;
2058 PIMAGE_SECTION_HEADER Section
;
2059 PFN_NUMBER DriverPages
;
2060 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
, ProtectionMask
;
2061 ULONG Sections
, Size
;
2062 ULONG_PTR BaseAddress
, CurrentAddress
;
2063 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
2064 ULONG CurrentMask
, CombinedMask
= 0;
2067 /* No need to write protect physical memory-backed drivers (large pages) */
2068 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2070 /* Get the image headers */
2071 NtHeaders
= RtlImageNtHeader(ImageBase
);
2072 if (!NtHeaders
) return;
2074 /* Check if this is a session driver or not */
2075 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
2077 /* Don't touch NT4 drivers */
2078 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
2079 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
2084 DPRINT1("Session drivers not supported\n");
2088 /* These are the only protection masks we care about */
2089 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
2091 /* Calculate the number of pages this driver is occupying */
2092 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
2094 /* Get the number of sections and the first section header */
2095 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2096 ASSERT(Sections
!= 0);
2097 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2099 /* Loop all the sections */
2100 CurrentAddress
= (ULONG_PTR
)ImageBase
;
2103 /* Get the section size */
2104 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2106 /* Get its virtual address */
2107 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2108 if (BaseAddress
< CurrentAddress
)
2110 /* Windows doesn't like these */
2111 DPRINT1("Badly linked image!\n");
2115 /* Remember the current address */
2116 CurrentAddress
= BaseAddress
+ Size
- 1;
2123 /* Get the number of sections and the first section header */
2124 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2125 ASSERT(Sections
!= 0);
2126 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2128 /* Set the address at the end to initialize the loop */
2129 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
2130 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
2132 /* Set the PTE points for the image, and loop its sections */
2133 StartPte
= MiAddressToPte(ImageBase
);
2134 LastPte
= StartPte
+ DriverPages
;
2137 /* Get the section size */
2138 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2140 /* Get its virtual address and PTE */
2141 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2142 PointerPte
= MiAddressToPte(BaseAddress
);
2144 /* Check if we were already protecting a run, and found a new run */
2145 if ((ComboPte
) && (PointerPte
> ComboPte
))
2147 /* Compute protection */
2148 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2151 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2153 /* Check for overlap */
2154 if (ComboPte
== StartPte
) StartPte
++;
2156 /* One done, reset variables */
2158 CombinedProtection
= 0;
2161 /* Break out when needed */
2162 if (PointerPte
>= LastPte
) break;
2164 /* Get the requested protection from the image header */
2165 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
2166 if (SectionProtection
== CurrentProtection
)
2168 /* Same protection, so merge the request */
2169 CurrentAddress
= BaseAddress
+ Size
- 1;
2177 /* This is now a new section, so close up the old one */
2178 CurrentPte
= MiAddressToPte(CurrentAddress
);
2180 /* Check for overlap */
2181 if (CurrentPte
== PointerPte
)
2183 /* Skip the last PTE, since it overlaps with us */
2186 /* And set the PTE we will merge with */
2187 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
2188 ComboPte
= PointerPte
;
2190 /* Get the most flexible protection by merging both */
2191 CombinedMask
|= (SectionProtection
| CurrentProtection
);
2194 /* Loop any PTEs left */
2195 if (CurrentPte
>= StartPte
)
2198 ASSERT(StartPte
< LastPte
);
2200 /* Make sure we don't overflow past the last PTE in the driver */
2201 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2202 ASSERT(CurrentPte
>= StartPte
);
2204 /* Compute the protection and set it */
2205 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2206 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2210 StartPte
= PointerPte
;
2211 CurrentAddress
= BaseAddress
+ Size
- 1;
2212 CurrentProtection
= SectionProtection
;
2219 /* Is there a leftover section to merge? */
2222 /* Compute and set the protection */
2223 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2224 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2226 /* Handle overlap */
2227 if (ComboPte
== StartPte
) StartPte
++;
2230 /* Finally, handle the last section */
2231 CurrentPte
= MiAddressToPte(CurrentAddress
);
2232 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
2234 /* Handle overlap */
2235 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2236 ASSERT(CurrentPte
>= StartPte
);
2238 /* Compute and set the protection */
2239 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2240 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2246 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2250 PETHREAD CurrentThread
= PsGetCurrentThread();
2251 PFN_NUMBER PageCount
= 0, PageFrameIndex
;
2255 /* Get the driver's base address */
2256 ImageBase
= MiPteToAddress(PointerPte
);
2257 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2259 /* If this is a large page, it's stuck in physical memory */
2260 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2262 /* Lock the working set */
2263 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2266 while (PointerPte
<= LastPte
)
2268 /* Check for valid PTE */
2269 if (PointerPte
->u
.Hard
.Valid
== 1)
2271 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2272 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2273 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2275 /* No working sets in ReactOS yet */
2279 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2283 /* Release the working set */
2284 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2286 /* Do we have any driver pages? */
2289 /* Update counters */
2290 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2296 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2298 ULONG_PTR ImageBase
;
2299 PIMAGE_NT_HEADERS NtHeaders
;
2300 ULONG Sections
, Alignment
, Size
;
2301 PIMAGE_SECTION_HEADER Section
;
2302 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2303 if (MmDisablePagingExecutive
) return;
2305 /* Get the driver base address and its NT header */
2306 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2307 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2308 if (!NtHeaders
) return;
2310 /* Get the sections and their alignment */
2311 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2312 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2314 /* Loop each section */
2315 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2318 /* Find PAGE or .edata */
2319 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2320 (*(PULONG
)Section
->Name
== 'ade.'))
2322 /* Had we already done some work? */
2325 /* Nope, setup the first PTE address */
2326 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2331 /* Compute the size */
2332 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2334 /* Find the last PTE that maps this section */
2335 LastPte
= MiAddressToPte(ImageBase
+
2336 Section
->VirtualAddress
+
2343 /* Had we found a section before? */
2346 /* Mark it as pageable */
2347 MiSetPagingOfDriver(PointerPte
, LastPte
);
2352 /* Keep searching */
2357 /* Handle the straggler */
2358 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2363 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2365 PIMAGE_NT_HEADERS NtHeader
;
2368 /* Get NT Headers */
2369 NtHeader
= RtlImageNtHeader(BaseAddress
);
2372 /* Check if this image is only safe for UP while we have 2+ CPUs */
2373 if ((KeNumberProcessors
> 1) &&
2374 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2381 /* Otherwise, it's safe */
2387 MmCheckSystemImage(IN HANDLE ImageHandle
,
2388 IN BOOLEAN PurgeSection
)
2391 HANDLE SectionHandle
;
2392 PVOID ViewBase
= NULL
;
2393 SIZE_T ViewSize
= 0;
2394 IO_STATUS_BLOCK IoStatusBlock
;
2395 FILE_STANDARD_INFORMATION FileStandardInfo
;
2396 KAPC_STATE ApcState
;
2397 PIMAGE_NT_HEADERS NtHeaders
;
2398 OBJECT_ATTRIBUTES ObjectAttributes
;
2401 /* Setup the object attributes */
2402 InitializeObjectAttributes(&ObjectAttributes
,
2404 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2408 /* Create a section for the DLL */
2409 Status
= ZwCreateSection(&SectionHandle
,
2410 SECTION_MAP_EXECUTE
,
2416 if (!NT_SUCCESS(Status
)) return Status
;
2418 /* Make sure we're in the system process */
2419 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2422 Status
= ZwMapViewOfSection(SectionHandle
,
2432 if (!NT_SUCCESS(Status
))
2434 /* We failed, close the handle and return */
2435 KeUnstackDetachProcess(&ApcState
);
2436 ZwClose(SectionHandle
);
2440 /* Now query image information */
2441 Status
= ZwQueryInformationFile(ImageHandle
,
2444 sizeof(FileStandardInfo
),
2445 FileStandardInformation
);
2446 if (NT_SUCCESS(Status
))
2448 /* First, verify the checksum */
2449 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2454 /* Set checksum failure */
2455 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2459 /* Make sure it's a real image */
2460 NtHeaders
= RtlImageNtHeader(ViewBase
);
2463 /* Set checksum failure */
2464 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2468 /* Make sure it's for the correct architecture */
2469 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2470 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2472 /* Set protection failure */
2473 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2477 /* Check that it's a valid SMP image if we have more then one CPU */
2478 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2480 /* Otherwise it's not the right image */
2481 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2485 /* Unmap the section, close the handle, and return status */
2487 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2488 KeUnstackDetachProcess(&ApcState
);
2489 ZwClose(SectionHandle
);
2495 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2496 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2497 IN PUNICODE_STRING LoadedName OPTIONAL
,
2499 OUT PVOID
*ModuleObject
,
2500 OUT PVOID
*ImageBaseAddress
)
2502 PVOID ModuleLoadBase
= NULL
;
2504 HANDLE FileHandle
= NULL
;
2505 OBJECT_ATTRIBUTES ObjectAttributes
;
2506 IO_STATUS_BLOCK IoStatusBlock
;
2507 PIMAGE_NT_HEADERS NtHeader
;
2508 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2509 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2510 ULONG EntrySize
, DriverSize
;
2511 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2512 PCHAR MissingApiName
, Buffer
;
2513 PWCHAR MissingDriverName
;
2514 HANDLE SectionHandle
;
2515 ACCESS_MASK DesiredAccess
;
2516 PVOID Section
= NULL
;
2517 BOOLEAN LockOwned
= FALSE
;
2518 PLIST_ENTRY NextEntry
;
2519 IMAGE_INFO ImageInfo
;
2523 /* Detect session-load */
2527 ASSERT(NamePrefix
== NULL
);
2528 ASSERT(LoadedName
== NULL
);
2530 /* Make sure the process is in session too */
2531 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2534 /* Allocate a buffer we'll use for names */
2535 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, 'nLmM');
2536 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2538 /* Check for a separator */
2539 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2544 /* Loop the path until we get to the base name */
2545 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2546 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2548 /* Get the length */
2549 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2550 BaseLength
*= sizeof(WCHAR
);
2552 /* Setup the string */
2553 BaseName
.Length
= (USHORT
)BaseLength
;
2554 BaseName
.Buffer
= p
;
2558 /* Otherwise, we already have a base name */
2559 BaseName
.Length
= FileName
->Length
;
2560 BaseName
.Buffer
= FileName
->Buffer
;
2563 /* Setup the maximum length */
2564 BaseName
.MaximumLength
= BaseName
.Length
;
2566 /* Now compute the base directory */
2567 BaseDirectory
= *FileName
;
2568 BaseDirectory
.Length
-= BaseName
.Length
;
2569 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2571 /* And the prefix, which for now is just the name itself */
2572 PrefixName
= *FileName
;
2574 /* Check if we have a prefix */
2575 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2577 /* Check if we already have a name, use it instead */
2578 if (LoadedName
) BaseName
= *LoadedName
;
2580 /* Check for loader snap debugging */
2581 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2583 /* Print out standard string */
2584 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2585 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2588 /* Acquire the load lock */
2590 ASSERT(LockOwned
== FALSE
);
2592 KeEnterCriticalRegion();
2593 KeWaitForSingleObject(&MmSystemLoadLock
,
2599 /* Scan the module list */
2600 NextEntry
= PsLoadedModuleList
.Flink
;
2601 while (NextEntry
!= &PsLoadedModuleList
)
2603 /* Get the entry and compare the names */
2604 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2605 LDR_DATA_TABLE_ENTRY
,
2607 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2609 /* Found it, break out */
2614 NextEntry
= NextEntry
->Flink
;
2617 /* Check if we found the image */
2618 if (NextEntry
!= &PsLoadedModuleList
)
2620 /* Check if we had already mapped a section */
2623 /* Dereference and clear */
2624 ObDereferenceObject(Section
);
2628 /* Check if this was supposed to be a session load */
2631 /* It wasn't, so just return the data */
2632 *ModuleObject
= LdrEntry
;
2633 *ImageBaseAddress
= LdrEntry
->DllBase
;
2634 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2638 /* We don't support session loading yet */
2639 DPRINT1("Unsupported Session-Load!\n");
2648 /* It wasn't loaded, and we didn't have a previous attempt */
2649 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2650 KeLeaveCriticalRegion();
2653 /* Check if KD is enabled */
2654 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2656 /* FIXME: Attempt to get image from KD */
2659 /* We don't have a valid entry */
2662 /* Setup image attributes */
2663 InitializeObjectAttributes(&ObjectAttributes
,
2665 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2669 /* Open the image */
2670 Status
= ZwOpenFile(&FileHandle
,
2674 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2676 if (!NT_SUCCESS(Status
)) goto Quickie
;
2679 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
2680 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
2681 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
2682 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
2688 /* Check if this is a session-load */
2691 /* Then we only need read and execute */
2692 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
2696 /* Otherwise, we can allow write access */
2697 DesiredAccess
= SECTION_ALL_ACCESS
;
2700 /* Initialize the attributes for the section */
2701 InitializeObjectAttributes(&ObjectAttributes
,
2703 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2707 /* Create the section */
2708 Status
= ZwCreateSection(&SectionHandle
,
2715 if (!NT_SUCCESS(Status
)) goto Quickie
;
2717 /* Now get the section pointer */
2718 Status
= ObReferenceObjectByHandle(SectionHandle
,
2719 SECTION_MAP_EXECUTE
,
2720 MmSectionObjectType
,
2724 ZwClose(SectionHandle
);
2725 if (!NT_SUCCESS(Status
)) goto Quickie
;
2727 /* Check if this was supposed to be a session-load */
2730 /* We don't support session loading yet */
2731 DPRINT1("Unsupported Session-Load!\n");
2735 /* Check the loader list again, we should end up in the path below */
2740 /* We don't have a valid entry */
2744 /* Load the image */
2745 Status
= MiLoadImageSection(&Section
,
2750 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
2752 /* Get the size of the driver */
2753 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
2755 /* Make sure we're not being loaded into session space */
2758 /* Check for success */
2759 if (NT_SUCCESS(Status
))
2761 /* Support large pages for drivers */
2762 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
2768 /* Dereference the section */
2769 ObDereferenceObject(Section
);
2773 /* Check for failure of the load earlier */
2774 if (!NT_SUCCESS(Status
)) goto Quickie
;
2776 /* Relocate the driver */
2777 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
2781 STATUS_CONFLICTING_ADDRESSES
,
2782 STATUS_INVALID_IMAGE_FORMAT
);
2783 if (!NT_SUCCESS(Status
)) goto Quickie
;
2786 /* Get the NT Header */
2787 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
2789 /* Calculate the size we'll need for the entry and allocate it */
2790 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2792 sizeof(UNICODE_NULL
);
2794 /* Allocate the entry */
2795 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2799 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2803 /* Setup the entry */
2804 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
2805 LdrEntry
->LoadCount
= 1;
2806 LdrEntry
->LoadedImports
= LoadedImports
;
2807 LdrEntry
->PatchInformation
= NULL
;
2809 /* Check the version */
2810 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
2811 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
2813 /* Mark this image as a native image */
2814 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
2817 /* Setup the rest of the entry */
2818 LdrEntry
->DllBase
= ModuleLoadBase
;
2819 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
2820 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
2821 LdrEntry
->SizeOfImage
= DriverSize
;
2822 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
2823 LdrEntry
->SectionPointer
= Section
;
2825 /* Now write the DLL name */
2826 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
2827 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
2828 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
2830 /* Copy and null-terminate it */
2831 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
2834 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2836 /* Now allocate the full name */
2837 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
2839 sizeof(UNICODE_NULL
),
2841 if (!LdrEntry
->FullDllName
.Buffer
)
2843 /* Don't fail, just set it to zero */
2844 LdrEntry
->FullDllName
.Length
= 0;
2845 LdrEntry
->FullDllName
.MaximumLength
= 0;
2850 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
2851 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
2853 /* Copy and null-terminate */
2854 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
2857 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2861 MiProcessLoaderEntry(LdrEntry
, TRUE
);
2863 /* Resolve imports */
2864 MissingApiName
= Buffer
;
2865 Status
= MiResolveImageReferences(ModuleLoadBase
,
2871 if (!NT_SUCCESS(Status
))
2874 MiProcessLoaderEntry(LdrEntry
, FALSE
);
2876 /* Check if we need to free the name */
2877 if (LdrEntry
->FullDllName
.Buffer
)
2880 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
2883 /* Free the entry itself */
2884 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
2889 /* Update the loader entry */
2890 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
2891 LDRP_ENTRY_PROCESSED
|
2893 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2894 LdrEntry
->LoadedImports
= LoadedImports
;
2896 /* FIXME: Call driver verifier's loader function */
2898 /* Write-protect the system image */
2899 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
2901 /* Check if notifications are enabled */
2902 if (PsImageNotifyEnabled
)
2904 /* Fill out the notification data */
2905 ImageInfo
.Properties
= 0;
2906 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
2907 ImageInfo
.SystemModeImage
= TRUE
;
2908 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
2909 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
2910 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
2912 /* Send the notification */
2913 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
2916 #if defined(KDBG) || defined(_WINKD_)
2917 /* MiCacheImageSymbols doesn't detect rossym */
2920 /* Check if there's symbols */
2921 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
2924 /* Check if the system root is present */
2925 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
2926 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
2928 /* Add the system root */
2929 UnicodeTemp
= PrefixName
;
2930 UnicodeTemp
.Buffer
+= 11;
2931 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
2934 &SharedUserData
->NtSystemRoot
[2],
2939 /* Build the name */
2940 sprintf_nt(Buffer
, "%wZ", &BaseName
);
2943 /* Setup the ansi string */
2944 RtlInitString(&AnsiTemp
, Buffer
);
2946 /* Notify the debugger */
2947 DbgLoadImageSymbols(&AnsiTemp
,
2949 (ULONG_PTR
)ZwCurrentProcess());
2950 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
2953 /* Page the driver */
2954 ASSERT(Section
== NULL
);
2955 MiEnablePagingOfDriver(LdrEntry
);
2957 /* Return pointers */
2958 *ModuleObject
= LdrEntry
;
2959 *ImageBaseAddress
= LdrEntry
->DllBase
;
2962 /* Check if we have the lock acquired */
2965 /* Release the lock */
2966 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2967 KeLeaveCriticalRegion();
2971 /* If we have a file handle, close it */
2972 if (FileHandle
) ZwClose(FileHandle
);
2974 /* Check if we had a prefix */
2975 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
2977 /* Free the name buffer and return status */
2978 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
2982 PLDR_DATA_TABLE_ENTRY
2984 MiLookupDataTableEntry(IN PVOID Address
)
2986 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
2987 PLIST_ENTRY NextEntry
;
2991 NextEntry
= PsLoadedModuleList
.Flink
;
2994 /* Get the loader entry */
2995 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2996 LDR_DATA_TABLE_ENTRY
,
2999 /* Check if the address matches */
3000 if ((Address
>= LdrEntry
->DllBase
) &&
3001 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3002 LdrEntry
->SizeOfImage
)))
3005 FoundEntry
= LdrEntry
;
3010 NextEntry
= NextEntry
->Flink
;
3011 } while(NextEntry
!= &PsLoadedModuleList
);
3013 /* Return the entry */
3017 /* PUBLIC FUNCTIONS ***********************************************************/
3024 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3026 PMMPTE StartPte
, EndPte
;
3027 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3030 /* Get the loader entry */
3031 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3032 if (!LdrEntry
) return NULL
;
3034 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3035 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3037 /* Don't do anything, just return the base address */
3038 return LdrEntry
->DllBase
;
3041 /* Wait for active DPCs to finish before we page out the driver */
3042 KeFlushQueuedDpcs();
3044 /* Get the PTE range for the whole driver image */
3045 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3046 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3048 /* Enable paging for the PTE range */
3049 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3050 MiSetPagingOfDriver(StartPte
, EndPte
);
3052 /* Return the base address */
3053 return LdrEntry
->DllBase
;
3061 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3071 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3073 PVOID ProcAddress
= NULL
;
3074 ANSI_STRING AnsiRoutineName
;
3076 PLIST_ENTRY NextEntry
;
3077 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3078 BOOLEAN Found
= FALSE
;
3079 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3080 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3083 /* Convert routine to ansi name */
3084 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3087 if (!NT_SUCCESS(Status
)) return NULL
;
3090 KeEnterCriticalRegion();
3091 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3093 /* Loop the loaded module list */
3094 NextEntry
= PsLoadedModuleList
.Flink
;
3095 while (NextEntry
!= &PsLoadedModuleList
)
3098 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3099 LDR_DATA_TABLE_ENTRY
,
3102 /* Check if it's the kernel or HAL */
3103 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3109 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3116 /* Check if we found a valid binary */
3119 /* Find the procedure name */
3120 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3123 /* Break out if we found it or if we already tried both modules */
3124 if (ProcAddress
) break;
3125 if (Modules
== 2) break;
3129 NextEntry
= NextEntry
->Flink
;
3132 /* Release the lock */
3133 ExReleaseResourceLite(&PsLoadedModuleResource
);
3134 KeLeaveCriticalRegion();
3136 /* Free the string and return */
3137 RtlFreeAnsiString(&AnsiRoutineName
);